diff --git a/lib/rules/no-dupe-keys.js b/lib/rules/no-dupe-keys.js index c812c5319..f959f4b66 100644 --- a/lib/rules/no-dupe-keys.js +++ b/lib/rules/no-dupe-keys.js @@ -4,10 +4,13 @@ */ 'use strict' +const { findVariable } = require('@eslint-community/eslint-utils') const utils = require('../utils') /** * @typedef {import('../utils').GroupName} GroupName + * @typedef {import('eslint').Scope.Variable} Variable + * @typedef {import('../utils').ComponentProp} ComponentProp */ /** @type {GroupName[]} */ @@ -39,24 +42,43 @@ module.exports = { const options = context.options[0] || {} const groups = new Set([...GROUP_NAMES, ...(options.groups || [])]) - return utils.executeOnVue(context, (obj) => { - /** @type {Set} */ - const usedNames = new Set() - const properties = utils.iterateProperties(obj, groups) - - for (const o of properties) { - if (usedNames.has(o.name)) { - context.report({ - node: o.node, - message: "Duplicated key '{{name}}'.", - data: { - name: o.name - } - }) + return utils.compositingVisitors( + utils.executeOnVue(context, (obj) => { + const properties = utils.iterateProperties(obj, groups) + /** @type {Set} */ + const usedNames = new Set() + for (const o of properties) { + if (usedNames.has(o.name)) { + context.report({ + node: o.node, + message: "Duplicated key '{{name}}'.", + data: { + name: o.name + } + }) + } + + usedNames.add(o.name) } + }), + utils.defineScriptSetupVisitor(context, { + onDefinePropsEnter(node, props) { + for (const prop of props) { + if (!prop.propName) continue - usedNames.add(o.name) - } - }) + const variable = findVariable(context.getScope(), prop.propName) + if (!variable || variable.defs.length === 0) continue + + context.report({ + node: variable.defs[0].node, + message: "Duplicated key '{{name}}'.", + data: { + name: prop.propName + } + }) + } + } + }) + ) } } diff --git a/tests/lib/rules/no-dupe-keys.js b/tests/lib/rules/no-dupe-keys.js index 26c9f7339..e1294032f 100644 --- a/tests/lib/rules/no-dupe-keys.js +++ b/tests/lib/rules/no-dupe-keys.js @@ -390,6 +390,32 @@ ruleTester.run('no-dupe-keys', rule, { }, } ` + }, + { + filename: 'test.vue', + code: ` + + `, + parser: require.resolve('vue-eslint-parser') + }, + { + filename: 'test.vue', + code: ` + + `, + parser: require.resolve('vue-eslint-parser'), + parserOptions: { parser: require.resolve('@typescript-eslint/parser') } } ], @@ -861,6 +887,85 @@ ruleTester.run('no-dupe-keys', rule, { line: 7 } ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser: require.resolve('vue-eslint-parser'), + errors: [ + { + message: "Duplicated key 'foo'.", + line: 6 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser: require.resolve('vue-eslint-parser'), + errors: [ + { + message: "Duplicated key 'baz'.", + line: 4 + }, + { + message: "Duplicated key 'foo'.", + line: 12 + }, + { + message: "Duplicated key 'bar'.", + line: 15 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + parser: require.resolve('vue-eslint-parser'), + parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, + errors: [ + { + message: "Duplicated key 'foo'.", + line: 8 + }, + { + message: "Duplicated key 'bar'.", + line: 9 + } + ] } ] })