typescript 7.1.0-dev.20260923.1 → 7.1.0-dev.20260925.1

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 (39) hide show
  1. package/dist/api/async/api.d.ts +79 -6
  2. package/dist/api/async/api.d.ts.map +1 -1
  3. package/dist/api/async/api.js +200 -29
  4. package/dist/api/async/api.js.map +1 -1
  5. package/dist/api/async/client.d.ts +1 -0
  6. package/dist/api/async/client.d.ts.map +1 -1
  7. package/dist/api/async/client.js +7 -0
  8. package/dist/api/async/client.js.map +1 -1
  9. package/dist/api/node/node.d.ts +1 -1
  10. package/dist/api/node/node.d.ts.map +1 -1
  11. package/dist/api/node/node.infrastructure.d.ts +1 -0
  12. package/dist/api/node/node.infrastructure.d.ts.map +1 -1
  13. package/dist/api/node/node.infrastructure.js +11 -1
  14. package/dist/api/node/node.infrastructure.js.map +1 -1
  15. package/dist/api/node/node.js +1 -1
  16. package/dist/api/node/node.js.map +1 -1
  17. package/dist/api/node/protocol.d.ts +5 -2
  18. package/dist/api/node/protocol.d.ts.map +1 -1
  19. package/dist/api/node/protocol.js +5 -2
  20. package/dist/api/node/protocol.js.map +1 -1
  21. package/dist/api/proto.generated.d.ts +47 -3
  22. package/dist/api/proto.generated.d.ts.map +1 -1
  23. package/dist/api/sourceFileCache.d.ts +15 -6
  24. package/dist/api/sourceFileCache.d.ts.map +1 -1
  25. package/dist/api/sourceFileCache.js +59 -27
  26. package/dist/api/sourceFileCache.js.map +1 -1
  27. package/dist/api/sync/api.d.ts +95 -8
  28. package/dist/api/sync/api.d.ts.map +1 -1
  29. package/dist/api/sync/api.js +288 -56
  30. package/dist/api/sync/api.js.map +1 -1
  31. package/dist/api/sync/client.d.ts +1 -0
  32. package/dist/api/sync/client.d.ts.map +1 -1
  33. package/dist/api/sync/client.js +4 -0
  34. package/dist/api/sync/client.js.map +1 -1
  35. package/dist/api/syncChannel.d.ts +1 -0
  36. package/dist/api/syncChannel.d.ts.map +1 -1
  37. package/dist/api/syncChannel.js +3 -0
  38. package/dist/api/syncChannel.js.map +1 -1
  39. package/package.json +9 -9
@@ -20,7 +20,7 @@ import { TypePredicateKind } from "#enums/typePredicateKind";
20
20
  import { ModifierFlags, unescapeLeadingUnderscores, } from "../../ast/index.js";
21
21
  import { assertNever } from "../../internal/utils.js";
22
22
  import { encodeNode, uint8ArrayToBase64, } from "../node/encoder.js";
23
- import { decodeNode, getNodeId, parseNodeHandle, readParseOptionsKey, readSourceFileHash, RemoteSourceFile, } from "../node/node.js";
23
+ import { decodeNode, getNodeId, parseNodeHandle, readParseOptionsKey, readSourceFileHash, readSourceFileLease, RemoteSourceFile, } from "../node/node.js";
24
24
  import { Wtf8Decoder } from "../node/wtf8.js";
25
25
  import { createGetCanonicalFileName, toPath, } from "../path.js";
26
26
  import { resolveFileName, toCreateSnapshotRequest, } from "../proto.js";
@@ -29,6 +29,22 @@ import { Client, } from "./client.js";
29
29
  export { formatDiagnostics, formatDiagnosticsWithColorAndContext } from "../diagnosticFormatter.js";
30
30
  export { documentURIToFileName, fileNameToDocumentURI } from "../path.js";
31
31
  export { CheckFlags, CompletionItemKind, DiagnosticCategory, ElementFlags, EmitOnly, IndexKind, JsxEmit, ModifierFlags, ModuleKind, ModuleResolutionKind, NodeBuilderFlags, ObjectFlags, ScriptKind, SignatureFlags, SignatureKind, SymbolFlags, TypeFlags, TypeFormatFlags, TypePredicateKind };
