Skip to content

Commit 3e18ed0

Browse files
committed
Merge branch 'master' into patch-22-render-return
2 parents e4e31af + b8d11de commit 3e18ed0

25 files changed

+2590
-503
lines changed

docs/rules/no-parsing-error.md

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
# Disallow parsing errors in `<template>` (no-parsing-error)
22

3-
This rule reports syntax errors in directives/mustaches of `<template>`.
3+
This rule reports syntax errors in `<template>`. For example:
4+
5+
- Syntax errors of scripts in directives.
6+
- Syntax errors of scripts in mustaches.
7+
- Syntax errors of HTML.
8+
- Invalid end tags.
9+
- Attributes in end tags.
10+
- ...
11+
- See also: https://html.spec.whatwg.org/multipage/parsing.html#parse-errors
412

513
## :book: Rule Details
614

@@ -25,4 +33,56 @@ Then reports syntax errors if exist.
2533

2634
## :wrench: Options
2735

28-
Nothing.
36+
```json
37+
{
38+
"vue/no-parsing-error": ["error", {
39+
"abrupt-closing-of-empty-comment": false,
40+
"absence-of-digits-in-numeric-character-reference": false,
41+
"cdata-in-html-content": false,
42+
"character-reference-outside-unicode-range": false,
43+
"control-character-in-input-stream": false,
44+
"control-character-reference": false,
45+
"eof-before-tag-name": false,
46+
"eof-in-cdata": false,
47+
"eof-in-comment": false,
48+
"eof-in-tag": false,
49+
"incorrectly-closed-comment": false,
50+
"incorrectly-opened-comment": false,
51+
"invalid-first-character-of-tag-name": false,
52+
"missing-attribute-value": false,
53+
"missing-end-tag-name": false,
54+
"missing-semicolon-after-character-reference": false,
55+
"missing-whitespace-between-attributes": false,
56+
"nested-comment": false,
57+
"noncharacter-character-reference": false,
58+
"noncharacter-in-input-stream": false,
59+
"null-character-reference": false,
60+
"surrogate-character-reference": false,
61+
"surrogate-in-input-stream": false,
62+
"unexpected-character-in-attribute-name": false,
63+
"unexpected-character-in-unquoted-attribute-value": false,
64+
"unexpected-equals-sign-before-attribute-name": false,
65+
"unexpected-null-character": false,
66+
"unexpected-question-mark-instead-of-tag-name": false,
67+
"unexpected-solidus-in-tag": false,
68+
"unknown-named-character-reference": false,
69+
"end-tag-with-attributes": false,
70+
"duplicate-attribute": false,
71+
"end-tag-with-trailing-solidus": false,
72+
"non-void-html-element-start-tag-with-trailing-solidus": false,
73+
"x-invalid-end-tag": false,
74+
"x-invalid-namespace": false
75+
}]
76+
}
77+
```
78+
79+
You can enable HTML syntax errors by opt-in.
80+
81+
For example, if `"x-invalid-end-tag": true` is given then this rule will catch the end tags of elements which have not opened.
82+
The error codes are defined in [WHATWG spec](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors), but this rule does not support all of those (E.g., it does not catch errors about DOCTYPE).
83+
Also, The codes which have `x-` prefix are original in this rule because errors in tree construction phase have not codified yet.
84+
85+
- `x-invalid-end-tag` enables the errors about the end tags of elements which have not opened.
86+
- `x-invalid-namespace` enables the errors about invalid `xmlns` attributes. See also [step 10. of "create an element for a token"](https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token).
87+
88+
> TODO(mysticatea): I will revisit errors in tree construction phase after those are codified.

docs/rules/require-prop-types.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Prop definitions should be detailed (require-prop-types)
2+
3+
In committed code, prop definitions should always be as detailed as possible, specifying at least type(s).
4+
5+
## :book: Rule Details
6+
7+
This rule enforces that a `props` statement contains type definition.
8+
9+
:-1: Examples of **incorrect** code for this rule:
10+
11+
```js
12+
export default {
13+
props: ['status']
14+
}
15+
```
16+
17+
:+1: Examples of **correct** code for this rule:
18+
19+
```js
20+
export default {
21+
props: {
22+
status: String
23+
}
24+
}
25+
```
26+
27+
```js
28+
export default {
29+
props: {
30+
status: {
31+
type: String,
32+
required: true,
33+
validate: function (value) {
34+
return ['syncing', 'synced', 'version-conflict', 'error'].indexOf(value) !== -1
35+
}
36+
}
37+
}
38+
}
39+
```
40+
## :wrench: Options
41+
42+
Nothing.

