|
15 | 15 | * limitations under the License.
|
16 | 16 | */
|
17 | 17 |
|
18 |
| -import { hasModifier, isCallExpression } from "tsutils"; |
| 18 | +import * as tsutils from "tsutils"; |
19 | 19 | import * as ts from "typescript";
|
20 | 20 |
|
21 | 21 | import * as Lint from "../index";
|
@@ -102,34 +102,41 @@ export class Rule extends Lint.Rules.TypedRule {
|
102 | 102 | function walk(ctx: Lint.WalkContext<EnabledSyntaxKinds>, tc: ts.TypeChecker) {
|
103 | 103 | const { sourceFile, options } = ctx;
|
104 | 104 | 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); |
127 | 112 | }
|
128 | 113 | }
|
129 | 114 | return ts.forEachChild(node, cb);
|
130 | 115 | });
|
131 | 116 | }
|
132 | 117 |
|
| 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 | + |
133 | 140 | function returnsPromise(node: ts.FunctionLikeDeclaration, tc: ts.TypeChecker): boolean {
|
134 | 141 | const type = tc.getReturnTypeOfSignature(tc.getTypeAtLocation(node).getCallSignatures()[0]);
|
135 | 142 | return type.symbol !== undefined && type.symbol.name === "Promise";
|
|
0 commit comments