32
+ let nextModuleResolutionCallbackId = 0;
33
+ function registerModuleResolutionCallback(client, callback, getSnapshot) {
34
+ const name = `resolveModuleName/${++nextModuleResolutionCallbackId}`;
35
+ const dispose = client.registerCallback(name, params => {
36
+ const { moduleName, containingDirectory, resolutionMode, snapshot: snapshotId, inProgressSnapshot } = params;
37
+ let snapshot = snapshotId === undefined ? undefined : getSnapshot(snapshotId);
38
+ if (snapshotId !== undefined && snapshot === undefined) {
39
+ throw new Error(`Snapshot ${snapshotId} is inactive`);
40
+ }
41
+ if (inProgressSnapshot !== undefined) {
42
+ snapshot = -inProgressSnapshot;
43
+ }
44
+ return callback(moduleName, containingDirectory, resolutionMode, { snapshot });
45
+ });
46
+ return { name, dispose };
47
+ }
32
48
  // @sync-only-start
33
49
  // export { all, defer, type APIRequestGenerator, type AnyAPIRequestGenerator, type AllAPIRequestGenerator, type DeferredAPIRequestGenerator, type ExecutedGeneratorsResults } from "./generatorSupport.ts";
34
50
  // import {executeRequestGenerators, type ExecutedGeneratorsResults, type AnyAPIRequestGenerator} from "./generatorSupport.ts";
