Skip to content

Commit afae97c

Browse files
committed
Refine extends-to-implements code fix
1. Retain surrounding trivia when swapping the keyword. 2. Insert commas at the full-starts, rather than starts, of existing keywords when merging with existing implements clauses. Fixes microsoft#18794
1 parent 4eb633e commit afae97c

File tree

4 files changed

+34
-4
lines changed

4 files changed

+34
-4
lines changed

src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,22 @@ namespace ts.codefix {
2727
}
2828

2929
function doChanges(changes: textChanges.ChangeTracker, sourceFile: SourceFile, extendsToken: Node, heritageClauses: ReadonlyArray<HeritageClause>): void {
30-
changes.replaceNode(sourceFile, extendsToken, createToken(SyntaxKind.ImplementsKeyword));
30+
changes.replaceRange(sourceFile, { pos: extendsToken.getStart(), end: extendsToken.end }, createToken(SyntaxKind.ImplementsKeyword));
3131
// We replace existing keywords with commas.
3232
for (let i = 1; i < heritageClauses.length; i++) {
3333
const keywordToken = heritageClauses[i].getFirstToken()!;
34-
changes.replaceNode(sourceFile, keywordToken, createToken(SyntaxKind.CommaToken));
34+
const keywordFullStart = keywordToken.getFullStart();
35+
changes.replaceRange(sourceFile, { pos: keywordFullStart, end: keywordFullStart }, createToken(SyntaxKind.CommaToken));
36+
37+
// Rough heuristic: delete trailing whitespace after keyword so that it's not excessive.
38+
// (Trailing because leading might be indentation, which is more sensitive.)
39+
const text = sourceFile.text;
40+
let end = keywordToken.end;
41+
while (end < text.length && ts.isWhiteSpaceSingleLine(text.charCodeAt(end))) {
42+
end++;
43+
}
44+
45+
changes.deleteRange(sourceFile, { pos: keywordToken.getStart(), end });
3546
}
3647
}
3748
}

tests/cases/fourslash/codeFixChangeExtendsToImplementsAbstractModifier.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
verify.codeFix({
99
description: "Change 'extends' to 'implements'",
1010
// TODO: GH#18794
11-
newRangeContent: "abstract class A implements I1 , I2",
11+
newRangeContent: "abstract class A implements I1, I2",
1212
});

tests/cases/fourslash/codeFixChangeExtendsToImplementsWithDecorator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313
verify.codeFix({
1414
description: "Change 'extends' to 'implements'",
1515
// TODO: GH#18794
16-
newRangeContent: "class A implements I1 , I2 { }",
16+
newRangeContent: "class A implements I1, I2 { }",
1717
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// interface I1 { }
4+
//// interface I2 { }
5+
//// interface I3 { }
6+
7+
//// [|class MyClass /*A !*/ //B !
8+
//// /*C !*/ extends /*D !*/ I1 /*E !*/ //F !
9+
//// /*G !*/ implements /*H !*/ I2 /*I !*/, /*J !*/ I3 /*K !*/ //L !|]
10+
//// {
11+
//// }
12+
13+
verify.codeFix({
14+
description: "Change 'extends' to 'implements'",
15+
// TODO: GH#18794
16+
newRangeContent: `class MyClass /*A !*/ //B !
17+
/*C !*/ implements /*D !*/ I1, /*E !*/ //F !
18+
/*G !*/ /*H !*/ I2 /*I !*/, /*J !*/ I3 /*K !*/ //L !`,
19+
});

0 commit comments

Comments
 (0)