1/* @internal */ 2namespace ts.codefix { 3 const fixId = "fixAwaitInSyncFunction"; 4 const errorCodes = [ 5 Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code, 6 Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code, 7 ]; 8 registerCodeFix({ 9 errorCodes, 10 getCodeActions(context) { 11 const { sourceFile, span } = context; 12 const nodes = getNodes(sourceFile, span.start); 13 if (!nodes) return undefined; 14 const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes)); 15 return [createCodeFixAction(fixId, changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers)]; 16 }, 17 fixIds: [fixId], 18 getAllCodeActions: context => { 19 const seen = new Map<string, true>(); 20 return codeFixAll(context, errorCodes, (changes, diag) => { 21 const nodes = getNodes(diag.file, diag.start); 22 if (!nodes || !addToSeen(seen, getNodeId(nodes.insertBefore))) return; 23 doChange(changes, context.sourceFile, nodes); 24 }); 25 }, 26 }); 27 28 function getReturnType(expr: FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction) { 29 if (expr.type) { 30 return expr.type; 31 } 32 if (isVariableDeclaration(expr.parent) && 33 expr.parent.type && 34 isFunctionTypeNode(expr.parent.type)) { 35 return expr.parent.type.type; 36 } 37 } 38 39 function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, returnType: TypeNode | undefined } | undefined { 40 const token = getTokenAtPosition(sourceFile, start); 41 const containingFunction = getContainingFunction(token); 42 if (!containingFunction) { 43 return; 44 } 45 46 let insertBefore: Node | undefined; 47 switch (containingFunction.kind) { 48 case SyntaxKind.MethodDeclaration: 49 insertBefore = containingFunction.name; 50 break; 51 case SyntaxKind.FunctionDeclaration: 52 case SyntaxKind.FunctionExpression: 53 insertBefore = findChildOfKind(containingFunction, SyntaxKind.FunctionKeyword, sourceFile); 54 break; 55 case SyntaxKind.ArrowFunction: 56 insertBefore = findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile) || first(containingFunction.parameters); 57 break; 58 default: 59 return; 60 } 61 62 return insertBefore && { 63 insertBefore, 64 returnType: getReturnType(containingFunction) 65 }; 66 } 67 68 function doChange( 69 changes: textChanges.ChangeTracker, 70 sourceFile: SourceFile, 71 { insertBefore, returnType }: { insertBefore: Node, returnType: TypeNode | undefined }): void { 72 73 if (returnType) { 74 const entityName = getEntityNameFromTypeNode(returnType); 75 if (!entityName || entityName.kind !== SyntaxKind.Identifier || entityName.text !== "Promise") { 76 changes.replaceNode(sourceFile, returnType, factory.createTypeReferenceNode("Promise", factory.createNodeArray([returnType]))); 77 } 78 } 79 changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, insertBefore); 80 } 81} 82