Skip to content

Commit 9cfa4bf

Browse files
committed
Make the indent rules supports ECMAScript 2020
1 parent 800182c commit 9cfa4bf

32 files changed

+451
-23
lines changed

Diff for: docs/rules/html-indent.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ description: enforce consistent indentation in `<template>`
1515
This rule enforces a consistent indentation style in `<template>`. The default style is 2 spaces.
1616

1717
- This rule checks all tags, also all expressions in directives and mustaches.
18-
- In the expressions, this rule supports ECMAScript 2017 syntaxes. It ignores unknown AST nodes, but it might be confused by non-standard syntaxes.
18+
- In the expressions, this rule supports ECMAScript 2020 syntaxes. It ignores unknown AST nodes, but it might be confused by non-standard syntaxes.
1919

2020
<eslint-code-block fix :rules="{'vue/html-indent': ['error']}">
2121

Diff for: lib/utils/indent-common.js

+90-18
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const assert = require('assert')
1414
// Helpers
1515
// ------------------------------------------------------------------------------
1616

17-
const KNOWN_NODES = new Set(['ArrayExpression', 'ArrayPattern', 'ArrowFunctionExpression', 'AssignmentExpression', 'AssignmentPattern', 'AwaitExpression', 'BinaryExpression', 'BlockStatement', 'BreakStatement', 'CallExpression', 'CatchClause', 'ClassBody', 'ClassDeclaration', 'ClassExpression', 'ConditionalExpression', 'ContinueStatement', 'DebuggerStatement', 'DoWhileStatement', 'EmptyStatement', 'ExperimentalRestProperty', 'ExperimentalSpreadProperty', 'ExportAllDeclaration', 'ExportDefaultDeclaration', 'ExportNamedDeclaration', 'ExportSpecifier', 'ExpressionStatement', 'ForInStatement', 'ForOfStatement', 'ForStatement', 'FunctionDeclaration', 'FunctionExpression', 'Identifier', 'IfStatement', 'ImportDeclaration', 'ImportDefaultSpecifier', 'ImportNamespaceSpecifier', 'ImportSpecifier', 'LabeledStatement', 'Literal', 'LogicalExpression', 'MemberExpression', 'MetaProperty', 'MethodDefinition', 'NewExpression', 'ObjectExpression', 'ObjectPattern', 'Program', 'Property', 'RestElement', 'ReturnStatement', 'SequenceExpression', 'SpreadElement', 'Super', 'SwitchCase', 'SwitchStatement', 'TaggedTemplateExpression', 'TemplateElement', 'TemplateLiteral', 'ThisExpression', 'ThrowStatement', 'TryStatement', 'UnaryExpression', 'UpdateExpression', 'VariableDeclaration', 'VariableDeclarator', 'WhileStatement', 'WithStatement', 'YieldExpression', 'VAttribute', 'VDirectiveKey', 'VDocumentFragment', 'VElement', 'VEndTag', 'VExpressionContainer', 'VFilter', 'VFilterSequenceExpression', 'VForExpression', 'VIdentifier', 'VLiteral', 'VOnExpression', 'VSlotScopeExpression', 'VStartTag', 'VText'])
17+
const KNOWN_NODES = new Set(['ArrayExpression', 'ArrayPattern', 'ArrowFunctionExpression', 'AssignmentExpression', 'AssignmentPattern', 'AwaitExpression', 'BinaryExpression', 'BlockStatement', 'BreakStatement', 'CallExpression', 'CatchClause', 'ClassBody', 'ClassDeclaration', 'ClassExpression', 'ConditionalExpression', 'ContinueStatement', 'DebuggerStatement', 'DoWhileStatement', 'EmptyStatement', 'ExperimentalRestProperty', 'ExperimentalSpreadProperty', 'ExportAllDeclaration', 'ExportDefaultDeclaration', 'ExportDefaultSpecifier', 'ExportNamedDeclaration', 'ExportNamespaceSpecifier', 'ExportSpecifier', 'ExpressionStatement', 'ForInStatement', 'ForOfStatement', 'ForStatement', 'FunctionDeclaration', 'FunctionExpression', 'Identifier', 'IfStatement', 'ImportDeclaration', 'ImportDefaultSpecifier', 'ImportExpression', 'ImportNamespaceSpecifier', 'ImportSpecifier', 'LabeledStatement', 'Literal', 'LogicalExpression', 'MemberExpression', 'MetaProperty', 'MethodDefinition', 'NewExpression', 'ObjectExpression', 'ObjectPattern', 'OptionalCallExpression', 'OptionalMemberExpression', 'Program', 'Property', 'RestElement', 'ReturnStatement', 'SequenceExpression', 'SpreadElement', 'Super', 'SwitchCase', 'SwitchStatement', 'TaggedTemplateExpression', 'TemplateElement', 'TemplateLiteral', 'ThisExpression', 'ThrowStatement', 'TryStatement', 'UnaryExpression', 'UpdateExpression', 'VariableDeclaration', 'VariableDeclarator', 'WhileStatement', 'WithStatement', 'YieldExpression', 'VAttribute', 'VDirectiveKey', 'VDocumentFragment', 'VElement', 'VEndTag', 'VExpressionContainer', 'VFilter', 'VFilterSequenceExpression', 'VForExpression', 'VIdentifier', 'VLiteral', 'VOnExpression', 'VSlotScopeExpression', 'VStartTag', 'VText'])
1818
const LT_CHAR = /[\r\n\u2028\u2029]/
1919
const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g
2020
const BLOCK_COMMENT_PREFIX = /^\s*\*/
@@ -552,7 +552,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
552552
}
553553
return true
554554
}
555-
if (t === 'CallExpression' || t === 'NewExpression') {
555+
if (t === 'CallExpression' || t === 'NewExpression' || t === 'OptionalCallExpression') {
556556
const openParen = tokenStore.getTokenAfter(parent.callee, isNotRightParen)
557557
return parent.arguments.some(param =>
558558
getFirstAndLastTokens(param, openParen.range[1]).firstToken.range[0] === token.range[0]
@@ -1065,7 +1065,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
10651065
}
10661066
},
10671067

1068-
CallExpression (node) {
1068+
'CallExpression, OptionalCallExpression' (node) {
10691069
const firstToken = tokenStore.getFirstToken(node)
10701070
const rightToken = tokenStore.getLastToken(node)
10711071
const leftToken = tokenStore.getTokenAfter(node.callee, isLeftParen)
@@ -1074,6 +1074,15 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
10741074
processNodeList(node.arguments, leftToken, rightToken, 1)
10751075
},
10761076

1077+
ImportExpression (node) {
1078+
const firstToken = tokenStore.getFirstToken(node)
1079+
const rightToken = tokenStore.getLastToken(node)
1080+
const leftToken = tokenStore.getTokenAfter(firstToken, isLeftParen)
1081+
1082+
setOffset(leftToken, 1, firstToken)
1083+
processNodeList([node.source], leftToken, rightToken, 1)
1084+
},
1085+
10771086
CatchClause (node) {
10781087
const firstToken = tokenStore.getFirstToken(node)
10791088
const bodyToken = tokenStore.getFirstToken(node.body)
@@ -1145,7 +1154,18 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
11451154
if (isSemicolon(last(tokens))) {
11461155
tokens.pop()
11471156
}
1148-
setOffset(tokens, 1, firstToken)
1157+
if (!node.exported) {
1158+
setOffset(tokens, 1, firstToken)
1159+
} else {
1160+
// export * as foo from "mod"
1161+
const asToken = tokenStore.getTokenBefore(node.exported)
1162+
const exportedTokens = tokenStore.getTokensBetween(asToken, node.exported, {
1163+
includeComments: true
1164+
})
1165+
const oneIndentTokens = tokens.filter(t => !exportedTokens.includes(t))
1166+
setOffset(oneIndentTokens, 1, firstToken)
1167+
setOffset(exportedTokens, 1, tokenStore.getTokenBefore(asToken))
1168+
}
11491169
},
11501170

11511171
ExportDefaultDeclaration (node) {
@@ -1162,17 +1182,65 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
11621182
const declarationToken = tokenStore.getFirstToken(node, 1)
11631183
setOffset(declarationToken, 1, exportToken)
11641184
} else {
1165-
// export {foo, bar}; or export {foo, bar} from "mod";
1166-
const leftParenToken = tokenStore.getFirstToken(node, 1)
1167-
const rightParenToken = tokenStore.getLastToken(node, isRightBrace)
1168-
setOffset(leftParenToken, 0, exportToken)
1169-
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)
1170-
1171-
const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
1172-
if (maybeFromToken != null && sourceCode.getText(maybeFromToken) === 'from') {
1173-
const fromToken = maybeFromToken
1174-
const nameToken = tokenStore.getTokenAfter(fromToken)
1175-
setOffset([fromToken, nameToken], 1, exportToken)
1185+
const firstSpecifier = node.specifiers[0]
1186+
const secondSpecifier = node.specifiers[1]
1187+
if (!firstSpecifier || firstSpecifier.type === 'ExportSpecifier') {
1188+
// export {foo, bar}; or export {foo, bar} from "mod";
1189+
const leftParenToken = tokenStore.getFirstToken(node, 1)
1190+
const rightParenToken = tokenStore.getLastToken(node, isRightBrace)
1191+
setOffset(leftParenToken, 0, exportToken)
1192+
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)
1193+
1194+
const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
1195+
if (maybeFromToken != null && sourceCode.getText(maybeFromToken) === 'from') {
1196+
const fromToken = maybeFromToken
1197+
const nameToken = tokenStore.getTokenAfter(fromToken)
1198+
setOffset([fromToken, nameToken], 1, exportToken)
1199+
}
1200+
} else if (firstSpecifier.type === 'ExportDefaultSpecifier') {
1201+
// for babel-eslint
1202+
if (secondSpecifier && secondSpecifier.type === 'ExportNamespaceSpecifier') {
1203+
// There is a pattern:
1204+
// export Foo, * as foo from "foo"
1205+
const idToken = tokenStore.getFirstToken(firstSpecifier)// Foo
1206+
const commaToken = tokenStore.getTokenAfter(firstSpecifier) // comma
1207+
const astaToken = tokenStore.getFirstToken(secondSpecifier)// *
1208+
const fromToken = tokenStore.getTokenAfter(secondSpecifier) // from
1209+
const modToken = tokenStore.getTokenAfter(fromToken)// "foo"
1210+
setOffset([idToken, commaToken, astaToken, fromToken, modToken], 1, exportToken)
1211+
} else {
1212+
// There are 3 patterns:
1213+
// export Foo from "foo"
1214+
// export Foo, {} from "foo"
1215+
// export Foo, {a} from "foo"
1216+
const idToken = tokenStore.getFirstToken(firstSpecifier)
1217+
const nextToken = tokenStore.getTokenAfter(firstSpecifier)
1218+
if (isComma(nextToken)) {
1219+
const leftBrace = tokenStore.getTokenAfter(nextToken)
1220+
const rightBrace = tokenStore.getLastToken(node, isRightBrace)
1221+
setOffset([idToken, nextToken], 1, exportToken)
1222+
setOffset(leftBrace, 0, idToken)
1223+
processNodeList(node.specifiers.slice(1), leftBrace, rightBrace, 1)
1224+
const fromToken = tokenStore.getTokenAfter(rightBrace) // from
1225+
const modToken = tokenStore.getTokenAfter(fromToken)// "foo"
1226+
setOffset([fromToken, modToken], 1, exportToken)
1227+
} else {
1228+
const modToken = tokenStore.getTokenAfter(nextToken)// "foo"
1229+
setOffset([
1230+
idToken,
1231+
nextToken, // from
1232+
modToken
1233+
], 1, exportToken)
1234+
}
1235+
}
1236+
} else if (firstSpecifier.type === 'ExportNamespaceSpecifier') {
1237+
// for babel-eslint
1238+
// There is a pattern:
1239+
// export * as foo from "foo"
1240+
const astaToken = tokenStore.getFirstToken(firstSpecifier)
1241+
const fromToken = tokenStore.getTokenAfter(firstSpecifier)
1242+
const modToken = tokenStore.getTokenAfter(fromToken)
1243+
setOffset([astaToken, fromToken, modToken], 1, exportToken)
11761244
}
11771245
}
11781246
},
@@ -1185,12 +1253,16 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
11851253

