typescript 7.0.1-rc → 7.1.0-dev.20260708.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/NOTICE.txt +1 -1
  2. package/README.md +39 -14
  3. package/dist/api/async/api.d.ts +274 -45
  4. package/dist/api/async/api.d.ts.map +1 -1
  5. package/dist/api/async/api.js +722 -137
  6. package/dist/api/async/api.js.map +1 -1
  7. package/dist/api/async/client.d.ts +17 -0
  8. package/dist/api/async/client.d.ts.map +1 -1
  9. package/dist/api/async/client.js +72 -1
  10. package/dist/api/async/client.js.map +1 -1
  11. package/dist/api/async/types.d.ts +108 -27
  12. package/dist/api/async/types.d.ts.map +1 -1
  13. package/dist/api/compilerOptions.d.ts +109 -0
  14. package/dist/api/compilerOptions.d.ts.map +1 -0
  15. package/dist/api/compilerOptions.js +2 -0
  16. package/dist/api/compilerOptions.js.map +1 -0
  17. package/dist/api/node/encoder.d.ts.map +1 -1
  18. package/dist/api/node/encoder.js +1 -18
  19. package/dist/api/node/encoder.js.map +1 -1
  20. package/dist/api/node/msgpack.d.ts.map +1 -1
  21. package/dist/api/node/msgpack.js +2 -1
  22. package/dist/api/node/msgpack.js.map +1 -1
  23. package/dist/api/node/node.d.ts +17 -3
  24. package/dist/api/node/node.d.ts.map +1 -1
  25. package/dist/api/node/node.generated.d.ts +11 -0
  26. package/dist/api/node/node.generated.d.ts.map +1 -1
  27. package/dist/api/node/node.generated.js +69 -48
  28. package/dist/api/node/node.generated.js.map +1 -1
  29. package/dist/api/node/node.infrastructure.d.ts +11 -0
  30. package/dist/api/node/node.infrastructure.d.ts.map +1 -1
  31. package/dist/api/node/node.infrastructure.js.map +1 -1
  32. package/dist/api/node/node.js +93 -9
  33. package/dist/api/node/node.js.map +1 -1
  34. package/dist/api/node/wtf8.d.ts +6 -0
  35. package/dist/api/node/wtf8.d.ts.map +1 -0
  36. package/dist/api/node/wtf8.js +61 -0
  37. package/dist/api/node/wtf8.js.map +1 -0
  38. package/dist/api/options.d.ts +8 -0
  39. package/dist/api/options.d.ts.map +1 -1
  40. package/dist/api/options.js.map +1 -1
  41. package/dist/api/proto.d.ts +58 -5
  42. package/dist/api/proto.d.ts.map +1 -1
  43. package/dist/api/proto.js +15 -0
  44. package/dist/api/proto.js.map +1 -1
  45. package/dist/api/sync/api.d.ts +274 -45
  46. package/dist/api/sync/api.d.ts.map +1 -1
  47. package/dist/api/sync/api.js +720 -135
  48. package/dist/api/sync/api.js.map +1 -1
  49. package/dist/api/sync/client.d.ts +17 -0
  50. package/dist/api/sync/client.d.ts.map +1 -1
  51. package/dist/api/sync/client.js +53 -1
  52. package/dist/api/sync/client.js.map +1 -1
  53. package/dist/api/sync/types.d.ts +108 -27
  54. package/dist/api/sync/types.d.ts.map +1 -1
  55. package/dist/api/syncChannel.d.ts +4 -1
  56. package/dist/api/syncChannel.d.ts.map +1 -1
  57. package/dist/api/syncChannel.js +21 -1
  58. package/dist/api/syncChannel.js.map +1 -1
  59. package/dist/api/timing.d.ts +175 -0
  60. package/dist/api/timing.d.ts.map +1 -0
  61. package/dist/api/timing.js +149 -0
  62. package/dist/api/timing.js.map +1 -0
  63. package/dist/ast/ast.d.ts +36 -2
  64. package/dist/ast/ast.d.ts.map +1 -1
  65. package/dist/ast/ast.generated.d.ts +3 -3
  66. package/dist/ast/ast.generated.d.ts.map +1 -1
  67. package/dist/ast/ast.js.map +1 -1
  68. package/dist/ast/factory.generated.d.ts +12 -4
  69. package/dist/ast/factory.generated.d.ts.map +1 -1
  70. package/dist/ast/factory.generated.js +36 -2
  71. package/dist/ast/factory.generated.js.map +1 -1
  72. package/dist/ast/index.d.ts +2 -0
  73. package/dist/ast/index.d.ts.map +1 -1
  74. package/dist/ast/index.js +2 -0
  75. package/dist/ast/index.js.map +1 -1
  76. package/dist/ast/is.d.ts +2 -1
  77. package/dist/ast/is.d.ts.map +1 -1
  78. package/dist/ast/is.generated.d.ts +2 -2
  79. package/dist/ast/is.generated.d.ts.map +1 -1
  80. package/dist/ast/is.generated.js +3 -4
  81. package/dist/ast/is.generated.js.map +1 -1
  82. package/dist/ast/is.js +8 -1
  83. package/dist/ast/is.js.map +1 -1
  84. package/dist/ast/jsdoc.d.ts +11 -0
  85. package/dist/ast/jsdoc.d.ts.map +1 -0
  86. package/dist/ast/jsdoc.js +202 -0
  87. package/dist/ast/jsdoc.js.map +1 -0
  88. package/dist/ast/utils.d.ts +12 -0
  89. package/dist/ast/utils.d.ts.map +1 -1
  90. package/dist/ast/utils.js +40 -0
  91. package/dist/ast/utils.js.map +1 -1
  92. package/dist/enums/internalSymbolName.d.ts +2 -0
  93. package/dist/enums/internalSymbolName.d.ts.map +1 -0
  94. package/dist/enums/internalSymbolName.enum.d.ts +23 -0
  95. package/dist/enums/internalSymbolName.enum.d.ts.map +1 -0
  96. package/dist/enums/internalSymbolName.enum.js +25 -0
  97. package/dist/enums/internalSymbolName.enum.js.map +1 -0
  98. package/dist/enums/internalSymbolName.js +25 -0
  99. package/dist/enums/internalSymbolName.js.map +1 -0
  100. package/dist/enums/jsxEmit.d.ts +2 -0
  101. package/dist/enums/jsxEmit.d.ts.map +1 -0
  102. package/dist/enums/jsxEmit.enum.d.ts +9 -0
  103. package/dist/enums/jsxEmit.enum.d.ts.map +1 -0
  104. package/dist/enums/jsxEmit.enum.js +11 -0
  105. package/dist/enums/jsxEmit.enum.js.map +1 -0
  106. package/dist/enums/jsxEmit.js +11 -0
  107. package/dist/enums/jsxEmit.js.map +1 -0
  108. package/dist/enums/moduleDetectionKind.d.ts +2 -0
  109. package/dist/enums/moduleDetectionKind.d.ts.map +1 -0
  110. package/dist/enums/moduleDetectionKind.enum.d.ts +7 -0
  111. package/dist/enums/moduleDetectionKind.enum.d.ts.map +1 -0
  112. package/dist/enums/moduleDetectionKind.enum.js +9 -0
  113. package/dist/enums/moduleDetectionKind.enum.js.map +1 -0
  114. package/dist/enums/moduleDetectionKind.js +9 -0
  115. package/dist/enums/moduleDetectionKind.js.map +1 -0
  116. package/dist/enums/moduleKind.d.ts +2 -0
  117. package/dist/enums/moduleKind.d.ts.map +1 -0
  118. package/dist/enums/moduleKind.enum.d.ts +17 -0
  119. package/dist/enums/moduleKind.enum.d.ts.map +1 -0
  120. package/dist/enums/moduleKind.enum.js +19 -0
  121. package/dist/enums/moduleKind.enum.js.map +1 -0
  122. package/dist/enums/moduleKind.js +19 -0
  123. package/dist/enums/moduleKind.js.map +1 -0
  124. package/dist/enums/moduleResolutionKind.d.ts +2 -0
  125. package/dist/enums/moduleResolutionKind.d.ts.map +1 -0
  126. package/dist/enums/moduleResolutionKind.enum.d.ts +9 -0
  127. package/dist/enums/moduleResolutionKind.enum.d.ts.map +1 -0
  128. package/dist/enums/moduleResolutionKind.enum.js +11 -0
  129. package/dist/enums/moduleResolutionKind.enum.js.map +1 -0
  130. package/dist/enums/moduleResolutionKind.js +11 -0
  131. package/dist/enums/moduleResolutionKind.js.map +1 -0
  132. package/dist/enums/newLineKind.d.ts +2 -0
  133. package/dist/enums/newLineKind.d.ts.map +1 -0
  134. package/dist/enums/newLineKind.enum.d.ts +6 -0
  135. package/dist/enums/newLineKind.enum.d.ts.map +1 -0
  136. package/dist/enums/newLineKind.enum.js +8 -0
  137. package/dist/enums/newLineKind.enum.js.map +1 -0
  138. package/dist/enums/newLineKind.js +8 -0
  139. package/dist/enums/newLineKind.js.map +1 -0
  140. package/dist/enums/outerExpressionKinds.enum.d.ts +5 -1
  141. package/dist/enums/outerExpressionKinds.enum.d.ts.map +1 -1
  142. package/dist/enums/outerExpressionKinds.enum.js +4 -0
  143. package/dist/enums/outerExpressionKinds.enum.js.map +1 -1
  144. package/dist/enums/outerExpressionKinds.js +4 -0
  145. package/dist/enums/outerExpressionKinds.js.map +1 -1
  146. package/dist/internal/utils.d.ts +23 -0
  147. package/dist/internal/utils.d.ts.map +1 -0
  148. package/dist/internal/utils.js +25 -0
  149. package/dist/internal/utils.js.map +1 -0
  150. package/lib/getExePath.js +6 -3
  151. package/lib/tsc.js +1 -1
  152. package/lib/version.cjs +3 -0
  153. package/lib/version.d.cts +2 -0
  154. package/package.json +18 -30
  155. package/dist/api/objectRegistry.d.ts +0 -40
  156. package/dist/api/objectRegistry.d.ts.map +0 -1
  157. package/dist/api/objectRegistry.js +0 -61
  158. package/dist/api/objectRegistry.js.map +0 -1
