typescript
Version:
TypeScript is a language for application scale JavaScript development
5,465 lines • 231 kB
JavaScript
import { apiRequest, cacheGeneratorMethod, } from "./generatorSupport.js";
import { CheckFlags } from "../../../enums/checkFlags.js";
import { CompletionItemKind } from "../../../enums/completionItemKind.js";
import { DiagnosticCategory } from "../../../enums/diagnosticCategory.js";
import { ElementFlags } from "../../../enums/elementFlags.js";
import { EmitOnly } from "../../../enums/emitOnly.js";
import { IndexKind } from "../../../enums/indexKind.js";
import { JsxEmit } from "../../../enums/jsxEmit.js";
import { ModuleKind } from "../../../enums/moduleKind.js";
import { ModuleResolutionKind } from "../../../enums/moduleResolutionKind.js";
import { NewLineKind } from "../../../enums/newLineKind.js";
import { NodeBuilderFlags } from "../../../enums/nodeBuilderFlags.js";
import { ObjectFlags } from "../../../enums/objectFlags.js";
import { ScriptKind } from "../../../enums/scriptKind.js";
import { SignatureFlags } from "../../../enums/signatureFlags.js";
import { SignatureKind } from "../../../enums/signatureKind.js";
import { SymbolFlags } from "../../../enums/symbolFlags.js";
import { SymbolOwnerKind } from "../../../enums/symbolOwnerKind.js";
import { TypeFlags } from "../../../enums/typeFlags.js";
import { TypeFormatFlags } from "../../../enums/typeFormatFlags.js";
import { TypePredicateKind } from "../../../enums/typePredicateKind.js";
import { ModifierFlags, unescapeLeadingUnderscores, } from "../../ast/index.js";
import { assertNever } from "../../internal/utils.js";
import { encodeNode, uint8ArrayToBase64, } from "../node/encoder.js";
import { decodeNode, getNodeId, getNodeRequestHandle, parseNodeHandleFromCompiler, readParseOptionsKey, readSourceFileHash, readSourceFileLease, RemoteNode, RemoteSourceFile, } from "../node/node.js";
import { Wtf8Decoder } from "../node/wtf8.js";
import { canonicalize, CaseSensitivity, pathKey, toRootedDirectoryPath, toRootedPath, } from "../path.js";
import { prepareCompilerOptions } from "../prepareCompilerOptions.generated.js";
import { resolveFileName, validateSymbolResponse, } from "../proto.js";
import { SourceFileCache, } from "../sourceFileCache.js";
import { Client, } from "./client.js";
export { formatDiagnostics, formatDiagnosticsWithColorAndContext } from "../diagnosticFormatter.js";
export { documentURIToFileName, fileNameToDocumentURI } from "../path.js";
export { CheckFlags, CompletionItemKind, DiagnosticCategory, ElementFlags, EmitOnly, IndexKind, JsxEmit, ModifierFlags, ModuleKind, ModuleResolutionKind, NodeBuilderFlags, ObjectFlags, ScriptKind, SignatureFlags, SignatureKind, SymbolFlags, SymbolOwnerKind, TypeFlags, TypeFormatFlags, TypePredicateKind };
let nextModuleResolutionCallbackId = 0;
function registerModuleResolutionCallback(client, callback, getSnapshot) {
const name = `resolveModuleName/${++nextModuleResolutionCallbackId}`;
const dispose = client.registerCallback(name, params => {
const { moduleName, containingDirectory, resolutionMode, snapshot: snapshotId, inProgressSnapshot } = params;
let snapshot = snapshotId === undefined ? undefined : getSnapshot(snapshotId);
if (snapshotId !== undefined && snapshot === undefined) {
throw new Error(`Snapshot ${snapshotId} is inactive`);
}
if (inProgressSnapshot !== undefined) {
snapshot = -inProgressSnapshot;
}
return callback(moduleName, containingDirectory, resolutionMode, { snapshot });
});
return { name, dispose };
}
export { all, defer } from "./generatorSupport.js";
import { sourceFileResponseToUint8Array } from "../node/encoder.js";
import { executeRequestGenerators, } from "./generatorSupport.js";
export class API {
/** @internal */
client;
/** @internal */
sourceFileCache;
toPath;
decoder = new Wtf8Decoder();
currentDirectory;
caseSensitivity;
initialized = false;
initializing;
activeSnapshots = new Map();
activeBuildOrchestrators = new Set();
activeSourceFileLeases = new Map();
printer;
debug;
constructor(options = {}) {
this.client = new Client(options);
this.sourceFileCache = new SourceFileCache();
this.printer = new Printer(this.client);
this.debug = new DebugHandlers(this.client, this.ensureInitialized);
}
/**
* Looks up a remote declaration's binder symbol. Throws for synthesized or configuration ASTs.
*/
get getSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getSymbol", function (declaration) {
const file = getRemoteSourceFile(declaration);
if (!file)
throw new Error(`Source file not found for declaration`);
const record = file.symbolCache;
if (!record)
throw new Error(`Cached source file not found for declaration`);
const index = parseNodeHandleFromCompiler(getNodeId(declaration)).index;
const cached = record.symbolsByDeclarationNodeIndex.get(index);
if (cached)
return cached;
return owner.fetchDeclarationSymbol(record, index);
}, function* (declaration) {
const file = getRemoteSourceFile(declaration);
if (!file)
throw new Error(`Source file not found for declaration`);
const record = file.symbolCache;
if (!record)
throw new Error(`Cached source file not found for declaration`);
const index = parseNodeHandleFromCompiler(getNodeId(declaration)).index;
const cached = record.symbolsByDeclarationNodeIndex.get(index);
if (cached)
return cached;
return yield* owner.fetchDeclarationSymbol.gen(record, index);
});
}
get fetchDeclarationSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchDeclarationSymbol", function (record, index) {
const data = owner.client.apiRequest("getSymbolOfDeclaration", {
file: record.descriptor,
index,
});
validateSymbolResponse(data);
const reference = data.reference;
if (reference.kind !== SymbolOwnerKind.File) {
throw new Error(`Symbol ${reference.id} is not file-owned`);
}
const fileOwner = { record, api: owner };
const symbol = owner.sourceFileCache.getOrCreateSymbol(record, reference.file, reference.id, () => new Symbol(data, { kind: SymbolOwnerKind.File, owner: fileOwner }));
record.symbolsByDeclarationNodeIndex.set(index, symbol);
return symbol;
}, function* (record, index) {
const data = yield* apiRequest("getSymbolOfDeclaration", {
file: record.descriptor,
index,
});
validateSymbolResponse(data);
const reference = data.reference;
if (reference.kind !== SymbolOwnerKind.File) {
throw new Error(`Symbol ${reference.id} is not file-owned`);
}
const fileOwner = { record, api: owner };
const symbol = owner.sourceFileCache.getOrCreateSymbol(record, reference.file, reference.id, () => new Symbol(data, { kind: SymbolOwnerKind.File, owner: fileOwner }));
record.symbolsByDeclarationNodeIndex.set(index, symbol);
return symbol;
});
}
/**
* Create an API instance from an existing LSP connection's API session.
* Use this when connecting to an API pipe provided by an LSP server via custom/initializeAPISession.
*/
static get fromLSPConnection() {
const owner = this;
return cacheGeneratorMethod(owner, "fromLSPConnection", function (options) {
const api = new API(options);
api.ensureInitialized();
return api;
}, function* (options) {
const api = new API(options);
yield* api.ensureInitialized.gen();
return api;
});
}
batch(...requestGenerators) {
return executeRequestGenerators(requestGenerators, requests => this.client.batchRequests(requests).responses);
}
get ensureInitialized() {
const owner = this;
return cacheGeneratorMethod(owner, "ensureInitialized", function () {
if (owner.initialized)
return;
return owner.initializing ??= owner.initializeWorker();
}, function* () {
if (owner.initialized)
return;
return owner.initializing ??= yield* owner.initializeWorker.gen();
});
}
get initializeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "initializeWorker", function () {
try {
const response = owner.client.apiRequest("initialize", null);
owner.currentDirectory = response.currentDirectory;
owner.caseSensitivity = response.caseSensitivity;
owner.toPath = (fileName, basePath = response.currentDirectory) => pathKey(toRootedPath(fileName, toRootedDirectoryPath(basePath, response.currentDirectory)), response.caseSensitivity);
owner.initialized = true;
}
catch (error) {
owner.initializing = undefined;
throw error;
}
}, function* () {
try {
const response = yield* apiRequest("initialize", null);
owner.currentDirectory = response.currentDirectory;
owner.caseSensitivity = response.caseSensitivity;
owner.toPath = (fileName, basePath = response.currentDirectory) => pathKey(toRootedPath(fileName, toRootedDirectoryPath(basePath, response.currentDirectory)), response.caseSensitivity);
owner.initialized = true;
}
catch (error) {
owner.initializing = undefined;
throw error;
}
});
}
getCurrentDirectory() {
if (this.currentDirectory === undefined) {
throw new Error("API has not been initialized");
}
return this.currentDirectory;
}
getCanonicalFileName(fileName) {
return canonicalize(fileName, this.getCaseSensitivity());
}
getCaseSensitivity() {
if (this.caseSensitivity === undefined) {
throw new Error("API has not been initialized");
}
return this.caseSensitivity;
}
getNewLine() {
return "\n";
}
/** @internal */
get createBuildOrchestrator() {
const owner = this;
return cacheGeneratorMethod(owner, "createBuildOrchestrator", function (rootNames, buildOrchestratorOptions) {
owner.ensureInitialized();
const orchestratorResponse = owner.client.apiRequest("createBuildOrchestrator", {
...buildOrchestratorOptions,
...buildOrchestratorOptions.overrideCompilerOptions,
cwd: buildOrchestratorOptions.cwd === undefined
? undefined
: toRootedDirectoryPath(buildOrchestratorOptions.cwd, owner.getCurrentDirectory()),
rootNames,
});
const orchestrator = new BuildOrchestrator(owner.client, orchestratorResponse, () => {
owner.activeBuildOrchestrators.delete(orchestrator);
});
owner.activeBuildOrchestrators.add(orchestrator);
return orchestrator;
}, function* (rootNames, buildOrchestratorOptions) {
yield* owner.ensureInitialized.gen();
const orchestratorResponse = yield* apiRequest("createBuildOrchestrator", {
...buildOrchestratorOptions,
...buildOrchestratorOptions.overrideCompilerOptions,
cwd: buildOrchestratorOptions.cwd === undefined
? undefined
: toRootedDirectoryPath(buildOrchestratorOptions.cwd, owner.getCurrentDirectory()),
rootNames,
});
const orchestrator = new BuildOrchestrator(owner.client, orchestratorResponse, () => {
owner.activeBuildOrchestrators.delete(orchestrator);
});
owner.activeBuildOrchestrators.add(orchestrator);
return orchestrator;
});
}
get parseConfigFile() {
const owner = this;
return cacheGeneratorMethod(owner, "parseConfigFile", function (file) {
owner.ensureInitialized();
return owner.client.apiRequest("parseConfigFile", { file });
}, function* (file) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("parseConfigFile", { file });
});
}
get parseCommandLine() {
const owner = this;
return cacheGeneratorMethod(owner, "parseCommandLine", function (commandLine) {
owner.ensureInitialized();
return owner.client.apiRequest("parseCommandLine", { commandLine });
}, function* (commandLine) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("parseCommandLine", { commandLine });
});
}
get readConfigFile() {
const owner = this;
return cacheGeneratorMethod(owner, "readConfigFile", function (file) {
owner.ensureInitialized();
return owner.client.apiRequest("readConfigFile", { file });
}, function* (file) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("readConfigFile", { file });
});
}
get parseJsonConfigFileContent() {
const owner = this;
return cacheGeneratorMethod(owner, "parseJsonConfigFileContent", function (json, options) {
owner.ensureInitialized();
return owner.client.apiRequest("parseJsonConfigFileContent", { json, ...options });
}, function* (json, options) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("parseJsonConfigFileContent", { json, ...options });
});
}
/**
* Create and retain a source file independently of a program.
* Dispose the returned lease when the source file no longer needs to remain available remotely.
*/
get createSourceFile() {
const owner = this;
return cacheGeneratorMethod(owner, "createSourceFile", function (fileName, sourceText, options = {}) {
owner.ensureInitialized();
const data = owner.client.apiRequestBinary("createSourceFile", { fileName, sourceText, options });
if (!data) {
throw new Error("createSourceFile returned no source file");
}
return owner.retainSourceFileResponse(data);
}, function* (fileName, sourceText, options = {}) {
yield* owner.ensureInitialized.gen();
const data = sourceFileResponseToUint8Array(yield* apiRequest("createSourceFile", { fileName, sourceText, options }));
if (!data) {
throw new Error("createSourceFile returned no source file");
}
return owner.retainSourceFileResponse(data);
});
}
/**
* Read, create, and retain a source file independently of a program.
* Dispose the returned lease when the source file no longer needs to remain available remotely.
*/
get createSourceFileFromFile() {
const owner = this;
return cacheGeneratorMethod(owner, "createSourceFileFromFile", function (file, options = {}) {
owner.ensureInitialized();
const data = owner.client.apiRequestBinary("createSourceFileFromFile", { fileName: resolveFileName(file), options });
if (!data) {
throw new Error("createSourceFileFromFile returned no source file");
}
return owner.retainSourceFileResponse(data);
}, function* (file, options = {}) {
yield* owner.ensureInitialized.gen();
const data = sourceFileResponseToUint8Array(yield* apiRequest("createSourceFileFromFile", { fileName: resolveFileName(file), options }));
if (!data) {
throw new Error("createSourceFileFromFile returned no source file");
}
return owner.retainSourceFileResponse(data);
});
}
/**
* Retain an ordinary remote source file independently of the snapshot or lease that produced it.
*/
get retainSourceFile() {
const owner = this;
return cacheGeneratorMethod(owner, "retainSourceFile", function (sourceFile) {
owner.ensureInitialized();
if (!(sourceFile instanceof RemoteSourceFile)) {
throw new TypeError("Only remote source files can be retained");
}
const cached = owner.sourceFileCache.get(sourceFile);
if (cached && cached !== sourceFile) {
throw new Error("Source file is no longer the canonical cached instance");
}
const result = owner.client.apiRequest("retainSourceFile", { file: sourceFileDescriptor(sourceFile) });
return owner.addSourceFileLease(sourceFile, result.lease);
}, function* (sourceFile) {
yield* owner.ensureInitialized.gen();
if (!(sourceFile instanceof RemoteSourceFile)) {
throw new TypeError("Only remote source files can be retained");
}
const cached = owner.sourceFileCache.get(sourceFile);
if (cached && cached !== sourceFile) {
throw new Error("Source file is no longer the canonical cached instance");
}
const result = yield* apiRequest("retainSourceFile", { file: sourceFileDescriptor(sourceFile) });
return owner.addSourceFileLease(sourceFile, result.lease);
});
}
retainSourceFileResponse(data) {
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
const lease = readSourceFileLease(view);
try {
const decoded = new RemoteSourceFile(data, this.decoder, this.client.getTimingCollector(), this);
return this.addSourceFileLease(decoded, lease);
}
catch (error) {
try {
this.client.apiRequest("releaseSourceFile", { lease });
}
catch { }
throw error;
}
}
addSourceFileLease(sourceFile, lease) {
const cached = this.sourceFileCache.setForLease(sourceFile, lease);
const retained = new RetainedSourceFile(cached, lease, () => {
this.activeSourceFileLeases.delete(lease);
this.sourceFileCache.releaseLease(lease);
});
this.activeSourceFileLeases.set(lease, retained);
return retained;
}
get transpileModule() {
const owner = this;
return cacheGeneratorMethod(owner, "transpileModule", function (input, options = {}) {
owner.ensureInitialized();
return owner.client.apiRequest("transpileModule", { input, options });
}, function* (input, options = {}) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("transpileModule", { input, options });
});
}
get transpileModuleFromFile() {
const owner = this;
return cacheGeneratorMethod(owner, "transpileModuleFromFile", function (file, options = {}) {
owner.ensureInitialized();
return owner.client.apiRequest("transpileModuleFromFile", { fileName: resolveFileName(file), options });
}, function* (file, options = {}) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("transpileModuleFromFile", { fileName: resolveFileName(file), options });
});
}
get transpileDeclaration() {
const owner = this;
return cacheGeneratorMethod(owner, "transpileDeclaration", function (input, options = {}) {
owner.ensureInitialized();
return owner.client.apiRequest("transpileDeclaration", { input, options });
}, function* (input, options = {}) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("transpileDeclaration", { input, options });
});
}
get transpileDeclarationFromFile() {
const owner = this;
return cacheGeneratorMethod(owner, "transpileDeclarationFromFile", function (file, options = {}) {
owner.ensureInitialized();
return owner.client.apiRequest("transpileDeclarationFromFile", { fileName: resolveFileName(file), options });
}, function* (file, options = {}) {
yield* owner.ensureInitialized.gen();
return yield* apiRequest("transpileDeclarationFromFile", { fileName: resolveFileName(file), options });
});
}
get createSnapshot() {
const owner = this;
function createSnapshot(params) {
owner.ensureInitialized();
const requestParams = owner.prepareCreateSnapshotParams(params);
const data = owner.client.apiRequest("createSnapshot", requestParams);
const snapshot = new Snapshot(data, owner.toPath, owner, () => {
owner.activeSnapshots.delete(snapshot.id);
owner.sourceFileCache.releaseSnapshot(snapshot.id);
}, owner.createSnapshotUpdater(() => snapshot), undefined);
owner.activeSnapshots.set(snapshot.id, snapshot);
return snapshot;
}
function* gen(params) {
yield* owner.ensureInitialized.gen();
const requestParams = owner.prepareCreateSnapshotParams(params);
const data = yield* apiRequest("createSnapshot", requestParams);
const snapshot = new Snapshot(data, owner.toPath, owner, () => {
owner.activeSnapshots.delete(snapshot.id);
owner.sourceFileCache.releaseSnapshot(snapshot.id);
}, owner.createSnapshotUpdater(() => snapshot), undefined);
owner.activeSnapshots.set(snapshot.id, snapshot);
return snapshot;
}
return cacheGeneratorMethod(owner, "createSnapshot", createSnapshot, gen);
}
get updateSnapshot() {
const owner = this;
return cacheGeneratorMethod(owner, "updateSnapshot", function (baseSnapshot, params) {
owner.ensureInitialized();
if (owner.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed()) {
throw new Error("Cannot update an inactive snapshot");
}
const data = owner.client.apiRequest("updateSnapshot", {
snapshot: baseSnapshot.id,
changes: owner.prepareCreateSnapshotParams(params),
});
if (data.snapshot === baseSnapshot.id) {
owner.client.apiRequest("release", { snapshot: data.snapshot });
return baseSnapshot;
}
owner.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
const snapshot = new Snapshot(data, owner.toPath, owner, () => {
owner.activeSnapshots.delete(snapshot.id);
owner.sourceFileCache.releaseSnapshot(snapshot.id);
}, owner.createSnapshotUpdater(() => snapshot), baseSnapshot);
owner.activeSnapshots.set(snapshot.id, snapshot);
return snapshot;
}, function* (baseSnapshot, params) {
yield* owner.ensureInitialized.gen();
if (owner.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed()) {
throw new Error("Cannot update an inactive snapshot");
}
const data = yield* apiRequest("updateSnapshot", {
snapshot: baseSnapshot.id,
changes: owner.prepareCreateSnapshotParams(params),
});
if (data.snapshot === baseSnapshot.id) {
yield* apiRequest("release", { snapshot: data.snapshot });
return baseSnapshot;
}
owner.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
const snapshot = new Snapshot(data, owner.toPath, owner, () => {
owner.activeSnapshots.delete(snapshot.id);
owner.sourceFileCache.releaseSnapshot(snapshot.id);
}, owner.createSnapshotUpdater(() => snapshot), baseSnapshot);
owner.activeSnapshots.set(snapshot.id, snapshot);
return snapshot;
});
}
prepareCreateSnapshotParams(params) {
params ??= {};
const prepareOptions = (options) => {
if (!options)
return undefined;
const { moduleResolver, projectReferences, ...rest } = options;
moduleResolver?.ensureNotDisposed();
return {
...rest,
moduleResolver: moduleResolver?.id,
projectReferences: projectReferences?.map(reference => ({
...reference,
path: toRootedPath(reference.path, this.getCurrentDirectory()),
})),
};
};
return {
...params,
createPrograms: params.createPrograms?.map(program => ({ ...program, options: prepareOptions(program.options) })),
reconfigurePrograms: params.reconfigurePrograms?.map(program => ({ ...program, options: prepareOptions(program.options) })),
};
}
prepareLanguageServerSnapshotChanges(changes) {
if (!changes)
return undefined;
const prepared = this.prepareCreateSnapshotParams(changes);
return prepared;
}
createSnapshotUpdater(getSnapshot) {
const update = ((params) => this.updateSnapshot(getSnapshot(), params));
const owner = this;
update.gen = function* (params) {
return yield* owner.updateSnapshot.gen(getSnapshot(), params);
};
return update;
}
/**
* Returns the language server's current canonical snapshot after atomically
* adopting any supplied API-driven changes. Only available on LSP-connected APIs.
*/
get getCurrentLanguageServerSnapshot() {
const owner = this;
function getCurrentLanguageServerSnapshot(...args) {
owner.ensureInitialized();
const changes = args[0];
const baseSnapshot = args[1];
if (baseSnapshot && (owner.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed())) {
throw new Error("Cannot use an inactive snapshot as a response base");
}
const data = owner.client.apiRequest("getCurrentLanguageServerSnapshot", {
baseSnapshot: baseSnapshot?.id,
changes: owner.prepareLanguageServerSnapshotChanges(changes),
});
if (baseSnapshot) {
owner.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
}
const snapshot = new Snapshot(data, owner.toPath, owner, () => {
owner.activeSnapshots.delete(snapshot.id);
owner.sourceFileCache.releaseSnapshot(snapshot.id);
}, owner.createSnapshotUpdater(() => snapshot), baseSnapshot);
owner.activeSnapshots.set(snapshot.id, snapshot);
return snapshot;
}
function* gen(...args) {
yield* owner.ensureInitialized.gen();
const changes = args[0];
const baseSnapshot = args[1];
if (baseSnapshot && (owner.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed())) {
throw new Error("Cannot use an inactive snapshot as a response base");
}
const data = yield* apiRequest("getCurrentLanguageServerSnapshot", {
baseSnapshot: baseSnapshot?.id,
changes: owner.prepareLanguageServerSnapshotChanges(changes),
});
if (baseSnapshot) {
owner.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
}
const snapshot = new Snapshot(data, owner.toPath, owner, () => {
owner.activeSnapshots.delete(snapshot.id);
owner.sourceFileCache.releaseSnapshot(snapshot.id);
}, owner.createSnapshotUpdater(() => snapshot), baseSnapshot);
owner.activeSnapshots.set(snapshot.id, snapshot);
return snapshot;
}
return cacheGeneratorMethod(owner, "getCurrentLanguageServerSnapshot", getCurrentLanguageServerSnapshot, gen);
}
[globalThis.Symbol.dispose]() {
this.close();
}
get close() {
const owner = this;
return cacheGeneratorMethod(owner, "close", function () {
try {
for (const retained of [...owner.activeSourceFileLeases.values()]) {
retained.dispose();
}
}
finally {
try {
for (const orchestrator of [...owner.activeBuildOrchestrators]) {
orchestrator.dispose();
}
for (const snapshot of [...owner.activeSnapshots.values()]) {
snapshot.dispose();
}
owner.sourceFileCache.clear();
}
finally {
owner.client.close(); // always close the underlying connection
}
}
}, function* () {
try {
for (const retained of [...owner.activeSourceFileLeases.values()]) {
yield* retained.dispose.gen();
}
}
finally {
try {
for (const orchestrator of [...owner.activeBuildOrchestrators]) {
yield* orchestrator.dispose.gen();
}
for (const snapshot of [...owner.activeSnapshots.values()]) {
yield* snapshot.dispose.gen();
}
owner.sourceFileCache.clear();
}
finally {
owner.client.close(); // always close the underlying connection
}
}
});
}
get createModuleResolver() {
const owner = this;
return cacheGeneratorMethod(owner, "createModuleResolver", function (compilerOptions, options) {
owner.ensureInitialized();
const callback = options?.resolveModuleName
? registerModuleResolutionCallback(owner.client, options.resolveModuleName, id => owner.activeSnapshots.get(id))
: undefined;
try {
const id = owner.client.apiRequest("createModuleResolver", {
compilerOptions: prepareCompilerOptions(compilerOptions, owner.getCurrentDirectory()),
moduleResolutions: options?.moduleResolutions,
resolveModuleNameCallback: callback?.name,
});
return new ModuleResolver(id, owner.client, callback?.dispose);
}
catch (error) {
callback?.dispose();
throw error;
}
}, function* (compilerOptions, options) {
yield* owner.ensureInitialized.gen();
const callback = options?.resolveModuleName
? registerModuleResolutionCallback(owner.client, options.resolveModuleName, id => owner.activeSnapshots.get(id))
: undefined;
try {
const id = yield* apiRequest("createModuleResolver", {
compilerOptions: prepareCompilerOptions(compilerOptions, owner.getCurrentDirectory()),
moduleResolutions: options?.moduleResolutions,
resolveModuleNameCallback: callback?.name,
});
return new ModuleResolver(id, owner.client, callback?.dispose);
}
catch (error) {
callback?.dispose();
throw error;
}
});
}
clearSourceFileCache() {
this.sourceFileCache.clear();
}
get runWithTemporaryFileUpdate() {
const owner = this;
return cacheGeneratorMethod(owner, "runWithTemporaryFileUpdate", function (baseSnapshot, file, newText, cb) {
owner.ensureInitialized();
if (owner.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed()) {
throw new Error("Cannot run a temporary file update on an inactive snapshot");
}
const snapshot = baseSnapshot.update({
fileSystem: {
kind: "layer",
files: { [resolveFileName(file)]: newText },
},
ensurePrograms: true,
});
try {
cb(snapshot);
}
finally {
snapshot.dispose();
}
}, function* (baseSnapshot, file, newText, cb) {
yield* owner.ensureInitialized.gen();
if (owner.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed()) {
throw new Error("Cannot run a temporary file update on an inactive snapshot");
}
const snapshot = yield* baseSnapshot.update.gen({
fileSystem: {
kind: "layer",
files: { [resolveFileName(file)]: newText },
},
ensurePrograms: true,
});
try {
yield* (cb(snapshot) ?? []);
}
finally {
yield* snapshot.dispose.gen();
}
});
}
/**
* Returns a snapshot of collected timing information for requests made
* through this API instance: client-measured round-trip latency and bytes
* transferred, folded together with the server's own per-request processing
* time and an estimated transport overhead (round-trip minus server time).
*
* Fetching the snapshot issues a lightweight request to the server to
* retrieve its timing collection. Collection must be enabled via the
* `collectTiming` option or `TS_API_TIMING_DIR` environment variable; when
* it is not, the returned snapshot has `enabled: false` and zeroed totals.
*/
get getTimingInfo() {
const owner = this;
return cacheGeneratorMethod(owner, "getTimingInfo", function () {
return owner.client.getTimingInfo();
}, function* () {
return owner.client.getTimingInfo();
});
}
/** Clears all accumulated timing totals and recent-request history, on both the client and the server. */
get resetTimingInfo() {
const owner = this;
return cacheGeneratorMethod(owner, "resetTimingInfo", function () {
return owner.client.resetTimingInfo();
}, function* () {
return owner.client.resetTimingInfo();
});
}
/** Creates a program from current filesystem state. */
get createProgram() {
const owner = this;
return cacheGeneratorMethod(owner, "createProgram", function (rootFiles, compilerOptions, createProgramOptions) {
owner.ensureInitialized();
const snapshot = owner.createSnapshot({
createPrograms: [{ rootFiles, compilerOptions, options: createProgramOptions }],
});
const program = snapshot.operation.createdPrograms[0];
if (!program) {
snapshot.dispose();
throw new Error("createProgram did not return a project");
}
program.setOwnedSnapshot(snapshot);
return program;
}, function* (rootFiles, compilerOptions, createProgramOptions) {
yield* owner.ensureInitialized.gen();
const snapshot = yield* owner.createSnapshot.gen({
createPrograms: [{ rootFiles, compilerOptions, options: createProgramOptions }],
});
const program = snapshot.operation.createdPrograms[0];
if (!program) {
yield* snapshot.dispose.gen();
throw new Error("createProgram did not return a project");
}
program.setOwnedSnapshot(snapshot);
return program;
});
}
}
function sourceFileDescriptor(sourceFile) {
return {
fileName: sourceFile.fileName,
path: sourceFile.path,
contentHash: sourceFile.contentHash,
parseOptionsKey: sourceFile.parseOptionsKey,
scriptKind: sourceFile.scriptKind,
nodeId: sourceFile.nodeId,
};
}
/** Returns whether a node is backed by a remote compiler response. */
export function isRemoteNode(node) {
return node instanceof RemoteNode;
}
function getRemoteSourceFile(node) {
if (!isRemoteNode(node))
return undefined;
const file = node.getSourceFile();
return file instanceof RemoteSourceFile && file.api ? file : undefined;
}
function getNodeAPI(node) {
const api = getRemoteSourceFile(node)?.api;
if (!api)
return undefined;
if (!(api instanceof API))
throw new Error("Source file does not belong to the sync API");
return api;
}
/** Looks up a remote declaration's binder symbol through its API. Throws for non-remote declarations. */
export function getSymbol(declaration) {
const api = getNodeAPI(declaration);
if (!api)
throw new Error("Source file not found for declaration");
return api.getSymbol(declaration);
}
getSymbol.gen = function* (declaration) {
const api = getNodeAPI(declaration);
if (!api)
throw new Error("Source file not found for declaration");
return yield* api.getSymbol.gen(declaration);
};
/** An independently retained source file and its disposable remote-lifetime lease. */
export class RetainedSourceFile {
sourceFile;
lease;
onDispose;
disposed = false;
disposePromise;
constructor(sourceFile, lease, onDispose) {
this.sourceFile = sourceFile;
this.lease = lease;
this.onDispose = onDispose;
}
[globalThis.Symbol.dispose]() {
this.dispose();
}
get dispose() {
const owner = this;
return cacheGeneratorMethod(owner, "dispose", function () {
return owner.disposePromise ??= owner.disposeWorker();
}, function* () {
return owner.disposePromise ??= yield* owner.disposeWorker.gen();
});
}
get disposeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "disposeWorker", function () {
if (owner.disposed)
return;
const api = getNodeAPI(owner.sourceFile);
if (!api)
throw new Error("Retained source file has no owning API");
owner.disposed = true;
try {
api.client.apiRequest("releaseSourceFile", { lease: owner.lease });
}
finally {
owner.onDispose();
}
}, function* () {
if (owner.disposed)
return;
const api = getNodeAPI(owner.sourceFile);
if (!api)
throw new Error("Retained source file has no owning API");
owner.disposed = true;
try {
yield* apiRequest("releaseSourceFile", { lease: owner.lease });
}
finally {
owner.onDispose();
}
});
}
}
export class DebugHandlers {
client;
ensureInitialized;
constructor(client, ensureInitialized) {
this.client = client;
this.ensureInitialized = ensureInitialized;
}
get startCPUProfile() {
const owner = this;
return cacheGeneratorMethod(owner, "startCPUProfile", function (dir) {
owner.ensureInitialized();
owner.client.apiRequest("startCPUProfile", { dir });
}, function* (dir) {
yield* owner.ensureInitialized.gen();
yield* apiRequest("startCPUProfile", { dir });
});
}
get stopCPUProfile() {
const owner = this;
return cacheGeneratorMethod(owner, "stopCPUProfile", function () {
owner.ensureInitialized();
const result = owner.client.apiRequest("stopCPUProfile", null);
return result.file;
}, function* () {
yield* owner.ensureInitialized.gen();
const result = yield* apiRequest("stopCPUProfile", null);
return result.file;
});
}
get saveHeapProfile() {
const owner = this;
return cacheGeneratorMethod(owner, "saveHeapProfile", function (dir) {
owner.ensureInitialized();
const result = owner.client.apiRequest("saveHeapProfile", { dir });
return result.file;
}, function* (dir) {
yield* owner.ensureInitialized.gen();
const result = yield* apiRequest("saveHeapProfile", { dir });
return result.file;
});
}
}
export class Snapshot {
id;
operation;
projectMap;
toPath;
api;
disposed = false;
disposePromise;
onDispose;
snapshotRegistry;
projectDataMap;
updateSnapshot;
get client() {
return this.api.client;
}
constructor(data, toPath, api, onDispose, updateSnapshot, baseSnapshot) {
this.id = data.snapshot;
this.api = api;
this.toPath = toPath;
this.onDispose = onDispose;
this.updateSnapshot = updateSnapshot;
this.projectMap = new Map();
const projectDataMap = new Map(baseSnapshot?.projectDataMap);
for (const projectId of data.changes?.removedProjects ?? []) {
projectDataMap.delete(projectId);
}
for (const projectData of data.projects) {
projectDataMap.set(projectData.id, projectData);
}
this.projectDataMap = new Map([...projectDataMap].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
this.snapshotRegistry = new SnapshotObjectRegistry(this.id);
for (const projData of this.projectDataMap.values()) {
const project = new Project(projData, this.id, toPath, api, this.snapshotRegistry);
this.projectMap.set(projData.id, project);
}
this.operation = {
createdPrograms: data.operation.createdPrograms?.map(projectId => this.requireProject(projectId).program),
openedFiles: data.operation.openedFiles?.map(result => ({ project: this.requireProject(result.project) })),
};
}
getProjects() {
this.ensureNotDisposed();
return [...this.projectMap.values()];
}
getConfiguredProject(configFileName) {
this.ensureNotDisposed();
const id = this.toPath(configFileName);
return this.projectMap.get(id);
}
getProject(projectId) {
this.ensureNotDisposed();
return this.projectMap.get(projectId);
}
getProgram(projectId) {
return this.getProject(projectId)?.program;
}
get update() {
const owner = this;
function update(params) {
owner.ensureNotDisposed();
return owner.updateSnapshot(params);
}
function* gen(params) {
owner.ensureNotDisposed();
return yield* owner.updateSnapshot.gen(params);
}
return cacheGeneratorMethod(owner, "update", update, gen);
}
/**
* Gets the default project for a given file from the configured projects and
* inferred project already loaded in the snapshot. Synthetic projects are not
* considered. Files that have been opened with `openFiles` are guaranteed to
* have a result.
*/
get getDefaultProjectForFile() {
const owner = this;
return cacheGeneratorMethod(owner, "getDefaultProjectForFile", function (file) {
owner.ensureNotDisposed();
const data = owner.client.apiRequest("getDefaultProjectForFile", {
snapshot: owner.id,
file,
});
if (!data)
return undefined;
return owner.projectMap.get(data.id);
}, function* (file) {
owner.ensureNotDisposed();
const data = yield* apiRequest("getDefaultProjectForFile", {
snapshot: owner.id,
file,
});
if (!data)
return undefined;
return owner.projectMap.get(data.id);
});
}
[globalThis.Symbol.dispose]() {
this.dispose();
}
get dispose() {
const owner = this;
return cacheGeneratorMethod(owner, "dispose", function () {
return owner.disposePromise ??= owner.disposeWorker();
}, function* () {
return owner.disposePromise ??= yield* owner.disposeWorker.gen();
});
}
get disposeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "disposeWorker", function () {
if (owner.disposed)
return;
owner.disposed = true;
for (const project of owner.projectMap.values()) {
project.dispose();
}
owner.projectMap.clear();
owner.snapshotRegistry.clear();
try {
owner.client.apiRequest("release", { snapshot: owner.id });
}
finally {
owner.onDispose();
}
}, function* () {
if (owner.disposed)
return;
owner.disposed = true;
for (const project of owner.projectMap.values()) {
project.dispose();
}
owner.projectMap.clear();
owner.snapshotRegistry.clear();
try {
yield* apiRequest("release", { snapshot: owner.id });
}
finally {
owner.onDispose();
}
});
}
isDisposed() {
return this.disposed;
}
ensureNotDisposed() {
if (this.disposed) {
throw new Error("Snapshot is disposed");
}
}
requireProject(projectId) {
const project = this.projectMap.get(projectId);
if (!project) {
throw new Error(`Snapshot operation returned unknown project '${projectId}'`);
}
return project;
}
}
export class ModuleResolver {
id;
client;
disposeCallback;
disposed = false;
constructor(id, client, disposeCallback) {
this.id = id;
this.client = client;
this.disposeCallback = disposeCallback;
}
get resolveModuleName() {
const owner = this;
return cacheGeneratorMethod(owner, "resolveModuleName", function (moduleName, containingDirectory, resolutionMode, options) {
owner.ensureNotDisposed();
if (options?.snapshot instanceof Snapshot && options.snapshot.isDisposed()) {
throw new Error("Snapshot is disposed");
}
return owner.client.apiRequest("resolveModuleName", {
snapshot: options?.snapshot instanceof Snapshot ? options.snapshot.id : undefined,
inProgressSnapshot: typeof options?.snapshot === "number" ? -options.snapshot : undefined,
resolver: owner.id,
moduleName,
containingDirectory,
resolutionMode,
});
}, function* (moduleName, containingDirectory, resolutionMode, options) {
owner.ensureNotDisposed();
if (options?.snapshot instanceof Snapshot && options.snapshot.isDisposed()) {
throw new Error("Snapshot is disposed");
}
return yield* apiRequest("resolveModuleName", {
snapshot: options?.snapshot instanceof Snapshot ? options.snapshot.id : undefined,
inProgressSnapshot: typeof options?.snapshot === "number" ? -options.snapshot : undefined,
resolver: owner.id,
moduleName,
containingDirectory,
resolutionMode,
});
});
}
[globalThis.Symbol.dispose]() {
return this.dispose();
}
get dispose() {
const owner = this;
return cacheGeneratorMethod(owner, "dispose", function () {
if (owner.disposed)
return;
owner.client.apiRequest("releaseModuleResolver", { resolver: owner.id });
owner.disposed = true;
owner.disposeCallback?.();
}, function* () {
if (owner.disposed)
return;
yield* apiRequest("releaseModuleResolver", { resolver: owner.id });
owner.disposed = true;
owner.disposeCallback?.();
});
}
/** @internal */
ensureNotDisposed() {
if (this.disposed)
throw new Error("ModuleResolver is disposed");
}
}
class SnapshotObjectRegistry {
symbols = new Map();
nodeHandles = new Map();
projectRegistries = new Map();
snapshotId;
disposed = false;
constructor(snapshotId) {
this.snapshotId = snapshotId;
}
addProjectRegistry(registry) {
this.projectRegistries.set(registry.project.handle, registry);
}
getOrCreateSymbol(data) {
const reference = data.reference;
if (reference.kind !== SymbolOwnerKind.Snapshot)
throw new Error(`Symbol ${reference.id} is not snapshot-owned`);
let symbol = this.symbols.get(reference.id);
if (!symbol) {
if (reference.snapshot !== this.snapshotId) {
throw new Error(`Symbol ${reference.id} belongs to snapshot ${reference.snapshot}, not ${this.snapshotId}`);
}
const registry = this.projectRegistries.get(reference.project);
if (!registry)
throw new Error(`Symbol ${reference.id} references unknown project '${reference.project}'`);
symbol = new Symbol(data, { kind: SymbolOwnerKind.Snapshot, registry });
this.symbols.set(reference.id, symbol);
}
return symbol;
}
getSymbol(id) {
return this.symbols.get(id);
}
getOrCreateNodeHandle(handle, project) {
let node = this.nodeHandles.get(handle);
if (!node) {
node = new NodeHandle(handle, project);
if (!this.disposed)
this.nodeHandles.set(handle, node);
}
return node;
}
clear() {
this.disposed = true;
this.symbols.clear();
this.nodeHandles.clear();
}
}
class ProjectObjectRegistry {
snapshotId;
project;
snapshotRegistry;
types = new Map();
signatures = new Map();
disposed = false;
get client() {
return this.project.api.client;
}
get sourceFileCache() {
return this.project.api.sourceFileCache;
}
constructor(snapshotId, project, snapshotRegistry) {
this.snapshotId = snapshotId;
this.project = project;
this.snapshotRegistry = snapshotRegistry;
snapshotRegistry.addProjectRegistry(this);
}
getOrCreateSymbol(data) {
this.ensureNotDisposed();
validateSymbolResponse(data);
const reference = data.reference;
if (reference.kind === SymbolOwnerKind.Snapshot) {
return this.snapshotRegistry.getOrCreateSymbol(data);
}
const record = this.sourceFileCache.getOrCreateRecord(reference.file, this.snapshotId, this.project.id);
return this.sourceFileCache.getOrCreateSymbol(record, reference.file, reference.id, () => new Symbol(data, {
kind: SymbolOwnerKind.File,
owner: { record, api: this.project.api },
}));
}
/** Find an already-interned symbol and retain its file record for this registry. */
getCachedSymbol(reference) {
this.ensureNotDisposed();
if (reference.file === undefined) {
return this.snapshotRegistry.getSymbol(reference.id);
}
const record = this.sourceFileCache.findRecord(reference.file);
const symbol = record?.symbolsById.get(reference.id);
if (record && symbol) {
this.sourceFileCache.retainRecord(record, this.snapshotId, this.project.id);
}
return symbol;
}
getOrCreateType(data) {
let type = this.types.get(data.id);
if (!type) {
type = new TypeObject(data, this);
this.types.set(data.id, type);
}
return type;
}
getType(id) {
return this.types.get(id);
}
createNodeHandle(handle) {
return this.snapshotRegistry.getOrCreateNodeHandle(handle, this.project);
}
getOrCreateSignature(data) {
let sig = this.signatures.get(data.id);
if (!sig) {
sig = new Signature(data, this.project, this);
this.signatures.set(data.id, sig);
}
return sig;
}
getSignature(id) {
return this.signatures.get(id);
}
clear() {
this.disposed = true;
this.types.clear();
this.signatures.clear();
}
ensureNotDisposed() {
if (this.disposed)
throw new Error("Project object registry is disposed");
}
get fetchOptionalType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchOptionalType", function (source, method, handle) {
if (handle !== false) {
if (!handle)
return undefined;
const cached = owner.getType(handle);
if (cached)
return cached;
}
const data = owner.client.apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (!data)
return undefined;
return owner.getOrCreateType(data);
}, function* (source, method, handle) {
if (handle !== false) {
if (!handle)
return undefined;
const cached = owner.getType(handle);
if (cached)
return cached;
}
const data = yield* apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (!data)
return undefined;
return owner.getOrCreateType(data);
});
}
get fetchType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchType", function (source, method, handle) {
const result = owner.fetchOptionalType(source, method, handle);
if (result === undefined)
throw new Error(`${method} returned no type for ${source.constructor.name} ${source.id}`);
return result;
}, function* (source, method, handle) {
const result = yield* owner.fetchOptionalType.gen(source, method, handle);
if (result === undefined)
throw new Error(`${method} returned no type for ${source.constructor.name} ${source.id}`);
return result;
});
}
get fetchSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSymbol", function (source, method, reference) {
if (!reference)
return undefined;
const cached = owner.getCachedSymbol(reference);
if (cached)
return cached;
const data = source instanceof Symbol
? owner.client.apiRequest(method, { symbol: source.reference })
: owner.client.apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (!data)
throw new Error(`${method} returned null symbol for ${source.constructor.name} ${source.id}`);
return owner.getOrCreateSymbol(data);
}, function* (source, method, reference) {
if (!reference)
return undefined;
const cached = owner.getCachedSymbol(reference);
if (cached)
return cached;
const data = source instanceof Symbol
? yield* apiRequest(method, { symbol: source.reference })
: yield* apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (!data)
throw new Error(`${method} returned null symbol for ${source.constructor.name} ${source.id}`);
return owner.getOrCreateSymbol(data);
});
}
get fetchSignature() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSignature", function (source, method, handle) {
if (!handle)
return undefined;
const cached = owner.getSignature(handle);
if (cached)
return cached;
const data = owner.client.apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (!data)
throw new Error(`${method} returned null signature for ${source.constructor.name} ${source.id}`);
return owner.getOrCreateSignature(data);
}, function* (source, method, handle) {
if (!handle)
return undefined;
const cached = owner.getSignature(handle);
if (cached)
return cached;
const data = yield* apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (!data)
throw new Error(`${method} returned null signature for ${source.constructor.name} ${source.id}`);
return owner.getOrCreateSignature(data);
});
}
get fetchTypes() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchTypes", function (source, method, handles) {
if (handles) {
const result = new Array(handles.length);
let allCached = true;
for (let i = 0; i < handles.length; i++) {
const cached = owner.getType(handles[i]);
if (!cached) {
allCached = false;
break;
}
result[i] = cached;
}
if (allCached)
return result;
}
const typesData = owner.client.apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (typesData == null)
return [];
else
return typesData.map(data => owner.getOrCreateType(data));
}, function* (source, method, handles) {
if (handles) {
const result = new Array(handles.length);
let allCached = true;
for (let i = 0; i < handles.length; i++) {
const cached = owner.getType(handles[i]);
if (!cached) {
allCached = false;
break;
}
result[i] = cached;
}
if (allCached)
return result;
}
const typesData = yield* apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
if (typesData == null)
return [];
else
return typesData.map(data => owner.getOrCreateType(data));
});
}
get fetchSymbols() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSymbols", function (source, method, references) {
if (references) {
const result = new Array(references.length);
for (let i = 0; i < references.length; i++) {
const cached = owner.getCachedSymbol(references[i]);
if (!cached) {
return owner.fetchSymbolsFromServer(source, method);
}
result[i] = cached;
}
return result;
}
return owner.fetchSymbolsFromServer(source, method);
}, function* (source, method, references) {
if (references) {
const result = new Array(references.length);
for (let i = 0; i < references.length; i++) {
const cached = owner.getCachedSymbol(references[i]);
if (!cached) {
return yield* owner.fetchSymbolsFromServer.gen(source, method);
}
result[i] = cached;
}
return result;
}
return yield* owner.fetchSymbolsFromServer.gen(source, method);
});
}
get fetchSymbolsFromServer() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSymbolsFromServer", function (source, method) {
const data = source instanceof Symbol
? owner.client.apiRequest(method, { symbol: source.reference })
: owner.client.apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
return data?.map(symbol => owner.getOrCreateSymbol(symbol)) ?? [];
}, function* (source, method) {
const data = source instanceof Symbol
? yield* apiRequest(method, { symbol: source.reference })
: yield* apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
return data?.map(symbol => owner.getOrCreateSymbol(symbol)) ?? [];
});
}
// getBaseTypes is a checker-level endpoint keyed by `type` (not `objectId`),
// so it cannot go through fetchTypes. This helper reuses that server method.
get fetchBaseTypes() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchBaseTypes", function (source) {
const typesData = owner.client.apiRequest("getBaseTypes", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
});
if (typesData == null)
return [];
return typesData.map(data => owner.getOrCreateType(data));
}, function* (source) {
const typesData = yield* apiRequest("getBaseTypes", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
});
if (typesData == null)
return [];
return typesData.map(data => owner.getOrCreateType(data));
});
}
get fetchPropertiesOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchPropertiesOfType", function (source) {
const data = owner.client.apiRequest("getPropertiesOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
});
return data ? data.map(symbol => owner.getOrCreateSymbol(symbol)) : [];
}, function* (source) {
const data = yield* apiRequest("getPropertiesOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
});
return data ? data.map(symbol => owner.getOrCreateSymbol(symbol)) : [];
});
}
get fetchApparentPropertiesOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchApparentPropertiesOfType", function (source) {
const data = owner.client.apiRequest("getApparentPropertiesOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
return data ? data.map(symbol => owner.getOrCreateSymbol(symbol)) : [];
}, function* (source) {
const data = yield* apiRequest("getApparentPropertiesOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
objectId: source.id,
});
return data ? data.map(symbol => owner.getOrCreateSymbol(symbol)) : [];
});
}
get fetchPropertyOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchPropertyOfType", function (source, name) {
const data = owner.client.apiRequest("getPropertyOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
name,
});
return data ? owner.getOrCreateSymbol(data) : undefined;
}, function* (source, name) {
const data = yield* apiRequest("getPropertyOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
name,
});
return data ? owner.getOrCreateSymbol(data) : undefined;
});
}
get fetchSignaturesOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSignaturesOfType", function (source, kind) {
const data = owner.client.apiRequest("getSignaturesOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
kind,
});
return data.map(signature => owner.getOrCreateSignature(signature));
}, function* (source, kind) {
const data = yield* apiRequest("getSignaturesOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
kind,
});
return data.map(signature => owner.getOrCreateSignature(signature));
});
}
get fetchIndexInfosOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchIndexInfosOfType", function (source) {
const data = owner.client.apiRequest("getIndexInfosOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
});
if (!data)
return [];
return data.map(info => ({
keyType: owner.getOrCreateType(info.keyType),
valueType: owner.getOrCreateType(info.valueType),
isReadonly: info.isReadonly ?? false,
declaration: info.declaration ? owner.createNodeHandle(info.declaration) : undefined,
}));
}, function* (source) {
const data = yield* apiRequest("getIndexInfosOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: source.id,
});
if (!data)
return [];
return data.map(info => ({
keyType: owner.getOrCreateType(info.keyType),
valueType: owner.getOrCreateType(info.valueType),
isReadonly: info.isReadonly ?? false,
declaration: info.declaration ? owner.createNodeHandle(info.declaration) : undefined,
}));
});
}
get fetchTypeParameterAtPosition() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchTypeParameterAtPosition", function (source, pos) {
const data = owner.client.apiRequest("getTypeParameterAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: source.id,
index: pos,
});
return owner.getOrCreateType(data);
}, function* (source, pos) {
const data = yield* apiRequest("getTypeParameterAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: source.id,
index: pos,
});
return owner.getOrCreateType(data);
});
}
}
export class Project {
/** @internal */
api;
id;
/**
* Server identity for this project's lifetime across snapshots.
* @internal
*/
handle;
configFileName;
currentDirectory;
dirty;
parsedCommandLine;
program;
checker;
languageService;
constructor(data, snapshotId, toPath, api, snapshotRegistry) {
this.id = data.id;
this.handle = data.handle;
this.api = api;
this.configFileName = data.configFileName;
this.currentDirectory = data.currentDirectory;
this.dirty = data.dirty;
if (!data.parsedCommandLine?.options) {
throw new Error(`Project '${data.configFileName}' has no parsed command line`);
}
this.parsedCommandLine = data.parsedCommandLine;
this.program = new Program(snapshotId, this, toPath);
const objectRegistry = new ProjectObjectRegistry(snapshotId, this, snapshotRegistry);
this.checker = new Checker(snapshotId, this, objectRegistry);
this.languageService = new LanguageService(snapshotId, this, objectRegistry);
}
dispose() {
this.checker.dispose();
}
}
export class LanguageService {
snapshotId;
project;
objectRegistry;
get client() {
return this.project.api.client;
}
constructor(snapshotId, project, objectRegistry) {
this.snapshotId = snapshotId;
this.project = project;
this.objectRegistry = objectRegistry;
}
get getImportAdderEdits() {
const owner = this;
return cacheGeneratorMethod(owner, "getImportAdderEdits", function (file, actions) {
const requestActions = actions.map(action => {
switch (action.kind) {
case "importSymbol":
const importSymbolAction = {
kind: "importSymbol",
symbol: action.symbol.reference,
};
if (action.isValidTypeOnlyUseSite !== undefined) {
importSymbolAction.isValidTypeOnlyUseSite = action.isValidTypeOnlyUseSite;
}
return importSymbolAction;
default:
return assertNever(action.kind);
}
});
const data = owner.client.apiRequest("getImportAdderEdits", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
actions: requestActions,
});
return data ?? [];
}, function* (file, actions) {
const requestActions = actions.map(action => {
switch (action.kind) {
case "importSymbol":
const importSymbolAction = {
kind: "importSymbol",
symbol: action.symbol.reference,
};
if (action.isValidTypeOnlyUseSite !== undefined) {
importSymbolAction.isValidTypeOnlyUseSite = action.isValidTypeOnlyUseSite;
}
return importSymbolAction;
default:
return assertNever(action.kind);
}
});
const data = yield* apiRequest("getImportAdderEdits", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
actions: requestActions,
});
return data ?? [];
});
}
get getImportEditsForSymbols() {
const owner = this;
return cacheGeneratorMethod(owner, "getImportEditsForSymbols", function (file, symbols, options = {}) {
return owner.getImportAdderEdits(file, symbols.map((symbol) => {
if (options.isValidTypeOnlyUseSite !== undefined) {
return {
kind: "importSymbol",
symbol,
isValidTypeOnlyUseSite: options.isValidTypeOnlyUseSite,
};
}
return {
kind: "importSymbol",
symbol,
};
}));
}, function* (file, symbols, options = {}) {
return yield* owner.getImportAdderEdits.gen(file, symbols.map((symbol) => {
if (options.isValidTypeOnlyUseSite !== undefined) {
return {
kind: "importSymbol",
symbol,
isValidTypeOnlyUseSite: options.isValidTypeOnlyUseSite,
};
}
return {
kind: "importSymbol",
symbol,
};
}));
});
}
get getReferencedSymbolsForNode() {
const owner = this;
return cacheGeneratorMethod(owner, "getReferencedSymbolsForNode", function (node, position) {
const data = owner.client.apiRequest("getReferencedSymbolsForNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
node: getNodeRequestHandle(node),
position,
});
return (data ?? []).map(entry => ({
definition: owner.objectRegistry.createNodeHandle(entry.definition),
symbol: entry.symbol ? owner.objectRegistry.getOrCreateSymbol(entry.symbol) : undefined,
references: (entry.references ?? []).map(h => owner.objectRegistry.createNodeHandle(h)),
}));
}, function* (node, position) {
const data = yield* apiRequest("getReferencedSymbolsForNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
node: getNodeRequestHandle(node),
position,
});
return (data ?? []).map(entry => ({
definition: owner.objectRegistry.createNodeHandle(entry.definition),
symbol: entry.symbol ? owner.objectRegistry.getOrCreateSymbol(entry.symbol) : undefined,
references: (entry.references ?? []).map(h => owner.objectRegistry.createNodeHandle(h)),
}));
});
}
get getSignatureUsage() {
const owner = this;
return cacheGeneratorMethod(owner, "getSignatureUsage", function (signatureDecl) {
const data = owner.client.apiRequest("getSignatureUsages", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signatureDecl: getNodeRequestHandle(signatureDecl),
});
return (data ?? []).map(entry => ({
name: owner.objectRegistry.createNodeHandle(entry.name),
call: entry.call ? owner.objectRegistry.createNodeHandle(entry.call) : undefined,
}));
}, function* (signatureDecl) {
const data = yield* apiRequest("getSignatureUsages", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signatureDecl: getNodeRequestHandle(signatureDecl),
});
return (data ?? []).map(entry => ({
name: owner.objectRegistry.createNodeHandle(entry.name),
call: entry.call ? owner.objectRegistry.createNodeHandle(entry.call) : undefined,
}));
});
}
get getCompletionsAtPosition() {
const owner = this;
return cacheGeneratorMethod(owner, "getCompletionsAtPosition", function (document, position, options) {
const data = owner.client.apiRequest("getCompletionsAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file: document,
position,
triggerCharacter: options?.triggerCharacter,
includeSymbol: options?.includeSymbol,
});
if (!data)
return undefined;
return {
isIncomplete: data.isIncomplete,
entries: data.entries.map(e => ({
...e,
symbol: e.symbol ? owner.objectRegistry.getOrCreateSymbol(e.symbol) : undefined,
})),
};
}, function* (document, position, options) {
const data = yield* apiRequest("getCompletionsAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file: document,
position,
triggerCharacter: options?.triggerCharacter,
includeSymbol: options?.includeSymbol,
});
if (!data)
return undefined;
return {
isIncomplete: data.isIncomplete,
entries: data.entries.map(e => ({
...e,
symbol: e.symbol ? owner.objectRegistry.getOrCreateSymbol(e.symbol) : undefined,
})),
};
});
}
/**
* Format a synthesized node with the correct indentation for insertion at a
* specific position in an existing source file.
*
* @param node The synthesized AST node to format.
* @param file The target file where the node will be inserted.
* @param position The UTF-16 code-unit offset in the target file for insertion.
* @returns The formatted text of the node, indented for the insertion position.
*/
get formatNodeForInsertion() {
const owner = this;
return cacheGeneratorMethod(owner, "formatNodeForInsertion", function (node, file, position) {
const encoded = encodeNode(node);
const base64 = uint8ArrayToBase64(encoded);
return owner.client.apiRequest("formatNodeForInsertion", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
position,
data: base64,
});
}, function* (node, file, position) {
const encoded = encodeNode(node);
const base64 = uint8ArrayToBase64(encoded);
return yield* apiRequest("formatNodeForInsertion", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
position,
data: base64,
});
});
}
}
export class Program {
/** @internal */
snapshotId;
id;
project;
toPath;
decoder = new Wtf8Decoder();
sourceFileMetadataCache = new Map();
ownedSnapshot;
disposePromise;
get client() {
return this.project.api.client;
}
get sourceFileCache() {
return this.project.api.sourceFileCache;
}
constructor(snapshotId, project, toPath) {
this.snapshotId = snapshotId;
this.id = project.id;
this.project = project;
this.toPath = toPath;
}
getCurrentDirectory() {
return this.project.currentDirectory;
}
getCanonicalFileName(fileName) {
return this.project.api.getCanonicalFileName(fileName);
}
getNewLine() {
return this.project.parsedCommandLine.options.newLine === NewLineKind.CRLF ? "\r\n" : "\n";
}
/** @internal */
setOwnedSnapshot(snapshot) {
this.ownedSnapshot = snapshot;
}
[globalThis.Symbol.dispose]() {
this.dispose();
}
get dispose() {
const owner = this;
return cacheGeneratorMethod(owner, "dispose", function () {
return owner.disposePromise ??= owner.disposeWorker();
}, function* () {
return owner.disposePromise ??= yield* owner.disposeWorker.gen();
});
}
get disposeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "disposeWorker", function () {
const snapshot = owner.ownedSnapshot;
owner.ownedSnapshot = undefined;
if (snapshot)
snapshot.dispose();
}, function* () {
const snapshot = owner.ownedSnapshot;
owner.ownedSnapshot = undefined;
if (snapshot)
yield* snapshot.dispose.gen();
});
}
getCompilerOptions() {
return this.project.parsedCommandLine.options;
}
get getSourceFile() {
const owner = this;
return cacheGeneratorMethod(owner, "getSourceFile", function (file) {
const fileName = resolveFileName(file);
const path = owner.pathKeyForFileName(fileName);
return owner.getSourceFileWorker(file, path);
}, function* (file) {
const fileName = resolveFileName(file);
const path = owner.pathKeyForFileName(fileName);
return yield* owner.getSourceFileWorker.gen(file, path);
});
}
/**
* Returns the source file for an already-canonical path.
*/
get getSourceFileByPath() {
const owner = this;
return cacheGeneratorMethod(owner, "getSourceFileByPath", function (path) {
// The wire format is a string, but the cache key remains the supplied
// PathKey and is never treated as a RootedPath.
return owner.getSourceFileWorker(path, path);
}, function* (path) {
// The wire format is a string, but the cache key remains the supplied
// PathKey and is never treated as a RootedPath.
return yield* owner.getSourceFileWorker.gen(path, path);
});
}
get getSourceFileWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "getSourceFileWorker", function (file, path) {
// Check if we already have a retained cache entry for this (snapshot, project) pair
const retained = owner.sourceFileCache.getRetained(path, owner.snapshotId, owner.project.id);
if (retained) {
return retained;
}
// Fetch from server
const binaryData = owner.client.apiRequestBinary("getSourceFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
});
if (!binaryData) {
return undefined;
}
// Create a new RemoteSourceFile and cache it (set returns existing if hash matches)
const decoded = new RemoteSourceFile(binaryData, owner.decoder, owner.client.getTimingCollector(), owner.project.api);
return owner.sourceFileCache.set(decoded, owner.snapshotId, owner.project.id);
}, function* (file, path) {
// Check if we already have a retained cache entry for this (snapshot, project) pair
const retained = owner.sourceFileCache.getRetained(path, owner.snapshotId, owner.project.id);
if (retained) {
return retained;
}
// Fetch from server
const binaryData = sourceFileResponseToUint8Array(yield* apiRequest("getSourceFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
}));
if (!binaryData) {
return undefined;
}
// Create a new RemoteSourceFile and cache it (set returns existing if hash matches)
const decoded = new RemoteSourceFile(binaryData, owner.decoder, owner.client.getTimingCollector(), owner.project.api);
return owner.sourceFileCache.set(decoded, owner.snapshotId, owner.project.id);
});
}
get getResolvedModule() {
const owner = this;
return cacheGeneratorMethod(owner, "getResolvedModule", function (file, moduleName, mode) {
const result = owner.client.apiRequest("getResolvedModule", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
moduleName,
mode,
});
return result ?? undefined;
}, function* (file, moduleName, mode) {
const result = yield* apiRequest("getResolvedModule", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
moduleName,
mode,
});
return result ?? undefined;
});
}
get getModeForUsageLocation() {
const owner = this;
return cacheGeneratorMethod(owner, "getModeForUsageLocation", function (file, usage) {
return owner.client.apiRequest("getModeForUsageLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
usage: getNodeRequestHandle(usage),
});
}, function* (file, usage) {
return yield* apiRequest("getModeForUsageLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
usage: getNodeRequestHandle(usage),
});
});
}
get getModeForResolutionAtIndex() {
const owner = this;
return cacheGeneratorMethod(owner, "getModeForResolutionAtIndex", function (file, index) {
return owner.client.apiRequest("getModeForResolutionAtIndex", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
index,
});
}, function* (file, index) {
return yield* apiRequest("getModeForResolutionAtIndex", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
index,
});
});
}
get getResolvedModuleFromModuleSpecifier() {
const owner = this;
return cacheGeneratorMethod(owner, "getResolvedModuleFromModuleSpecifier", function (moduleSpecifier, sourceFile) {
const result = owner.client.apiRequest("getResolvedModuleFromModuleSpecifier", {
snapshot: owner.snapshotId,
project: owner.project.handle,
moduleSpecifier: getNodeRequestHandle(moduleSpecifier),
sourceFile,
});
return result ?? undefined;
}, function* (moduleSpecifier, sourceFile) {
const result = yield* apiRequest("getResolvedModuleFromModuleSpecifier", {
snapshot: owner.snapshotId,
project: owner.project.handle,
moduleSpecifier: getNodeRequestHandle(moduleSpecifier),
sourceFile,
});
return result ?? undefined;
});
}
get getResolvedTypeReferenceDirective() {
const owner = this;
return cacheGeneratorMethod(owner, "getResolvedTypeReferenceDirective", function (file, typeDirectiveName, mode) {
const result = owner.client.apiRequest("getResolvedTypeReferenceDirective", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
typeDirectiveName,
mode,
});
return result ?? undefined;
}, function* (file, typeDirectiveName, mode) {
const result = yield* apiRequest("getResolvedTypeReferenceDirective", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
typeDirectiveName,
mode,
});
return result ?? undefined;
});
}
get getResolvedTypeReferenceDirectiveFromTypeReferenceDirective() {
const owner = this;
return cacheGeneratorMethod(owner, "getResolvedTypeReferenceDirectiveFromTypeReferenceDirective", function (typeReferenceDirective, sourceFile) {
const result = owner.client.apiRequest("getResolvedTypeReferenceDirectiveFromTypeReferenceDirective", {
snapshot: owner.snapshotId,
project: owner.project.handle,
sourceFile,
typeDirectiveName: typeReferenceDirective.fileName,
resolutionMode: typeReferenceDirective.resolutionMode,
});
return result ?? undefined;
}, function* (typeReferenceDirective, sourceFile) {
const result = yield* apiRequest("getResolvedTypeReferenceDirectiveFromTypeReferenceDirective", {
snapshot: owner.snapshotId,
project: owner.project.handle,
sourceFile,
typeDirectiveName: typeReferenceDirective.fileName,
resolutionMode: typeReferenceDirective.resolutionMode,
});
return result ?? undefined;
});
}
get getSourceFileNames() {
const owner = this;
return cacheGeneratorMethod(owner, "getSourceFileNames", function () {
const data = owner.client.apiRequest("getSourceFileNames", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
}, function* () {
const data = yield* apiRequest("getSourceFileNames", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
});
}
/**
* Returns program-stored metadata for the given source file, or `undefined` if the file
* is not part of the program. Metadata is fetched lazily per file and cached on this
* `Program` instance.
*/
get getSourceFileMetadata() {
const owner = this;
return cacheGeneratorMethod(owner, "getSourceFileMetadata", function (file) {
return owner.getSourceFileMetadataByPath(owner.pathKeyForFileName(resolveFileName(file)));
}, function* (file) {
return yield* owner.getSourceFileMetadataByPath.gen(owner.pathKeyForFileName(resolveFileName(file)));
});
}
/**
* Returns program-stored metadata for the source file at the given path, or `undefined`
* if the file is not part of the program. Like {@link getSourceFileMetadata}, but skips
* the file name to path conversion. Metadata is fetched lazily per file and cached on
* this `Program` instance.
*/
get getSourceFileMetadataByPath() {
const owner = this;
return cacheGeneratorMethod(owner, "getSourceFileMetadataByPath", function (path) {
let metadata = owner.sourceFileMetadataCache.get(path);
if (metadata === undefined) {
metadata = owner.fetchSourceFileMetadata(path);
owner.sourceFileMetadataCache.set(path, metadata);
}
return metadata;
}, function* (path) {
let metadata = owner.sourceFileMetadataCache.get(path);
if (metadata === undefined) {
metadata = yield* owner.fetchSourceFileMetadata.gen(path);
owner.sourceFileMetadataCache.set(path, metadata);
}
return metadata;
});
}
get fetchSourceFileMetadata() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSourceFileMetadata", function (path) {
// PathKey is serialized as a string; the server deliberately treats all
// client-provided path text as untrusted input.
const data = owner.client.apiRequest("getSourceFileMetadata", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file: path,
});
return data ?? undefined;
}, function* (path) {
// PathKey is serialized as a string; the server deliberately treats all
// client-provided path text as untrusted input.
const data = yield* apiRequest("getSourceFileMetadata", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file: path,
});
return data ?? undefined;
});
}
pathKeyForFileName(fileName) {
return this.toPath(fileName, this.project.currentDirectory);
}
/**
* Returns whether the given source file was loaded as part of an external library
* (e.g. a dependency resolved from `node_modules`). The underlying program metadata is
* fetched lazily per file and cached on this `Program` instance.
*/
get isSourceFileFromExternalLibrary() {
const owner = this;
return cacheGeneratorMethod(owner, "isSourceFileFromExternalLibrary", function (file) {
const metadata = owner.getSourceFileMetadataByPath(file.path);
return metadata?.isFromExternalLibrary ?? false;
}, function* (file) {
const metadata = yield* owner.getSourceFileMetadataByPath.gen(file.path);
return metadata?.isFromExternalLibrary ?? false;
});
}
/**
* Returns whether the given source file is a default library file (e.g. `lib.d.ts`).
* The underlying program metadata is fetched lazily per file and cached on this
* `Program` instance.
*/
get isSourceFileDefaultLibrary() {
const owner = this;
return cacheGeneratorMethod(owner, "isSourceFileDefaultLibrary", function (file) {
const metadata = owner.getSourceFileMetadataByPath(file.path);
return metadata?.isDefaultLibrary ?? false;
}, function* (file) {
const metadata = yield* owner.getSourceFileMetadataByPath.gen(file.path);
return metadata?.isDefaultLibrary ?? false;
});
}
/**
* Get all config source file names associated with this program's project config.
* Includes the root config file and any extended config files.
*/
get getConfigFileNames() {
const owner = this;
return cacheGeneratorMethod(owner, "getConfigFileNames", function () {
const data = owner.client.apiRequest("getConfigFileNames", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
}, function* () {
const data = yield* apiRequest("getConfigFileNames", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
});
}
/**
* Get a config source file by file name/URI.
* This can return the project's root tsconfig file or one of its extended config files.
*/
get getConfigSourceFile() {
const owner = this;
return cacheGeneratorMethod(owner, "getConfigSourceFile", function (file) {
const binaryData = owner.client.apiRequestBinary("getConfigSourceFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
});
if (!binaryData) {
return undefined;
}
return new RemoteSourceFile(binaryData, owner.decoder, undefined, owner.project.api);
}, function* (file) {
const binaryData = sourceFileResponseToUint8Array(yield* apiRequest("getConfigSourceFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
}));
if (!binaryData) {
return undefined;
}
return new RemoteSourceFile(binaryData, owner.decoder, undefined, owner.project.api);
});
}
/**
* Get syntactic (parse) diagnostics for specific files or all files.
* @param file - Optional file(s) to get diagnostics for. If omitted, returns diagnostics for all files.
*/
get getSyntacticDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getSyntacticDiagnostics", function (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = owner.client.apiRequest("getSyntacticDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
}, function* (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = yield* apiRequest("getSyntacticDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
});
}
/**
* Get binder diagnostics for specific files or all files.
* @param file - Optional file(s) to get diagnostics for. If omitted, returns diagnostics for all files.
*/
get getBindDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getBindDiagnostics", function (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = owner.client.apiRequest("getBindDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
}, function* (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = yield* apiRequest("getBindDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
});
}
/**
* Get semantic (type-check) diagnostics for specific files or all files.
* @param file - Optional file(s) to get diagnostics for. If omitted, returns diagnostics for all files.
*/
get getSemanticDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getSemanticDiagnostics", function (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = owner.client.apiRequest("getSemanticDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
}, function* (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = yield* apiRequest("getSemanticDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
});
}
/**
* Get suggestion diagnostics for specific files or all files.
* @param file - Optional file(s) to get diagnostics for. If omitted, returns diagnostics for all files.
*/
get getSuggestionDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getSuggestionDiagnostics", function (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = owner.client.apiRequest("getSuggestionDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
}, function* (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = yield* apiRequest("getSuggestionDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
});
}
/**
* Get declaration emit diagnostics for specific files or all files.
* @param file - Optional file(s) to get diagnostics for. If omitted, returns diagnostics for all files.
*/
get getDeclarationDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getDeclarationDiagnostics", function (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = owner.client.apiRequest("getDeclarationDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
}, function* (file) {
const files = file === undefined ? undefined
: Array.isArray(file) ? file
: [file];
const data = yield* apiRequest("getDeclarationDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return data ?? [];
});
}
/**
* Get program-wide diagnostics for the project, including compiler options diagnostics.
*/
get getProgramDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getProgramDiagnostics", function () {
const data = owner.client.apiRequest("getProgramDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
}, function* () {
const data = yield* apiRequest("getProgramDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
});
}
/**
* Get global (non-file-specific) semantic diagnostics for the project.
*/
get getGlobalDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getGlobalDiagnostics", function () {
const data = owner.client.apiRequest("getGlobalDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
}, function* () {
const data = yield* apiRequest("getGlobalDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
});
}
/**
* Get config file parsing diagnostics for the project.
*/
get getConfigFileParsingDiagnostics() {
const owner = this;
return cacheGeneratorMethod(owner, "getConfigFileParsingDiagnostics", function () {
const data = owner.client.apiRequest("getConfigFileParsingDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
}, function* () {
const data = yield* apiRequest("getConfigFileParsingDiagnostics", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return data ?? [];
});
}
/**
* Emits files to the configured filesystem. Layer and host filesystems are
* written through; full filesystems remain immutable and return emitted
* files in {@link EmitResult.fileSystem}.
*/
get emit() {
const owner = this;
return cacheGeneratorMethod(owner, "emit", function (emitOnly) {
const response = owner.client.apiRequest("emit", {
snapshot: owner.snapshotId,
project: owner.project.handle,
emitOnly,
});
const fileSystem = response.emittedFilesContents.length
? {
kind: "layer",
files: Object.fromEntries(response.emittedFiles.map((fileName, index) => [fileName, response.emittedFilesContents[index]])),
}
: undefined;
return {
emitSkipped: response.emitSkipped,
diagnostics: response.diagnostics,
emittedFiles: response.emittedFiles,
fileSystem,
};
}, function* (emitOnly) {
const response = yield* apiRequest("emit", {
snapshot: owner.snapshotId,
project: owner.project.handle,
emitOnly,
});
const fileSystem = response.emittedFilesContents.length
? {
kind: "layer",
files: Object.fromEntries(response.emittedFiles.map((fileName, index) => [fileName, response.emittedFilesContents[index]])),
}
: undefined;
return {
emitSkipped: response.emitSkipped,
diagnostics: response.diagnostics,
emittedFiles: response.emittedFiles,
fileSystem,
};
});
}
/**
* Emits files and returns their contents without writing to the filesystem.
*/
get emitToString() {
const owner = this;
return cacheGeneratorMethod(owner, "emitToString", function (emitOnly) {
const response = owner.client.apiRequest("emitToString", {
snapshot: owner.snapshotId,
project: owner.project.handle,
emitOnly,
});
return toEmitOutput(response);
}, function* (emitOnly) {
const response = yield* apiRequest("emitToString", {
snapshot: owner.snapshotId,
project: owner.project.handle,
emitOnly,
});
return toEmitOutput(response);
});
}
/**
* Gets JavaScript output for selected files regardless of project `noEmit`, `emitDeclarationOnly`, and `noEmitOnError` settings.
*/
get getJavaScriptEmit() {
const owner = this;
return cacheGeneratorMethod(owner, "getJavaScriptEmit", function (files) {
const response = owner.client.apiRequest("getJavaScriptEmit", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return toEmitOutput(response);
}, function* (files) {
const response = yield* apiRequest("getJavaScriptEmit", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return toEmitOutput(response);
});
}
/**
* Gets declaration output for selected files regardless of project `noEmit`, `declaration`, `emitDeclarationOnly`, and `noEmitOnError` settings.
*/
get getDeclarationEmit() {
const owner = this;
return cacheGeneratorMethod(owner, "getDeclarationEmit", function (files) {
const response = owner.client.apiRequest("getDeclarationEmit", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return toEmitOutput(response);
}, function* (files) {
const response = yield* apiRequest("getDeclarationEmit", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files,
});
return toEmitOutput(response);
});
}
getProject() {
return this.project;
}
}
export class BuildOrchestrator {
client;
id;
disposed = false;
disposePromise;
onDispose;
constructor(client, orchestratorResponse, onDispose) {
this.client = client;
this.id = orchestratorResponse.buildOrchestratorID;
this.onDispose = onDispose;
}
[globalThis.Symbol.dispose]() {
this.dispose();
}
get dispose() {
const owner = this;
return cacheGeneratorMethod(owner, "dispose", function () {
return owner.disposePromise ??= owner.disposeWorker();
}, function* () {
return owner.disposePromise ??= yield* owner.disposeWorker.gen();
});
}
get disposeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "disposeWorker", function () {
if (owner.disposed)
return;
owner.disposed = true;
try {
owner.client.apiRequest("disposeBuildOrchestrator", {
buildOrchestratorID: owner.id,
});
}
finally {
owner.onDispose();
}
}, function* () {
if (owner.disposed)
return;
owner.disposed = true;
try {
yield* apiRequest("disposeBuildOrchestrator", {
buildOrchestratorID: owner.id,
});
}
finally {
owner.onDispose();
}
});
}
get build() {
const owner = this;
return cacheGeneratorMethod(owner, "build", function (project) {
owner.ensureNotDisposed();
const response = owner.client.apiRequest("build", {
buildOrchestratorID: owner.id,
...(project !== undefined ? { project } : {}),
});
return response;
}, function* (project) {
owner.ensureNotDisposed();
const response = yield* apiRequest("build", {
buildOrchestratorID: owner.id,
...(project !== undefined ? { project } : {}),
});
return response;
});
}
get buildReferences() {
const owner = this;
return cacheGeneratorMethod(owner, "buildReferences", function (project) {
owner.ensureNotDisposed();
const response = owner.client.apiRequest("buildReferences", {
buildOrchestratorID: owner.id,
project,
});
return response;
}, function* (project) {
owner.ensureNotDisposed();
const response = yield* apiRequest("buildReferences", {
buildOrchestratorID: owner.id,
project,
});
return response;
});
}
get clean() {
const owner = this;
return cacheGeneratorMethod(owner, "clean", function (project) {
owner.ensureNotDisposed();
const response = owner.client.apiRequest("cleanBuild", {
buildOrchestratorID: owner.id,
...(project !== undefined ? { project } : {}),
});
return response;
}, function* (project) {
owner.ensureNotDisposed();
const response = yield* apiRequest("cleanBuild", {
buildOrchestratorID: owner.id,
...(project !== undefined ? { project } : {}),
});
return response;
});
}
get cleanReferences() {
const owner = this;
return cacheGeneratorMethod(owner, "cleanReferences", function (project) {
owner.ensureNotDisposed();
const response = owner.client.apiRequest("cleanReferences", {
buildOrchestratorID: owner.id,
...(project !== undefined ? { project } : {}),
});
return response;
}, function* (project) {
owner.ensureNotDisposed();
const response = yield* apiRequest("cleanReferences", {
buildOrchestratorID: owner.id,
...(project !== undefined ? { project } : {}),
});
return response;
});
}
isDisposed() {
return this.disposed;
}
ensureNotDisposed() {
if (this.disposed) {
throw new Error("Build orchestrator is disposed");
}
}
}
function toEmitOutput(response) {
const outputFiles = new Map();
for (const { fileName, ...outputFile } of response.outputFiles) {
outputFiles.set(fileName, outputFile);
}
return {
emitSkipped: response.emitSkipped,
diagnostics: response.diagnostics,
outputFiles,
};
}
export class Checker {
snapshotId;
project;
objectRegistry;
wellKnownSymbols;
wellKnownSignatures;
get client() {
return this.project.api.client;
}
constructor(snapshotId, project, objectRegistry) {
this.snapshotId = snapshotId;
this.project = project;
this.objectRegistry = objectRegistry;
}
dispose() {
this.objectRegistry.clear();
}
/** Get the merged symbol, or the original symbol if it has not been merged. */
get getMergedSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getMergedSymbol", function (symbol) {
const data = owner.client.apiRequest("getMergedSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
}, function* (symbol) {
const data = yield* apiRequest("getMergedSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
});
}
/**
* Get a node's merged symbol. For a declaration, prefer
* {@link Checker.getSymbolOfDeclaration} for a non-nullable result.
*/
get getSymbolOfNode() {
const owner = this;
return cacheGeneratorMethod(owner, "getSymbolOfNode", function (node) {
const data = owner.client.apiRequest("getSymbolOfNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (node) {
const data = yield* apiRequest("getSymbolOfNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
/** Get a declaration's merged symbol. */
get getSymbolOfDeclaration() {
const owner = this;
return cacheGeneratorMethod(owner, "getSymbolOfDeclaration", function (node) {
const data = owner.client.apiRequest("getSymbolOfDeclarationForChecker", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
// Declarations normally have symbols, but preserve unexpected null results at runtime.
return (data && owner.objectRegistry.getOrCreateSymbol(data));
}, function* (node) {
const data = yield* apiRequest("getSymbolOfDeclarationForChecker", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
// Declarations normally have symbols, but preserve unexpected null results at runtime.
return (data && owner.objectRegistry.getOrCreateSymbol(data));
});
}
/** Get a symbol's merged parent, if any. */
get getParentOfSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getParentOfSymbol", function (symbol) {
const data = owner.client.apiRequest("getParentOfSymbolForChecker", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (symbol) {
const data = yield* apiRequest("getParentOfSymbolForChecker", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
get getSymbolAtLocation() {
const owner = this;
function getSymbolAtLocation(nodeOrNodes) {
if (Array.isArray(nodeOrNodes)) {
const data = owner.client.apiRequest("getSymbolsAtLocations", {
snapshot: owner.snapshotId,
project: owner.project.handle,
locations: nodeOrNodes.map(node => getNodeRequestHandle(node)),
});
return data.map(d => d ? owner.objectRegistry.getOrCreateSymbol(d) : undefined);
}
const data = owner.client.apiRequest("getSymbolAtLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(nodeOrNodes),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}
function* gen(nodeOrNodes) {
if (Array.isArray(nodeOrNodes)) {
const data = yield* apiRequest("getSymbolsAtLocations", {
snapshot: owner.snapshotId,
project: owner.project.handle,
locations: nodeOrNodes.map(node => getNodeRequestHandle(node)),
});
return data.map(d => d ? owner.objectRegistry.getOrCreateSymbol(d) : undefined);
}
const data = yield* apiRequest("getSymbolAtLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(nodeOrNodes),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}
return cacheGeneratorMethod(owner, "getSymbolAtLocation", getSymbolAtLocation, gen);
}
get getSymbolAtPosition() {
const owner = this;
function getSymbolAtPosition(file, positionOrPositions) {
if (typeof positionOrPositions === "number") {
const data = owner.client.apiRequest("getSymbolAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
position: positionOrPositions,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}
const data = owner.client.apiRequest("getSymbolsAtPositions", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
positions: positionOrPositions,
});
return data.map(d => d ? owner.objectRegistry.getOrCreateSymbol(d) : undefined);
}
function* gen(file, positionOrPositions) {
if (typeof positionOrPositions === "number") {
const data = yield* apiRequest("getSymbolAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
position: positionOrPositions,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}
const data = yield* apiRequest("getSymbolsAtPositions", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
positions: positionOrPositions,
});
return data.map(d => d ? owner.objectRegistry.getOrCreateSymbol(d) : undefined);
}
return cacheGeneratorMethod(owner, "getSymbolAtPosition", getSymbolAtPosition, gen);
}
get getSymbolOfSourceFile() {
const owner = this;
function getSymbolOfSourceFile(fileOrFiles) {
if (Array.isArray(fileOrFiles)) {
const data = owner.client.apiRequest("getSymbolsOfSourceFiles", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files: fileOrFiles,
});
return data.map(d => d ? owner.objectRegistry.getOrCreateSymbol(d) : undefined);
}
const data = owner.client.apiRequest("getSymbolOfSourceFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file: fileOrFiles,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}
function* gen(fileOrFiles) {
if (Array.isArray(fileOrFiles)) {
const data = yield* apiRequest("getSymbolsOfSourceFiles", {
snapshot: owner.snapshotId,
project: owner.project.handle,
files: fileOrFiles,
});
return data.map(d => d ? owner.objectRegistry.getOrCreateSymbol(d) : undefined);
}
const data = yield* apiRequest("getSymbolOfSourceFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file: fileOrFiles,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}
return cacheGeneratorMethod(owner, "getSymbolOfSourceFile", getSymbolOfSourceFile, gen);
}
/**
* Get the type of a symbol. Always returns a type; for symbols whose type
* cannot be determined the checker yields the error type (use
* {@link Type.isErrorType} to detect it).
*/
get getTypeOfSymbol() {
const owner = this;
function getTypeOfSymbol(symbolOrSymbols) {
if (Array.isArray(symbolOrSymbols)) {
const data = owner.client.apiRequest("getTypesOfSymbols", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbols: symbolOrSymbols.map(symbol => symbol.reference),
});
return data.map(d => owner.objectRegistry.getOrCreateType(d));
}
const data = owner.client.apiRequest("getTypeOfSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbolOrSymbols.reference,
});
return owner.objectRegistry.getOrCreateType(data);
}
function* gen(symbolOrSymbols) {
if (Array.isArray(symbolOrSymbols)) {
const data = yield* apiRequest("getTypesOfSymbols", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbols: symbolOrSymbols.map(symbol => symbol.reference),
});
return data.map(d => owner.objectRegistry.getOrCreateType(d));
}
const data = yield* apiRequest("getTypeOfSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbolOrSymbols.reference,
});
return owner.objectRegistry.getOrCreateType(data);
}
return cacheGeneratorMethod(owner, "getTypeOfSymbol", getTypeOfSymbol, gen);
}
/**
* Get the declared type of a symbol. Always returns a type; for symbols whose
* declared type cannot be determined the checker yields the error type (use
* {@link Type.isErrorType} to detect it).
*/
get getDeclaredTypeOfSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getDeclaredTypeOfSymbol", function (symbol) {
const data = owner.client.apiRequest("getDeclaredTypeOfSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (symbol) {
const data = yield* apiRequest("getDeclaredTypeOfSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
/**
* Get the type of a symbol, excluding the missing type when
* `exactOptionalPropertyTypes: true` is set; for symbols whose
* type cannot be determined the checker yields the error type
* (use {@link Type.isErrorType} to detect it).
*/
get getNonMissingTypeOfSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getNonMissingTypeOfSymbol", function (symbol) {
const data = owner.client.apiRequest("getNonMissingTypeOfSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (symbol) {
const data = yield* apiRequest("getNonMissingTypeOfSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
get getReferencesToSymbolInFile() {
const owner = this;
return cacheGeneratorMethod(owner, "getReferencesToSymbolInFile", function (file, symbol) {
const data = owner.client.apiRequest("getReferencesToSymbolInFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
symbol: symbol.reference,
});
return (data ?? []).map(h => owner.objectRegistry.createNodeHandle(h));
}, function* (file, symbol) {
const data = yield* apiRequest("getReferencesToSymbolInFile", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
symbol: symbol.reference,
});
return (data ?? []).map(h => owner.objectRegistry.createNodeHandle(h));
});
}
/**
* Get the type at a node location. Always returns a type; for nodes whose
* type cannot be determined the checker yields the error type (use
* {@link Type.isErrorType} to detect it).
*/
get getTypeAtLocation() {
const owner = this;
function getTypeAtLocation(nodeOrNodes) {
if (Array.isArray(nodeOrNodes)) {
const data = owner.client.apiRequest("getTypeAtLocations", {
snapshot: owner.snapshotId,
project: owner.project.handle,
locations: nodeOrNodes.map(node => getNodeRequestHandle(node)),
});
return data.map(d => owner.objectRegistry.getOrCreateType(d));
}
const data = owner.client.apiRequest("getTypeAtLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(nodeOrNodes),
});
return owner.objectRegistry.getOrCreateType(data);
}
function* gen(nodeOrNodes) {
if (Array.isArray(nodeOrNodes)) {
const data = yield* apiRequest("getTypeAtLocations", {
snapshot: owner.snapshotId,
project: owner.project.handle,
locations: nodeOrNodes.map(node => getNodeRequestHandle(node)),
});
return data.map(d => owner.objectRegistry.getOrCreateType(d));
}
const data = yield* apiRequest("getTypeAtLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(nodeOrNodes),
});
return owner.objectRegistry.getOrCreateType(data);
}
return cacheGeneratorMethod(owner, "getTypeAtLocation", getTypeAtLocation, gen);
}
get getSignaturesOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getSignaturesOfType", function (type, kind) {
return kind === SignatureKind.Call ? type.getCallSignatures() : type.getConstructSignatures();
}, function* (type, kind) {
return kind === SignatureKind.Call ? (yield* type.getCallSignatures.gen()) : (yield* type.getConstructSignatures.gen());
});
}
/**
* Get the resolved signature of a call-like expression. Always returns a
* signature; when a call cannot be resolved the checker yields the unknown
* signature (use {@link Checker.isUnknownSignature} to detect it).
*/
get getResolvedSignature() {
const owner = this;
return cacheGeneratorMethod(owner, "getResolvedSignature", function (node) {
const data = owner.client.apiRequest("getResolvedSignature", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return owner.objectRegistry.getOrCreateSignature(data);
}, function* (node) {
const data = yield* apiRequest("getResolvedSignature", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return owner.objectRegistry.getOrCreateSignature(data);
});
}
get getTypeAtPosition() {
const owner = this;
function getTypeAtPosition(file, positionOrPositions) {
if (typeof positionOrPositions === "number") {
const data = owner.client.apiRequest("getTypeAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
position: positionOrPositions,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}
const data = owner.client.apiRequest("getTypesAtPositions", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
positions: positionOrPositions,
});
return data.map(d => d ? owner.objectRegistry.getOrCreateType(d) : undefined);
}
function* gen(file, positionOrPositions) {
if (typeof positionOrPositions === "number") {
const data = yield* apiRequest("getTypeAtPosition", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
position: positionOrPositions,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}
const data = yield* apiRequest("getTypesAtPositions", {
snapshot: owner.snapshotId,
project: owner.project.handle,
file,
positions: positionOrPositions,
});
return data.map(d => d ? owner.objectRegistry.getOrCreateType(d) : undefined);
}
return cacheGeneratorMethod(owner, "getTypeAtPosition", getTypeAtPosition, gen);
}
get resolveName() {
const owner = this;
return cacheGeneratorMethod(owner, "resolveName", function (name, meaning, location, excludeGlobals) {
// Distinguish Node (has `kind`) from DocumentPosition (has `document` and `position`)
const isNode = location && "kind" in location;
const data = owner.client.apiRequest("resolveName", {
snapshot: owner.snapshotId,
project: owner.project.handle,
name,
meaning,
location: isNode ? getNodeRequestHandle(location) : undefined,
file: !isNode && location ? location.document : undefined,
position: !isNode && location ? location.position : undefined,
excludeGlobals,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (name, meaning, location, excludeGlobals) {
// Distinguish Node (has `kind`) from DocumentPosition (has `document` and `position`)
const isNode = location && "kind" in location;
const data = yield* apiRequest("resolveName", {
snapshot: owner.snapshotId,
project: owner.project.handle,
name,
meaning,
location: isNode ? getNodeRequestHandle(location) : undefined,
file: !isNode && location ? location.document : undefined,
position: !isNode && location ? location.position : undefined,
excludeGlobals,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
/**
* Returns all symbols with the given meaning that are visible at `location`.
*/
get getSymbolsInScope() {
const owner = this;
return cacheGeneratorMethod(owner, "getSymbolsInScope", function (location, meaning) {
// Distinguish Node (has `kind`) from DocumentPosition (has `document` and `position`)
const isNode = "kind" in location;
const data = owner.client.apiRequest("getSymbolsInScope", {
snapshot: owner.snapshotId,
project: owner.project.handle,
meaning,
location: isNode ? getNodeRequestHandle(location) : undefined,
file: isNode ? undefined : location.document,
position: isNode ? undefined : location.position,
});
return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : [];
}, function* (location, meaning) {
// Distinguish Node (has `kind`) from DocumentPosition (has `document` and `position`)
const isNode = "kind" in location;
const data = yield* apiRequest("getSymbolsInScope", {
snapshot: owner.snapshotId,
project: owner.project.handle,
meaning,
location: isNode ? getNodeRequestHandle(location) : undefined,
file: isNode ? undefined : location.document,
position: isNode ? undefined : location.position,
});
return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : [];
});
}
get getResolvedSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getResolvedSymbol", function (node) {
const text = node.text;
if (!text)
return undefined;
return owner.resolveName(text, SymbolFlags.Value | SymbolFlags.ExportValue, node);
}, function* (node) {
const text = node.text;
if (!text)
return undefined;
return yield* owner.resolveName.gen(text, SymbolFlags.Value | SymbolFlags.ExportValue, node);
});
}
get getContextualType() {
const owner = this;
return cacheGeneratorMethod(owner, "getContextualType", function (node) {
const data = owner.client.apiRequest("getContextualType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}, function* (node) {
const data = yield* apiRequest("getContextualType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
});
}
get getContextualTypeForArgumentAtIndex() {
const owner = this;
return cacheGeneratorMethod(owner, "getContextualTypeForArgumentAtIndex", function (node, argIndex) {
const data = owner.client.apiRequest("getContextualTypeForArgument", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
index: argIndex,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}, function* (node, argIndex) {
const data = yield* apiRequest("getContextualTypeForArgument", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
index: argIndex,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
});
}
get getAwaitedType() {
const owner = this;
return cacheGeneratorMethod(owner, "getAwaitedType", function (type) {
const data = owner.client.apiRequest("getAwaitedType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}, function* (type) {
const data = yield* apiRequest("getAwaitedType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
});
}
/** Get the base type of a literal type (e.g. `number` for `42`). Always returns a type. */
get getBaseTypeOfLiteralType() {
const owner = this;
return cacheGeneratorMethod(owner, "getBaseTypeOfLiteralType", function (type) {
const data = owner.client.apiRequest("getBaseTypeOfLiteralType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (type) {
const data = yield* apiRequest("getBaseTypeOfLiteralType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
/** Get the type with `null` and `undefined` removed. Always returns a type. */
get getNonNullableType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNonNullableType", function (type) {
return type.getNonNullableType();
}, function* (type) {
return yield* type.getNonNullableType.gen();
});
}
/**
* Get the type for a type node. Always returns a type; for type nodes whose
* type cannot be determined the checker yields the error type (use
* {@link Type.isErrorType} to detect it).
*/
get getTypeFromTypeNode() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeFromTypeNode", function (node) {
const data = owner.client.apiRequest("getTypeFromTypeNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (node) {
const data = yield* apiRequest("getTypeFromTypeNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return owner.objectRegistry.getOrCreateType(data);
});
}
/** Get the widened type. Always returns a type. */
get getWidenedType() {
const owner = this;
return cacheGeneratorMethod(owner, "getWidenedType", function (type) {
const data = owner.client.apiRequest("getWidenedType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (type) {
const data = yield* apiRequest("getWidenedType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
/**
* Get the type of the parameter at the given index in a signature. Always
* returns a type; an out-of-range index yields the `any` type.
*/
get getParameterType() {
const owner = this;
return cacheGeneratorMethod(owner, "getParameterType", function (signature, index) {
const data = owner.client.apiRequest("getParameterType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
index,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (signature, index) {
const data = yield* apiRequest("getParameterType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
index,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
get isArrayLikeType() {
const owner = this;
return cacheGeneratorMethod(owner, "isArrayLikeType", function (type) {
return owner.client.apiRequest("isArrayLikeType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
}, function* (type) {
return yield* apiRequest("isArrayLikeType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
});
}
get isTypeAssignableTo() {
const owner = this;
return cacheGeneratorMethod(owner, "isTypeAssignableTo", function (source, target) {
return owner.client.apiRequest("isTypeAssignableTo", {
snapshot: owner.snapshotId,
project: owner.project.handle,
source: source.id,
target: target.id,
});
}, function* (source, target) {
return yield* apiRequest("isTypeAssignableTo", {
snapshot: owner.snapshotId,
project: owner.project.handle,
source: source.id,
target: target.id,
});
});
}
get getShorthandAssignmentValueSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getShorthandAssignmentValueSymbol", function (node) {
const data = owner.client.apiRequest("getShorthandAssignmentValueSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (node) {
const data = yield* apiRequest("getShorthandAssignmentValueSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
/**
* Get the type of a symbol as narrowed at a specific location. Always returns
* a type; for symbols whose type cannot be determined the checker yields the
* error type (use {@link Type.isErrorType} to detect it).
*/
get getTypeOfSymbolAtLocation() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeOfSymbolAtLocation", function (symbol, location) {
const data = owner.client.apiRequest("getTypeOfSymbolAtLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
location: getNodeRequestHandle(location),
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (symbol, location) {
const data = yield* apiRequest("getTypeOfSymbolAtLocation", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
location: getNodeRequestHandle(location),
});
return owner.objectRegistry.getOrCreateType(data);
});
}
get getIntrinsicType() {
const owner = this;
return cacheGeneratorMethod(owner, "getIntrinsicType", function (method) {
const data = owner.client.apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (method) {
const data = yield* apiRequest(method, {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
get getAnyType() {
const owner = this;
return cacheGeneratorMethod(owner, "getAnyType", function () {
return owner.getIntrinsicType("getAnyType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getAnyType");
});
}
get getStringType() {
const owner = this;
return cacheGeneratorMethod(owner, "getStringType", function () {
return owner.getIntrinsicType("getStringType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getStringType");
});
}
get getNumberType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNumberType", function () {
return owner.getIntrinsicType("getNumberType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getNumberType");
});
}
get getBooleanType() {
const owner = this;
return cacheGeneratorMethod(owner, "getBooleanType", function () {
return owner.getIntrinsicType("getBooleanType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getBooleanType");
});
}
get getVoidType() {
const owner = this;
return cacheGeneratorMethod(owner, "getVoidType", function () {
return owner.getIntrinsicType("getVoidType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getVoidType");
});
}
get getUndefinedType() {
const owner = this;
return cacheGeneratorMethod(owner, "getUndefinedType", function () {
return owner.getIntrinsicType("getUndefinedType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getUndefinedType");
});
}
get getNullType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNullType", function () {
return owner.getIntrinsicType("getNullType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getNullType");
});
}
get getNeverType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNeverType", function () {
return owner.getIntrinsicType("getNeverType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getNeverType");
});
}
get getUnknownType() {
const owner = this;
return cacheGeneratorMethod(owner, "getUnknownType", function () {
return owner.getIntrinsicType("getUnknownType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getUnknownType");
});
}
get getBigIntType() {
const owner = this;
return cacheGeneratorMethod(owner, "getBigIntType", function () {
return owner.getIntrinsicType("getBigIntType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getBigIntType");
});
}
get getESSymbolType() {
const owner = this;
return cacheGeneratorMethod(owner, "getESSymbolType", function () {
return owner.getIntrinsicType("getESSymbolType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getESSymbolType");
});
}
get getNonPrimitiveType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNonPrimitiveType", function () {
return owner.getIntrinsicType("getNonPrimitiveType");
}, function* () {
return yield* owner.getIntrinsicType.gen("getNonPrimitiveType");
});
}
get typeToTypeNode() {
const owner = this;
return cacheGeneratorMethod(owner, "typeToTypeNode", function (type, enclosingDeclaration, flags) {
const binaryData = owner.client.apiRequestBinary("typeToTypeNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
location: enclosingDeclaration ? getNodeRequestHandle(enclosingDeclaration) : undefined,
flags,
});
if (!binaryData)
return undefined;
return decodeNode(binaryData);
}, function* (type, enclosingDeclaration, flags) {
const binaryData = sourceFileResponseToUint8Array(yield* apiRequest("typeToTypeNode", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
location: enclosingDeclaration ? getNodeRequestHandle(enclosingDeclaration) : undefined,
flags,
}));
if (!binaryData)
return undefined;
return decodeNode(binaryData);
});
}
get signatureToSignatureDeclaration() {
const owner = this;
return cacheGeneratorMethod(owner, "signatureToSignatureDeclaration", function (signature, kind, enclosingDeclaration, flags) {
const binaryData = owner.client.apiRequestBinary("signatureToSignatureDeclaration", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
kind,
location: enclosingDeclaration ? getNodeRequestHandle(enclosingDeclaration) : undefined,
flags,
});
if (!binaryData)
return undefined;
return decodeNode(binaryData);
}, function* (signature, kind, enclosingDeclaration, flags) {
const binaryData = sourceFileResponseToUint8Array(yield* apiRequest("signatureToSignatureDeclaration", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
kind,
location: enclosingDeclaration ? getNodeRequestHandle(enclosingDeclaration) : undefined,
flags,
}));
if (!binaryData)
return undefined;
return decodeNode(binaryData);
});
}
get typeToString() {
const owner = this;
return cacheGeneratorMethod(owner, "typeToString", function (type, enclosingDeclaration, flags) {
const result = owner.client.apiRequest("typeToString", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
location: enclosingDeclaration ? getNodeRequestHandle(enclosingDeclaration) : undefined,
flags,
});
if (typeof result !== "string")
throw new TypeError("typeToString returned a non-string result");
return result;
}, function* (type, enclosingDeclaration, flags) {
const result = yield* apiRequest("typeToString", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
location: enclosingDeclaration ? getNodeRequestHandle(enclosingDeclaration) : undefined,
flags,
});
if (typeof result !== "string")
throw new TypeError("typeToString returned a non-string result");
return result;
});
}
get isContextSensitive() {
const owner = this;
return cacheGeneratorMethod(owner, "isContextSensitive", function (node) {
return owner.client.apiRequest("isContextSensitive", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
}, function* (node) {
return yield* apiRequest("isContextSensitive", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
});
}
get isArrayType() {
const owner = this;
return cacheGeneratorMethod(owner, "isArrayType", function (type) {
return owner.client.apiRequest("isArrayType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
}, function* (type) {
return yield* apiRequest("isArrayType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
});
}
get isTupleType() {
const owner = this;
return cacheGeneratorMethod(owner, "isTupleType", function (type) {
return type.isTupleType();
}, function* (type) {
return type.isTupleType();
});
}
get isTupleTypeTarget() {
const owner = this;
return cacheGeneratorMethod(owner, "isTupleTypeTarget", function (type) {
return type.isTupleTypeTarget();
}, function* (type) {
return type.isTupleTypeTarget();
});
}
/**
* The following symbols are considered read-only:
* - Properties with a `readonly` modifier
* - Variables declared with `const`
* - Get accessors without matching set accessors
* - Enum members
* - `Object.defineProperty` assignments with `writable: false` or no setter
* - Unions and intersections of the above
*/
get isReadonlySymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "isReadonlySymbol", function (symbol) {
return owner.client.apiRequest("isReadonlySymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
}, function* (symbol) {
return yield* apiRequest("isReadonlySymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
});
}
/** Get the return type of a signature. Always returns a type. */
get getReturnTypeOfSignature() {
const owner = this;
return cacheGeneratorMethod(owner, "getReturnTypeOfSignature", function (signature) {
return signature.getReturnType();
}, function* (signature) {
return yield* signature.getReturnType.gen();
});
}
/**
* Get the rest type of a signature. Always returns a type; a signature with
* no rest parameter yields the `any` type.
*/
get getRestTypeOfSignature() {
const owner = this;
return cacheGeneratorMethod(owner, "getRestTypeOfSignature", function (signature) {
const data = owner.client.apiRequest("getRestTypeOfSignature", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
});
return owner.objectRegistry.getOrCreateType(data);
}, function* (signature) {
const data = yield* apiRequest("getRestTypeOfSignature", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
});
return owner.objectRegistry.getOrCreateType(data);
});
}
get getTypePredicateOfSignature() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypePredicateOfSignature", function (signature) {
const data = owner.client.apiRequest("getTypePredicateOfSignature", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
});
if (!data)
return undefined;
return {
kind: data.kind,
parameterIndex: data.parameterIndex,
parameterName: data.parameterName,
type: data.type ? owner.objectRegistry.getOrCreateType(data.type) : undefined,
};
}, function* (signature) {
const data = yield* apiRequest("getTypePredicateOfSignature", {
snapshot: owner.snapshotId,
project: owner.project.handle,
signature: signature.id,
});
if (!data)
return undefined;
return {
kind: data.kind,
parameterIndex: data.parameterIndex,
parameterName: data.parameterName,
type: data.type ? owner.objectRegistry.getOrCreateType(data.type) : undefined,
};
});
}
/**
* Get the base types of a class or interface type. A type with no base types
* yields an empty array.
*/
get getBaseTypes() {
const owner = this;
return cacheGeneratorMethod(owner, "getBaseTypes", function (type) {
return type.getBaseTypes() ?? [];
}, function* (type) {
return (yield* type.getBaseTypes.gen()) ?? [];
});
}
/** Get the apparent type of a type. Always returns a type. */
get getApparentType() {
const owner = this;
return cacheGeneratorMethod(owner, "getApparentType", function (type) {
return type.getApparentType();
}, function* (type) {
return yield* type.getApparentType.gen();
});
}
/** Get the reduced type of a type. Always returns a type. */
get getReducedType() {
const owner = this;
return cacheGeneratorMethod(owner, "getReducedType", function (type) {
return type.getReducedType();
}, function* (type) {
return yield* type.getReducedType.gen();
});
}
get getPropertiesOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getPropertiesOfType", function (type) {
return type.getProperties();
}, function* (type) {
return yield* type.getProperties.gen();
});
}
get getIndexInfosOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getIndexInfosOfType", function (type) {
return type.getIndexInfos();
}, function* (type) {
return yield* type.getIndexInfos.gen();
});
}
get getIndexInfoOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getIndexInfoOfType", function (type, kind) {
const data = owner.client.apiRequest("getIndexInfoOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
kind,
});
return data ? {
keyType: owner.objectRegistry.getOrCreateType(data.keyType),
valueType: owner.objectRegistry.getOrCreateType(data.valueType),
isReadonly: data.isReadonly ?? false,
declaration: data.declaration ? owner.objectRegistry.createNodeHandle(data.declaration) : undefined,
} : undefined;
}, function* (type, kind) {
const data = yield* apiRequest("getIndexInfoOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
kind,
});
return data ? {
keyType: owner.objectRegistry.getOrCreateType(data.keyType),
valueType: owner.objectRegistry.getOrCreateType(data.valueType),
isReadonly: data.isReadonly ?? false,
declaration: data.declaration ? owner.objectRegistry.createNodeHandle(data.declaration) : undefined,
} : undefined;
});
}
get getIndexTypeOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getIndexTypeOfType", function (type, kind) {
return kind === IndexKind.String ? type.getStringIndexType() : type.getNumberIndexType();
}, function* (type, kind) {
return kind === IndexKind.String ? (yield* type.getStringIndexType.gen()) : (yield* type.getNumberIndexType.gen());
});
}
get getTypeOfPropertyOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeOfPropertyOfType", function (type, propertyName) {
const data = owner.client.apiRequest("getTypeOfPropertyOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
name: propertyName,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}, function* (type, propertyName) {
const data = yield* apiRequest("getTypeOfPropertyOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
name: propertyName,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
});
}
/**
* Get the constraint of a type parameter (the `T` in `<U extends T>`), or
* undefined if it has none.
*/
get getConstraintOfTypeParameter() {
const owner = this;
return cacheGeneratorMethod(owner, "getConstraintOfTypeParameter", function (type) {
return type.getConstraint();
}, function* (type) {
return yield* type.getConstraint.gen();
});
}
get getDefaultFromTypeParameter() {
const owner = this;
return cacheGeneratorMethod(owner, "getDefaultFromTypeParameter", function (type) {
return type.getDefault();
}, function* (type) {
return yield* type.getDefault.gen();
});
}
get getBaseConstraintOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getBaseConstraintOfType", function (type) {
const data = owner.client.apiRequest("getBaseConstraintOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
}, function* (type) {
const data = yield* apiRequest("getBaseConstraintOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return data ? owner.objectRegistry.getOrCreateType(data) : undefined;
});
}
get getPropertyOfType() {
const owner = this;
return cacheGeneratorMethod(owner, "getPropertyOfType", function (type, name) {
const data = owner.client.apiRequest("getPropertyOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
name,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (type, name) {
const data = yield* apiRequest("getPropertyOfType", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
name,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
get getConstantValue() {
const owner = this;
return cacheGeneratorMethod(owner, "getConstantValue", function (node) {
const data = owner.client.apiRequest("getConstantValue", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
if (!data || (typeof data.value !== "string" && typeof data.value !== "number")) {
return undefined;
}
if (data.isNumber && typeof data.value === "string") {
if (data.value === "+Infinity") {
return Infinity;
}
else if (data.value === "-Infinity") {
return -Infinity;
}
return NaN;
}
return data.value;
}, function* (node) {
const data = yield* apiRequest("getConstantValue", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
if (!data || (typeof data.value !== "string" && typeof data.value !== "number")) {
return undefined;
}
if (data.isNumber && typeof data.value === "string") {
if (data.value === "+Infinity") {
return Infinity;
}
else if (data.value === "-Infinity") {
return -Infinity;
}
return NaN;
}
return data.value;
});
}
/** Get the signature of a function-like declaration. Always returns a signature. */
get getSignatureFromDeclaration() {
const owner = this;
return cacheGeneratorMethod(owner, "getSignatureFromDeclaration", function (node) {
const data = owner.client.apiRequest("getSignatureFromDeclaration", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return owner.objectRegistry.getOrCreateSignature(data);
}, function* (node) {
const data = yield* apiRequest("getSignatureFromDeclaration", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return owner.objectRegistry.getOrCreateSignature(data);
});
}
get getExportSpecifierLocalTargetSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getExportSpecifierLocalTargetSymbol", function (node) {
const data = owner.client.apiRequest("getExportSpecifierLocalTargetSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (node) {
const data = yield* apiRequest("getExportSpecifierLocalTargetSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
location: getNodeRequestHandle(node),
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
/**
* Follow all aliases to get the original symbol. Always returns a symbol; for
* an unresolved alias the checker yields the unknown symbol (use
* {@link Checker.isUnknownSymbol} to detect it).
*/
get getAliasedSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getAliasedSymbol", function (symbol) {
const data = owner.client.apiRequest("getAliasedSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
}, function* (symbol) {
const data = yield* apiRequest("getAliasedSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
});
}
/**
* Get the fully qualified name of a symbol, walking up its parent chain
* (e.g. `"/path/to/module".Namespace.Name`).
*/
get getFullyQualifiedName() {
const owner = this;
return cacheGeneratorMethod(owner, "getFullyQualifiedName", function (symbol) {
return owner.client.apiRequest("getFullyQualifiedName", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
}, function* (symbol) {
return yield* apiRequest("getFullyQualifiedName", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
});
}
get getImmediateAliasedSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getImmediateAliasedSymbol", function (symbol) {
const data = owner.client.apiRequest("getImmediateAliasedSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (symbol) {
const data = yield* apiRequest("getImmediateAliasedSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
/**
* Get the target symbol if instantiated, or the provided symbol otherwise.
*/
get getTargetSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getTargetSymbol", function (symbol) {
if (symbol.checkFlags & CheckFlags.Instantiated) {
const data = owner.client.apiRequest("getTargetSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
}
return symbol;
}, function* (symbol) {
if (symbol.checkFlags & CheckFlags.Instantiated) {
const data = yield* apiRequest("getTargetSymbol", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
}
return symbol;
});
}
get getExportSymbolOfSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getExportSymbolOfSymbol", function (symbol) {
const data = owner.client.apiRequest("getExportSymbolOfSymbolForChecker", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
}, function* (symbol) {
const data = yield* apiRequest("getExportSymbolOfSymbolForChecker", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return owner.objectRegistry.getOrCreateSymbol(data);
});
}
/**
* Fetch (once, then cache) the handle ids of the per-checker singleton
* symbols (unknown, undefined, arguments). These ids are stable for the life
* of the project's checker, so identity checks against them are local after
* the first call.
*/
get getWellKnownSymbols() {
const owner = this;
return cacheGeneratorMethod(owner, "getWellKnownSymbols", function () {
return owner.wellKnownSymbols ??= owner.client.apiRequest("getWellKnownSymbols", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
}, function* () {
return owner.wellKnownSymbols ??= yield* apiRequest("getWellKnownSymbols", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
});
}
/**
* Returns `true` if the symbol is the checker's "unknown" symbol (e.g. the
* result of {@link Checker.getAliasedSymbol} on an unresolved alias).
*/
get isUnknownSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "isUnknownSymbol", function (symbol) {
return symbol.id === (owner.getWellKnownSymbols()).unknown;
}, function* (symbol) {
return symbol.id === (yield* owner.getWellKnownSymbols.gen()).unknown;
});
}
/**
* Returns `true` if the symbol is the checker's "undefined" symbol.
*/
get isUndefinedSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "isUndefinedSymbol", function (symbol) {
return symbol.id === (owner.getWellKnownSymbols()).undefined;
}, function* (symbol) {
return symbol.id === (yield* owner.getWellKnownSymbols.gen()).undefined;
});
}
/**
* Returns `true` if the symbol is the checker's "arguments" symbol.
*/
get isArgumentsSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "isArgumentsSymbol", function (symbol) {
return symbol.id === (owner.getWellKnownSymbols()).arguments;
}, function* (symbol) {
return symbol.id === (yield* owner.getWellKnownSymbols.gen()).arguments;
});
}
/**
* Fetch (once, then cache) the handle id of the per-checker unknown
* signature. This id is stable for the life of the project's checker, so
* identity checks against it are local after the first call.
*/
get getWellKnownSignatures() {
const owner = this;
return cacheGeneratorMethod(owner, "getWellKnownSignatures", function () {
return owner.wellKnownSignatures ??= owner.client.apiRequest("getWellKnownSignatures", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
}, function* () {
return owner.wellKnownSignatures ??= yield* apiRequest("getWellKnownSignatures", {
snapshot: owner.snapshotId,
project: owner.project.handle,
});
});
}
/**
* Returns `true` if the signature is the checker's "unknown" signature (e.g.
* the result of {@link Checker.getResolvedSignature} on a call that cannot be
* resolved).
*/
get isUnknownSignature() {
const owner = this;
return cacheGeneratorMethod(owner, "isUnknownSignature", function (signature) {
return signature.id === (owner.getWellKnownSignatures()).unknown;
}, function* (signature) {
return signature.id === (yield* owner.getWellKnownSignatures.gen()).unknown;
});
}
get getExportsOfModule() {
const owner = this;
return cacheGeneratorMethod(owner, "getExportsOfModule", function (symbol) {
const data = owner.client.apiRequest("getExportsOfModule", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : [];
}, function* (symbol) {
const data = yield* apiRequest("getExportsOfModule", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : [];
});
}
get getMemberInModuleExports() {
const owner = this;
return cacheGeneratorMethod(owner, "getMemberInModuleExports", function (symbol, name) {
const data = owner.client.apiRequest("getMemberInModuleExports", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
name,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
}, function* (symbol, name) {
const data = yield* apiRequest("getMemberInModuleExports", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
name,
});
return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined;
});
}
get getJsDocTagsOfSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getJsDocTagsOfSymbol", function (symbol) {
const data = owner.client.apiRequest("getJsDocTags", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ?? [];
}, function* (symbol) {
const data = yield* apiRequest("getJsDocTags", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
return data ?? [];
});
}
get getDocumentationCommentOfSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getDocumentationCommentOfSymbol", function (symbol) {
return owner.client.apiRequest("getDocumentationComment", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
}, function* (symbol) {
return yield* apiRequest("getDocumentationComment", {
snapshot: owner.snapshotId,
project: owner.project.handle,
symbol: symbol.reference,
});
});
}
/**
* Get the type arguments of a type reference (e.g. the `string` in `Array<string>`).
*/
get getTypeArguments() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeArguments", function (type) {
const data = owner.client.apiRequest("getTypeArguments", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return data ? data.map(d => owner.objectRegistry.getOrCreateType(d)) : [];
}, function* (type) {
const data = yield* apiRequest("getTypeArguments", {
snapshot: owner.snapshotId,
project: owner.project.handle,
type: type.id,
});
return data ? data.map(d => owner.objectRegistry.getOrCreateType(d)) : [];
});
}
}
export class Printer {
client;
constructor(client) {
this.client = client;
}
get printNode() {
const owner = this;
return cacheGeneratorMethod(owner, "printNode", function (node, options = {}) {
const encoded = encodeNode(node);
const base64 = uint8ArrayToBase64(encoded);
return owner.client.apiRequest("printNode", {
data: base64,
preserveSourceNewlines: options.preserveSourceNewlines,
neverAsciiEscape: options.neverAsciiEscape,
terminateUnterminatedLiterals: options.terminateUnterminatedLiterals,
});
}, function* (node, options = {}) {
const encoded = encodeNode(node);
const base64 = uint8ArrayToBase64(encoded);
return yield* apiRequest("printNode", {
data: base64,
preserveSourceNewlines: options.preserveSourceNewlines,
neverAsciiEscape: options.neverAsciiEscape,
terminateUnterminatedLiterals: options.terminateUnterminatedLiterals,
});
});
}
get printFile() {
const owner = this;
return cacheGeneratorMethod(owner, "printFile", function (sourceFile, options = {}) {
const encoded = encodeNode(sourceFile);
const base64 = uint8ArrayToBase64(encoded);
return owner.client.apiRequest("printNode", {
data: base64,
preserveSourceNewlines: options.preserveSourceNewlines,
neverAsciiEscape: options.neverAsciiEscape,
terminateUnterminatedLiterals: options.terminateUnterminatedLiterals,
});
}, function* (sourceFile, options = {}) {
const encoded = encodeNode(sourceFile);
const base64 = uint8ArrayToBase64(encoded);
return yield* apiRequest("printNode", {
data: base64,
preserveSourceNewlines: options.preserveSourceNewlines,
neverAsciiEscape: options.neverAsciiEscape,
terminateUnterminatedLiterals: options.terminateUnterminatedLiterals,
});
});
}
}
export class NodeHandle {
/**
* The project where this handle was first materialized, used as the default for {@link resolve}.
* Node handles are only meaningful within a project's program, so the producing project
* is remembered so callers don't have to pass it explicitly.
*/
canonicalProject;
/** The owning source file of a file-owned symbol's declaration. */
fileOwner;
index;
kind;
/** Identity of the exact parsed source file, shared across programs that reuse that AST. */
sourceFileId;
/** Retrieval metadata; never used to substitute a different source-file AST. */
path;
constructor(handle, canonicalProject, fileOwner) {
const parsed = parseNodeHandleFromCompiler(handle);
this.index = parsed.index;
this.kind = parsed.kind;
this.sourceFileId = parsed.sourceFileId;
this.path = parsed.path;
this.canonicalProject = canonicalProject;
this.fileOwner = fileOwner;
}
/**
* Resolve this handle to the actual AST node by fetching the source file from a project
* and looking up the node by index. If no project is passed, the project that produced
* the handle is used. Declarations of file-owned symbols identify an exact source file and
* resolve through it, independently of any project. A different AST at the
* same path is never substituted.
*/
get resolve() {
const owner = this;
return cacheGeneratorMethod(owner, "resolve", function (project = owner.canonicalProject) {
if (owner.fileOwner) {
const sourceFile = owner.fileOwner.record.file ?? owner.fetchOwnerFile(owner.fileOwner);
return owner.resolveInFile(sourceFile);
}
if (!project)
throw new Error(`Node handle for source file '${owner.sourceFileId}' has no project context`);
const sourceFile = project.program.getSourceFileByPath(owner.path);
if (!sourceFile) {
throw new Error("Node handle source file is not part of the requested program");
}
return owner.resolveInFile(sourceFile);
}, function* (project = owner.canonicalProject) {
if (owner.fileOwner) {
const sourceFile = owner.fileOwner.record.file ?? (yield* owner.fetchOwnerFile.gen(owner.fileOwner));
return owner.resolveInFile(sourceFile);
}
if (!project)
throw new Error(`Node handle for source file '${owner.sourceFileId}' has no project context`);
const sourceFile = yield* project.program.getSourceFileByPath.gen(owner.path);
if (!sourceFile) {
throw new Error("Node handle source file is not part of the requested program");
}
return owner.resolveInFile(sourceFile);
});
}
resolveInFile(sourceFile) {
if (sourceFile.nodeId !== this.sourceFileId) {
throw new Error(`Node handle source file is not part of the requested program`);
}
const node = sourceFile.getOrCreateNodeAtIndex(this.index);
if (!node || node.kind !== this.kind) {
throw new Error("Node handle does not identify a node of the expected kind");
}
return node;
}
get fetchOwnerFile() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchOwnerFile", function (fileOwner) {
const data = fileOwner.api.client.apiRequestBinary("getCachedSourceFile", { file: fileOwner.record.descriptor });
if (!data)
throw new Error(`Source file '${fileOwner.record.descriptor.fileName}' is not available`);
return fileOwner.api.sourceFileCache.attachFile(fileOwner.record, new RemoteSourceFile(data, new Wtf8Decoder(), fileOwner.api.client.getTimingCollector(), fileOwner.api));
}, function* (fileOwner) {
const data = sourceFileResponseToUint8Array(yield* apiRequest("getCachedSourceFile", { file: fileOwner.record.descriptor }));
if (!data)
throw new Error(`Source file '${fileOwner.record.descriptor.fileName}' is not available`);
return fileOwner.api.sourceFileCache.attachFile(fileOwner.record, new RemoteSourceFile(data, new Wtf8Decoder(), fileOwner.api.client.getTimingCollector(), fileOwner.api));
});
}
}
export class Symbol {
storage;
get id() {
return this.reference.id;
}
/** The escaped (`__String`) name, used as the key in member/export tables. */
escapedName;
/** The display name (escaped underscores removed). */
name;
flags;
checkFlags;
/** @internal */
reference;
// Declaration handles are kept in their wire form until first accessed.
declarationHandles;
valueDeclarationHandle;
declarationsCache;
valueDeclarationCache;
parent;
exportSymbol;
membersCache;
exportsCache;
constructor(data, storage) {
if (data.reference.kind !== storage.kind)
throw new Error(`Symbol ${data.reference.id} has mismatched ownership and storage`);
this.storage = storage;
this.reference = data.reference;
this.escapedName = data.name;
this.name = unescapeLeadingUnderscores(data.name);
this.flags = data.flags;
this.checkFlags = data.checkFlags ?? 0;
this.declarationHandles = data.declarations;
this.valueDeclarationHandle = data.valueDeclaration;
this.declarationsCache = undefined;
this.valueDeclarationCache = undefined;
if (data.parent !== undefined)
this.parent = data.parent;
if (data.exportSymbol !== undefined)
this.exportSymbol = data.exportSymbol;
}
get declarations() {
return this.declarationsCache ??= this.declarationHandles?.map(handle => this.createDeclarationHandle(handle)) ?? [];
}
get valueDeclaration() {
if (this.valueDeclarationCache === undefined && this.valueDeclarationHandle) {
this.valueDeclarationCache = this.createDeclarationHandle(this.valueDeclarationHandle);
}
return this.valueDeclarationCache;
}
createDeclarationHandle(handle) {
// A file-owned symbol has no canonical project; its declarations resolve through its file.
return this.storage.kind === SymbolOwnerKind.Snapshot
? this.storage.registry.createNodeHandle(handle)
: new NodeHandle(handle, undefined, this.storage.owner);
}
get getParent() {
const owner = this;
return cacheGeneratorMethod(owner, "getParent", function () {
if (!owner.parent)
return undefined;
return owner.fetchSymbol("getParentOfSymbol", owner.parent);
}, function* () {
if (!owner.parent)
return undefined;
return yield* owner.fetchSymbol.gen("getParentOfSymbol", owner.parent);
});
}
/**
* Get this symbol's members keyed by escaped name. The result is cached on
* the symbol, so repeated calls do not round-trip to the server.
*/
get getMembers() {
const owner = this;
return cacheGeneratorMethod(owner, "getMembers", function () {
return owner.membersCache ??= owner.fetchSymbolTable("getMembersOfSymbol");
}, function* () {
return owner.membersCache ??= yield* owner.fetchSymbolTable.gen("getMembersOfSymbol");
});
}
/**
* Get this symbol's exports keyed by escaped name. The result is cached on
* the symbol, so repeated calls do not round-trip to the server.
*/
get getExports() {
const owner = this;
return cacheGeneratorMethod(owner, "getExports", function () {
return owner.exportsCache ??= owner.fetchSymbolTable("getExportsOfSymbol");
}, function* () {
return owner.exportsCache ??= yield* owner.fetchSymbolTable.gen("getExportsOfSymbol");
});
}
get fetchSymbolTable() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSymbolTable", function (method) {
const symbols = owner.fetchSymbols(method);
const table = new Map();
for (const symbol of symbols) {
table.set(symbol.escapedName, symbol);
}
return table;
}, function* (method) {
const symbols = yield* owner.fetchSymbols.gen(method);
const table = new Map();
for (const symbol of symbols) {
table.set(symbol.escapedName, symbol);
}
return table;
});
}
get getExportSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getExportSymbol", function () {
if (!owner.exportSymbol)
return owner;
return owner.fetchSymbol("getExportSymbolOfSymbol", owner.exportSymbol);
}, function* () {
if (!owner.exportSymbol)
return owner;
return yield* owner.fetchSymbol.gen("getExportSymbolOfSymbol", owner.exportSymbol);
});
}
get getJsDocTags() {
const owner = this;
return cacheGeneratorMethod(owner, "getJsDocTags", function (checker) {
return checker.getJsDocTagsOfSymbol(owner);
}, function* (checker) {
return yield* checker.getJsDocTagsOfSymbol.gen(owner);
});
}
get getDocumentationComment() {
const owner = this;
return cacheGeneratorMethod(owner, "getDocumentationComment", function (checker) {
return checker.getDocumentationCommentOfSymbol(owner);
}, function* (checker) {
return yield* checker.getDocumentationCommentOfSymbol.gen(owner);
});
}
get fetchSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSymbol", function (method, reference) {
if (owner.storage.kind === SymbolOwnerKind.Snapshot) {
return owner.storage.registry.fetchSymbol(owner, method, reference);
}
const fileOwner = owner.storage.owner;
// A file-owned symbol's relationships are always owned by the same file.
const cached = reference.file === fileOwner.record.descriptor.nodeId ? fileOwner.record.symbolsById.get(reference.id) : undefined;
if (cached)
return cached;
const data = fileOwner.api.client.apiRequest(method, { symbol: owner.reference });
if (!data)
throw new Error(`${method} returned null symbol for Symbol ${owner.id}`);
return owner.internFileSymbol(fileOwner, data);
}, function* (method, reference) {
if (owner.storage.kind === SymbolOwnerKind.Snapshot) {
return yield* owner.storage.registry.fetchSymbol.gen(owner, method, reference);
}
const fileOwner = owner.storage.owner;
// A file-owned symbol's relationships are always owned by the same file.
const cached = reference.file === fileOwner.record.descriptor.nodeId ? fileOwner.record.symbolsById.get(reference.id) : undefined;
if (cached)
return cached;
const data = yield* apiRequest(method, { symbol: owner.reference });
if (!data)
throw new Error(`${method} returned null symbol for Symbol ${owner.id}`);
return owner.internFileSymbol(fileOwner, data);
});
}
get fetchSymbols() {
const owner = this;
return cacheGeneratorMethod(owner, "fetchSymbols", function (method) {
if (owner.storage.kind === SymbolOwnerKind.Snapshot) {
return owner.storage.registry.fetchSymbols(owner, method);
}
const fileOwner = owner.storage.owner;
const data = fileOwner.api.client.apiRequest(method, { symbol: owner.reference });
return data?.map(symbol => owner.internFileSymbol(fileOwner, symbol)) ?? [];
}, function* (method) {
if (owner.storage.kind === SymbolOwnerKind.Snapshot) {
return yield* owner.storage.registry.fetchSymbols.gen(owner, method);
}
const fileOwner = owner.storage.owner;
const data = yield* apiRequest(method, { symbol: owner.reference });
return data?.map(symbol => owner.internFileSymbol(fileOwner, symbol)) ?? [];
});
}
internFileSymbol(fileOwner, data) {
validateSymbolResponse(data);
const reference = data.reference;
if (reference.kind !== SymbolOwnerKind.File)
throw new Error(`Symbol ${reference.id} is not file-owned`);
return fileOwner.api.sourceFileCache.getOrCreateSymbol(fileOwner.record, reference.file, reference.id, () => new Symbol(data, { kind: SymbolOwnerKind.File, owner: fileOwner }));
}
}
class TypeObject {
objectRegistry;
// Fields included in TypeResponse. References to other objects are stored as IDs
// and resolved lazily via the object registry.
id;
flags;
objectFlags;
symbol;
value;
intrinsicName;
isThisType;
freshType;
regularType;
target;
tupleType;
typeParameters;
outerTypeParameters;
localTypeParameters;
thisType;
aliasTypeArguments;
aliasSymbol;
elementFlags;
fixedLength;
readonly;
labeledElementDeclarations;
texts;
objectType;
indexType;
checkType;
extendsType;
baseType;
substConstraint;
typeParameter;
constraintType;
nameType;
templateType;
// Cached results of lazy fetches, not included in TypeResponse
// (typically because they require some amount of computation or
// could cause an arbitrarily large number of types to be cached
// on the server for ID-based lookup). `false` is a sentinel value
// indicating a fetch has not yet occurred.
trueType;
falseType;
constraint;
default;
nonNullableType;
apparentType;
reducedType;
properties;
apparentProperties;
callSignatures;
constructSignatures;
indexInfos;
baseTypes;
types;
stringIndexType;
numberIndexType;
constructor(data, objectRegistry) {
this.objectRegistry = objectRegistry;
this.id = data.id;
this.flags = data.flags;
this.objectFlags = data.objectFlags ?? 0;
if (data.symbol !== undefined)
this.symbol = data.symbol;
if (data.value != null) {
// BigInt literal values are serialized as decimal strings (e.g. "-123") because
// JSON cannot represent bigint. Decode them back into a real bigint here.
const value = data.value;
if (data.flags & TypeFlags.BigIntLiteral) {
this.value = BigInt(value);
}
// JSON cannot represent infinities, so the API serializes them as strings.
else if (data.flags & TypeFlags.NumberLiteral && typeof value === "string") {
if (value === "+Infinity") {
this.value = Infinity;
}
else if (value === "-Infinity") {
this.value = -Infinity;
}
else {
this.value = NaN;
}
}
else {
this.value = value;
}
}
if (data.intrinsicName !== undefined)
this.intrinsicName = data.intrinsicName;
this.isThisType = data.isThisType ?? false;
if (data.freshType !== undefined)
this.freshType = data.freshType;
if (data.regularType !== undefined)
this.regularType = data.regularType;
if (data.target !== undefined)
this.target = data.target;
this.tupleType = data.isTupleType ?? false;
this.typeParameters = data.typeParameters ?? [];
this.outerTypeParameters = data.outerTypeParameters ?? [];
this.localTypeParameters = data.localTypeParameters ?? [];
if (data.thisType !== undefined)
this.thisType = data.thisType;
this.aliasTypeArguments = data.aliasTypeArguments ?? [];
if (data.aliasSymbol !== undefined)
this.aliasSymbol = data.aliasSymbol;
if (data.fixedLength !== undefined) {
this.elementFlags = data.elementFlags ?? [];
this.fixedLength = data.fixedLength;
}
if (data.readonly !== undefined)
this.readonly = data.readonly;
if (data.labeledElementDeclarations !== undefined) {
this.labeledElementDeclarations = data.labeledElementDeclarations.map(handle => handle ? objectRegistry.createNodeHandle(handle) : undefined);
}
if (data.texts !== undefined)
this.texts = data.texts;
if (data.objectType !== undefined)
this.objectType = data.objectType;
if (data.indexType !== undefined)
this.indexType = data.indexType;
if (data.checkType !== undefined)
this.checkType = data.checkType;
if (data.extendsType !== undefined)
this.extendsType = data.extendsType;
if (data.baseType !== undefined)
this.baseType = data.baseType;
if (data.substConstraint !== undefined)
this.substConstraint = data.substConstraint;
if (data.typeParameter !== undefined)
this.typeParameter = data.typeParameter;
if (data.constraintType !== undefined)
this.constraintType = data.constraintType;
if (data.nameType !== undefined)
this.nameType = data.nameType;
if (data.templateType !== undefined)
this.templateType = data.templateType;
this.trueType = false;
this.falseType = false;
this.constraint = false;
this.default = false;
this.nonNullableType = false;
this.apparentType = false;
this.reducedType = false;
this.properties = false;
this.apparentProperties = false;
this.callSignatures = false;
this.constructSignatures = false;
this.indexInfos = false;
this.baseTypes = false;
this.types = false;
this.stringIndexType = false;
this.numberIndexType = false;
}
get getSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getSymbol", function () {
return owner.objectRegistry.fetchSymbol(owner, "getSymbolOfType", owner.symbol);
}, function* () {
return yield* owner.objectRegistry.fetchSymbol.gen(owner, "getSymbolOfType", owner.symbol);
});
}
get getProperties() {
const owner = this;
return cacheGeneratorMethod(owner, "getProperties", function () {
if (owner.properties === false) {
owner.properties = owner.objectRegistry.fetchPropertiesOfType(owner);
}
return owner.properties;
}, function* () {
if (owner.properties === false) {
owner.properties = yield* owner.objectRegistry.fetchPropertiesOfType.gen(owner);
}
return owner.properties;
});
}
get getProperty() {
const owner = this;
return cacheGeneratorMethod(owner, "getProperty", function (propertyName) {
return owner.objectRegistry.fetchPropertyOfType(owner, propertyName);
}, function* (propertyName) {
return yield* owner.objectRegistry.fetchPropertyOfType.gen(owner, propertyName);
});
}
get getApparentProperties() {
const owner = this;
return cacheGeneratorMethod(owner, "getApparentProperties", function () {
if (owner.apparentProperties === false) {
owner.apparentProperties = owner.objectRegistry.fetchApparentPropertiesOfType(owner);
}
return owner.apparentProperties;
}, function* () {
if (owner.apparentProperties === false) {
owner.apparentProperties = yield* owner.objectRegistry.fetchApparentPropertiesOfType.gen(owner);
}
return owner.apparentProperties;
});
}
get getCallSignatures() {
const owner = this;
return cacheGeneratorMethod(owner, "getCallSignatures", function () {
if (owner.callSignatures === false) {
owner.callSignatures = owner.objectRegistry.fetchSignaturesOfType(owner, SignatureKind.Call);
}
return owner.callSignatures;
}, function* () {
if (owner.callSignatures === false) {
owner.callSignatures = yield* owner.objectRegistry.fetchSignaturesOfType.gen(owner, SignatureKind.Call);
}
return owner.callSignatures;
});
}
get getConstructSignatures() {
const owner = this;
return cacheGeneratorMethod(owner, "getConstructSignatures", function () {
if (owner.constructSignatures === false) {
owner.constructSignatures = owner.objectRegistry.fetchSignaturesOfType(owner, SignatureKind.Construct);
}
return owner.constructSignatures;
}, function* () {
if (owner.constructSignatures === false) {
owner.constructSignatures = yield* owner.objectRegistry.fetchSignaturesOfType.gen(owner, SignatureKind.Construct);
}
return owner.constructSignatures;
});
}
get getNonNullableType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNonNullableType", function () {
const result = owner.objectRegistry.fetchType(owner, "getNonNullableType", owner.nonNullableType);
owner.nonNullableType = result.id;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getNonNullableType", owner.nonNullableType);
owner.nonNullableType = result.id;
return result;
});
}
get getStringIndexType() {
const owner = this;
return cacheGeneratorMethod(owner, "getStringIndexType", function () {
if (owner.stringIndexType === false) {
owner.stringIndexType = owner.getStringIndexTypeWorker();
}
return owner.stringIndexType;
}, function* () {
if (owner.stringIndexType === false) {
owner.stringIndexType = yield* owner.getStringIndexTypeWorker.gen();
}
return owner.stringIndexType;
});
}
get getStringIndexTypeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "getStringIndexTypeWorker", function () {
const infos = owner.getIndexInfos();
return infos.find(info => (info.keyType.flags & TypeFlags.String) !== 0)?.valueType;
}, function* () {
const infos = yield* owner.getIndexInfos.gen();
return infos.find(info => (info.keyType.flags & TypeFlags.String) !== 0)?.valueType;
});
}
get getNumberIndexType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNumberIndexType", function () {
if (owner.numberIndexType === false) {
owner.numberIndexType = owner.getNumberIndexTypeWorker();
}
return owner.numberIndexType;
}, function* () {
if (owner.numberIndexType === false) {
owner.numberIndexType = yield* owner.getNumberIndexTypeWorker.gen();
}
return owner.numberIndexType;
});
}
get getNumberIndexTypeWorker() {
const owner = this;
return cacheGeneratorMethod(owner, "getNumberIndexTypeWorker", function () {
const infos = owner.getIndexInfos();
return infos.find(info => (info.keyType.flags & TypeFlags.Number) !== 0)?.valueType;
}, function* () {
const infos = yield* owner.getIndexInfos.gen();
return infos.find(info => (info.keyType.flags & TypeFlags.Number) !== 0)?.valueType;
});
}
get getApparentType() {
const owner = this;
return cacheGeneratorMethod(owner, "getApparentType", function () {
const result = owner.objectRegistry.fetchType(owner, "getApparentType", owner.apparentType);
owner.apparentType = result.id;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getApparentType", owner.apparentType);
owner.apparentType = result.id;
return result;
});
}
get getReducedType() {
const owner = this;
return cacheGeneratorMethod(owner, "getReducedType", function () {
const result = owner.objectRegistry.fetchType(owner, "getReducedType", owner.reducedType);
owner.reducedType = result.id;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getReducedType", owner.reducedType);
owner.reducedType = result.id;
return result;
});
}
get getIndexInfos() {
const owner = this;
return cacheGeneratorMethod(owner, "getIndexInfos", function () {
if (owner.indexInfos === false) {
owner.indexInfos = owner.objectRegistry.fetchIndexInfosOfType(owner);
}
return owner.indexInfos;
}, function* () {
if (owner.indexInfos === false) {
owner.indexInfos = yield* owner.objectRegistry.fetchIndexInfosOfType.gen(owner);
}
return owner.indexInfos;
});
}
get getAliasSymbol() {
const owner = this;
return cacheGeneratorMethod(owner, "getAliasSymbol", function () {
return owner.objectRegistry.fetchSymbol(owner, "getAliasSymbolOfType", owner.aliasSymbol);
}, function* () {
return yield* owner.objectRegistry.fetchSymbol.gen(owner, "getAliasSymbolOfType", owner.aliasSymbol);
});
}
get getTarget() {
const owner = this;
return cacheGeneratorMethod(owner, "getTarget", function () {
return owner.objectRegistry.fetchType(owner, "getTargetOfType", owner.target);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getTargetOfType", owner.target);
});
}
get getFreshType() {
const owner = this;
return cacheGeneratorMethod(owner, "getFreshType", function () {
return owner.objectRegistry.fetchOptionalType(owner, "getFreshTypeOfType", owner.freshType);
}, function* () {
return yield* owner.objectRegistry.fetchOptionalType.gen(owner, "getFreshTypeOfType", owner.freshType);
});
}
get getRegularType() {
const owner = this;
return cacheGeneratorMethod(owner, "getRegularType", function () {
return owner.objectRegistry.fetchOptionalType(owner, "getRegularTypeOfType", owner.regularType);
}, function* () {
return yield* owner.objectRegistry.fetchOptionalType.gen(owner, "getRegularTypeOfType", owner.regularType);
});
}
get getTypes() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypes", function () {
// Only union, intersection, and template literal types have constituent
// types; any other kind has none, so return undefined rather than sending
// a request the server cannot satisfy.
if (!(owner.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral))) {
return undefined;
}
if (owner.types === false) {
owner.types = owner.objectRegistry.fetchTypes(owner, "getTypesOfType");
}
return owner.types;
}, function* () {
// Only union, intersection, and template literal types have constituent
// types; any other kind has none, so return undefined rather than sending
// a request the server cannot satisfy.
if (!(owner.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral))) {
return undefined;
}
if (owner.types === false) {
owner.types = yield* owner.objectRegistry.fetchTypes.gen(owner, "getTypesOfType");
}
return owner.types;
});
}
get getTypeParameters() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeParameters", function () {
return owner.objectRegistry.fetchTypes(owner, "getTypeParametersOfType", owner.typeParameters);
}, function* () {
return (yield* owner.objectRegistry.fetchTypes.gen(owner, "getTypeParametersOfType", owner.typeParameters));
});
}
get getOuterTypeParameters() {
const owner = this;
return cacheGeneratorMethod(owner, "getOuterTypeParameters", function () {
return owner.objectRegistry.fetchTypes(owner, "getOuterTypeParametersOfType", owner.outerTypeParameters);
}, function* () {
return (yield* owner.objectRegistry.fetchTypes.gen(owner, "getOuterTypeParametersOfType", owner.outerTypeParameters));
});
}
get getLocalTypeParameters() {
const owner = this;
return cacheGeneratorMethod(owner, "getLocalTypeParameters", function () {
return owner.objectRegistry.fetchTypes(owner, "getLocalTypeParametersOfType", owner.localTypeParameters);
}, function* () {
return (yield* owner.objectRegistry.fetchTypes.gen(owner, "getLocalTypeParametersOfType", owner.localTypeParameters));
});
}
get getThisType() {
const owner = this;
return cacheGeneratorMethod(owner, "getThisType", function () {
return owner.objectRegistry.fetchOptionalType(owner, "getThisTypeOfType", owner.thisType);
}, function* () {
return (yield* owner.objectRegistry.fetchOptionalType.gen(owner, "getThisTypeOfType", owner.thisType));
});
}
get getAliasTypeArguments() {
const owner = this;
return cacheGeneratorMethod(owner, "getAliasTypeArguments", function () {
return owner.objectRegistry.fetchTypes(owner, "getAliasTypeArgumentsOfType", owner.aliasTypeArguments);
}, function* () {
return yield* owner.objectRegistry.fetchTypes.gen(owner, "getAliasTypeArgumentsOfType", owner.aliasTypeArguments);
});
}
get getTypeParameter() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeParameter", function () {
return owner.objectRegistry.fetchType(owner, "getTypeParameterOfMappedType", owner.typeParameter);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getTypeParameterOfMappedType", owner.typeParameter);
});
}
get getConstraintType() {
const owner = this;
return cacheGeneratorMethod(owner, "getConstraintType", function () {
return owner.objectRegistry.fetchType(owner, "getConstraintTypeOfMappedType", owner.constraintType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getConstraintTypeOfMappedType", owner.constraintType);
});
}
get getNameType() {
const owner = this;
return cacheGeneratorMethod(owner, "getNameType", function () {
return owner.objectRegistry.fetchOptionalType(owner, "getNameTypeOfMappedType", owner.nameType);
}, function* () {
return yield* owner.objectRegistry.fetchOptionalType.gen(owner, "getNameTypeOfMappedType", owner.nameType);
});
}
get getTemplateType() {
const owner = this;
return cacheGeneratorMethod(owner, "getTemplateType", function () {
return owner.objectRegistry.fetchType(owner, "getTemplateTypeOfMappedType", owner.templateType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getTemplateTypeOfMappedType", owner.templateType);
});
}
get getObjectType() {
const owner = this;
return cacheGeneratorMethod(owner, "getObjectType", function () {
return owner.objectRegistry.fetchType(owner, "getObjectTypeOfType", owner.objectType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getObjectTypeOfType", owner.objectType);
});
}
get getIndexType() {
const owner = this;
return cacheGeneratorMethod(owner, "getIndexType", function () {
return owner.objectRegistry.fetchType(owner, "getIndexTypeOfType", owner.indexType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getIndexTypeOfType", owner.indexType);
});
}
get getCheckType() {
const owner = this;
return cacheGeneratorMethod(owner, "getCheckType", function () {
return owner.objectRegistry.fetchType(owner, "getCheckTypeOfType", owner.checkType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getCheckTypeOfType", owner.checkType);
});
}
get getExtendsType() {
const owner = this;
return cacheGeneratorMethod(owner, "getExtendsType", function () {
return owner.objectRegistry.fetchType(owner, "getExtendsTypeOfType", owner.extendsType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getExtendsTypeOfType", owner.extendsType);
});
}
get getBaseType() {
const owner = this;
return cacheGeneratorMethod(owner, "getBaseType", function () {
return owner.objectRegistry.fetchType(owner, "getBaseTypeOfType", owner.baseType);
}, function* () {
return yield* owner.objectRegistry.fetchType.gen(owner, "getBaseTypeOfType", owner.baseType);
});
}
get getConstraint() {
const owner = this;
return cacheGeneratorMethod(owner, "getConstraint", function () {
// Type parameters resolve their constraint lazily through the checker,
// whereas substitution types carry a preloaded constraint handle.
if (owner.flags & TypeFlags.TypeParameter) {
const result = owner.objectRegistry.fetchOptionalType(owner, "getConstraintOfTypeParameter", owner.constraint);
owner.constraint = result ? result.id : 0;
return result;
}
return owner.objectRegistry.fetchType(owner, "getConstraintOfType", owner.substConstraint);
}, function* () {
// Type parameters resolve their constraint lazily through the checker,
// whereas substitution types carry a preloaded constraint handle.
if (owner.flags & TypeFlags.TypeParameter) {
const result = yield* owner.objectRegistry.fetchOptionalType.gen(owner, "getConstraintOfTypeParameter", owner.constraint);
owner.constraint = result ? result.id : 0;
return result;
}
return yield* owner.objectRegistry.fetchType.gen(owner, "getConstraintOfType", owner.substConstraint);
});
}
get getDefault() {
const owner = this;
return cacheGeneratorMethod(owner, "getDefault", function () {
const result = owner.objectRegistry.fetchOptionalType(owner, "getDefaultFromTypeParameter", owner.default);
owner.default = result ? result.id : 0;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchOptionalType.gen(owner, "getDefaultFromTypeParameter", owner.default);
owner.default = result ? result.id : 0;
return result;
});
}
get getTrueType() {
const owner = this;
return cacheGeneratorMethod(owner, "getTrueType", function () {
const result = owner.objectRegistry.fetchType(owner, "getTrueTypeOfConditionalType", owner.trueType);
owner.trueType = result.id;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getTrueTypeOfConditionalType", owner.trueType);
owner.trueType = result.id;
return result;
});
}
get getFalseType() {
const owner = this;
return cacheGeneratorMethod(owner, "getFalseType", function () {
const result = owner.objectRegistry.fetchType(owner, "getFalseTypeOfConditionalType", owner.falseType);
owner.falseType = result.id;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getFalseTypeOfConditionalType", owner.falseType);
owner.falseType = result.id;
return result;
});
}
/**
* Get the base types of this type. Returns `undefined` for any type that is
* not a class or interface.
*/
get getBaseTypes() {
const owner = this;
return cacheGeneratorMethod(owner, "getBaseTypes", function () {
if (!owner.isClassOrInterface()) {
return undefined;
}
if (owner.baseTypes === false) {
owner.baseTypes = owner.objectRegistry.fetchBaseTypes(owner);
}
return owner.baseTypes;
}, function* () {
if (!owner.isClassOrInterface()) {
return undefined;
}
if (owner.baseTypes === false) {
owner.baseTypes = yield* owner.objectRegistry.fetchBaseTypes.gen(owner);
}
return owner.baseTypes;
});
}
isClassOrInterface() {
return isClassOrInterfaceType(this);
}
isUnionType() {
return isUnionType(this);
}
isIntersectionType() {
return isIntersectionType(this);
}
isObjectType() {
return isObjectType(this);
}
isIntrinsicType() {
return isIntrinsicType(this);
}
isErrorType() {
return isErrorType(this);
}
isLiteralType() {
return isLiteralType(this);
}
isStringLiteralType() {
return isStringLiteralType(this);
}
isNumberLiteralType() {
return isNumberLiteralType(this);
}
isBigIntLiteralType() {
return isBigIntLiteralType(this);
}
isBooleanLiteralType() {
return isBooleanLiteralType(this);
}
isTypeReference() {
return isTypeReference(this);
}
isTupleType() {
return this.tupleType;
}
isTupleTypeTarget() {
return this.fixedLength !== undefined;
}
isIndexType() {
return isIndexType(this);
}
isIndexedAccessType() {
return isIndexedAccessType(this);
}
isConditionalType() {
return isConditionalType(this);
}
isSubstitutionType() {
return isSubstitutionType(this);
}
isTemplateLiteralType() {
return isTemplateLiteralType(this);
}
isStringMappingType() {
return isStringMappingType(this);
}
isTypeParameter() {
return isTypeParameter(this);
}
isMappedType() {
return !!(this.flags & TypeFlags.Object) && !!(this.objectFlags & ObjectFlags.Mapped);
}
}
export function isUnionType(type) {
return (type.flags & TypeFlags.Union) !== 0;
}
export function isIntersectionType(type) {
return (type.flags & TypeFlags.Intersection) !== 0;
}
export function isObjectType(type) {
return (type.flags & TypeFlags.Object) !== 0;
}
export function isClassOrInterfaceType(type) {
return isObjectType(type) && (type.objectFlags & ObjectFlags.ClassOrInterface) !== 0;
}
export function isIntrinsicType(type) {
return (type.flags & TypeFlags.Intrinsic) !== 0;
}
/**
* Whether this is the error type — the placeholder the checker produces when a
* type cannot be determined (e.g. an unresolved reference). It is an intrinsic
* type named `"error"` (this covers both the singleton error type and the
* per-alias error types manufactured for unresolved type alias references).
*/
export function isErrorType(type) {
return isIntrinsicType(type) && type.intrinsicName === "error";
}
export function isLiteralType(type) {
return (type.flags & TypeFlags.Literal) !== 0;
}
export function isStringLiteralType(type) {
return (type.flags & TypeFlags.StringLiteral) !== 0;
}
export function isNumberLiteralType(type) {
return (type.flags & TypeFlags.NumberLiteral) !== 0;
}
export function isBigIntLiteralType(type) {
return (type.flags & TypeFlags.BigIntLiteral) !== 0;
}
export function isBooleanLiteralType(type) {
return (type.flags & TypeFlags.BooleanLiteral) !== 0;
}
export function isTypeReference(type) {
return isObjectType(type) && (type.objectFlags & ObjectFlags.Reference) !== 0;
}
export function isTupleType(type) {
return type.isTupleType();
}
export function isTupleTypeTarget(type) {
return type.isTupleTypeTarget();
}
export function isIndexType(type) {
return (type.flags & TypeFlags.Index) !== 0;
}
export function isIndexedAccessType(type) {
return (type.flags & TypeFlags.IndexedAccess) !== 0;
}
export function isConditionalType(type) {
return (type.flags & TypeFlags.Conditional) !== 0;
}
export function isSubstitutionType(type) {
return (type.flags & TypeFlags.Substitution) !== 0;
}
export function isTemplateLiteralType(type) {
return (type.flags & TypeFlags.TemplateLiteral) !== 0;
}
export function isStringMappingType(type) {
return (type.flags & TypeFlags.StringMapping) !== 0;
}
export function isTypeParameter(type) {
return (type.flags & TypeFlags.TypeParameter) !== 0;
}
export class Signature {
flags;
objectRegistry;
id;
project;
declarationHandle;
declarationCache;
typeParameters;
parameters;
thisParameter;
target;
returnType;
constructor(data, project, objectRegistry) {
this.id = data.id;
this.flags = data.flags ?? 0;
this.objectRegistry = objectRegistry;
this.project = project;
this.declarationHandle = data.declaration;
this.declarationCache = undefined;
this.typeParameters = data.typeParameters ?? [];
this.parameters = data.parameters ?? [];
this.thisParameter = data.thisParameter;
this.target = data.target;
this.returnType = false;
}
get declaration() {
if (this.declarationCache === undefined && this.declarationHandle) {
this.declarationCache = this.objectRegistry.createNodeHandle(this.declarationHandle);
}
return this.declarationCache;
}
get getTypeParameters() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeParameters", function () {
return owner.objectRegistry.fetchTypes(owner, "getTypeParametersOfSignature", owner.typeParameters);
}, function* () {
return (yield* owner.objectRegistry.fetchTypes.gen(owner, "getTypeParametersOfSignature", owner.typeParameters));
});
}
get getParameters() {
const owner = this;
return cacheGeneratorMethod(owner, "getParameters", function () {
return owner.objectRegistry.fetchSymbols(owner, "getParametersOfSignature", owner.parameters);
}, function* () {
return yield* owner.objectRegistry.fetchSymbols.gen(owner, "getParametersOfSignature", owner.parameters);
});
}
get getThisParameter() {
const owner = this;
return cacheGeneratorMethod(owner, "getThisParameter", function () {
return owner.objectRegistry.fetchSymbol(owner, "getThisParameterOfSignature", owner.thisParameter);
}, function* () {
return yield* owner.objectRegistry.fetchSymbol.gen(owner, "getThisParameterOfSignature", owner.thisParameter);
});
}
get getTarget() {
const owner = this;
return cacheGeneratorMethod(owner, "getTarget", function () {
return owner.objectRegistry.fetchSignature(owner, "getTargetOfSignature", owner.target);
}, function* () {
return yield* owner.objectRegistry.fetchSignature.gen(owner, "getTargetOfSignature", owner.target);
});
}
get getReturnType() {
const owner = this;
return cacheGeneratorMethod(owner, "getReturnType", function () {
const result = owner.objectRegistry.fetchType(owner, "getReturnTypeOfSignature", owner.returnType);
owner.returnType = result.id;
return result;
}, function* () {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getReturnTypeOfSignature", owner.returnType);
owner.returnType = result.id;
return result;
});
}
get getTypeParameterAtPosition() {
const owner = this;
return cacheGeneratorMethod(owner, "getTypeParameterAtPosition", function (pos) {
return owner.objectRegistry.fetchTypeParameterAtPosition(owner, pos);
}, function* (pos) {
return yield* owner.objectRegistry.fetchTypeParameterAtPosition.gen(owner, pos);
});
}
get hasRestParameter() {
return (this.flags & SignatureFlags.HasRestParameter) !== 0;
}
get isConstruct() {
return (this.flags & SignatureFlags.Construct) !== 0;
}
get isAbstract() {
return (this.flags & SignatureFlags.Abstract) !== 0;
}
}
//# sourceMappingURL=api.js.map