Skip to content

Commit c019c6e

Browse files
author
perrysong
committed
fix(valid-template-root): no v-if on template root
1 parent 6916db0 commit c019c6e

File tree

3 files changed

+89
-10
lines changed

3 files changed

+89
-10
lines changed

docs/rules/valid-template-root.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,18 @@ This rule reports the template root in the following cases:
3737

3838
## :wrench: Options
3939

40-
Nothing.
40+
```json
41+
{
42+
"vue/valid-template-root": [
43+
"error",
44+
{
45+
"ignoreOnlyIfDirective": true
46+
}
47+
]
48+
}
49+
```
50+
51+
- `ignoreOnlyIfDirective` (`boolean`) ... ignore the root elements and only have the `v-if` directive. Default is `true`.
4152

4253
## :rocket: Version
4354

lib/rules/valid-template-root.js

+61-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@
77

88
const utils = require('../utils')
99

10+
/**
11+
* Get the number of root element directive
12+
* @param {VNode[]} rootElements The start tag node to check.
13+
* @param {string} directiveName The directive name to check.
14+
*/
15+
function getDirectiveLength(rootElements, directiveName) {
16+
if (!directiveName) return 0
17+
return rootElements.filter(
18+
(element) =>
19+
element.type === 'VElement' && utils.hasDirective(element, directiveName)
20+
).length
21+
}
22+
1023
module.exports = {
1124
meta: {
1225
type: 'problem',
@@ -16,10 +29,26 @@ module.exports = {
1629
url: 'https://eslint.vuejs.org/rules/valid-template-root.html'
1730
},
1831
fixable: null,
19-
schema: []
32+
schema: [
33+
{
34+
type: 'object',
35+
properties: {
36+
ignoreOnlyIfDirective: {
37+
type: 'boolean'
38+
}
39+
},
40+
additionalProperties: false
41+
}
42+
]
2043
},
2144
/** @param {RuleContext} context */
2245
create(context) {
46+
const options = context.options[0] || {}
47+
const ignoreOnlyIfDirective =
48+
options.ignoreOnlyIfDirective !== undefined
49+
? options.ignoreOnlyIfDirective
50+
: true
51+
2352
const sourceCode = context.getSourceCode()
2453

2554
return {
@@ -39,14 +68,37 @@ module.exports = {
3968
}
4069
}
4170

42-
if (hasSrc && rootElements.length > 0) {
43-
for (const element of rootElements) {
44-
context.report({
45-
node: element,
46-
loc: element.loc,
47-
message:
48-
"The template root with 'src' attribute is required to be empty."
49-
})
71+
if (rootElements.length > 0) {
72+
if (hasSrc) {
73+
for (const element of rootElements) {
74+
context.report({
75+
node: element,
76+
loc: element.loc,
77+
message:
78+
"The template root with 'src' attribute is required to be empty."
79+
})
80+
}
81+
}
82+
83+
if (!ignoreOnlyIfDirective) {
84+
const hasRootVIfLength = getDirectiveLength(rootElements, 'if')
85+
const hasRootVElseLength = getDirectiveLength(rootElements, 'else')
86+
const hasRootVElseIfLength = getDirectiveLength(
87+
rootElements,
88+
'else-if'
89+
)
90+
if (
91+
hasRootVIfLength === 1 &&
92+
hasRootVElseLength === 0 &&
93+
hasRootVElseIfLength === 0
94+
) {
95+
context.report({
96+
node: element,
97+
loc: element.loc,
98+
message:
99+
'`v-if` should not be used on root element without `v-else`.'
100+
})
101+
}
50102
}
51103
} else if (rootElements.length === 0 && !hasSrc) {
52104
context.report({

tests/lib/rules/valid-template-root.js

+16
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ tester.run('valid-template-root', rule, {
9999
filename: 'test.vue',
100100
code: '<template><template></template></template>'
101101
}
102+
{
103+
filename: 'test.vue',
104+
options: [{ ignoreOnlyIfDirective: false }],
105+
code: '<template> <div v-if="mode === \'a\'"></div><div v-if="mode === \'b\'"></div></template>'
106+
},
107+
{
108+
filename: 'test.vue',
109+
options: [{ ignoreOnlyIfDirective: false }],
110+
code: '<template> <div v-if="loading"></div><div v-else></div></template>'
111+
}
102112
],
103113
invalid: [
104114
{
@@ -119,6 +129,12 @@ tester.run('valid-template-root', rule, {
119129
errors: [
120130
"The template root with 'src' attribute is required to be empty."
121131
]
132+
},
133+
{
134+
filename: 'test.vue',
135+
code: '<template><div v-if="foo"></div></template>',
136+
options: [{ ignoreOnlyIfDirective: false }],
137+
errors: ['`v-if` should not be used on root element without `v-else`.']
122138
}
123139
]
124140
})

0 commit comments

Comments
 (0)