Skip to content

Commit

Permalink
fix(valid-template-root): no v-if on template root
Browse files Browse the repository at this point in the history
  • Loading branch information
perrysong committed Apr 25, 2023
1 parent 6916db0 commit b1782bb
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 10 deletions.
13 changes: 12 additions & 1 deletion docs/rules/valid-template-root.md
Expand Up @@ -37,7 +37,18 @@ This rule reports the template root in the following cases:

## :wrench: Options

Nothing.
```json
{
"vue/valid-template-root": [
"error",
{
"ignoreOnlyIfDirective": true
}
]
}
```

- `ignoreOnlyIfDirective` (`boolean`) ... ignores the root element only `v-if` directive. Default is `true`.

## :rocket: Version

Expand Down
70 changes: 61 additions & 9 deletions lib/rules/valid-template-root.js
Expand Up @@ -7,6 +7,19 @@

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',
Expand All @@ -16,10 +29,26 @@ module.exports = {
url: 'https://eslint.vuejs.org/rules/valid-template-root.html'
},
fixable: null,
schema: []
schema: [
{
type: 'object',
properties: {
ignoreOnlyIfDirective: {
type: 'boolean'
}
},
additionalProperties: false
}
]
},
/** @param {RuleContext} context */
create(context) {
const options = context.options[0] || {}
const ignoreOnlyIfDirective =
options.ignoreOnlyIfDirective !== undefined
? options.ignoreOnlyIfDirective
: true

const sourceCode = context.getSourceCode()

return {
Expand All @@ -39,14 +68,37 @@ module.exports = {
}
}

if (hasSrc && rootElements.length > 0) {
for (const element of rootElements) {
context.report({
node: element,
loc: element.loc,
message:
"The template root with 'src' attribute is required to be empty."
})
if (rootElements.length > 0) {
if (hasSrc) {
for (const element of rootElements) {
context.report({
node: element,
loc: element.loc,
message:
"The template root with 'src' attribute is required to be empty."
})
}
}

if (!ignoreOnlyIfDirective) {
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`.'
})
}
}
} else if (rootElements.length === 0 && !hasSrc) {
context.report({
Expand Down
16 changes: 16 additions & 0 deletions tests/lib/rules/valid-template-root.js
Expand Up @@ -99,6 +99,16 @@ tester.run('valid-template-root', rule, {
filename: 'test.vue',
code: '<template><template></template></template>'
}
{
filename: 'test.vue',
options: [{ ignoreOnlyIfDirective: false }],
code: '<template> <div v-if="mode === \'a\'"></div><div v-if="mode === \'b\'"></div></template>'
},
{
filename: 'test.vue',
options: [{ ignoreOnlyIfDirective: false }],
code: '<template> <div v-if="loading"></div><div v-else></div></template>'
}
],
invalid: [
{
Expand All @@ -119,6 +129,12 @@ tester.run('valid-template-root', rule, {
errors: [
"The template root with 'src' attribute is required to be empty."
]
},
{
filename: 'test.vue',
code: '<template><div v-if="foo"></div></template>',
options: [{ ignoreOnlyIfDirective: false }],
errors: ['`v-if` should not be used on root element without `v-else`.']
}
]
})

0 comments on commit b1782bb

Please sign in to comment.