11861254
'ForInStatement, ForOfStatement' (node) {
11871255
const forToken = tokenStore.getFirstToken(node)
1188-
const leftParenToken = tokenStore.getTokenAfter(forToken)
1256+
const awaitToken = (node.await && tokenStore.getTokenAfter(forToken)) || null
1257+
const leftParenToken = tokenStore.getTokenAfter(awaitToken || forToken)
11891258
const leftToken = tokenStore.getTokenAfter(leftParenToken)
11901259
const inToken = tokenStore.getTokenAfter(leftToken, isNotRightParen)
11911260
const rightToken = tokenStore.getTokenAfter(inToken)
11921261
const rightParenToken = tokenStore.getTokenBefore(node.body, isNotLeftParen)
11931262

1263+
if (awaitToken != null) {
1264+
setOffset(awaitToken, 0, forToken)
1265+
}
11941266
setOffset(leftParenToken, 1, forToken)
11951267
setOffset(leftToken, 1, leftParenToken)
11961268
setOffset(inToken, 1, leftToken)
@@ -1353,7 +1425,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
13531425
}
13541426
},
13551427

1356-
ImportNamespaceSpecifier (node) {
1428+
'ImportNamespaceSpecifier, ExportNamespaceSpecifier' (node) {
13571429
const tokens = tokenStore.getTokens(node)
13581430
const firstToken = tokens.shift()
13591431
setOffset(tokens, 1, firstToken)
@@ -1367,7 +1439,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
13671439
setOffset([colonToken, bodyToken], 1, labelToken)
13681440
},
13691441

1370-
'MemberExpression, MetaProperty' (node) {
1442+
'MemberExpression, MetaProperty, OptionalMemberExpression' (node) {
13711443
const objectToken = tokenStore.getFirstToken(node)
13721444
if (node.computed) {
13731445
const leftBracketToken = tokenStore.getTokenBefore(node.property, isLeftBracket)

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
},
5454
"devDependencies": {
5555
"@types/node": "^4.2.16",
56-
"@typescript-eslint/parser": "^2.6.1",
56+
"@typescript-eslint/parser": "^2.13.0",
5757
"acorn": "^7.1.0",
5858
"babel-eslint": "^10.0.2",
5959
"chai": "^4.1.0",
@@ -66,7 +66,7 @@
6666
"lodash": "^4.17.4",
6767
"mocha": "^5.2.0",
6868
"nyc": "^12.0.2",
69-
"typescript": "^3.5.2",
69+
"typescript": "^3.7.4",
7070
"vue-eslint-editor": "^0.1.4",
7171
"vuepress": "^0.14.5"
7272
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
2+
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
3+
<template>
4+
<div v-bind:a="a
5+
??
6+
b
7+
"/>
8+
</template>

Diff for: tests/fixtures/html-indent/optional-chaining-01.vue

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
2+
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
3+
4+
<template>
5+
<div v-bind:a="
6+
obj
7+
?.aaa
8+
?.bbb
9+
?.ccc
10+
"/>
11+
</template>

Diff for: tests/fixtures/html-indent/optional-chaining-02.vue

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
2+
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
3+
<template>
4+
<div v-bind:a="
5+
obj?.
6+
aaa?.
7+
bbb?.
8+
ccc
9+
"/>
10+
</template>

Diff for: tests/fixtures/html-indent/optional-chaining-03.vue

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
2+
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
3+
<template>
4+
<div v-bind:a="
5+
obj?.
6+
[aaa]?.
7+
[bbb]
8+
?.[ccc]
9+
"/>
10+
</template>

Diff for: tests/fixtures/html-indent/optional-chaining-04.vue

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
2+
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
3+
<template>
4+
<div v-bind:a="
5+
obj?.
6+
(
7+
aaa
8+
)?.
9+
(
10+
bbb
11+
)
12+
?.(
13+
ccc
14+
)
15+
"/>
16+
</template>

Diff for: tests/fixtures/script-indent/bigint-01.vue

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!--{}-->
2+
<script>
3+
var a =
4+
10n
5+
+
6+
5n
7+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
2+
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
3+
<script>
4+
export
5+
*
6+
as
7+
foo
8+
from
9+
"mod"
10+
;
11+
export
12+
*
13+
as
14+
bar
15+
from
16+
"mod"
17+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
2+
<script>
3+
export
4+
Foo
5+
from
6+
"mod"
7+
;
8+
export
9+
Bar
10+
from
11+
"mod"
12+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
2+
<script>
3+
export
4+
Foo
5+
,
6+
{
7+
a
8+
as
9+
A
10+
,
11+
b
12+
as
13+
B
14+
}
15+
from
16+
"mod"
17+
;
18+
export
19+
Bar,
20+
{
21+
c
22+
as
23+
C,
24+
d
25+
as
26+
D
27+
}
28+
from
29+
"mod"
30+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
2+
<script>
3+
export
4+
Foo
5+
,
6+
*
7+
as
8+
fooAll
9+
from
10+
"mod"
11+
;
12+
export
13+
Bar,
14+
*
15+
as
16+
barAll
17+
from
18+
"mod"
19+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
2+
<script>
3+
export
4+
*
5+
as
6+
foo
7+
from
8+
"mod"
9+
;
10+
export
11+
*
12+
as
13+
bar
14+
from
15+
"mod"
16+
</script>

Diff for: tests/fixtures/script-indent/for-await-of-01.vue

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!--{}-->
2+
<script>
3+
async function fn() {
4+
for
5+
await
6+
(
7+
a
8+
of
9+
b
10+
)
11+
{
12+
;
13+
}
14+
}
15+
</script>
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!--{}-->
2+
<script>
3+
const fs = import
4+
(
5+
'fs'
6+
)
7+
</script>

0 commit comments

Comments
 (0)