forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfixAwaitInSyncFunction.ts
74 lines (69 loc) · 3.23 KB
/
fixAwaitInSyncFunction.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* @internal */
namespace ts.codefix {
const fixId = "fixAwaitInSyncFunction";
const errorCodes = [
Diagnostics.await_expression_is_only_allowed_within_an_async_function.code,
Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator.code,
];
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile, span } = context;
const nodes = getNodes(sourceFile, span.start);
if (!nodes) return undefined;
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes));
return [{ description: getLocaleSpecificMessage(Diagnostics.Add_async_modifier_to_containing_function), changes, fixId }];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const nodes = getNodes(diag.file, diag.start);
if (!nodes) return;
doChange(changes, context.sourceFile, nodes);
}),
});
function getReturnType(expr: FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction) {
if (expr.type) {
return expr.type;
}
if (isVariableDeclaration(expr.parent) &&
expr.parent.type &&
isFunctionTypeNode(expr.parent.type)) {
return expr.parent.type.type;
}
}
function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, returnType: TypeNode | undefined } | undefined {
const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false);
const containingFunction = getContainingFunction(token);
let insertBefore: Node | undefined;
switch (containingFunction.kind) {
case SyntaxKind.MethodDeclaration:
insertBefore = containingFunction.name;
break;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
insertBefore = findChildOfKind(containingFunction, SyntaxKind.FunctionKeyword, sourceFile);
break;
case SyntaxKind.ArrowFunction:
insertBefore = findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile) || first(containingFunction.parameters);
break;
default:
return;
}
return {
insertBefore,
returnType: getReturnType(containingFunction)
};
}
function doChange(
changes: textChanges.ChangeTracker,
sourceFile: SourceFile,
{ insertBefore, returnType }: { insertBefore: Node | undefined, returnType: TypeNode | undefined }): void {
if (returnType) {
const entityName = getEntityNameFromTypeNode(returnType);
if (!entityName || entityName.kind !== SyntaxKind.Identifier || entityName.text !== "Promise") {
changes.replaceNode(sourceFile, returnType, createTypeReferenceNode("Promise", createNodeArray([returnType])));
}
}
changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, insertBefore);
}
}