microsoft/TypeScript
Emitter
The pretty-printer that turns the post-transformer AST into .js, .d.ts, and source-map bytes on disk. Also the home of --declaration emit and .tsbuildinfo writing.
Source
| File | Lines | Role |
|---|---|---|
src/compiler/emitter.ts |
6,378 | Tree → text printer |
src/compiler/sourcemap.ts |
1,000+ | Source-map (V3) generation |
src/compiler/transformers/declarations.ts |
3,000+ | Builds the .d.ts AST that the emitter prints |
src/compiler/expressionToTypeNode.ts |
~70k | Type-to-syntax conversion used by declaration emit |
src/compiler/builder.ts |
116k | Incremental emit + .tsbuildinfo |
Purpose
The emitter is a printer plus an orchestrator. Its responsibilities:
- Print every
Nodekind into target-flavoured JavaScript text. - Apply
EmitFlagsand per-node emit metadata (synthetic comments, source-map ranges,noSubstitutionmarkers). - Emit source maps using V3 mappings.
- Emit declarations (
.d.ts) by runningtransformDeclarationsand then printing. - Emit
.tsbuildinfofiles for incremental compilation. - Decide where each output file goes (
outDir,outFile,rootDir,declarationDir).
The emitter does not type-check. It assumes the tree it received is already valid and post-transformation. The most subtle thing it does is apply parenthesisation, comment placement, and substitution hooks.
Key abstractions
| Symbol | File | Role |
|---|---|---|
createPrinter(options?, handlers?) |
emitter.ts |
Public API to print arbitrary nodes; used by code fixes |
Printer |
emitter.ts |
Internal printer state (writer, source-map generator, current node, helpers) |
emitFiles |
emitter.ts |
Internal entry called by program.emit |
Writer |
emitter.ts |
Buffered text writer (line/column tracking, indentation) |
SourceMapGenerator |
sourcemap.ts |
Builds V3 mappings |
EmitNode, EmitFlags |
factory/emitNode.ts |
Per-node emit metadata |
noSubstitution, enableSubstitution, enableEmitNotification |
transformer.ts |
Cross-cutting print-time hooks |
How it works
graph TD
Tree["transformed tree (per file)"] --> Print["Printer.printNode"]
Print --> Emit["emitTextOfNode"]
Emit --> Comments["pipelineEmitWithComments"]
Comments --> SM["pipelineEmitWithSourceMaps"]
SM --> Hint["pipelineEmitWithHint"]
Hint --> Sub["substituteNode (transformer hooks)"]
Sub --> Notify["onEmitNode (transformer hooks)"]
Notify --> Switch["switch on SyntaxKind"]
Switch --> Children["recurse for children"]
Children --> Out["writer text"]The printer organises printing as a pipeline per node:
- Decide what comments to emit before/after.
- Emit the source-map opener.
- Apply emit hint (
Expressionvs.Statementvs.JsxAttributeValueetc.) to choose the right grammar context. - Apply transformer-installed substitution and notification hooks.
- Switch on
SyntaxKindto print the construct itself. - Recurse for children, with parenthesisation rules from
factory/parenthesizerRules.ts. - Close the source-map span and trailing comments.
Source maps
Source-map generation lives in sourcemap.ts. It produces V3 source maps with optional --sourceRoot rewriting, --inlineSourceMap for embedded maps, and --inlineSources for embedded original text. Mappings are recorded by the emitter at every node boundary; the generator deduplicates and base64-VLQ encodes them at flush time.
Declaration emit
--declaration triggers transformDeclarations (src/compiler/transformers/declarations.ts). Declaration emit is type-aware: it asks the checker for the type of unannotated exports and synthesises .d.ts representations. Type-to-node conversion uses expressionToTypeNode.ts to produce minimal, portable types. See features/declaration-emit.
Incremental emit
When --incremental (or --composite) is enabled, builder.ts records per-file signatures and writes a .tsbuildinfo file. On subsequent runs, only files whose dependencies changed are re-emitted. builder.ts is large (~116k lines including utilities) because it must conservatively decide which downstream files to invalidate for each change in a way that remains correct under structural typing.
Pretty-printing rules
- Line endings —
\r\non Windows by default;--newLine LFforces Unix-style. - Indentation — tabs vs spaces and width come from the printer options (and ultimately
tsconfig.json's deprecated--indent). - Strict adherence to original positions — when emitting unmodified subtrees, the printer copies the source text verbatim (preserving comments and whitespace).
- Module emit — module-system specifics come from the transformer (not the emitter); the emitter just prints whatever module shape the transformer produced.
Integration points
- Called by
program.emit. - Receives the transformed tree from
transformer.ts. - Receives metadata from
factory/emitNode.ts. - Used (via
createPrinter) by code fixes and refactors insrc/services/to print snippet edits.
Entry points for modification
- Adding a new node-print case: extend the switch in
emitter.ts. NewSyntaxKinds require entries here or output is "[no print]" placeholder text. - Tweaking helper-printing: see
emitFileandemitHelperspaths. - Source-map changes:
sourcemap.ts. - Declaration emit shape changes:
transformers/declarations.tsandexpressionToTypeNode.ts.
See systems/transformers for what feeds the emitter and systems/program for the orchestration.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.