diff --git a/lib/rules/no-template-shadow.js b/lib/rules/no-template-shadow.js index 44f26cf57..f66f8a701 100644 --- a/lib/rules/no-template-shadow.js +++ b/lib/rules/no-template-shadow.js @@ -19,7 +19,7 @@ const utils = require('../utils') // ------------------------------------------------------------------------------ /** @type {GroupName[]} */ -const GROUP_NAMES = ['props', 'computed', 'data', 'methods'] +const GROUP_NAMES = ['props', 'computed', 'data', 'methods', 'setup'] module.exports = { meta: { @@ -50,44 +50,43 @@ module.exports = { // Public // ---------------------------------------------------------------------- - return utils.defineTemplateBodyVisitor( - context, - { - /** @param {VElement} node */ - VElement(node) { - scopeStack = { - parent: scopeStack, - nodes: scopeStack - ? scopeStack.nodes.slice() // make copy - : [] - } - if (node.variables) { - for (const variable of node.variables) { - const varNode = variable.id - const name = varNode.name - if ( - scopeStack.nodes.some((node) => node.name === name) || - jsVars.has(name) - ) { - context.report({ - node: varNode, - loc: varNode.loc, - message: - "Variable '{{name}}' is already declared in the upper scope.", - data: { - name - } - }) - } else { - scopeStack.nodes.push(varNode) + return utils.compositingVisitors( + utils.isScriptSetup(context) + ? { + Program() { + const globalScope = + context.getSourceCode().scopeManager.globalScope + if (!globalScope) { + return + } + for (const variable of globalScope.variables) { + if (variable.defs.length > 0) { + jsVars.add(variable.name) + } + } + const moduleScope = globalScope.childScopes.find( + (scope) => scope.type === 'module' + ) + if (!moduleScope) { + return + } + for (const variable of moduleScope.variables) { + if (variable.defs.length > 0) { + jsVars.add(variable.name) + } } } } - }, - 'VElement:exit'() { - scopeStack = scopeStack && scopeStack.parent + : {}, + utils.defineScriptSetupVisitor(context, { + onDefinePropsEnter(_node, props) { + for (const prop of props) { + if (prop.propName) { + jsVars.add(prop.propName) + } + } } - }, + }), utils.executeOnVue(context, (obj) => { const properties = Array.from( utils.iterateProperties(obj, new Set(GROUP_NAMES)) @@ -95,6 +94,38 @@ module.exports = { for (const node of properties) { jsVars.add(node.name) } + }), + utils.defineTemplateBodyVisitor(context, { + /** @param {VElement} node */ + VElement(node) { + scopeStack = { + parent: scopeStack, + nodes: scopeStack ? [...scopeStack.nodes] : [] + } + for (const variable of node.variables) { + const varNode = variable.id + const name = varNode.name + if ( + scopeStack.nodes.some((node) => node.name === name) || + jsVars.has(name) + ) { + context.report({ + node: varNode, + loc: varNode.loc, + message: + "Variable '{{name}}' is already declared in the upper scope.", + data: { + name + } + }) + } else { + scopeStack.nodes.push(varNode) + } + } + }, + 'VElement:exit'() { + scopeStack = scopeStack && scopeStack.parent + } }) ) } diff --git a/tests/lib/rules/no-template-shadow.js b/tests/lib/rules/no-template-shadow.js index 872dffcf1..1f1daa184 100644 --- a/tests/lib/rules/no-template-shadow.js +++ b/tests/lib/rules/no-template-shadow.js @@ -115,6 +115,54 @@ ruleTester.run('no-template-shadow', rule, { } } ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` + }, + { + filename: 'test.vue', + code: ` + + + ` } ], @@ -345,6 +393,72 @@ ruleTester.run('no-template-shadow', rule, { line: 7 } ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: "Variable 'j' is already declared in the upper scope.", + line: 4 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: "Variable 'j' is already declared in the upper scope.", + line: 4 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: "Variable 'j' is already declared in the upper scope.", + line: 4 + } + ] } ] })