Skip to content

Commit bbcc1f0

Browse files
authored
Make the indent rules supports ECMAScript 2020 (#1017)
* Make the indent rules supports ECMAScript 2020 * update
1 parent 7617a91 commit bbcc1f0

32 files changed

+418
-30
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

+81-24
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// Helpers
1313
// ------------------------------------------------------------------------------
1414

15+
/** @type {Set<ASTNode['type']>} */
1516
const KNOWN_NODES = new Set([
1617
'ArrayExpression',
1718
'ArrayPattern',
@@ -24,6 +25,7 @@ const KNOWN_NODES = new Set([
2425
'BreakStatement',
2526
'CallExpression',
2627
'CatchClause',
28+
'ChainExpression',
2729
'ClassBody',
2830
'ClassDeclaration',
2931
'ClassExpression',
@@ -32,8 +34,6 @@ const KNOWN_NODES = new Set([
3234
'DebuggerStatement',
3335
'DoWhileStatement',
3436
'EmptyStatement',
35-
'ExperimentalRestProperty',
36-
'ExperimentalSpreadProperty',
3737
'ExportAllDeclaration',
3838
'ExportDefaultDeclaration',
3939
'ExportNamedDeclaration',
@@ -48,6 +48,7 @@ const KNOWN_NODES = new Set([
4848
'IfStatement',
4949
'ImportDeclaration',
5050
'ImportDefaultSpecifier',
51+
'ImportExpression',
5152
'ImportNamespaceSpecifier',
5253
'ImportSpecifier',
5354
'LabeledStatement',
@@ -97,6 +98,10 @@ const KNOWN_NODES = new Set([
9798
'VStartTag',
9899
'VText'
99100
])
101+
const NON_STANDARD_KNOWN_NODES = new Set([
102+
'ExperimentalRestProperty',
103+
'ExperimentalSpreadProperty'
104+
])
100105
const LT_CHAR = /[\r\n\u2028\u2029]/
101106
const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g
102107
const BLOCK_COMMENT_PREFIX = /^\s*\*/
@@ -300,6 +305,14 @@ function isSemicolon(token) {
300305
function isComma(token) {
301306
return token != null && token.type === 'Punctuator' && token.value === ','
302307
}
308+
/**
309+
* Check whether the given token is a wildcard.
310+
* @param {Token} token The token to check.
311+
* @returns {boolean} `true` if the token is a wildcard.
312+
*/
313+
function isWildcard(token) {
314+
return token != null && token.type === 'Punctuator' && token.value === '*'
315+
}
303316

304317
/**
305318
* Check whether the given token is a whitespace.
@@ -321,7 +334,9 @@ function isComment(token) {
321334
(token.type === 'Block' ||
322335
token.type === 'Line' ||
323336
token.type === 'Shebang' ||
324-
token.type.endsWith('Comment'))
337+
(typeof token.type ===
338+
'string' /* Although acorn supports new tokens, espree may not yet support new tokens.*/ &&
339+
token.type.endsWith('Comment')))
325340
)
326341
}
327342

@@ -336,7 +351,11 @@ function isNotComment(token) {
336351
token.type !== 'Block' &&
337352
token.type !== 'Line' &&
338353
token.type !== 'Shebang' &&
339-
!token.type.endsWith('Comment')
354+
!(
355+
typeof token.type ===
356+
'string' /* Although acorn supports new tokens, espree may not yet support new tokens.*/ &&
357+
token.type.endsWith('Comment')
358+
)
340359
)
341360
}
342361

@@ -1330,6 +1349,15 @@ module.exports.defineVisitor = function create(
13301349
setOffset(leftToken, 1, firstToken)
13311350
processNodeList(node.arguments, leftToken, rightToken, 1)
13321351
},
1352+
/** @param {ImportExpression} node */
1353+
ImportExpression(node) {
1354+
const firstToken = tokenStore.getFirstToken(node)
1355+
const rightToken = tokenStore.getLastToken(node)
1356+
const leftToken = tokenStore.getTokenAfter(firstToken, isLeftParen)
1357+
1358+
setOffset(leftToken, 1, firstToken)
1359+
processNodeList([node.source], leftToken, rightToken, 1)
1360+
},
13331361
/** @param {CatchClause} node */
13341362
CatchClause(node) {
13351363
const firstToken = tokenStore.getFirstToken(node)
@@ -1417,7 +1445,20 @@ module.exports.defineVisitor = function create(
14171445
if (isSemicolon(last(tokens))) {
14181446
tokens.pop()
14191447
}
1420-
setOffset(tokens, 1, firstToken)
1448+
if (!node.exported) {
1449+
setOffset(tokens, 1, firstToken)
1450+
} else {
1451+
// export * as foo from "mod"
1452+
const starToken = /** @type {Token} */ (tokens.find(isWildcard))
1453+
const asToken = tokenStore.getTokenAfter(starToken)
1454+
const exportedToken = tokenStore.getTokenAfter(asToken)
1455+
const afterTokens = tokens.slice(tokens.indexOf(exportedToken) + 1)
1456+
1457+
setOffset(starToken, 1, firstToken)
1458+
setOffset(asToken, 1, starToken)
1459+
setOffset(exportedToken, 1, starToken)
1460+
setOffset(afterTokens, 1, firstToken)
1461+
}
14211462
},
14221463
/** @param {ExportDefaultDeclaration} node */
14231464
ExportDefaultDeclaration(node) {
@@ -1435,23 +1476,28 @@ module.exports.defineVisitor = function create(
14351476
const declarationToken = tokenStore.getFirstToken(node, 1)
14361477
setOffset(declarationToken, 1, exportToken)
14371478
} else {
1438-
// export {foo, bar}; or export {foo, bar} from "mod";
1439-
const leftParenToken = tokenStore.getFirstToken(node, 1)
1440-
const rightParenToken = /** @type {Token} */ (tokenStore.getLastToken(
1441-
node,
1442-
isRightBrace
1443-
))
1444-
setOffset(leftParenToken, 0, exportToken)
1445-
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)
1446-
1447-
const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
1448-
if (
1449-
maybeFromToken != null &&
1450-
sourceCode.getText(maybeFromToken) === 'from'
1451-
) {
1452-
const fromToken = maybeFromToken
1453-
const nameToken = tokenStore.getTokenAfter(fromToken)
1454-
setOffset([fromToken, nameToken], 1, exportToken)
1479+
const firstSpecifier = node.specifiers[0]
1480+
if (!firstSpecifier || firstSpecifier.type === 'ExportSpecifier') {
1481+
// export {foo, bar}; or export {foo, bar} from "mod";
1482+
const leftParenToken = tokenStore.getFirstToken(node, 1)
1483+
const rightParenToken = /** @type {Token} */ (tokenStore.getLastToken(
1484+
node,
1485+
isRightBrace
1486+
))
1487+
setOffset(leftParenToken, 0, exportToken)
1488+
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)
1489+
1490+
const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
1491+
if (
1492+
maybeFromToken != null &&
1493+
sourceCode.getText(maybeFromToken) === 'from'
1494+
) {
1495+
const fromToken = maybeFromToken
1496+
const nameToken = tokenStore.getTokenAfter(fromToken)
1497+
setOffset([fromToken, nameToken], 1, exportToken)
1498+
}
1499+
} else {
1500+
// maybe babel-eslint
14551501
}
14561502
}
14571503
},
@@ -1464,7 +1510,12 @@ module.exports.defineVisitor = function create(
14641510
/** @param {ForInStatement | ForOfStatement} node */
14651511
'ForInStatement, ForOfStatement'(node) {
14661512
const forToken = tokenStore.getFirstToken(node)
1467-
const leftParenToken = tokenStore.getTokenAfter(forToken)
1513+
const awaitToken =
1514+
(node.type === 'ForOfStatement' &&
1515+
node.await &&
1516+
tokenStore.getTokenAfter(forToken)) ||
1517+
null
1518+
const leftParenToken = tokenStore.getTokenAfter(awaitToken || forToken)
14681519
const leftToken = tokenStore.getTokenAfter(leftParenToken)
14691520
const inToken = /** @type {Token} */ (tokenStore.getTokenAfter(
14701521
leftToken,
@@ -1476,6 +1527,9 @@ module.exports.defineVisitor = function create(
14761527
isNotLeftParen
14771528
)
14781529

1530+
if (awaitToken != null) {
1531+
setOffset(awaitToken, 0, forToken)
1532+
}
14791533
setOffset(leftParenToken, 1, forToken)
14801534
setOffset(leftToken, 1, leftParenToken)
14811535
setOffset(inToken, 1, leftToken)
@@ -1958,7 +2012,10 @@ module.exports.defineVisitor = function create(
19582012
/** @param {ASTNode} node */
19592013
// Ignore tokens of unknown nodes.
19602014
'*:exit'(node) {
1961-
if (!KNOWN_NODES.has(node.type)) {
2015+
if (
2016+
!KNOWN_NODES.has(node.type) &&
2017+
!NON_STANDARD_KNOWN_NODES.has(node.type)
2018+
) {
19622019
ignore(node)
19632020
}
19642021
},

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"@types/eslint": "^6.8.1",
6464
"@types/natural-compare": "^1.4.0",
6565
"@types/node": "^13.13.5",
66-
"@typescript-eslint/parser": "^2.31.0",
66+
"@typescript-eslint/parser": "^3.0.2",
6767
"@vuepress/plugin-pwa": "^1.4.1",
6868
"babel-eslint": "^10.1.0",
6969
"chai": "^4.2.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!--{}-->
2+
<template>
3+
<div v-bind:a="a
4+
??
5+
b
6+
"/>
7+
</template>

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

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!--{}-->
2+
<template>
3+
<div v-bind:a="
4+
obj
5+
?.aaa
6+
?.bbb
7+
?.ccc
8+
"/>
9+
</template>

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

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!--{}-->
2+
<template>
3+
<div v-bind:a="
4+
obj?.
5+
aaa?.
6+
bbb?.
7+
ccc
8+
"/>
9+
</template>

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

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!--{}-->
2+
<template>
3+
<div v-bind:a="
4+
obj?.
5+
[aaa]?.
6+
[bbb]
7+
?.[ccc]
8+
"/>
9+
</template>

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

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!--{}-->
2+
<template>
3+
<div v-bind:a="
4+
obj?.
5+
(
6+
aaa
7+
)?.
8+
(
9+
bbb
10+
)
11+
?.(
12+
ccc
13+
)
14+
"/>
15+
</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,16 @@
1+
<!--{}-->
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>
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!--{}-->
2+
<script>
3+
const module = import
4+
(
5+
m.
6+
n
7+
)
8+
</script>
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!--{}-->
2+
<script>
3+
async function fn() {
4+
return await
5+
import
6+
(
7+
m.
8+
n
9+
)
10+
}
11+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!--{}-->
2+
<script>
3+
var v = a
4+
??
5+
b
6+
</script>
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!--{}-->
2+
<script>
3+
var obj = {
4+
a:
5+
1,
6+
...obj1,
7+
b:
8+
2,
9+
...
10+
obj2,
11+
}
12+
</script>
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!--{}-->
2+
<script>
3+
obj
4+
?.aaa
5+
?.bbb
6+
?.ccc
7+
</script>
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!--{}-->
2+
<script>
3+
obj?.
4+
aaa?.
5+
bbb?.
6+
ccc
7+
</script>
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!--{}-->
2+
<script>
3+
obj?.
4+
[aaa]?.
5+
[bbb]
6+
?.[ccc]
7+
</script>

0 commit comments

Comments
 (0)