Skip to content

Commit 8494cd5

Browse files
authored
Extend vue/no-dupe-keys to support <script setup> (#2185)
1 parent c1f3d55 commit 8494cd5

File tree

2 files changed

+144
-17
lines changed

2 files changed

+144
-17
lines changed

lib/rules/no-dupe-keys.js

+39-17
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
*/
55
'use strict'
66

7+
const { findVariable } = require('@eslint-community/eslint-utils')
78
const utils = require('../utils')
89

910
/**
1011
* @typedef {import('../utils').GroupName} GroupName
12+
* @typedef {import('eslint').Scope.Variable} Variable
13+
* @typedef {import('../utils').ComponentProp} ComponentProp
1114
*/
1215

1316
/** @type {GroupName[]} */
@@ -39,24 +42,43 @@ module.exports = {
3942
const options = context.options[0] || {}
4043
const groups = new Set([...GROUP_NAMES, ...(options.groups || [])])
4144

42-
return utils.executeOnVue(context, (obj) => {
43-
/** @type {Set<string>} */
44-
const usedNames = new Set()
45-
const properties = utils.iterateProperties(obj, groups)
46-
47-
for (const o of properties) {
48-
if (usedNames.has(o.name)) {
49-
context.report({
50-
node: o.node,
51-
message: "Duplicated key '{{name}}'.",
52-
data: {
53-
name: o.name
54-
}
55-
})
45+
return utils.compositingVisitors(
46+
utils.executeOnVue(context, (obj) => {
47+
const properties = utils.iterateProperties(obj, groups)
48+
/** @type {Set<string>} */
49+
const usedNames = new Set()
50+
for (const o of properties) {
51+
if (usedNames.has(o.name)) {
52+
context.report({
53+
node: o.node,
54+
message: "Duplicated key '{{name}}'.",
55+
data: {
56+
name: o.name
57+
}
58+
})
59+
}
60+
61+
usedNames.add(o.name)
5662
}
63+
}),
64+
utils.defineScriptSetupVisitor(context, {
65+
onDefinePropsEnter(node, props) {
66+
for (const prop of props) {
67+
if (!prop.propName) continue
5768

58-
usedNames.add(o.name)
59-
}
60-
})
69+
const variable = findVariable(context.getScope(), prop.propName)
70+
if (!variable || variable.defs.length === 0) continue
71+
72+
context.report({
73+
node: variable.defs[0].node,
74+
message: "Duplicated key '{{name}}'.",
75+
data: {
76+
name: prop.propName
77+
}
78+
})
79+
}
80+
}
81+
})
82+
)
6183
}
6284
}

tests/lib/rules/no-dupe-keys.js

+105
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,32 @@ ruleTester.run('no-dupe-keys', rule, {
390390
},
391391
}
392392
`
393+
},
394+
{
395+
filename: 'test.vue',
396+
code: `
397+
<script setup>
398+
defineProps({
399+
foo: String,
400+
})
401+
const bar = 0
402+
</script>
403+
`,
404+
parser: require.resolve('vue-eslint-parser')
405+
},
406+
{
407+
filename: 'test.vue',
408+
code: `
409+
<script setup lang="ts">
410+
defineProps<{
411+
foo: string;
412+
}>();
413+
414+
const bar = 0
415+
</script>
416+
`,
417+
parser: require.resolve('vue-eslint-parser'),
418+
parserOptions: { parser: require.resolve('@typescript-eslint/parser') }
393419
}
394420
],
395421

@@ -861,6 +887,85 @@ ruleTester.run('no-dupe-keys', rule, {
861887
line: 7
862888
}
863889
]
890+
},
891+
{
892+
filename: 'test.vue',
893+
code: `
894+
<script setup>
895+
defineProps({
896+
foo: String,
897+
})
898+
const foo = 0
899+
</script>
900+
`,
901+
parser: require.resolve('vue-eslint-parser'),
902+
errors: [
903+
{
904+
message: "Duplicated key 'foo'.",
905+
line: 6
906+
}
907+
]
908+
},
909+
{
910+
filename: 'test.vue',
911+
code: `
912+
<script setup>
913+
import { Foo } from './Foo.vue';
914+
import baz from './baz';
915+
916+
defineProps({
917+
foo: String,
918+
bar: String,
919+
baz: String,
920+
});
921+
922+
function foo() {
923+
const baz = 'baz';
924+
}
925+
const bar = () => 'bar';
926+
</script>
927+
`,
928+
parser: require.resolve('vue-eslint-parser'),
929+
errors: [
930+
{
931+
message: "Duplicated key 'baz'.",
932+
line: 4
933+
},
934+
{
935+
message: "Duplicated key 'foo'.",
936+
line: 12
937+
},
938+
{
939+
message: "Duplicated key 'bar'.",
940+
line: 15
941+
}
942+
]
943+
},
944+
{
945+
filename: 'test.vue',
946+
code: `
947+
<script setup lang="ts">
948+
defineProps<{
949+
foo: string;
950+
bar: string;
951+
}>();
952+
953+
const foo = 'foo';
954+
const bar = 'bar';
955+
</script>
956+
`,
957+
parser: require.resolve('vue-eslint-parser'),
958+
parserOptions: { parser: require.resolve('@typescript-eslint/parser') },
959+
errors: [
960+
{
961+
message: "Duplicated key 'foo'.",
962+
line: 8
963+
},
964+
{
965+
message: "Duplicated key 'bar'.",
966+
line: 9
967+
}
968+
]
864969
}
865970
]
866971
})

0 commit comments

Comments
 (0)