@@ -10,6 +10,7 @@
10
10
  import { CompletionItemKind } from "#enums/completionItemKind";
11
11
  import { DiagnosticCategory } from "#enums/diagnosticCategory";
12
12
  import { ElementFlags } from "#enums/elementFlags";
13
+ import { ModuleKind } from "#enums/moduleKind";
13
14
  import { NodeBuilderFlags } from "#enums/nodeBuilderFlags";
14
15
  import { ObjectFlags } from "#enums/objectFlags";
15
16
  import { SignatureFlags } from "#enums/signatureFlags";
@@ -17,16 +18,16 @@ import { SignatureKind } from "#enums/signatureKind";
17
18
  import { SymbolFlags } from "#enums/symbolFlags";
18
19
  import { TypeFlags } from "#enums/typeFlags";
19
20
  import { TypePredicateKind } from "#enums/typePredicateKind";
20
- import { ModifierFlags, } from "../../ast/index.js";
21
+ import { ModifierFlags, unescapeLeadingUnderscores, } from "../../ast/index.js";
21
22
  import { encodeNode, uint8ArrayToBase64, } from "../node/encoder.js";
22
23
  import { decodeNode, getNodeId, parseNodeHandle, readParseOptionsKey, readSourceFileHash, RemoteSourceFile, } from "../node/node.js";
23
- import { ObjectRegistry, } from "../objectRegistry.js";
24
+ import { Wtf8Decoder } from "../node/wtf8.js";
24
25
  import { createGetCanonicalFileName, toPath, } from "../path.js";
25
- import { resolveFileName } from "../proto.js";
26
+ import { resolveFileName, toUpdateSnapshotRequest, } from "../proto.js";
26
27
  import { SourceFileCache } from "../sourceFileCache.js";
27
28
  import { Client, } from "./client.js";
28
- export { CompletionItemKind, DiagnosticCategory, ElementFlags, ModifierFlags, NodeBuilderFlags, ObjectFlags, SignatureFlags, SignatureKind, SymbolFlags, TypeFlags, TypePredicateKind };
29
29
  export { documentURIToFileName, fileNameToDocumentURI } from "../path.js";
