mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Simplify createChildren (#22270)
* Simplify createChildren * Move 'getSourceFile()' call after early returns
This commit is contained in:
@@ -54,7 +54,7 @@ namespace ts {
|
||||
public jsDoc: JSDoc[];
|
||||
public original: Node;
|
||||
public transformFlags: TransformFlags;
|
||||
private _children: Node[];
|
||||
private _children: Node[] | undefined;
|
||||
|
||||
constructor(kind: SyntaxKind, pos: number, end: number) {
|
||||
this.pos = pos;
|
||||
@@ -117,106 +117,17 @@ namespace ts {
|
||||
return sourceFile.text.substring(this.getStart(sourceFile), this.getEnd());
|
||||
}
|
||||
|
||||
private addSyntheticNodes(nodes: Push<Node>, pos: number, end: number): number {
|
||||
scanner.setTextPos(pos);
|
||||
while (pos < end) {
|
||||
const token = scanner.scan();
|
||||
const textPos = scanner.getTextPos();
|
||||
if (textPos <= end) {
|
||||
if (token === SyntaxKind.Identifier) {
|
||||
Debug.fail(`Did not expect ${Debug.showSyntaxKind(this)} to have an Identifier in its trivia`);
|
||||
}
|
||||
nodes.push(createNode(token, pos, textPos, this));
|
||||
}
|
||||
pos = textPos;
|
||||
if (token === SyntaxKind.EndOfFileToken) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private createSyntaxList(nodes: NodeArray<Node>): Node {
|
||||
const list = <NodeObject>createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, this);
|
||||
list._children = [];
|
||||
let pos = nodes.pos;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (pos < node.pos) {
|
||||
pos = this.addSyntheticNodes(list._children, pos, node.pos);
|
||||
}
|
||||
list._children.push(node);
|
||||
pos = node.end;
|
||||
}
|
||||
if (pos < nodes.end) {
|
||||
this.addSyntheticNodes(list._children, pos, nodes.end);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private createChildren(sourceFile?: SourceFileLike) {
|
||||
if (!isNodeKind(this.kind)) {
|
||||
this._children = emptyArray;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJSDocCommentContainingNode(this)) {
|
||||
/** Don't add trivia for "tokens" since this is in a comment. */
|
||||
const children: Node[] = [];
|
||||
this.forEachChild(child => { children.push(child); });
|
||||
this._children = children;
|
||||
return;
|
||||
}
|
||||
|
||||
const children: Node[] = [];
|
||||
scanner.setText((sourceFile || this.getSourceFile()).text);
|
||||
let pos = this.pos;
|
||||
const processNode = (node: Node) => {
|
||||
pos = this.addSyntheticNodes(children, pos, node.pos);
|
||||
children.push(node);
|
||||
pos = node.end;
|
||||
};
|
||||
const processNodes = (nodes: NodeArray<Node>) => {
|
||||
if (pos < nodes.pos) {
|
||||
pos = this.addSyntheticNodes(children, pos, nodes.pos);
|
||||
}
|
||||
children.push(this.createSyntaxList(nodes));
|
||||
pos = nodes.end;
|
||||
};
|
||||
// jsDocComments need to be the first children
|
||||
if (this.jsDoc) {
|
||||
for (const jsDocComment of this.jsDoc) {
|
||||
processNode(jsDocComment);
|
||||
}
|
||||
}
|
||||
// For syntactic classifications, all trivia are classcified together, including jsdoc comments.
|
||||
// For that to work, the jsdoc comments should still be the leading trivia of the first child.
|
||||
// Restoring the scanner position ensures that.
|
||||
pos = this.pos;
|
||||
forEachChild(this, processNode, processNodes);
|
||||
if (pos < this.end) {
|
||||
this.addSyntheticNodes(children, pos, this.end);
|
||||
}
|
||||
scanner.setText(undefined);
|
||||
this._children = children;
|
||||
}
|
||||
|
||||
public getChildCount(sourceFile?: SourceFile): number {
|
||||
this.assertHasRealPosition();
|
||||
if (!this._children) this.createChildren(sourceFile);
|
||||
return this._children.length;
|
||||
return this.getChildren(sourceFile).length;
|
||||
}
|
||||
|
||||
public getChildAt(index: number, sourceFile?: SourceFile): Node {
|
||||
this.assertHasRealPosition();
|
||||
if (!this._children) this.createChildren(sourceFile);
|
||||
return this._children[index];
|
||||
return this.getChildren(sourceFile)[index];
|
||||
}
|
||||
|
||||
public getChildren(sourceFile?: SourceFileLike): Node[] {
|
||||
this.assertHasRealPosition("Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine");
|
||||
if (!this._children) this.createChildren(sourceFile);
|
||||
return this._children;
|
||||
return this._children || (this._children = createChildren(this, sourceFile));
|
||||
}
|
||||
|
||||
public getFirstToken(sourceFile?: SourceFile): Node {
|
||||
@@ -249,6 +160,74 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createChildren(node: Node, sourceFile: SourceFileLike | undefined): Node[] {
|
||||
if (!isNodeKind(node.kind)) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
const children: Node[] = [];
|
||||
|
||||
if (isJSDocCommentContainingNode(node)) {
|
||||
/** Don't add trivia for "tokens" since this is in a comment. */
|
||||
node.forEachChild(child => { children.push(child); });
|
||||
return children;
|
||||
}
|
||||
|
||||
scanner.setText((sourceFile || node.getSourceFile()).text);
|
||||
let pos = node.pos;
|
||||
const processNode = (child: Node) => {
|
||||
addSyntheticNodes(children, pos, child.pos, node);
|
||||
children.push(child);
|
||||
pos = child.end;
|
||||
};
|
||||
const processNodes = (nodes: NodeArray<Node>) => {
|
||||
addSyntheticNodes(children, pos, nodes.pos, node);
|
||||
children.push(createSyntaxList(nodes, node));
|
||||
pos = nodes.end;
|
||||
};
|
||||
// jsDocComments need to be the first children
|
||||
forEach((node as JSDocContainer).jsDoc, processNode);
|
||||
// For syntactic classifications, all trivia are classified together, including jsdoc comments.
|
||||
// For that to work, the jsdoc comments should still be the leading trivia of the first child.
|
||||
// Restoring the scanner position ensures that.
|
||||
pos = node.pos;
|
||||
node.forEachChild(processNode, processNodes);
|
||||
addSyntheticNodes(children, pos, node.end, node);
|
||||
scanner.setText(undefined);
|
||||
return children;
|
||||
}
|
||||
|
||||
function addSyntheticNodes(nodes: Push<Node>, pos: number, end: number, parent: Node): void {
|
||||
scanner.setTextPos(pos);
|
||||
while (pos < end) {
|
||||
const token = scanner.scan();
|
||||
const textPos = scanner.getTextPos();
|
||||
if (textPos <= end) {
|
||||
if (token === SyntaxKind.Identifier) {
|
||||
Debug.fail(`Did not expect ${Debug.showSyntaxKind(parent)} to have an Identifier in its trivia`);
|
||||
}
|
||||
nodes.push(createNode(token, pos, textPos, parent));
|
||||
}
|
||||
pos = textPos;
|
||||
if (token === SyntaxKind.EndOfFileToken) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createSyntaxList(nodes: NodeArray<Node>, parent: Node): Node {
|
||||
const list = createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, parent) as any as SyntaxList;
|
||||
list._children = [];
|
||||
let pos = nodes.pos;
|
||||
for (const node of nodes) {
|
||||
addSyntheticNodes(list._children, pos, node.pos, parent);
|
||||
list._children.push(node);
|
||||
pos = node.end;
|
||||
}
|
||||
addSyntheticNodes(list._children, pos, nodes.end, parent);
|
||||
return list;
|
||||
}
|
||||
|
||||
class TokenOrIdentifierObject implements Node {
|
||||
public kind: SyntaxKind;
|
||||
public pos: number;
|
||||
|
||||
Reference in New Issue
Block a user