lib/rules/html-end-tags.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const utils = require('../utils')
2424
function create (context) {
2525
utils.registerTemplateBodyVisitor(context, {
2626
VElement (node) {
27-
const name = node.startTag.id.name
27+
const name = node.name
2828
const isVoid = utils.isVoidElementName(name)
2929
const hasEndTag = node.endTag != null
3030

lib/rules/html-no-self-closing.js

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,23 @@ const utils = require('../utils')
2323
*/
2424
function create (context) {
2525
utils.registerTemplateBodyVisitor(context, {
26-
'VStartTag[selfClosing=true]' (node) {
27-
if (!utils.isSvgElementName(node.id.name)) {
28-
const pos = node.range[1] - 2
29-
context.report({
30-
node,
31-
loc: node.loc,
32-
message: 'Self-closing should not be used.',
33-
fix: (fixer) => fixer.removeRange([pos, pos + 1])
34-
})
26+
'VElement' (node) {
27+
if (utils.isSvgElementName(node.name)) {
28+
return
3529
}
30+
31+
const sourceCode = context.parserServices.getTemplateBodyTokenStore(context)
32+
const lastToken = sourceCode.getLastToken(node.startTag)
33+
if (lastToken.type !== 'HTMLSelfClosingTagClose') {
34+
return
35+
}
36+
37+
context.report({
38+
node: lastToken,
39+
loc: lastToken.loc,
40+
message: 'Self-closing should not be used.',
41+
fix: (fixer) => fixer.removeRange([lastToken.range[0], lastToken.range[0] + 1])
42+
})
3643
}
3744
})
3845

@@ -49,8 +56,10 @@ module.exports = {
4956
docs: {
5057
description: 'disallow self-closing elements.',
5158
category: 'Best Practices',
52-
recommended: false
59+
recommended: false,
60+
replacedBy: []
5361
},
62+
deprecated: true,
5463
fixable: 'code',
5564
schema: []
5665
}

lib/rules/name-property-casing.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ function create (context) {
2121

2222
return utils.executeOnVue(context, (obj) => {
2323
const node = obj.properties
24-
.filter(item => (
24+
.find(item => (
2525
item.type === 'Property' &&
2626
item.key.name === 'name' &&
2727
item.value.type === 'Literal'
28-
))[0]
28+
))
2929

3030
if (!node) return
3131

lib/rules/no-confusing-v-for-v-if.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ function isUsingIterationVar (vIf) {
3939
function create (context) {
4040
utils.registerTemplateBodyVisitor(context, {
4141
"VAttribute[directive=true][key.name='if']" (node) {
42-
if (utils.hasDirective(node.parent, 'for') && !isUsingIterationVar(node)) {
42+
const element = node.parent.parent
43+
44+
if (utils.hasDirective(element, 'for') && !isUsingIterationVar(node)) {
4345
context.report({
4446
node,
4547
loc: node.loc,

lib/rules/no-invalid-template-root.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,24 @@ function create (context) {
2626

2727
return {
2828
Program (program) {
29-
const node = program.templateBody
30-
if (node == null) {
29+
const element = program.templateBody
30+
if (element == null) {
3131
return
3232
}
3333

34-
const hasSrc = utils.hasAttribute(node.startTag, 'src')
34+
const hasSrc = utils.hasAttribute(element, 'src')
3535
const rootElements = []
3636
let extraText = null
3737
let extraElement = null
3838
let vIf = false
39-
for (const child of node.children) {
39+
for (const child of element.children) {
4040
if (child.type === 'VElement') {
4141
if (rootElements.length === 0 && !hasSrc) {
4242
rootElements.push(child)
43-
vIf = utils.hasDirective(child.startTag, 'if')
44-
} else if (vIf && utils.hasDirective(child.startTag, 'else-if')) {
43+
vIf = utils.hasDirective(child, 'if')
44+
} else if (vIf && utils.hasDirective(child, 'else-if')) {
4545
rootElements.push(child)
46-
} else if (vIf && utils.hasDirective(child.startTag, 'else')) {
46+
} else if (vIf && utils.hasDirective(child, 'else')) {
4747
rootElements.push(child)
4848
vIf = false
4949
} else {
@@ -74,14 +74,14 @@ function create (context) {
7474
})
7575
} else if (rootElements.length === 0 && !hasSrc) {
7676
context.report({
77-
node,
78-
loc: node.loc,
77+
node: element,
78+
loc: element.loc,
7979
message: 'The template root requires exactly one element.'
8080
})
8181
} else {
8282
for (const element of rootElements) {
8383
const tag = element.startTag
84-
const name = tag.id.name
84+
const name = element.name
8585

8686
if (name === 'template' || name === 'slot') {
8787
context.report({
@@ -91,7 +91,7 @@ function create (context) {
9191
data: { name }
9292
})
9393
}
94-
if (utils.hasDirective(tag, 'for')) {
94+
if (utils.hasDirective(element, 'for')) {
9595
context.report({
9696
node: tag,
9797
loc: tag.loc,

lib/rules/no-invalid-v-else-if.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,23 @@ const utils = require('../utils')
2424
function create (context) {
2525
utils.registerTemplateBodyVisitor(context, {
2626
"VAttribute[directive=true][key.name='else-if']" (node) {
27-
if (!utils.prevElementHasIf(node.parent.parent)) {
27+
const element = node.parent.parent
28+
29+
if (!utils.prevElementHasIf(element)) {
2830
context.report({
2931
node,
3032
loc: node.loc,
3133
message: "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."
3234
})
3335
}
34-
if (utils.hasDirective(node.parent, 'if')) {
36+
if (utils.hasDirective(element, 'if')) {
3537
context.report({
3638
node,
3739
loc: node.loc,
3840
message: "'v-else-if' and 'v-if' directives can't exist on the same element."
3941
})
4042
}
41-
if (utils.hasDirective(node.parent, 'else')) {
43+
if (utils.hasDirective(element, 'else')) {
4244
context.report({
4345
node,
4446
loc: node.loc,

lib/rules/no-invalid-v-else.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,23 @@ const utils = require('../utils')
2424
function create (context) {
2525
utils.registerTemplateBodyVisitor(context, {
2626
"VAttribute[directive=true][key.name='else']" (node) {
27-
if (!utils.prevElementHasIf(node.parent.parent)) {
27+
const element = node.parent.parent
28+
29+
if (!utils.prevElementHasIf(element)) {
2830
context.report({
2931
node,
3032
loc: node.loc,
3133
message: "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else' directive."
3234
})
3335
}
34-
if (utils.hasDirective(node.parent, 'if')) {
36+
if (utils.hasDirective(element, 'if')) {
3537
context.report({
3638
node,
3739
loc: node.loc,
3840
message: "'v-else' and 'v-if' directives can't exist on the same element. You may want 'v-else-if' directives."
3941
})
4042
}
41-
if (utils.hasDirective(node.parent, 'else-if')) {
43+
if (utils.hasDirective(element, 'else-if')) {
4244
context.report({
4345
node,
4446
loc: node.loc,

lib/rules/no-invalid-v-for.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,21 @@ function isUsingIterationVar (vFor, vBindKey) {
4343
* @param {ASTNode} element The element node to check.
4444
*/
4545
function checkKey (context, vFor, element) {
46-
const startTag = element.startTag
47-
const vBindKey = utils.getDirective(startTag, 'bind', 'key')
46+
if (element.name === 'template') {
47+
for (const child of element.children) {
48+
if (child.type === 'VElement') {
49+
checkKey(context, vFor, child)
50+
}
51+
}
52+
return
53+
}
4854

49-
if (utils.isCustomComponent(startTag) && vBindKey == null) {
55+
const vBindKey = utils.getDirective(element, 'bind', 'key')
56+
57+
if (utils.isCustomComponent(element) && vBindKey == null) {
5058
context.report({
51-
node: startTag,
52-
loc: startTag.loc,
59+
node: element.startTag,
60+
loc: element.startTag.loc,
5361
message: "Custom elements in iteration require 'v-bind:key' directives."
5462
})
5563
}
@@ -76,13 +84,6 @@ function create (context) {
7684
const element = node.parent.parent
7785

7886
checkKey(context, node, element)
79-
if (element.startTag.id.name === 'template') {
80-
for (const child of element.children) {
81-
if (child.type === 'VElement') {
82-
checkKey(context, node, child)
83-
}
84-
}
85-
}
8687

8788
if (node.key.argument) {
8889
context.report({

lib/rules/no-invalid-v-if.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ const utils = require('../utils')
2424
function create (context) {
2525
utils.registerTemplateBodyVisitor(context, {
2626
"VAttribute[directive=true][key.name='if']" (node) {
27-
if (utils.hasDirective(node.parent, 'else')) {
27+
const element = node.parent.parent
28+
29+
if (utils.hasDirective(element, 'else')) {
2830
context.report({
2931
node,
3032
loc: node.loc,
3133
message: "'v-if' and 'v-else' directives can't exist on the same element. You may want 'v-else-if' directives."
3234
})
3335
}
34-
if (utils.hasDirective(node.parent, 'else-if')) {
36+
if (utils.hasDirective(element, 'else-if')) {
3537
context.report({
3638
node,
3739
loc: node.loc,

0 commit comments

Comments
 (0)