From 3b254e554b8f07e441848c285a1ee66406c12f95 Mon Sep 17 00:00:00 2001 From: Nikita Stefaniak Date: Wed, 10 Mar 2021 01:17:36 +0100 Subject: [PATCH 1/3] fix(eslint-plugin): prom-func-async fixer bug --- .../src/rules/promise-function-async.ts | 43 ++++++++++++++++++- .../rules/promise-function-async.test.ts | 36 ++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index ce624be643c1..07423313a2e7 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -1,7 +1,9 @@ import { AST_NODE_TYPES, + AST_TOKEN_TYPES, TSESTree, } from '@typescript-eslint/experimental-utils'; +import { last } from 'lodash'; import * as ts from 'typescript'; import * as util from '../util'; @@ -156,8 +158,47 @@ export default util.createRule({ (node.parent.type === AST_NODE_TYPES.Property && node.parent.method)) ) { - return fixer.insertTextBefore(node.parent.key, 'async '); + // this function is a class method or object function property shorthand + const method = node.parent; + + /** the token to put `async` before */ + let keyToken = sourceCode.getFirstToken(method)!; + + // if there are decorators then skip past them + if ( + method.type === AST_NODE_TYPES.MethodDefinition && + method.decorators + ) { + const lastDecorator = last(method.decorators); + if (lastDecorator) { + keyToken = sourceCode.getTokenAfter(lastDecorator)!; + } + } + + // if current token is a keyword like `static` or `public` then skip it + while (keyToken?.type === AST_TOKEN_TYPES.Keyword) { + keyToken = sourceCode.getTokenAfter(keyToken)!; + } + + // check if there is a space between key and previous token + let insertSpace = false; + if (keyToken) { + const beforeKeyToken = sourceCode.getTokenBefore(keyToken); + if (beforeKeyToken) { + insertSpace = !sourceCode.isSpaceBetween!( + beforeKeyToken, + keyToken, + ); + } + } + + let code = 'async '; + if (insertSpace) { + code = ` ${code}`; + } + return fixer.insertTextBefore(keyToken, code); } + return fixer.insertTextBefore(node, 'async '); }, }); diff --git a/packages/eslint-plugin/tests/rules/promise-function-async.test.ts b/packages/eslint-plugin/tests/rules/promise-function-async.test.ts index 961047138c99..6a0451ed8580 100644 --- a/packages/eslint-plugin/tests/rules/promise-function-async.test.ts +++ b/packages/eslint-plugin/tests/rules/promise-function-async.test.ts @@ -1,3 +1,4 @@ +import { noFormat } from '@typescript-eslint/experimental-utils/src/eslint-utils'; import rule from '../../src/rules/promise-function-async'; import { getFixturesRootDir, RuleTester } from '../RuleTester'; @@ -630,6 +631,41 @@ class Test { public async test() { return Promise.resolve(123); } +} + `, + }, + { + code: noFormat` +class Test { + @decorator(async () => {}) + static protected[(1)]() { + return Promise.resolve(1); + } + public'bar'() { + return Promise.resolve(2); + } + private['baz']() { + return Promise.resolve(3); + } +} + `, + errors: [ + { line: 4, column: 3, messageId }, + { line: 7, column: 3, messageId }, + { line: 10, column: 3, messageId }, + ], + output: noFormat` +class Test { + @decorator(async () => {}) + static protected async [(1)]() { + return Promise.resolve(1); + } + public async 'bar'() { + return Promise.resolve(2); + } + private async ['baz']() { + return Promise.resolve(3); + } } `, }, From a65462e3cfc31fc0d6b9eced118a5570a0f3064f Mon Sep 17 00:00:00 2001 From: Nikita Stefaniak Date: Wed, 10 Mar 2021 02:30:41 +0100 Subject: [PATCH 2/3] test(eslint-plugin): improve coverage --- .../src/rules/promise-function-async.ts | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index 07423313a2e7..2e6231c3a763 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -169,28 +169,20 @@ export default util.createRule({ method.type === AST_NODE_TYPES.MethodDefinition && method.decorators ) { - const lastDecorator = last(method.decorators); - if (lastDecorator) { - keyToken = sourceCode.getTokenAfter(lastDecorator)!; - } + const lastDecorator = last(method.decorators)!; + keyToken = sourceCode.getTokenAfter(lastDecorator)!; } // if current token is a keyword like `static` or `public` then skip it - while (keyToken?.type === AST_TOKEN_TYPES.Keyword) { + while (keyToken.type === AST_TOKEN_TYPES.Keyword) { keyToken = sourceCode.getTokenAfter(keyToken)!; } // check if there is a space between key and previous token - let insertSpace = false; - if (keyToken) { - const beforeKeyToken = sourceCode.getTokenBefore(keyToken); - if (beforeKeyToken) { - insertSpace = !sourceCode.isSpaceBetween!( - beforeKeyToken, - keyToken, - ); - } - } + const insertSpace = !sourceCode.isSpaceBetween!( + sourceCode.getTokenBefore(keyToken)!, + keyToken, + ); let code = 'async '; if (insertSpace) { From c35ef36d739c4ac715619d5349f146713ded571c Mon Sep 17 00:00:00 2001 From: Nikita Stefaniak Date: Mon, 15 Mar 2021 23:12:48 +0100 Subject: [PATCH 3/3] style(eslint-plugin): fix style --- packages/eslint-plugin/src/rules/promise-function-async.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index 2e6231c3a763..68b1d42567c5 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -3,7 +3,6 @@ import { AST_TOKEN_TYPES, TSESTree, } from '@typescript-eslint/experimental-utils'; -import { last } from 'lodash'; import * as ts from 'typescript'; import * as util from '../util'; @@ -161,7 +160,7 @@ export default util.createRule({ // this function is a class method or object function property shorthand const method = node.parent; - /** the token to put `async` before */ + // the token to put `async` before let keyToken = sourceCode.getFirstToken(method)!; // if there are decorators then skip past them @@ -169,7 +168,8 @@ export default util.createRule({ method.type === AST_NODE_TYPES.MethodDefinition && method.decorators ) { - const lastDecorator = last(method.decorators)!; + const lastDecorator = + method.decorators[method.decorators.length - 1]; keyToken = sourceCode.getTokenAfter(lastDecorator)!; }