diff --git a/CHANGELOG.md b/CHANGELOG.md index a358c59def..a6971a072f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`boolean-prop-naming`]: avoid a crash with a non-TSTypeReference type ([#3718][] @developer-bandi) +* [`jsx-no-leaked-render`]: invalid report if left side is boolean ([#3746][] @akulsr0) +[#3746]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3746 [#3718]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3718 ## [7.34.1] - 2024.03.15 diff --git a/lib/rules/jsx-no-leaked-render.js b/lib/rules/jsx-no-leaked-render.js index a6bf54b72a..e20524c8d2 100644 --- a/lib/rules/jsx-no-leaked-render.js +++ b/lib/rules/jsx-no-leaked-render.js @@ -10,6 +10,7 @@ const from = require('es-iterator-helpers/Iterator.from'); const docsUrl = require('../util/docsUrl'); const report = require('../util/report'); +const variableUtil = require('../util/variable'); const testReactVersion = require('../util/version').testReactVersion; const isParenthesized = require('../util/ast').isParenthesized; @@ -160,6 +161,17 @@ module.exports = { if (isCoerceValidLeftSide || getIsCoerceValidNestedLogicalExpression(leftSide)) { return; } + const variables = variableUtil.variablesInScope(context); + const leftSideVar = variableUtil.getVariable(variables, leftSide.name); + if (leftSideVar) { + const leftSideValue = leftSideVar.defs + && leftSideVar.defs.length + && leftSideVar.defs[0].node.init + && leftSideVar.defs[0].node.init.value; + if (typeof leftSideValue === 'boolean') { + return; + } + } } if (testReactVersion(context, '>= 18') && leftSide.type === 'Literal' && leftSide.value === '') { diff --git a/tests/lib/rules/jsx-no-leaked-render.js b/tests/lib/rules/jsx-no-leaked-render.js index f5729bf059..a6742a29cd 100644 --- a/tests/lib/rules/jsx-no-leaked-render.js +++ b/tests/lib/rules/jsx-no-leaked-render.js @@ -195,6 +195,24 @@ ruleTester.run('jsx-no-leaked-render', rule, { `, options: [{ validStrategies: ['coerce'] }], }, + { + code: ` + const isOpen = true; + const Component = () => { + return 0} /> + } + `, + options: [{ validStrategies: ['coerce'] }], + }, + { + code: ` + const isOpen = false; + const Component = () => { + return 0} /> + } + `, + options: [{ validStrategies: ['coerce'] }], + }, ]) || [], invalid: parsers.all([].concat( @@ -972,6 +990,26 @@ ruleTester.run('jsx-no-leaked-render', rule, { line: 5, column: 16, }], - } : [] + } : [], + { + code: ` + const isOpen = 0; + const Component = () => { + return 0} /> + } + `, + output: ` + const isOpen = 0; + const Component = () => { + return 0} /> + } + `, + options: [{ validStrategies: ['coerce'] }], + errors: [{ + message: 'Potential leaked value that might cause unintentionally rendered values or rendering crashes', + line: 4, + column: 33, + }], + } )), });