ts-morph

Navigating the AST should be simple and straightforward.

Right now, the best way to explore what's implemented is to look at the autocompletion/intellisense results or view this report.

If you can't find something that means it's most likely not implemented and you should open an issue on GitHub.

General methods

Search autocomplete for methods like .getChildren(), .getParent(), .getFirstChildBySyntaxKind(kind), etc...

Many exist. If you find one you would really like, then please open an issue.

getChildren() and forEachChild(child => ...)

In general, you can easily navigate the tree by using methods such as .getClasses(), .getClass('MyClass'), .getModules(), and so on, but in some cases you might want to get all the child nodes.

In the compiler API, there exists a node.getChildren() method and ts.forEachChild(node, child => { })/node.forEachChild(child => { }) function/method.

  • .getChildren() - Returns all the children including the all the tokens (ex. OpenBraceToken, SemiColonToken etc.).
  • .forEachChild(child => {}) - Iterates all the child nodes that are properties of the node.

getChildren vs forEachChild

In ts-morph, these methods also exist and they can be used similarly to the compiler API:

const allChildren = node.getChildren();

node.forEachChild(node => {
  console.log(node.getText());
});

const classDec = node.forEachChild(node => {
  if (Node.isClassDeclaration(node))
    return node; // stops iterating over the children and returns this value
  return undefined; // return a falsy value or no value to continue iterating
});

forEachDescendant

If you wish to iterate all the descendants, then use the forEachDescendant method:

node.forEachDescendant(node => console.log(node.getText()));

This is especially useful when writing code that implements a visitor pattern:

interface Visitor {
    visit(node: Node): void;
}

const myVisitors: Visitor[] = ...;

for (const sourceFile of sourceFiles)
    sourceFile.forEachDescendant(node => myVisitors.forEach(v => v.visit(node)));

Traversal Control

Traversal can be controlled with the second parameter:

const result = node.forEachDescendant((node, traversal) => {
  switch (node.getKind()) {
    case SyntaxKind.ClassDeclaration:
      // skips traversal of the current node's descendants
      traversal.skip();
      break;
    case SyntaxKind.Parameter:
      // skips traversal of the current node's descendants and its siblings and all their descendants
      traversal.up();
      break;
    case SyntaxKind.FunctionDeclaration:
      // stops traversal completely
      traversal.stop();
      break;
    case SyntaxKind.InterfaceDeclaration:
      // stops traversal completely and returns this value
      return node;
  }

  return undefined;
});