Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new vue/no-use-v-else-with-v-for #2224

Merged
merged 3 commits into from
Jul 2, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Rules in this category are enabled for all presets provided by eslint-plugin-vue
| [vue/no-unused-components](./no-unused-components.md) | disallow registering components that are not used inside templates | | :three::two::hammer: |
| [vue/no-unused-vars](./no-unused-vars.md) | disallow unused variable definitions of v-for directives or scope attributes | :bulb: | :three::two::hammer: |
| [vue/no-use-computed-property-like-method](./no-use-computed-property-like-method.md) | disallow use computed property like method | | :three::two::warning: |
| [vue/no-use-v-if-with-v-for](./no-use-v-if-with-v-for.md) | disallow use v-if on the same element as v-for | | :three::two::hammer: |
| [vue/no-use-v-if-with-v-for](./no-use-v-if-with-v-for.md) | disallow using `v-if` on the same element as `v-for` | | :three::two::hammer: |
| [vue/no-useless-template-attributes](./no-useless-template-attributes.md) | disallow useless attribute on `<template>` | | :three::two::warning: |
| [vue/no-v-for-template-key-on-child](./no-v-for-template-key-on-child.md) | disallow key of `<template v-for>` placed on child elements | | :three::warning: |
| [vue/no-v-for-template-key](./no-v-for-template-key.md) | disallow `key` attribute on `<template v-for>` | | :two::warning: |
Expand Down Expand Up @@ -251,6 +251,7 @@ For example:
| [vue/no-unsupported-features](./no-unsupported-features.md) | disallow unsupported Vue.js syntax on the specified version | :wrench: | :hammer: |
| [vue/no-unused-properties](./no-unused-properties.md) | disallow unused properties | | :hammer: |
| [vue/no-unused-refs](./no-unused-refs.md) | disallow unused refs | | :hammer: |
| [vue/no-use-v-else-with-v-for](./no-use-v-else-with-v-for.md) | disallow using `v-else-if`/`v-else` on the same element as `v-for` | | :hammer: |
| [vue/no-useless-mustaches](./no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: | :hammer: |
| [vue/no-useless-v-bind](./no-useless-v-bind.md) | disallow unnecessary `v-bind` directives | :wrench: | :hammer: |
| [vue/no-v-text](./no-v-text.md) | disallow use of v-text | | :hammer: |
Expand Down
54 changes: 54 additions & 0 deletions docs/rules/no-use-v-else-with-v-for.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/no-use-v-else-with-v-for
description: disallow using `v-else-if`/`v-else` on the same element as `v-for`
---
# vue/no-use-v-else-with-v-for

> disallow using `v-else-if`/`v-else` on the same element as `v-for`

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>

## :book: Rule Details

This rule reports elements that have both `v-else-if`/`v-else` and `v-for` directives. That is valid in Vue (`v-else-if`/`v-else` will take precedence), but is confusing to read.

<eslint-code-block :rules="{'vue/no-use-v-else-with-v-for': ['error']}">

```vue
<template>
<!-- ✓ GOOD -->
<div v-if="foo">foo</div>
<template v-else-if="bar">
<div v-for="x in xs">{{ x }}</div>
</template>
<template v-else>
<div v-for="x in xs">{{ x }}</div>
</template>

<!-- ✗ BAD -->
<div v-if="foo">foo</div>
<div v-else-if="bar" v-for="x in xs">{{ x }}</div>
<div v-else v-for="x in xs">{{ x }}</div>
</template>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :mute: When Not To Use It

If you don't find using `v-else-if`/`v-else` together with `v-for` confusing to read, you can safely disable this rule.

## :couple: Related Rules

- [vue/no-use-v-if-with-v-for](./no-use-v-if-with-v-for.md)

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-use-v-else-with-v-for.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-use-v-else-with-v-for.js)
8 changes: 6 additions & 2 deletions docs/rules/no-use-v-if-with-v-for.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
pageClass: rule-details
sidebarDepth: 0
title: vue/no-use-v-if-with-v-for
description: disallow use v-if on the same element as v-for
description: disallow using `v-if` on the same element as `v-for`
since: v4.6.0
---
# vue/no-use-v-if-with-v-for

> disallow use v-if on the same element as v-for
> disallow using `v-if` on the same element as `v-for`

- :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/essential"`, `"plugin:vue/vue3-strongly-recommended"`, `"plugin:vue/strongly-recommended"`, `"plugin:vue/vue3-recommended"` and `"plugin:vue/recommended"`.

Expand Down Expand Up @@ -88,6 +88,10 @@ There are two common cases where this can be tempting:

</eslint-code-block>

## :couple: Related Rules

- [vue/no-use-v-else-with-v-for](./no-use-v-else-with-v-for.md)

## :books: Further Reading

- [Style guide - Avoid v-if with v-for](https://vuejs.org/style-guide/rules-essential.html#avoid-v-if-with-v-for)
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
'no-unused-refs': require('./rules/no-unused-refs'),
'no-unused-vars': require('./rules/no-unused-vars'),
'no-use-computed-property-like-method': require('./rules/no-use-computed-property-like-method'),
'no-use-v-else-with-v-for': require('./rules/no-use-v-else-with-v-for'),
'no-use-v-if-with-v-for': require('./rules/no-use-v-if-with-v-for'),
'no-useless-concat': require('./rules/no-useless-concat'),
'no-useless-mustaches': require('./rules/no-useless-mustaches'),
Expand Down Expand Up @@ -253,7 +254,7 @@
'.vue': require('./processor')
},
environments: {
// TODO Remove in the next major version

Check warning on line 257 in lib/index.js

View workflow job for this annotation

GitHub Actions / Lint

Unexpected 'todo' comment: 'TODO Remove in the next major version'
/** @deprecated */
'setup-compiler-macros': {
globals: {
Expand Down
49 changes: 49 additions & 0 deletions lib/rules/no-use-v-else-with-v-for.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @author Yosuke Ota
*
* Style guide: https://vuejs.org/style-guide/rules-essential.html#avoid-v-if-with-v-for
*/
ota-meshi marked this conversation as resolved.
Show resolved Hide resolved
'use strict'

const { defineTemplateBodyVisitor, hasDirective } = require('../utils')

module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'disallow using `v-else-if`/`v-else` on the same element as `v-for`',
categories: null,
url: 'https://eslint.vuejs.org/rules/no-use-v-else-with-v-for.html'
},
fixable: null,
schema: [],
messages: {
unexpectedDirectiveWithVFor:
'Unexpected `{{ directiveName }}` and `v-for` on the same element. Move `{{ directiveName }}` to a wrapper element instead.'
}
},
/** @param {RuleContext} context */
create(context) {
return defineTemplateBodyVisitor(context, {
/** @param {VDirective} node */
"VAttribute[directive=true][key.name.name='for']"(node) {
const element = node.parent.parent

if (hasDirective(element, 'else-if')) {
context.report({
node: element,
messageId: 'unexpectedDirectiveWithVFor',
data: { directiveName: 'v-else-if' }
})
} else if (hasDirective(element, 'else')) {
context.report({
node: element,
messageId: 'unexpectedDirectiveWithVFor',
data: { directiveName: 'v-else' }
})
}
}
})
}
}
2 changes: 1 addition & 1 deletion lib/rules/no-use-v-if-with-v-for.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow use v-if on the same element as v-for',
description: 'disallow using `v-if` on the same element as `v-for`',
categories: ['vue3-essential', 'essential'],
url: 'https://eslint.vuejs.org/rules/no-use-v-if-with-v-for.html'
},
Expand Down
101 changes: 101 additions & 0 deletions tests/lib/rules/no-use-v-else-with-v-for.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* @author Yosuke Ota
*/
ota-meshi marked this conversation as resolved.
Show resolved Hide resolved
'use strict'

