Skip to content

Commit b75f6af

Browse files
committed
fix(40042): add modifiers in correct position for decorated methods
1 parent 610fa28 commit b75f6af

7 files changed

+166
-12
lines changed

src/services/codefixes/convertToAsyncFunction.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,13 @@ namespace ts.codefix {
7373
}
7474

7575
// add the async keyword
76-
changes.insertLastModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, functionToConvert);
76+
if (functionToConvert.modifiers) {
77+
changes.insertModifierAt(sourceFile, functionToConvert.modifiers.end, SyntaxKind.AsyncKeyword, { prefix: " " });
78+
}
79+
else {
80+
const pos = functionToConvert.decorators ? skipTrivia(sourceFile.text, functionToConvert.decorators.end) : functionToConvert.getStart(sourceFile);
81+
changes.insertModifierAt(sourceFile, pos, SyntaxKind.AsyncKeyword, { suffix: " " });
82+
}
7783

7884
for (const returnStatement of returnStatements) {
7985
forEachChild(returnStatement, function visit(node) {

src/services/textChanges.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -388,19 +388,12 @@ namespace ts.textChanges {
388388
this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, options), newNode, this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween));
389389
}
390390

391-
public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void {
392-
const pos = before.getStart(sourceFile);
393-
this.insertNodeAt(sourceFile, pos, factory.createToken(modifier), { suffix: " " });
391+
public insertModifierAt(sourceFile: SourceFile, pos: number, modifier: SyntaxKind, options: InsertNodeOptions = {}): void {
392+
this.insertNodeAt(sourceFile, pos, factory.createToken(modifier), options);
394393
}
395394

396-
public insertLastModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void {
397-
if (!before.modifiers) {
398-
this.insertModifierBefore(sourceFile, modifier, before);
399-
return;
400-
}
401-
402-
const pos = before.modifiers.end;
403-
this.insertNodeAt(sourceFile, pos, factory.createToken(modifier), { prefix: " " });
395+
public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void {
396+
return this.insertModifierAt(sourceFile, before.getStart(sourceFile), modifier, { suffix: " " });
404397
}
405398

406399
public insertCommentBeforeLine(sourceFile: SourceFile, lineNumber: number, position: number, commentText: string): void {

src/testRunner/unittests/services/convertToAsyncFunction.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,57 @@ function [#|foo|]() {
13781378
return fetch('b').then(() => 'c');
13791379
})
13801380
}
1381+
`);
1382+
_testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethod", `
1383+
function decorator() {
1384+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1385+
}
1386+
class Foo {
1387+
@decorator()
1388+
[#|m|]() {
1389+
return fetch('a').then(x => x);
1390+
}
1391+
}
1392+
`);
1393+
1394+
_testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithSingleLineComment", `
1395+
function decorator() {
1396+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1397+
}
1398+
class Foo {
1399+
@decorator()
1400+
// comment
1401+
[#|m|]() {
1402+
return fetch('a').then(x => x);
1403+
}
1404+
}
1405+
`);
1406+
1407+
_testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithMultipleLineComment", `
1408+
function decorator() {
1409+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1410+
}
1411+
class Foo {
1412+
@decorator()
1413+
/**
1414+
* comment
1415+
*/
1416+
[#|m|]() {
1417+
return fetch('a').then(x => x);
1418+
}
1419+
}
1420+
`);
1421+
1422+
_testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithModifier", `
1423+
function decorator() {
1424+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1425+
}
1426+
class Foo {
1427+
@decorator()
1428+
public [#|m|]() {
1429+
return fetch('a').then(x => x);
1430+
}
1431+
}
13811432
`);
13821433

13831434
_testConvertToAsyncFunctionFailedSuggestion("convertToAsyncFunction_OutermostOnlyFailure", `
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// ==ORIGINAL==
2+
3+
function decorator() {
4+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
5+
}
6+
class Foo {
7+
@decorator()
8+
/*[#|*/m/*|]*/() {
9+
return fetch('a').then(x => x);
10+
}
11+
}
12+
13+
// ==ASYNC FUNCTION::Convert to async function==
14+
15+
function decorator() {
16+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
17+
}
18+
class Foo {
19+
@decorator()
20+
async m() {
21+
const x = await fetch('a');
22+
return x;
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// ==ORIGINAL==
2+
3+
function decorator() {
4+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
5+
}
6+
class Foo {
7+
@decorator()
8+
public /*[#|*/m/*|]*/() {
9+
return fetch('a').then(x => x);
10+
}
11+
}
12+
13+
// ==ASYNC FUNCTION::Convert to async function==
14+
15+
function decorator() {
16+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
17+
}
18+
class Foo {
19+
@decorator()
20+
public async m() {
21+
const x = await fetch('a');
22+
return x;
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// ==ORIGINAL==
2+
3+
function decorator() {
4+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
5+
}
6+
class Foo {
7+
@decorator()
8+
/**
9+
* comment
10+
*/
11+
/*[#|*/m/*|]*/() {
12+
return fetch('a').then(x => x);
13+
}
14+
}
15+
16+
// ==ASYNC FUNCTION::Convert to async function==
17+
18+
function decorator() {
19+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
20+
}
21+
class Foo {
22+
@decorator()
23+
/**
24+
* comment
25+
*/
26+
async m() {
27+
const x = await fetch('a');
28+
return x;
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// ==ORIGINAL==
2+
3+
function decorator() {
4+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
5+
}
6+
class Foo {
7+
@decorator()
8+
// comment
9+
/*[#|*/m/*|]*/() {
10+
return fetch('a').then(x => x);
11+
}
12+
}
13+
14+
// ==ASYNC FUNCTION::Convert to async function==
15+
16+
function decorator() {
17+
return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
18+
}
19+
class Foo {
20+
@decorator()
21+
// comment
22+
async m() {
23+
const x = await fetch('a');
24+
return x;
25+
}
26+
}

0 commit comments

Comments
 (0)