typescript-program.ts

TypeScript program and language-service creation.

Two entry points sharing host configuration (tsconfig parsing, virtual file plumbing, .svelte module resolution):

  • createAnalysisProgram — one-shot ts.Program from a ts.CompilerHost. Lower-level escape hatch for power users + dependency resolution. Does not support incremental updates.
  • createAnalysisLanguageService — persistent ts.LanguageService with versioned IScriptSnapshots. Incremental: subsequent getProgram() calls reuse parsed ASTs and checker state for unchanged files. Used by createAnalysisSession (in session.ts).

@see typescript-exports.ts for analyzeExports, analyzeDeclaration @see typescript-extract-*.ts for the per-declaration extractors @see session.ts for createAnalysisSession, the high-level incremental API

view source

Declarations
#

14 declarations

AnalysisLanguageService
#

typescript-program.ts view source

AnalysisLanguageService import type {AnalysisLanguageService} from 'svelte-docinfo/typescript-program.js';

Persistent language-service handle that drives a ts.Program incrementally.

Owns the LS, document registry, and a `Map<path, {content, version, scriptKind}>` of "owned" files (real source files + virtuals pushed via setFile). Files not in the owned map are read from disk on demand by the LS host.

Each setFile(path, entry) bumps the version when content or script kind differs from cache, so the next getProgram() reparses only the changed file. Calling getProgram() with no version bumps returns the same ts.Program as the previous call (reference-stable when nothing changed).

see also

  • ``createAnalysisSession`` in session.ts for the high-level API that wraps this with content cache + svelte virtual cache + analysis pipeline.

getProgram

Get the current ts.Program.

Returns the same reference as the previous call when no setFile / deleteFile invalidated state in between. Returns a fresh ts.Program (sharing parsed ASTs for unchanged files via the document registry) when versions changed.

type (): Program

returns Program

