Skip to content

Commit 8f23bf8

Browse files
author
Andy
authored
Add textChanges methods to insert nodes at the start of multiline bodies (#20445)
* Add textChanges methods to insert nodes at the start of multiline bodies * Replace constructor body if not already multiline
1 parent 8153397 commit 8f23bf8

File tree

5 files changed

+44
-13
lines changed

5 files changed

+44
-13
lines changed

src/harness/fourslash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2471,7 +2471,7 @@ Actual: ${stringify(fullActual)}`);
24712471
}
24722472

24732473
private verifyNewContent(options: FourSlashInterface.NewContentOptions) {
2474-
if (options.newFileContent) {
2474+
if (options.newFileContent !== undefined) {
24752475
assert(!options.newRangeContent);
24762476
this.verifyCurrentFileContent(options.newFileContent);
24772477
}

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ namespace ts.codefix {
6262
}
6363

6464
const classDeclarationSourceFile = getSourceFileOfNode(classDeclaration);
65-
const classOpenBrace = getOpenBraceOfClassLike(classDeclaration, classDeclarationSourceFile);
6665

6766
return isInJavaScriptFile(classDeclarationSourceFile) ?
6867
getActionsForAddMissingMemberInJavaScriptFile(classDeclaration, makeStatic) :
@@ -154,7 +153,7 @@ namespace ts.codefix {
154153
typeNode,
155154
/*initializer*/ undefined);
156155
const propertyChangeTracker = textChanges.ChangeTracker.fromContext(context);
157-
propertyChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, property, { suffix: context.newLineCharacter });
156+
propertyChangeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, property, context.newLineCharacter);
158157

159158
const diag = makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0;
160159
actions = append(actions, {
@@ -180,7 +179,7 @@ namespace ts.codefix {
180179
typeNode);
181180

182181
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromContext(context);
183-
indexSignatureChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, indexSignature, { suffix: context.newLineCharacter });
182+
indexSignatureChangeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, indexSignature, context.newLineCharacter);
184183

185184
actions.push({
186185
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_property_0), [tokenName]),
@@ -197,7 +196,7 @@ namespace ts.codefix {
197196
const methodDeclaration = createMethodFromCallExpression(callExpression, tokenName, includeTypeScriptSyntax, makeStatic);
198197

199198
const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromContext(context);
200-
methodDeclarationChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, methodDeclaration, { suffix: context.newLineCharacter });
199+
methodDeclarationChangeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, methodDeclaration, context.newLineCharacter);
201200
const diag = makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0;
202201
return {
203202
description: formatStringFromArgs(getLocaleSpecificMessage(diag), [tokenName]),

src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace ts.codefix {
1212

1313
const changeTracker = textChanges.ChangeTracker.fromContext(context);
1414
const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray));
15-
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>token.parent, sourceFile), superCall, { suffix: context.newLineCharacter });
15+
changeTracker.insertNodeAtConstructorStart(sourceFile, <ConstructorDeclaration>token.parent, superCall, context.newLineCharacter);
1616

1717
return [{
1818
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),

src/services/textChanges.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,32 @@ namespace ts.textChanges {
337337
return this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, options);
338338
}
339339

340-
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}) {
341-
if ((isStatementButNotDeclaration(after)) ||
340+
public insertNodeAtConstructorStart(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement, newLineCharacter: string): void {
341+
const firstStatement = firstOrUndefined(ctr.body.statements);
342+
if (!firstStatement || !ctr.body.multiLine) {
343+
this.replaceNode(sourceFile, ctr.body, createBlock([newStatement, ...ctr.body.statements], /*multiLine*/ true), { useNonAdjustedEndPosition: true });
344+
}
345+
else {
346+
this.insertNodeBefore(sourceFile, firstStatement, newStatement, { suffix: newLineCharacter });
347+
}
348+
}
349+
350+
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration, newElement: ClassElement, newLineCharacter: string): void {
351+
const firstMember = firstOrUndefined(cls.members);
352+
if (!firstMember) {
353+
const members = [newElement];
354+
const newCls = cls.kind === SyntaxKind.ClassDeclaration
355+
? updateClassDeclaration(cls, cls.decorators, cls.modifiers, cls.name, cls.typeParameters, cls.heritageClauses, members)
356+
: updateClassExpression(cls, cls.modifiers, cls.name, cls.typeParameters, cls.heritageClauses, members);
357+
this.replaceNode(sourceFile, cls, newCls, { useNonAdjustedEndPosition: true });
358+
}
359+
else {
360+
this.insertNodeBefore(sourceFile, firstMember, newElement, { suffix: newLineCharacter });
361+
}
362+
}
363+
364+
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}): this {
365+
if (isStatementButNotDeclaration(after) ||
342366
after.kind === SyntaxKind.PropertyDeclaration ||
343367
after.kind === SyntaxKind.PropertySignature ||
344368
after.kind === SyntaxKind.MethodSignature) {

tests/cases/fourslash/codeFixSuperCall.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@
33
////class Base{
44
////}
55
////class C extends Base{
6-
//// constructor() {[|
7-
//// |]}
6+
//// constructor() {}
87
////}
9-
// TODO: GH#18445
10-
verify.rangeAfterCodeFix(`
8+
9+
verify.codeFix({
10+
description: "Add missing 'super()' call",
11+
// TODO: GH#18445
12+
newFileContent:
13+
`class Base{
14+
}
15+
class C extends Base{
16+
constructor() {\r
1117
super();\r
12-
`, /*includeWhitespace*/ true);
18+
}
19+
}`,
20+
});

0 commit comments

Comments
 (0)