Skip to content

Commit 5fb5ff7

Browse files
committed
add option for object literal indent
1 parent 1ced600 commit 5fb5ff7

File tree

8 files changed

+89
-18
lines changed

8 files changed

+89
-18
lines changed

src/services/formatting/formatting.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ namespace ts.formatting {
328328
break;
329329
}
330330

331-
if (SmartIndenter.shouldIndentChildNode(n, child, sourceFile)) {
331+
if (SmartIndenter.shouldIndentChildNode(options, n, child, sourceFile)) {
332332
return options.indentSize;
333333
}
334334

@@ -470,7 +470,7 @@ namespace ts.formatting {
470470
parentDynamicIndentation: DynamicIndentation,
471471
effectiveParentStartLine: number
472472
): { indentation: number, delta: number } {
473-
const delta = SmartIndenter.shouldIndentChildNode(node) ? options.indentSize : 0;
473+
const delta = SmartIndenter.shouldIndentChildNode(options, node) ? options.indentSize : 0;
474474

475475
if (effectiveParentStartLine === startLine) {
476476
// if node is located on the same line with the parent
@@ -541,9 +541,9 @@ namespace ts.formatting {
541541
getIndentation: () => indentation,
542542
getDelta,
543543
recomputeIndentation: lineAdded => {
544-
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent, node, sourceFile)) {
544+
if (node.parent && SmartIndenter.shouldIndentChildNode(options, node.parent, node, sourceFile)) {
545545
indentation += lineAdded ? options.indentSize : -options.indentSize;
546-
delta = SmartIndenter.shouldIndentChildNode(node) ? options.indentSize : 0;
546+
delta = SmartIndenter.shouldIndentChildNode(options, node) ? options.indentSize : 0;
547547
}
548548
}
549549
};
@@ -581,9 +581,9 @@ namespace ts.formatting {
581581
&& !(node.decorators && kind === getFirstNonDecoratorTokenOfNode(node));
582582
}
583583

584-
function getDelta(child: Node) {
584+
function getDelta(child: TextRangeWithKind) {
585585
// Delta value should be zero when the node explicitly prevents indentation of the child node
586-
return SmartIndenter.nodeWillIndentChild(node, child, sourceFile, /*indentByDefault*/ true) ? delta : 0;
586+
return SmartIndenter.nodeWillIndentChild(options, node, child, sourceFile, /*indentByDefault*/ true) ? delta : 0;
587587
}
588588
}
589589

src/services/formatting/smartIndenter.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ namespace ts.formatting {
112112
let previous: Node | undefined;
113113
let current = precedingToken;
114114
while (current) {
115-
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current, previous, sourceFile, /*isNextChild*/ true)) {
115+
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(options, current, previous, sourceFile, /*isNextChild*/ true)) {
116116
const currentStart = getStartLineAndCharacterForNode(current, sourceFile);
117117
const nextTokenKind = nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile);
118118
const indentationDelta = nextTokenKind !== NextTokenKind.Unknown
@@ -193,7 +193,7 @@ namespace ts.formatting {
193193
}
194194

195195
// increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line
196-
if (shouldIndentChildNode(parent, current, sourceFile, isNextChild) && !parentAndChildShareLine) {
196+
if (shouldIndentChildNode(options, parent, current, sourceFile, isNextChild) && !parentAndChildShareLine) {
197197
indentationDelta += options.indentSize;
198198
}
199199

@@ -531,18 +531,15 @@ namespace ts.formatting {
531531
return false;
532532
}
533533

534-
export function nodeWillIndentChild(parent: TextRangeWithKind, child: TextRangeWithKind | undefined, sourceFile: SourceFileLike | undefined, indentByDefault: boolean): boolean {
534+
export function nodeWillIndentChild(settings: FormatCodeSettings | undefined, parent: TextRangeWithKind, child: TextRangeWithKind | undefined, sourceFile: SourceFileLike | undefined, indentByDefault: boolean): boolean {
535535
const childKind = child ? child.kind : SyntaxKind.Unknown;
536536

537537
switch (parent.kind) {
538538
case SyntaxKind.VariableDeclaration:
539539
case SyntaxKind.PropertyAssignment:
540540
case SyntaxKind.ObjectLiteralExpression:
541-
if (sourceFile && childKind === SyntaxKind.ObjectLiteralExpression) {
542-
const childStart = skipTrivia(sourceFile.text, child.pos);
543-
const startLine = sourceFile.getLineAndCharacterOfPosition(childStart).line;
544-
const endLine = sourceFile.getLineAndCharacterOfPosition(child.end).line;
545-
return startLine === endLine;
541+
if (!settings.indentMultiLineObjectLiteralBeginningOnBlankLine && sourceFile && childKind === SyntaxKind.ObjectLiteralExpression) {
542+
return rangeIsOnOneLine(sourceFile, child);
546543
}
547544
break;
548545
case SyntaxKind.DoStatement:
@@ -596,9 +593,16 @@ namespace ts.formatting {
596593
* True when the parent node should indent the given child by an explicit rule.
597594
* @param isNextChild If true, we are judging indent of a hypothetical child *after* this one, not the current child.
598595
*/
599-
export function shouldIndentChildNode(parent: TextRangeWithKind, child?: Node, sourceFile?: SourceFileLike, isNextChild = false): boolean {
600-
return (nodeContentIsAlwaysIndented(parent.kind) || nodeWillIndentChild(parent, child, sourceFile, /*indentByDefault*/ false))
596+
export function shouldIndentChildNode(settings: FormatCodeSettings | undefined, parent: TextRangeWithKind, child?: Node, sourceFile?: SourceFileLike, isNextChild = false): boolean {
597+
return (nodeContentIsAlwaysIndented(parent.kind) || nodeWillIndentChild(settings, parent, child, sourceFile, /*indentByDefault*/ false))
601598
&& !(isNextChild && child && isControlFlowEndingStatement(child.kind, parent));
602599
}
600+
601+
function rangeIsOnOneLine(sourceFile: SourceFileLike, range: TextRangeWithKind) {
602+
const rangeStart = skipTrivia(sourceFile.text, range.pos);
603+
const startLine = sourceFile.getLineAndCharacterOfPosition(rangeStart).line;
604+
const endLine = sourceFile.getLineAndCharacterOfPosition(range.end).line;
605+
return startLine === endLine;
606+
}
603607
}
604608
}

src/services/textChanges.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ namespace ts.textChanges {
670670
const delta =
671671
options.delta !== undefined
672672
? options.delta
673-
: formatting.SmartIndenter.shouldIndentChildNode(nodeIn)
673+
: formatting.SmartIndenter.shouldIndentChildNode(formatContext.options, nodeIn)
674674
? (formatOptions.indentSize || 0)
675675
: 0;
676676
const file: SourceFileLike = { text, getLineAndCharacterOfPosition(pos) { return getLineAndCharacterOfPosition(this, pos); } };

src/services/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ namespace ts {
629629
placeOpenBraceOnNewLineForFunctions?: boolean;
630630
placeOpenBraceOnNewLineForControlBlocks?: boolean;
631631
insertSpaceBeforeTypeAnnotation?: boolean;
632+
indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean;
632633
}
633634

634635
export interface DefinitionInfo {

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4654,6 +4654,7 @@ declare namespace ts {
46544654
placeOpenBraceOnNewLineForFunctions?: boolean;
46554655
placeOpenBraceOnNewLineForControlBlocks?: boolean;
46564656
insertSpaceBeforeTypeAnnotation?: boolean;
4657+
indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean;
46574658
}
46584659
interface DefinitionInfo {
46594660
fileName: string;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////
4+
//// namespace M {
5+
//// class C {
6+
//// foo() {
7+
//// /*a*/let x = {a:1};
8+
//// let y = {
9+
//// b: 2
10+
//// };
11+
//// let z =
12+
//// {
13+
//// c: 3
14+
//// };/*b*/
15+
//// return x.a + y.b + z.c;
16+
//// }
17+
//// }
18+
//// }
19+
////
20+
21+
goTo.select('a', 'b');
22+
edit.applyRefactor({
23+
refactorName: "Extract Symbol",
24+
actionName: "function_scope_1",
25+
actionDescription: "Extract to method in class 'C'",
26+
newContent:
27+
`
28+
namespace M {
29+
class C {
30+
foo() {
31+
let { x, y, z } = this./*RENAME*/newMethod();
32+
return x.a + y.b + z.c;
33+
}
34+
35+
private newMethod() {
36+
let x = { a: 1 };
37+
let y = {
38+
b: 2
39+
};
40+
let z = {
41+
c: 3
42+
};
43+
return { x, y, z };
44+
}
45+
}
46+
}
47+
`
48+
});
49+
50+

tests/cases/fourslash/formattingObjectLiteralOpenCurlyNewline.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,19 @@ var clear =
2626
};
2727
`
2828
);
29+
30+
format.setOption("indentMultiLineObjectLiteralBeginningOnBlankLine", true);
31+
format.document();
32+
verify.currentFileContentIs(
33+
`
34+
var clear =
35+
{
36+
outerKey:
37+
{
38+
innerKey: 1,
39+
innerKey2:
40+
2
41+
}
42+
};
43+
`
44+
);

tests/cases/fourslash/formattingObjectLiteralOpenCurlySingleLine.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,3 @@ let obj2 =
2020
{ y: 10 };
2121
`
2222
);
23-

0 commit comments

Comments
 (0)