From 118568bcbbebdb466ab3cbe18bb0a39fe05d77b5 Mon Sep 17 00:00:00 2001 From: perrysong Date: Mon, 8 May 2023 18:50:14 +0800 Subject: [PATCH] Added valid-v-if-template-root rule. --- docs/rules/index.md | 1 + docs/rules/valid-template-root.md | 2 +- docs/rules/valid-v-if-template-root.md | 40 +++++++ lib/configs/essential.js | 1 + lib/configs/vue3-essential.js | 1 + lib/index.js | 1 + lib/rules/valid-v-if-template-root.js | 72 +++++++++++++ tests/lib/rules/valid-v-if-template-root.js | 111 ++++++++++++++++++++ 8 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 docs/rules/valid-v-if-template-root.md create mode 100644 lib/rules/valid-v-if-template-root.js create mode 100644 tests/lib/rules/valid-v-if-template-root.js diff --git a/docs/rules/index.md b/docs/rules/index.md index eca5a3191..052df19bc 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -118,6 +118,7 @@ Rules in this category are enabled for all presets provided by eslint-plugin-vue | [vue/valid-v-else](./valid-v-else.md) | enforce valid `v-else` directives | | :three::two::warning: | | [vue/valid-v-for](./valid-v-for.md) | enforce valid `v-for` directives | | :three::two::warning: | | [vue/valid-v-html](./valid-v-html.md) | enforce valid `v-html` directives | | :three::two::warning: | +| [vue/valid-v-if-template-root](./valid-v-if-template-root.md) | enforce valid `v-if` directives on root element | | :three::two::warning: | | [vue/valid-v-if](./valid-v-if.md) | enforce valid `v-if` directives | | :three::two::warning: | | [vue/valid-v-is](./valid-v-is.md) | enforce valid `v-is` directives | | :three::warning: | | [vue/valid-v-memo](./valid-v-memo.md) | enforce valid `v-memo` directives | | :three::warning: | diff --git a/docs/rules/valid-template-root.md b/docs/rules/valid-template-root.md index 14a56edc0..144581a1c 100644 --- a/docs/rules/valid-template-root.md +++ b/docs/rules/valid-template-root.md @@ -46,4 +46,4 @@ This rule was introduced in eslint-plugin-vue v3.11.0 ## :mag: Implementation - [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/valid-template-root.js) -- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/valid-template-root.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/valid-template-root.js) \ No newline at end of file diff --git a/docs/rules/valid-v-if-template-root.md b/docs/rules/valid-v-if-template-root.md new file mode 100644 index 000000000..c1adfb7ad --- /dev/null +++ b/docs/rules/valid-v-if-template-root.md @@ -0,0 +1,40 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/valid-v-if-template-root +description: enforce valid `v-if` directives on root element +--- +# vue/valid-v-if-template-root + +> enforce valid `v-if` directives on root element + +- :exclamation: ***This rule has not been released yet.*** +- :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"`. + +This rule checks whether every template root is valid. + +## :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/valid-v-if-template-root.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/valid-v-if-template-root.js) diff --git a/lib/configs/essential.js b/lib/configs/essential.js index 944a162ea..d89aaf3cc 100644 --- a/lib/configs/essential.js +++ b/lib/configs/essential.js @@ -62,6 +62,7 @@ module.exports = { 'vue/valid-v-else': 'error', 'vue/valid-v-for': 'error', 'vue/valid-v-html': 'error', + 'vue/valid-v-if-template-root': 'error', 'vue/valid-v-if': 'error', 'vue/valid-v-model': 'error', 'vue/valid-v-on': 'error', diff --git a/lib/configs/vue3-essential.js b/lib/configs/vue3-essential.js index 5fe530beb..4702f2c94 100644 --- a/lib/configs/vue3-essential.js +++ b/lib/configs/vue3-essential.js @@ -77,6 +77,7 @@ module.exports = { 'vue/valid-v-else': 'error', 'vue/valid-v-for': 'error', 'vue/valid-v-html': 'error', + 'vue/valid-v-if-template-root': 'error', 'vue/valid-v-if': 'error', 'vue/valid-v-is': 'error', 'vue/valid-v-memo': 'error', diff --git a/lib/index.js b/lib/index.js index aef60a604..16648b792 100644 --- a/lib/index.js +++ b/lib/index.js @@ -219,6 +219,7 @@ module.exports = { 'valid-v-else': require('./rules/valid-v-else'), 'valid-v-for': require('./rules/valid-v-for'), 'valid-v-html': require('./rules/valid-v-html'), + 'valid-v-if-template-root': require('./rules/valid-v-if-template-root'), 'valid-v-if': require('./rules/valid-v-if'), 'valid-v-is': require('./rules/valid-v-is'), 'valid-v-memo': require('./rules/valid-v-memo'), diff --git a/lib/rules/valid-v-if-template-root.js b/lib/rules/valid-v-if-template-root.js new file mode 100644 index 000000000..2cd62cfe2 --- /dev/null +++ b/lib/rules/valid-v-if-template-root.js @@ -0,0 +1,72 @@ +/** + * @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') + +/** + * Get the number of root element directive + * @param {VNode[]} rootElements The start tag node to check. + * @param {string} directiveName The directive name to check. + */ +function getDirectiveLength(rootElements, directiveName) { + if (!directiveName) return 0 + return rootElements.filter( + (element) => + element.type === 'VElement' && utils.hasDirective(element, directiveName) + ).length +} + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'enforce valid `v-if` directives on root element', + categories: ['vue3-essential', 'essential'], + url: 'https://eslint.vuejs.org/rules/valid-v-if-template-root.html' + }, + fixable: null, + schema: [] + }, + /** @param {RuleContext} context */ + create(context) { + const sourceCode = context.getSourceCode() + + return { + /** @param {Program} program */ + Program(program) { + const element = program.templateBody + if (element == null) { + return + } + + const rootElements = [] + for (const child of element.children) { + if (sourceCode.getText(child).trim() !== '') { + rootElements.push(child) + } + } + + if (rootElements.length === 0) return + const hasRootVIfLength = getDirectiveLength(rootElements, 'if') + const hasRootVElseLength = getDirectiveLength(rootElements, 'else') + const hasRootVElseIfLength = getDirectiveLength(rootElements, 'else-if') + if ( + hasRootVIfLength === 1 && + hasRootVElseLength === 0 && + hasRootVElseIfLength === 0 + ) { + 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/valid-v-if-template-root.js b/tests/lib/rules/valid-v-if-template-root.js new file mode 100644 index 000000000..bca90aebd --- /dev/null +++ b/tests/lib/rules/valid-v-if-template-root.js @@ -0,0 +1,111 @@ +/** + * @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/valid-v-if-template-root') + +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-v-if-template-root', 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: '