diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7256d179505..82a8ab1f128 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4278,11 +4278,13 @@ namespace ts { return rangeIsOnSingleLine(parentNode, currentSourceFile!) ? 0 : 1; } else if (!positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(firstChild) && firstChild.parent === parentNode) { - let lines = getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(firstChild.pos, currentSourceFile!, /*includeComments*/ true); - if (lines === 0) { - lines = getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(firstChild.pos, currentSourceFile!, /*includeComments*/ false); + if (preserveNewlines) { + const lines = getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(firstChild.pos, currentSourceFile!, /*includeComments*/ true); + return lines === 0 + ? getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(firstChild.pos, currentSourceFile!, /*includeComments*/ false) + : lines; } - return printerOptions.preserveNewlines ? lines : Math.min(lines, 1); + return rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile!) ? 0 : 1; } else if (synthesizedNodeStartsOnNewLine(firstChild, format)) { return 1; @@ -4297,8 +4299,8 @@ namespace ts { return 0; } else if (!nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode) && previousNode.parent === nextNode.parent) { - const lines = getEffectiveLinesBetweenRanges(previousNode, nextNode, getLinesBetweenRangeEndAndRangeStart); - return printerOptions.preserveNewlines ? lines : Math.min(lines, 1); + const lines = getEffectiveLinesBetweenRanges(previousNode, nextNode); + return preserveNewlines ? lines : Math.min(lines, 1); } else if (synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format)) { return 1; @@ -4322,7 +4324,7 @@ namespace ts { } else if (!positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(lastChild) && lastChild.parent === parentNode) { const lines = getLinesBetweenRangeEndPositions(lastChild, parentNode, currentSourceFile!); - return printerOptions.preserveNewlines ? lines : Math.min(lines, 1); + return preserveNewlines ? lines : Math.min(lines, 1); } else if (synthesizedNodeStartsOnNewLine(lastChild, format)) { return 1; @@ -4334,26 +4336,28 @@ namespace ts { return 0; } - function getEffectiveLinesBetweenRanges( - node1: TextRange, - node2: TextRange, - getLinesBetweenPositions: (range1: TextRange, range2: TextRange, sourceFile: SourceFile, includeComments: boolean) => number - ) { - // We start by measuring the line difference from parentNode's start to node2's comments start, - // so that this is counted as a one line difference, not two: + function getEffectiveLinesBetweenRanges(node1: TextRange, node2: TextRange) { + // If 'preserveNewlines' is disabled, skip the more accurate check that might require + // querying for source position twice. + if (!preserveNewlines) { + return getLinesBetweenRangeEndAndRangeStart(node1, node2, currentSourceFile!, /*includeComments*/ false); + } + // We start by measuring the line difference from node1's end to node2's comments start, + // so that this is counted as a one-line difference, not two: // // node1; // // NODE2 COMMENT // node2; - const lines = getLinesBetweenPositions(node1, node2, currentSourceFile!, /*includeComments*/ true); + const lines = getLinesBetweenRangeEndAndRangeStart(node1, node2, currentSourceFile!, /*includeComments*/ true); if (lines === 0) { // However, if the line difference considering node2's comments was 0, we might have this: // // node1; // NODE2 COMMENT // node2; // - // in which case we should be ignoring node2's comment. - return getLinesBetweenPositions(node1, node2, currentSourceFile!, /*includeComments*/ false); + // in which case we should be ignoring node2's comment, so this too is counted as + // a one-line difference, not zero. + return getLinesBetweenRangeEndAndRangeStart(node1, node2, currentSourceFile!, /*includeComments*/ false); } return lines; } @@ -4386,7 +4390,7 @@ namespace ts { } if (!nodeIsSynthesized(parent) && !nodeIsSynthesized(node1) && !nodeIsSynthesized(node2)) { - const lines = getEffectiveLinesBetweenRanges(node1, node2, getLinesBetweenRangeEndAndRangeStart); + const lines = getEffectiveLinesBetweenRanges(node1, node2); return preserveNewlines ? lines : Math.min(lines, 1); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 085670d31b8..dc9dc0db524 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4703,7 +4703,7 @@ namespace ts { export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, sourceFile: SourceFile, includeComments?: boolean) { const startPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments); - const prevPos = getPreviousNonWhitespacePosition(pos, sourceFile); + const prevPos = getPreviousNonWhitespacePosition(startPos, sourceFile); return getLineOfLocalPosition(sourceFile, startPos) - getLineOfLocalPosition(sourceFile, prevPos || 0); }