Skip to content

Commit f350303

Browse files
akulsr0ljharb
authored andcommitted
[Fix] jsx-no-leaked-render: invalid fixes in coerce mode
1 parent 12fe944 commit f350303

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
1919
* [`jsx-no-leaked-render`]: Don't report errors on empty strings if React >= v18 ([#3488][] @himanshu007-creator)
2020
* [`no-invalid-html-attribute`]: convert autofix to suggestion ([#3474][] @himanshu007-creator @ljharb)
2121
* [`jsx-no-leaked-render`]: fix removing parentheses for conditionals ([#3502][] @akulsr0)
22+
* [`jsx-no-leaked-render`]: invalid fixes in coerce mode ([#3511][] @akulsr0)
2223

2324
### Changed
2425
* [Docs] [`jsx-no-leaked-render`]: Remove mentions of empty strings for React 18 ([#3468][] @karlhorky)
@@ -28,6 +29,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
2829
* [Docs] [`prefer-exact-props`]: fix example flow syntax ([#3510][] @smackfu)
2930
* [Perf] use `anyOf` instead of `oneOf` (@ljharb @remcohaszing)
3031

32+
[#3511]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3511
3133
[#3510]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3510
3234
[#3504]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3504
3335
[#3502]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3502

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

+15
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,27 @@ function ruleFixer(context, fixStrategy, fixer, reportedNode, leftNode, rightNod
6161
if (isParenthesized(context, node)) {
6262
nodeText = `(${nodeText})`;
6363
}
64+
if (node.parent && node.parent.type === 'ConditionalExpression' && node.parent.consequent.value === false) {
65+
return `${getIsCoerceValidNestedLogicalExpression(node) ? '' : '!'}${nodeText}`;
66+
}
6467
return `${getIsCoerceValidNestedLogicalExpression(node) ? '' : '!!'}${nodeText}`;
6568
}).join(' && ');
6669

70+
if (rightNode.parent && rightNode.parent.type === 'ConditionalExpression' && rightNode.parent.consequent.value === false) {
71+
const consequentVal = rightNode.parent.consequent.raw || rightNode.parent.consequent.name;
72+
const alternateVal = rightNode.parent.alternate.raw || rightNode.parent.alternate.name;
73+
if (rightNode.parent.test && rightNode.parent.test.type === 'LogicalExpression') {
74+
return fixer.replaceText(reportedNode, `${newText} ? ${consequentVal} : ${alternateVal}`);
75+
}
76+
return fixer.replaceText(reportedNode, `${newText} && ${alternateVal}`);
77+
}
78+
6779
if (rightNode.type === 'ConditionalExpression') {
6880
return fixer.replaceText(reportedNode, `${newText} && (${rightSideText})`);
6981
}
82+
if (rightNode.type === 'Literal') {
83+
return null;
84+
}
7085
return fixer.replaceText(reportedNode, `${newText} && ${rightSideText}`);
7186
}
7287

tests/lib/rules/jsx-no-leaked-render.js

+41-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
// Requirements
1010
//------------------------------------------------------------------------------
1111

12+
const semver = require('semver');
13+
const eslintPkg = require('eslint/package.json');
1214
const RuleTester = require('eslint').RuleTester;
1315
const rule = require('../../../lib/rules/jsx-no-leaked-render');
1416

@@ -193,9 +195,9 @@ ruleTester.run('jsx-no-leaked-render', rule, {
193195
`,
194196
options: [{ validStrategies: ['coerce'] }],
195197
},
196-
]),
198+
]) || [],
197199

198-
invalid: parsers.all([
200+
invalid: parsers.all([].concat(
199201
// Common invalid cases with default options
200202
{
201203
code: `
@@ -847,5 +849,41 @@ ruleTester.run('jsx-no-leaked-render', rule, {
847849
column: 24,
848850
}],
849851
},
850-
]),
852+
{
853+
code: `
854+
const MyComponent = () => {
855+
return <Something checked={isIndeterminate ? false : isChecked} />
856+
}
857+
`,
858+
output: semver.satisfies(eslintPkg.version, '> 4') ? `
859+
const MyComponent = () => {
860+
return <Something checked={!isIndeterminate && isChecked} />
861+
}
862+
` : null,
863+
options: [{ validStrategies: ['coerce'] }],
864+
errors: [{
865+
message: 'Potential leaked value that might cause unintentionally rendered values or rendering crashes',
866+
line: 3,
867+
column: 38,
868+
}],
869+
},
870+
{
871+
code: `
872+
const MyComponent = () => {
873+
return <Something checked={cond && isIndeterminate ? false : isChecked} />
874+
}
875+
`,
876+
output: semver.satisfies(eslintPkg.version, '> 4') ? `
877+
const MyComponent = () => {
878+
return <Something checked={!!cond && !!isIndeterminate ? false : isChecked} />
879+
}
880+
` : null,
881+
options: [{ validStrategies: ['coerce'] }],
882+
errors: [{
883+
message: 'Potential leaked value that might cause unintentionally rendered values or rendering crashes',
884+
line: 3,
885+
column: 38,
886+
}],
887+
}
888+
)),
851889
});

0 commit comments

Comments
 (0)