Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/giant-cars-open.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-vue': minor
---

Added `allowEmptyAlias` option to `vue/valid-v-for`
43 changes: 42 additions & 1 deletion docs/rules/valid-v-for.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,48 @@ The following cases are syntax errors:

## :wrench: Options

Nothing.
```json
{
"vue/valid-v-for": [
"error",
{
"allowEmptyAlias": false
}
]
}
```

- `allowEmptyAlias` (`boolean`) ... Allows empty aliases in `v-for` expressions. Default is `false`.

### `"allowEmptyAlias": false` (default)

<eslint-code-block :rules="{'vue/valid-v-for': ['error', {allowEmptyAlias: false}]}">

```vue
<template>
<!-- ✗ BAD -->
<div v-for="(,a,b) in list" />
<div v-for="(a,,b) in list" />
<div v-for="(a,b,,) in list" />
</template>
```

</eslint-code-block>

### `"allowEmptyAlias": true`

<eslint-code-block :rules="{'vue/valid-v-for': ['error', {allowEmptyAlias: true}]}">

```vue
<template>
<!-- ✓ GOOD -->
<div v-for="(,a,b) in list" />
<div v-for="(a,,b) in list" />
<div v-for="(a,b,,) in list" />
</template>
```

</eslint-code-block>

## :couple: Related Rules

Expand Down
42 changes: 33 additions & 9 deletions lib/rules/valid-v-for.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,17 @@ module.exports = {
url: 'https://eslint.vuejs.org/rules/valid-v-for.html'
},
fixable: null,
schema: [],
schema: [
{
type: 'object',
properties: {
allowEmptyAlias: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
requireKey:
"Custom elements in iteration require 'v-bind:key' directives.",
Expand All @@ -107,13 +117,23 @@ module.exports = {
expectedValue: "'v-for' directives require that attribute value.",
unexpectedExpression:
"'v-for' directives require the special syntax '<alias> in <expression>'.",
invalidEmptyAlias: "Invalid alias ''.",
invalidEmptyAlias: 'Invalid empty alias.',
invalidAlias: "Invalid alias '{{text}}'."
}
},
/** @param {RuleContext} context */
create(context) {
const sourceCode = context.sourceCode
const options = context.options[0] || {}
const allowEmptyAlias = options.allowEmptyAlias === true

/**
* @param {Pattern|null} alias
* @returns {boolean}
*/
function isValidAlias(alias) {
return alias ? alias.type === 'Identifier' : allowEmptyAlias
}

return utils.defineTemplateBodyVisitor(context, {
/** @param {VDirective} node */
Expand Down Expand Up @@ -164,24 +184,28 @@ module.exports = {
const key = lhs[1]
const index = lhs[2]

if (value === null) {
if (value === null && !allowEmptyAlias) {
context.report({
node: expr,
messageId: 'invalidEmptyAlias'
})
}
if (key !== undefined && (!key || key.type !== 'Identifier')) {

if (key !== undefined && !isValidAlias(key)) {
const isEmptyAlias = !key
context.report({
node: key || expr,
messageId: 'invalidAlias',
data: { text: key ? sourceCode.getText(key) : '' }
messageId: isEmptyAlias ? 'invalidEmptyAlias' : 'invalidAlias',
data: isEmptyAlias ? {} : { text: sourceCode.getText(key) }
})
}
if (index !== undefined && (!index || index.type !== 'Identifier')) {

if (index !== undefined && !isValidAlias(index)) {
const isEmptyAlias = !index
context.report({
node: index || expr,
messageId: 'invalidAlias',
data: { text: index ? sourceCode.getText(index) : '' }
messageId: isEmptyAlias ? 'invalidEmptyAlias' : 'invalidAlias',
data: isEmptyAlias ? {} : { text: sourceCode.getText(index) }
})
}
}
Expand Down
33 changes: 30 additions & 3 deletions tests/lib/rules/valid-v-for.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,27 @@ tester.run('valid-v-for', rule, {
{
filename: 'comment-value.vue',
code: '<template><div v-for="/**/"></div></template>'
},
// allowEmptyAlias option
{
filename: 'test.vue',
code: '<template><div><div v-for="(,a) in list"></div></div></template>',
options: [{ allowEmptyAlias: true }]
},
{
filename: 'test.vue',
code: '<template><div><div v-for="(,a,b) in list"></div></div></template>',
options: [{ allowEmptyAlias: true }]
},
{
filename: 'test.vue',
code: '<template><div><div v-for="(a,,b) in list"></div></div></template>',
options: [{ allowEmptyAlias: true }]
},
{
filename: 'test.vue',
code: '<template><div><div v-for="(a,b,,) in list"></div></div></template>',
options: [{ allowEmptyAlias: true }]
}
],
invalid: [
Expand All @@ -186,17 +207,17 @@ tester.run('valid-v-for', rule, {
{
filename: 'test.vue',
code: '<template><div><div v-for="(,a,b) in list"></div></div></template>',
errors: ["Invalid alias ''."]
errors: ['Invalid empty alias.']
},
{
filename: 'test.vue',
code: '<template><div><div v-for="(a,,b) in list"></div></div></template>',
errors: ["Invalid alias ''."]
errors: ['Invalid empty alias.']
},
{
filename: 'test.vue',
code: '<template><div><div v-for="(a,b,,) in list"></div></div></template>',
errors: ["Invalid alias ''."]
errors: ['Invalid empty alias.']
},
{
filename: 'test.vue',
Expand Down Expand Up @@ -326,6 +347,12 @@ tester.run('valid-v-for', rule, {
filename: 'empty-value.vue',
code: '<template><div v-for=""></div></template>',
errors: ["'v-for' directives require that attribute value."]
},
{
filename: 'test.vue',
code: '<template><div><div v-for="(,a) in list"></div></div></template>',
options: [{ allowEmptyAlias: false }],
errors: ['Invalid empty alias.']
}
]
})