/**
* 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 `IScriptSnapshot`s. 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
*
* @module
*/
import {join, dirname} from 'node:path';
import ts from 'typescript';
import type {AnalysisLog} from './log.js';
import {SVELTE_VIRTUAL_SUFFIX} from './source.js';
import {type ModuleSourceOptions, getSourceRoot} from './source-config.js';
import {toPosixPath} from './paths.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.
*/
export interface LoadTsconfigOptions {
/**
* Absolute path to project root directory.
* @default process.cwd()
*/
projectRoot?: string;
/**
* Path to tsconfig.json (relative to `projectRoot`).
* @default 'tsconfig.json'
*/
tsconfig?: string;
/**
* 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.
*/
compilerOptions?: ts.CompilerOptions;
}
/**
* Options for `createAnalysisProgram`.
*/
export interface AnalysisProgramOptions extends LoadTsconfigOptions {
/**
* Virtual files to seed the program (maps virtual path to content).
*
* Used to include svelte2tsx transformed outputs alongside real source files,
* enabling full type resolution for Svelte components via the checker.
*
* On a `LanguageService`, virtuals can also be added/replaced/removed after
* construction via `setFile` / `deleteFile`.
*/
virtualFiles?: Map<string, string>;
}
/**
* Options for `createAnalysisLanguageService`.
*/
export interface AnalysisLanguageServiceOptions extends AnalysisProgramOptions {
/**
* 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.
*/
documentRegistry?: ts.DocumentRegistry;
}
/**
* Persistent language-service handle that drives a `ts.Program` incrementally.
*
* Owns the LS, document registry, and a `Map<path, {content, version}>` 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, content)` bumps the version when content 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 `createAnalysisSession` in `session.ts` for the high-level API that
* wraps this with content cache + svelte virtual cache + analysis pipeline.
*/
export interface AnalysisLanguageService {
/**
* 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.
*
* @throws Error if the underlying LS returned undefined (should not happen
* in practice — TS only returns undefined during initialization)
*/
getProgram(): ts.Program;
/**
* 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: no-op (version unchanged).
* - Existing file with new content: version bumped.
*
* @returns `true` when the file was added or its version bumped, `false` on no-op.
*/
setFile(path: string, content: string): boolean;
/**
* Remove a file from the owned set.
*
* @returns `true` when the file was tracked, `false` when it was unknown.
*/
deleteFile(path: string): boolean;
/** Whether the given path is currently tracked. */
hasFile(path: string): boolean;
/**
* Release LS resources.
*
* Calls `ts.LanguageService.dispose()` and clears the owned map. The
* service must not be used after disposal.
*/
dispose(): void;
}
/**
* 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`.
*
* @throws Error if tsconfig.json (or the requested `tsconfigName`) is not found.
*/
export const loadTsconfig = (
options?: LoadTsconfigOptions,
log?: AnalysisLog,
): {compilerOptions: ts.CompilerOptions; rootFileNames: Array<string>} => {
const projectRoot = options?.projectRoot ?? process.cwd();
const tsconfigName = options?.tsconfig ?? 'tsconfig.json';
const configPath = ts.findConfigFile(projectRoot, ts.sys.fileExists, tsconfigName);
if (!configPath) {
throw new Error(`No ${tsconfigName} found in ${projectRoot}`);
}
log?.info(`using ${configPath}`);
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, projectRoot);
const compilerOptions = options?.compilerOptions
? {...parsedConfig.options, ...options.compilerOptions}
: parsedConfig.options;
return {compilerOptions, rootFileNames: parsedConfig.fileNames};
};
/**
* Resolve `.svelte` import specifiers to their virtual `.__svelte2tsx__.ts` paths.
*
* Shared between the `CompilerHost` and `LanguageServiceHost` paths so cross-Svelte
* re-exports (`export {X} from './Other.svelte'`) work uniformly. Returns `undefined`
* for non-Svelte specifiers; the caller falls back to default module resolution.
*/
const resolveSvelteVirtualSpecifier = (
specifier: string,
containingFile: string,
hasVirtual: (path: string) => boolean,
): ts.ResolvedModuleFull | undefined => {
if (!specifier.startsWith('.') || !specifier.endsWith('.svelte')) return undefined;
// `join`/`dirname` return native separators on Windows. Posixify so the
// `hasVirtual` lookup hits the POSIX-keyed virtual map populated by
// session ingest.
const resolved = toPosixPath(join(dirname(containingFile), specifier)) + SVELTE_VIRTUAL_SUFFIX;
if (!hasVirtual(resolved)) return undefined;
return {
resolvedFileName: resolved,
isExternalLibraryImport: false,
extension: ts.Extension.Ts,
};
};
/**
* 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.
*
* @param options - configuration options for program creation
* @param log - optional logger for info messages
* @returns the TypeScript program
* @throws Error if tsconfig.json is not found
*
* @example
* ```ts
* const program = createAnalysisProgram({projectRoot: process.cwd()});
* ```
*/
export const createAnalysisProgram = (
options?: AnalysisProgramOptions,
log?: AnalysisLog,
): ts.Program => {
const {compilerOptions, rootFileNames} = loadTsconfig(options, log);
const virtualFiles = options?.virtualFiles;
if (!virtualFiles || virtualFiles.size === 0) {
return ts.createProgram(rootFileNames, compilerOptions);
}
// Include virtual file paths alongside real files
const allRootFiles = [...rootFileNames, ...virtualFiles.keys()];
const host = ts.createCompilerHost(compilerOptions);
const originalGetSourceFile = host.getSourceFile;
const originalFileExists = host.fileExists;
const originalReadFile = host.readFile;
host.getSourceFile = (fileName, languageVersion, onError, shouldCreate) => {
const virtualContent = virtualFiles.get(fileName);
if (virtualContent !== undefined) {
return ts.createSourceFile(fileName, virtualContent, languageVersion, true);
}
return originalGetSourceFile.call(host, fileName, languageVersion, onError, shouldCreate);
};
host.fileExists = (fileName) => {
if (virtualFiles.has(fileName)) return true;
return originalFileExists.call(host, fileName);
};
host.readFile = (fileName) => {
const virtualContent = virtualFiles.get(fileName);
if (virtualContent !== undefined) return virtualContent;
return originalReadFile.call(host, fileName);
};
host.resolveModuleNameLiterals = (literals, containingFile, _redirected, optionsInner) => {
return literals.map((literal) => {
const resolved = resolveSvelteVirtualSpecifier(literal.text, containingFile, (p) =>
virtualFiles.has(p),
);
if (resolved) return {resolvedModule: resolved};
return ts.resolveModuleName(literal.text, containingFile, optionsInner, host);
});
};
return ts.createProgram(allRootFiles, compilerOptions, host);
};
/**
* 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.
*
* @param options - configuration options
* @param log - optional logger for info messages
* @returns the language service handle
* @throws Error if tsconfig.json is not found
*
* @example
* ```ts
* const ls = createAnalysisLanguageService({projectRoot});
* ls.setFile('/abs/path/to/foo.ts', 'export const x = 1;');
* const program = ls.getProgram();
* // ... use program ...
* ls.setFile('/abs/path/to/foo.ts', 'export const x = 2;'); // bumps version
* const program2 = ls.getProgram(); // fresh program, foo.ts reparsed
* ls.dispose();
* ```
*/
export const createAnalysisLanguageService = (
options?: AnalysisLanguageServiceOptions,
log?: AnalysisLog,
): AnalysisLanguageService => {
const projectRoot = options?.projectRoot ?? process.cwd();
const {compilerOptions, rootFileNames} = loadTsconfig(options, log);
const documentRegistry = options?.documentRegistry ?? ts.createDocumentRegistry();
interface OwnedFile {
content: string;
version: number;
snapshot: ts.IScriptSnapshot;
}
const owned = new Map<string, OwnedFile>();
// Root file names from tsconfig — kept as a Set for fast membership checks
// during deleteFile (so a deleted owned file that was *also* in tsconfig
// stays in the program's root set, falling through to disk).
const tsconfigRoots = new Set<string>(rootFileNames);
// Virtual roots (e.g., `.__svelte2tsx__.ts` paths) added via `setFile`.
// Tracked separately so `deleteFile` can drop them from the LS's root list.
const ownedRoots = new Set<string>();
const setFileInternal = (path: string, content: string): boolean => {
const existing = owned.get(path);
if (existing && existing.content === content) return false;
owned.set(path, {
content,
version: existing ? existing.version + 1 : 1,
snapshot: ts.ScriptSnapshot.fromString(content),
});
if (!tsconfigRoots.has(path)) ownedRoots.add(path);
return true;
};
// Seed initial virtuals from options. Common path for one-shot callers.
if (options?.virtualFiles) {
for (const [path, content] of options.virtualFiles) {
setFileInternal(path, content);
}
}
// Combined module-resolution host — used both as the LS host's resolution
// surface and (cast) as the fallback host for `ts.resolveModuleName`. Owned
// content takes precedence over `ts.sys` so virtuals resolve correctly.
const moduleResolutionHost: ts.ModuleResolutionHost = {
fileExists: (path) => owned.has(path) || ts.sys.fileExists(path),
readFile: (path) => {
const entry = owned.get(path);
if (entry) return entry.content;
return ts.sys.readFile(path);
},
directoryExists: ts.sys.directoryExists,
getCurrentDirectory: () => projectRoot,
getDirectories: ts.sys.getDirectories,
realpath: ts.sys.realpath,
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
};
const host: ts.LanguageServiceHost = {
getCompilationSettings: () => compilerOptions,
getScriptFileNames: () => {
// Combine tsconfig roots with owned virtual roots. Set semantics
// dedupe when an owned file was also a tsconfig root.
if (ownedRoots.size === 0) return [...tsconfigRoots];
const combined = new Set(tsconfigRoots);
for (const path of ownedRoots) combined.add(path);
return [...combined];
},
getScriptVersion: (fileName) => {
const entry = owned.get(fileName);
// External / disk-only files: stable version. We don't watch them;
// the LS reads them once into the document registry.
return entry ? String(entry.version) : '1';
},
getScriptSnapshot: (fileName) => {
const entry = owned.get(fileName);
if (entry) return entry.snapshot;
if (!ts.sys.fileExists(fileName)) return undefined;
const content = ts.sys.readFile(fileName);
if (content === undefined) return undefined;
return ts.ScriptSnapshot.fromString(content);
},
getCurrentDirectory: () => projectRoot,
getDefaultLibFileName: ts.getDefaultLibFilePath,
fileExists: moduleResolutionHost.fileExists,
readFile: moduleResolutionHost.readFile,
directoryExists: moduleResolutionHost.directoryExists,
getDirectories: moduleResolutionHost.getDirectories,
readDirectory: ts.sys.readDirectory,
realpath: moduleResolutionHost.realpath,
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
resolveModuleNameLiterals: (literals, containingFile, _redirected, optionsInner) => {
return literals.map((literal) => {
const resolved = resolveSvelteVirtualSpecifier(literal.text, containingFile, (p) =>
owned.has(p),
);
if (resolved) return {resolvedModule: resolved};
return ts.resolveModuleName(
literal.text,
containingFile,
optionsInner,
moduleResolutionHost,
);
});
},
};
const ls = ts.createLanguageService(host, documentRegistry);
const getProgram = (): ts.Program => {
const program = ls.getProgram();
if (!program) {
throw new Error('LanguageService.getProgram() returned undefined');
}
return program;
};
const setFile = (path: string, content: string): boolean => setFileInternal(path, content);
const deleteFile = (path: string): boolean => {
const removed = owned.delete(path);
ownedRoots.delete(path);
return removed;
};
const hasFile = (path: string): boolean => owned.has(path);
const dispose = (): void => {
ls.dispose();
owned.clear();
ownedRoots.clear();
};
return {getProgram, setFile, deleteFile, hasFile, dispose};
};
/**
* 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.
*/
export type IsExternalFile = (sourceFile: ts.SourceFile) => boolean;
/**
* Create an `IsExternalFile` predicate from `ModuleSourceOptions`.
*
* A file is external if it is:
* - Outside the project root
* - Inside `node_modules/`
* - A `.d.ts` declaration file outside the source root (catches framework-generated
* declarations like `.svelte-kit/non-ambient.d.ts` while keeping user `.d.ts` files
* in the source tree)
*/
export const createIsExternalFile = (options: ModuleSourceOptions): IsExternalFile => {
const projectPrefix = options.projectRoot + '/';
const effectiveRoot = getSourceRoot(options);
const sourcePrefix = effectiveRoot ? projectPrefix + effectiveRoot + '/' : projectPrefix;
return (sf) =>
!sf.fileName.startsWith(projectPrefix) ||
sf.fileName.includes('/node_modules/') ||
(sf.isDeclarationFile && !sf.fileName.startsWith(sourcePrefix));
};
{
"path": "typescript-program.ts",
"declarations": [
{
"name": "LoadTsconfigOptions",
"kind": "interface",
"docComment": "Base configuration shared by every entry point in this module.\n\n`projectRoot` + `tsconfig` + `compilerOptions` together drive `loadTsconfig`,\nwhich is also exposed publicly. `AnalysisProgramOptions` and\n`AnalysisLanguageServiceOptions` extend this with their own fields.",
"typeSignature": "LoadTsconfigOptions",
"sourceLine": 37,
"members": [
{
"name": "projectRoot",
"kind": "variable",
"docComment": "Absolute path to project root directory.",
"typeSignature": "string",
"optional": true,
"defaultValue": "process.cwd()"
},
{
"name": "tsconfig",
"kind": "variable",
"docComment": "Path to tsconfig.json (relative to `projectRoot`).",
"typeSignature": "string",
"optional": true,
"defaultValue": "'tsconfig.json'"
},
{
"name": "compilerOptions",
"kind": "variable",
"docComment": "Compiler options merged on top of those parsed from `tsconfig.json`\n(per-key override; user-supplied keys win). Does not bypass the\n`tsconfig.json` file requirement — `loadTsconfig` still throws when no\nconfig file is found.",
"typeSignature": "ts.CompilerOptions",
"optional": true
}
]
},
{
"name": "AnalysisProgramOptions",
"kind": "interface",
"docComment": "Options for `createAnalysisProgram`.",
"typeSignature": "AnalysisProgramOptions",
"sourceLine": 60,
"extends": [
"LoadTsconfigOptions"
],
"members": [
{
"name": "virtualFiles",
"kind": "variable",
"docComment": "Virtual files to seed the program (maps virtual path to content).\n\nUsed to include svelte2tsx transformed outputs alongside real source files,\nenabling full type resolution for Svelte components via the checker.\n\nOn a `LanguageService`, virtuals can also be added/replaced/removed after\nconstruction via `setFile` / `deleteFile`.",
"typeSignature": "Map<string, string>",
"optional": true
}
]
},
{
"name": "AnalysisLanguageServiceOptions",
"kind": "interface",
"docComment": "Options for `createAnalysisLanguageService`.",
"typeSignature": "AnalysisLanguageServiceOptions",
"sourceLine": 76,
"extends": [
"AnalysisProgramOptions"
],
"members": [
{
"name": "documentRegistry",
"kind": "variable",
"docComment": "Optional document registry for AST sharing across services.\n\nPass an explicit registry to share parsed source files when running\nmultiple language services (e.g., LSP integration). Defaults to a fresh\nregistry per service when omitted.",
"typeSignature": "ts.DocumentRegistry",
"optional": true
}
]
},
{
"name": "AnalysisLanguageService",
"kind": "interface",
"docComment": "Persistent language-service handle that drives a `ts.Program` incrementally.\n\nOwns the LS, document registry, and a `Map<path, {content, version}>` of\n\"owned\" files (real source files + virtuals pushed via `setFile`). Files\nnot in the owned map are read from disk on demand by the LS host.\n\nEach `setFile(path, content)` bumps the version when content differs from\ncache, so the next `getProgram()` reparses only the changed file. Calling\n`getProgram()` with no version bumps returns the same `ts.Program` as the\nprevious call (reference-stable when nothing changed).",
"typeSignature": "AnalysisLanguageService",
"sourceLine": 102,
"seeAlso": [
"`createAnalysisSession` in `session.ts` for the high-level API that wraps this with content cache + svelte virtual cache + analysis pipeline."
],
"members": [
{
"name": "getProgram",
"kind": "function",
"docComment": "Get the current `ts.Program`.\n\nReturns the same reference as the previous call when no `setFile` /\n`deleteFile` invalidated state in between. Returns a fresh `ts.Program`\n(sharing parsed ASTs for unchanged files via the document registry) when\nversions changed.",
"typeSignature": "(): Program",
"throws": [
{
"type": "Error",
"description": "if the underlying LS returned undefined (should not happen"
}
],
"returnType": "Program"
},
{
"name": "setFile",
"kind": "function",
"docComment": "Set or replace a file's content (real path or virtual path).\n\n- New file: added to the owned map with version 1.\n- Existing file with identical content: no-op (version unchanged).\n- Existing file with new content: version bumped.",
"typeSignature": "(path: string, content: string): boolean",
"parameters": [
{
"name": "path",
"type": "string"
},
{
"name": "content",
"type": "string"
}
],
"returnType": "boolean",
"returnDescription": "`true` when the file was added or its version bumped, `false` on no-op."
},
{
"name": "deleteFile",
"kind": "function",
"docComment": "Remove a file from the owned set.",
"typeSignature": "(path: string): boolean",
"parameters": [
{
"name": "path",
"type": "string"
}
],
"returnType": "boolean",
"returnDescription": "`true` when the file was tracked, `false` when it was unknown."
},
{
"name": "hasFile",
"kind": "function",
"docComment": "Whether the given path is currently tracked.",
"typeSignature": "(path: string): boolean",
"parameters": [
{
"name": "path",
"type": "string"
}
],
"returnType": "boolean"
},
{
"name": "dispose",
"kind": "function",
"docComment": "Release LS resources.\n\nCalls `ts.LanguageService.dispose()` and clears the owned map. The\nservice must not be used after disposal.",
"typeSignature": "(): void",
"returnType": "void"
}
]
},
{
"name": "loadTsconfig",
"kind": "function",
"docComment": "Load and parse tsconfig.json into compiler options + initial file list.\n\nShared by `createAnalysisProgram` and `createAnalysisLanguageService` so\ntsconfig-resolution behavior stays identical across the two paths. Also\nuseful directly when a caller needs only `CompilerOptions` (e.g., import\nresolution via `ts.resolveModuleName`) without the cost of building a full\n`ts.Program`.",
"typeSignature": "(options?: LoadTsconfigOptions | undefined, log?: AnalysisLog | undefined): { compilerOptions: CompilerOptions; rootFileNames: string[]; }",
"sourceLine": 153,
"throws": [
{
"type": "Error",
"description": "if tsconfig.json (or the requested `tsconfigName`) is not found."
}
],
"parameters": [
{
"name": "options",
"type": "LoadTsconfigOptions | undefined",
"optional": true
},
{
"name": "log",
"type": "AnalysisLog | undefined",
"optional": true
}
],
"returnType": "{ compilerOptions: CompilerOptions; rootFileNames: string[]; }"
},
{
"name": "createAnalysisProgram",
"kind": "function",
"docComment": "Create TypeScript program for one-shot analysis.\n\nUse `createAnalysisLanguageService` instead when you need to analyze the\nsame source set multiple times — the LS path reuses parsed ASTs and checker\nstate across calls.",
"typeSignature": "(options?: AnalysisProgramOptions | undefined, log?: AnalysisLog | undefined): Program",
"sourceLine": 219,
"examples": [
"```ts\nconst program = createAnalysisProgram({projectRoot: process.cwd()});\n```"
],
"throws": [
{
"type": "Error",
"description": "if tsconfig.json is not found"
}
],
"parameters": [
{
"name": "options",
"type": "AnalysisProgramOptions | undefined",
"optional": true,
"description": "configuration options for program creation"
},
{
"name": "log",
"type": "AnalysisLog | undefined",
"optional": true,
"description": "optional logger for info messages"
}
],
"returnType": "Program",
"returnDescription": "the TypeScript program"
},
{
"name": "createAnalysisLanguageService",
"kind": "function",
"docComment": "Create a persistent language service for incremental analysis.\n\nThe LS owns parsed source ASTs and checker state across calls. Use the\nreturned handle to push file-content updates (`setFile` / `deleteFile`)\nbetween analysis passes; subsequent `getProgram()` calls return either the\nsame `ts.Program` (no changes since last call) or a fresh one that reuses\nunchanged files via the document registry.",
"typeSignature": "(options?: AnalysisLanguageServiceOptions | undefined, log?: AnalysisLog | undefined): AnalysisLanguageService",
"sourceLine": 295,
"examples": [
"```ts\nconst ls = createAnalysisLanguageService({projectRoot});\nls.setFile('/abs/path/to/foo.ts', 'export const x = 1;');\nconst program = ls.getProgram();\n// ... use program ...\nls.setFile('/abs/path/to/foo.ts', 'export const x = 2;'); // bumps version\nconst program2 = ls.getProgram(); // fresh program, foo.ts reparsed\nls.dispose();\n```"
],
"throws": [
{
"type": "Error",
"description": "if tsconfig.json is not found"
}
],
"parameters": [
{
"name": "options",
"type": "AnalysisLanguageServiceOptions | undefined",
"optional": true,
"description": "configuration options"
},
{
"name": "log",
"type": "AnalysisLog | undefined",
"optional": true,
"description": "optional logger for info messages"
}
],
"returnType": "AnalysisLanguageService",
"returnDescription": "the language service handle"
},
{
"name": "IsExternalFile",
"kind": "type",
"docComment": "Predicate for determining whether a TypeScript source file is external to the project.\nUsed by intersection type filtering to separate user-authored properties from\nlibrary/framework properties.\n\nConstructed from `ModuleSourceOptions` at analysis entry points — files under the\nsource root (e.g., `src/lib/`) are internal, everything else is external.",
"typeSignature": "IsExternalFile",
"sourceLine": 439,
"members": [
{
"name": "(call)",
"kind": "function",
"typeSignature": "(sourceFile: SourceFile): boolean",
"parameters": [
{
"name": "sourceFile",
"type": "SourceFile"
}
],
"returnType": "boolean"
}
]
},
{
"name": "createIsExternalFile",
"kind": "function",
"docComment": "Create an `IsExternalFile` predicate from `ModuleSourceOptions`.\n\nA file is external if it is:\n- Outside the project root\n- Inside `node_modules/`\n- A `.d.ts` declaration file outside the source root (catches framework-generated\n declarations like `.svelte-kit/non-ambient.d.ts` while keeping user `.d.ts` files\n in the source tree)",
"typeSignature": "(options: ModuleSourceOptions): IsExternalFile",
"sourceLine": 451,
"parameters": [
{
"name": "options",
"type": "ModuleSourceOptions"
}
],
"returnType": "IsExternalFile"
}
],
"moduleComment": "TypeScript program and language-service creation.\n\nTwo entry points sharing host configuration (tsconfig parsing, virtual file\nplumbing, `.svelte` module resolution):\n\n- `createAnalysisProgram` — one-shot `ts.Program` from a `ts.CompilerHost`.\n Lower-level escape hatch for power users + dependency resolution. Does not\n support incremental updates.\n- `createAnalysisLanguageService` — persistent `ts.LanguageService` with\n versioned `IScriptSnapshot`s. Incremental: subsequent `getProgram()` calls\n reuse parsed ASTs and checker state for unchanged files. Used by\n `createAnalysisSession` (in `session.ts`).\n\n@see `typescript-exports.ts` for `analyzeExports`, `analyzeDeclaration`\n@see `typescript-extract-*.ts` for the per-declaration extractors\n@see `session.ts` for `createAnalysisSession`, the high-level incremental API",
"dependencies": [
"log.ts",
"paths.ts",
"source-config.ts",
"source.ts"
],
"dependents": [
"session.ts",
"svelte.ts",
"typescript-exports.ts",
"typescript-extract-shared.ts",
"typescript-extract-type-properties.ts",
"typescript-extract-type.ts"
]
}