#TS compiler API, Statements and printing

2 messages · Page 1 of 1 (latest)

neat elbow
#

Hi all, diving into the world of the TS library to try and swing together a little VSCode extension which does some pretty basic TypeScript refactors that I'm interested in automating.

One of these usecases I'm trying to build is refactoring something like this:

const someFunc = () => {
  if (A) {
    a();
  } else {
    b();
  }
}

Into something that looks like this:

const someFunc = () => {
  if (A) {
    return a();
  }

  b();
}

Current have some code for doing this that looks roughly like the following:
(The first function is calling parser which is a module for getting stuff from the AST, that works fine)

const oldIfStatement = parser.getContainingIfStatement(cursorNode);

// If we have no containing if statement, or it is not an if/else statement, do nothing.
if (
    oldIfStatement === undefined ||
    oldIfStatement.elseStatement === undefined
) {
    return;
}

const newIfStatement = ts.factory.createIfStatement(
    oldIfStatement.expression,
    ts.factory.createBlock([
        oldIfStatement.thenStatement,
        ts.factory.createReturnStatement(),
    ])
);

const replacement = ts.factory.createNodeArray<ts.Node>(
    [newIfStatement, oldIfStatement.elseStatement],
    false
);

This all looks well and good, but when I go to print out the replacement using ts.Printer, both the elseStatement and the thenStatement are wrapped in braces. So it ends up looking like:

const someFunc = () => {
  if (A) {
    {
      a();
    }
    return;
  }
  {
    b();
  }
}

Diving into them, they have 3 children, the open brace, a SyntaxList (the thing I probably want) and an end parenthesis. So this printing behaviour is probably pretty reasonable. My confusion mainly lies in the difference between a ts.Node and a ts.Statement.

Is there any good documentation on this stuff? It's very hard to follow the source.
Should I be using ts.transform instead? Is there some other way to remove the braces? cheers ❤️

neat elbow
#

Figured it out.
For any future searchers, the TS compiler is an awful, undocumented jungle.
The solution here was to get the ts.Block and then use ts.Block.statements to get a list of ts.Statements to pass in.

so it ends up looking like

const thenBlock = ifStatement.thenStatement.getChildren().find(ts.isBlock);
const thenBlockStatements = thenBlock?.statements ?? [];

...obviously 🙄

some good resources here are
https://ts-ast-viewer.com/
and
https://basarat.gitbook.io/typescript/overview/parser/parser-functions