From 02067be4fda8decdc0e9c8a0de18f3b3b0a26d8e Mon Sep 17 00:00:00 2001 From: Rel1cx Date: Tue, 2 Dec 2025 16:26:34 +0800 Subject: [PATCH] Fix forwardRef's ref should be excluded from check, closes #1332 --- .pkgs/function-rules/package.json | 2 +- package.json | 2 +- packages/core/package.json | 2 +- .../eslint-plugin-react-debug/package.json | 2 +- .../eslint-plugin-react-dom/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../eslint-plugin-react-web-api/package.json | 2 +- .../eslint-plugin-react-x/package.json | 2 +- .../prefer-destructuring-assignment.spec.ts | 1 + .../rules/prefer-destructuring-assignment.ts | 34 +++------ packages/plugins/eslint-plugin/README.md | 4 +- packages/plugins/eslint-plugin/package.json | 2 +- packages/shared/package.json | 2 +- packages/utilities/ast/package.json | 2 +- packages/utilities/eff/package.json | 2 +- packages/utilities/var/package.json | 2 +- pnpm-lock.yaml | 70 +++++++++---------- 18 files changed, 60 insertions(+), 77 deletions(-) diff --git a/.pkgs/function-rules/package.json b/.pkgs/function-rules/package.json index 0c3f1bd079..5ade91a7b6 100644 --- a/.pkgs/function-rules/package.json +++ b/.pkgs/function-rules/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "eslint": "^9.39.1", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^9.39.1", diff --git a/package.json b/package.json index a0639ebbd4..a85201bdeb 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "sort-package-json": "^3.5.0", "tinyglobby": "^0.2.15", "ts-pattern": "^5.9.0", - "tsdown": "^0.17.0-beta.4", + "tsdown": "^0.17.0-beta.5", "tsx": "^4.21.0", "type-fest": "^5.2.0", "typedoc": "^0.28.15", diff --git a/packages/core/package.json b/packages/core/package.json index 4ab7283048..88b9418f01 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -53,7 +53,7 @@ }, "devDependencies": { "@local/configs": "workspace:*", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "engines": { "node": ">=20.19.0" diff --git a/packages/plugins/eslint-plugin-react-debug/package.json b/packages/plugins/eslint-plugin-react-debug/package.json index 7536e36d7c..ddd1698c8d 100644 --- a/packages/plugins/eslint-plugin-react-debug/package.json +++ b/packages/plugins/eslint-plugin-react-debug/package.json @@ -60,7 +60,7 @@ "@local/configs": "workspace:*", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/plugins/eslint-plugin-react-dom/package.json b/packages/plugins/eslint-plugin-react-dom/package.json index 3d6dc8320f..36c7776de2 100644 --- a/packages/plugins/eslint-plugin-react-dom/package.json +++ b/packages/plugins/eslint-plugin-react-dom/package.json @@ -60,7 +60,7 @@ "@local/configs": "workspace:*", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/plugins/eslint-plugin-react-hooks-extra/package.json b/packages/plugins/eslint-plugin-react-hooks-extra/package.json index aec0ec5d6f..c724772469 100644 --- a/packages/plugins/eslint-plugin-react-hooks-extra/package.json +++ b/packages/plugins/eslint-plugin-react-hooks-extra/package.json @@ -61,7 +61,7 @@ "@local/configs": "workspace:*", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/plugins/eslint-plugin-react-naming-convention/package.json b/packages/plugins/eslint-plugin-react-naming-convention/package.json index dfad1532b8..a990724197 100644 --- a/packages/plugins/eslint-plugin-react-naming-convention/package.json +++ b/packages/plugins/eslint-plugin-react-naming-convention/package.json @@ -60,7 +60,7 @@ "@local/configs": "workspace:*", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/plugins/eslint-plugin-react-web-api/package.json b/packages/plugins/eslint-plugin-react-web-api/package.json index 0738150859..e34bc0060f 100644 --- a/packages/plugins/eslint-plugin-react-web-api/package.json +++ b/packages/plugins/eslint-plugin-react-web-api/package.json @@ -59,7 +59,7 @@ "@local/configs": "workspace:*", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/plugins/eslint-plugin-react-x/package.json b/packages/plugins/eslint-plugin-react-x/package.json index 8d40f49160..b1a4ee81db 100644 --- a/packages/plugins/eslint-plugin-react-x/package.json +++ b/packages/plugins/eslint-plugin-react-x/package.json @@ -62,7 +62,7 @@ "@local/configs": "workspace:*", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.spec.ts index 6ce534ddc6..a45ccf6424 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.spec.ts @@ -272,6 +272,7 @@ ruleTester.run(RULE_NAME, rule, { export const App = memo( forwardRef( function App({ day }, ref) { + const onClick = () => { console.log(ref.current) }; return
{day}
; } ) diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.ts b/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.ts index 3a711a96f0..d191c6cac8 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.ts @@ -41,7 +41,7 @@ export default createRule<[], MessageID>({ export function create(context: RuleContext): RuleListener { const { ctx, listeners } = useComponentCollector(context); // Store all member expressions with their scope - const memberExpressionWithNames: [Scope, MemberExpressionWithObjectName][] = []; + const exprs: [Scope, MemberExpressionWithObjectName][] = []; return { ...listeners, @@ -50,17 +50,13 @@ export function create(context: RuleContext): RuleListener { if (isMemberExpressionWithObjectName(node)) { const scope = context.sourceCode.getScope(node); - memberExpressionWithNames.push([scope, node]); + exprs.push([scope, node]); } }, // After traversing the whole AST, check the collected member expressions "Program:exit"(program) { - const components = [ - ...ctx - .getAllComponents(program) - .values(), - ]; + const components = [...ctx.getAllComponents(program).values()]; // Check if a node is a function component collected by `useComponentCollector` function isFunctionComponent(block: TSESTree.Node): block is AST.TSESTreeFunction { if (!AST.isFunction(block)) { @@ -73,15 +69,11 @@ export function create(context: RuleContext): RuleListener { } // For each member expression, find its parent component - for (const [initialScope, memberExpression] of memberExpressionWithNames) { + for (const [initialScope, expr] of exprs) { let scope = initialScope; let isComponent = isFunctionComponent(scope.block); // Traverse up the scope chain to find the component scope - while ( - !isComponent - && scope.upper != null - && scope.upper !== scope - ) { + while (!isComponent && scope.upper != null && scope.upper !== scope) { scope = scope.upper; isComponent = isFunctionComponent(scope.block); } @@ -93,32 +85,22 @@ export function create(context: RuleContext): RuleListener { if (!("params" in component)) { continue; } - const [props, ctx] = component.params; + const props = component.params.at(0); // Check if a node is an identifier with the same name as the member expression's object const isMatch = (node: null | TSESTree.Node | undefined) => node != null && node.type === T.Identifier - && node.name === memberExpression.object.name; + && node.name === expr.object.name; // If the member expression's object is `props`, report an error if (isMatch(props)) { context.report({ messageId: "preferDestructuringAssignment", - node: memberExpression, + node: expr, data: { name: "props", }, }); } - // If the member expression's object is `context`, report an error - if (isMatch(ctx)) { - context.report({ - messageId: "preferDestructuringAssignment", - node: memberExpression, - data: { - name: "context", - }, - }); - } } }, }; diff --git a/packages/plugins/eslint-plugin/README.md b/packages/plugins/eslint-plugin/README.md index 506d2a9191..c7e628075f 100644 --- a/packages/plugins/eslint-plugin/README.md +++ b/packages/plugins/eslint-plugin/README.md @@ -191,8 +191,8 @@ This project is and will continue to maintain that 90% of the code is written by Contributions are welcome! -Please follow our [contributing guidelines](https://github.com/Rel1cx/eslint-react/tree/main/.github/CONTRIBUTING.md). +Please follow our [contributing guidelines](https://github.com/Rel1cx/eslint-react/tree/prefer-destructuring-assignment/.github/CONTRIBUTING.md). ## License -This project is licensed under the MIT License - see the [LICENSE](https://github.com/Rel1cx/eslint-react/tree/main/LICENSE) file for details. +This project is licensed under the MIT License - see the [LICENSE](https://github.com/Rel1cx/eslint-react/tree/prefer-destructuring-assignment/LICENSE) file for details. diff --git a/packages/plugins/eslint-plugin/package.json b/packages/plugins/eslint-plugin/package.json index af3ce21fbc..1f38ba1992 100644 --- a/packages/plugins/eslint-plugin/package.json +++ b/packages/plugins/eslint-plugin/package.json @@ -61,7 +61,7 @@ }, "devDependencies": { "@local/configs": "workspace:*", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", diff --git a/packages/shared/package.json b/packages/shared/package.json index 56549ccbbf..b20c906d8c 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -50,7 +50,7 @@ "@local/configs": "workspace:*", "@tsconfig/node22": "^22.0.5", "@types/picomatch": "^4.0.2", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "engines": { "node": ">=20.19.0" diff --git a/packages/utilities/ast/package.json b/packages/utilities/ast/package.json index 9cf3fba973..05a1f73523 100644 --- a/packages/utilities/ast/package.json +++ b/packages/utilities/ast/package.json @@ -48,7 +48,7 @@ }, "devDependencies": { "@local/configs": "workspace:*", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "engines": { "node": ">=20.19.0" diff --git a/packages/utilities/eff/package.json b/packages/utilities/eff/package.json index f41ba87456..6053a9329e 100644 --- a/packages/utilities/eff/package.json +++ b/packages/utilities/eff/package.json @@ -38,7 +38,7 @@ }, "devDependencies": { "@local/configs": "workspace:*", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "engines": { "node": ">=20.19.0" diff --git a/packages/utilities/var/package.json b/packages/utilities/var/package.json index 1a8fad584c..236d20a748 100644 --- a/packages/utilities/var/package.json +++ b/packages/utilities/var/package.json @@ -49,7 +49,7 @@ }, "devDependencies": { "@local/configs": "workspace:*", - "tsdown": "^0.17.0-beta.4" + "tsdown": "^0.17.0-beta.5" }, "engines": { "node": ">=20.19.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df52492f44..86be5cee6c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,8 +127,8 @@ importers: specifier: ^5.9.0 version: 5.9.0 tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -215,8 +215,8 @@ importers: specifier: ^9.39.1 version: 9.39.1(jiti@2.6.1) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) apps/website: dependencies: @@ -675,8 +675,8 @@ importers: specifier: workspace:* version: link:../../.pkgs/configs tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin: dependencies: @@ -727,8 +727,8 @@ importers: specifier: workspace:* version: link:../../../.pkgs/configs tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin-react-debug: dependencies: @@ -782,8 +782,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin-react-dom: dependencies: @@ -837,8 +837,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin-react-hooks-extra: dependencies: @@ -892,8 +892,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin-react-naming-convention: dependencies: @@ -947,8 +947,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin-react-web-api: dependencies: @@ -999,8 +999,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/plugins/eslint-plugin-react-x: dependencies: @@ -1063,8 +1063,8 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.7) tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/shared: dependencies: @@ -1097,8 +1097,8 @@ importers: specifier: ^4.0.2 version: 4.0.2 tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/utilities/ast: dependencies: @@ -1128,8 +1128,8 @@ importers: specifier: workspace:* version: link:../../../.pkgs/configs tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/utilities/eff: devDependencies: @@ -1137,8 +1137,8 @@ importers: specifier: workspace:* version: link:../../../.pkgs/configs tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages/utilities/var: dependencies: @@ -1171,8 +1171,8 @@ importers: specifier: workspace:* version: link:../../../.pkgs/configs tsdown: - specifier: ^0.17.0-beta.4 - version: 0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3) + specifier: ^0.17.0-beta.5 + version: 0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3) packages: @@ -4981,8 +4981,8 @@ packages: import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} - import-without-cache@0.1.3: - resolution: {integrity: sha512-OZH1TcBGBP1YGCFUVAV0cVLU9ULxE4cGEez1wMNdH5+UqmGdJP8uS5myn405d6iZRtjJwhxmkSR7/RgbaOqvLQ==} + import-without-cache@0.2.0: + resolution: {integrity: sha512-I662PbFnhZjlpMQKeOgmZiuCOfMXfdX0Q4vMjDQ9cxIiOKNUzWJobE1FA+5ulKTssXlY6GY8l7hJ6Sy+/I5AEA==} engines: {node: '>=20.19.0'} importx@0.5.2: @@ -6376,8 +6376,8 @@ packages: ts-pattern@5.9.0: resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} - tsdown@0.17.0-beta.4: - resolution: {integrity: sha512-/ECe7U9bYrgXTHpos7m0LdmgnY5gkhN3xwAbFWPdCaJ2EB5oRcy76dOkGeVPA7+EDd4cQ7ySq42oh9gI76ezeg==} + tsdown@0.17.0-beta.5: + resolution: {integrity: sha512-Rmu4kmNsyYA4aI+h2okJKYaxj04pIJHlTxyYRprKWYaR1QOqos+rDfz3N38Sb5kGDXoZJl67Kqokjdk+p5oZ2A==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -10798,7 +10798,7 @@ snapshots: import-meta-resolve@4.2.0: {} - import-without-cache@0.1.3: {} + import-without-cache@0.2.0: {} importx@0.5.2: dependencies: @@ -12554,13 +12554,13 @@ snapshots: ts-pattern@5.9.0: {} - tsdown@0.17.0-beta.4(publint@0.3.15)(typescript@5.9.3): + tsdown@0.17.0-beta.5(publint@0.3.15)(typescript@5.9.3): dependencies: ansis: 4.2.0 cac: 6.7.14 empathic: 2.0.0 hookable: 5.5.3 - import-without-cache: 0.1.3 + import-without-cache: 0.2.0 obug: 2.1.1 rolldown: 1.0.0-beta.52 rolldown-plugin-dts: 0.18.1(rolldown@1.0.0-beta.52)(typescript@5.9.3)