Skip to content

Commit 6b493f2

Browse files
authored
fix(23871): change insertNodeAfter to replaceNode to avoid extra newlines (microsoft#38045)
1 parent 5b4cbc9 commit 6b493f2

File tree

4 files changed

+25
-48
lines changed

4 files changed

+25
-48
lines changed

src/services/codefixes/convertFunctionToEs6Class.ts

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,31 @@ namespace ts.codefix {
1414

1515
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker): void {
1616
const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position))!;
17-
1817
if (!ctorSymbol || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) {
1918
// Bad input
2019
return undefined;
2120
}
2221

2322
const ctorDeclaration = ctorSymbol.valueDeclaration;
24-
25-
let precedingNode: Node | undefined;
26-
let newClassDeclaration: ClassDeclaration | undefined;
27-
switch (ctorDeclaration.kind) {
28-
case SyntaxKind.FunctionDeclaration:
29-
precedingNode = ctorDeclaration;
30-
changes.delete(sourceFile, ctorDeclaration);
31-
newClassDeclaration = createClassFromFunctionDeclaration(ctorDeclaration as FunctionDeclaration);
32-
break;
33-
34-
case SyntaxKind.VariableDeclaration:
35-
precedingNode = ctorDeclaration.parent.parent;
36-
newClassDeclaration = createClassFromVariableDeclaration(ctorDeclaration as VariableDeclaration);
37-
if ((<VariableDeclarationList>ctorDeclaration.parent).declarations.length === 1) {
38-
copyLeadingComments(precedingNode, newClassDeclaration!, sourceFile); // TODO: GH#18217
39-
changes.delete(sourceFile, precedingNode);
40-
}
41-
else {
42-
changes.delete(sourceFile, ctorDeclaration);
43-
}
44-
break;
45-
}
46-
47-
if (!newClassDeclaration) {
48-
return undefined;
23+
if (isFunctionDeclaration(ctorDeclaration)) {
24+
changes.replaceNode(sourceFile, ctorDeclaration, createClassFromFunctionDeclaration(ctorDeclaration));
4925
}
26+
else if (isVariableDeclaration(ctorDeclaration)) {
27+
const classDeclaration = createClassFromVariableDeclaration(ctorDeclaration);
28+
if (!classDeclaration) {
29+
return undefined;
30+
}
5031

51-
// Deleting a declaration only deletes JSDoc style comments, so only copy those to the new node.
52-
if (hasJSDocNodes(ctorDeclaration)) {
53-
copyLeadingComments(ctorDeclaration, newClassDeclaration, sourceFile);
32+
const ancestor = ctorDeclaration.parent.parent;
33+
if (isVariableDeclarationList(ctorDeclaration.parent) && ctorDeclaration.parent.declarations.length > 1) {
34+
changes.delete(sourceFile, ctorDeclaration);
35+
changes.insertNodeAfter(sourceFile, ancestor, classDeclaration);
36+
}
37+
else {
38+
changes.replaceNode(sourceFile, ancestor, classDeclaration);
39+
}
5440
}
5541

56-
// Because the preceding node could be touched, we need to insert nodes before delete nodes.
57-
changes.insertNodeAfter(sourceFile, precedingNode!, newClassDeclaration);
58-
5942
function createClassElementsFromSymbol(symbol: Symbol) {
6043
const memberElements: ClassElement[] = [];
6144
// all instance members are stored in the "member" array of symbol
@@ -220,12 +203,8 @@ namespace ts.codefix {
220203
}
221204

222205
function createClassFromVariableDeclaration(node: VariableDeclaration): ClassDeclaration | undefined {
223-
const initializer = node.initializer as FunctionExpression;
224-
if (!initializer || initializer.kind !== SyntaxKind.FunctionExpression) {
225-
return undefined;
226-
}
227-
228-
if (node.name.kind !== SyntaxKind.Identifier) {
206+
const initializer = node.initializer;
207+
if (!initializer || !isFunctionExpression(initializer) || !isIdentifier(node.name)) {
229208
return undefined;
230209
}
231210

@@ -234,7 +213,7 @@ namespace ts.codefix {
234213
memberElements.unshift(factory.createConstructorDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, initializer.parameters, initializer.body));
235214
}
236215

237-
const modifiers = getModifierKindFromSource(precedingNode!, SyntaxKind.ExportKeyword);
216+
const modifiers = getModifierKindFromSource(node.parent.parent, SyntaxKind.ExportKeyword);
238217
const cls = factory.createClassDeclaration(/*decorators*/ undefined, modifiers, node.name,
239218
/*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements);
240219
// Don't call copyComments here because we'll already leave them in place

tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
verify.codeFix({
99
description: "Convert function to an ES2015 class",
1010
newFileContent:
11-
`
12-
/** Doc */
11+
`/** Doc */
1312
class C {
1413
constructor() { this.x = 0; }
15-
}
16-
`,
14+
}`,
1715
});

tests/cases/fourslash/server/convertFunctionToEs6Class-server1.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ class fn {\r
2222
bar() {\r
2323
console.log('hello world');\r
2424
}\r
25-
}\r
25+
}
2626
`,
2727
});

tests/cases/fourslash/server/convertFunctionToEs6Class-server2.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616
verify.codeFix({
1717
description: "Convert function to an ES2015 class",
1818
newFileContent:
19-
`/**\r
20-
* JSDoc Comment\r
21-
*/\r
19+
`/**
20+
* JSDoc Comment
21+
*/
2222
class fn {\r
2323
constructor() {\r
2424
this.baz = 10;\r
2525
}\r
2626
bar() {\r
2727
console.log('hello world');\r
2828
}\r
29-
}\r
29+
}
3030
`,
3131
});

0 commit comments

Comments
 (0)