microsoft/TypeScript
Parser
A recursive-descent parser that turns the scanner's token stream into a SourceFile AST. The parser is incremental: when given a previous SourceFile and a TextChangeRange, it reuses unchanged subtrees and re-parses only what's affected.
Purpose
The parser produces every TypeScript syntax tree node and is the canonical owner of node pos, end, parent, and flags. It also records:
- Comment directives (
// @ts-ignore,// @ts-expect-error,// @ts-nocheck) for downstream filtering. - Pragmas like
/// <reference />,/// <amd-module />, JSDoc reference tags. - JSDoc comments, parsed into the same tree under each node's
.jsDocproperty.
Source
| File | Lines | Role |
|---|---|---|
src/compiler/parser.ts |
10,823 | The whole parser (incl. JSDoc subset) |
src/compiler/factory/nodeFactory.ts |
7,542 | Node creation primitives the parser uses |
src/compiler/types.ts |
10,670 | Node and SyntaxKind definitions |
Key abstractions
| Symbol | Role |
|---|---|
createSourceFile(fileName, sourceText, options) |
Public entry — parses a .ts / .js / .d.ts file into a SourceFile |
updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks?) |
Incremental update |
Parser (internal namespace) |
Holds parser state and grammar productions |
JSDocParser (internal namespace) |
JSDoc subset, invoked inline |
IncrementalParser (internal namespace) |
Reuse logic for incremental parses |
parseJsonText(fileName, text) |
JSON / JSONC → SourceFile (used for tsconfig.json) |
parseIsolatedEntityName(text, languageVersion) |
Used by name-resolution code paths that get a string and need an entity-name node |
The parser is implemented as a single closure-rich namespace; no class is exported. Its state (scanner, current token, context flags, factory) is held in let-bound module-level variables and reset between files.
Grammar contexts
Parsing is driven by context flags (NodeFlags.YieldContext, AwaitContext, DecoratorContext, DisallowInContext, …). Production functions like parseExpression consult these flags to decide what's grammatically permitted at the current position. tryParse and lookAhead save and restore scanner state so the parser can speculatively try one production and fall back if it misses.
graph TD
Text["source text"] --> Scanner["Scanner.scan"]
Scanner --> Loop["Parser main loop"]
Loop --> Stmts["parseStatements"]
Stmts --> Decls["parseDeclaration"]
Stmts --> Exprs["parseExpression"]
Decls --> Factory["factory.createXxx"]
Exprs --> Factory
Factory --> SF["SourceFile (root)"]
Loop --> JSDoc["JSDoc sub-parser"]
JSDoc --> Factory
SF --> Out["SourceFile + parseDiagnostics"]Incremental parsing
The parser caches every node's pos, end, and parent. When the user types a character in an editor, tsserver calls updateSourceFile with a TextChangeRange. The incremental parser:
- Walks the old tree to find subtrees fully outside the change range — these can be reused verbatim, with
pos/endshifted by the text-length delta. - Re-parses subtrees that intersect the change range from scratch, splicing them into the otherwise-reused tree.
- Reuses the original
parseDiagnosticsfor unchanged regions.
This makes typing in even very large files cheap — the typical edit re-parses only the function or class containing the cursor.
Error recovery
Parsing must succeed on every input, including malformed code. The parser uses several strategies:
- Synthetic tokens — when an expected token is missing, the parser reports a diagnostic and inserts a
Missingplaceholder so children continue to type-check. - Recovery tokens — production-specific lists of tokens that signal "abandon this production and pop up a level" (e.g.,
}ends a block). - Reparse fallbacks — JSX vs. less-than expression, arrow-function vs. parenthesised expression, and similar ambiguous constructs use
lookAheadto commit only after disambiguation.
Comment directives like // @ts-ignore are recorded by the parser into commentDirectives on the SourceFile. The checker reads these to suppress diagnostics on the next line.
JSDoc
The parser's JSDocParser namespace is invoked when a /** … */ comment is encountered. JSDoc has its own grammar (@param {Foo} bar - description, @returns, …), supports a TypeScript-flavoured type subset, and produces specialized JSDoc* node kinds. The result is attached to the next "real" node via .jsDoc. The JSDoc tree is what powers --allowJs/--checkJs JS-with-types support.
Diagnostics
Per-file parse errors live on SourceFile.parseDiagnostics. The checker later merges them with bind diagnostics, semantic diagnostics, and suggestion diagnostics to produce the final user-visible list. Diagnostic locations come from token positions and are precise to the character.
Integration points
- Called from
src/compiler/program.tsduring program construction to load each source file. - Called from
src/server/scriptInfo.tsevery time atsserverScriptInfo's text changes. - Called from
src/services/preProcess.tsfor fast import scanning. - Used directly by JSON-config parsing in
src/compiler/commandLineParser.ts(parseJsonText).
Entry points for modification
- New syntax: add productions to the appropriate
parseXxxfunctions inparser.ts, updateforEachChildand the visitor insrc/compiler/visitorPublic.ts, add factory methods tonodeFactory.ts, and add type predicates tonodeTests.ts. - Improving error recovery: search for
parseErrorAtCurrentTokenandcreateMissingNodeto find the existing recovery patterns. - Touching JSDoc: the
JSDocParsernamespace insideparser.ts.
See systems/binder for the next pipeline stage and primitives/source-file for what the parser produces.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.