AST Tip: Visit Children
There is a utility function ts.forEachChild
that allows you to visit all the child nodes of any Node in the AST.
Here is simplified snippet of the source code to demonstrate how it functions:
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T {
if (!node) {
return;
}
switch (node.kind) {
case SyntaxKind.BinaryExpression:
return visitNode(cbNode, (<BinaryExpression>node).left) ||
visitNode(cbNode, (<BinaryExpression>node).operatorToken) ||
visitNode(cbNode, (<BinaryExpression>node).right);
case SyntaxKind.IfStatement:
return visitNode(cbNode, (<IfStatement>node).expression) ||
visitNode(cbNode, (<IfStatement>node).thenStatement) ||
visitNode(cbNode, (<IfStatement>node).elseStatement);
// .... lots more
Basically it checks node.kind
and based on that assumes an interface offered by the node
and calls the cbNode
on the children. Note, however that this function doesn't call visitNode
for all children (e.g. SyntaxKind.SemicolonToken). If you want all the children of a node in the AST just call .getChildren
member function of the Node
.
E.g. here is a function that prints the verbose AST
of a node:
function printAllChildren(node: ts.Node, depth = 0) {
console.log(new Array(depth+1).join('----'), ts.syntaxKindToName(node.kind), node.pos, node.end);
depth++;
node.getChildren().forEach(c=> printAllChildren(c, depth));
}
We will see a sample usage of this function when we discuss the parser further.