microsoft/TypeScript
For the CLI, input is argv -> tsoptions parsing (with ancestor tsconfig discovery and extended-config caching) -> a file loader that walks imports/type directives as parse tasks -> parser.ParseSourceFile producing ast.SourceFile trees -> binder-produced symbols -> a parallel checker pool producing diagnostics -> transformer chain -> printer/sourcemap emit through vfs.FS.WriteFile. For the LSP/API servers the same core is wrapped by internal/project: an immutable Snapshot owns a SnapshotFS overlay plus a ProjectCollection, and every edit/request produces a new snapshot; language-service operations read a snapshot's program. The API server adds a registry layer assigning stable SymbolID/TypeID/NodeHandle values that are encoded to MessagePack or JSON for the Node client.
- CLI input boundary: execute.CommandLine lower-cases argv[0] to detect -b/--build, then tsoptions.ParseCommandLine/ParseBuildCommandLine produce ParsedCommandLine values; tscCompilation locates tsconfig.json by walking ancestor directories via tspath.ForEachAncestorDirectory.
- tsconfig parsing (GetParsedCommandLineOfConfigFile) resolves `extends` chains through an ExtendedConfigCache, merges command-line compilerOptions wrapped under a 'compilerOptions' key, and reports config parse errors as diagnostics before any compilation.
- File loading is a worklist of parseTask structs: each task loads a file via the compiler host, records module/type-reference resolutions in ModeAwareCache fields, and enqueues sub-tasks for discovered dependencies (filesparser.go/filesParser, fileloader.go).
- Module resolution is centralized in internal/module.Resolver with per-file mode-aware caches; resolved modules feed both the loader (which files to parse) and emit metadata (importHelpersImportSpecifier, jsxRuntimeImportSpecifier).
- Parse/bind/check/emit diagnostics flow through compiler.GetDiagnosticsOfAnyProgram; EmitFilesAndReportErrors calls GetBindDiagnostics and GetSemanticDiagnostics per file (timed against CompileTimes), then ProgramLike.Emit writes outputs via compiler.EmitOptions.WriteFile.
- Emit runs a transformer chain (internal/transformers: tstransforms type erasure/legacy decorators/metadata, moduletransforms commonjs/esmodule, estransforms for downlevel ES features, declarations for .d.ts) feeding internal/printer and internal/sourcemap.
- Type checking is parallelized by a CheckerPool on the Program (compilerCheckerPool enables grouped parallel iteration and non-exclusive access for emit); ProgramOptions.CreateCheckerPool is injectable so the project system can supply its own pool.
- In the language server, state ownership is an immutable project.Snapshot: it holds a SnapshotFS (overlay of open-file contents over the base FS), a ProjectCollection, ConfigFileRegistry, AutoImports registry, and user preferences; each update clones forward the unchanged state.
- LSP request path: stdin bytes -> lsproto.BaseReader -> json.Unmarshal into lsproto.Message -> dynamic_queue requestQueue -> handleRequestOrNotification -> handlers() lookup -> for document requests, session.GetLanguageService(ctx, uri) resolves the project/snapshot, then ls.LanguageService methods compute results converted by internal/ls/lsconv.
- The API session assigns cross-process handles: symbols get IDs from a global atomic (ast.GetSymbolId) stored in a snapshot-wide symbolRegistry, while types and signatures get per-project registries keyed by project.ID to avoid ID collisions between checker pools.
- API transport: StdioServer.Run picks ipc.NewPipeTransport (PipePath) or NewStdioTransport, then wraps a session in either NewMessagePackProtocol+NewSyncConn or NewJSONRPCProtocol+NewAsyncConn depending on the --async flag.
- Node-side, the sync API client (packages/typescript/src/api/sync/client.ts) spawns the binary with getAPIProcessArgs, optionally enabling FS callbacks (--callbacks=...) so the Go server can call back into JS for readFile/fileExists/writeFile etc. via SyncRpcChannel.
- Content-mapped files enter the pipeline when the host returns content-mapped source files (GetContentMappedSourceFiles); ReuseProgram must re-run the external transform for such files and falls back to a full rebuild on failure.
- Output boundaries: diagnostics are rendered by tsc.CreateDiagnosticReporter to sys.Writer (stdout), emitted files go through vfs.FS.WriteFile, .tsbuildinfo is written by the incremental layer, and --diagnostics stats/printed lists go to the writer.