Skip to content
This repository was archived by the owner on Mar 25, 2021. It is now read-only.

Commit af24731

Browse files
author
Josh Goldberg
authored
Allowed parenthesis bodies for one-line promise-function-async functions (#4765)
* Allowed parenthesis bodies for one-line promise-function-async functions Fixes #4757. * Used tsutils intead of ts for new parenthesized expression method Gets me every time...
1 parent 9924e7a commit af24731

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

src/rules/promiseFunctionAsyncRule.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { hasModifier, isCallExpression } from "tsutils";
18+
import * as tsutils from "tsutils";
1919
import * as ts from "typescript";
2020

2121
import * as Lint from "../index";
@@ -102,34 +102,41 @@ export class Rule extends Lint.Rules.TypedRule {
102102
function walk(ctx: Lint.WalkContext<EnabledSyntaxKinds>, tc: ts.TypeChecker) {
103103
const { sourceFile, options } = ctx;
104104
return ts.forEachChild(sourceFile, function cb(node): void {
105-
if (options.has(node.kind)) {
106-
const declaration = node as ts.FunctionLikeDeclaration;
107-
switch (node.kind) {
108-
case ts.SyntaxKind.MethodDeclaration:
109-
case ts.SyntaxKind.FunctionDeclaration:
110-
if (declaration.body === undefined) {
111-
break;
112-
}
113-
// falls through
114-
case ts.SyntaxKind.FunctionExpression:
115-
case ts.SyntaxKind.ArrowFunction:
116-
if (
117-
!hasModifier(node.modifiers, ts.SyntaxKind.AsyncKeyword) &&
118-
returnsPromise(declaration, tc) &&
119-
!isCallExpression(declaration.body as ts.Expression)
120-
) {
121-
ctx.addFailure(
122-
node.getStart(sourceFile),
123-
(node as ts.FunctionLikeDeclaration).body!.pos,
124-
Rule.FAILURE_STRING,
125-
);
126-
}
105+
if (options.has(node.kind) && isFunctionLikeWithBody(node)) {
106+
if (
107+
!tsutils.hasModifier(node.modifiers, ts.SyntaxKind.AsyncKeyword) &&
108+
!isCallExpressionBody(node.body) &&
109+
returnsPromise(node, tc)
110+
) {
111+
ctx.addFailure(node.getStart(sourceFile), node.body.pos, Rule.FAILURE_STRING);
127112
}
128113
}
129114
return ts.forEachChild(node, cb);
130115
});
131116
}
132117

118+
function isFunctionLikeWithBody(
119+
node: ts.Node,
120+
): node is ts.FunctionLikeDeclaration & { body: ts.Node } {
121+
switch (node.kind) {
122+
case ts.SyntaxKind.MethodDeclaration:
123+
case ts.SyntaxKind.FunctionDeclaration:
124+
case ts.SyntaxKind.FunctionExpression:
125+
case ts.SyntaxKind.ArrowFunction:
126+
return (node as ts.FunctionLikeDeclaration).body !== undefined;
127+
}
128+
129+
return false;
130+
}
131+
132+
function isCallExpressionBody(body: ts.Node) {
133+
while (tsutils.isParenthesizedExpression(body)) {
134+
body = body.expression;
135+
}
136+
137+
return tsutils.isCallExpression(body);
138+
}
139+
133140
function returnsPromise(node: ts.FunctionLikeDeclaration, tc: ts.TypeChecker): boolean {
134141
const type = tc.getReturnTypeOfSignature(tc.getTypeAtLocation(node).getCallSignatures()[0]);
135142
return type.symbol !== undefined && type.symbol.name === "Promise";

test/rules/promise-function-async/test.ts.lint

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const asyncPromiseArrowFunctionB = async () => new Promise<void>();
3838

3939
// non-'async' non-'Promise'-returning arrow functions are allowed
4040
const nonAsyncNonPromiseArrowFunction = (n: number) => n;
41+
const nonAsyncNonPromiseArrowFunctionParenthesisOne = (n: number) => (n);
42+
const nonAsyncNonPromiseArrowFunctionParenthesisTwo = (n: number) => ((n));
4143

4244
class Test {
4345
public nonAsyncPromiseMethodA(p: Promise<void>) {
@@ -65,6 +67,8 @@ class Test {
6567

6668
// single statement lamda functions that delegate to another promise-returning function are allowed
6769
public delegatingMethod = () => this.asyncPromiseMethodB(1);
70+
public delegatingMethodParenthesisOne = () => (this.asyncPromiseMethodB(1));
71+
public delegatingMethodParenthesisTwo = () => ((this.asyncPromiseMethodB(1)));
6872
}
6973

7074
[0]: functions that return promises must be async

0 commit comments

Comments
 (0)