Skip to content

Commit 25998ae

Browse files
committed
Fixes emit for module/enum and single-line arrow functions.
1 parent 9bbbb33 commit 25998ae

6 files changed

Lines changed: 123 additions & 66 deletions

File tree

src/compiler/factory.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,15 @@ namespace ts {
452452
return node;
453453
}
454454

455-
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange) {
455+
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange, options?: { startOnNewLine?: boolean; }) {
456456
const node = <IfStatement>createNode(SyntaxKind.IfStatement, location);
457457
node.expression = expression;
458458
node.thenStatement = thenStatement;
459459
node.elseStatement = elseStatement;
460+
if (options && options.startOnNewLine) {
461+
node.startsOnNewLine = true;
462+
}
463+
460464
return node;
461465
}
462466

src/compiler/printer.ts

Lines changed: 38 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,30 +1411,41 @@ const _super = (function (geti, seti) {
14111411
}
14121412

14131413
function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) {
1414+
// We must emit a function body as a single-line body in the following case:
1415+
// * The body has NodeEmitFlags.SingleLine specified.
1416+
1417+
// We must emit a function body as a multi-line body in the following cases:
1418+
// * The body is explicitly marked as multi-line.
1419+
// * A non-synthesized body's start and end position are on different lines.
1420+
// * Any statement in the body starts on a new line.
1421+
1422+
if (getNodeEmitFlags(body) & NodeEmitFlags.SingleLine) {
1423+
return true;
1424+
}
1425+
14141426
if (body.multiLine) {
14151427
return false;
14161428
}
14171429

1418-
const originalNode = getOriginalNode(parentNode);
1419-
if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode)) {
1420-
const body = originalNode.body;
1421-
if (isBlock(body)) {
1422-
if (rangeEndIsOnSameLineAsRangeStart(body, body)) {
1423-
for (const statement of body.statements) {
1424-
if (synthesizedNodeStartsOnNewLine(statement)) {
1425-
return false;
1426-
}
1427-
}
1430+
if (!nodeIsSynthesized(body) && !rangeIsOnSingleLine(body, currentSourceFile)) {
1431+
return false;
1432+
}
14281433

1429-
return true;
1430-
}
1431-
}
1432-
else {
1433-
return rangeEndIsOnSameLineAsRangeStart((<ArrowFunction>originalNode).equalsGreaterThanToken, originalNode.body);
1434+
if (shouldWriteLeadingLineTerminator(body, body.statements, ListFormat.PreserveLines)
1435+
|| shouldWriteClosingLineTerminator(body, body.statements, ListFormat.PreserveLines)) {
1436+
return false;
1437+
}
1438+
1439+
let previousStatement: Statement;
1440+
for (const statement of body.statements) {
1441+
if (shouldWriteSeparatingLineTerminator(previousStatement, statement, ListFormat.PreserveLines)) {
1442+
return false;
14341443
}
1444+
1445+
previousStatement = statement;
14351446
}
14361447

1437-
return false;
1448+
return true;
14381449
}
14391450

14401451
function emitBlockFunctionBody(parentNode: Node, body: Block) {
@@ -1457,7 +1468,7 @@ const _super = (function (geti, seti) {
14571468

14581469
const endingLine = writer.getLine();
14591470
emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine);
1460-
emitLeadingComments(collapseTextRange(body.statements, TextRangeCollapse.CollapseToEnd));
1471+
emitLeadingComments(collapseRangeToEnd(body.statements));
14611472
decreaseIndent();
14621473
}
14631474

@@ -1738,7 +1749,7 @@ const _super = (function (geti, seti) {
17381749
}
17391750

17401751
function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray<Statement>) {
1741-
if (statements.length === 1 && rangeStartPositionsAreOnSameLine(parentNode, statements[0])) {
1752+
if (statements.length === 1 && rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile)) {
17421753
write(" ");
17431754
emit(statements[0]);
17441755
}
@@ -1778,7 +1789,7 @@ const _super = (function (geti, seti) {
17781789
// }
17791790
// "comment1" is not considered to be leading comment for node.initializer
17801791
// but rather a trailing comment on the previous node.
1781-
emitLeadingComments(node.initializer, getTrailingComments(collapseTextRange(node.initializer, TextRangeCollapse.CollapseToStart)));
1792+
emitLeadingComments(node.initializer, getTrailingComments(collapseRangeToStart(node.initializer)));
17821793
emitExpression(node.initializer);
17831794
}
17841795

@@ -2236,13 +2247,13 @@ const _super = (function (geti, seti) {
22362247

22372248
const firstChild = children[0];
22382249
if (firstChild === undefined) {
2239-
return !positionsAreOnSameLine(getStartPos(parentNode), parentNode.end);
2250+
return !rangeIsOnSingleLine(parentNode, currentSourceFile);
22402251
}
22412252
else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) {
22422253
return synthesizedNodeStartsOnNewLine(firstChild, format);
22432254
}
22442255
else {
2245-
return !rangeStartPositionsAreOnSameLine(parentNode, firstChild);
2256+
return !rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile);
22462257
}
22472258
}
22482259
else {
@@ -2262,7 +2273,7 @@ const _super = (function (geti, seti) {
22622273
return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format);
22632274
}
22642275
else {
2265-
return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode);
2276+
return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile);
22662277
}
22672278
}
22682279
else {
@@ -2281,13 +2292,13 @@ const _super = (function (geti, seti) {
22812292

22822293
const lastChild = lastOrUndefined(children);
22832294
if (lastChild === undefined) {
2284-
return !positionsAreOnSameLine(getStartPos(parentNode), parentNode.end);
2295+
return !rangeIsOnSingleLine(parentNode, currentSourceFile);
22852296
}
22862297
else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) {
22872298
return synthesizedNodeStartsOnNewLine(lastChild, format);
22882299
}
22892300
else {
2290-
return !rangeEndPositionsAreOnSameLine(parentNode, lastChild);
2301+
return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile);
22912302
}
22922303
}
22932304
else {
@@ -2304,28 +2315,8 @@ const _super = (function (geti, seti) {
23042315

23052316
return startsOnNewLine;
23062317
}
2307-
return (format & ListFormat.PreferNewLine) !== 0;
2308-
}
2309-
2310-
function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: TextRange) {
2311-
return positionsAreOnSameLine(getStartPos(range1), getStartPos(range2));
2312-
}
23132318

2314-
function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRange) {
2315-
return positionsAreOnSameLine(range1.end, range2.end);
2316-
}
2317-
2318-
function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange) {
2319-
return positionsAreOnSameLine(range1.end, getStartPos(range2));
2320-
}
2321-
2322-
function positionsAreOnSameLine(pos1: number, pos2: number) {
2323-
return pos1 === pos2 ||
2324-
getLineOfLocalPosition(currentSourceFile, pos1) === getLineOfLocalPosition(currentSourceFile, pos2);
2325-
}
2326-
2327-
function getStartPos(range: TextRange) {
2328-
return range.pos === -1 ? -1 : skipTrivia(currentText, range.pos);
2319+
return (format & ListFormat.PreferNewLine) !== 0;
23292320
}
23302321

