Skip to content

Commit

Permalink
Make the indent rules supports ECMAScript 2020
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi committed Jan 9, 2020
1 parent 2e1d15b commit d2e6045
Show file tree
Hide file tree
Showing 27 changed files with 285 additions and 10 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
23 changes: 18 additions & 5 deletions lib/utils/indent-common.js
Expand Up @@ -14,7 +14,7 @@ const assert = require('assert')
// Helpers
// ------------------------------------------------------------------------------

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'])
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', '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'])
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 @@ -552,7 +552,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
}
return true
}
if (t === 'CallExpression' || t === 'NewExpression') {
if (t === 'CallExpression' || t === 'NewExpression' || t === 'OptionalCallExpression') {
const openParen = tokenStore.getTokenAfter(parent.callee, isNotRightParen)
return parent.arguments.some(param =>
getFirstAndLastTokens(param, openParen.range[1]).firstToken.range[0] === token.range[0]
Expand Down Expand Up @@ -1065,7 +1065,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
}
},

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

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)
},

CatchClause (node) {
const firstToken = tokenStore.getFirstToken(node)
const bodyToken = tokenStore.getFirstToken(node.body)
Expand Down Expand Up @@ -1185,12 +1194,16 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti

'ForInStatement, ForOfStatement' (node) {
const forToken = tokenStore.getFirstToken(node)
const leftParenToken = tokenStore.getTokenAfter(forToken)
const awaitToken = (node.await && tokenStore.getTokenAfter(forToken)) || null
const leftParenToken = tokenStore.getTokenAfter(awaitToken || forToken)
const leftToken = tokenStore.getTokenAfter(leftParenToken)
const inToken = tokenStore.getTokenAfter(leftToken, isNotRightParen)
const rightToken = tokenStore.getTokenAfter(inToken)
const rightParenToken = tokenStore.getTokenBefore(node.body, isNotLeftParen)

if (awaitToken != null) {
setOffset(awaitToken, 0, forToken)
}
setOffset(leftParenToken, 1, forToken)
setOffset(leftToken, 1, leftParenToken)
setOffset(inToken, 1, leftToken)
Expand Down Expand Up @@ -1367,7 +1380,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
setOffset([colonToken, bodyToken], 1, labelToken)
},

'MemberExpression, MetaProperty' (node) {
'MemberExpression, MetaProperty, OptionalMemberExpression' (node) {
const objectToken = tokenStore.getFirstToken(node)
if (node.computed) {
const leftBracketToken = tokenStore.getTokenBefore(node.property, isLeftBracket)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -52,7 +52,7 @@
},
"devDependencies": {
"@types/node": "^4.2.16",
"@typescript-eslint/parser": "^2.6.1",
"@typescript-eslint/parser": "^2.13.0",
"acorn": "^7.1.0",
"babel-eslint": "^10.0.2",
"chai": "^4.1.0",
Expand All @@ -65,7 +65,7 @@
"lodash": "^4.17.4",
"mocha": "^5.2.0",
"nyc": "^12.0.2",
"typescript": "^3.5.2",
"typescript": "^3.7.4",
"vue-eslint-editor": "^0.1.4",
"vuepress": "^0.14.5"
}
Expand Down
8 changes: 8 additions & 0 deletions tests/fixtures/html-indent/nullish-coalescing-operator-01.vue
@@ -0,0 +1,8 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<template>
<div v-bind:a="a
??
b
"/>
</template>
11 changes: 11 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-01.vue
@@ -0,0 +1,11 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->

<template>
<div v-bind:a="
obj
?.aaa
?.bbb
?.ccc
"/>
</template>
10 changes: 10 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-02.vue
@@ -0,0 +1,10 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<template>
<div v-bind:a="
obj?.
aaa?.
bbb?.
ccc
"/>
</template>
10 changes: 10 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-03.vue
@@ -0,0 +1,10 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<template>
<div v-bind:a="
obj?.
[aaa]?.
[bbb]
?.[ccc]
"/>
</template>
16 changes: 16 additions & 0 deletions tests/fixtures/html-indent/optional-chaining-04.vue
@@ -0,0 +1,16 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<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>
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,7 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<script>
var v = a
??
b
</script>
@@ -0,0 +1,6 @@
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
<script>
var v = a
??
b
</script>
@@ -0,0 +1,6 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<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>
8 changes: 8 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-01.vue
@@ -0,0 +1,8 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<script>
obj
?.aaa
?.bbb
?.ccc
</script>
8 changes: 8 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-02.vue
@@ -0,0 +1,8 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<script>
obj?.
aaa?.
bbb?.
ccc
</script>
8 changes: 8 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-03.vue
@@ -0,0 +1,8 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<script>
obj?.
[aaa]?.
[bbb]
?.[ccc]
</script>
14 changes: 14 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-04.vue
@@ -0,0 +1,14 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<!-- TODO If ESLint supports the new syntax by default, remove the parser specification and test. -->
<script>
obj?.
(
aaa
)?.
(
bbb
)
?.(
ccc
)
</script>
28 changes: 28 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-babel-01.vue
@@ -0,0 +1,28 @@
<!--{"parserOptions": {"parser":"babel-eslint"}}-->
<script>
obj
?.aaa
?.bbb
?.ccc;
obj?.
aaa?.
bbb?.
ccc;
obj?.
[aaa]?.
[bbb]
?.[ccc];
obj?.
(
aaa
)?.
(
bbb
)
?.(
ccc
)
</script>
28 changes: 28 additions & 0 deletions tests/fixtures/script-indent/optional-chaining-ts-01.vue
@@ -0,0 +1,28 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<script>
obj
?.aaa
?.bbb
?.ccc;
obj?.
aaa?.
bbb?.
ccc;
obj?.
[aaa]?.
[bbb]
?.[ccc];
obj?.
(
aaa
)?.
(
bbb
)
?.(
ccc
)
</script>
8 changes: 8 additions & 0 deletions tests/fixtures/script-indent/rest-properties-01.vue
@@ -0,0 +1,8 @@
<!--{}-->
<script>
({
a,
...
b
} = {})
</script>
14 changes: 14 additions & 0 deletions tests/fixtures/script-indent/try-statement-04.vue
@@ -0,0 +1,14 @@
<!--{}-->
<script>
try
{
}
catch
{
;
}
finally
{
;
}
</script>
8 changes: 7 additions & 1 deletion tests/lib/rules/html-indent.js
Expand Up @@ -42,6 +42,12 @@ function loadPatterns (additionalValid, additionalInvalid) {
const code0 = fs.readFileSync(path.join(FIXTURE_ROOT, filename), 'utf8')
const code = code0.replace(/^<!--(.+?)-->/, `<!--${filename}-->`)
const baseObj = JSON.parse(/^<!--(.+?)-->/.exec(code0)[1])
if ('parser' in baseObj) {
baseObj.parser = require.resolve(baseObj.parser)
}
if ('parserOptions' in baseObj && 'parser' in baseObj.parserOptions) {
baseObj.parserOptions.parser = require.resolve(baseObj.parserOptions.parser)
}
return Object.assign(baseObj, { code, filename })
})
const invalid = valid
Expand Down Expand Up @@ -97,7 +103,7 @@ function unIndent (strings) {
const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
ecmaVersion: 2017,
ecmaVersion: 2020,
ecmaFeatures: {
globalReturn: true
}
Expand Down

0 comments on commit d2e6045

Please sign in to comment.