@@ -43,7 +59,8 @@ export class API {
43
59
  getCanonicalFileNameWorker;
44
60
  initialized = false;
45
61
  initializing;
46
- activeSnapshots = new Set();
62
+ activeSnapshots = new Map();
63
+ activeSourceFileLeases = new Map();
47
64
  printer;
48
65
  internal;
49
66
  constructor(options = {}) {
@@ -122,21 +139,55 @@ export class API {
122
139
  await this.ensureInitialized();
123
140
  return this.client.apiRequest("parseJsonConfigFileContent", { json, ...options });
124
141
  }
142
+ /**
143
+ * Create and retain a source file independently of a program.
144
+ * Dispose the returned lease when the source file no longer needs to remain available remotely.
145
+ */
125
146
  async createSourceFile(fileName, sourceText, options = {}) {
126
147
  await this.ensureInitialized();
127
148
  const data = await this.client.apiRequestBinary("createSourceFile", { fileName, sourceText, options });
128
149
  if (!data) {
129
150
  throw new Error("createSourceFile returned no source file");
130
151
  }
131
- return new RemoteSourceFile(data, this.decoder, this.client.getTimingCollector());
152
+ return this.retainSourceFileResponse(data);
132
153
  }
154
+ /**
155
+ * Read, create, and retain a source file independently of a program.
156
+ * Dispose the returned lease when the source file no longer needs to remain available remotely.
157
+ */
133
158
  async createSourceFileFromFile(file, options = {}) {
134
159
  await this.ensureInitialized();
135
160
  const data = await this.client.apiRequestBinary("createSourceFileFromFile", { fileName: resolveFileName(file), options });
136
161
  if (!data) {
137
162
  throw new Error("createSourceFileFromFile returned no source file");
138
163
  }
139
- return new RemoteSourceFile(data, this.decoder, this.client.getTimingCollector());
164
+ return this.retainSourceFileResponse(data);
165
+ }
166
+ retainSourceFileResponse(data) {
167
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
168
+ const lease = readSourceFileLease(view);
169
+ try {
170
+ const decoded = new RemoteSourceFile(data, this.decoder, this.client.getTimingCollector());
171
+ const sourceFile = this.sourceFileCache.setForLease(decoded.path, decoded, readParseOptionsKey(view), readSourceFileHash(view), lease);
172
+ const retained = new RetainedSourceFile(sourceFile, lease, this.client, () => {
173
+ this.activeSourceFileLeases.delete(lease);
174
+ this.sourceFileCache.releaseLease(lease);
175
+ });
176
+ this.activeSourceFileLeases.set(lease, retained);
177
+ return retained;
178
+ }
179
+ catch (error) {
180
+ // @sync-skip-block-start
181
+ void this.client.apiRequest("releaseSourceFile", { lease }).catch(() => { });
182
+ // @sync-skip-block-end
183
+ // @sync-only-start
184
+ // try {
185
+ // this.client.apiRequest("releaseSourceFile", { lease });
186
+ // }
187
+ // catch {}
188
+ // @sync-only-end
189
+ throw error;
190
+ }
140
191
  }
141
192
  async transpileModule(input, options = {}) {
142
193
  await this.ensureInitialized();
@@ -156,23 +207,23 @@ export class API {
156
207
  }
157
208
  async createSnapshot(params) {
158
209
  await this.ensureInitialized();
159
- const requestParams = toCreateSnapshotRequest(params);
210
+ const requestParams = toCreateSnapshotRequest(this.prepareCreateSnapshotParams(params));
160
211
  const data = await this.client.apiRequest("createSnapshot", requestParams);
161
212
  const snapshot = new Snapshot(data, this.client, this.sourceFileCache, this.toPath, this, () => {
162
- this.activeSnapshots.delete(snapshot);
213
+ this.activeSnapshots.delete(snapshot.id);
163
214
  this.sourceFileCache.releaseSnapshot(snapshot.id);
164
215
  }, this.createSnapshotUpdater(() => snapshot), undefined);
165
- this.activeSnapshots.add(snapshot);
216
+ this.activeSnapshots.set(snapshot.id, snapshot);
166
217
  return snapshot;
167
218
  }
168
219
  async updateSnapshot(baseSnapshot, params) {
169
220
  await this.ensureInitialized();
170
- if (!this.activeSnapshots.has(baseSnapshot) || baseSnapshot.isDisposed()) {
221
+ if (this.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed()) {
171
222
  throw new Error("Cannot update an inactive snapshot");
172
223
  }
173
224
  const data = await this.client.apiRequest("updateSnapshot", {
174
225
  snapshot: baseSnapshot.id,
175
- changes: toCreateSnapshotRequest(params),
226
+ changes: toCreateSnapshotRequest(this.prepareCreateSnapshotParams(params)),
176
227
  });
177
228
  if (data.snapshot === baseSnapshot.id) {
178
229
  await this.client.apiRequest("release", { snapshot: data.snapshot });
@@ -180,12 +231,37 @@ export class API {
180
231
  }
181
232
  this.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
182
233
  const snapshot = new Snapshot(data, this.client, this.sourceFileCache, this.toPath, this, () => {
183
- this.activeSnapshots.delete(snapshot);
234
+ this.activeSnapshots.delete(snapshot.id);
184
235
  this.sourceFileCache.releaseSnapshot(snapshot.id);
185
236
  }, this.createSnapshotUpdater(() => snapshot), baseSnapshot);
186
- this.activeSnapshots.add(snapshot);
237
+ this.activeSnapshots.set(snapshot.id, snapshot);
187
238
  return snapshot;
188
239
  }
240
+ prepareCreateSnapshotParams(params) {
241
+ if (!params)
242
+ return undefined;
243
+ const prepareOptions = (options) => {
244
+ if (!options)
245
+ return undefined;
246
+ const { moduleResolver, ...rest } = options;
247
+ moduleResolver?.ensureNotDisposed();
248
+ return {
249
+ ...rest,
250
+ moduleResolver: moduleResolver?.id,
251
+ };
252
+ };
253
+ return {
254
+ ...params,
255
+ createPrograms: params.createPrograms?.map(program => ({ ...program, options: prepareOptions(program.options) })),
256
+ reconfigurePrograms: params.reconfigurePrograms?.map(program => ({ ...program, options: prepareOptions(program.options) })),
257
+ };
258
+ }
259
+ prepareLanguageServerSnapshotChanges(changes) {
260
+ if (!changes)
261
+ return undefined;
262
+ const prepared = this.prepareCreateSnapshotParams(changes);
263
+ return prepared;
264
+ }
189
265
  createSnapshotUpdater(getSnapshot) {
190
266
  const update = params => this.updateSnapshot(getSnapshot(), params); // @sync: const update = ((params: CreateSnapshotParams) => this.updateSnapshot(getSnapshot(), params)) as SnapshotUpdater;
191
267
  // @sync-only-start
@@ -198,21 +274,21 @@ export class API {
198
274
  await this.ensureInitialized();
199
275
  const changes = args[0];
200
276
  const baseSnapshot = args[1];
201
- if (baseSnapshot && (!this.activeSnapshots.has(baseSnapshot) || baseSnapshot.isDisposed())) {
277
+ if (baseSnapshot && (this.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed())) {
202
278
  throw new Error("Cannot use an inactive snapshot as a response base");
203
279
  }
204
280
  const data = await this.client.apiRequest("getCurrentLanguageServerSnapshot", {
205
281
  baseSnapshot: baseSnapshot?.id,
206
- changes,
282
+ changes: this.prepareLanguageServerSnapshotChanges(changes),
207
283
  });
208
284
  if (baseSnapshot) {
209
285
  this.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
210
286
  }
211
287
  const snapshot = new Snapshot(data, this.client, this.sourceFileCache, this.toPath, this, () => {
212
- this.activeSnapshots.delete(snapshot);
288
+ this.activeSnapshots.delete(snapshot.id);
213
289
  this.sourceFileCache.releaseSnapshot(snapshot.id);
214
290
  }, this.createSnapshotUpdater(() => snapshot), baseSnapshot);
215
- this.activeSnapshots.add(snapshot);
291
+ this.activeSnapshots.set(snapshot.id, snapshot);
216
292
  return snapshot;
217
293
  }
218
294
  async [globalThis.Symbol.asyncDispose]() {
@@ -220,15 +296,39 @@ export class API {
220
296
  }
221
297
  async close() {
222
298
  await this.initializing?.catch(() => { }); // @sync-skip
223
- // Dispose all active snapshots
224
299
  try {
225
- for (const snapshot of [...this.activeSnapshots]) {
226
- await snapshot.dispose();
300
+ for (const retained of [...this.activeSourceFileLeases.values()]) {
301
+ await retained.dispose();
227
302
  }
228
- this.sourceFileCache.clear();
229
303
  }
230
304
  finally {
231
- await this.client.close(); // always close the underlying connection
305
+ try {
306
+ for (const snapshot of [...this.activeSnapshots.values()]) {
307
+ await snapshot.dispose();
308
+ }
309
+ this.sourceFileCache.clear();
310
+ }
311
+ finally {
312
+ await this.client.close(); // always close the underlying connection
313
+ }
314
+ }
315
+ }
316
+ async createModuleResolver(compilerOptions, options) {
317
+ await this.ensureInitialized();
318
+ const callback = options?.resolveModuleName
319
+ ? registerModuleResolutionCallback(this.client, options.resolveModuleName, id => this.activeSnapshots.get(id))
320
+ : undefined;
321
+ try {
322
+ const id = await this.client.apiRequest("createModuleResolver", {
323
+ compilerOptions,
324
+ moduleResolutions: options?.moduleResolutions,
325
+ resolveModuleNameCallback: callback?.name,
326
+ });
327
+ return new ModuleResolver(id, this.client, callback?.dispose);
328
+ }
329
+ catch (error) {
330
+ callback?.dispose();
331
+ throw error;
232
332
  }
233
333
  }
234
334
  clearSourceFileCache() {
@@ -236,7 +336,7 @@ export class API {
236
336
  }
237
337
  async runWithTemporaryFileUpdate(baseSnapshot, file, newText, cb) {
238
338
  await this.ensureInitialized();
239
- if (!this.activeSnapshots.has(baseSnapshot) || baseSnapshot.isDisposed()) {
339
+ if (this.activeSnapshots.get(baseSnapshot.id) !== baseSnapshot || baseSnapshot.isDisposed()) {
240
340
  throw new Error("Cannot run a temporary file update on an inactive snapshot");
241
341
  }
242
342
  const snapshot = await baseSnapshot.update({
@@ -286,6 +386,38 @@ export class API {
286
386
  return program;
287
387
  }
288
388
  }
389
+ /** An independently retained source file and its disposable remote-lifetime lease. */
390
+ export class RetainedSourceFile {
391
+ sourceFile;
392
+ lease;
393
+ client;
394
+ onDispose;
395
+ disposed = false;
396
+ disposePromise;
397
+ constructor(sourceFile, lease, client, onDispose) {
398
+ this.sourceFile = sourceFile;
399
+ this.lease = lease;
400
+ this.client = client;
401
+ this.onDispose = onDispose;
402
+ }
403
+ [globalThis.Symbol.asyncDispose]() {
404
+ return this.dispose(); // @sync: this.dispose();
405
+ }
406
+ dispose() {
407
+ return this.disposePromise ??= this.disposeWorker();
408
+ }
409
+ async disposeWorker() {
410
+ if (this.disposed)
411
+ return;
412
+ this.disposed = true;
413
+ try {
414
+ await this.client.apiRequest("releaseSourceFile", { lease: this.lease });
415
+ }
416
+ finally {
417
+ this.onDispose();
418
+ }
419
+ }
420
+ }
289
421
  export class InternalAPI {
290
422
  client;
291
423
  ensureInitialized;
@@ -421,6 +553,46 @@ export class Snapshot {
421
553
  return project;
422
554
  }
423
555
  }
556
+ export class ModuleResolver {
557
+ id;
558
+ client;
559
+ disposeCallback;
560
+ disposed = false;
561
+ constructor(id, client, disposeCallback) {
562
+ this.id = id;
563
+ this.client = client;
564
+ this.disposeCallback = disposeCallback;
565
+ }
566
+ async resolveModuleName(moduleName, containingDirectory, resolutionMode, options) {
567
+ this.ensureNotDisposed();
568
+ if (options?.snapshot instanceof Snapshot && options.snapshot.isDisposed()) {
569
+ throw new Error("Snapshot is disposed");
570
+ }
571
+ return this.client.apiRequest("resolveModuleName", {
572
+ snapshot: options?.snapshot instanceof Snapshot ? options.snapshot.id : undefined,
573
+ inProgressSnapshot: typeof options?.snapshot === "number" ? -options.snapshot : undefined,
574
+ resolver: this.id,
575
+ moduleName,
576
+ containingDirectory,
577
+ resolutionMode,
578
+ });
579
+ }
580
+ [globalThis.Symbol.asyncDispose]() {
581
+ return this.dispose();
582
+ }
583
+ async dispose() {
584
+ if (this.disposed)
585
+ return;
586
+ await this.client.apiRequest("releaseModuleResolver", { resolver: this.id });
587
+ this.disposed = true;
588
+ this.disposeCallback?.();
589
+ }
590
+ /** @internal */
591
+ ensureNotDisposed() {
592
+ if (this.disposed)
593
+ throw new Error("ModuleResolver is disposed");
594
+ }
595
+ }
424
596
  class SnapshotObjectRegistry {
425
597
  symbols = new Map();
426
598
  client;
@@ -1714,13 +1886,7 @@ export class Checker {
1714
1886
  } : undefined;
1715
1887
  }
1716
1888
  async getIndexTypeOfType(type, kind) {
1717
- const data = await this.client.apiRequest("getIndexTypeOfTypeByKind", {
1718
- snapshot: this.snapshotId,
1719
- project: this.project.id,
1720
- type: type.id,
1721
- kind,
1722
- });
1723
- return data ? this.objectRegistry.getOrCreateType(data) : undefined;
1889
+ return kind === IndexKind.String ? type.getStringIndexType() : type.getNumberIndexType();
1724
1890
  }
1725
1891
  async getTypeOfPropertyOfType(type, propertyName) {
1726
1892
  const data = await this.client.apiRequest("getTypeOfPropertyOfType", {
@@ -2165,6 +2331,7 @@ class TypeObject {
2165
2331
  constructSignatures;
2166
2332
  indexInfos;
2167
2333
  baseTypes;
2334
+ types;
2168
2335
  stringIndexType;
2169
2336
  numberIndexType;
2170
2337
  constructor(data, objectRegistry) {
@@ -2261,6 +2428,7 @@ class TypeObject {
2261
2428
  this.constructSignatures = false;
2262
2429
  this.indexInfos = false;
2263
2430
  this.baseTypes = false;
2431
+ this.types = false;
2264
2432
  this.stringIndexType = false;
2265
2433
  this.numberIndexType = false;
2266
2434
  }
@@ -2354,7 +2522,10 @@ class TypeObject {
2354
2522
  if (!(this.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral))) {
2355
2523
  return undefined;
2356
2524
  }
2357
- return this.objectRegistry.fetchTypes(this, "getTypesOfType");
2525
+ if (this.types === false) {
2526
+ this.types = await this.objectRegistry.fetchTypes(this, "getTypesOfType");
2527
+ }
2528
+ return this.types;
2358
2529
  }
2359
2530
  async getTypeParameters() {
2360
2531
  return this.objectRegistry.fetchTypes(this, "getTypeParametersOfType", this.typeParameters);