Skip to content

Commit 30b1471

Browse files
authored
Fix false positives for script setup with ts (#1976)
* Fix false positives for script setup with ts * fix test for ts eslint v4
1 parent b1f1432 commit 30b1471

File tree

3 files changed

+106
-30
lines changed

3 files changed

+106
-30
lines changed

lib/rules/no-undef-components.js

+23-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,29 @@ module.exports = {
133133
(scope) => scope.type === 'module'
134134
)
135135
for (const variable of (moduleScope && moduleScope.variables) || []) {
136-
if (variable.isTypeVariable) {
136+
if (
137+
// Check for type definitions. e.g. type Foo = {}
138+
(variable.isTypeVariable && !variable.isValueVariable) ||
139+
// type-only import seems to have isValueVariable set to true. So we need to check the actual Node.
140+
(variable.defs.length > 0 &&
141+
variable.defs.every((def) => {
142+
if (def.type !== 'ImportBinding') {
143+
return false
144+
}
145+
if (def.parent.importKind === 'type') {
146+
// check for `import type Foo from './xxx'`
147+
return true
148+
}
149+
if (
150+
def.node.type === 'ImportSpecifier' &&
151+
def.node.importKind === 'type'
152+
) {
153+
// check for `import { type Foo } from './xxx'`
154+
return true
155+
}
156+
return false
157+
}))
158+
) {
137159
scriptTypeOnlyNames.add(variable.name)
138160
} else {
139161
scriptVariableNames.add(variable.name)

tests/lib/rules/no-undef-components.js

+82-29
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
const RuleTester = require('eslint').RuleTester
88
const rule = require('../../../lib/rules/no-undef-components')
9+
const semver = require('semver')
910

1011
const tester = new RuleTester({
1112
parser: require.resolve('vue-eslint-parser'),
@@ -598,6 +599,26 @@ tester.run('no-undef-components', rule, {
598599
<script setup>
599600
import TheModal from 'foo'
600601
</script>`
602+
},
603+
{
604+
filename: 'test.vue',
605+
code: `
606+
<script setup lang="ts">
607+
import Foo from './Foo.vue'
608+
import {HelloWorld1} from './components/HelloWorld'
609+
</script>
610+
611+
<template>
612+
<Foo />
613+
<HelloWorld1 />
614+
</template>
615+
`,
616+
parserOptions: {
617+
ecmaVersion: 6,
618+
sourceType: 'module',
619+
parser: require.resolve('@typescript-eslint/parser')
620+
},
621+
parser: require.resolve('vue-eslint-parser')
601622
}
602623
],
603624
invalid: [
@@ -661,9 +682,14 @@ tester.run('no-undef-components', rule, {
661682
}
662683
]
663684
},
664-
{
665-
filename: 'test.vue',
666-
code: `
685+
...(semver.gte(
686+
require('@typescript-eslint/parser/package.json').version,
687+
'5.0.0'
688+
)
689+
? [
690+
{
691+
filename: 'test.vue',
692+
code: `
667693
<script setup lang="ts">
668694
import type Foo from './Foo.vue'
669695
import type {HelloWorld1} from './components/HelloWorld'
@@ -681,6 +707,58 @@ tester.run('no-undef-components', rule, {
681707
<HelloWorld4 />
682708
<HelloWorld5 />
683709
</template>
710+
`,
711+
parserOptions: {
712+
ecmaVersion: 6,
713+
sourceType: 'module',
714+
parser: require.resolve('@typescript-eslint/parser')
715+
},
716+
parser: require.resolve('vue-eslint-parser'),
717+
errors: [
718+
{
719+
message:
720+
"The '<Foo>' component has been used, but 'Foo' only refers to a type.",
721+
line: 12
722+
},
723+
{
724+
message:
725+
"The '<HelloWorld1>' component has been used, but 'HelloWorld1' only refers to a type.",
726+
line: 13
727+
},
728+
{
729+
message:
730+
"The '<HelloWorld2>' component has been used, but 'HelloWorld2' only refers to a type.",
731+
line: 14
732+
},
733+
{
734+
message:
735+
"The '<HelloWorld3>' component has been used, but 'HelloWorld3' only refers to a type.",
736+
line: 15
737+
},
738+
{
739+
message:
740+
"The '<HelloWorld4>' component has been used, but 'HelloWorld4' only refers to a type.",
741+
line: 16
742+
},
743+
{
744+
message:
745+
"The '<HelloWorld5>' component has been used, but 'HelloWorld5' only refers to a type.",
746+
line: 17
747+
}
748+
]
749+
}
750+
]
751+
: []),
752+
{
753+
filename: 'test.vue',
754+
code: `
755+
<script setup lang="ts">
756+
type Foo = {}
757+
</script>
758+
759+
<template>
760+
<Foo />
761+
</template>
684762
`,
685763
parserOptions: {
686764
ecmaVersion: 6,
@@ -692,32 +770,7 @@ tester.run('no-undef-components', rule, {
692770
{
693771
message:
694772
"The '<Foo>' component has been used, but 'Foo' only refers to a type.",
695-
line: 12
696-
},
697-
{
698-
message:
699-
"The '<HelloWorld1>' component has been used, but 'HelloWorld1' only refers to a type.",
700-
line: 13
701-
},
702-
{
703-
message:
704-
"The '<HelloWorld2>' component has been used, but 'HelloWorld2' only refers to a type.",
705-
line: 14
706-
},
707-
{
708-
message:
709-
"The '<HelloWorld3>' component has been used, but 'HelloWorld3' only refers to a type.",
710-
line: 15
711-
},
712-
{
713-
message:
714-
"The '<HelloWorld4>' component has been used, but 'HelloWorld4' only refers to a type.",
715-
line: 16
716-
},
717-
{
718-
message:
719-
"The '<HelloWorld5>' component has been used, but 'HelloWorld5' only refers to a type.",
720-
line: 17
773+
line: 7
721774
}
722775
]
723776
},

typings/eslint-plugin-vue/util-types/ast/es-ast.ts

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ export interface ImportSpecifier extends HasParentNode {
274274
type: 'ImportSpecifier'
275275
imported: Identifier
276276
local: Identifier
277+
importKind?: 'type' | 'value'
277278
}
278279
export interface ImportDefaultSpecifier extends HasParentNode {
279280
type: 'ImportDefaultSpecifier'

0 commit comments

Comments
 (0)