Skip to content

Commit 626f399

Browse files
committed
add fixAwaitInSyncFunction code fix
1 parent 943e522 commit 626f399

11 files changed

+177
-0
lines changed

Diff for: src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -3843,6 +3843,10 @@
38433843
"category": "Message",
38443844
"code": 90028
38453845
},
3846+
"Convert to async": {
3847+
"category": "Message",
3848+
"code": 90028
3849+
},
38463850
"Convert function to an ES2015 class": {
38473851
"category": "Message",
38483852
"code": 95001

Diff for: src/services/codefixes/fixAwaitInSyncFunction.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "fixAwaitInSyncFunction";
4+
const errorCodes = [
5+
Diagnostics.await_expression_is_only_allowed_within_an_async_function.code,
6+
Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator.code,
7+
];
8+
registerCodeFix({
9+
errorCodes,
10+
getCodeActions(context) {
11+
const { sourceFile, span } = context;
12+
const node = getNode(sourceFile, span.start);
13+
if (!node) return undefined;
14+
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node));
15+
return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_to_async), changes, fixId }];
16+
},
17+
fixIds: [fixId],
18+
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) =>
19+
doChange(changes, context.sourceFile, getNode(diag.file, diag.start!))),
20+
});
21+
22+
function getNode(sourceFile: SourceFile, pos: number): FunctionLikeDeclaration {
23+
const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
24+
const containingFunction = getContainingFunction(token);
25+
if (!isFunctionLikeDeclaration(containingFunction) ||
26+
isConstructorDeclaration(containingFunction) ||
27+
isGetAccessorDeclaration(containingFunction) ||
28+
isSetAccessorDeclaration(containingFunction)) return;
29+
return containingFunction;
30+
}
31+
32+
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, decl: FunctionLikeDeclaration) {
33+
const asyncToken = createToken(SyntaxKind.AsyncKeyword);
34+
const modifiers = decl.modifiers ? decl.modifiers.concat(asyncToken) : createNodeArray([asyncToken]);
35+
let changed;
36+
switch (decl.kind) {
37+
case SyntaxKind.MethodDeclaration:
38+
changed = createMethod(decl.decorators, modifiers, decl.asteriskToken, decl.name, decl.questionToken, decl.typeParameters, decl.parameters, decl.type, decl.body);
39+
break;
40+
case SyntaxKind.FunctionExpression:
41+
changed = createFunctionExpression(modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, decl.type, decl.body);
42+
break;
43+
case SyntaxKind.FunctionDeclaration:
44+
changed = createFunctionDeclaration(decl.decorators, modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, decl.type, decl.body);
45+
break;
46+
case SyntaxKind.ArrowFunction:
47+
changed = createArrowFunction(modifiers, decl.typeParameters, decl.parameters, decl.type, decl.equalsGreaterThanToken, decl.body);
48+
break;
49+
}
50+
changes.replaceNode(sourceFile, decl, changed);
51+
}
52+
}

Diff for: src/services/codefixes/fixes.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/// <reference path="fixForgottenThisPropertyAccess.ts" />
1212
/// <reference path='fixUnusedIdentifier.ts' />
1313
/// <reference path='fixJSDocTypes.ts' />
14+
/// <reference path='fixAwaitInSyncFunction.ts' />
1415
/// <reference path='importFixes.ts' />
1516
/// <reference path='disableJsDiagnostics.ts' />
1617
/// <reference path='helpers.ts' />

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////function f() {
4+
//// await Promise.resolve();
5+
////}
6+
7+
verify.codeFix({
8+
description: "Convert to async",
9+
index: 0,
10+
newFileContent:
11+
`async function f() {\r
12+
await Promise.resolve();\r
13+
}`,
14+
});

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////const f = function() {
4+
//// await Promise.resolve();
5+
//// await Promise.resolve();
6+
////}
7+
8+
verify.codeFix({
9+
description: "Convert to async",
10+
index: 0,
11+
newFileContent:
12+
`const f = async function() {\r
13+
await Promise.resolve();\r
14+
await Promise.resolve();\r
15+
}`,
16+
});

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction3.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////const f = {
4+
//// get a() {
5+
//// return await Promise.resolve();
6+
//// },
7+
//// get a() {
8+
//// await Promise.resolve();
9+
//// },
10+
////}
11+
12+
verify.not.codeFixAvailable();

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction4.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class Foo {
4+
//// constructor {
5+
//// await Promise.resolve();
6+
//// }
7+
////}
8+
9+
verify.not.codeFixAvailable();

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class Foo {
4+
//// bar() {
5+
//// await Promise.resolve();
6+
//// }
7+
////}
8+
9+
verify.codeFix({
10+
description: "Convert to async",
11+
index: 0,
12+
newFileContent:
13+
`class Foo {
14+
async bar() {\r
15+
await Promise.resolve();\r
16+
}}`,
17+
});

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////const f = (promise) => {
4+
//// await promise;
5+
////}
6+
7+
verify.codeFix({
8+
description: "Convert to async",
9+
index: 0,
10+
newFileContent:
11+
`const f = async (promise) => {\r
12+
await promise;\r
13+
}`,
14+
});

Diff for: tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////function f() {
4+
//// for await (const x of g()) {
5+
//// console.log(x);
6+
//// }
7+
////}
8+
9+
verify.codeFix({
10+
description: "Convert to async",
11+
index: 0,
12+
newFileContent:
13+
`function f() => {\r
14+
for await (const x of g()) {\r
15+
console.log(x);\r
16+
}\r
17+
}`,
18+
});
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////function f() {
4+
//// await Promise.resolve();
5+
////}
6+
////
7+
////const g = () => {
8+
//// await f();
9+
////}
10+
11+
verify.codeFixAll({
12+
fixId: "fixAwaitInSyncFunction",
13+
newFileContent:
14+
`async function f() {\r
15+
await Promise.resolve();\r
16+
}
17+
const g = async () => {\r
18+
await f();\r
19+
}`,
20+
});

0 commit comments

Comments
 (0)