From ab2916c046139a0024932de5bd9a8b0209cdd58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Sat, 8 Jun 2024 09:49:15 -0400 Subject: [PATCH] chore: enable eslint-plugin/no-property-in-node internally (#9261) * chore: enable eslint-plugin/no-property-in-node internally * commit yarn.lock changes --- ...n-eslint-plugin-npm-5.5.1-4206c2506d.patch | 12 ++++++++++ eslint.config.mjs | 1 + package.json | 3 ++- .../src/rules/adjacent-overload-signatures.ts | 20 ++++++++-------- .../src/rules/class-literal-property-style.ts | 21 +++++++++-------- .../src/rules/default-param-last.ts | 9 +++++++- packages/eslint-plugin/src/rules/indent.ts | 2 +- .../src/rules/member-ordering.ts | 8 +++++++ .../src/rules/naming-convention.ts | 3 +++ .../src/rules/no-extraneous-class.ts | 16 ++++++++++--- .../src/rules/no-inferrable-types.ts | 3 +-- .../eslint-plugin/src/rules/no-misused-new.ts | 23 +++++++++++++++---- .../eslint-plugin/src/rules/no-unused-vars.ts | 8 +++---- .../src/rules/no-useless-constructor.ts | 7 ++++-- .../rules/padding-line-between-statements.ts | 2 +- .../src/rules/prefer-as-const.ts | 2 +- .../src/rules/prefer-destructuring.ts | 4 +++- yarn.lock | 14 ++++++++++- 18 files changed, 116 insertions(+), 42 deletions(-) create mode 100644 .yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch diff --git a/.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch b/.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch new file mode 100644 index 000000000000..c8bc09c2dfe1 --- /dev/null +++ b/.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch @@ -0,0 +1,12 @@ +diff --git a/lib/rules/no-property-in-node.js b/lib/rules/no-property-in-node.js +index f3e2e0c829685213c7807b34158237f59142173c..11e54e8f6d69e0f06b27bb83ed96a96690b5ed9a 100644 +--- a/lib/rules/no-property-in-node.js ++++ b/lib/rules/no-property-in-node.js +@@ -3,6 +3,7 @@ + const typedNodeSourceFileTesters = [ + /@types[/\\]estree[/\\]index\.d\.ts/, + /@typescript-eslint[/\\]types[/\\]dist[/\\]generated[/\\]ast-spec\.d\.ts/, ++ /packages[/\\]types[/\\]dist[/\\]generated[/\\]ast-spec\.d\.ts/, + ]; + + /** diff --git a/eslint.config.mjs b/eslint.config.mjs index 5e32e82438f5..3e71ec470c9d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -430,6 +430,7 @@ export default tseslint.config( 'packages/eslint-plugin/src/rules/**/*.{ts,tsx,cts,mts}', ], rules: { + 'eslint-plugin/no-property-in-node': 'error', 'eslint-plugin/require-meta-docs-description': [ 'error', { pattern: '^(Enforce|Require|Disallow) .+[^. ]$' }, diff --git a/package.json b/package.json index 6693650e9d3a..a60e8634494d 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,8 @@ "tmp": "0.2.1", "tsx": "^4.7.2", "typescript": "5.4.5", - "nx@18.3.5": "patch:nx@npm%3A18.3.5#./.yarn/patches/nx-npm-18.3.5-58c0bedf91.patch" + "nx@18.3.5": "patch:nx@npm%3A18.3.5#./.yarn/patches/nx-npm-18.3.5-58c0bedf91.patch", + "eslint-plugin-eslint-plugin@^5.5.0": "patch:eslint-plugin-eslint-plugin@npm%3A5.5.1#./.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch" }, "packageManager": "yarn@3.8.2" } diff --git a/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts b/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts index d55a3ad5fac3..f28472e73a7b 100644 --- a/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts +++ b/packages/eslint-plugin/src/rules/adjacent-overload-signatures.ts @@ -10,11 +10,16 @@ type RuleNode = | TSESTree.TSInterfaceBody | TSESTree.TSModuleBlock | TSESTree.TSTypeLiteral; + type Member = | TSESTree.ClassElement | TSESTree.ProgramStatement | TSESTree.TypeElement; +type MemberDeclaration = + | TSESTree.DefaultExportDeclarations + | TSESTree.NamedExportDeclarations; + export default createRule({ name: 'adjacent-overload-signatures', meta: { @@ -32,7 +37,7 @@ export default createRule({ create(context) { interface Method { name: string; - static: boolean; + static?: boolean; callSignature: boolean; type: MemberNameType; } @@ -42,9 +47,9 @@ export default createRule({ * @param member the member being processed. * @returns the name and attribute of the member or null if it's a member not relevant to the rule. */ - function getMemberMethod(member: TSESTree.Node): Method | null { - const isStatic = 'static' in member && !!member.static; - + function getMemberMethod( + member: Member | MemberDeclaration, + ): Method | null { switch (member.type) { case AST_NODE_TYPES.ExportDefaultDeclaration: case AST_NODE_TYPES.ExportNamedDeclaration: { @@ -64,7 +69,6 @@ export default createRule({ } return { name, - static: isStatic, callSignature: false, type: MemberNameType.Normal, }; @@ -72,27 +76,25 @@ export default createRule({ case AST_NODE_TYPES.TSMethodSignature: return { ...getNameFromMember(member, context.sourceCode), - static: isStatic, + static: !!member.static, callSignature: false, }; case AST_NODE_TYPES.TSCallSignatureDeclaration: return { name: 'call', - static: isStatic, callSignature: true, type: MemberNameType.Normal, }; case AST_NODE_TYPES.TSConstructSignatureDeclaration: return { name: 'new', - static: isStatic, callSignature: false, type: MemberNameType.Normal, }; case AST_NODE_TYPES.MethodDefinition: return { ...getNameFromMember(member, context.sourceCode), - static: isStatic, + static: !!member.static, callSignature: false, }; } diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts index 416267d2835e..6813e80f60d8 100644 --- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts +++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts @@ -37,18 +37,19 @@ const printNodeModifiers = ( const isSupportedLiteral = ( node: TSESTree.Node, ): node is TSESTree.LiteralExpression => { - if (node.type === AST_NODE_TYPES.Literal) { - return true; - } + switch (node.type) { + case AST_NODE_TYPES.Literal: + return true; - if ( - node.type === AST_NODE_TYPES.TaggedTemplateExpression || - node.type === AST_NODE_TYPES.TemplateLiteral - ) { - return ('quasi' in node ? node.quasi.quasis : node.quasis).length === 1; - } + case AST_NODE_TYPES.TaggedTemplateExpression: + return node.quasi.quasis.length === 1; - return false; + case AST_NODE_TYPES.TemplateLiteral: + return node.quasis.length === 1; + + default: + return false; + } }; export default createRule({ diff --git a/packages/eslint-plugin/src/rules/default-param-last.ts b/packages/eslint-plugin/src/rules/default-param-last.ts index b8638031ac5a..1340ecfa17b1 100644 --- a/packages/eslint-plugin/src/rules/default-param-last.ts +++ b/packages/eslint-plugin/src/rules/default-param-last.ts @@ -24,7 +24,14 @@ export default createRule({ * @private */ function isOptionalParam(node: TSESTree.Parameter): boolean { - return 'optional' in node && node.optional; + return ( + (node.type === AST_NODE_TYPES.ArrayPattern || + node.type === AST_NODE_TYPES.AssignmentPattern || + node.type === AST_NODE_TYPES.Identifier || + node.type === AST_NODE_TYPES.ObjectPattern || + node.type === AST_NODE_TYPES.RestElement) && + node.optional + ); } /** diff --git a/packages/eslint-plugin/src/rules/indent.ts b/packages/eslint-plugin/src/rules/indent.ts index 9ebb23d75844..248ecd0d7e8a 100644 --- a/packages/eslint-plugin/src/rules/indent.ts +++ b/packages/eslint-plugin/src/rules/indent.ts @@ -3,7 +3,7 @@ * This is due to some really funky type conversions between different node types. * This is done intentionally based on the internal implementation of the base indent rule. */ -/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, eslint-plugin/no-property-in-node */ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 3741b6b27b71..4713192770a7 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -1,3 +1,6 @@ +// This rule was feature-frozen before we enabled no-property-in-node. +/* eslint-disable eslint-plugin/no-property-in-node */ + import type { JSONSchema, TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import naturalCompare from 'natural-compare'; @@ -1064,6 +1067,11 @@ export default createRule({ // https://github.com/typescript-eslint/typescript-eslint/issues/5439 /* eslint-disable @typescript-eslint/no-non-null-assertion */ return { + 'ClassDeclaration, FunctionDeclaration'(node): void { + if ('superClass' in node) { + // ... + } + }, ClassDeclaration(node): void { validateMembersOrder( node.body.body, diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts index 635e1a625b80..c5c36436bc2e 100644 --- a/packages/eslint-plugin/src/rules/naming-convention.ts +++ b/packages/eslint-plugin/src/rules/naming-convention.ts @@ -1,3 +1,6 @@ +// This rule was feature-frozen before we enabled no-property-in-node. +/* eslint-disable eslint-plugin/no-property-in-node */ + import { PatternVisitor } from '@typescript-eslint/scope-manager'; import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils'; diff --git a/packages/eslint-plugin/src/rules/no-extraneous-class.ts b/packages/eslint-plugin/src/rules/no-extraneous-class.ts index 009da2a21a75..528c0e998cb4 100644 --- a/packages/eslint-plugin/src/rules/no-extraneous-class.ts +++ b/packages/eslint-plugin/src/rules/no-extraneous-class.ts @@ -87,7 +87,10 @@ export default createRule({ return; } - const reportNode = 'id' in parent && parent.id ? parent.id : parent; + const reportNode = + parent.type === AST_NODE_TYPES.ClassDeclaration && parent.id + ? parent.id + : parent; if (node.body.length === 0) { if (allowEmpty) { return; @@ -105,7 +108,10 @@ export default createRule({ let onlyConstructor = true; for (const prop of node.body) { - if ('kind' in prop && prop.kind === 'constructor') { + if ( + prop.type === AST_NODE_TYPES.MethodDefinition && + prop.kind === 'constructor' + ) { if ( prop.value.params.some( param => param.type === AST_NODE_TYPES.TSParameterProperty, @@ -116,7 +122,11 @@ export default createRule({ } } else { onlyConstructor = false; - if ('static' in prop && !prop.static) { + if ( + (prop.type === AST_NODE_TYPES.PropertyDefinition || + prop.type === AST_NODE_TYPES.MethodDefinition) && + !prop.static + ) { onlyStatic = false; } } diff --git a/packages/eslint-plugin/src/rules/no-inferrable-types.ts b/packages/eslint-plugin/src/rules/no-inferrable-types.ts index 7455675f6ac7..51ead2ae476a 100644 --- a/packages/eslint-plugin/src/rules/no-inferrable-types.ts +++ b/packages/eslint-plugin/src/rules/no-inferrable-types.ts @@ -120,8 +120,7 @@ export default createRule({ return ( isFunctionCall(unwrappedInit, 'BigInt') || - (unwrappedInit.type === AST_NODE_TYPES.Literal && - 'bigint' in unwrappedInit) + unwrappedInit.type === AST_NODE_TYPES.Literal ); } diff --git a/packages/eslint-plugin/src/rules/no-misused-new.ts b/packages/eslint-plugin/src/rules/no-misused-new.ts index 049101a110e0..932a85cc6080 100644 --- a/packages/eslint-plugin/src/rules/no-misused-new.ts +++ b/packages/eslint-plugin/src/rules/no-misused-new.ts @@ -50,14 +50,20 @@ export default createRule({ * @param returnType type to be compared */ function isMatchingParentType( - parent: TSESTree.Node | undefined, + parent: + | TSESTree.TSInterfaceDeclaration + | TSESTree.ClassDeclaration + | TSESTree.ClassExpression + | TSESTree.Identifier + | undefined, returnType: TSESTree.TSTypeAnnotation | undefined, ): boolean { if ( parent && - 'id' in parent && - parent.id && - parent.id.type === AST_NODE_TYPES.Identifier + (parent.type === AST_NODE_TYPES.ClassDeclaration || + parent.type === AST_NODE_TYPES.ClassExpression || + parent.type === AST_NODE_TYPES.TSInterfaceDeclaration) && + parent.id ) { return getTypeReferenceName(returnType) === parent.id.name; } @@ -93,7 +99,14 @@ export default createRule({ node: TSESTree.MethodDefinition, ): void { if (node.value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression) { - if (isMatchingParentType(node.parent.parent, node.value.returnType)) { + if ( + isMatchingParentType( + node.parent.parent as + | TSESTree.ClassDeclaration + | TSESTree.ClassExpression, + node.value.returnType, + ) + ) { context.report({ node, messageId: 'errorMessageClass', diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index 3f6c18f3f0c6..402e83763440 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -227,7 +227,7 @@ export default createRule({ if ( (def.name.parent.type === AST_NODE_TYPES.ArrayPattern || refUsedInArrayPatterns) && - 'name' in def.name && + def.name.type === AST_NODE_TYPES.Identifier && options.destructuredArrayIgnorePattern?.test(def.name.name) ) { continue; @@ -240,7 +240,7 @@ export default createRule({ } // skip ignored parameters if ( - 'name' in def.name && + def.name.type === AST_NODE_TYPES.Identifier && options.caughtErrorsIgnorePattern?.test(def.name.name) ) { continue; @@ -254,7 +254,7 @@ export default createRule({ } // skip ignored parameters if ( - 'name' in def.name && + def.name.type === AST_NODE_TYPES.Identifier && options.argsIgnorePattern?.test(def.name.name) ) { continue; @@ -270,7 +270,7 @@ export default createRule({ } else { // skip ignored variables if ( - 'name' in def.name && + def.name.type === AST_NODE_TYPES.Identifier && options.varsIgnorePattern?.test(def.name.name) ) { continue; diff --git a/packages/eslint-plugin/src/rules/no-useless-constructor.ts b/packages/eslint-plugin/src/rules/no-useless-constructor.ts index f7d4970a381d..dcfc7dd976de 100644 --- a/packages/eslint-plugin/src/rules/no-useless-constructor.ts +++ b/packages/eslint-plugin/src/rules/no-useless-constructor.ts @@ -24,8 +24,11 @@ function checkAccessibility(node: TSESTree.MethodDefinition): boolean { case 'public': if ( node.parent.type === AST_NODE_TYPES.ClassBody && - 'superClass' in node.parent.parent && - node.parent.parent.superClass + ( + node.parent.parent as + | TSESTree.ClassDeclaration + | TSESTree.ClassExpression + ).superClass ) { return false; } diff --git a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts index 20d6b8e1dfd4..ecd87a06a643 100644 --- a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts +++ b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/no-non-null-assertion, eslint-plugin/no-property-in-node */ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index f13430b59fed..f3bcaf2963af 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -32,7 +32,7 @@ export default createRule({ if ( valueNode.type === AST_NODE_TYPES.Literal && typeNode.type === AST_NODE_TYPES.TSLiteralType && - 'raw' in typeNode.literal && + typeNode.literal.type === AST_NODE_TYPES.Literal && valueNode.raw === typeNode.literal.raw ) { if (canFix) { diff --git a/packages/eslint-plugin/src/rules/prefer-destructuring.ts b/packages/eslint-plugin/src/rules/prefer-destructuring.ts index 41a4db152543..60e53dbb61e6 100644 --- a/packages/eslint-plugin/src/rules/prefer-destructuring.ts +++ b/packages/eslint-plugin/src/rules/prefer-destructuring.ts @@ -121,7 +121,9 @@ export default createRule({ ? baseRules : baseRulesWithoutFix(); if ( - 'typeAnnotation' in leftNode && + (leftNode.type === AST_NODE_TYPES.ArrayPattern || + leftNode.type === AST_NODE_TYPES.Identifier || + leftNode.type === AST_NODE_TYPES.ObjectPattern) && leftNode.typeAnnotation !== undefined && !enforceForDeclarationWithTypeAnnotation ) { diff --git a/yarn.lock b/yarn.lock index 5ff9c78c9388..bb68e27229fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9808,7 +9808,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-eslint-plugin@npm:^5.5.0": +"eslint-plugin-eslint-plugin@npm:5.5.1": version: 5.5.1 resolution: "eslint-plugin-eslint-plugin@npm:5.5.1" dependencies: @@ -9820,6 +9820,18 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-eslint-plugin@patch:eslint-plugin-eslint-plugin@npm%3A5.5.1#./.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch::locator=%40typescript-eslint%2Ftypescript-eslint%40workspace%3A.": + version: 5.5.1 + resolution: "eslint-plugin-eslint-plugin@patch:eslint-plugin-eslint-plugin@npm%3A5.5.1#./.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch::version=5.5.1&hash=0c6729&locator=%40typescript-eslint%2Ftypescript-eslint%40workspace%3A." + dependencies: + eslint-utils: ^3.0.0 + estraverse: ^5.3.0 + peerDependencies: + eslint: ">=7.0.0" + checksum: d46fb241fbcff5c7a9ec44c6f19930ad7bd2394c0cadb75a97bb151c86fc506da9dfbbcf34ec41151abf2024151945a0dd6ba9b031a3d75e87e58e7f267bf488 + languageName: node + linkType: hard + "eslint-plugin-import@npm:^2.29.1": version: 2.29.1 resolution: "eslint-plugin-import@npm:2.29.1"