Skip to content

Commit 85137c9

Browse files
HerringtonDarkholmemysticatea
authored andcommitted
Fix: polish template v-for error report (fixes #164)(#168)
* polish template v-for error report Fix #164, don't report error when nested v-for refers iterator. Do report error when nested v-for doesn't refer iterator. * update jsdoc * check iterator usage in new way * add more test cases * fix code style * cosmetic indentation
1 parent a73f5e2 commit 85137c9

File tree

2 files changed

+97
-2
lines changed

2 files changed

+97
-2
lines changed

lib/rules/valid-v-for.js

+29-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ function isUsingIterationVar (vFor, vBindKey) {
2727
}
2828
const references = vBindKey.value.references
2929
const variables = vFor.parent.parent.variables
30-
3130
return references.some(reference =>
3231
variables.some(variable =>
3332
variable.id.name === reference.id.name &&
@@ -36,6 +35,34 @@ function isUsingIterationVar (vFor, vBindKey) {
3635
)
3736
}
3837

38+
/**
39+
* Check the child element in tempalte v-for about `v-bind:key` attributes.
40+
* @param {RuleContext} context The rule context to report.
41+
* @param {ASTNode} vFor The attribute node of `v-for` to check.
42+
* @param {ASTNode} child The child node to check.
43+
*/
44+
function checkChildKey (context, vFor, child) {
45+
const childFor = utils.getDirective(child, 'for')
46+
// if child has v-for, check if parent iterator is used in v-for
47+
if (childFor != null) {
48+
const childForRefs = childFor.value.references
49+
const variables = vFor.parent.parent.variables
50+
const usedInFor = childForRefs.some(cref =>
51+
variables.some(variable =>
52+
cref.id.name === variable.id.name &&
53+
variable.kind === 'v-for'
54+
)
55+
)
56+
// if parent iterator is used, skip other checks
57+
// iterator usage will be checked later by child v-for
58+
if (usedInFor) {
59+
return
60+
}
61+
}
62+
// otherwise, check if parent iterator is directly used in child's key
63+
checkKey(context, vFor, child)
64+
}
65+
3966
/**
4067
* Check the given element about `v-bind:key` attributes.
4168
* @param {RuleContext} context The rule context to report.
@@ -46,7 +73,7 @@ function checkKey (context, vFor, element) {
4673
if (element.name === 'template') {
4774
for (const child of element.children) {
4875
if (child.type === 'VElement') {
49-
checkKey(context, vFor, child)
76+
checkChildKey(context, vFor, child)
5077
}
5178
}
5279
return

tests/lib/rules/valid-v-for.js

+68
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,32 @@ tester.run('valid-v-for', rule, {
8282
{
8383
filename: 'test.vue',
8484
code: '<template v-for="x of list">foo<div></div></template>'
85+
},
86+
{
87+
filename: 'test.vue',
88+
code: '<template><div><template v-for="x of list"><div v-for="foo of x" :key="foo"></div></template></div></template>'
89+
},
90+
{
91+
filename: 'test.vue',
92+
code: `
93+
<template v-for="x in xs">
94+
<template v-for="y in x.ys">
95+
<li v-for="z in y.zs" :key="z.id">
96+
123
97+
</li>
98+
</template>
99+
</template>`
100+
},
101+
{
102+
filename: 'test.vue',
103+
code: `
104+
<template v-for="x in xs">
105+
<template v-for="y in ys">
106+
<li v-for="z in zs" :key="x.id + y.id + z.id">
107+
123
108+
</li>
109+
</template>
110+
</template>`
85111
}
86112
],
87113
invalid: [
@@ -179,6 +205,48 @@ tester.run('valid-v-for', rule, {
179205
filename: 'test.vue',
180206
code: '<template><div><template v-for="xin list"><div></div></template></div></template>',
181207
errors: ["'v-for' directives require that attribute value."]
208+
},
209+
{
210+
filename: 'test.vue',
211+
code: '<template><div><template v-for="x of list"><div v-for="foo of y" :key="foo"></div></template></div></template>',
212+
errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."]
213+
},
214+
{
215+
filename: 'test.vue',
216+
errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."],
217+
code: `
218+
<template v-for="x in xs">
219+
<template v-for="y in a.ys">
220+
<li v-for="z in y.zs" :key="z.id">
221+
123
222+
</li>
223+
</template>
224+
</template>`
225+
},
226+
{
227+
filename: 'test.vue',
228+
errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."],
229+
code: `
230+
<template v-for="x in xs">
231+
<template v-for="y in x.ys">
232+
<li v-for="z in a.zs" :key="z.id">
233+
123
234+
</li>
235+
</template>
236+
</template>`
237+
},
238+
{
239+
filename: 'test.vue',
240+
errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."],
241+
code: `
242+
<template v-for="x in xs">
243+
<template v-for="y in x.ys">
244+
<li v-for="z in x.zs" :key="z.id">
245+
123
246+
</li>
247+
</template>
248+
</template>`
182249
}
250+
183251
]
184252
})

0 commit comments

Comments
 (0)