From 5c182e669e1bfecb52b09e5a273fc1df5569c7b0 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Thu, 5 Jun 2025 14:22:43 +0800 Subject: [PATCH 1/4] fix(typescript-estree): add validation to interface extends --- .../snapshots/1-TSESTree-Error.shot | 5 ++- .../snapshots/3-Alignment-Error.shot | 2 +- .../snapshots/1-TSESTree-Error.shot | 7 +++- .../snapshots/3-Alignment-Error.shot | 2 +- .../fixtures-with-differences-errors.shot | 2 -- packages/typescript-estree/src/convert.ts | 33 +++++++++++++++++++ 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/1-TSESTree-Error.shot index 3192c89d0208..70781ef9b372 100644 --- a/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/1-TSESTree-Error.shot +++ b/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/1-TSESTree-Error.shot @@ -1,4 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`AST Fixtures > declaration > TSInterfaceDeclaration > _error_ > non-identifier-extends > TSESTree - Error`] -NO ERROR +TSError +> 1 | interface F extends 1 {} + | ^ Interface declaration can only extend an identifier/qualified name with optional type arguments. + 2 | diff --git a/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/3-Alignment-Error.shot index 8b8a05459c4b..a0844838800f 100644 --- a/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/3-Alignment-Error.shot +++ b/packages/ast-spec/src/declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/snapshots/3-Alignment-Error.shot @@ -1,4 +1,4 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`AST Fixtures > declaration > TSInterfaceDeclaration > _error_ > non-identifier-extends > Error Alignment`] -Babel errored but TSESTree didn't +Both errored diff --git a/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/1-TSESTree-Error.shot index b9716b289515..f57a1b692cd1 100644 --- a/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/1-TSESTree-Error.shot +++ b/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/1-TSESTree-Error.shot @@ -1,4 +1,9 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`AST Fixtures > legacy-fixtures > errorRecovery > _error_ > interface-multiple-extends > TSESTree - Error`] -NO ERROR +TSError + 1 | // TODO: This fixture might be too large, and if so should be split up. + 2 | +> 3 | interface foo extends bar extends baz {} + | ^^^^^^^^^^^ 'extends' clause already seen. + 4 | diff --git a/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/3-Alignment-Error.shot index 8c05c9ec9327..2b5ef310d7cd 100644 --- a/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/3-Alignment-Error.shot +++ b/packages/ast-spec/src/legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/snapshots/3-Alignment-Error.shot @@ -1,4 +1,4 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`AST Fixtures > legacy-fixtures > errorRecovery > _error_ > interface-multiple-extends > Error Alignment`] -Babel errored but TSESTree didn't +Both errored diff --git a/packages/ast-spec/tests/fixtures-with-differences-errors.shot b/packages/ast-spec/tests/fixtures-with-differences-errors.shot index ef7f47117298..7051aa777fbb 100644 --- a/packages/ast-spec/tests/fixtures-with-differences-errors.shot +++ b/packages/ast-spec/tests/fixtures-with-differences-errors.shot @@ -12,7 +12,6 @@ exports[`AST Fixtures > List fixtures with Error differences`] "declaration/TSImportEqualsDeclaration/fixtures/_error_/import-kind/fixture.ts", "declaration/TSInterfaceDeclaration/fixtures/_error_/missing-extends/fixture.ts", "declaration/TSInterfaceDeclaration/fixtures/_error_/missing-type-param/fixture.ts", - "declaration/TSInterfaceDeclaration/fixtures/_error_/non-identifier-extends/fixture.ts", "declaration/TSTypeAliasDeclaration/fixtures/_error_/missing-type-parameter/fixture.ts", "declaration/VariableDeclaration/fixtures/_error_/const-destructure-no-init/fixture.ts", "declaration/VariableDeclaration/fixtures/_error_/const-destructure-type-no-init/fixture.ts", @@ -45,7 +44,6 @@ exports[`AST Fixtures > List fixtures with Error differences`] "legacy-fixtures/errorRecovery/fixtures/_error_/empty-type-parameters/fixture.ts", "legacy-fixtures/errorRecovery/fixtures/_error_/index-signature-parameters/fixture.ts", "legacy-fixtures/errorRecovery/fixtures/_error_/interface-empty-extends/fixture.ts", - "legacy-fixtures/errorRecovery/fixtures/_error_/interface-multiple-extends/fixture.ts", "legacy-fixtures/errorRecovery/fixtures/_error_/interface-with-optional-index-signature/fixture.ts", "legacy-fixtures/parameter-decorators/fixtures/_error_/parameter-array-pattern-decorator/fixture.ts", "legacy-fixtures/parameter-decorators/fixtures/_error_/parameter-rest-element-decorator/fixture.ts", diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 22c0257505a2..8f293db2af02 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -70,6 +70,25 @@ export interface ASTMaps { tsNodeToESTreeNodeMap: ParserWeakMap; } +function isPropertyAccessEntityNameExpression( + node: ts.Node, +): node is ts.PropertyAccessEntityNameExpression { + return ( + ts.isPropertyAccessExpression(node) && + ts.isIdentifier(node.name) && + isEntityNameExpression(node.expression) + ); +} + +function isEntityNameExpression( + node: ts.Node, +): node is ts.EntityNameExpression { + return ( + node.kind === SyntaxKind.Identifier || + isPropertyAccessEntityNameExpression(node) + ); +} + export class Converter { private allowPattern = false; private readonly ast: ts.SourceFile; @@ -3024,6 +3043,7 @@ export class Converter { const interfaceHeritageClauses = node.heritageClauses ?? []; const interfaceExtends: TSESTree.TSInterfaceHeritage[] = []; + let seenExtendsClause = false; for (const heritageClause of interfaceHeritageClauses) { if (heritageClause.token !== SyntaxKind.ExtendsKeyword) { this.#throwError( @@ -3033,8 +3053,21 @@ export class Converter { : 'Unexpected token.', ); } + if (seenExtendsClause) { + this.#throwError(heritageClause, "'extends' clause already seen."); + } + seenExtendsClause = true; for (const heritageType of heritageClause.types) { + if ( + !isEntityNameExpression(heritageType.expression) || + ts.isOptionalChain(heritageType.expression) + ) { + this.#throwError( + heritageType, + 'Interface declaration can only extend an identifier/qualified name with optional type arguments.', + ); + } interfaceExtends.push( this.convertChild( heritageType, From 7e5ac008127b567748f230a6e7de0fb10fcbfb78 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Thu, 5 Jun 2025 17:07:02 +0800 Subject: [PATCH 2/4] remove an outdated test case --- .../no-unused-vars/no-unused-vars.test.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts index 5ebc8d9a406b..5f40bbcdc3cc 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts @@ -360,25 +360,6 @@ export interface Bar extends baz.test {} code: ` import test from 'test'; import baz from 'baz'; -export interface Bar extends baz().test {} - `, - errors: [ - { - column: 8, - data: { - action: 'defined', - additional: '', - varName: 'test', - }, - line: 2, - messageId: 'unusedVar', - }, - ], - }, - { - code: ` -import test from 'test'; -import baz from 'baz'; export class Bar implements baz.test {} `, errors: [ From 2332e9680fdcc89b544e2f39c0605f57d3c2717a Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Thu, 5 Jun 2025 20:03:55 +0800 Subject: [PATCH 3/4] increase the patch coverage --- .../tests/lib/convert.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/typescript-estree/tests/lib/convert.test.ts b/packages/typescript-estree/tests/lib/convert.test.ts index 77dea1f5f4b4..97ba346c5e79 100644 --- a/packages/typescript-estree/tests/lib/convert.test.ts +++ b/packages/typescript-estree/tests/lib/convert.test.ts @@ -449,4 +449,25 @@ describe('convert', () => { expect(Object.keys(tsMappedType)).toContain('typeParameter'); }); }); + + describe('should throw error for invalid interface extends clauses', () => { + it('should throw error for multiple extends', () => { + const code = 'interface Foo extends Bar extends Bar {}'; + + const instance = new Converter(convertCode(code)); + + expect(() => instance.convertProgram()).toThrow( + "'extends' clause already seen.", + ); + }); + it('should throw error for optional chain', () => { + const code = 'interface Foo extends Bar?.Bar {}'; + + const instance = new Converter(convertCode(code)); + + expect(() => instance.convertProgram()).toThrow( + 'Interface declaration can only extend an identifier/qualified name with optional type arguments.', + ); + }); + }); }); From 50fea5e80966b2b84ecd3588639100465f17c0ec Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 9 Jun 2025 16:43:45 +0930 Subject: [PATCH 4/4] Discard changes to packages/typescript-estree/tests/lib/convert.test.ts --- .../tests/lib/convert.test.ts | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/packages/typescript-estree/tests/lib/convert.test.ts b/packages/typescript-estree/tests/lib/convert.test.ts index 97ba346c5e79..77dea1f5f4b4 100644 --- a/packages/typescript-estree/tests/lib/convert.test.ts +++ b/packages/typescript-estree/tests/lib/convert.test.ts @@ -449,25 +449,4 @@ describe('convert', () => { expect(Object.keys(tsMappedType)).toContain('typeParameter'); }); }); - - describe('should throw error for invalid interface extends clauses', () => { - it('should throw error for multiple extends', () => { - const code = 'interface Foo extends Bar extends Bar {}'; - - const instance = new Converter(convertCode(code)); - - expect(() => instance.convertProgram()).toThrow( - "'extends' clause already seen.", - ); - }); - it('should throw error for optional chain', () => { - const code = 'interface Foo extends Bar?.Bar {}'; - - const instance = new Converter(convertCode(code)); - - expect(() => instance.convertProgram()).toThrow( - 'Interface declaration can only extend an identifier/qualified name with optional type arguments.', - ); - }); - }); }); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy