From 8baf0c58ab1cb3cbaad57f13c24c95a65e95f87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Madrigal?= Date: Wed, 27 Jul 2022 09:16:01 +0200 Subject: [PATCH] [Fix] `display-name`, component detection: fix HOF returning null as Components Fixes #3346 --- CHANGELOG.md | 2 ++ lib/util/Components.js | 41 ++++++++++++++++++++++++ tests/lib/rules/display-name.js | 56 +++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4170a4edf4..e398952980 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * [`display-name`]: fix false positive for assignment of function returning null ([#3331][] @apbarrero) * [`display-name`]: fix identifying `_` as a capital letter ([#3335][] @apbarrero) * [`require-default-props`]: avoid a crash when function has no props param ([#3350][] @noahnu) +* [`display-name`], component detection: fix HOF returning null as Components ([#3347][] @jxm-math) ### Changed * [Refactor] [`jsx-indent-props`]: improved readability of the checkNodesIndent function ([#3315][] @caroline223) @@ -28,6 +29,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange [#3350]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3350 [#3349]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3349 +[#3347]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3347 [#3344]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3344 [#3339]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3339 [#3335]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3335 diff --git a/lib/util/Components.js b/lib/util/Components.js index dec1143162..7abfbee72f 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -517,6 +517,47 @@ function componentRule(rule, context) { return undefined; } + // case: any = () => () => null + if (node.parent.type === 'ArrowFunctionExpression' && node.parent.parent.type === 'AssignmentExpression' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) { + if (isFirstLetterCapitalized(node.parent.parent.left.name)) { + return node; + } + return undefined; + } + + // case: { any: () => () => null } + if (node.parent.type === 'ArrowFunctionExpression' && node.parent.parent.type === 'Property' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) { + if (isFirstLetterCapitalized(node.parent.parent.key.name)) { + return node; + } + return undefined; + } + + // case: any = function() {return function() {return null;};} + if (node.parent.type === 'ReturnStatement') { + if (isFirstLetterCapitalized(node.id && node.id.name)) { + return node; + } + const functionExpr = node.parent.parent.parent; + if (functionExpr.parent.type === 'AssignmentExpression' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) { + if (isFirstLetterCapitalized(functionExpr.parent.left.name)) { + return node; + } + return undefined; + } + } + + // case: { any: function() {return function() {return null;};} } + if (node.parent.type === 'ReturnStatement') { + const functionExpr = node.parent.parent.parent; + if (functionExpr.parent.type === 'Property' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) { + if (isFirstLetterCapitalized(functionExpr.parent.key.name)) { + return node; + } + return undefined; + } + } + // for case abc = { [someobject.somekey]: props => { ... return not-jsx } } if (node.parent && node.parent.key && node.parent.key.type === 'MemberExpression' && !utils.isReturningJSX(node) && !utils.isReturningOnlyNull(node)) { return undefined; diff --git a/tests/lib/rules/display-name.js b/tests/lib/rules/display-name.js index ba4b9181fe..841af839fc 100644 --- a/tests/lib/rules/display-name.js +++ b/tests/lib/rules/display-name.js @@ -615,6 +615,34 @@ ruleTester.run('display-name', rule, { }; `, }, + { + // issue #3346 + code: ` + demo = () => () => null; + `, + }, + { + // issue #3346 + code: ` + demo = { + property: () => () => null + } + `, + }, + { + // issue #3346 + code: ` + demo = function() {return function() {return null;};}; + `, + }, + { + // issue #3346 + code: ` + demo = { + property: function() {return function() {return null;};} + } + `, + }, { // issue #3303 code: ` @@ -1141,5 +1169,33 @@ ruleTester.run('display-name', rule, { }, ], }, + { + code: ` + Demo = () => () => null; + `, + errors: [{ messageId: 'noDisplayName' }], + }, + { + code: ` + demo = { + Property: () => () => null + } + `, + errors: [{ messageId: 'noDisplayName' }], + }, + { + code: ` + Demo = function() {return function() {return null;};}; + `, + errors: [{ messageId: 'noDisplayName' }], + }, + { + code: ` + demo = { + Property: function() {return function() {return null;};} + } + `, + errors: [{ messageId: 'noDisplayName' }], + }, ]), });