Fixes emit for module/enum and single-line arrow functions.
This commit is contained in:
parent
9bbbb33df5
commit
25998ae865
6 changed files with 125 additions and 68 deletions
|
@ -452,11 +452,15 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange) {
|
||||
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange, options?: { startOnNewLine?: boolean; }) {
|
||||
const node = <IfStatement>createNode(SyntaxKind.IfStatement, location);
|
||||
node.expression = expression;
|
||||
node.thenStatement = thenStatement;
|
||||
node.elseStatement = elseStatement;
|
||||
if (options && options.startOnNewLine) {
|
||||
node.startsOnNewLine = true;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
|
@ -1411,30 +1411,41 @@ const _super = (function (geti, seti) {
|
|||
}
|
||||
|
||||
function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) {
|
||||
// We must emit a function body as a single-line body in the following case:
|
||||
// * The body has NodeEmitFlags.SingleLine specified.
|
||||
|
||||
// We must emit a function body as a multi-line body in the following cases:
|
||||
// * The body is explicitly marked as multi-line.
|
||||
// * A non-synthesized body's start and end position are on different lines.
|
||||
// * Any statement in the body starts on a new line.
|
||||
|
||||
if (getNodeEmitFlags(body) & NodeEmitFlags.SingleLine) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (body.multiLine) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const originalNode = getOriginalNode(parentNode);
|
||||
if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode)) {
|
||||
const body = originalNode.body;
|
||||
if (isBlock(body)) {
|
||||
if (rangeEndIsOnSameLineAsRangeStart(body, body)) {
|
||||
for (const statement of body.statements) {
|
||||
if (synthesizedNodeStartsOnNewLine(statement)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return rangeEndIsOnSameLineAsRangeStart((<ArrowFunction>originalNode).equalsGreaterThanToken, originalNode.body);
|
||||
}
|
||||
if (!nodeIsSynthesized(body) && !rangeIsOnSingleLine(body, currentSourceFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (shouldWriteLeadingLineTerminator(body, body.statements, ListFormat.PreserveLines)
|
||||
|| shouldWriteClosingLineTerminator(body, body.statements, ListFormat.PreserveLines)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let previousStatement: Statement;
|
||||
for (const statement of body.statements) {
|
||||
if (shouldWriteSeparatingLineTerminator(previousStatement, statement, ListFormat.PreserveLines)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
previousStatement = statement;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitBlockFunctionBody(parentNode: Node, body: Block) {
|
||||
|
@ -1457,7 +1468,7 @@ const _super = (function (geti, seti) {
|
|||
|
||||
const endingLine = writer.getLine();
|
||||
emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine);
|
||||
emitLeadingComments(collapseTextRange(body.statements, TextRangeCollapse.CollapseToEnd));
|
||||
emitLeadingComments(collapseRangeToEnd(body.statements));
|
||||
decreaseIndent();
|
||||
}
|
||||
|
||||
|
@ -1738,7 +1749,7 @@ const _super = (function (geti, seti) {
|
|||
}
|
||||
|
||||
function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray<Statement>) {
|
||||
if (statements.length === 1 && rangeStartPositionsAreOnSameLine(parentNode, statements[0])) {
|
||||
if (statements.length === 1 && rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile)) {
|
||||
write(" ");
|
||||
emit(statements[0]);
|
||||
}
|
||||
|
@ -1778,7 +1789,7 @@ const _super = (function (geti, seti) {
|
|||
// }
|
||||
// "comment1" is not considered to be leading comment for node.initializer
|
||||
// but rather a trailing comment on the previous node.
|
||||
emitLeadingComments(node.initializer, getTrailingComments(collapseTextRange(node.initializer, TextRangeCollapse.CollapseToStart)));
|
||||
emitLeadingComments(node.initializer, getTrailingComments(collapseRangeToStart(node.initializer)));
|
||||
emitExpression(node.initializer);
|
||||
}
|
||||
|
||||
|
@ -2236,13 +2247,13 @@ const _super = (function (geti, seti) {
|
|||
|
||||
const firstChild = children[0];
|
||||
if (firstChild === undefined) {
|
||||
return !positionsAreOnSameLine(getStartPos(parentNode), parentNode.end);
|
||||
return !rangeIsOnSingleLine(parentNode, currentSourceFile);
|
||||
}
|
||||
else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) {
|
||||
return synthesizedNodeStartsOnNewLine(firstChild, format);
|
||||
}
|
||||
else {
|
||||
return !rangeStartPositionsAreOnSameLine(parentNode, firstChild);
|
||||
return !rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2262,7 +2273,7 @@ const _super = (function (geti, seti) {
|
|||
return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format);
|
||||
}
|
||||
else {
|
||||
return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode);
|
||||
return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2281,13 +2292,13 @@ const _super = (function (geti, seti) {
|
|||
|
||||
const lastChild = lastOrUndefined(children);
|
||||
if (lastChild === undefined) {
|
||||
return !positionsAreOnSameLine(getStartPos(parentNode), parentNode.end);
|
||||
return !rangeIsOnSingleLine(parentNode, currentSourceFile);
|
||||
}
|
||||
else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) {
|
||||
return synthesizedNodeStartsOnNewLine(lastChild, format);
|
||||
}
|
||||
else {
|
||||
return !rangeEndPositionsAreOnSameLine(parentNode, lastChild);
|
||||
return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2304,30 +2315,10 @@ const _super = (function (geti, seti) {
|
|||
|
||||
return startsOnNewLine;
|
||||
}
|
||||
|
||||
return (format & ListFormat.PreferNewLine) !== 0;
|
||||
}
|
||||
|
||||
function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: TextRange) {
|
||||
return positionsAreOnSameLine(getStartPos(range1), getStartPos(range2));
|
||||
}
|
||||
|
||||
function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRange) {
|
||||
return positionsAreOnSameLine(range1.end, range2.end);
|
||||
}
|
||||
|
||||
function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange) {
|
||||
return positionsAreOnSameLine(range1.end, getStartPos(range2));
|
||||
}
|
||||
|
||||
function positionsAreOnSameLine(pos1: number, pos2: number) {
|
||||
return pos1 === pos2 ||
|
||||
getLineOfLocalPosition(currentSourceFile, pos1) === getLineOfLocalPosition(currentSourceFile, pos2);
|
||||
}
|
||||
|
||||
function getStartPos(range: TextRange) {
|
||||
return range.pos === -1 ? -1 : skipTrivia(currentText, range.pos);
|
||||
}
|
||||
|
||||
function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
|
||||
parent = skipSynthesizedParentheses(parent);
|
||||
node1 = skipSynthesizedParentheses(node1);
|
||||
|
@ -2341,7 +2332,7 @@ const _super = (function (geti, seti) {
|
|||
return !nodeIsSynthesized(parent)
|
||||
&& !nodeIsSynthesized(node1)
|
||||
&& !nodeIsSynthesized(node2)
|
||||
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2);
|
||||
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile);
|
||||
}
|
||||
|
||||
function skipSynthesizedParentheses(node: Node) {
|
||||
|
@ -2381,7 +2372,7 @@ const _super = (function (geti, seti) {
|
|||
function isSingleLineEmptyBlock(block: Block) {
|
||||
return !block.multiLine
|
||||
&& block.statements.length === 0
|
||||
&& rangeEndIsOnSameLineAsRangeStart(block, block);
|
||||
&& rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile);
|
||||
}
|
||||
|
||||
function getNotEmittedParent(node: Node): Node {
|
||||
|
|
|
@ -994,8 +994,8 @@ namespace ts {
|
|||
|
||||
const start = new Date().getTime();
|
||||
|
||||
// TODO(rbuckton): remove USE_TRANSFORMS condition when we switch to transforms permenantly.
|
||||
if (Boolean(sys.getEnvironmentVariable("USE_TRANSFORMS"))) {
|
||||
// TODO(rbuckton): remove USE_TRANSFORMS condition when we switch to transforms permanently.
|
||||
if (/^(y(es)?|t(rue|ransforms?)?|1|\+)$/i.test(sys.getEnvironmentVariable("USE_TRANSFORMS"))) {
|
||||
options.experimentalTransforms = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -564,7 +564,10 @@ namespace ts {
|
|||
)
|
||||
]),
|
||||
NodeEmitFlags.SingleLine
|
||||
)
|
||||
),
|
||||
/*elseStatement*/ undefined,
|
||||
/*location*/ undefined,
|
||||
{ startOnNewLine: true }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -841,25 +844,62 @@ namespace ts {
|
|||
* @param node A function-like node.
|
||||
*/
|
||||
function transformFunctionBody(node: FunctionLikeDeclaration) {
|
||||
let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
|
||||
let singleLine = false; // indicates whether the block *may* be emitted as a single line
|
||||
|
||||
const statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
addCaptureThisForNodeIfNeeded(statements, node);
|
||||
addDefaultValueAssignmentsIfNeeded(statements, node);
|
||||
addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false);
|
||||
|
||||
// If we added any generated statements, this must be a multi-line block.
|
||||
if (!multiLine && statements.length > 0) {
|
||||
multiLine = true;
|
||||
}
|
||||
|
||||
const body = node.body;
|
||||
if (isBlock(body)) {
|
||||
addRange(statements, visitNodes(body.statements, visitor, isStatement));
|
||||
|
||||
// If the original body was a multi-line block, this must be a multi-line block.
|
||||
if (!multiLine && body.multiLine) {
|
||||
multiLine = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.assert(node.kind === SyntaxKind.ArrowFunction);
|
||||
|
||||
const equalsGreaterThanToken = (<ArrowFunction>node).equalsGreaterThanToken;
|
||||
if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
|
||||
if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
|
||||
singleLine = true;
|
||||
}
|
||||
else {
|
||||
multiLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
const expression = visitNode(body, visitor, isExpression);
|
||||
if (expression) {
|
||||
statements.push(createReturn(expression, /*location*/ body));
|
||||
statements.push(createReturn(expression));
|
||||
}
|
||||
}
|
||||
|
||||
addRange(statements, endLexicalEnvironment());
|
||||
return createBlock(statements, node.body);
|
||||
const lexicalEnvironment = endLexicalEnvironment();
|
||||
addRange(statements, lexicalEnvironment);
|
||||
|
||||
// If we added any final generated statements, this must be a multi-line block
|
||||
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
|
||||
multiLine = true;
|
||||
}
|
||||
|
||||
const block = createBlock(statements, node.body, multiLine);
|
||||
if (!multiLine && singleLine) {
|
||||
setNodeEmitFlags(block, NodeEmitFlags.SingleLine);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2228,7 +2228,7 @@ namespace ts {
|
|||
startLexicalEnvironment();
|
||||
addNodes(statements, map(node.members, transformEnumMember));
|
||||
addNodes(statements, endLexicalEnvironment());
|
||||
return createBlock(statements);
|
||||
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2455,7 +2455,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
addNodes(statements, endLexicalEnvironment());
|
||||
return createBlock(statements);
|
||||
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2925,19 +2925,41 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
export const enum TextRangeCollapse {
|
||||
CollapseToStart,
|
||||
CollapseToEnd,
|
||||
export function collapseRangeToStart(range: TextRange) {
|
||||
return range.pos === range.end ? range : { pos: range.pos, end: range.pos };
|
||||
}
|
||||
|
||||
export function collapseTextRange(range: TextRange, collapse: TextRangeCollapse) {
|
||||
if (range.pos === range.end) {
|
||||
return range;
|
||||
}
|
||||
export function collapseRangeToEnd(range: TextRange) {
|
||||
return range.pos === range.end ? range : { pos: range.end, end: range.end };
|
||||
}
|
||||
|
||||
return collapse === TextRangeCollapse.CollapseToStart
|
||||
? { pos: range.pos, end: range.pos }
|
||||
: { pos: range.end, end: range.end };
|
||||
export function rangeIsOnSingleLine(range: TextRange, sourceFile: SourceFile) {
|
||||
return rangeStartIsOnSameLineAsRangeEnd(range, range, sourceFile);
|
||||
}
|
||||
|
||||
export function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
|
||||
return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile), getStartPositionOfRange(range2, sourceFile), sourceFile);
|
||||
}
|
||||
|
||||
export function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
|
||||
return positionsAreOnSameLine(range1.end, range2.end, sourceFile);
|
||||
}
|
||||
|
||||
export function rangeStartIsOnSameLineAsRangeEnd(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
|
||||
return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile), range2.end, sourceFile);
|
||||
}
|
||||
|
||||
export function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
|
||||
return positionsAreOnSameLine(range1.end, getStartPositionOfRange(range2, sourceFile), sourceFile);
|
||||
}
|
||||
|
||||
export function positionsAreOnSameLine(pos1: number, pos2: number, sourceFile: SourceFile) {
|
||||
return pos1 === pos2 ||
|
||||
getLineOfLocalPosition(sourceFile, pos1) === getLineOfLocalPosition(sourceFile, pos2);
|
||||
}
|
||||
|
||||
export function getStartPositionOfRange(range: TextRange, sourceFile: SourceFile) {
|
||||
return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos);
|
||||
}
|
||||
|
||||
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver) {
|
||||
|
|
Loading…
Reference in a new issue