Fix preserveNewlines printer option when a list child has the same start or end as its parent (#37846)

* Fix preserveNewlines printer option when a list child has the same start or end as its parent

* Fix leading line separator calculation and JSX bug
This commit is contained in:
Andrew Branch 2020-04-21 15:34:30 -07:00 committed by GitHub
parent d571a09cf8
commit 7d4fc73331
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 16 deletions

View File

@ -2366,16 +2366,10 @@ namespace ts {
function emitParenthesizedExpression(node: ParenthesizedExpression) {
const openParenPos = emitTokenWithComment(SyntaxKind.OpenParenToken, node.pos, writePunctuation, node);
const leadingNewlines = preserveSourceNewlines && getLeadingLineTerminatorCount(node, [node.expression], ListFormat.None);
if (leadingNewlines) {
writeLinesAndIndent(leadingNewlines, /*writeLinesIfNotIndenting*/ false);
}
const indented = writeLineSeparatorsAndIndentBefore(node.expression, node);
emitExpression(node.expression);
const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(node, [node.expression], ListFormat.None);
if (trailingNewlines) {
writeLine(trailingNewlines);
}
decreaseIndentIf(leadingNewlines);
writeLineSeparatorsAfter(node.expression, node);
decreaseIndentIf(indented);
emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression ? node.expression.end : openParenPos, writePunctuation, node);
}
@ -3293,12 +3287,15 @@ namespace ts {
writePunctuation("<");
if (isJsxOpeningElement(node)) {
const indented = writeLineSeparatorsAndIndentBefore(node.tagName, node);
emitJsxTagName(node.tagName);
emitTypeArguments(node, node.typeArguments);
if (node.attributes.properties && node.attributes.properties.length > 0) {
writeSpace();
}
emit(node.attributes);
writeLineSeparatorsAfter(node.attributes, node);
decreaseIndentIf(indented);
}
writePunctuation(">");
@ -4302,6 +4299,7 @@ namespace ts {
return getEffectiveLines(
includeComments => getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(
firstChild.pos,
parentNode.pos,
currentSourceFile!,
includeComments));
}
@ -4359,6 +4357,7 @@ namespace ts {
return getEffectiveLines(
includeComments => getLinesBetweenPositionAndNextNonWhitespaceCharacter(
lastChild.end,
parentNode.end,
currentSourceFile!,
includeComments));
}
@ -4398,6 +4397,21 @@ namespace ts {
return lines;
}
function writeLineSeparatorsAndIndentBefore(node: Node, parent: Node): boolean {
const leadingNewlines = preserveSourceNewlines && getLeadingLineTerminatorCount(parent, [node], ListFormat.None);
if (leadingNewlines) {
writeLinesAndIndent(leadingNewlines, /*writeLinesIfNotIndenting*/ false);
}
return !!leadingNewlines;
}
function writeLineSeparatorsAfter(node: Node, parent: Node) {
const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(parent, [node], ListFormat.None);
if (trailingNewlines) {
writeLine(trailingNewlines);
}
}
function synthesizedNodeStartsOnNewLine(node: Node, format: ListFormat) {
if (nodeIsSynthesized(node)) {
const startsOnNewLine = getStartsOnNewLine(node);

View File

@ -4780,19 +4780,19 @@ namespace ts {
return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments);
}
export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, sourceFile: SourceFile, includeComments?: boolean) {
export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) {
const startPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments);
const prevPos = getPreviousNonWhitespacePosition(startPos, sourceFile);
return getLinesBetweenPositions(sourceFile, prevPos || 0, startPos);
const prevPos = getPreviousNonWhitespacePosition(startPos, stopPos, sourceFile);
return getLinesBetweenPositions(sourceFile, prevPos ?? stopPos, startPos);
}
export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number, sourceFile: SourceFile, includeComments?: boolean) {
export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) {
const nextPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments);
return getLinesBetweenPositions(sourceFile, pos, nextPos);
return getLinesBetweenPositions(sourceFile, pos, Math.min(stopPos, nextPos));
}
function getPreviousNonWhitespacePosition(pos: number, sourceFile: SourceFile) {
while (pos-- > 0) {
function getPreviousNonWhitespacePosition(pos: number, stopPos = 0, sourceFile: SourceFile) {
while (pos-- > stopPos) {
if (!isWhiteSpaceLike(sourceFile.text.charCodeAt(pos))) {
return pos;
}

View File

@ -0,0 +1,29 @@
// #37813
/// <reference path="fourslash.ts" />
////function foo() {
//// /*1*/var x: number
////
//// x = 10;
//// return x;/*2*/
////}
goTo.select("1", "2");
edit.applyRefactor({
refactorName: "Extract Symbol",
actionName: "function_scope_1",
actionDescription: "Extract to function in global scope",
newContent:
`function foo() {
return /*RENAME*/newFunction();
}
function newFunction() {
var x: number;
x = 10;
return x;
}
`
});