Skip to content

Commit

Permalink
Make the indent rules supports ECMAScript 2020 (#1017)
Browse files Browse the repository at this point in the history
* Make the indent rules supports ECMAScript 2020

* update
  • Loading branch information
ota-meshi committed Jun 12, 2020
1 parent 7617a91 commit bbcc1f0
Show file tree
Hide file tree
Showing 32 changed files with 418 additions and 30 deletions.
2 changes: 1 addition & 1 deletion docs/rules/html-indent.md
Expand Up @@ -15,7 +15,7 @@ description: enforce consistent indentation in `<template>`
This rule enforces a consistent indentation style in `<template>`. The default style is 2 spaces.

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

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

Expand Down
105 changes: 81 additions & 24 deletions lib/utils/indent-common.js
Expand Up @@ -12,6 +12,7 @@
// Helpers
// ------------------------------------------------------------------------------

/** @type {Set<ASTNode['type']>} */
const KNOWN_NODES = new Set([
'ArrayExpression',
'ArrayPattern',
Expand All @@ -24,6 +25,7 @@ const KNOWN_NODES = new Set([
'BreakStatement',
'CallExpression',
'CatchClause',
'ChainExpression',
'ClassBody',
'ClassDeclaration',
'ClassExpression',
Expand All @@ -32,8 +34,6 @@ const KNOWN_NODES = new Set([
'DebuggerStatement',
'DoWhileStatement',
'EmptyStatement',
'ExperimentalRestProperty',
'ExperimentalSpreadProperty',
'ExportAllDeclaration',
'ExportDefaultDeclaration',
'ExportNamedDeclaration',
Expand All @@ -48,6 +48,7 @@ const KNOWN_NODES = new Set([
'IfStatement',
'ImportDeclaration',
'ImportDefaultSpecifier',
'ImportExpression',
'ImportNamespaceSpecifier',
'ImportSpecifier',
'LabeledStatement',
Expand Down Expand Up @@ -97,6 +98,10 @@ const KNOWN_NODES = new Set([
'VStartTag',
'VText'
])
const NON_STANDARD_KNOWN_NODES = new Set([
'ExperimentalRestProperty',
'ExperimentalSpreadProperty'
])
const LT_CHAR = /[\r\n\u2028\u2029]/
const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g
const BLOCK_COMMENT_PREFIX = /^\s*\*/
Expand Down Expand Up @@ -300,6 +305,14 @@ function isSemicolon(token) {
function isComma(token) {
return token != null && token.type === 'Punctuator' && token.value === ','
}
/**
* Check whether the given token is a wildcard.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a wildcard.
*/
function isWildcard(token) {
return token != null && token.type === 'Punctuator' && token.value === '*'
}

/**
* Check whether the given token is a whitespace.
Expand All @@ -321,7 +334,9 @@ function isComment(token) {
(token.type === 'Block' ||
token.type === 'Line' ||
token.type === 'Shebang' ||
token.type.endsWith('Comment'))
(typeof token.type ===
'string' /* Although acorn supports new tokens, espree may not yet support new tokens.*/ &&
token.type.endsWith('Comment')))
)
}

Expand All @@ -336,7 +351,11 @@ function isNotComment(token) {
token.type !== 'Block' &&
token.type !== 'Line' &&
token.type !== 'Shebang' &&
!token.type.endsWith('Comment')
!(
typeof token.type ===
'string' /* Although acorn supports new tokens, espree may not yet support new tokens.*/ &&
token.type.endsWith('Comment')
)
)
}

Expand Down Expand Up @@ -1330,6 +1349,15 @@ module.exports.defineVisitor = function create(
setOffset(leftToken, 1, firstToken)
processNodeList(node.arguments, leftToken, rightToken, 1)
},
/** @param {ImportExpression} node */
ImportExpression(node) {
const firstToken = tokenStore.getFirstToken(node)
const rightToken = tokenStore.getLastToken(node)
const leftToken = tokenStore.getTokenAfter(firstToken, isLeftParen)

setOffset(leftToken, 1, firstToken)
processNodeList([node.source], leftToken, rightToken, 1)
},
/** @param {CatchClause} node */
CatchClause(node) {
const firstToken = tokenStore.getFirstToken(node)
Expand Down Expand Up @@ -1417,7 +1445,20 @@ module.exports.defineVisitor = function create(
if (isSemicolon(last(tokens))) {
tokens.pop()
}
setOffset(tokens, 1, firstToken)
if (!node.exported) {
setOffset(tokens, 1, firstToken)
} else {
// export * as foo from "mod"
const starToken = /** @type {Token} */ (tokens.find(isWildcard))
const asToken = tokenStore.getTokenAfter(starToken)
const exportedToken = tokenStore.getTokenAfter(asToken)
const afterTokens = tokens.slice(tokens.indexOf(exportedToken) + 1)

setOffset(starToken, 1, firstToken)
setOffset(asToken, 1, starToken)
setOffset(exportedToken, 1, starToken)
setOffset(afterTokens, 1, firstToken)
}
},
/** @param {ExportDefaultDeclaration} node */
ExportDefaultDeclaration(node) {
Expand All @@ -1435,23 +1476,28 @@ module.exports.defineVisitor = function create(
const declarationToken = tokenStore.getFirstToken(node, 1)
setOffset(declarationToken, 1, exportToken)
} else {
// export {foo, bar}; or export {foo, bar} from "mod";
const leftParenToken = tokenStore.getFirstToken(node, 1)
const rightParenToken = /** @type {Token} */ (tokenStore.getLastToken(
node,
isRightBrace
))
setOffset(leftParenToken, 0, exportToken)
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)

const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
if (
maybeFromToken != null &&
sourceCode.getText(maybeFromToken) === 'from'
) {
const fromToken = maybeFromToken
const nameToken = tokenStore.getTokenAfter(fromToken)
setOffset([fromToken, nameToken], 1, exportToken)
const firstSpecifier = node.specifiers[0]
if (!firstSpecifier || firstSpecifier.type === 'ExportSpecifier') {
// export {foo, bar}; or export {foo, bar} from "mod";
const leftParenToken = tokenStore.getFirstToken(node, 1)
const rightParenToken = /** @type {Token} */ (tokenStore.getLastToken(
node,
isRightBrace
))
setOffset(leftParenToken, 0, exportToken)
processNodeList(node.specifiers, leftParenToken, rightParenToken, 1)

const maybeFromToken = tokenStore.getTokenAfter(rightParenToken)
if (
maybeFromToken != null &&
sourceCode.getText(maybeFromToken) === 'from'
) {
const fromToken = maybeFromToken
const nameToken = tokenStore.getTokenAfter(fromToken)
setOffset([fromToken, nameToken], 1, exportToken)
}
} else {
// maybe babel-eslint
}
}
},
Expand All @@ -1464,7 +1510,12 @@ module.exports.defineVisitor = function create(
/** @param {ForInStatement | ForOfStatement} node */
'ForInStatement, ForOfStatement'(node) {
const forToken = tokenStore.getFirstToken(node)
const leftParenToken = tokenStore.getTokenAfter(forToken)
const awaitToken =
(node.type === 'ForOfStatement' &&
node.await &&
tokenStore.getTokenAfter(forToken)) ||
null
const leftParenToken = tokenStore.getTokenAfter(awaitToken || forToken)
const leftToken = tokenStore.getTokenAfter(leftParenToken)
const inToken = /** @type {Token} */ (tokenStore.getTokenAfter(
leftToken,
Expand All @@ -1476,6 +1527,9 @@ module.exports.defineVisitor = function create(
isNotLeftParen
)

if (awaitToken != null) {
setOffset(awaitToken, 0, forToken)
}
setOffset(leftParenToken, 1, forToken)
setOffset(leftToken, 1, leftParenToken)
setOffset(inToken, 1, leftToken)
Expand Down Expand Up @@ -1958,7 +2012,10 @@ module.exports.defineVisitor = function create(
/** @param {ASTNode} node */
// Ignore tokens of unknown nodes.
'*:exit'(node) {
if (!KNOWN_NODES.has(node.type)) {
if (
!KNOWN_NODES.has(node.type) &&
!NON_STANDARD_KNOWN_NODES.has(node.type)
) {
ignore(node)
}
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -63,7 +63,7 @@
"@types/eslint": "^6.8.1",
"@types/natural-compare": "^1.4.0",
"@types/node": "^13.13.5",
"@typescript-eslint/parser": "^2.31.0",
"@typescript-eslint/parser": "^3.0.2",
"@vuepress/plugin-pwa": "^1.4.1",
"babel-eslint": "^10.1.0",
"chai": "^4.2.0",
Expand Down
7 changes: 7 additions & 0 deletions tests/fixtures/html-indent/nullish-coalescing-operator-01.vue
@@ -0,0 +1,7 @@
<!--{}-->
<template>
<div v-bind:a="a
??
b
"/>
</template>
9 changes: 9 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-01.vue
@@ -0,0 +1,9 @@
<!--{}-->
<template>
<div v-bind:a="
obj
?.aaa
?.bbb
?.ccc
"/>
</template>
9 changes: 9 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-02.vue
@@ -0,0 +1,9 @@
<!--{}-->
<template>
<div v-bind:a="
obj?.
aaa?.
bbb?.
ccc
"/>
</template>
9 changes: 9 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-03.vue
@@ -0,0 +1,9 @@
<!--{}-->
<template>
<div v-bind:a="
obj?.
[aaa]?.
[bbb]
?.[ccc]
"/>
</template>
15 changes: 15 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-04.vue
@@ -0,0 +1,15 @@
<!--{}-->
<template>
<div v-bind:a="
obj?.
(
aaa
)?.
(
bbb
)
?.(
ccc
)
"/>
</template>
7 changes: 7 additions & 0 deletions tests/fixtures/script-indent/bigint-01.vue
@@ -0,0 +1,7 @@
<!--{}-->
<script>
var a =
10n
+
5n
</script>
16 changes: 16 additions & 0 deletions tests/fixtures/script-indent/export-all-declaration-02.vue
@@ -0,0 +1,16 @@
<!--{}-->
<script>
export
*
as
foo
from
"mod"
;
export
*
as
bar
from
"mod"
</script>
15 changes: 15 additions & 0 deletions tests/fixtures/script-indent/for-await-of-01.vue
@@ -0,0 +1,15 @@
<!--{}-->
<script>
async function fn() {
for
await
(
a
of
b
)
{
;
}
}
</script>
7 changes: 7 additions & 0 deletions tests/fixtures/script-indent/import-expression-01.vue
@@ -0,0 +1,7 @@
<!--{}-->
<script>
const fs = import
(
'fs'
)
</script>
8 changes: 8 additions & 0 deletions tests/fixtures/script-indent/import-expression-02.vue
@@ -0,0 +1,8 @@
<!--{}-->
<script>
const module = import
(
m.
n
)
</script>
11 changes: 11 additions & 0 deletions tests/fixtures/script-indent/import-expression-03.vue
@@ -0,0 +1,11 @@
<!--{}-->
<script>
async function fn() {
return await
import
(
m.
n
)
}
</script>
@@ -0,0 +1,6 @@
<!--{}-->
<script>
var v = a
??
b
</script>
12 changes: 12 additions & 0 deletions tests/fixtures/script-indent/object-expression-04.vue
@@ -0,0 +1,12 @@
<!--{}-->
<script>
var obj = {
a:
1,
...obj1,
b:
2,
...
obj2,
}
</script>
7 changes: 7 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-01.vue
@@ -0,0 +1,7 @@
<!--{}-->
<script>
obj
?.aaa
?.bbb
?.ccc
</script>
7 changes: 7 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-02.vue
@@ -0,0 +1,7 @@
<!--{}-->
<script>
obj?.
aaa?.
bbb?.
ccc
</script>
7 changes: 7 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-03.vue
@@ -0,0 +1,7 @@
<!--{}-->
<script>
obj?.
[aaa]?.
[bbb]
?.[ccc]
</script>

0 comments on commit bbcc1f0

Please sign in to comment.