Skip to content

Commit

Permalink
[New] jsx-no-leaked-render: add ignoreAttributes option
Browse files Browse the repository at this point in the history
When true, validation of JSX attribute values is skipped.
  • Loading branch information
aleclarson committed Sep 26, 2022
1 parent b52e0ca commit 9c84be6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/rules/jsx-no-leaked-render.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ const Component = ({ elements }) => {

The supported options are:

### `ignoreAttributes`

*TODO*

### `validStrategies`

An array containing `"coerce"`, `"ternary"`, or both (default: `["ternary", "coerce"]`) - Decide which strategies are considered valid to prevent leaked renders (at least 1 is required). The "coerce" option will transform the conditional of the JSX expression to a boolean. The "ternary" option transforms the binary expression into a ternary expression returning `null` for falsy values. The first option from the array will be the strategy used when autofixing, so the order of the values matters.
Expand Down
23 changes: 23 additions & 0 deletions lib/rules/jsx-no-leaked-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ function extractExpressionBetweenLogicalAnds(node) {
);
}

function isWithinAttribute(node) {
const stopTypes = [
'JSXElement',
'JSXFragment',
];
let parent = node.parent;
while (stopTypes.indexOf(parent.type) < 0) {
if (parent.type === 'JSXAttribute') return true;
parent = parent.parent;
}
return false;
}

function ruleFixer(context, fixStrategy, fixer, reportedNode, leftNode, rightNode) {
const sourceCode = context.getSourceCode();
const rightSideText = sourceCode.getText(rightNode);
Expand Down Expand Up @@ -107,6 +120,10 @@ module.exports = {
uniqueItems: true,
default: DEFAULT_VALID_STRATEGIES,
},
ignoreAttributes: {
type: 'boolean',
default: false,
},
},
additionalProperties: false,
},
Expand All @@ -120,6 +137,9 @@ module.exports = {

return {
'JSXExpressionContainer > LogicalExpression[operator="&&"]'(node) {
if (config.ignoreAttributes && isWithinAttribute(node)) {
return;
}
const leftSide = node.left;

const isCoerceValidLeftSide = COERCE_VALID_LEFT_SIDE_EXPRESSIONS
Expand All @@ -142,6 +162,9 @@ module.exports = {
if (validStrategies.has(TERNARY_STRATEGY)) {
return;
}
if (config.ignoreAttributes && isWithinAttribute(node)) {
return;

Check warning on line 166 in lib/rules/jsx-no-leaked-render.js

View check run for this annotation

Codecov / codecov/patch

lib/rules/jsx-no-leaked-render.js#L166

Added line #L166 was not covered by tests
}

const isValidTernaryAlternate = TERNARY_INVALID_ALTERNATE_VALUES.indexOf(node.alternate.value) === -1;
const isJSXElementAlternate = node.alternate.type === 'JSXElement';
Expand Down
55 changes: 55 additions & 0 deletions tests/lib/rules/jsx-no-leaked-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ ruleTester.run('jsx-no-leaked-render', rule, {
`,
options: [{ validStrategies: ['coerce'] }],
},

// See #3292
{
code: `
const Component = ({ enabled, checked }) => {
return <CheckBox checked={enabled && checked} />
}
`,
options: [{ ignoreAttributes: true }],
},
]),

invalid: parsers.all([
Expand Down Expand Up @@ -789,5 +799,50 @@ ruleTester.run('jsx-no-leaked-render', rule, {
column: 24,
}],
},

// See #3292
{
code: `
const Component = ({ enabled, checked }) => {
return <CheckBox checked={enabled && checked} />
}
`,
output: `
const Component = ({ enabled, checked }) => {
return <CheckBox checked={enabled ? checked : null} />
}
`,
errors: [{
message: 'Potential leaked value that might cause unintentionally rendered values or rendering crashes',
line: 3,
column: 37,
}],
},
{
code: `
const Component = ({ enabled }) => {
return (
<Foo bar={
<Something>{enabled && <MuchWow />}</Something>
} />
)
}
`,
output: `
const Component = ({ enabled }) => {
return (
<Foo bar={
<Something>{enabled ? <MuchWow /> : null}</Something>
} />
)
}
`,
options: [{ ignoreAttributes: true }],
errors: [{
message: 'Potential leaked value that might cause unintentionally rendered values or rendering crashes',
line: 5,
column: 27,
}],
},
]),
});

0 comments on commit 9c84be6

Please sign in to comment.