23312322
function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
@@ -2341,7 +2332,7 @@ const _super = (function (geti, seti) {
23412332
return !nodeIsSynthesized(parent)
23422333
&& !nodeIsSynthesized(node1)
23432334
&& !nodeIsSynthesized(node2)
2344-
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2);
2335+
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile);
23452336
}
23462337

23472338
function skipSynthesizedParentheses(node: Node) {
@@ -2381,7 +2372,7 @@ const _super = (function (geti, seti) {
23812372
function isSingleLineEmptyBlock(block: Block) {
23822373
return !block.multiLine
23832374
&& block.statements.length === 0
2384-
&& rangeEndIsOnSameLineAsRangeStart(block, block);
2375+
&& rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile);
23852376
}
23862377

23872378
function getNotEmittedParent(node: Node): Node {

src/compiler/program.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -994,8 +994,8 @@ namespace ts {
994994

995995
const start = new Date().getTime();
996996

997-
// TODO(rbuckton): remove USE_TRANSFORMS condition when we switch to transforms permenantly.
998-
if (Boolean(sys.getEnvironmentVariable("USE_TRANSFORMS"))) {
997+
// TODO(rbuckton): remove USE_TRANSFORMS condition when we switch to transforms permanently.
998+
if (/^(y(es)?|t(rue|ransforms?)?|1|\+)$/i.test(sys.getEnvironmentVariable("USE_TRANSFORMS"))) {
999999
options.experimentalTransforms = true;
10001000
}
10011001

src/compiler/transformers/es6.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,10 @@ namespace ts {
564564
)
565565
]),
566566
NodeEmitFlags.SingleLine
567-
)
567+
),
568+
/*elseStatement*/ undefined,
569+
/*location*/ undefined,
570+
{ startOnNewLine: true }
568571
)
569572
);
570573
}
@@ -841,25 +844,62 @@ namespace ts {
841844
* @param node A function-like node.
842845
*/
843846
function transformFunctionBody(node: FunctionLikeDeclaration) {
847+
let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
848+
let singleLine = false; // indicates whether the block *may* be emitted as a single line
849+
844850
const statements: Statement[] = [];
845851
startLexicalEnvironment();
846852
addCaptureThisForNodeIfNeeded(statements, node);
847853
addDefaultValueAssignmentsIfNeeded(statements, node);
848854
addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false);
849855

856+
// If we added any generated statements, this must be a multi-line block.
857+
if (!multiLine && statements.length > 0) {
858+
multiLine = true;
859+
}
860+
850861
const body = node.body;
851862
if (isBlock(body)) {
852863
addRange(statements, visitNodes(body.statements, visitor, isStatement));
864+
865+
// If the original body was a multi-line block, this must be a multi-line block.
866+
if (!multiLine && body.multiLine) {
867+
multiLine = true;
868+
}
853869
}
854870
else {
871+
Debug.assert(node.kind === SyntaxKind.ArrowFunction);
872+
873+
const equalsGreaterThanToken = (<ArrowFunction>node).equalsGreaterThanToken;
874+
if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
875+
if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
876+
singleLine = true;
877+
}
878+
else {
879+
multiLine = true;
880+
}
881+
}
882+
855883
const expression = visitNode(body, visitor, isExpression);
856884
if (expression) {
857-
statements.push(createReturn(expression, /*location*/ body));
885+
statements.push(createReturn(expression));
858886
}
859887
}
860888