30
+ export { CompletionItemKind, DiagnosticCategory, ElementFlags, ModifierFlags, ModuleKind, NodeBuilderFlags, ObjectFlags, SignatureFlags, SignatureKind, SymbolFlags, TypeFlags, TypePredicateKind };
30
31
  export class API {
31
32
  client;
32
33
  sourceFileCache;
@@ -35,7 +36,7 @@ export class API {
35
36
  activeSnapshots = new Set();
36
37
  latestSnapshot;
37
38
  internal;
38
- constructor(options) {
39
+ constructor(options = {}) {
39
40
  this.client = new Client(options);
40
41
  this.sourceFileCache = new SourceFileCache();
41
42
  this.internal = new InternalAPI(this.client, () => this.ensureInitialized());
@@ -64,10 +65,7 @@ export class API {
64
65
  }
65
66
  updateSnapshot(params) {
66
67
  this.ensureInitialized();
67
- const requestParams = params ?? {};
68
- if (requestParams.openProject) {
69
- requestParams.openProject = resolveFileName(requestParams.openProject);
70
- }
68
+ const requestParams = toUpdateSnapshotRequest(params);
71
69
  const data = this.client.apiRequest("updateSnapshot", requestParams);
72
70
  // Retain cached source files from previous snapshot for unchanged files
73
71
  if (this.latestSnapshot) {
@@ -102,6 +100,24 @@ export class API {
102
100
  clearSourceFileCache() {
103
101
  this.sourceFileCache.clear();
104
102
  }
103
+ /**
104
+ * Returns a snapshot of collected timing information for requests made
105
+ * through this API instance: client-measured round-trip latency and bytes
106
+ * transferred, folded together with the server's own per-request processing
107
+ * time and an estimated transport overhead (round-trip minus server time).
108
+ *
109
+ * Fetching the snapshot issues a lightweight request to the server to
110
+ * retrieve its timing collection. Collection must be enabled via the
111
+ * `collectTiming` option; when it is not, the returned snapshot has
112
+ * `enabled: false` and zeroed totals.
113
+ */
114
+ getTimingInfo() {
115
+ return this.client.getTimingInfo();
116
+ }
117
+ /** Clears all accumulated timing totals and recent-request history, on both the client and the server. */
118
+ resetTimingInfo() {
119
+ return this.client.resetTimingInfo();
120
+ }
105
121
  }
106
122
  export class InternalAPI {
107
123
  client;
@@ -131,23 +147,18 @@ export class Snapshot {
131
147
  projectMap;
132
148
  toPath;
133
149
  client;
134
- objectRegistry;
135
150
  disposed = false;
136
151
  onDispose;
152
+ snapshotRegistry;
137
153
  constructor(data, client, sourceFileCache, toPath, onDispose) {
138
154
  this.id = data.snapshot;
139
155
  this.client = client;
140
156
  this.toPath = toPath;
141
157
  this.onDispose = onDispose;
142
- this.objectRegistry = new SnapshotObjectRegistry({
143
- createSymbol: symbolData => new Symbol(symbolData, this.objectRegistry),
144
- createType: typeData => new TypeObject(typeData, this.objectRegistry),
145
- createSignature: sigData => new Signature(sigData, this.objectRegistry),
146
- }, client, this.id);
147
- // Create projects
148
158
  this.projectMap = new Map();
159
+ this.snapshotRegistry = new SnapshotObjectRegistry(client, this.id, projectId => this.projectMap.get(projectId));
149
160
  for (const projData of data.projects) {
150
- const project = new Project(projData, this.id, client, this.objectRegistry, sourceFileCache, toPath);
161
+ const project = new Project(projData, this.id, client, sourceFileCache, toPath, this.snapshotRegistry);
151
162
  this.projectMap.set(toPath(projData.configFileName), project);
152
163
  }
153
164
  }
@@ -176,7 +187,11 @@ export class Snapshot {
176
187
  if (this.disposed)
177
188
  return;
178
189
  this.disposed = true;
179
- this.objectRegistry.clear();
190
+ for (const project of this.projectMap.values()) {
191
+ project.dispose();
192
+ }
193
+ this.projectMap.clear();
194
+ this.snapshotRegistry.clear();
180
195
  this.onDispose();
181
196
  this.client.apiRequest("release", { snapshot: this.id });
182
197
  }
@@ -189,41 +204,139 @@ export class Snapshot {
189
204
  }
190
205
  }
191
206
  }
192
- class SnapshotObjectRegistry extends ObjectRegistry {
207
+ class SnapshotObjectRegistry {
208
+ symbols = new Map();
193
209
  client;
194
210
  snapshotId;
195
- constructor(factories, client, snapshotId) {
196
- super(factories);
211
+ resolveProject;
212
+ constructor(client, snapshotId, resolveProject) {
197
213
  this.client = client;
198
214
  this.snapshotId = snapshotId;
215
+ this.resolveProject = resolveProject;
199
216
  }
200
- fetchType(source, method, handle) {
217
+ /** Resolve a project id (a config file path) to its Project within this snapshot. */
218
+ getProject(projectId) {
219
+ return this.resolveProject(projectId);
220
+ }
221
+ getOrCreateSymbol(data) {
222
+ let symbol = this.symbols.get(data.id);
223
+ if (!symbol) {
224
+ symbol = new Symbol(data, this);
225
+ this.symbols.set(data.id, symbol);
226
+ }
227
+ return symbol;
228
+ }
229
+ getSymbol(id) {
230
+ return this.symbols.get(id);
231
+ }
232
+ clear() {
233
+ this.symbols.clear();
234
+ }
235
+ fetchSymbol(source, method, handle, projectId) {
201
236
  if (!handle)
202
237
  return undefined;
203
- const cached = this.getType(handle);
238
+ const cached = this.getSymbol(handle);
204
239
  if (cached)
205
240
  return cached;
206
241
  const data = this.client.apiRequest(method, {
207
242
  snapshot: this.snapshotId,
243
+ project: projectId,
208
244
  objectId: source.id,
209
245
  });
210
246
  if (!data)
211
- throw new Error(`${method} returned null type for ${source.constructor.name} ${source.id}`);
212
- return this.getOrCreateType(data);
247
+ throw new Error(`${method} returned null symbol for ${source.constructor.name} ${source.id}`);
248
+ return this.getOrCreateSymbol(data);
213
249
  }
214
- fetchSymbol(source, method, handle) {
215
- if (!handle)
216
- return undefined;
217
- const cached = this.getSymbol(handle);
218
- if (cached)
219
- return cached;
250
+ fetchSymbols(source, method, handles, projectId) {
251
+ if (handles) {
252
+ const result = new Array(handles.length);
253
+ let allCached = true;
254
+ for (let i = 0; i < handles.length; i++) {
255
+ const cached = this.getSymbol(handles[i]);
256
+ if (!cached) {
257
+ allCached = false;
258
+ break;
259
+ }
260
+ result[i] = cached;
261
+ }
262
+ if (allCached)
263
+ return result;
264
+ }
265
+ const symbolData = this.client.apiRequest(method, {
266
+ snapshot: this.snapshotId,
267
+ project: projectId,
268
+ objectId: source.id,
269
+ });
270
+ if (symbolData == null)
271
+ return [];
272
+ else
273
+ return symbolData.map(data => this.getOrCreateSymbol(data));
274
+ }
275
+ }
276
+ class ProjectObjectRegistry {
277
+ client;
278
+ snapshotId;
279
+ project;
280
+ snapshotRegistry;
281
+ types = new Map();
282
+ signatures = new Map();
283
+ constructor(client, snapshotId, project, snapshotRegistry) {
284
+ this.client = client;
285
+ this.snapshotId = snapshotId;
286
+ this.project = project;
287
+ this.snapshotRegistry = snapshotRegistry;
288
+ }
289
+ getOrCreateSymbol(data) {
290
+ return this.snapshotRegistry.getOrCreateSymbol(data);
291
+ }
292
+ getSymbol(id) {
293
+ return this.snapshotRegistry.getSymbol(id);
294
+ }
295
+ getOrCreateType(data) {
296
+ let type = this.types.get(data.id);
297
+ if (!type) {
298
+ type = new TypeObject(data, this);
299
+ this.types.set(data.id, type);
300
+ }
301
+ return type;
302
+ }
303
+ getType(id) {
304
+ return this.types.get(id);
305
+ }
306
+ getOrCreateSignature(data) {
307
+ let sig = this.signatures.get(data.id);
308
+ if (!sig) {
309
+ sig = new Signature(data, this.project, this);
310
+ this.signatures.set(data.id, sig);
311
+ }
312
+ return sig;
313
+ }
314
+ getSignature(id) {
315
+ return this.signatures.get(id);
316
+ }
317
+ clear() {
318
+ this.types.clear();
319
+ this.signatures.clear();
320
+ }
321
+ fetchType(source, method, handle) {
322
+ if (handle !== false) {
323
+ if (!handle)
324
+ return undefined;
325
+ const cached = this.getType(handle);
326
+ if (cached)
327
+ return cached;
328
+ }
220
329
  const data = this.client.apiRequest(method, {
221
330
  snapshot: this.snapshotId,
331
+ project: this.project.id,
222
332
  objectId: source.id,
223
333
  });
224
334
  if (!data)
225
- throw new Error(`${method} returned null symbol for ${source.constructor.name} ${source.id}`);
226
- return this.getOrCreateSymbol(data);
335
+ throw new Error(`${method} returned null type for ${source.constructor.name} ${source.id}`);
336
+ return this.getOrCreateType(data);
337
+ }
338
+ fetchSymbol(source, method, handle) {
339
+ return this.snapshotRegistry.fetchSymbol(source, method, handle, this.project.id);
227
340
  }
228
341
  fetchSignature(source, method, handle) {
229
342
  if (!handle)
@@ -233,6 +346,7 @@ class SnapshotObjectRegistry extends ObjectRegistry {
233
346
  return cached;
234
347
  const data = this.client.apiRequest(method, {
235
348
  snapshot: this.snapshotId,
349
+ project: this.project.id,
236
350
  objectId: source.id,
237
351
  });
238
352
  if (!data)
@@ -256,6 +370,7 @@ class SnapshotObjectRegistry extends ObjectRegistry {
256
370
  }
257
371
  const typesData = this.client.apiRequest(method, {
258
372
  snapshot: this.snapshotId,
373
+ project: this.project.id,
259
374
  objectId: source.id,
260
375
  });
261
376
  if (typesData == null)
@@ -264,28 +379,19 @@ class SnapshotObjectRegistry extends ObjectRegistry {
264
379
  return typesData.map(data => this.getOrCreateType(data));
265
380
  }
266
381
  fetchSymbols(source, method, handles) {
267
- if (handles) {
268
- const result = new Array(handles.length);
269
- let allCached = true;
270
- for (let i = 0; i < handles.length; i++) {
271
- const cached = this.getSymbol(handles[i]);
272
- if (!cached) {
273
- allCached = false;
274
- break;
275
- }
276
- result[i] = cached;
277
- }
278
- if (allCached)
279
- return result;
280
- }
281
- const symbolData = this.client.apiRequest(method, {
382
+ return this.snapshotRegistry.fetchSymbols(source, method, handles, this.project.id);
383
+ }
384
+ // getBaseTypes is a checker-level endpoint keyed by `type` (not `objectId`),
385
+ // so it cannot go through fetchTypes. This helper reuses that server method.
386
+ fetchBaseTypes(source) {
387
+ const typesData = this.client.apiRequest("getBaseTypes", {
282
388
  snapshot: this.snapshotId,
283
- objectId: source.id,
389
+ project: this.project.id,
390
+ type: source.id,
284
391
  });
285
- if (symbolData == null)
392
+ if (typesData == null)
286
393
  return [];
287
- else
288
- return symbolData.map(data => this.getOrCreateSymbol(data));
394
+ return typesData.map(data => this.getOrCreateType(data));
289
395
  }
290
396
  }
291
397
  export class Project {
@@ -297,43 +403,51 @@ export class Project {
297
403
  checker;
298
404
  emitter;
299
405
  client;
300
- constructor(data, snapshotId, client, objectRegistry, sourceFileCache, toPath) {
406
+ constructor(data, snapshotId, client, sourceFileCache, toPath, snapshotRegistry) {
301
407
  this.id = data.id;
302
408
  this.configFileName = data.configFileName;
303
409
  this.compilerOptions = data.compilerOptions;
304
410
  this.rootFiles = data.rootFiles;
305
411
  this.client = client;
306
- this.program = new Program(snapshotId, this.id, client, sourceFileCache, toPath);
307
- this.checker = new Checker(snapshotId, this.id, client, objectRegistry);
412
+ this.program = new Program(snapshotId, this, client, sourceFileCache, toPath);
413
+ const objectRegistry = new ProjectObjectRegistry(client, snapshotId, this, snapshotRegistry);
414
+ this.checker = new Checker(snapshotId, this, client, objectRegistry);
308
415
  this.emitter = new Emitter(client);
309
416
  }
417
+ dispose() {
418
+ this.checker.dispose();
419
+ }
310
420
  }
311
421
  export class Program {
312
422
  snapshotId;
313
- projectId;
423
+ project;
314
424
  client;
315
425
  sourceFileCache;
316
426
  toPath;
317
- decoder = new TextDecoder();
318
- constructor(snapshotId, projectId, client, sourceFileCache, toPath) {
427
+ decoder = new Wtf8Decoder();
428
+ sourceFileMetadataCache = new Map();
429
+ constructor(snapshotId, project, client, sourceFileCache, toPath) {
319
430
  this.snapshotId = snapshotId;
320
- this.projectId = projectId;
431
+ this.project = project;
321
432
  this.client = client;
322
433
  this.sourceFileCache = sourceFileCache;
323
434
  this.toPath = toPath;
324
435
  }
436
+ getCompilerOptions() {
437
+ return this.project.compilerOptions;
438
+ }
325
439
  getSourceFile(file) {
326
440
  const fileName = resolveFileName(file);
327
441
  const path = this.toPath(fileName);
328
442
  // Check if we already have a retained cache entry for this (snapshot, project) pair
329
- const retained = this.sourceFileCache.getRetained(path, this.snapshotId, this.projectId);
443
+ const retained = this.sourceFileCache.getRetained(path, this.snapshotId, this.project.id);
330
444
  if (retained) {
331
445
  return retained;
332
446
  }
333
447
  // Fetch from server
334
448
  const binaryData = this.client.apiRequestBinary("getSourceFile", {
335
449
  snapshot: this.snapshotId,
336
- project: this.projectId,
450
+ project: this.project.id,
337
451
  file,
338
452
  });
339
453
  if (!binaryData) {
@@ -343,8 +457,63 @@ export class Program {
343
457
  const contentHash = readSourceFileHash(view);
344
458
  const parseOptionsKey = readParseOptionsKey(view);
345
459
  // Create a new RemoteSourceFile and cache it (set returns existing if hash matches)
346
- const sourceFile = new RemoteSourceFile(binaryData, this.decoder);
347
- return this.sourceFileCache.set(path, sourceFile, parseOptionsKey, contentHash, this.snapshotId, this.projectId);
460
+ const sourceFile = new RemoteSourceFile(binaryData, this.decoder, this.client.getTimingCollector());
461
+ return this.sourceFileCache.set(path, sourceFile, parseOptionsKey, contentHash, this.snapshotId, this.project.id);
462
+ }
463
+ getSourceFileNames() {
464
+ const data = this.client.apiRequest("getSourceFileNames", {
465
+ snapshot: this.snapshotId,
466
+ project: this.project.id,
467
+ });
468
+ return data ?? [];
469
+ }
470
+ /**
471
+ * Returns program-stored metadata for the given source file, or `undefined` if the file
472
+ * is not part of the program. Metadata is fetched lazily per file and cached on this
473
+ * `Program` instance.
474
+ */
475
+ getSourceFileMetadata(fileName) {
476
+ return this.getSourceFileMetadataByPath(this.toPath(fileName));
477
+ }
478
+ /**
479
+ * Returns program-stored metadata for the source file at the given path, or `undefined`
480
+ * if the file is not part of the program. Like {@link getSourceFileMetadata}, but skips
481
+ * the file name to path conversion. Metadata is fetched lazily per file and cached on
482
+ * this `Program` instance.
483
+ */
484
+ getSourceFileMetadataByPath(path) {
485
+ let metadata = this.sourceFileMetadataCache.get(path);
486
+ if (metadata === undefined) {
487
+ metadata = this.fetchSourceFileMetadata(path);
488
+ this.sourceFileMetadataCache.set(path, metadata);
489
+ }
490
+ return metadata;
491
+ }
492
+ fetchSourceFileMetadata(path) {
493
+ const data = this.client.apiRequest("getSourceFileMetadata", {
494
+ snapshot: this.snapshotId,
495
+ project: this.project.id,
496
+ file: path,
497
+ });
498
+ return data ?? undefined;
499
+ }
500
+ /**
501
+ * Returns whether the given source file was loaded as part of an external library
502
+ * (e.g. a dependency resolved from `node_modules`). The underlying program metadata is
503
+ * fetched lazily per file and cached on this `Program` instance.
504
+ */
505
+ isSourceFileFromExternalLibrary(file) {
506
+ const metadata = this.getSourceFileMetadataByPath(file.path);
507
+ return metadata?.isFromExternalLibrary ?? false;
508
+ }
509
+ /**
510
+ * Returns whether the given source file is a default library file (e.g. `lib.d.ts`).
511
+ * The underlying program metadata is fetched lazily per file and cached on this
512
+ * `Program` instance.
513
+ */
514
+ isSourceFileDefaultLibrary(file) {
515
+ const metadata = this.getSourceFileMetadataByPath(file.path);
516
+ return metadata?.isDefaultLibrary ?? false;
348
517
  }
349
518
  /**
350
519
  * Get syntactic (parse) diagnostics for a specific file or all files.
@@ -353,7 +522,19 @@ export class Program {
353
522
  getSyntacticDiagnostics(file) {
354
523
  const data = this.client.apiRequest("getSyntacticDiagnostics", {
355
524
  snapshot: this.snapshotId,
356
- project: this.projectId,
525
+ project: this.project.id,
526
+ ...(file !== undefined ? { file } : {}),
527
+ });
528
+ return data ?? [];
529
+ }
530
+ /**
531
+ * Get binder diagnostics for a specific file or all files.
532
+ * @param file - Optional file to get diagnostics for. If omitted, returns diagnostics for all files.
533
+ */
534
+ getBindDiagnostics(file) {
535
+ const data = this.client.apiRequest("getBindDiagnostics", {
536
+ snapshot: this.snapshotId,
537
+ project: this.project.id,
357
538
  ...(file !== undefined ? { file } : {}),
358
539
  });
359
540
  return data ?? [];
@@ -365,7 +546,7 @@ export class Program {
365
546
  getSemanticDiagnostics(file) {
366
547
  const data = this.client.apiRequest("getSemanticDiagnostics", {
367
548
  snapshot: this.snapshotId,
368
- project: this.projectId,
549
+ project: this.project.id,
369
550
  ...(file !== undefined ? { file } : {}),
370
551
  });
371
552
  return data ?? [];
@@ -377,7 +558,7 @@ export class Program {
377
558
  getSuggestionDiagnostics(file) {
378
559
  const data = this.client.apiRequest("getSuggestionDiagnostics", {
379
560
  snapshot: this.snapshotId,
380
- project: this.projectId,
561
+ project: this.project.id,
381
562
  ...(file !== undefined ? { file } : {}),
382
563
  });
383
564
  return data ?? [];
@@ -389,45 +570,69 @@ export class Program {
389
570
  getDeclarationDiagnostics(file) {
390
571
  const data = this.client.apiRequest("getDeclarationDiagnostics", {
391
572
  snapshot: this.snapshotId,
392
- project: this.projectId,
573
+ project: this.project.id,
393
574
  ...(file !== undefined ? { file } : {}),
394
575
  });
395
576
  return data ?? [];
396
577
  }
578
+ /**
579
+ * Get program-wide diagnostics for the project, including compiler options diagnostics.
580
+ */
581
+ getProgramDiagnostics() {
582
+ const data = this.client.apiRequest("getProgramDiagnostics", {
583
+ snapshot: this.snapshotId,
584
+ project: this.project.id,
585
+ });
586
+ return data ?? [];
587
+ }
588
+ /**
589
+ * Get global (non-file-specific) semantic diagnostics for the project.
590
+ */
591
+ getGlobalDiagnostics() {
592
+ const data = this.client.apiRequest("getGlobalDiagnostics", {
593
+ snapshot: this.snapshotId,
594
+ project: this.project.id,
595
+ });
596
+ return data ?? [];
597
+ }
397
598
  /**
398
599
  * Get config file parsing diagnostics for the project.
399
600
  */
400
601
  getConfigFileParsingDiagnostics() {
401
602
  const data = this.client.apiRequest("getConfigFileParsingDiagnostics", {
402
603
  snapshot: this.snapshotId,
403
- project: this.projectId,
604
+ project: this.project.id,
404
605
  });
405
606
  return data ?? [];
406
607
  }
407
608
  }
408
609
  export class Checker {
409
610
  snapshotId;
410
- projectId;
611
+ project;
411
612
  client;
412
613
  objectRegistry;
413
- constructor(snapshotId, projectId, client, objectRegistry) {
614
+ wellKnownSymbols;
615
+ constructor(snapshotId, project, client, objectRegistry) {
414
616
  this.snapshotId = snapshotId;
415
- this.projectId = projectId;
617
+ this.project = project;
416
618
  this.client = client;
417
619
  this.objectRegistry = objectRegistry;
418
620
  }
621
+ dispose() {
622
+ this.objectRegistry.clear();
623
+ }
419
624
  getSymbolAtLocation(nodeOrNodes) {
420
625
  if (Array.isArray(nodeOrNodes)) {
421
626
  const data = this.client.apiRequest("getSymbolsAtLocations", {
422
627
  snapshot: this.snapshotId,
423
- project: this.projectId,
628
+ project: this.project.id,
424
629
  locations: nodeOrNodes.map(node => getNodeId(node)),
425
630
  });
426
631
  return data.map(d => d ? this.objectRegistry.getOrCreateSymbol(d) : undefined);
427
632
  }
428
633
  const data = this.client.apiRequest("getSymbolAtLocation", {
429
634
  snapshot: this.snapshotId,
430
- project: this.projectId,
635
+ project: this.project.id,
431
636
  location: getNodeId(nodeOrNodes),
432
637
  });
433
638
  return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
@@ -436,7 +641,7 @@ export class Checker {
436
641
  if (typeof positionOrPositions === "number") {
437
642
  const data = this.client.apiRequest("getSymbolAtPosition", {
438
643
  snapshot: this.snapshotId,
439
- project: this.projectId,
644
+ project: this.project.id,
440
645
  file,
441
646
  position: positionOrPositions,
442
647
  });
@@ -444,7 +649,7 @@ export class Checker {
444
649
  }
445
650
  const data = this.client.apiRequest("getSymbolsAtPositions", {
446
651
  snapshot: this.snapshotId,
447
- project: this.projectId,
652
+ project: this.project.id,
448
653
  file,
449
654
  positions: positionOrPositions,
450
655
  });
@@ -454,63 +659,70 @@ export class Checker {
454
659
  if (Array.isArray(symbolOrSymbols)) {
455
660
  const data = this.client.apiRequest("getTypesOfSymbols", {
456
661
  snapshot: this.snapshotId,
457
- project: this.projectId,
662
+ project: this.project.id,
458
663
  symbols: symbolOrSymbols.map(s => s.id),
459
664
  });
460
665
  return data.map(d => d ? this.objectRegistry.getOrCreateType(d) : undefined);
461
666
  }
462
667
  const data = this.client.apiRequest("getTypeOfSymbol", {
463
668
  snapshot: this.snapshotId,
464
- project: this.projectId,
669
+ project: this.project.id,
465
670
  symbol: symbolOrSymbols.id,
466
671
  });
467
672
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
468
673
  }
674
+ /**
675
+ * Get the declared type of a symbol. Always returns a type; for symbols whose
676
+ * declared type cannot be determined the checker yields the error type (use
677
+ * {@link Type.isErrorType} to detect it).
678
+ */
469
679
  getDeclaredTypeOfSymbol(symbol) {
470
680
  const data = this.client.apiRequest("getDeclaredTypeOfSymbol", {
471
681
  snapshot: this.snapshotId,
472
- project: this.projectId,
682
+ project: this.project.id,
473
683
  symbol: symbol.id,
474
684
  });
475
- return data ? this.objectRegistry.getOrCreateType(data) : undefined;
685
+ if (!data)
686
+ throw new Error(`getDeclaredTypeOfSymbol returned no type for symbol ${symbol.id}`);
687
+ return this.objectRegistry.getOrCreateType(data);
476
688
  }
477
689
  getReferencesToSymbolInFile(file, symbol) {
478
690
  const data = this.client.apiRequest("getReferencesToSymbolInFile", {
479
691
  snapshot: this.snapshotId,
480
- project: this.projectId,
692
+ project: this.project.id,
481
693
  file,
482
694
  symbol: symbol.id,
483
695
  });
484
- return (data ?? []).map(h => new NodeHandle(h));
696
+ return (data ?? []).map(h => new NodeHandle(h, this.project));
485
697
  }
486
698
  getReferencedSymbolsForNode(node, position) {
487
699
  const data = this.client.apiRequest("getReferencedSymbolsForNode", {
488
700
  snapshot: this.snapshotId,
489
- project: this.projectId,
701
+ project: this.project.id,
490
702
  node: getNodeId(node),
491
703
  position,
492
704
  });
493
705
  return (data ?? []).map(entry => ({
494
- definition: new NodeHandle(entry.definition),
706
+ definition: new NodeHandle(entry.definition, this.project),
495
707
  symbol: entry.symbol ? this.objectRegistry.getOrCreateSymbol(entry.symbol) : undefined,
496
- references: (entry.references ?? []).map(h => new NodeHandle(h)),
708
+ references: (entry.references ?? []).map(h => new NodeHandle(h, this.project)),
497
709
  }));
498
710
  }
499
711
  getSignatureUsage(signatureDecl) {
500
712
  const data = this.client.apiRequest("getSignatureUsages", {
501
713
  snapshot: this.snapshotId,
502
- project: this.projectId,
714
+ project: this.project.id,
503
715
  signatureDecl: getNodeId(signatureDecl),
504
716
  });
505
717
  return (data ?? []).map(entry => ({
506
- name: new NodeHandle(entry.name),
507
- call: entry.call ? new NodeHandle(entry.call) : undefined,
718
+ name: new NodeHandle(entry.name, this.project),
719
+ call: entry.call ? new NodeHandle(entry.call, this.project) : undefined,
508
720
  }));
509
721
  }
510
722
  getCompletionsAtPosition(document, position, options) {
511
723
  const data = this.client.apiRequest("getCompletionsAtPosition", {
512
724
  snapshot: this.snapshotId,
513
- project: this.projectId,
725
+ project: this.project.id,
514
726
  file: document,
515
727
  position,
516
728
  triggerCharacter: options?.triggerCharacter,
@@ -530,14 +742,14 @@ export class Checker {
530
742
  if (Array.isArray(nodeOrNodes)) {
531
743
  const data = this.client.apiRequest("getTypeAtLocations", {
532
744
  snapshot: this.snapshotId,
533
- project: this.projectId,
745
+ project: this.project.id,
534
746
  locations: nodeOrNodes.map(node => getNodeId(node)),
535
747
  });
536
748
  return data.map(d => d ? this.objectRegistry.getOrCreateType(d) : undefined);
537
749
  }
538
750
  const data = this.client.apiRequest("getTypeAtLocation", {
539
751
  snapshot: this.snapshotId,
540
- project: this.projectId,
752
+ project: this.project.id,
541
753
  location: getNodeId(nodeOrNodes),
542
754
  });
543
755
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -545,7 +757,7 @@ export class Checker {
545
757
  getSignaturesOfType(type, kind) {
546
758
  const data = this.client.apiRequest("getSignaturesOfType", {
547
759
  snapshot: this.snapshotId,
548
- project: this.projectId,
760
+ project: this.project.id,
549
761
  type: type.id,
550
762
  kind,
551
763
  });
@@ -554,7 +766,7 @@ export class Checker {
554
766
  getResolvedSignature(node) {
555
767
  const data = this.client.apiRequest("getResolvedSignature", {
556
768
  snapshot: this.snapshotId,
557
- project: this.projectId,
769
+ project: this.project.id,
558
770
  location: getNodeId(node),
559
771
  });
560
772
  return data ? this.objectRegistry.getOrCreateSignature(data) : undefined;
@@ -563,7 +775,7 @@ export class Checker {
563
775
  if (typeof positionOrPositions === "number") {
564
776
  const data = this.client.apiRequest("getTypeAtPosition", {
565
777
  snapshot: this.snapshotId,
566
- project: this.projectId,
778
+ project: this.project.id,
567
779
  file,
568
780
  position: positionOrPositions,
569
781
  });
@@ -571,7 +783,7 @@ export class Checker {
571
783
  }
572
784
  const data = this.client.apiRequest("getTypesAtPositions", {
573
785
  snapshot: this.snapshotId,
574
- project: this.projectId,
786
+ project: this.project.id,
575
787
  file,
576
788
  positions: positionOrPositions,
577
789
  });
@@ -582,7 +794,7 @@ export class Checker {
582
794
  const isNode = location && "kind" in location;
583
795
  const data = this.client.apiRequest("resolveName", {
584
796
  snapshot: this.snapshotId,
585
- project: this.projectId,
797
+ project: this.project.id,
586
798
  name,
587
799
  meaning,
588
800
  location: isNode ? getNodeId(location) : undefined,
@@ -601,7 +813,7 @@ export class Checker {
601
813
  getContextualType(node) {
602
814
  const data = this.client.apiRequest("getContextualType", {
603
815
  snapshot: this.snapshotId,
604
- project: this.projectId,
816
+ project: this.project.id,
605
817
  location: getNodeId(node),
606
818
  });
607
819
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -609,7 +821,7 @@ export class Checker {
609
821
  getBaseTypeOfLiteralType(type) {
610
822
  const data = this.client.apiRequest("getBaseTypeOfLiteralType", {
611
823
  snapshot: this.snapshotId,
612
- project: this.projectId,
824
+ project: this.project.id,
613
825
  type: type.id,
614
826
  });
615
827
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -617,7 +829,7 @@ export class Checker {
617
829
  getNonNullableType(type) {
618
830
  const data = this.client.apiRequest("getNonNullableType", {
619
831
  snapshot: this.snapshotId,
620
- project: this.projectId,
832
+ project: this.project.id,
621
833
  type: type.id,
622
834
  });
623
835
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -625,7 +837,7 @@ export class Checker {
625
837
  getTypeFromTypeNode(node) {
626
838
  const data = this.client.apiRequest("getTypeFromTypeNode", {
627
839
  snapshot: this.snapshotId,
628
- project: this.projectId,
840
+ project: this.project.id,
629
841
  location: getNodeId(node),
630
842
  });
631
843
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -633,7 +845,7 @@ export class Checker {
633
845
  getWidenedType(type) {
634
846
  const data = this.client.apiRequest("getWidenedType", {
635
847
  snapshot: this.snapshotId,
636
- project: this.projectId,
848
+ project: this.project.id,
637
849
  type: type.id,
638
850
  });
639
851
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -641,7 +853,7 @@ export class Checker {
641
853
  getParameterType(signature, index) {
642
854
  const data = this.client.apiRequest("getParameterType", {
643
855
  snapshot: this.snapshotId,
644
- project: this.projectId,
856
+ project: this.project.id,
645
857
  signature: signature.id,
646
858
  index,
647
859
  });
@@ -650,14 +862,14 @@ export class Checker {
650
862
  isArrayLikeType(type) {
651
863
  return this.client.apiRequest("isArrayLikeType", {
652
864
  snapshot: this.snapshotId,
653
- project: this.projectId,
865
+ project: this.project.id,
654
866
  type: type.id,
655
867
  });
656
868
  }
657
869
  isTypeAssignableTo(source, target) {
658
870
  return this.client.apiRequest("isTypeAssignableTo", {
659
871
  snapshot: this.snapshotId,
660
- project: this.projectId,
872
+ project: this.project.id,
661
873
  source: source.id,
662
874
  target: target.id,
663
875
  });
@@ -665,24 +877,31 @@ export class Checker {
665
877
  getShorthandAssignmentValueSymbol(node) {
666
878
  const data = this.client.apiRequest("getShorthandAssignmentValueSymbol", {
667
879
  snapshot: this.snapshotId,
668
- project: this.projectId,
880
+ project: this.project.id,
669
881
  location: getNodeId(node),
670
882
  });
671
883
  return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
672
884
  }
885
+ /**
886
+ * Get the type of a symbol as narrowed at a specific location. Always returns
887
+ * a type; for symbols whose type cannot be determined the checker yields the
888
+ * error type (use {@link Type.isErrorType} to detect it).
889
+ */
673
890
  getTypeOfSymbolAtLocation(symbol, location) {
674
891
  const data = this.client.apiRequest("getTypeOfSymbolAtLocation", {
675
892
  snapshot: this.snapshotId,
676
- project: this.projectId,
893
+ project: this.project.id,
677
894
  symbol: symbol.id,
678
895
  location: getNodeId(location),
679
896
  });
680
- return data ? this.objectRegistry.getOrCreateType(data) : undefined;
897
+ if (!data)
898
+ throw new Error(`getTypeOfSymbolAtLocation returned no type for symbol ${symbol.id}`);
899
+ return this.objectRegistry.getOrCreateType(data);
681
900
  }
682
901
  getIntrinsicType(method) {
683
902
  const data = this.client.apiRequest(method, {
684
903
  snapshot: this.snapshotId,
685
- project: this.projectId,
904
+ project: this.project.id,
686
905
  });
687
906
  return this.objectRegistry.getOrCreateType(data);
688
907
  }
@@ -722,7 +941,7 @@ export class Checker {
722
941
  typeToTypeNode(type, enclosingDeclaration, flags) {
723
942
  const binaryData = this.client.apiRequestBinary("typeToTypeNode", {
724
943
  snapshot: this.snapshotId,
725
- project: this.projectId,
944
+ project: this.project.id,
726
945
  type: type.id,
727
946
  location: enclosingDeclaration ? getNodeId(enclosingDeclaration) : undefined,
728
947
  flags,
@@ -734,7 +953,7 @@ export class Checker {
734
953
  signatureToSignatureDeclaration(signature, kind, enclosingDeclaration, flags) {
735
954
  const binaryData = this.client.apiRequestBinary("signatureToSignatureDeclaration", {
736
955
  snapshot: this.snapshotId,
737
- project: this.projectId,
956
+ project: this.project.id,
738
957
  signature: signature.id,
739
958
  kind,
740
959
  location: enclosingDeclaration ? getNodeId(enclosingDeclaration) : undefined,
@@ -747,7 +966,7 @@ export class Checker {
747
966
  typeToString(type, enclosingDeclaration, flags) {
748
967
  return this.client.apiRequest("typeToString", {
749
968
  snapshot: this.snapshotId,
750
- project: this.projectId,
969
+ project: this.project.id,
751
970
  type: type.id,
752
971
  location: enclosingDeclaration ? getNodeId(enclosingDeclaration) : undefined,
753
972
  flags,
@@ -756,14 +975,28 @@ export class Checker {
756
975
  isContextSensitive(node) {
757
976
  return this.client.apiRequest("isContextSensitive", {
758
977
  snapshot: this.snapshotId,
759
- project: this.projectId,
978
+ project: this.project.id,
760
979
  location: getNodeId(node),
761
980
  });
762
981
  }
982
+ isArrayType(type) {
983
+ return this.client.apiRequest("isArrayType", {
984
+ snapshot: this.snapshotId,
985
+ project: this.project.id,
986
+ type: type.id,
987
+ });
988
+ }
989
+ isTupleType(type) {
990
+ return this.client.apiRequest("isTupleType", {
991
+ snapshot: this.snapshotId,
992
+ project: this.project.id,
993
+ type: type.id,
994
+ });
995
+ }
763
996
  getReturnTypeOfSignature(signature) {
764
997
  const data = this.client.apiRequest("getReturnTypeOfSignature", {
765
998
  snapshot: this.snapshotId,
766
- project: this.projectId,
999
+ project: this.project.id,
767
1000
  signature: signature.id,
768
1001
  });
769
1002
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -771,7 +1004,7 @@ export class Checker {
771
1004
  getRestTypeOfSignature(signature) {
772
1005
  const data = this.client.apiRequest("getRestTypeOfSignature", {
773
1006
  snapshot: this.snapshotId,
774
- project: this.projectId,
1007
+ project: this.project.id,
775
1008
  signature: signature.id,
776
1009
  });
777
1010
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
@@ -779,7 +1012,7 @@ export class Checker {
779
1012
  getTypePredicateOfSignature(signature) {
780
1013
  const data = this.client.apiRequest("getTypePredicateOfSignature", {
781
1014
  snapshot: this.snapshotId,
782
- project: this.projectId,
1015
+ project: this.project.id,
783
1016
  signature: signature.id,
784
1017
  });
785
1018
  if (!data)
@@ -791,18 +1024,30 @@ export class Checker {
791
1024
  type: data.type ? this.objectRegistry.getOrCreateType(data.type) : undefined,
792
1025
  };
793
1026
  }
1027
+ /**
1028
+ * Get the base types of a class or interface type. A type with no base types
1029
+ * yields an empty array.
1030
+ */
794
1031
  getBaseTypes(type) {
795
1032
  const data = this.client.apiRequest("getBaseTypes", {
796
1033
  snapshot: this.snapshotId,
797
- project: this.projectId,
1034
+ project: this.project.id,
798
1035
  type: type.id,
799
1036
  });
800
1037
  return data ? data.map(d => this.objectRegistry.getOrCreateType(d)) : [];
801
1038
  }
1039
+ getApparentType(type) {
1040
+ const data = this.client.apiRequest("getApparentType", {
1041
+ snapshot: this.snapshotId,
1042
+ project: this.project.id,
1043
+ type: type.id,
1044
+ });
1045
+ return data ? this.objectRegistry.getOrCreateType(data) : undefined;
1046
+ }
802
1047
  getPropertiesOfType(type) {
803
1048
  const data = this.client.apiRequest("getPropertiesOfType", {
804
1049
  snapshot: this.snapshotId,
805
- project: this.projectId,
1050
+ project: this.project.id,
806
1051
  type: type.id,
807
1052
  });
808
1053
  return data ? data.map(d => this.objectRegistry.getOrCreateSymbol(d)) : [];
@@ -810,7 +1055,7 @@ export class Checker {
810
1055
  getIndexInfosOfType(type) {
811
1056
  const data = this.client.apiRequest("getIndexInfosOfType", {
812
1057
  snapshot: this.snapshotId,
813
- project: this.projectId,
1058
+ project: this.project.id,
814
1059
  type: type.id,
815
1060
  });
816
1061
  if (!data)
@@ -819,21 +1064,155 @@ export class Checker {
819
1064
  keyType: this.objectRegistry.getOrCreateType(d.keyType),
820
1065
  valueType: this.objectRegistry.getOrCreateType(d.valueType),
821
1066
  isReadonly: d.isReadonly ?? false,
822
- declaration: d.declaration ? new NodeHandle(d.declaration) : undefined,
1067
+ declaration: d.declaration ? new NodeHandle(d.declaration, this.project) : undefined,
823
1068
  }));
824
1069
  }
1070
+ /**
1071
+ * Get the constraint of a type parameter (the `T` in `<U extends T>`), or
1072
+ * undefined if it has none.
1073
+ */
825
1074
  getConstraintOfTypeParameter(type) {
826
1075
  const data = this.client.apiRequest("getConstraintOfTypeParameter", {
827
1076
  snapshot: this.snapshotId,
828
- project: this.projectId,
1077
+ project: this.project.id,
1078
+ type: type.id,
1079
+ });
1080
+ return data ? this.objectRegistry.getOrCreateType(data) : undefined;
1081
+ }
1082
+ getBaseConstraintOfType(type) {
1083
+ const data = this.client.apiRequest("getBaseConstraintOfType", {
1084
+ snapshot: this.snapshotId,
1085
+ project: this.project.id,
829
1086
  type: type.id,
830
1087
  });
831
1088
  return data ? this.objectRegistry.getOrCreateType(data) : undefined;
832
1089
  }
1090
+ getPropertyOfType(type, name) {
1091
+ const data = this.client.apiRequest("getPropertyOfType", {
1092
+ snapshot: this.snapshotId,
1093
+ project: this.project.id,
1094
+ type: type.id,
1095
+ name,
1096
+ });
1097
+ return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
1098
+ }
1099
+ getConstantValue(node) {
1100
+ const data = this.client.apiRequest("getConstantValue", {
1101
+ snapshot: this.snapshotId,
1102
+ project: this.project.id,
1103
+ location: getNodeId(node),
1104
+ });
1105
+ return data ?? undefined;
1106
+ }
1107
+ getSignatureFromDeclaration(node) {
1108
+ const data = this.client.apiRequest("getSignatureFromDeclaration", {
1109
+ snapshot: this.snapshotId,
1110
+ project: this.project.id,
1111
+ location: getNodeId(node),
1112
+ });
1113
+ return data ? this.objectRegistry.getOrCreateSignature(data) : undefined;
1114
+ }
1115
+ getExportSpecifierLocalTargetSymbol(node) {
1116
+ const data = this.client.apiRequest("getExportSpecifierLocalTargetSymbol", {
1117
+ snapshot: this.snapshotId,
1118
+ project: this.project.id,
1119
+ location: getNodeId(node),
1120
+ });
1121
+ return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
1122
+ }
1123
+ /**
1124
+ * Follow all aliases to get the original symbol. Always returns a symbol; for
1125
+ * an unresolved alias the checker yields the unknown symbol (use
1126
+ * {@link Checker.isUnknownSymbol} to detect it).
1127
+ */
1128
+ getAliasedSymbol(symbol) {
1129
+ const data = this.client.apiRequest("getAliasedSymbol", {
1130
+ snapshot: this.snapshotId,
1131
+ project: this.project.id,
1132
+ symbol: symbol.id,
1133
+ });
1134
+ if (!data)
1135
+ throw new Error(`getAliasedSymbol returned no symbol for symbol ${symbol.id}`);
1136
+ return this.objectRegistry.getOrCreateSymbol(data);
1137
+ }
1138
+ getImmediateAliasedSymbol(symbol) {
1139
+ const data = this.client.apiRequest("getImmediateAliasedSymbol", {
1140
+ snapshot: this.snapshotId,
1141
+ project: this.project.id,
1142
+ symbol: symbol.id,
1143
+ });
1144
+ return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
1145
+ }
1146
+ /**
1147
+ * Fetch (once, then cache) the handle ids of the per-checker singleton
1148
+ * symbols (unknown, undefined, arguments). These ids are stable for the life
1149
+ * of the project's checker, so identity checks against them are local after
1150
+ * the first call.
1151
+ */
1152
+ getWellKnownSymbols() {
1153
+ return this.wellKnownSymbols ??= this.client.apiRequest("getWellKnownSymbols", {
1154
+ snapshot: this.snapshotId,
1155
+ project: this.project.id,
1156
+ });
1157
+ }
1158
+ /**
1159
+ * Returns `true` if the symbol is the checker's "unknown" symbol (e.g. the
1160
+ * result of {@link Checker.getAliasedSymbol} on an unresolved alias).
1161
+ */
1162
+ isUnknownSymbol(symbol) {
1163
+ return symbol.id === (this.getWellKnownSymbols()).unknown;
1164
+ }
1165
+ /**
1166
+ * Returns `true` if the symbol is the checker's "undefined" symbol.
1167
+ */
1168
+ isUndefinedSymbol(symbol) {
1169
+ return symbol.id === (this.getWellKnownSymbols()).undefined;
1170
+ }
1171
+ /**
1172
+ * Returns `true` if the symbol is the checker's "arguments" symbol.
1173
+ */
1174
+ isArgumentsSymbol(symbol) {
1175
+ return symbol.id === (this.getWellKnownSymbols()).arguments;
1176
+ }
1177
+ getExportsOfModule(symbol) {
1178
+ const data = this.client.apiRequest("getExportsOfModule", {
1179
+ snapshot: this.snapshotId,
1180
+ project: this.project.id,
1181
+ symbol: symbol.id,
1182
+ });
1183
+ return data ? data.map(d => this.objectRegistry.getOrCreateSymbol(d)) : [];
1184
+ }
1185
+ getMemberInModuleExports(symbol, name) {
1186
+ const data = this.client.apiRequest("getMemberInModuleExports", {
1187
+ snapshot: this.snapshotId,
1188
+ project: this.project.id,
1189
+ symbol: symbol.id,
1190
+ name,
1191
+ });
1192
+ return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
1193
+ }
1194
+ getJsDocTagsOfSymbol(symbol) {
1195
+ const data = this.client.apiRequest("getJsDocTags", {
1196
+ snapshot: this.snapshotId,
1197
+ project: this.project.id,
1198
+ symbol: symbol.id,
1199
+ });
1200
+ return data ?? [];
1201
+ }
1202
+ getDocumentationCommentOfSymbol(symbol) {
1203
+ return this.client.apiRequest("getDocumentationComment", {
1204
+ snapshot: this.snapshotId,
1205
+ project: this.project.id,
1206
+ symbol: symbol.id,
1207
+ });
1208
+ }
1209
+ /**
1210
+ * Get the type arguments of a type reference (e.g. the `string` in `Array<string>`).
1211
+ */
833
1212
  getTypeArguments(type) {
834
1213
  const data = this.client.apiRequest("getTypeArguments", {
835
1214
  snapshot: this.snapshotId,
836
- project: this.projectId,
1215
+ project: this.project.id,
837
1216
  type: type.id,
838
1217
  });
839
1218
  return data ? data.map(d => this.objectRegistry.getOrCreateType(d)) : [];
@@ -854,20 +1233,28 @@ export class Emitter {
854
1233
  }
855
1234
  }
856
1235
  export class NodeHandle {
1236
+ /**
1237
+ * The project this handle was produced in, used as the default for {@link resolve}.
1238
+ * Node handles are only meaningful within a project's program, so the producing project
1239
+ * is remembered so callers don't have to pass it explicitly.
1240
+ */
1241
+ canonicalProject;
857
1242
  index;
858
1243
  kind;
859
1244
  path;
860
- constructor(handle) {
1245
+ constructor(handle, canonicalProject) {
861
1246
  const parsed = parseNodeHandle(handle);
862
1247
  this.index = parsed.index;
863
1248
  this.kind = parsed.kind;
864
1249
  this.path = parsed.path;
1250
+ this.canonicalProject = canonicalProject;
865
1251
  }
866
1252
  /**
867
- * Resolve this handle to the actual AST node by fetching the source file
868
- * from the given project and looking up the node by index.
1253
+ * Resolve this handle to the actual AST node by fetching the source file from a project
1254
+ * and looking up the node by index. If no project is passed, the project that produced
1255
+ * the handle is used.
869
1256
  */
870
- resolve(project) {
1257
+ resolve(project = this.canonicalProject) {
871
1258
  const sourceFile = project.program.getSourceFile(this.path);
872
1259
  if (!sourceFile) {
873
1260
  return undefined;
@@ -877,7 +1264,16 @@ export class NodeHandle {
877
1264
  }
878
1265
  export class Symbol {
879
1266
  objectRegistry;
1267
+ /**
1268
+ * The project this symbol was first observed in, used as the default project for
1269
+ * lookups that need a project context (members/exports/parent). Symbols are shared
1270
+ * snapshot-wide, so these lookups can otherwise be ambiguous about which project to use.
1271
+ */
1272
+ canonicalProject;
880
1273
  id;
1274
+ /** The escaped (`__String`) name, used as the key in member/export tables. */
1275
+ escapedName;
1276
+ /** The display name (escaped underscores removed). */
881
1277
  name;
882
1278
  flags;
883
1279
  checkFlags;
@@ -885,32 +1281,62 @@ export class Symbol {
885
1281
  valueDeclaration;
886
1282
  parent;
887
1283
  exportSymbol;
1284
+ membersCache;
1285
+ exportsCache;
888
1286
  constructor(data, objectRegistry) {
889
1287
  this.objectRegistry = objectRegistry;
890
1288
  this.id = data.id;
891
- this.name = data.name;
1289
+ this.escapedName = data.name;
1290
+ this.name = unescapeLeadingUnderscores(data.name);
892
1291
  this.flags = data.flags;
893
1292
  this.checkFlags = data.checkFlags;
894
- this.declarations = (data.declarations ?? []).map(d => new NodeHandle(d));
895
- this.valueDeclaration = data.valueDeclaration ? new NodeHandle(data.valueDeclaration) : undefined;
1293
+ const canonicalProject = objectRegistry.getProject(data.project);
1294
+ if (!canonicalProject) {
1295
+ throw new Error(`Symbol ${data.id} references unknown canonical project '${data.project}'`);
1296
+ }
1297
+ this.canonicalProject = canonicalProject;
1298
+ this.declarations = (data.declarations ?? []).map(d => new NodeHandle(d, canonicalProject));
1299
+ this.valueDeclaration = data.valueDeclaration ? new NodeHandle(data.valueDeclaration, canonicalProject) : undefined;
896
1300
  if (data.parent !== undefined)
897
1301
  this.parent = data.parent;
898
1302
  if (data.exportSymbol !== undefined)
899
1303
  this.exportSymbol = data.exportSymbol;
900
1304
  }
901
1305
  getParent() {
902
- return this.objectRegistry.fetchSymbol(this, "getParentOfSymbol", this.parent);
1306
+ return this.objectRegistry.fetchSymbol(this, "getParentOfSymbol", this.parent, this.canonicalProject.id);
903
1307
  }
1308
+ /**
1309
+ * Get this symbol's members keyed by escaped name. The result is cached on
1310
+ * the symbol, so repeated calls do not round-trip to the server.
1311
+ */
904
1312
  getMembers() {
905
- return this.objectRegistry.fetchSymbols(this, "getMembersOfSymbol");
1313
+ return this.membersCache ??= this.fetchSymbolTable("getMembersOfSymbol");
906
1314
  }
1315
+ /**
1316
+ * Get this symbol's exports keyed by escaped name. The result is cached on
1317
+ * the symbol, so repeated calls do not round-trip to the server.
1318
+ */
907
1319
  getExports() {
908
- return this.objectRegistry.fetchSymbols(this, "getExportsOfSymbol");
1320
+ return this.exportsCache ??= this.fetchSymbolTable("getExportsOfSymbol");
1321
+ }
1322
+ fetchSymbolTable(method) {
1323
+ const symbols = this.objectRegistry.fetchSymbols(this, method, undefined, this.canonicalProject.id);
1324
+ const table = new Map();
1325
+ for (const symbol of symbols) {
1326
+ table.set(symbol.escapedName, symbol);
1327
+ }
1328
+ return table;
909
1329
  }
910
1330
  getExportSymbol() {
911
1331
  if (!this.exportSymbol)
912
1332
  return this;
913
- return this.objectRegistry.fetchSymbol(this, "getExportSymbolOfSymbol", this.exportSymbol);
1333
+ return this.objectRegistry.fetchSymbol(this, "getExportSymbolOfSymbol", this.exportSymbol, this.canonicalProject.id);
1334
+ }
1335
+ getJsDocTags(checker) {
1336
+ return checker.getJsDocTagsOfSymbol(this);
1337
+ }
1338
+ getDocumentationComment(checker) {
1339
+ return checker.getDocumentationCommentOfSymbol(this);
914
1340
  }
915
1341
  }
916
1342
  class TypeObject {
@@ -940,6 +1366,8 @@ class TypeObject {
940
1366
  extendsType;
941
1367
  baseType;
942
1368
  substConstraint;
1369
+ trueType; // false if not yet loaded
1370
+ falseType; // false if not yet loaded
943
1371
  constructor(data, objectRegistry) {
944
1372
  this.objectRegistry = objectRegistry;
945
1373
  this.id = data.id;
@@ -948,8 +1376,11 @@ class TypeObject {
948
1376
  this.objectFlags = data.objectFlags;
949
1377
  if (data.symbol !== undefined)
950
1378
  this.symbol = data.symbol;
951
- if (data.value !== undefined)
952
- this.value = data.value;
1379
+ if (data.value != null) {
1380
+ // BigInt literal values are serialized as decimal strings (e.g. "-123") because
1381
+ // JSON cannot represent bigint. Decode them back into a real bigint here.
1382
+ this.value = (data.flags & TypeFlags.BigIntLiteral) ? BigInt(data.value) : data.value;
1383
+ }
953
1384
  if (data.intrinsicName !== undefined)
954
1385
  this.intrinsicName = data.intrinsicName;
955
1386
  if (data.isThisType !== undefined)
@@ -986,6 +1417,8 @@ class TypeObject {
986
1417
  this.baseType = data.baseType;
987
1418
  if (data.substConstraint !== undefined)
988
1419
  this.substConstraint = data.substConstraint;
1420
+ this.trueType = false;
1421
+ this.falseType = false;
989
1422
  }
990
1423
  getSymbol() {
991
1424
  return this.objectRegistry.fetchSymbol(this, "getSymbolOfType", this.symbol);
@@ -1003,6 +1436,12 @@ class TypeObject {
1003
1436
  return this.objectRegistry.fetchType(this, "getRegularTypeOfType", this.regularType);
1004
1437
  }
1005
1438
  getTypes() {
1439
+ // Only union, intersection, and template literal types have constituent
1440
+ // types; any other kind has none, so return undefined rather than sending
1441
+ // a request the server cannot satisfy.
1442
+ if (!(this.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral))) {
1443
+ return undefined;
1444
+ }
1006
1445
  return this.objectRegistry.fetchTypes(this, "getTypesOfType");
1007
1446
  }
1008
1447
  getTypeParameters() {
@@ -1035,6 +1474,152 @@ class TypeObject {
1035
1474
  getConstraint() {
1036
1475
  return this.objectRegistry.fetchType(this, "getConstraintOfType", this.substConstraint);
1037
1476
  }
1477
+ getTrueType() {
1478
+ const result = this.objectRegistry.fetchType(this, "getTrueTypeOfConditionalType", this.trueType);
1479
+ this.trueType = result.id;
1480
+ return result;
1481
+ }
1482
+ getFalseType() {
1483
+ const result = this.objectRegistry.fetchType(this, "getFalseTypeOfConditionalType", this.falseType);
1484
+ this.falseType = result.id;
1485
+ return result;
1486
+ }
1487
+ /**
1488
+ * Get the base types of this type. Returns `undefined` for any type that is
1489
+ * not a class or interface.
1490
+ */
1491
+ getBaseTypes() {
1492
+ if (!this.isClassOrInterface()) {
1493
+ return undefined;
1494
+ }
1495
+ return this.objectRegistry.fetchBaseTypes(this);
1496
+ }
1497
+ isClassOrInterface() {
1498
+ return isClassOrInterfaceType(this);
1499
+ }
1500
+ isUnionType() {
1501
+ return isUnionType(this);
1502
+ }
1503
+ isIntersectionType() {
1504
+ return isIntersectionType(this);
1505
+ }
1506
+ isObjectType() {
1507
+ return isObjectType(this);
1508
+ }
1509
+ isIntrinsicType() {
1510
+ return isIntrinsicType(this);
1511
+ }
1512
+ isErrorType() {
1513
+ return isErrorType(this);
1514
+ }
1515
+ isLiteralType() {
1516
+ return isLiteralType(this);
1517
+ }
1518
+ isStringLiteralType() {
1519
+ return isStringLiteralType(this);
1520
+ }
1521
+ isNumberLiteralType() {
1522
+ return isNumberLiteralType(this);
1523
+ }
1524
+ isBigIntLiteralType() {
1525
+ return isBigIntLiteralType(this);
1526
+ }
1527
+ isBooleanLiteralType() {
1528
+ return isBooleanLiteralType(this);
1529
+ }
1530
+ isTypeReference() {
1531
+ return isTypeReference(this);
1532
+ }
1533
+ isTupleType() {
1534
+ return isTupleType(this);
1535
+ }
1536
+ isIndexType() {
1537
+ return isIndexType(this);
1538
+ }
1539
+ isIndexedAccessType() {
1540
+ return isIndexedAccessType(this);
1541
+ }
1542
+ isConditionalType() {
1543
+ return isConditionalType(this);
1544
+ }
1545
+ isSubstitutionType() {
1546
+ return isSubstitutionType(this);
1547
+ }
1548
+ isTemplateLiteralType() {
1549
+ return isTemplateLiteralType(this);
1550
+ }
1551
+ isStringMappingType() {
1552
+ return isStringMappingType(this);
1553
+ }
1554
+ isTypeParameter() {
1555
+ return isTypeParameter(this);
1556
+ }
1557
+ }
1558
+ export function isUnionType(type) {
1559
+ return (type.flags & TypeFlags.Union) !== 0;
1560
+ }
1561
+ export function isIntersectionType(type) {
1562
+ return (type.flags & TypeFlags.Intersection) !== 0;
1563
+ }
1564
+ export function isObjectType(type) {
1565
+ return (type.flags & TypeFlags.Object) !== 0;
1566
+ }
1567
+ export function isClassOrInterfaceType(type) {
1568
+ return isObjectType(type) && (type.objectFlags & ObjectFlags.ClassOrInterface) !== 0;
1569
+ }
1570
+ export function isIntrinsicType(type) {
1571
+ return (type.flags & TypeFlags.Intrinsic) !== 0;
1572
+ }
1573
+ /**
1574
+ * Whether this is the error type — the placeholder the checker produces when a
1575
+ * type cannot be determined (e.g. an unresolved reference). It is an intrinsic
1576
+ * type named `"error"` (this covers both the singleton error type and the
1577
+ * per-alias error types manufactured for unresolved type alias references).
1578
+ */
1579
+ export function isErrorType(type) {
1580
+ return isIntrinsicType(type) && type.intrinsicName === "error";
1581
+ }
1582
+ export function isLiteralType(type) {
1583
+ return (type.flags & TypeFlags.Literal) !== 0;
1584
+ }
1585
+ export function isStringLiteralType(type) {
1586
+ return (type.flags & TypeFlags.StringLiteral) !== 0;
1587
+ }
1588
+ export function isNumberLiteralType(type) {
1589
+ return (type.flags & TypeFlags.NumberLiteral) !== 0;
1590
+ }
1591
+ export function isBigIntLiteralType(type) {
1592
+ return (type.flags & TypeFlags.BigIntLiteral) !== 0;
1593
+ }
1594
+ export function isBooleanLiteralType(type) {
1595
+ return (type.flags & TypeFlags.BooleanLiteral) !== 0;
1596
+ }
1597
+ export function isTypeReference(type) {
1598
+ return isObjectType(type) && (type.objectFlags & ObjectFlags.Reference) !== 0;
1599
+ }
1600
+ export function isTupleType(type) {
1601
+ return isObjectType(type) && (type.objectFlags & ObjectFlags.Tuple) !== 0;
1602
+ }
1603
+ export function isIndexType(type) {
1604
+ return (type.flags & TypeFlags.Index) !== 0;
1605
+ }
1606
+ export function isIndexedAccessType(type) {
1607
+ return (type.flags & TypeFlags.IndexedAccess) !== 0;
1608
+ }
1609
+ export function isConditionalType(type) {
1610
+ return (type.flags & TypeFlags.Conditional) !== 0;
1611
+ }
1612
+ export function isSubstitutionType(type) {
1613
+ return (type.flags & TypeFlags.Substitution) !== 0;
1614
+ }
1615
+ export function isTemplateLiteralType(type) {
1616
+ return (type.flags & TypeFlags.TemplateLiteral) !== 0;
1617
+ }
1618
+ export function isStringMappingType(type) {
1619
+ return (type.flags & TypeFlags.StringMapping) !== 0;
1620
+ }
1621
+ export function isTypeParameter(type) {
1622
+ return (type.flags & TypeFlags.TypeParameter) !== 0;
1038
1623
  }
1039
1624
  export class Signature {
1040
1625
  flags;
@@ -1045,11 +1630,11 @@ export class Signature {
1045
1630
  parameters;
1046
1631
  thisParameter;
1047
1632
  target;
1048
- constructor(data, objectRegistry) {
1633
+ constructor(data, project, objectRegistry) {
1049
1634
  this.id = data.id;
1050
1635
  this.flags = data.flags;
1051
1636
  this.objectRegistry = objectRegistry;
1052
- this.declaration = data.declaration ? new NodeHandle(data.declaration) : undefined;
1637
+ this.declaration = data.declaration ? new NodeHandle(data.declaration, project) : undefined;
1053
1638
  this.typeParameters = data.typeParameters ?? [];
1054
1639
  this.parameters = data.parameters ?? [];
1055
1640
  this.thisParameter = data.thisParameter;