Skip to content

Commit 1957dfe

Browse files
authored
Merge pull request microsoft#20991 from amcasey/GH18794
Refine extends-to-implements code fix
2 parents 4437476 + a961d7a commit 1957dfe

File tree

4 files changed

+41
-7
lines changed

4 files changed

+41
-7
lines changed

src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,26 @@ 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));
31-
// We replace existing keywords with commas.
32-
for (let i = 1; i < heritageClauses.length; i++) {
33-
const keywordToken = heritageClauses[i].getFirstToken()!;
34-
changes.replaceNode(sourceFile, keywordToken, createToken(SyntaxKind.CommaToken));
30+
changes.replaceRange(sourceFile, { pos: extendsToken.getStart(), end: extendsToken.end }, createToken(SyntaxKind.ImplementsKeyword));
31+
32+
// If there is already an implements clause, replace the implements keyword with a comma.
33+
if (heritageClauses.length === 2 &&
34+
heritageClauses[0].token === SyntaxKind.ExtendsKeyword &&
35+
heritageClauses[1].token === SyntaxKind.ImplementsKeyword) {
36+
37+
const implementsToken = heritageClauses[1].getFirstToken()!;
38+
const implementsFullStart = implementsToken.getFullStart();
39+
changes.replaceRange(sourceFile, { pos: implementsFullStart, end: implementsFullStart }, createToken(SyntaxKind.CommaToken));
40+
41+
// Rough heuristic: delete trailing whitespace after keyword so that it's not excessive.
42+
// (Trailing because leading might be indentation, which is more sensitive.)
43+
const text = sourceFile.text;
44+
let end = implementsToken.end;
45+
while (end < text.length && ts.isWhiteSpaceSingleLine(text.charCodeAt(end))) {
46+
end++;
47+
}
48+
49+
changes.deleteRange(sourceFile, { pos: implementsToken.getStart(), end });
3550
}
3651
}
3752
}

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)