Skip to content

Commit e495132

Browse files
authored
Update vue/no-template-shadow rule to support setup() and <script setup> (#1543)
1 parent 747ab5b commit e495132

File tree

2 files changed

+180
-35
lines changed

2 files changed

+180
-35
lines changed

Diff for: lib/rules/no-template-shadow.js

+66-35
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const utils = require('../utils')
1919
// ------------------------------------------------------------------------------
2020

2121
/** @type {GroupName[]} */
22-
const GROUP_NAMES = ['props', 'computed', 'data', 'methods']
22+
const GROUP_NAMES = ['props', 'computed', 'data', 'methods', 'setup']
2323

2424
module.exports = {
2525
meta: {
@@ -50,51 +50,82 @@ module.exports = {
5050
// Public
5151
// ----------------------------------------------------------------------
5252

53-
return utils.defineTemplateBodyVisitor(
54-
context,
55-
{
56-
/** @param {VElement} node */
57-
VElement(node) {
58-
scopeStack = {
59-
parent: scopeStack,
60-
nodes: scopeStack
61-
? scopeStack.nodes.slice() // make copy
62-
: []
63-
}
64-
if (node.variables) {
65-
for (const variable of node.variables) {
66-
const varNode = variable.id
67-
const name = varNode.name
68-
if (
69-
scopeStack.nodes.some((node) => node.name === name) ||
70-
jsVars.has(name)
71-
) {
72-
context.report({
73-
node: varNode,
74-
loc: varNode.loc,
75-
message:
76-
"Variable '{{name}}' is already declared in the upper scope.",
77-
data: {
78-
name
79-
}
80-
})
81-
} else {
82-
scopeStack.nodes.push(varNode)
53+
return utils.compositingVisitors(
54+
utils.isScriptSetup(context)
55+
? {
56+
Program() {
57+
const globalScope =
58+
context.getSourceCode().scopeManager.globalScope
59+
if (!globalScope) {
60+
return
61+
}
62+
for (const variable of globalScope.variables) {
63+
if (variable.defs.length > 0) {
64+
jsVars.add(variable.name)
65+
}
66+
}
67+
const moduleScope = globalScope.childScopes.find(
68+
(scope) => scope.type === 'module'
69+
)
70+
if (!moduleScope) {
71+
return
72+
}
73+
for (const variable of moduleScope.variables) {
74+
if (variable.defs.length > 0) {
75+
jsVars.add(variable.name)
76+
}
8377
}
8478
}
8579
}
86-
},
87-
'VElement:exit'() {
88-
scopeStack = scopeStack && scopeStack.parent
80+
: {},
81+
utils.defineScriptSetupVisitor(context, {
82+
onDefinePropsEnter(_node, props) {
83+
for (const prop of props) {
84+
if (prop.propName) {
85+
jsVars.add(prop.propName)
86+
}
87+
}
8988
}
90-
},
89+
}),
9190
utils.executeOnVue(context, (obj) => {
9291
const properties = Array.from(
9392
utils.iterateProperties(obj, new Set(GROUP_NAMES))
9493
)
9594
for (const node of properties) {
9695
jsVars.add(node.name)
9796
}
97+
}),
98+
utils.defineTemplateBodyVisitor(context, {
99+
/** @param {VElement} node */
100+
VElement(node) {
101+
scopeStack = {
102+
parent: scopeStack,
103+
nodes: scopeStack ? [...scopeStack.nodes] : []
104+
}
105+
for (const variable of node.variables) {
106+
const varNode = variable.id
107+
const name = varNode.name
108+
if (
109+
scopeStack.nodes.some((node) => node.name === name) ||
110+
jsVars.has(name)
111+
) {
112+
context.report({
113+
node: varNode,
114+
loc: varNode.loc,
115+
message:
116+
"Variable '{{name}}' is already declared in the upper scope.",
117+
data: {
118+
name
119+
}
120+
})
121+
} else {
122+
scopeStack.nodes.push(varNode)
123+
}
124+
}
125+
},
126+
'VElement:exit'() {
127+
scopeStack = scopeStack && scopeStack.parent
128+
}
98129
})
99130
)
100131
}

Diff for: tests/lib/rules/no-template-shadow.js

+114
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,54 @@ ruleTester.run('no-template-shadow', rule, {
115115
}
116116
}
117117
</script>`
118+
},
119+
{
120+
filename: 'test.vue',
121+
code: `
122+
<template>
123+
<div v-for="i in 5">
124+
<div v-for="j in 5">
125+
</div>
126+
</div>
127+
</template>
128+
<script>
129+
export default {
130+
setup() {
131+
return {
132+
k: 42
133+
}
134+
}
135+
}
136+
</script>
137+
`
138+
},
139+
{
140+
filename: 'test.vue',
141+
code: `
142+
<template>
143+
<div v-for="i in 5">
144+
<div v-for="j in 5">
145+
</div>
146+
</div>
147+
</template>
148+
<script setup>
149+
let k = 42
150+
</script>
151+
`
152+
},
153+
{
154+
filename: 'test.vue',
155+
code: `
156+
<template>
157+
<div v-for="i in 5">
158+
<div v-for="j in 5">
159+
</div>
160+
</div>
161+
</template>
162+
<script setup>
163+
defineProps({k:Number})
164+
</script>
165+
`
118166
}
119167
],
120168

@@ -345,6 +393,72 @@ ruleTester.run('no-template-shadow', rule, {
345393
line: 7
346394
}
347395
]
396+
},
397+
{
398+
filename: 'test.vue',
399+
code: `
400+
<template>
401+
<div v-for="i in 5">
402+
<div v-for="j in 5">
403+
</div>
404+
</div>
405+
</template>
406+
<script>
407+
export default {
408+
setup() {
409+
return {
410+
j: 42
411+
}
412+
}
413+
}
414+
</script>
415+
`,
416+
errors: [
417+
{
418+
message: "Variable 'j' is already declared in the upper scope.",
419+
line: 4
420+
}
421+
]
422+
},
423+
{
424+
filename: 'test.vue',
425+
code: `
426+
<template>
427+
<div v-for="i in 5">
428+
<div v-for="j in 5">
429+
</div>
430+
</div>
431+
</template>
432+
<script setup>
433+
let j = 42
434+
</script>
435+
`,
436+
errors: [
437+
{
438+
message: "Variable 'j' is already declared in the upper scope.",
439+
line: 4
440+
}
441+
]
442+
},
443+
{
444+
filename: 'test.vue',
445+
code: `
446+
<template>
447+
<div v-for="i in 5">
448+
<div v-for="j in 5">
449+
</div>
450+
</div>
451+
</template>
452+
<script setup>
453+
defineProps({j:Number})
454+
</script>
455+
`,
456+
errors: [
457+
{
458+
message: "Variable 'j' is already declared in the upper scope.",
459+
line: 4
460+
}
461+
]
348462
}
349463
]
350464
})

0 commit comments

Comments
 (0)