Simplify createChildren (#22270)

* Simplify createChildren

* Move 'getSourceFile()' call after early returns
This commit is contained in:
Andy
2018-03-28 13:57:43 -07:00
committed by GitHub
parent 85a7118c42
commit 7d39b457f8

View File

@@ -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;