From 0ee35d3bd296a87465fb39e69adaf892557cc7cb Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Mon, 6 Sep 2021 08:21:49 +0900 Subject: [PATCH] Update indent rule to support Class static block and typescript-eslint v5(rc) (#1619) * Update indent rule to support typescript-eslint v5 * Update ts-static-block-01.vue * static block to es * fix job * ignore cache * use cache * ignore cache * use cache * remove cache --- .circleci/config.yml | 53 ++++++-- lib/utils/indent-common.js | 11 ++ lib/utils/indent-ts.js | 116 +++++++++++++++--- package.json | 2 +- .../ts-abstract-class-property-02.vue | 10 +- .../script-indent/ts-static-block-01.vue | 8 ++ .../script-indent/ts-type-annotation-03.vue | 13 +- typings/eslint-plugin-vue/global.d.ts | 1 + .../eslint-plugin-vue/util-types/ast/ast.ts | 2 + .../util-types/ast/es-ast.ts | 14 ++- 10 files changed, 187 insertions(+), 43 deletions(-) create mode 100644 tests/fixtures/script-indent/ts-static-block-01.vue diff --git a/.circleci/config.yml b/.circleci/config.yml index b80032ae8..7d8f4bcde 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,6 +6,7 @@ workflows: - node-v10 - eslint-v7 - eslint-v8 + - ts-eslint-v4 - node-v12 - node-v14 - lint @@ -20,19 +21,19 @@ jobs: name: Versions command: npm version - checkout - - restore_cache: - keys: - - v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }} + # - restore_cache: + # keys: + # - v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }} - run: name: Install dependencies command: npm install - - save_cache: - key: v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }} - paths: - - node_modules - run: name: Test command: npm test + # - save_cache: + # key: v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }} + # paths: + # - node_modules node-v8: docker: @@ -53,9 +54,23 @@ jobs: name: Test command: npm test node-v10: - <<: *node-base docker: - image: node:10 + steps: + - run: + name: Versions + command: npm version + - checkout + - run: + name: Install @typescript-eslint/parser@4 + command: | + npm install @typescript-eslint/parser@^4 + - run: + name: Install dependencies + command: npm install + - run: + name: Test + command: npm test eslint-v7: docker: - image: node:10 @@ -67,7 +82,7 @@ jobs: - run: name: Install eslint@7 command: | - npm install --save-exact eslint@7 + npm install eslint@7 - run: name: Install dependencies command: npm install @@ -85,7 +100,25 @@ jobs: - run: name: Install eslint@8 command: | - npm install --save-exact eslint@^8.0.0-0 + npm install eslint@^8.0.0-0 + - run: + name: Install dependencies + command: npm install + - run: + name: Test + command: npm test + ts-eslint-v4: + docker: + - image: node:14 + steps: + - run: + name: Versions + command: npm version + - checkout + - run: + name: Install @typescript-eslint/parser@4 + command: | + npm install @typescript-eslint/parser@^4 - run: name: Install dependencies command: npm install diff --git a/lib/utils/indent-common.js b/lib/utils/indent-common.js index a4d0dbcfd..39ef58670 100644 --- a/lib/utils/indent-common.js +++ b/lib/utils/indent-common.js @@ -16,6 +16,7 @@ const { isNotClosingParenToken, isOpeningBraceToken, isClosingBraceToken, + isNotOpeningBraceToken, isOpeningBracketToken, isClosingBracketToken, isSemicolonToken @@ -1150,6 +1151,16 @@ module.exports.defineVisitor = function create( 1 ) }, + StaticBlock(node) { + const firstToken = tokenStore.getFirstToken(node) + let next = tokenStore.getTokenAfter(firstToken) + while (next && isNotOpeningBraceToken(next)) { + setOffset(next, 0, firstToken) + next = tokenStore.getTokenAfter(next) + } + setOffset(next, 0, firstToken) + processNodeList(node.body, next, tokenStore.getLastToken(node), 1) + }, /** @param {BreakStatement | ContinueStatement | ReturnStatement | ThrowStatement} node */ 'BreakStatement, ContinueStatement, ReturnStatement, ThrowStatement'(node) { if ( diff --git a/lib/utils/indent-ts.js b/lib/utils/indent-ts.js index 9afcdb34f..ed2080750 100644 --- a/lib/utils/indent-ts.js +++ b/lib/utils/indent-ts.js @@ -27,7 +27,7 @@ const { * @typedef {import('@typescript-eslint/types').TSESTree.TSConstructSignatureDeclaration} TSConstructSignatureDeclaration * @typedef {import('@typescript-eslint/types').TSESTree.TSImportEqualsDeclaration} TSImportEqualsDeclaration * @typedef {import('@typescript-eslint/types').TSESTree.TSAbstractMethodDefinition} TSAbstractMethodDefinition - * @typedef {import('@typescript-eslint/types').TSESTree.TSAbstractClassProperty} TSAbstractClassProperty + * @typedef {import('@typescript-eslint/types').TSESTree.TSAbstractPropertyDefinition} TSAbstractPropertyDefinition * @typedef {import('@typescript-eslint/types').TSESTree.TSEnumMember} TSEnumMember * @typedef {import('@typescript-eslint/types').TSESTree.TSPropertySignature} TSPropertySignature * @typedef {import('@typescript-eslint/types').TSESTree.TSIndexSignature} TSIndexSignature @@ -50,12 +50,13 @@ const { * @typedef {import('@typescript-eslint/types').TSESTree.TSOptionalType} TSOptionalType * @typedef {import('@typescript-eslint/types').TSESTree.TSNonNullExpression} TSNonNullExpression * @typedef {import('@typescript-eslint/types').TSESTree.JSXChild} JSXChild + * @typedef {import('@typescript-eslint/types').TSESTree.TypeNode} TypeNode * */ /** - * Perhaps this node will be deprecated in the future. - * It was present in @typescript-eslint/parser@4.1.0. - * @typedef {import('@typescript-eslint/types').TSESTree.ClassProperty} ClassProperty + * Deprecated in @typescript-eslint/parser v5 + * @typedef {import('@typescript-eslint/types').TSESTree.PropertyDefinition} ClassProperty + * @typedef {import('@typescript-eslint/types').TSESTree.TSAbstractPropertyDefinition} TSAbstractClassProperty */ module.exports = { @@ -203,6 +204,7 @@ function defineVisitor({ * | TSConstructSignatureDeclaration * | TSImportEqualsDeclaration * | TSAbstractMethodDefinition + * | TSAbstractPropertyDefinition * | TSAbstractClassProperty * | TSEnumMember * | ClassProperty @@ -211,10 +213,80 @@ function defineVisitor({ * | TSMethodSignature} node */ ['TSTypeAliasDeclaration, TSCallSignatureDeclaration, TSConstructSignatureDeclaration, TSImportEqualsDeclaration,' + - 'TSAbstractMethodDefinition, TSAbstractClassProperty, TSEnumMember, ClassProperty,' + - 'TSPropertySignature, TSIndexSignature, TSMethodSignature'](node) { + 'TSAbstractMethodDefinition, TSAbstractPropertyDefinition, TSEnumMember,' + + 'TSPropertySignature, TSIndexSignature, TSMethodSignature,' + + // Deprecated in @typescript-eslint/parser v5 + 'ClassProperty, TSAbstractClassProperty'](node) { processSemicolons(node) }, + /** + * @param {TSESTreeNode} node + */ + // eslint-disable-next-line complexity -- ignore + '*[type=/^TS/]'(node) { + if ( + node.type !== 'TSAnyKeyword' && + node.type !== 'TSArrayType' && + node.type !== 'TSBigIntKeyword' && + node.type !== 'TSBooleanKeyword' && + node.type !== 'TSConditionalType' && + node.type !== 'TSConstructorType' && + node.type !== 'TSFunctionType' && + node.type !== 'TSImportType' && + node.type !== 'TSIndexedAccessType' && + node.type !== 'TSInferType' && + node.type !== 'TSIntersectionType' && + node.type !== 'TSIntrinsicKeyword' && + node.type !== 'TSLiteralType' && + node.type !== 'TSMappedType' && + node.type !== 'TSNamedTupleMember' && + node.type !== 'TSNeverKeyword' && + node.type !== 'TSNullKeyword' && + node.type !== 'TSNumberKeyword' && + node.type !== 'TSObjectKeyword' && + node.type !== 'TSOptionalType' && + node.type !== 'TSRestType' && + node.type !== 'TSStringKeyword' && + node.type !== 'TSSymbolKeyword' && + node.type !== 'TSTemplateLiteralType' && + node.type !== 'TSThisType' && + node.type !== 'TSTupleType' && + node.type !== 'TSTypeLiteral' && + node.type !== 'TSTypeOperator' && + node.type !== 'TSTypePredicate' && + node.type !== 'TSTypeQuery' && + node.type !== 'TSTypeReference' && + node.type !== 'TSUndefinedKeyword' && + node.type !== 'TSUnionType' && + node.type !== 'TSUnknownKeyword' && + node.type !== 'TSVoidKeyword' + ) { + return + } + /** @type {TypeNode} */ + const typeNode = node + if (/** @type {any} */ (typeNode.parent).type === 'TSParenthesizedType') { + return + } + // Process parentheses. + let leftToken = tokenStore.getTokenBefore(node) + let rightToken = tokenStore.getTokenAfter(node) + let firstToken = tokenStore.getFirstToken(node) + + while ( + leftToken && + rightToken && + isOpeningParenToken(leftToken) && + isClosingParenToken(rightToken) + ) { + setOffset(firstToken, 1, leftToken) + setOffset(rightToken, 0, leftToken) + + firstToken = leftToken + leftToken = tokenStore.getTokenBefore(leftToken) + rightToken = tokenStore.getTokenAfter(rightToken) + } + }, /** * Process type annotation * @@ -535,15 +607,6 @@ function defineVisitor({ setOffset(typeTokens.firstToken, offset, firstToken) } }, - TSParenthesizedType(node) { - // (T) - processNodeList( - [node.typeAnnotation], - tokenStore.getFirstToken(node), - tokenStore.getLastToken(node), - 1 - ) - }, TSMappedType(node) { // {[key in foo]: bar} const leftBraceToken = tokenStore.getFirstToken(node) @@ -1026,12 +1089,12 @@ function defineVisitor({ * // ^^^^^^^ * ``` * - * @param {TSAbstractMethodDefinition | TSAbstractClassProperty | TSEnumMember | ClassProperty} node + * @param {TSAbstractMethodDefinition | TSAbstractPropertyDefinition | TSEnumMember | TSAbstractClassProperty | ClassProperty} node * */ - 'TSAbstractMethodDefinition, TSAbstractClassProperty, TSEnumMember, ClassProperty'( - node - ) { + ['TSAbstractMethodDefinition, TSAbstractPropertyDefinition, TSEnumMember,' + + // Deprecated in @typescript-eslint/parser v5 + 'ClassProperty, TSAbstractClassProperty'](node) { const { keyNode, valueNode } = node.type === 'TSEnumMember' ? { keyNode: node.id, valueNode: node.initializer } @@ -1275,6 +1338,21 @@ function defineVisitor({ setOffset(atToken, 0, tokenStore.getFirstToken(decorators[0])) } }, + + // ---------------------------------------------------------------------- + // DEPRECATED NODES + // ---------------------------------------------------------------------- + /** @param {any} node */ + TSParenthesizedType(node) { + // Deprecated in @typescript-eslint/parser v5 + // (T) + processNodeList( + [node.typeAnnotation], + tokenStore.getFirstToken(node), + tokenStore.getLastToken(node), + 1 + ) + }, // ---------------------------------------------------------------------- // SINGLE TOKEN NODES // ---------------------------------------------------------------------- diff --git a/package.json b/package.json index 661acff1e..7076d867e 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@types/natural-compare": "^1.4.0", "@types/node": "^13.13.5", "@types/semver": "^7.2.0", - "@typescript-eslint/parser": "^4.28.0", + "@typescript-eslint/parser": "^5.0.0-0", "@vuepress/plugin-pwa": "^1.4.1", "env-cmd": "^10.1.0", "eslint": "^7.0.0", diff --git a/tests/fixtures/script-indent/ts-abstract-class-property-02.vue b/tests/fixtures/script-indent/ts-abstract-class-property-02.vue index 9e3214a0f..6b10b8033 100644 --- a/tests/fixtures/script-indent/ts-abstract-class-property-02.vue +++ b/tests/fixtures/script-indent/ts-abstract-class-property-02.vue @@ -6,12 +6,14 @@ abstract class A { 1 ; abstract public b - = - 's' + // parser v5 does not parse value. + // = + // 's' ; protected abstract c - = - i + // parser v5 does not parse value. + // = + // i ; } diff --git a/tests/fixtures/script-indent/ts-static-block-01.vue b/tests/fixtures/script-indent/ts-static-block-01.vue new file mode 100644 index 000000000..522271628 --- /dev/null +++ b/tests/fixtures/script-indent/ts-static-block-01.vue @@ -0,0 +1,8 @@ + + diff --git a/tests/fixtures/script-indent/ts-type-annotation-03.vue b/tests/fixtures/script-indent/ts-type-annotation-03.vue index ed1bab907..6569f4e53 100644 --- a/tests/fixtures/script-indent/ts-type-annotation-03.vue +++ b/tests/fixtures/script-indent/ts-type-annotation-03.vue @@ -18,11 +18,12 @@ class Foo { ? : number; - abstract absopt2 - ? - : - number - = - 42; +// parser v5 does not parse value. +// abstract absopt2 +// ? +// : +// number +// = +// 42; } diff --git a/typings/eslint-plugin-vue/global.d.ts b/typings/eslint-plugin-vue/global.d.ts index 96ceee311..c2ae50632 100644 --- a/typings/eslint-plugin-vue/global.d.ts +++ b/typings/eslint-plugin-vue/global.d.ts @@ -137,6 +137,7 @@ declare global { type ClassBody = VAST.ClassBody type MethodDefinition = VAST.MethodDefinition type PropertyDefinition = VAST.PropertyDefinition + type StaticBlock = VAST.StaticBlock type ModuleDeclaration = VAST.ModuleDeclaration type ImportDeclaration = VAST.ImportDeclaration type ExportNamedDeclaration = VAST.ExportNamedDeclaration diff --git a/typings/eslint-plugin-vue/util-types/ast/ast.ts b/typings/eslint-plugin-vue/util-types/ast/ast.ts index 68d6b8843..005fabe57 100644 --- a/typings/eslint-plugin-vue/util-types/ast/ast.ts +++ b/typings/eslint-plugin-vue/util-types/ast/ast.ts @@ -333,6 +333,8 @@ export type ESNodeListenerMap = { 'MethodDefinition:exit': ES.MethodDefinition PropertyDefinition: ES.PropertyDefinition 'PropertyDefinition:exit': ES.PropertyDefinition + StaticBlock: ES.StaticBlock + 'StaticBlock:exit': ES.StaticBlock ImportDeclaration: ES.ImportDeclaration 'ImportDeclaration:exit': ES.ImportDeclaration ExportNamedDeclaration: ES.ExportNamedDeclaration diff --git a/typings/eslint-plugin-vue/util-types/ast/es-ast.ts b/typings/eslint-plugin-vue/util-types/ast/es-ast.ts index ba320a979..eff4f983b 100644 --- a/typings/eslint-plugin-vue/util-types/ast/es-ast.ts +++ b/typings/eslint-plugin-vue/util-types/ast/es-ast.ts @@ -27,6 +27,7 @@ export type ESNode = | ClassBody | MethodDefinition | PropertyDefinition + | StaticBlock | ModuleDeclaration | ModuleSpecifier @@ -63,10 +64,12 @@ export type Statement = export interface EmptyStatement extends HasParentNode { type: 'EmptyStatement' } -export interface BlockStatement extends HasParentNode { - type: 'BlockStatement' +interface BaseBlock extends HasParentNode { body: Statement[] } +export interface BlockStatement extends BaseBlock { + type: 'BlockStatement' +} export interface ExpressionStatement extends HasParentNode { type: 'ExpressionStatement' expression: Expression @@ -187,7 +190,7 @@ export interface ClassDeclaration extends HasParentNode { } export interface ClassBody extends HasParentNode { type: 'ClassBody' - body: (MethodDefinition | PropertyDefinition)[] + body: (MethodDefinition | PropertyDefinition | StaticBlock)[] } interface BaseMethodDefinition extends HasParentNode { type: 'MethodDefinition' @@ -242,6 +245,11 @@ export type PropertyDefinition = | PropertyDefinitionComputedName | PropertyDefinitionPrivate +export interface StaticBlock extends BaseBlock { + type: 'StaticBlock' + parent: ClassBody +} + export type ModuleDeclaration = | ImportDeclaration | ExportNamedDeclaration