Skip to content

Commit 7e4dd5a

Browse files
committed
Make the indent rules supports ECMAScript 2020
1 parent b33c708 commit 7e4dd5a

32 files changed

+420
-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

+83-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,12 @@ const KNOWN_NODES = new Set([
9798
'VStartTag',
9899
'VText'
99100
])
101+
const NON_STANDARD_KNOWN_NODES = new Set([
102+
'ExperimentalRestProperty',
103+
'ExperimentalSpreadProperty',
104+
'OptionalCallExpression',
105+
'OptionalMemberExpression'
106+
])
100107
const LT_CHAR = /[\r\n\u2028\u2029]/
101108
const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g
102109
const BLOCK_COMMENT_PREFIX = /^\s*\*/
@@ -300,6 +307,14 @@ function isSemicolon(token) {
300307
function isComma(token) {
301308
return token != null && token.type === 'Punctuator' && token.value === ','
302309
}
310+
/**
311+
* Check whether the given token is a wildcard.
312+
* @param {Token} token The token to check.
313+
* @returns {boolean} `true` if the token is a wildcard.
314+
*/
315+
function isWildcard(token) {
316+
return token != null && token.type === 'Punctuator' && token.value === '*'
317+
}
303318

304319
/**
305320
* Check whether the given token is a whitespace.
@@ -321,7 +336,9 @@ function isComment(token) {
321336
(token.type === 'Block' ||
322337
token.type === 'Line' ||
323338
token.type === 'Shebang' ||
324-
token.type.endsWith('Comment'))
339+
(typeof token.type ===
340+
'string' /* Although acorn supports new tokens, espree may not yet support new tokens.*/ &&
341+
token.type.endsWith('Comment')))
325342
)
326343
}
327344

@@ -336,7 +353,11 @@ function isNotComment(token) {
336353
token.type !== 'Block' &&
337354
token.type !== 'Line' &&
338355
token.type !== 'Shebang' &&
339-
!token.type.endsWith('Comment')
356+
!(
357+
typeof token.type ===
358+
'string' /* Although acorn supports new tokens, espree may not yet support new tokens.*/ &&
359+
token.type.endsWith('Comment')
360+
)
340361
)
341362
}
342363

@@ -1330,6 +1351,15 @@ module.exports.defineVisitor = function create(
13301351
setOffset(leftToken, 1, firstToken)
13311352
processNodeList(node.arguments, leftToken, rightToken, 1)
13321353
},
1354+
/** @param {ImportExpression} node */
1355+
ImportExpression(node) {
1356+
const firstToken = tokenStore.getFirstToken(node)
1357+
const rightToken = tokenStore.getLastToken(node)
1358+
const leftToken = tokenStore.getTokenAfter(firstToken, isLeftParen)
1359+
1360+
setOffset(leftToken, 1, firstToken)
1361+
processNodeList([node.source], leftToken, rightToken, 1)
1362+
},
13331363
/** @param {CatchClause} node */
13341364
CatchClause(node) {
13351365
const firstToken = tokenStore.getFirstToken(node)
@@ -1417,7 +1447,20 @@ module.exports.defineVisitor = function create(
14171447
if (isSemicolon(last(tokens))) {
14181448
tokens.pop()
14191449
}
1420-
setOffset(tokens, 1, firstToken)
1450+
if (!node.exported) {
1451+
setOffset(tokens, 1, firstToken)
1452+
} else {
1453+
// export * as foo from "mod"
1454+
const starToken = /** @type {Token} */ (tokens.find(isWildcard))
1455+
const asToken = tokenStore.getTokenAfter(starToken)
1456+
const exportedToken = tokenStore.getTokenAfter(asToken)
1457+
const afterTokens = tokens.slice(tokens.indexOf(exportedToken) + 1)
1458+
1459+
setOffset(starToken, 1, firstToken)
1460+
setOffset(asToken, 1, starToken)
1461+
setOffset(exportedToken, 1, starToken)
1462+
setOffset(afterTokens, 1, firstToken)
1463+
}
14211464
},
14221465
/** @param {ExportDefaultDeclaration} node */
14231466
ExportDefaultDeclaration(node) {
@@ -1435,23 +1478,28 @@ module.exports.defineVisitor = function create(
14351478
const declarationToken = tokenStore.getFirstToken(node, 1)
14361479
setOffset(declarationToken, 1, exportToken)
14371480
} 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)
1481+
const firstSpecifier = node.specifiers[0]
1482+
if (!firstSpecifier || firstSpecifier.type === 'ExportSpecifier') {
1483+
// export {foo, bar}; or export {foo, bar} from "mod";
1484+
const leftParenToken = tokenStore.getFirstToken(node, 1)
1485+
const rightParenToken = /** @type {Token} */ (tokenStore.getLastToken(
1486+
node,
1487+
isRightBrace
1488+
))
1489+
setOffset(leftParenToken, 0, exportToken)
1490+
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)
1491+
1492+
const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
1493+
if (
1494+
maybeFromToken != null &&
1495+
sourceCode.getText(maybeFromToken) === 'from'
1496+
) {
1497+
const fromToken = maybeFromToken
1498+
const nameToken = tokenStore.getTokenAfter(fromToken)
1499+
setOffset([fromToken, nameToken], 1, exportToken)
1500+
}
1501+
} else {
1502+
// maybe babel-eslint
14551503
}
14561504
}
14571505
},
@@ -1464,7 +1512,12 @@ module.exports.defineVisitor = function create(
14641512
/** @param {ForInStatement | ForOfStatement} node */
14651513
'ForInStatement, ForOfStatement'(node) {
14661514
const forToken = tokenStore.getFirstToken(node)
1467-
const leftParenToken = tokenStore.getTokenAfter(forToken)
1515+
const awaitToken =
1516+
(node.type === 'ForOfStatement' &&
1517+
node.await &&
1518+
tokenStore.getTokenAfter(forToken)) ||
1519+
null
1520+
const leftParenToken = tokenStore.getTokenAfter(awaitToken || forToken)
14681521
const leftToken = tokenStore.getTokenAfter(leftParenToken)
14691522
const inToken = /** @type {Token} */ (tokenStore.getTokenAfter(
14701523
leftToken,
@@ -1476,6 +1529,9 @@ module.exports.defineVisitor = function create(
14761529
isNotLeftParen
14771530
)
14781531

1532+
if (awaitToken != null) {
1533+
setOffset(awaitToken, 0, forToken)
1534+
}
14791535
setOffset(leftParenToken, 1, forToken)
14801536
setOffset(leftToken, 1, leftParenToken)
14811537
setOffset(inToken, 1, leftToken)
@@ -1958,7 +2014,10 @@ module.exports.defineVisitor = function create(
19582014
/** @param {ASTNode} node */
19592015
// Ignore tokens of unknown nodes.
19602016
'*:exit'(node) {
1961-
if (!KNOWN_NODES.has(node.type)) {
2017+
if (
2018+
!KNOWN_NODES.has(node.type) &&
2019+
!NON_STANDARD_KNOWN_NODES.has(node.type)
2020+
) {
19622021
ignore(node)
19632022
}
19642023
},

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)