861-
addRange(statements, endLexicalEnvironment());
862-
return createBlock(statements, node.body);
889+
const lexicalEnvironment = endLexicalEnvironment();
890+
addRange(statements, lexicalEnvironment);
891+
892+
// If we added any final generated statements, this must be a multi-line block
893+
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
894+
multiLine = true;
895+
}
896+
897+
const block = createBlock(statements, node.body, multiLine);
898+
if (!multiLine && singleLine) {
899+
setNodeEmitFlags(block, NodeEmitFlags.SingleLine);
900+
}
901+
902+
return block;
863903
}
864904

865905
/**

src/compiler/transformers/ts.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2228,7 +2228,7 @@ namespace ts {
22282228
startLexicalEnvironment();
22292229
addNodes(statements, map(node.members, transformEnumMember));
22302230
addNodes(statements, endLexicalEnvironment());
2231-
return createBlock(statements);
2231+
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
22322232
}
22332233

22342234
/**
@@ -2455,7 +2455,7 @@ namespace ts {
24552455
}
24562456

24572457
addNodes(statements, endLexicalEnvironment());
2458-
return createBlock(statements);
2458+
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
24592459
}
24602460

24612461
/**

src/compiler/utilities.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,19 +2925,41 @@ namespace ts {
29252925
}
29262926
}
29272927

2928-
export const enum TextRangeCollapse {
2929-
CollapseToStart,
2930-
CollapseToEnd,
2928+
export function collapseRangeToStart(range: TextRange) {
2929+
return range.pos === range.end ? range : { pos: range.pos, end: range.pos };
29312930
}
29322931

2933-
export function collapseTextRange(range: TextRange, collapse: TextRangeCollapse) {
2934-
if (range.pos === range.end) {
2935-
return range;
2936-
}
2932+
export function collapseRangeToEnd(range: TextRange) {
2933+
return range.pos === range.end ? range : { pos: range.end, end: range.end };
2934+
}
2935+
2936+
export function rangeIsOnSingleLine(range: TextRange, sourceFile: SourceFile) {
2937+
return rangeStartIsOnSameLineAsRangeEnd(range, range, sourceFile);
2938+
}
2939+
2940+
export function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
2941+
return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile), getStartPositionOfRange(range2, sourceFile), sourceFile);
2942+
}
2943+
2944+
export function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
2945+
return positionsAreOnSameLine(range1.end, range2.end, sourceFile);
2946+
}
2947+
2948+
export function rangeStartIsOnSameLineAsRangeEnd(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
2949+
return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile), range2.end, sourceFile);
2950+
}
2951+
2952+
export function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
2953+
return positionsAreOnSameLine(range1.end, getStartPositionOfRange(range2, sourceFile), sourceFile);
2954+
}
2955+
2956+
export function positionsAreOnSameLine(pos1: number, pos2: number, sourceFile: SourceFile) {
2957+
return pos1 === pos2 ||
2958+
getLineOfLocalPosition(sourceFile, pos1) === getLineOfLocalPosition(sourceFile, pos2);
2959+
}
29372960

2938-
return collapse === TextRangeCollapse.CollapseToStart
2939-
? { pos: range.pos, end: range.pos }
2940-
: { pos: range.end, end: range.end };
2961+
export function getStartPositionOfRange(range: TextRange, sourceFile: SourceFile) {
2962+
return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos);
29412963
}
29422964

29432965
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver) {

0 commit comments

Comments
 (0)