const RuleTester = require('eslint').RuleTester
const rule = require('../../../lib/rules/no-use-v-else-with-v-for')

const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: { ecmaVersion: 2015 }
})

tester.run('no-use-v-else-with-v-for', rule, {
valid: [
{
// caught by `vue/no-use-v-if-with-v-for`
filename: 'test.vue',
code: `
<template>
<div v-if="foo" v-for="x in xs">{{ x }}</div>
</template>
`
},
{
// `v-if`/`v-else-if`/`v-else` only
filename: 'test.vue',
code: `
<template>
<div v-if="foo">{{ x }}</div>
<div v-else-if="foo">{{ x }}</div>
<div v-else="foo">{{ x }}</div>
</template>
`
},
{
// `v-for` only
filename: 'test.vue',
code: `
<template>
<div v-for="x in xs">{{ x }}</div>
</template>
`
},
{
// `v-else-if`/`v-else` in template + `v-for`
filename: 'test.vue',
code: `
<template>
<div v-if="foo">foo</div>
<template v-else-if="bar">
<div v-for="x in xs">{{ x }}</div>
</template>
<template v-else>
<div v-for="x in xs">{{ x }}</div>
</template>
</template>
`
}
],
invalid: [
{
filename: 'test.vue',
code: `
<template>
<div v-if="foo">foo</div>
<div v-else v-for="x in xs">{{ x }}</div>
</template>
`,
errors: [
{
message:
'Unexpected `v-else` and `v-for` on the same element. Move `v-else` to a wrapper element instead.',
line: 4,
endLine: 4,
column: 11,
endColumn: 52
}
]
},
{
filename: 'test.vue',
code: `
<template>
<div v-if="foo">foo</div>
<div v-else-if="bar" v-for="x in xs">{{ x }}</div>
</template>
`,
errors: [
{
message:
'Unexpected `v-else-if` and `v-for` on the same element. Move `v-else-if` to a wrapper element instead.',
line: 4,
endLine: 4,
column: 11,
endColumn: 61
}
]
}
]
})