The TypeScript transformation pipeline uses a chain-of-responsibility pattern to convert TypeScript and modern JavaScript features into JavaScript code compatible with target environments. This page documents the core architecture of the transformer system, including the TransformationContext, the node factory, the transformer chain pattern, and how transformers are orchestrated.
For information about specific transformations (TypeScript syntax, modules, ECMAScript downleveling), see pages 3.2 3.3 and 3.4
The transformation system processes Abstract Syntax Trees (ASTs) through a sequential pipeline of transformer functions. Each transformer is responsible for handling specific language features or downleveling operations. The system provides a unified context object that transformers use to access the node factory, manage lexical environments, request emit helpers, and coordinate with other transformers.
Sources: src/compiler/transformer.ts1-213
Sources: src/compiler/transformer.ts120-190 src/compiler/transformer.ts78-102
The TransformationContext is the central coordination object passed to all transformers. It provides access to shared resources and utilities needed during transformation.
Sources: src/compiler/transformer.ts51-52 src/compiler/factory/nodeFactory.ts1-218
| Member | Type | Purpose |
|---|---|---|
factory | NodeFactory | Creates and updates AST nodes |
getCompilerOptions() | () => CompilerOptions | Access to compiler configuration |
getEmitResolver() | () => EmitResolver | Access to type checker information |
getEmitHost() | () => EmitHost | Access to file system operations |
getEmitHelperFactory() | () => EmitHelperFactory | Creates emit helpers like __awaiter |
startLexicalEnvironment() | () => void | Begins a new lexical scope |
endLexicalEnvironment() | () => Statement[] | Ends scope, returns hoisted declarations |
hoistVariableDeclaration() | (name) => void | Hoists a variable to current scope |
hoistFunctionDeclaration() | (func) => void | Hoists a function to current scope |
requestEmitHelper() | (helper) => void | Requests a runtime helper function |
readEmitHelpers() | () => EmitHelper[] | Retrieves requested helpers |
enableSubstitution() | (kind) => void | Enables node substitution for syntax kind |
enableEmitNotification() | (kind) => void | Enables emit notifications for syntax kind |
onSubstituteNode | (hint, node) => Node | Hook for substituting nodes during emit |
onEmitNode | (hint, node, emit) => void | Hook for wrapping node emission |
Sources: src/compiler/transformer.ts51-52 src/compiler/transformers/ts.ts236-245
Each transformer is created through a two-step process:
Initialization: The TransformerFactory function receives the TransformationContext and returns a Transformer function. This allows the factory to set up state, register hooks, and configure the transformer based on the context. src/compiler/transformer.ts56-57
Transformation: The returned Transformer function receives an AST node and returns the transformed node. src/compiler/transformer.ts56
Sources: src/compiler/transformer.ts51-57
Sources: src/compiler/transformer.ts120-190
The getScriptTransformers function builds the transformer array based on compiler options and target language version. Transformers are added in a specific order to ensure correct transformation semantics:
Sources: src/compiler/transformer.ts127-190
The factory object on the context provides methods to create and update AST nodes. This is the primary way transformers produce new AST nodes.
| Category | Example Methods | Purpose |
|---|---|---|
| Identifiers | createIdentifier, createUniqueName | Create name references src/compiler/factory/nodeFactory.ts126 |
| Literals | createStringLiteral, createNumericLiteral | Create literal values src/compiler/factory/nodeFactory.ts211 |
| Expressions | createBinaryExpression, createCallExpression | Create expressions src/compiler/factory/nodeFactory.ts23 |
| Statements | createBlock, createIfStatement | Create statements src/compiler/factory/nodeFactory.ts29 |
| Declarations | createFunctionDeclaration, createVariableDeclaration | Create declarations src/compiler/factory/nodeFactory.ts101 |
| Update Methods | updateSourceFile, updateClassDeclaration | Update existing nodes src/compiler/factory/nodeFactory.ts208 |
Sources: src/compiler/factory/nodeFactory.ts1-282
Transformers need to manage hoisted declarations and statements. The lexical environment provides a stack-based mechanism for this.
Sources: src/compiler/transformers/ts.ts239-242 src/compiler/transformers/module/module.ts195-197
In transformESNext, the lexical environment is used to handle top-level using declarations which require hoisting of other bindings into a generated try block. src/compiler/transformers/esnext.ts169-196
Sources: src/compiler/transformers/esnext.ts169-172
Emit helpers are runtime library functions injected into the output to support downleveled features.
| Helper | Purpose | Used By |
|---|---|---|
__awaiter | async/await polyfill | ES2017 async functions src/compiler/transformers/es2017.ts9 |
__generator | Generator state machine | ES2015 generators src/compiler/transformers/generators.ts161 |
__asyncGenerator | Async generator support | ES2015 async generators tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js66 |
__await | Await wrapping in async generators | ES2015 async generators tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js65 |
Sources: src/compiler/transformers/generators.ts100-166 tests/baselines/reference/emitter.asyncGenerators.classMethods.es2015.js65-77
Transformers can register hooks to intercept node processing during emission. This allows fine-grained control over how nodes are printed.
The onSubstituteNode hook allows transformers to replace nodes during emission without modifying the AST.
Use cases:
import.meta in SystemJS src/compiler/transformers/module/system.ts160Sources: src/compiler/transformers/module/module.ts207-213 src/compiler/transformers/module/system.ts155-160
Transformers register hooks during initialization:
Sources: src/compiler/transformers/module/module.ts205-213
Transformers use the visitor pattern to traverse and transform the AST. The system provides several visitor helper functions.
| Function | Purpose | Returns |
|---|---|---|
visitNode(node, visitor, test) | Visit a single node | Transformed node src/compiler/transformers/ts.ts200 |
visitNodes(nodes, visitor, test) | Visit an array of nodes | Array of transformed nodes src/compiler/transformers/ts.ts201 |
visitEachChild(node, visitor, context) | Visit all children of a node | Node with transformed children src/compiler/transformers/ts.ts197 |
visitFunctionBody(body, visitor, context) | Visit function body | Transformed body src/compiler/transformers/ts.ts198 |
Sources: src/compiler/transformers/ts.ts197-203
Nodes are marked with TransformFlags that indicate which transformers need to process them. This allows transformers to skip nodes that don't contain relevant syntax.
Sources: src/compiler/transformers/esnext.ts105-108 src/compiler/transformers/ts.ts194
The TypeScript transformer architecture provides a sequential pipeline where:
getScriptTransformers builds a list of TransformerFactory objects based on compilerOptions. src/compiler/transformer.ts127-133TransformationContext containing a NodeFactory and environment management. src/compiler/transformer.ts51-52TransformFlags, and use visitEachChild to recurse. src/compiler/transformers/esnext.ts105-125Sources: src/compiler/transformer.ts1-213 src/compiler/transformers/ts.ts235-250
Refresh this wiki