throws

  • Error - if the underlying LS returned undefined (should not happen

getCompilerOptions

The merged compiler options the service was constructed with — parsed tsconfig with the caller's compilerOptions overrides applied per-key.

Cheap accessor over the construction-time loadTsconfig result; prefer it over getProgram().getCompilerOptions() when only the options are needed — getProgram() forces the LS to sync and parse every root file.

Treat the returned object as read-only: it is the same reference the LS host serves via getCompilationSettings, so mutating it would desync consumers (e.g., the session's default import resolver) from the checker.

type (): CompilerOptions

returns CompilerOptions

setFile

Set or replace a file's content (real path or virtual path).

  • New file: added to the owned map with version 1.
  • Existing file with identical content and script kind: no-op (version unchanged).
  • Existing file with new content or script kind: version bumped.

type (path: string, entry: VirtualFileEntry): boolean

path

type string

entry

returns boolean

true when the file was added or its version bumped, false on no-op.

deleteFile

Remove a file from the owned set.

type (path: string): boolean

path

type string
returns boolean

true when the file was tracked, false when it was unknown.

hasFile

Whether the given path is currently tracked.

type (path: string): boolean

path

type string
returns boolean

dispose

Release LS resources.

Calls ts.LanguageService.dispose() and clears the owned map. The service must not be used after disposal.

type (): void

returns void

AnalysisLanguageServiceOptions
#

typescript-program.ts view source

AnalysisLanguageServiceOptions import type {AnalysisLanguageServiceOptions} from 'svelte-docinfo/typescript-program.js';

inheritance

documentRegistry?

Optional document registry for AST sharing across services.

Pass an explicit registry to share parsed source files when running multiple language services (e.g., LSP integration). Defaults to a fresh registry per service when omitted.

type DocumentRegistry

AnalysisProgramOptions
#

typescript-program.ts view source

AnalysisProgramOptions import type {AnalysisProgramOptions} from 'svelte-docinfo/typescript-program.js';

inheritance

virtualFiles?

Virtual files to seed the program, keyed by virtual path.

Used to include svelte2tsx transformed outputs alongside real source files, enabling full type resolution for Svelte components via the checker. SvelteVirtualFile satisfies the entry shape structurally, so transform results can be passed as entries directly.

On a LanguageService, virtuals can also be added/replaced/removed after construction via setFile / deleteFile.

type Map<string, VirtualFileEntry>

applyVirtualFiles
#

typescript-program.ts view source

(host: CompilerHost, virtualFiles: ReadonlyMap<string, VirtualFileEntry>): ReadonlyMap<string, VirtualFileEntry> import {applyVirtualFiles} from 'svelte-docinfo/typescript-program.js';

Decorate a compiler host so virtualFiles shadow the filesystem — getSourceFile (honoring per-entry scriptKind), fileExists, readFile, and directoryExists.

Entries are copied to minimal {content, scriptKind} records so the host's closures don't retain larger caller objects (a SvelteVirtualFile's source map, say) for the program's lifetime. The copied map is returned so callers layering module resolution on top (.svelte specifier mapping) can key it off the same snapshot instead of re-capturing the caller's map. The entry set is fixed at decoration time — the returned ReadonlyMap and the directory index are built in the same pass, so no host answer can be served from a staler view of the set than another (a LanguageService is the mutable counterpart; see createAnalysisLanguageService).

host

type CompilerHost

virtualFiles

type ReadonlyMap<string, VirtualFileEntry>

returns

ReadonlyMap<string, VirtualFileEntry>

the copied entries, keyed by path

mutates

  • host — replaces `getSourceFile`, `fileExists`, `readFile`, and

createAnalysisLanguageService
#

typescript-program.ts view source

(options?: AnalysisLanguageServiceOptions | undefined, log?: AnalysisLog | undefined): AnalysisLanguageService import {createAnalysisLanguageService} from 'svelte-docinfo/typescript-program.js';

Create a persistent language service for incremental analysis.

The LS owns parsed source ASTs and checker state across calls. Use the returned handle to push file-content updates (setFile / deleteFile) between analysis passes; subsequent getProgram() calls return either the same ts.Program (no changes since last call) or a fresh one that reuses unchanged files via the document registry.

options?

configuration options

optional

log?

optional logger for info messages

optional

returns

AnalysisLanguageService

the language service handle

throws

  • Error - if tsconfig.json is not found

examples

const ls = createAnalysisLanguageService({projectRoot}); ls.setFile('/abs/path/to/foo.ts', {content: 'export const x = 1;'}); const program = ls.getProgram(); // ... use program ... ls.setFile('/abs/path/to/foo.ts', {content: 'export const x = 2;'}); // bumps version const program2 = ls.getProgram(); // fresh program, foo.ts reparsed ls.dispose();

createAnalysisProgram
#

typescript-program.ts view source

(options?: AnalysisProgramOptions | undefined, log?: AnalysisLog | undefined): Program import {createAnalysisProgram} from 'svelte-docinfo/typescript-program.js';

Create TypeScript program for one-shot analysis.

Use createAnalysisLanguageService instead when you need to analyze the same source set multiple times — the LS path reuses parsed ASTs and checker state across calls.

options?

configuration options for program creation

optional

log?

optional logger for info messages

optional

returns

Program

the TypeScript program

throws

  • Error - if tsconfig.json is not found

examples

const program = createAnalysisProgram({projectRoot: process.cwd()});

createIsExternalFile
#

createIsExternalPath
#

typescript-program.ts view source

(options: ModuleSourceOptions): (file: string) => boolean import {createIsExternalPath} from 'svelte-docinfo/typescript-program.js';

Path-string counterpart of IsExternalFile, for call sites that hold a file path rather than a ts.SourceFile (re-export classification). Same rule, with declaration-file suffixes standing in for isDeclarationFile.

Deliberately distinct from isSource: isSource answers "does this file emit a module?" while this answers "is this file outside the project?" — an in-root file can fail isSource (the src/lib/internal/ convention, user excludes) while remaining project-local, and conflating the two mis-files project-local re-exports as external-package facts.

options

returns

(file: string) => boolean

createOwnedDirIndex
#

IsExternalFile
#

typescript-program.ts view source

IsExternalFile import type {IsExternalFile} from 'svelte-docinfo/typescript-program.js';

Predicate for determining whether a TypeScript source file is external to the project. Used by intersection type filtering to separate user-authored properties from library/framework properties.

Constructed from ModuleSourceOptions at analysis entry points — files under the source root (e.g., src/lib/) are internal, everything else is external.

(call)

type (sourceFile: SourceFile): boolean

sourceFile

type SourceFile
returns boolean

loadTsconfig
#

typescript-program.ts view source

(options?: LoadTsconfigOptions | undefined, log?: AnalysisLog | undefined): { compilerOptions: CompilerOptions; rootFileNames: string[]; } import {loadTsconfig} from 'svelte-docinfo/typescript-program.js';

Load and parse tsconfig.json into compiler options + initial file list.

Shared by createAnalysisProgram and createAnalysisLanguageService so tsconfig-resolution behavior stays identical across the two paths. Also useful directly when a caller needs only CompilerOptions (e.g., import resolution via ts.resolveModuleName) without the cost of building a full ts.Program.

options?

optional

log?

optional

returns

{ compilerOptions: CompilerOptions; rootFileNames: string[]; }

throws

  • Error - if tsconfig.json (or the requested `tsconfigName`) is not found.

LoadTsconfigOptions
#

typescript-program.ts view source

LoadTsconfigOptions import type {LoadTsconfigOptions} from 'svelte-docinfo/typescript-program.js';

Base configuration shared by every entry point in this module.

projectRoot + tsconfig + compilerOptions together drive loadTsconfig, which is also exposed publicly. AnalysisProgramOptions and AnalysisLanguageServiceOptions extend this with their own fields.

projectRoot?

Absolute path to project root directory.

type string

default process.cwd()

tsconfig?

Path to tsconfig.json (relative to projectRoot).

type string

default 'tsconfig.json'

compilerOptions?

Compiler options merged on top of those parsed from tsconfig.json (per-key override; user-supplied keys win). Does not bypass the tsconfig.json file requirement — loadTsconfig still throws when no config file is found.

type CompilerOptions

OwnedDirIndex
#

typescript-program.ts view source

OwnedDirIndex import type {OwnedDirIndex} from 'svelte-docinfo/typescript-program.js';

Ancestor-directory index over a path set, maintained as the set mutates.

Module resolution probes directoryExists before trying file candidates inside it (directoryProbablyExists): a directory reported absent has every candidate recorded as a failed lookup with fileExists never consulted, so a directory that exists only as the prefix of served in-memory paths must report present. Refcounted per ancestor so removal is exact — O(path depth) per mutation, O(1) per query; a per-probe scan of the path set would multiply into resolution's hot path (bare-specifier resolution walks many nonexistent ancestor node_modules directories per import).

The index owns its path set, so add/remove are idempotent and a caller can't skew the refcounts by double-adding or by removing something it never added (which would drop an ancestor still holding live paths). Membership bookkeeping therefore stays here rather than in each caller's guard.

add

Count path's ancestor directories into the index. Idempotent.

type (path: string): void

path

type string
returns void

remove

Reverse of add; a path that isn't indexed is a no-op.

type (path: string): void

path

type string
returns void

has

Whether dir is an ancestor of any indexed path (trailing slash tolerated).

type (dir: string): boolean

dir

type string
returns boolean

clear

type (): void

returns void

VirtualFileEntry
#

typescript-program.ts view source

VirtualFileEntry import type {VirtualFileEntry} from 'svelte-docinfo/typescript-program.js';

A host-served file entry: content plus optional parser treatment.

content

type string

scriptKind?

Overrides script-kind inference from the path's extension; undefined defers to the extension.

type ScriptKind

Depends on
#

Imported by
#