From 9119153fea58499958d9b40983f7aa0c302920f9 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelbaset Date: Fri, 16 Aug 2024 19:35:41 +0300 Subject: [PATCH] handle defs outside the scope --- src/index.ts | 2 +- src/rules/no-phyisical-properties/test.ts | 110 +++++++++++++++++++++- src/utils/ast.ts | 35 +++++-- vitest.config.ts | 2 +- 4 files changed, 140 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index efb4f42..b4386a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import type { FlatConfig } from "@typescript-eslint/utils/ts-eslint"; -import { noPhysicalProperties } from "./rules/no-phyisical-properties/rule"; import { name, version } from "../package.json"; +import { noPhysicalProperties } from "./rules/no-phyisical-properties/rule"; const rtlFriendly = { meta: { name, version }, diff --git a/src/rules/no-phyisical-properties/test.ts b/src/rules/no-phyisical-properties/test.ts index 3817c55..799841f 100644 --- a/src/rules/no-phyisical-properties/test.ts +++ b/src/rules/no-phyisical-properties/test.ts @@ -216,7 +216,16 @@ vitest.describe(RULE_NAME, () => { }); tester.run("Look for variable decleration", noPhysicalProperties, { - valid: [], + valid: [ + { + name: "function arg", + code: ` + function Comp({className}) { + return
+ } + `, + }, + ], invalid: [ { name: "className={variable}", @@ -244,6 +253,105 @@ vitest.describe(RULE_NAME, () => { `, errors: [{ messageId: NO_PHYSICAL_CLASSESS }], }, + { + name: "let b = '...'", + code: ` + let b = "text-left"; +
+ `, + output: ` + let b = "text-start"; +
+ `, + errors: [{ messageId: NO_PHYSICAL_CLASSESS }], + }, + { + name: "let b = '...'; b = '...'", + code: ` + let b = "text-left"; + b = "text-right"; +
+ `, + output: ` + let b = "text-start"; + b = "text-end"; +
+ `, + errors: [ + { messageId: NO_PHYSICAL_CLASSESS }, + { messageId: NO_PHYSICAL_CLASSESS }, + ], + }, + { + name: "Outside the scope", + code: ` + const cls = "left-2"; + function Comp() { + return
+ } + `, + output: ` + const cls = "start-2"; + function Comp() { + return
+ } + `, + errors: [{ messageId: NO_PHYSICAL_CLASSESS }], + }, + { + name: "Reassignment in a nested scope", + code: ` + let cls = "left-2"; + function Comp() { + cls = "text-left"; + return
+ } + `, + output: ` + let cls = "start-2"; + function Comp() { + cls = "text-start"; + return
+ } + `, + errors: [ + { messageId: NO_PHYSICAL_CLASSESS }, + { messageId: NO_PHYSICAL_CLASSESS }, + ], + }, + { + name: "Don't conflict with other vars with the same name", + code: ` + const cls = "left-2"; + function Comp() { + const cls = "text-left"; + return
+ } + `, + output: ` + const cls = "left-2"; + function Comp() { + const cls = "text-start"; + return
+ } + `, + errors: [{ messageId: NO_PHYSICAL_CLASSESS }], + }, + { + name: "function arg", + code: ` + function Comp({ className = "text-left" }) { + return
+ } + `, + output: ` + function Comp({ className = "text-start" }) { + return
+ } + `, + errors: [{ messageId: NO_PHYSICAL_CLASSESS }], + skip: true, + }, ], }); diff --git a/src/utils/ast.ts b/src/utils/ast.ts index 9cd3dca..3defdfb 100644 --- a/src/utils/ast.ts +++ b/src/utils/ast.ts @@ -1,4 +1,5 @@ -import { TSESTree } from "@typescript-eslint/utils"; +import type { TSESTree } from "@typescript-eslint/utils"; +import type { Scope } from "@typescript-eslint/utils/ts-eslint"; import type { Context } from "../rules/no-phyisical-properties/rule"; const unimplemented = new Set(); @@ -50,7 +51,7 @@ export function extractTokensFromNode( return run(node.init); } - if (is(node, "ArrowFunctionExpression")) return run(node); + // if (is(node, "ArrowFunctionExpression")) return run(node); return []; } @@ -150,11 +151,12 @@ function extractTokensFromExpression( if (is(exp, "Identifier")) { // We should follow the identifier and get the value const scope = ctx.sourceCode.getScope(exp); - const binding = scope?.set.get(exp.name); - const node = binding?.defs[0].node; - if (!node) return []; - return extractTokensFromNode(node, ctx, runner); + const writes = getDefinitions(exp, ctx, scope).filter( + (r) => r?.type === "Literal" || r?.type === "Identifier" + ); + + return writes.flatMap((n) => rerun(n)); } if (is(exp, "MemberExpression")) { @@ -259,3 +261,24 @@ function is( ): exp is Extract { return exp.type === type; } + +function getDefinitions( + identifier: TSESTree.Identifier, + ctx: Context, + scope: Scope.Scope +) { + const writes = scope.references + .filter((r) => r.identifier.name === identifier.name && r.writeExpr) + .flatMap((r) => r.writeExpr); + + const defs = scope.set.get(identifier.name)?.defs ?? []; + if (!defs.length && scope.upper) { + const defs = getDefinitions(identifier, ctx, scope.upper); + writes.push(...defs); + } + + if (writes.length) return writes; + + if (scope.upper) return getDefinitions(identifier, ctx, scope.upper); + return []; +} diff --git a/vitest.config.ts b/vitest.config.ts index da90069..6a25499 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,6 +7,6 @@ export default defineConfig({ include: ["src/**/test.ts"], coverage: { include: ["src/**"], - } + }, }, });