Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix preserveSourceNewlines sibling node comparison (fixes extra newlines in organize imports) #42630

Merged
merged 40 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
cb05c28
Update package-lock.json
typescript-bot Nov 20, 2020
2f4d4c1
Update package-lock.json
typescript-bot Nov 23, 2020
b94544a
Update package-lock.json
typescript-bot Nov 26, 2020
60d63dd
Update package-lock.json
typescript-bot Nov 27, 2020
3d45ac0
Update package-lock.json
typescript-bot Dec 1, 2020
7dda7e3
Update package-lock.json
typescript-bot Dec 2, 2020
24f0d6b
Update package-lock.json
typescript-bot Dec 3, 2020
a9a8cbb
Update package-lock.json
typescript-bot Dec 4, 2020
9e42a69
Update package-lock.json
typescript-bot Dec 5, 2020
12cc980
Update package-lock.json
typescript-bot Dec 6, 2020
a43ec41
Update package-lock.json
typescript-bot Dec 9, 2020
3a6a36a
Update package-lock.json
typescript-bot Dec 11, 2020
202873a
Update package-lock.json
typescript-bot Dec 13, 2020
78ea60a
Update package-lock.json
typescript-bot Dec 16, 2020
2b0578d
Update package-lock.json
typescript-bot Dec 17, 2020
e7c832a
Update package-lock.json
typescript-bot Dec 19, 2020
62604bc
Update package-lock.json
typescript-bot Dec 21, 2020
4d807de
Update package-lock.json
typescript-bot Dec 23, 2020
dda079d
Update package-lock.json
typescript-bot Dec 24, 2020
9c121aa
Update package-lock.json
typescript-bot Dec 31, 2020
8777dc7
Update package-lock.json
typescript-bot Jan 1, 2021
f1aa0f9
Update package-lock.json
typescript-bot Jan 2, 2021
e4e4cf2
Update package-lock.json
typescript-bot Jan 5, 2021
dd79363
Update package-lock.json
typescript-bot Jan 6, 2021
2e93e31
Merge remote-tracking branch 'upstream/master'
armanio123 Jan 7, 2021
c709f17
More sophisticated check for source position comparability
andrewbranch Apr 8, 2020
67ad6b4
Merge branch 'master' of https://github.com/armanio123/TypeScript
armanio123 Jan 7, 2021
5215977
Fix organize imports by looking at the nodes positions
armanio123 Jan 7, 2021
7cdbdb9
Merge remote-tracking branch 'upstream/master' into FixOrganizeImports
armanio123 Jan 7, 2021
b51345e
Rollback formatting changes
armanio123 Jan 7, 2021
662ee6c
Added tests, fixed organizeImports algorithm
armanio123 Jan 12, 2021
aaf353e
Fix autoformatting again
armanio123 Jan 12, 2021
c40b579
Make sibling node comparison work for all lists
andrewbranch Jan 12, 2021
07930c2
Don’t run siblingNodePositionsAreComparable at all unless `preserveSo…
andrewbranch Feb 3, 2021
a368a48
Merge branch 'master' into FixOrganizeImports
andrewbranch Feb 3, 2021
de698f9
Move getNodeAtPosition back
andrewbranch Feb 3, 2021
77b1902
Optimize
andrewbranch Feb 5, 2021
bcbec24
Use node array index check instead of tree walk
andrewbranch Feb 9, 2021
af14aef
Revert unneeded change
andrewbranch Feb 9, 2021
a0bf137
Merge branch 'master' into FixOrganizeImports
andrewbranch Feb 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ namespace ts {
let containerEnd = -1;
let declarationListContainerEnd = -1;
let currentLineMap: readonly number[] | undefined;
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[] | undefined;
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number }[] | undefined;
let hasWrittenComment = false;
let commentsDisabled = !!printerOptions.removeComments;
const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment");
Expand Down Expand Up @@ -4469,15 +4469,15 @@ namespace ts {
// JsxText will be written with its leading whitespace, so don't add more manually.
return 0;
}
else if (!nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode) && (!previousNode.parent || !nextNode.parent || previousNode.parent === nextNode.parent)) {
if (preserveSourceNewlines && previousNode.parent && nextNode.parent) {
return getEffectiveLines(
includeComments => getLinesBetweenRangeEndAndRangeStart(
previousNode,
nextNode,
currentSourceFile!,
includeComments));
}
else if (preserveSourceNewlines && siblingNodePositionsAreComparable(previousNode, nextNode)) {
return getEffectiveLines(
includeComments => getLinesBetweenRangeEndAndRangeStart(
previousNode,
nextNode,
currentSourceFile!,
includeComments));
}
else if (!preserveSourceNewlines && !nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode)) {
return rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile!) ? 0 : 1;
}
else if (synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format)) {
Expand Down Expand Up @@ -5173,6 +5173,27 @@ namespace ts {

}

function siblingNodePositionsAreComparable(previousNode: Node, nextNode: Node) {
if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) {
return false;
}

if (nextNode.pos < previousNode.end) {
return false;
}

previousNode = getOriginalNode(previousNode);
nextNode = getOriginalNode(nextNode);
const parent = previousNode.parent;
if (!parent || parent !== nextNode.parent) {
return false;
}

const parentNodeArray = getContainingNodeArray(previousNode);
const prevNodeIndex = parentNodeArray?.indexOf(previousNode);
return prevNodeIndex !== undefined && prevNodeIndex > -1 && parentNodeArray!.indexOf(nextNode) === prevNodeIndex + 1;
}

function emitLeadingComments(pos: number, isEmittedNode: boolean) {
hasWrittenComment = false;

Expand Down
67 changes: 67 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7097,4 +7097,71 @@ namespace ts {
export function containsIgnoredPath(path: string) {
return some(ignoredPaths, p => stringContains(path, p));
}

export function getContainingNodeArray(node: Node): NodeArray<Node> | undefined {
if (!node.parent) return undefined;
switch (node.kind) {
case SyntaxKind.TypeParameter:
const { parent } = node as TypeParameterDeclaration;
return parent.kind === SyntaxKind.InferType ? undefined : parent.typeParameters;
case SyntaxKind.Parameter:
return (node as ParameterDeclaration).parent.parameters;
case SyntaxKind.TemplateLiteralTypeSpan:
return (node as TemplateLiteralTypeSpan).parent.templateSpans;
case SyntaxKind.TemplateSpan:
return (node as TemplateSpan).parent.templateSpans;
case SyntaxKind.Decorator:
return (node as Decorator).parent.decorators;
case SyntaxKind.HeritageClause:
return (node as HeritageClause).parent.heritageClauses;
}

const { parent } = node;
if (isJSDocTag(node)) {
return isJSDocTypeLiteral(node.parent) ? undefined : node.parent.tags;
}

switch (parent.kind) {
case SyntaxKind.TypeLiteral:
case SyntaxKind.InterfaceDeclaration:
return isTypeElement(node) ? (parent as TypeLiteralNode | InterfaceDeclaration).members : undefined;
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return (parent as UnionOrIntersectionTypeNode).types;
case SyntaxKind.TupleType:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.CommaListExpression:
case SyntaxKind.NamedImports:
case SyntaxKind.NamedExports:
return (parent as TupleTypeNode | ArrayLiteralExpression | CommaListExpression | NamedImports | NamedExports).elements;
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.JsxAttributes:
return (parent as ObjectLiteralExpressionBase<ObjectLiteralElement>).properties;
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return isTypeNode(node) ? (parent as CallExpression | NewExpression).typeArguments :
(parent as CallExpression | NewExpression).expression === node ? undefined :
(parent as CallExpression | NewExpression).arguments;
case SyntaxKind.JsxElement:
case SyntaxKind.JsxFragment:
return isJsxChild(node) ? (parent as JsxElement | JsxFragment).children : undefined;
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxSelfClosingElement:
return isTypeNode(node) ? (parent as JsxOpeningElement | JsxSelfClosingElement).typeArguments : undefined;
case SyntaxKind.Block:
case SyntaxKind.CaseClause:
case SyntaxKind.DefaultClause:
case SyntaxKind.ModuleBlock:
return (parent as Block | CaseOrDefaultClause | ModuleBlock).statements;
case SyntaxKind.CaseBlock:
return (parent as CaseBlock).clauses;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return isClassElement(node) ? (parent as ClassLikeDeclaration).members : undefined;
case SyntaxKind.EnumDeclaration:
return isEnumMember(node) ? (parent as EnumDeclaration).members : undefined;
case SyntaxKind.SourceFile:
return (parent as SourceFile).statements;
}
}
}
32 changes: 32 additions & 0 deletions tests/cases/fourslash/organizeImports1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/// <reference path="fourslash.ts" />

// Regression test for bug #41417

//// import {
//// d, d as D,
//// c,
//// c as C, b,
//// b as B, a
//// } from './foo';
//// import {
//// h, h as H,
//// g,
//// g as G, f,
//// f as F, e
//// } from './foo';
////
//// console.log(a, B, b, c, C, d, D);
//// console.log(e, f, F, g, G, H, h);

verify.organizeImports(
`import {
a, b,
b as B, c,
c as C, d, d as D, e, f,
f as F, g,
g as G, h, h as H
} from './foo';

console.log(a, B, b, c, C, d, D);
console.log(e, f, F, g, G, H, h);`
);
16 changes: 16 additions & 0 deletions tests/cases/fourslash/organizeImports2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />

// Regression test for bug #41417

//// import {
//// Foo
//// , Bar
//// } from "foo"
////
//// console.log(Foo, Bar);

verify.organizeImports(
`import { Bar, Foo } from "foo";

console.log(Foo, Bar);`
);
18 changes: 18 additions & 0 deletions tests/cases/fourslash/organizeImports3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />

// Regression test for bug #41417

//// import {
//// Bar
//// , Foo
//// } from "foo"
////
//// console.log(Foo, Bar);

verify.organizeImports(
`import {
Bar,
Foo
} from "foo";

console.log(Foo, Bar);`);