From c83369322e4b89561ee6af8ed50dbb03bb3d3f15 Mon Sep 17 00:00:00 2001 From: auvred Date: Thu, 1 Feb 2024 09:48:07 +0300 Subject: [PATCH 1/2] fix(eslint-plugin): [consistent-type-imports] dont report on types used in export assignment expressions --- .../src/rules/consistent-type-imports.ts | 5 +- .../rules/consistent-type-imports.test.ts | 52 +++++++++++++++++++ .../src/referencer/Referencer.ts | 6 ++- .../tests/fixtures/export/equals4-type.ts | 3 ++ .../fixtures/export/equals4-type.ts.shot | 49 +++++++++++++++++ 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 packages/scope-manager/tests/fixtures/export/equals4-type.ts create mode 100644 packages/scope-manager/tests/fixtures/export/equals4-type.ts.shot diff --git a/packages/eslint-plugin/src/rules/consistent-type-imports.ts b/packages/eslint-plugin/src/rules/consistent-type-imports.ts index 4bceed75f740..4ac3c011746d 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-imports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-imports.ts @@ -183,12 +183,15 @@ export default createRule({ * keep origin import kind when export * export { Type } * export default Type; + * export = Type; */ if ( ref.identifier.parent.type === AST_NODE_TYPES.ExportSpecifier || ref.identifier.parent.type === - AST_NODE_TYPES.ExportDefaultDeclaration + AST_NODE_TYPES.ExportDefaultDeclaration || + ref.identifier.parent.type === + AST_NODE_TYPES.TSExportAssignment ) { if (ref.isValueReference && ref.isTypeReference) { return node.importKind === 'type'; diff --git a/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts b/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts index 055f8473ee28..a9956f09fc4f 100644 --- a/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts @@ -566,6 +566,22 @@ export type Y = { [constants.X]: ReadonlyArray; }; `, + ` + import A from 'foo'; + export = A; + `, + ` + import type A from 'foo'; + export = A; + `, + ` + import type A from 'foo'; + export = {} as A; + `, + ` + import { type A } from 'foo'; + export = {} as A; + `, ], invalid: [ { @@ -2230,5 +2246,41 @@ let baz: D; }, ], }, + { + code: ` +import A from 'foo'; +export = {} as A; + `, + output: ` +import type A from 'foo'; +export = {} as A; + `, + options: [{ prefer: 'type-imports', fixStyle: 'inline-type-imports' }], + errors: [ + { + messageId: 'typeOverValue', + line: 2, + column: 1, + }, + ], + }, + { + code: ` +import { A } from 'foo'; +export = {} as A; + `, + output: ` +import { type A } from 'foo'; +export = {} as A; + `, + options: [{ prefer: 'type-imports', fixStyle: 'inline-type-imports' }], + errors: [ + { + messageId: 'typeOverValue', + line: 2, + column: 1, + }, + ], + }, ], }); diff --git a/packages/scope-manager/src/referencer/Referencer.ts b/packages/scope-manager/src/referencer/Referencer.ts index ddbdf7c61a4c..cbceaf15d40b 100644 --- a/packages/scope-manager/src/referencer/Referencer.ts +++ b/packages/scope-manager/src/referencer/Referencer.ts @@ -444,7 +444,11 @@ class Referencer extends Visitor { } protected TSExportAssignment(node: TSESTree.TSExportAssignment): void { - ExportVisitor.visit(this, node); + if (node.expression.type === AST_NODE_TYPES.Identifier) { + ExportVisitor.visit(this, node); + } else { + this.visit(node.expression); + } } protected ExportNamedDeclaration( diff --git a/packages/scope-manager/tests/fixtures/export/equals4-type.ts b/packages/scope-manager/tests/fixtures/export/equals4-type.ts new file mode 100644 index 000000000000..d0ea4b63da81 --- /dev/null +++ b/packages/scope-manager/tests/fixtures/export/equals4-type.ts @@ -0,0 +1,3 @@ +type T = 1; + +export = {} as T; diff --git a/packages/scope-manager/tests/fixtures/export/equals4-type.ts.shot b/packages/scope-manager/tests/fixtures/export/equals4-type.ts.shot new file mode 100644 index 000000000000..2741a680fa31 --- /dev/null +++ b/packages/scope-manager/tests/fixtures/export/equals4-type.ts.shot @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`export equals4-type 1`] = ` +ScopeManager { + variables: [ + ImplicitGlobalConstTypeVariable, + Variable$2 { + defs: [ + TypeDefinition$1 { + name: Identifier<"T">, + node: TSTypeAliasDeclaration$1, + }, + ], + name: "T", + references: [ + Reference$1 { + identifier: Identifier<"T">, + isRead: true, + isTypeReference: true, + isValueReference: false, + isWrite: false, + resolved: Variable$2, + }, + ], + isValueVariable: false, + isTypeVariable: true, + }, + ], + scopes: [ + GlobalScope$1 { + block: Program$2, + isStrict: false, + references: [ + Reference$1, + ], + set: Map { + "const" => ImplicitGlobalConstTypeVariable, + "T" => Variable$2, + }, + type: "global", + upper: null, + variables: [ + ImplicitGlobalConstTypeVariable, + Variable$2, + ], + }, + ], +} +`; From de9754f400229427567cbca4e74c98b4d3b0e621 Mon Sep 17 00:00:00 2001 From: auvred Date: Thu, 1 Feb 2024 12:49:50 +0300 Subject: [PATCH 2/2] create dual reference for identifiers in export assignment expressions --- .../scope-manager/src/referencer/ExportVisitor.ts | 12 ++---------- packages/scope-manager/src/referencer/Referencer.ts | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/scope-manager/src/referencer/ExportVisitor.ts b/packages/scope-manager/src/referencer/ExportVisitor.ts index 24d35b49dab2..1af3a81ca2c6 100644 --- a/packages/scope-manager/src/referencer/ExportVisitor.ts +++ b/packages/scope-manager/src/referencer/ExportVisitor.ts @@ -7,8 +7,7 @@ import { Visitor } from './Visitor'; type ExportNode = | TSESTree.ExportAllDeclaration | TSESTree.ExportDefaultDeclaration - | TSESTree.ExportNamedDeclaration - | TSESTree.TSExportAssignment; + | TSESTree.ExportNamedDeclaration; class ExportVisitor extends Visitor { readonly #referencer: Referencer; @@ -26,10 +25,7 @@ class ExportVisitor extends Visitor { } protected Identifier(node: TSESTree.Identifier): void { - if ( - this.#exportNode.type !== AST_NODE_TYPES.TSExportAssignment && - this.#exportNode.exportKind === 'type' - ) { + if (this.#exportNode.exportKind === 'type') { // export type { T }; // type exports can only reference types this.#referencer.currentScope().referenceType(node); @@ -53,10 +49,6 @@ class ExportVisitor extends Visitor { } } - protected TSExportAssignment(node: TSESTree.TSExportAssignment): void { - this.visit(node.expression); - } - protected ExportNamedDeclaration( node: TSESTree.ExportNamedDeclaration, ): void { diff --git a/packages/scope-manager/src/referencer/Referencer.ts b/packages/scope-manager/src/referencer/Referencer.ts index cbceaf15d40b..6082f4846611 100644 --- a/packages/scope-manager/src/referencer/Referencer.ts +++ b/packages/scope-manager/src/referencer/Referencer.ts @@ -445,7 +445,7 @@ class Referencer extends Visitor { protected TSExportAssignment(node: TSESTree.TSExportAssignment): void { if (node.expression.type === AST_NODE_TYPES.Identifier) { - ExportVisitor.visit(this, node); + this.currentScope().referenceDualValueType(node.expression); } else { this.visit(node.expression); }