Skip to content

Commit 8a51c80

Browse files
authored
Update from TSCO CLI (#112)
1 parent 89aff9f commit 8a51c80

11 files changed

Lines changed: 241 additions & 102 deletions

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ See [TypeScript Code Organizer Command Line Interface](https://www.npmjs.com/pac
222222
- add support for declaration dependency order resolution
223223
- fix issue with file name casing
224224

225-
### 2.0.13
225+
### 2.0.15
226226

227227
- fix issue with access modifiers not being correctly updated
228+
- fix issue with leading and trailing comments being lost
229+
- fix issue with unused imports not being removed correctly

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "tsco",
33
"displayName": "TypeScript Code Organizer",
44
"description": "TypeScript Code Organizer for VS Code",
5-
"version": "2.0.13",
5+
"version": "2.0.15",
66
"publisher": "aljazsim",
77
"author": {
88
"name": "aljazsim",

src/tsco-cli/elements/class-node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ export class ClassNode extends ElementNode
4545

4646
if (classDeclaration.members && classDeclaration.members.length > 0)
4747
{
48-
this.membersStart = classDeclaration.members[0].getFullStart() - classDeclaration.getFullStart();
49-
this.membersEnd = classDeclaration.members[classDeclaration.members.length - 1].getEnd() - classDeclaration.getFullStart();
48+
this.membersStart = this.getOpeningBraceIndex(sourceFile, classDeclaration) + 1 - classDeclaration.getStart(sourceFile);
49+
this.membersEnd = this.getClosingBraceIndex(sourceFile, classDeclaration) - 1 - classDeclaration.getStart(sourceFile);
5050
}
5151

5252
this.decorators = getDecorators(classDeclaration, sourceFile);

src/tsco-cli/elements/element-node.ts

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { getLeadingComment, getTrailingComment } from "../helpers/node-helper";
44

55
export abstract class ElementNode
66
{
7-
// #region Properties (5)
7+
// #region Properties (6)
88

99
public readonly dependencies: string[] = [];
10+
public readonly indentation: string = "";
1011
public readonly leadingComment: string | null;
1112
public abstract readonly name: string;
1213
public readonly sourceCode: string;
@@ -18,20 +19,86 @@ export abstract class ElementNode
1819

1920
constructor(sourceFile: ts.SourceFile, public readonly node: ts.Node, leadingComment: string | null = null, trailingComment: string | null = null)
2021
{
21-
this.sourceCode = ElementNode.getSourceCode(sourceFile, node.getFullStart(), node.getEnd());
22+
this.indentation = this.getIndentation(sourceFile, node);
2223

2324
this.leadingComment = leadingComment ?? getLeadingComment(node, sourceFile);
2425
this.trailingComment = trailingComment ?? getTrailingComment(node, sourceFile);
26+
27+
this.sourceCode = node.getText(sourceFile);
28+
this.sourceCode = this.sourceCode.replace(leadingComment ?? "", "");
29+
this.sourceCode = this.sourceCode.replace(trailingComment ?? "", "");
30+
this.sourceCode = this.indentation + this.sourceCode.trim();
2531
}
2632

2733
// #endregion Constructors
2834

29-
// #region Private Static Methods (1)
35+
// #region Protected Methods (2)
36+
37+
protected getClosingBraceIndex(sourceFile: ts.SourceFile, node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.TypeLiteralNode)
38+
{
39+
const closingBrace = "}";
40+
const sourceCode = sourceFile.getText();
41+
42+
for (let i = node.getEnd(); i > node.getStart(sourceFile); i--)
43+
{
44+
if (sourceCode[i] === closingBrace)
45+
{
46+
return i
47+
}
48+
}
49+
50+
throw new Error("Closing brace not found");
51+
}
52+
53+
protected getOpeningBraceIndex(sourceFile: ts.SourceFile, node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.TypeLiteralNode)
54+
{
55+
const openingBrace = "{";
56+
const sourceCode = sourceFile.getText();
57+
let startIndex = node.getStart(sourceFile);
58+
59+
if (ts.isClassDeclaration(node))
60+
{
61+
// class could start with a decorator containing curly braces
62+
startIndex = sourceCode.indexOf("class ", startIndex);
63+
}
64+
65+
for (let i = startIndex; i < node.getEnd(); i++)
66+
{
67+
if (sourceCode[i] === openingBrace)
68+
{
69+
return i
70+
}
71+
}
72+
73+
throw new Error("Opening brace not found");
74+
}
75+
76+
// #endregion Protected Methods
77+
78+
// #region Private Methods (1)
3079

31-
private static getSourceCode(sourceFile: ts.SourceFile, start: number, end: number)
80+
private getIndentation(sourceFile: ts.SourceFile, node: ts.Node)
3281
{
33-
return sourceFile.getFullText().substring(start, end);
82+
const space = " ";
83+
const tab = "\t";
84+
const sourceCode = sourceFile.getText();
85+
const startIndex = sourceCode.indexOf(node.getText(sourceFile));
86+
let indentation = "";
87+
88+
for (let i = startIndex - 1; i > 0; i--)
89+
{
90+
if (sourceCode[i] === space || sourceCode[i] === tab)
91+
{
92+
indentation = sourceCode[i] + indentation;
93+
}
94+
else
95+
{
96+
break;
97+
}
98+
}
99+
100+
return indentation;
34101
}
35102

36-
// #endregion Private Static Methods
103+
// #endregion Private Methods
37104
}

src/tsco-cli/elements/interface-node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export class InterfaceNode extends ElementNode
3737

3838
if (interfaceDeclaration.members && interfaceDeclaration.members.length > 0)
3939
{
40-
this.membersStart = interfaceDeclaration.members[0].getFullStart() - interfaceDeclaration.getFullStart();
41-
this.membersEnd = interfaceDeclaration.members[interfaceDeclaration.members.length - 1].getEnd() - interfaceDeclaration.getFullStart();
40+
this.membersStart = this.getOpeningBraceIndex(sourceFile, interfaceDeclaration) + 1 - interfaceDeclaration.getStart(sourceFile);
41+
this.membersEnd = this.getClosingBraceIndex(sourceFile, interfaceDeclaration) - 1 - interfaceDeclaration.getStart(sourceFile);
4242
}
4343

4444
// members

src/tsco-cli/elements/type-alias-node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export class TypeAliasNode extends ElementNode
3939

4040
if (typeLiteral.members && typeLiteral.members.length > 0)
4141
{
42-
this.membersStart = typeLiteral.members[0].getFullStart() - typeAliasDeclaration.getFullStart();
43-
this.membersEnd = typeLiteral.members[typeLiteral.members.length - 1].getEnd() - typeAliasDeclaration.getFullStart();
42+
this.membersStart = this.getOpeningBraceIndex(sourceFile, typeLiteral) + 1 - typeAliasDeclaration.getStart(sourceFile);
43+
this.membersEnd = this.getClosingBraceIndex(sourceFile, typeLiteral) - 1 - typeAliasDeclaration.getStart(sourceFile);
4444

4545
// members
4646
for (const member of typeLiteral.members)

src/tsco-cli/helpers/node-helper.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,16 +227,15 @@ export function getIsStatic(node: ts.ClassDeclaration | ts.GetAccessorDeclaratio
227227

228228
export function getLeadingComment(node: ts.Node, sourceFile: ts.SourceFile)
229229
{
230-
const sourceCode = node.getFullText(sourceFile);
231-
const commentRanges = ts.getLeadingCommentRanges(sourceCode, 0)
230+
const commentRanges = ts.getLeadingCommentRanges(sourceFile.getFullText(), node.pos);
232231

233232
if (commentRanges && commentRanges.length > 0)
234233
{
235234
const start = commentRanges[0].pos;
236235
const end = commentRanges[commentRanges.length - 1].end;
237236
const trailingNewLine = commentRanges[commentRanges.length - 1].hasTrailingNewLine;
238237

239-
return sourceCode.substring(start, end).trimStart() + (trailingNewLine ? newLine : "");
238+
return sourceFile.getFullText().substring(start, end) + (trailingNewLine ? newLine : "");
240239
}
241240
else
242241
{
@@ -339,16 +338,14 @@ export function getNodeNames(nodes: ElementNode[])
339338

340339
export function getTrailingComment(node: ts.Node, sourceFile: ts.SourceFile)
341340
{
342-
const sourceCode = node.getFullText(sourceFile);
343-
const commentRanges = ts.getTrailingCommentRanges(sourceCode, 0);
341+
const commentRanges = ts.getTrailingCommentRanges(sourceFile.getFullText(), node.end);
344342

345343
if (commentRanges && commentRanges.length > 0)
346344
{
347345
const start = commentRanges[0].pos;
348346
const end = commentRanges[commentRanges.length - 1].end;
349-
const trailingNewLine = commentRanges[commentRanges.length - 1].hasTrailingNewLine;
350347

351-
return sourceCode.substring(start, end).trimEnd() + (trailingNewLine ? newLine : "");
348+
return sourceFile.getFullText().substring(start, end);
352349
}
353350
else
354351
{
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { ElementNode } from "../elements/element-node";
2+
import { ElementNodeGroup } from "../elements/element-node-group";
3+
import { distinct } from "../helpers/array-helper";
4+
import { getNodeNames } from "../helpers/node-helper";
5+
6+
// #region Functions (1)
7+
8+
function resolveDeclarationDependenciesOrderWithinGroup(nodes: ElementNode[])
9+
{
10+
const maxIterations = 1000; // there might be a declaration dependency cycle
11+
12+
for (let iteration = 0; iteration < maxIterations; iteration++)
13+
{
14+
let dependenciesDetected = false;
15+
16+
for (let i = 0; i < nodes.length; i++)
17+
{
18+
const dependencies = distinct(nodes[i].dependencies.sort());
19+
20+
for (const dependency of dependencies)
21+
{
22+
const dependencyIndex = nodes.findIndex(n => getNodeNames([n]).indexOf(dependency) >= 0);
23+
24+
if (dependencyIndex > i)
25+
{
26+
const node = nodes[i];
27+
const dependencyNode = nodes[dependencyIndex];
28+
29+
for (let j = dependencyIndex; j > i; j--)
30+
{
31+
nodes[j] = nodes[j - 1];
32+
}
33+
34+
nodes[i] = dependencyNode;
35+
nodes[i + 1] = node;
36+
37+
dependenciesDetected = true;
38+
39+
break;
40+
}
41+
}
42+
}
43+
44+
if (!dependenciesDetected)
45+
{
46+
break;
47+
}
48+
}
49+
}
50+
51+
// #endregion Functions
52+
53+
// #region Exported Functions (1)
54+
55+
export function resolveDeclarationDependenciesOrder(nodeGroups: ElementNodeGroup[])
56+
{
57+
for (const nodeGroup of nodeGroups)
58+
{
59+
resolveDeclarationDependenciesOrderWithinGroup(nodeGroup.nodes);
60+
resolveDeclarationDependenciesOrder(nodeGroup.nodeSubGroups);
61+
}
62+
}
63+
64+
// #endregion Exported Functions

0 commit comments

Comments
 (0)