diff --git a/lib/rules/no-undef-components.js b/lib/rules/no-undef-components.js index dc58fd2e9..3ffe9cc3b 100644 --- a/lib/rules/no-undef-components.js +++ b/lib/rules/no-undef-components.js @@ -133,7 +133,29 @@ module.exports = { (scope) => scope.type === 'module' ) for (const variable of (moduleScope && moduleScope.variables) || []) { - if (variable.isTypeVariable) { + if ( + // Check for type definitions. e.g. type Foo = {} + (variable.isTypeVariable && !variable.isValueVariable) || + // type-only import seems to have isValueVariable set to true. So we need to check the actual Node. + (variable.defs.length > 0 && + variable.defs.every((def) => { + if (def.type !== 'ImportBinding') { + return false + } + if (def.parent.importKind === 'type') { + // check for `import type Foo from './xxx'` + return true + } + if ( + def.node.type === 'ImportSpecifier' && + def.node.importKind === 'type' + ) { + // check for `import { type Foo } from './xxx'` + return true + } + return false + })) + ) { scriptTypeOnlyNames.add(variable.name) } else { scriptVariableNames.add(variable.name) diff --git a/tests/lib/rules/no-undef-components.js b/tests/lib/rules/no-undef-components.js index fc3461e5a..5af9468fe 100644 --- a/tests/lib/rules/no-undef-components.js +++ b/tests/lib/rules/no-undef-components.js @@ -6,6 +6,7 @@ const RuleTester = require('eslint').RuleTester const rule = require('../../../lib/rules/no-undef-components') +const semver = require('semver') const tester = new RuleTester({ parser: require.resolve('vue-eslint-parser'), @@ -598,6 +599,26 @@ tester.run('no-undef-components', rule, { ` + }, + { + filename: 'test.vue', + code: ` + + + + `, + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + parser: require.resolve('@typescript-eslint/parser') + }, + parser: require.resolve('vue-eslint-parser') } ], invalid: [ @@ -661,9 +682,14 @@ tester.run('no-undef-components', rule, { } ] }, - { - filename: 'test.vue', - code: ` + ...(semver.gte( + require('@typescript-eslint/parser/package.json').version, + '5.0.0' + ) + ? [ + { + filename: 'test.vue', + code: ` + + `, parserOptions: { ecmaVersion: 6, @@ -692,32 +770,7 @@ tester.run('no-undef-components', rule, { { message: "The '' component has been used, but 'Foo' only refers to a type.", - line: 12 - }, - { - message: - "The '' component has been used, but 'HelloWorld1' only refers to a type.", - line: 13 - }, - { - message: - "The '' component has been used, but 'HelloWorld2' only refers to a type.", - line: 14 - }, - { - message: - "The '' component has been used, but 'HelloWorld3' only refers to a type.", - line: 15 - }, - { - message: - "The '' component has been used, but 'HelloWorld4' only refers to a type.", - line: 16 - }, - { - message: - "The '' component has been used, but 'HelloWorld5' only refers to a type.", - line: 17 + line: 7 } ] }, diff --git a/typings/eslint-plugin-vue/util-types/ast/es-ast.ts b/typings/eslint-plugin-vue/util-types/ast/es-ast.ts index f4dd208c3..b3d5b6e2e 100644 --- a/typings/eslint-plugin-vue/util-types/ast/es-ast.ts +++ b/typings/eslint-plugin-vue/util-types/ast/es-ast.ts @@ -274,6 +274,7 @@ export interface ImportSpecifier extends HasParentNode { type: 'ImportSpecifier' imported: Identifier local: Identifier + importKind?: 'type' | 'value' } export interface ImportDefaultSpecifier extends HasParentNode { type: 'ImportDefaultSpecifier'