Skip to content

Commit 5995338

Browse files
author
MQuy
committed
fix(48281) - Preserve indentation when adding missing properties
1 parent 073ac92 commit 5995338

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace ts.codefix {
1919
errorCodes,
2020
getCodeActions(context) {
2121
const typeChecker = context.program.getTypeChecker();
22-
const info = getInfo(context.sourceFile, context.span.start, context.errorCode, typeChecker, context.program);
22+
const info = getInfo(context.sourceFile, context.span.start, context.errorCode, typeChecker, context.program, context.formatContext);
2323
if (!info) {
2424
return undefined;
2525
}
@@ -50,7 +50,7 @@ namespace ts.codefix {
5050

5151
return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => {
5252
eachDiagnostic(context, errorCodes, diag => {
53-
const info = getInfo(diag.file, diag.start, diag.code, checker, context.program);
53+
const info = getInfo(diag.file, diag.start, diag.code, checker, context.program, context.formatContext);
5454
if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + info.token.text)) {
5555
return;
5656
}
@@ -141,6 +141,7 @@ namespace ts.codefix {
141141
readonly properties: Symbol[];
142142
readonly parentDeclaration: ObjectLiteralExpression;
143143
readonly indentation?: number;
144+
readonly trimLeadingWhiteSpaces?: boolean;
144145
}
145146

146147
interface JsxAttributesInfo {
@@ -150,7 +151,7 @@ namespace ts.codefix {
150151
readonly parentDeclaration: JsxOpeningLikeElement;
151152
}
152153

153-
function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, checker: TypeChecker, program: Program): Info | undefined {
154+
function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, checker: TypeChecker, program: Program, formatContext: formatting.FormatContext): Info | undefined {
154155
// The identifier of the missing property. eg:
155156
// this.missing = 1;
156157
// ^^^^^^^
@@ -171,7 +172,10 @@ namespace ts.codefix {
171172

172173
const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), checker.getTypeAtLocation(param), /* requireOptionalProperties */ false, /* matchDiscriminantProperties */ false));
173174
if (!length(properties)) return undefined;
174-
return { kind: InfoKind.ObjectLiteral, token: param.name, properties, indentation: 0, parentDeclaration: parent };
175+
176+
const formatOptions = getFormatCodeSettingsForWriting(formatContext, sourceFile);
177+
const indentation = formatting.SmartIndenter.getIndentation(getLineStartPositionForPosition(tokenPos, sourceFile), sourceFile, formatOptions, getLineStartPositionForPosition(tokenPos, sourceFile) === tokenPos);
178+
return { kind: InfoKind.ObjectLiteral, token: param.name, properties, indentation, trimLeadingWhiteSpaces: true, parentDeclaration: parent };
175179
}
176180

177181
if (!isMemberName(token)) return undefined;
@@ -490,7 +494,8 @@ namespace ts.codefix {
490494
const options = {
491495
leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude,
492496
trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude,
493-
indentation: info.indentation
497+
indentation: info.indentation,
498+
trimLeadingWhiteSpaces: info.trimLeadingWhiteSpaces,
494499
};
495500
changes.replaceNode(context.sourceFile, info.parentDeclaration, factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true), options);
496501
}

src/services/textChanges.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ namespace ts.textChanges {
117117
*/
118118
delta?: number;
119119
/**
120-
* Do not trim leading white spaces in the edit range
120+
* Trim leading white spaces in the edit range
121121
*/
122-
preserveLeadingWhitespace?: boolean;
122+
trimLeadingWhiteSpaces?: boolean;
123123
}
124124

125125
export interface ReplaceWithMultipleNodesOptions extends InsertNodeOptions {
@@ -492,7 +492,7 @@ namespace ts.textChanges {
492492
}
493493
const startPosition = getPrecedingNonSpaceCharacterPosition(sourceFile.text, fnStart - 1);
494494
const indent = sourceFile.text.slice(startPosition, fnStart);
495-
this.insertNodeAt(sourceFile, fnStart, tag, { preserveLeadingWhitespace: false, suffix: this.newLineCharacter + indent });
495+
this.insertNodeAt(sourceFile, fnStart, tag, { suffix: this.newLineCharacter + indent });
496496
}
497497

498498
private createJSDocText(sourceFile: SourceFile, node: HasJSDoc) {
@@ -1068,7 +1068,7 @@ namespace ts.textChanges {
10681068
? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(change.options?.joiner || newLineCharacter)
10691069
: format(change.node);
10701070
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
1071-
const noIndent = (options.preserveLeadingWhitespace || options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, "");
1071+
const noIndent = (options.trimLeadingWhiteSpaces || (options.indentation === undefined && getLineStartPositionForPosition(pos, sourceFile) !== pos)) ? text.replace(/^\s+/, "") : text;
10721072
return (options.prefix || "") + noIndent
10731073
+ ((!options.suffix || endsWith(noIndent, options.suffix))
10741074
? "" : options.suffix);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////interface Test {
4+
//// foo: string;
5+
//// bar(a: string): void;
6+
////}
7+
////function f (_spec: any) {}
8+
////function g (_spec: Test) {}
9+
////[|f(() => {
10+
//// g({});
11+
////});|]
12+
13+
verify.codeFix({
14+
index: 2,
15+
description: ts.Diagnostics.Add_missing_properties.message,
16+
newRangeContent:
17+
`f(() => {
18+
g({
19+
foo: "",
20+
bar: function(a: string): void {
21+
throw new Error("Function not implemented.");
22+
}
23+
});
24+
});`});

0 commit comments

Comments
 (0)