CodeBlanks Logo Icon CodeBlanks

Custom transformer

Learn to write your own transformer.

Writing a custom transformer

When writing your own transformer you define a visitor function. The visitor recognizes specific nodes and replaces them with new nodes built via ts.factory. For other nodes you descend with ts.visitEachChild.

function visit(node: ts.Node): ts.Node {
  if (ts.isStringLiteral(node)) {
    return ts.factory.createStringLiteral("X");
  }
  return ts.visitEachChild(node, visit, context);
}

When the visitor returns a new node, that branch is replaced entirely.

Node replacement and visitEachChild

There are two ways to change a node: return a completely new node, or update the existing node's fields with ts.factory.updateX. visitEachChild automatically updates the parent when a child changes.

// visitEachChild is recommended even for identity
return ts.visitEachChild(node, visit, context);

Practice Replace strings with "X"

Create a source with const a = 'merhaba'; and const b = 'dünya';. Write a transformer that replaces every StringLiteral node found with ts.isStringLiteral by ts.factory.createStringLiteral("X"). Apply it with ts.transform and print the result with the Printer.

Starter code

index.ts
import * as ts from "typescript";

// Kaynak: const a = 'merhaba'; const b = 'dünya';
// SourceFile oluştur
// Bir transformer yaz: StringLiteral düğümlerini "X" ile değiştir
// transform ile uygula
// Printer ile sonucu yazdır

// kodunu buraya yaz

Sample solution

index.ts
import ts from "typescript";

const sourceText = `const a = 'merhaba';\nconst b = 'dünya';`;
const sf = ts.createSourceFile("app.ts", sourceText, ts.ScriptTarget.Latest, true);

const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
  function visit(node: ts.Node): ts.Node {
    if (ts.isStringLiteral(node)) {
      return ts.factory.createStringLiteral("X");
    }
    return ts.visitEachChild(node, visit, context);
  }
  return (node) => ts.visitEachChild(node, visit, context);
};

const result = ts.transform(sf, [transformer]);
const printer = ts.createPrinter();
process.stdout.write(printer.printFile(result.transformed[0] as ts.SourceFile));
result.dispose();

Expected output

const a = "X";
const b = "X";

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 To change a node in a custom transformer, what do you do?

  • You call program.getTypeChecker
  • You mutate the node's text property directly
  • You return a new node in the visitor function Correct answer
  • You print the node with console.log

Explanation: AST nodes are immutable; you cannot mutate the text property. When the visitor returns a new node, that branch is replaced.

2 Replace a string literal

Question
function visit(node: ts.Node): ts.Node {
  if (ts.isStringLiteral(node)) {
    return ts.factory.____("X");
  }
  return ts.visitEachChild(node, visit, context);
}
Answer
function visit(node: ts.Node): ts.Node {
  if (ts.isStringLiteral(node)) {
    return ts.factory.createStringLiteral("X");
  }
  return ts.visitEachChild(node, visit, context);
}

Explanation: createStringLiteral produces a new StringLiteral node; createString does not exist on the factory and updateStringLiteral updates an existing node (we want a new one here).

3 Custom transformer parts

Term Meaning
Visitor fonksiyonu Recognizes and returns nodes
ts.factory.createStringLiteral Produces a new string node
ts.visitEachChild Transforms child nodes
ts.isStringLiteral Tests the node kind

All lessons in Expert