diff --git a/docs/rules/index.md b/docs/rules/index.md index eca5a3191..abc3419a4 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -240,6 +240,7 @@ For example: | [vue/no-restricted-props](./no-restricted-props.md) | disallow specific props | :bulb: | :hammer: | | [vue/no-restricted-static-attribute](./no-restricted-static-attribute.md) | disallow specific attribute | | :hammer: | | [vue/no-restricted-v-bind](./no-restricted-v-bind.md) | disallow specific argument in `v-bind` | | :hammer: | +| [vue/no-root-v-if](./no-root-v-if.md) | disallow `v-if` directives on root element | | :hammer: | | [vue/no-static-inline-styles](./no-static-inline-styles.md) | disallow static inline `style` attributes | | :hammer: | | [vue/no-template-target-blank](./no-template-target-blank.md) | disallow target="_blank" attribute without rel="noopener noreferrer" | :bulb: | :warning: | | [vue/no-this-in-before-route-enter](./no-this-in-before-route-enter.md) | disallow `this` usage in a `beforeRouteEnter` method | | :warning: | diff --git a/docs/rules/no-root-v-if.md b/docs/rules/no-root-v-if.md new file mode 100644 index 000000000..0899dc036 --- /dev/null +++ b/docs/rules/no-root-v-if.md @@ -0,0 +1,37 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/no-root-v-if +description: disallow `v-if` directives on root element +--- + +# vue/no-root-v-if + +> disallow `v-if` directives on root element + +- :exclamation: ***This rule has not been released yet.*** + +This rule reports template roots with `v-if`. Rendering of the whole component could be made conditional in the parent component (with a `v-if` there) instead. + +## :book: Rule Details + +This rule reports the template root in the following cases: + + + +```vue + +``` + + + +## :wrench: Options + +Nothing. + +## :mag: Implementation + +- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-root-v-if.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-root-v-if.js) diff --git a/lib/index.js b/lib/index.js index 879a49056..c7b580868 100644 --- a/lib/index.js +++ b/lib/index.js @@ -124,6 +124,7 @@ module.exports = { 'no-restricted-static-attribute': require('./rules/no-restricted-static-attribute'), 'no-restricted-syntax': require('./rules/no-restricted-syntax'), 'no-restricted-v-bind': require('./rules/no-restricted-v-bind'), + 'no-root-v-if': require('./rules/no-root-v-if'), 'no-setup-props-destructure': require('./rules/no-setup-props-destructure'), 'no-shared-component-data': require('./rules/no-shared-component-data'), 'no-side-effects-in-computed-properties': require('./rules/no-side-effects-in-computed-properties'), diff --git a/lib/rules/no-root-v-if.js b/lib/rules/no-root-v-if.js new file mode 100644 index 000000000..304ef3f12 --- /dev/null +++ b/lib/rules/no-root-v-if.js @@ -0,0 +1,46 @@ +/** + * @author Perry Song + * @copyright 2023 Perry Song. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +const utils = require('../utils') + +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'disallow `v-if` directives on root element', + categories: undefined, + url: 'https://eslint.vuejs.org/rules/no-root-v-if.html' + }, + fixable: null, + schema: [] + }, + /** @param {RuleContext} context */ + create(context) { + return { + /** @param {Program} program */ + Program(program) { + const element = program.templateBody + if (element == null) { + return + } + + const rootElements = element.children.filter(utils.isVElement) + if ( + rootElements.length === 1 && + utils.hasDirective(rootElements[0], 'if') + ) { + context.report({ + node: element, + loc: element.loc, + message: + '`v-if` should not be used on root element without `v-else`.' + }) + } + } + } + } +} diff --git a/tests/lib/rules/no-root-v-if.js b/tests/lib/rules/no-root-v-if.js new file mode 100644 index 000000000..766c5b2ad --- /dev/null +++ b/tests/lib/rules/no-root-v-if.js @@ -0,0 +1,115 @@ +/** + * @author Perry Song + * @copyright 2023 Perry Song. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/no-root-v-if') + +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('no-root-v-if', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: `` + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '