From 0007168800da11757f2d1d97bded8940f2adbc43 Mon Sep 17 00:00:00 2001 From: Eric Morand Date: Mon, 6 Jan 2025 17:30:29 +0100 Subject: [PATCH] JS-20 - Fix FP S6754 (`hook-use-state`): Add exception when using `useState` for components --- .../expected/jsts/eigen/typescript-S6754.json | 3 -- packages/jsts/src/rules/S6754/decorator.ts | 28 +++++++++++++++-- packages/jsts/src/rules/S6754/unit.test.ts | 30 +++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/its/ruling/src/test/expected/jsts/eigen/typescript-S6754.json b/its/ruling/src/test/expected/jsts/eigen/typescript-S6754.json index c191cbe8d56..ecbb9c0bc36 100644 --- a/its/ruling/src/test/expected/jsts/eigen/typescript-S6754.json +++ b/its/ruling/src/test/expected/jsts/eigen/typescript-S6754.json @@ -33,9 +33,6 @@ 17, 18 ], -"eigen:src/app/Scenes/Inbox/Components/Conversations/CTAPopUp.tsx": [ -5 -], "eigen:src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/Rarity.tsx": [ 13 ], diff --git a/packages/jsts/src/rules/S6754/decorator.ts b/packages/jsts/src/rules/S6754/decorator.ts index 170866c19ac..294663f78c0 100644 --- a/packages/jsts/src/rules/S6754/decorator.ts +++ b/packages/jsts/src/rules/S6754/decorator.ts @@ -19,6 +19,7 @@ import type { Rule } from 'eslint'; import { generateMeta, interceptReportForReact } from '../helpers/index.js'; import { meta } from './meta.js'; +import { Node } from 'estree'; export function decorate(rule: Rule.RuleModule): Rule.RuleModule { return interceptReportForReact( @@ -27,10 +28,31 @@ export function decorate(rule: Rule.RuleModule): Rule.RuleModule { meta: generateMeta(meta as Rule.RuleMetaData, rule.meta), }, (context, descriptor) => { - const { node } = descriptor as any; - if (node.type === 'ArrayPattern' && node.elements.length === 1) { - return; + const { node } = descriptor as { + node: Node; + }; + + if (node.type === 'ArrayPattern') { + if (node.elements.length === 1) { + return; + } + + const [getter, setter] = node.elements; + + if (getter?.type === 'Identifier' && setter?.type === 'Identifier') { + const getterName = getter.name; + const setterName = setter.name; + const setterPrefix = 'set'; + + if ( + setterName.startsWith(setterPrefix) && + setterName.substring(setterPrefix.length) === getterName + ) { + return; + } + } } + context.report(descriptor); }, ); diff --git a/packages/jsts/src/rules/S6754/unit.test.ts b/packages/jsts/src/rules/S6754/unit.test.ts index aa99d4eff9b..6be9e299015 100644 --- a/packages/jsts/src/rules/S6754/unit.test.ts +++ b/packages/jsts/src/rules/S6754/unit.test.ts @@ -33,6 +33,20 @@ ruleTester.run( return [foo]; }`, }, + { + code: ` + import { useState } from 'react'; + function useFoo() { + const [foo, setFoo] = useState(); + }`, + }, + { + code: ` + import { useState } from 'react'; + function useFoo() { + const [Foo, setFoo] = useState(); + }`, + }, ], invalid: [ { @@ -44,6 +58,22 @@ ruleTester.run( }`, errors: 1, }, + { + code: `import { useState } from 'react'; + + function foo() { + [client.searchState, client.setSearchState] = useState(baseState); +}`, + errors: 1, + }, + { + code: ` + import { useState } from 'react'; + function useFoo() { + const getterAndSetter = useState(); + }`, + errors: 1, + }, ], }, );