Skip to content

Commit 8976f82

Browse files
polish template v-for error report
Fix vuejs#164, don't report error when nested v-for refers iterator. Do report error when nested v-for doesn't refer iterator.
1 parent a6feec3 commit 8976f82

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

lib/rules/valid-v-for.js

+22-6
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,50 @@ const utils = require('../utils')
1919
* Check whether the given attribute is using the variables which are defined by `v-for` directives.
2020
* @param {ASTNode} vFor The attribute node of `v-for` to check.
2121
* @param {ASTNode} vBindKey The attribute node of `v-bind:key` to check.
22+
* @param {boolean} isChild If checks on child in template[v-for].
2223
* @returns {boolean} `true` if the node is using the variables which are defined by `v-for` directives.
2324
*/
24-
function isUsingIterationVar (vFor, vBindKey) {
25+
function isUsingIterationVar (vFor, vBindKey, isChild) {
2526
if (vBindKey.value == null) {
2627
return false
2728
}
2829
const references = vBindKey.value.references
2930
const variables = vFor.parent.parent.variables
30-
31-
return references.some(reference =>
31+
const used = references.some(reference =>
3232
variables.some(variable =>
3333
variable.id.name === reference.id.name &&
3434
variable.kind === 'v-for'
3535
)
3636
)
37+
38+
if (!isChild || used) {
39+
return used
40+
}
41+
const childFor = utils.getDirective(vBindKey.parent.parent, 'for')
42+
if (!childFor) {
43+
return false
44+
}
45+
const childForRefs = childFor.value.references
46+
return childForRefs.some(cref =>
47+
variables.some(variable =>
48+
cref.id.name === variable.id.name &&
49+
variable.kind === 'v-for'
50+
)
51+
)
3752
}
3853

3954
/**
4055
* Check the given element about `v-bind:key` attributes.
4156
* @param {RuleContext} context The rule context to report.
4257
* @param {ASTNode} vFor The attribute node of `v-for` to check.
4358
* @param {ASTNode} element The element node to check.
59+
* @param {boolean} isChild If element is a child of template[v-for].
4460
*/
45-
function checkKey (context, vFor, element) {
61+
function checkKey (context, vFor, element, isChild) {
4662
if (element.name === 'template') {
4763
for (const child of element.children) {
4864
if (child.type === 'VElement') {
49-
checkKey(context, vFor, child)
65+
checkKey(context, vFor, child, true)
5066
}
5167
}
5268
return
@@ -61,7 +77,7 @@ function checkKey (context, vFor, element) {
6177
message: "Custom elements in iteration require 'v-bind:key' directives."
6278
})
6379
}
64-
if (vBindKey != null && !isUsingIterationVar(vFor, vBindKey)) {
80+
if (vBindKey != null && !isUsingIterationVar(vFor, vBindKey, isChild)) {
6581
context.report({
6682
node: vBindKey,
6783
loc: vBindKey.loc,

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

+9
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ 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>'
8589
}
8690
],
8791
invalid: [
@@ -179,6 +183,11 @@ tester.run('valid-v-for', rule, {
179183
filename: 'test.vue',
180184
code: '<template><div><template v-for="xin list"><div></div></template></div></template>',
181185
errors: ["'v-for' directives require that attribute value."]
186+
},
187+
{
188+
filename: 'test.vue',
189+
code: '<template><div><template v-for="x of list"><div v-for="foo of y" :key="foo"></div></template></div></template>',
190+
errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."]
182191
}
183192
]
184193
})

0 commit comments

Comments
 (0)