typescript 7.1.0-dev.20261001.1 → 7.1.0-dev.20261003.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 (118) hide show
  1. package/dist/api/async/api.d.ts +73 -42
  2. package/dist/api/async/api.d.ts.map +1 -1
  3. package/dist/api/async/api.js +224 -68
  4. package/dist/api/async/api.js.map +1 -1
  5. package/dist/api/async/client.d.ts.map +1 -1
  6. package/dist/api/async/client.js +73 -16
  7. package/dist/api/async/client.js.map +1 -1
  8. package/dist/api/async/types.d.ts +4 -3
  9. package/dist/api/async/types.d.ts.map +1 -1
  10. package/dist/api/compilerOptions.generated.d.ts +123 -0
  11. package/dist/api/compilerOptions.generated.d.ts.map +1 -0
  12. package/dist/api/compilerOptions.generated.js +8 -0
  13. package/dist/api/compilerOptions.generated.js.map +1 -0
  14. package/dist/api/diagnosticFormatter.d.ts.map +1 -1
  15. package/dist/api/diagnosticFormatter.js.map +1 -1
  16. package/dist/api/fs.d.ts +10 -8
  17. package/dist/api/fs.d.ts.map +1 -1
  18. package/dist/api/fs.js.map +1 -1
  19. package/dist/api/node/encoder.generated.js +1 -1
  20. package/dist/api/node/encoder.generated.js.map +1 -1
  21. package/dist/api/node/node.d.ts +18 -10
  22. package/dist/api/node/node.d.ts.map +1 -1
  23. package/dist/api/node/node.generated.js +1 -1
  24. package/dist/api/node/node.generated.js.map +1 -1
  25. package/dist/api/node/node.infrastructure.d.ts.map +1 -1
  26. package/dist/api/node/node.infrastructure.js.map +1 -1
  27. package/dist/api/node/node.js +39 -11
  28. package/dist/api/node/node.js.map +1 -1
  29. package/dist/api/path.d.ts +46 -9
  30. package/dist/api/path.d.ts.map +1 -1
  31. package/dist/api/path.js +365 -28
  32. package/dist/api/path.js.map +1 -1
  33. package/dist/api/prepareCompilerOptions.generated.d.ts +5 -0
  34. package/dist/api/prepareCompilerOptions.generated.d.ts.map +1 -0
  35. package/dist/api/prepareCompilerOptions.generated.js +24 -0
  36. package/dist/api/prepareCompilerOptions.generated.js.map +1 -0
  37. package/dist/api/proto.generated.d.ts +223 -172
  38. package/dist/api/proto.generated.d.ts.map +1 -1
  39. package/dist/api/proto.generated.js +3 -0
  40. package/dist/api/proto.generated.js.map +1 -1
  41. package/dist/api/sourceFileCache.d.ts +15 -9
  42. package/dist/api/sourceFileCache.d.ts.map +1 -1
  43. package/dist/api/sourceFileCache.js +30 -12
  44. package/dist/api/sourceFileCache.js.map +1 -1
  45. package/dist/api/sync/api.d.ts +101 -49
  46. package/dist/api/sync/api.d.ts.map +1 -1
  47. package/dist/api/sync/api.js +314 -86
  48. package/dist/api/sync/api.js.map +1 -1
  49. package/dist/api/sync/types.d.ts +4 -3
  50. package/dist/api/sync/types.d.ts.map +1 -1
  51. package/dist/api/typedPaths.d.ts +3 -0
  52. package/dist/api/typedPaths.d.ts.map +1 -0
  53. package/dist/api/typedPaths.js +2 -0
  54. package/dist/api/typedPaths.js.map +1 -0
  55. package/dist/ast/ast.d.ts +58 -7
  56. package/dist/ast/ast.d.ts.map +1 -1
  57. package/dist/ast/ast.generated.d.ts +3 -3
  58. package/dist/ast/ast.generated.d.ts.map +1 -1
  59. package/dist/ast/factory.generated.d.ts +2 -2
  60. package/dist/ast/factory.generated.d.ts.map +1 -1
  61. package/dist/ast/factory.generated.js.map +1 -1
  62. package/dist/ast/is.generated.d.ts.map +1 -1
  63. package/dist/ast/is.generated.js +2 -1
  64. package/dist/ast/is.generated.js.map +1 -1
  65. package/dist/ast/scanner.d.ts.map +1 -1
  66. package/dist/ast/scanner.js +1 -0
  67. package/dist/ast/scanner.js.map +1 -1
  68. package/dist/enums/caseSensitivity.d.ts +2 -0
  69. package/dist/enums/caseSensitivity.d.ts.map +1 -0
  70. package/dist/enums/caseSensitivity.enum.d.ts +5 -0
  71. package/dist/enums/caseSensitivity.enum.d.ts.map +1 -0
  72. package/dist/enums/caseSensitivity.enum.js +7 -0
  73. package/dist/enums/caseSensitivity.enum.js.map +1 -0
  74. package/dist/enums/caseSensitivity.js +7 -0
  75. package/dist/enums/caseSensitivity.js.map +1 -0
  76. package/dist/enums/jsxEmit.enum.js +1 -1
  77. package/dist/enums/jsxEmit.enum.js.map +1 -1
  78. package/dist/enums/jsxEmit.js +1 -1
  79. package/dist/enums/jsxEmit.js.map +1 -1
  80. package/dist/enums/moduleDetectionKind.enum.js +1 -1
  81. package/dist/enums/moduleDetectionKind.enum.js.map +1 -1
  82. package/dist/enums/moduleDetectionKind.js +1 -1
  83. package/dist/enums/moduleDetectionKind.js.map +1 -1
  84. package/dist/enums/moduleKind.enum.js +1 -1
  85. package/dist/enums/moduleKind.enum.js.map +1 -1
  86. package/dist/enums/moduleKind.js +1 -1
  87. package/dist/enums/moduleKind.js.map +1 -1
  88. package/dist/enums/moduleResolutionKind.enum.js +1 -1
  89. package/dist/enums/moduleResolutionKind.enum.js.map +1 -1
  90. package/dist/enums/moduleResolutionKind.js +1 -1
  91. package/dist/enums/moduleResolutionKind.js.map +1 -1
  92. package/dist/enums/newLineKind.enum.js +1 -1
  93. package/dist/enums/newLineKind.enum.js.map +1 -1
  94. package/dist/enums/newLineKind.js +1 -1
  95. package/dist/enums/newLineKind.js.map +1 -1
  96. package/dist/enums/scriptTarget.d.ts.map +1 -1
  97. package/dist/enums/scriptTarget.enum.d.ts.map +1 -1
  98. package/dist/enums/scriptTarget.enum.js +1 -0
  99. package/dist/enums/scriptTarget.enum.js.map +1 -1
  100. package/dist/enums/scriptTarget.js +1 -0
  101. package/dist/enums/scriptTarget.js.map +1 -1
  102. package/dist/enums/syntaxKind.enum.d.ts +198 -197
  103. package/dist/enums/syntaxKind.enum.d.ts.map +1 -1
  104. package/dist/enums/syntaxKind.enum.js +199 -198
  105. package/dist/enums/syntaxKind.enum.js.map +1 -1
  106. package/dist/enums/syntaxKind.js +199 -198
  107. package/dist/enums/syntaxKind.js.map +1 -1
  108. package/dist/vscode/extensionApi.d.ts +56 -0
  109. package/dist/vscode/extensionApi.d.ts.map +1 -0
  110. package/dist/vscode/extensionApi.js +2 -0
  111. package/dist/vscode/extensionApi.js.map +1 -0
  112. package/dist/vscode/protocol.generated.d.ts +2886 -0
  113. package/dist/vscode/protocol.generated.d.ts.map +1 -0
  114. package/dist/vscode/protocol.generated.js +4 -0
  115. package/dist/vscode/protocol.generated.js.map +1 -0
  116. package/package.json +16 -9
  117. package/schemas/jsconfig.schema.json +2207 -0
  118. package/schemas/tsconfig.schema.json +2206 -0
@@ -21,9 +21,10 @@ import { TypePredicateKind } from "#enums/typePredicateKind";
21
21
  import { ModifierFlags, unescapeLeadingUnderscores, } from "../../ast/index.js";
22
22
  import { assertNever } from "../../internal/utils.js";
23
23
  import { encodeNode, uint8ArrayToBase64, } from "../node/encoder.js";
24
- import { decodeNode, getNodeId, parseNodeHandle, readSourceFileLease, RemoteSourceFile, } from "../node/node.js";
24
+ import { decodeNode, getNodeId, parseNodeHandleFromCompiler, readParseOptionsKey, readSourceFileHash, readSourceFileLease, RemoteNode, RemoteSourceFile, } from "../node/node.js";
25
25
  import { Wtf8Decoder } from "../node/wtf8.js";
26
- import { createGetCanonicalFileName, toPath, } from "../path.js";
26
+ import { canonicalize, CaseSensitivity, pathKey, toRootedDirectoryPath, toRootedPath, } from "../path.js";
27
+ import { prepareCompilerOptions } from "../prepareCompilerOptions.generated.js";
27
28
  import { resolveFileName, toCreateSnapshotRequest, validateSymbolResponse, } from "../proto.js";
28
29
  import { SourceFileCache, } from "../sourceFileCache.js";
29
30
  import { Client, } from "./client.js";
@@ -52,12 +53,14 @@ function registerModuleResolutionCallback(client, callback, getSnapshot) {
52
53
  // import { sourceFileResponseToUint8Array } from "../node/encoder.ts";
53
54
  // @sync-only-end
54
55
  export class API {
56
+ /** @internal */
55
57
  client;
58
+ /** @internal */
56
59
  sourceFileCache;
57
60
  toPath;
58
- currentDirectory;
59
61
  decoder = new Wtf8Decoder();
60
- getCanonicalFileNameWorker;
62
+ currentDirectory;
63
+ caseSensitivity;
61
64
  initialized = false;
62
65
  initializing;
63
66
  activeSnapshots = new Map();
@@ -71,6 +74,52 @@ export class API {
71
74
  this.printer = new Printer(this.client);
72
75
  this.internal = new InternalAPI(this.client, () => this.ensureInitialized()); // @sync: this.internal = new InternalAPI(this.client, this.ensureInitialized);
73
76
  }
77
+ /**
78
+ * Looks up a remote declaration's binder symbol. Throws for synthesized or configuration ASTs.
79
+ */
80
+ async getSymbol(declaration) {
81
+ const file = getRemoteSourceFile(declaration);
82
+ if (!file)
83
+ throw new Error(`Source file not found for declaration`);
84
+ const record = file.symbolCache;
85
+ if (!record)
86
+ throw new Error(`Cached source file not found for declaration`);
87
+ const index = parseNodeHandleFromCompiler(getNodeId(declaration)).index;
88
+ const cached = record.symbolsByDeclarationNodeIndex.get(index);
89
+ if (cached)
90
+ return cached;
91
+ // @sync-only-start
92
+ // return this.fetchDeclarationSymbol(record, index);
93
+ // @sync-only-end
94
+ // @sync-skip-block-start
95
+ let request = record.declarationSymbolRequests.get(index);
96
+ if (!request) {
97
+ request = this.fetchDeclarationSymbol(record, index);
98
+ record.declarationSymbolRequests.set(index, request);
99
+ }
100
+ try {
101
+ return await request;
102
+ }
103
+ finally {
104
+ record.declarationSymbolRequests.delete(index);
105
+ }
106
+ // @sync-skip-block-end
107
+ }
108
+ async fetchDeclarationSymbol(record, index) {
109
+ const data = await this.client.apiRequest("getSymbolOfDeclaration", {
110
+ file: record.descriptor,
111
+ index,
112
+ });
113
+ validateSymbolResponse(data);
114
+ const reference = data.reference;
115
+ if (reference.kind !== SymbolOwnerKind.File) {
116
+ throw new Error(`Symbol ${reference.id} is not file-owned`);
117
+ }
118
+ const fileOwner = { record, api: this };
119
+ const symbol = this.sourceFileCache.getOrCreateSymbol(record, reference.file, reference.id, () => new Symbol(data, { kind: SymbolOwnerKind.File, owner: fileOwner }));
120
+ record.symbolsByDeclarationNodeIndex.set(index, symbol);
121
+ return symbol;
122
+ }
74
123
  /**
75
124
  * Create an API instance from an existing LSP connection's API session.
76
125
  * Use this when connecting to an API pipe provided by an LSP server via custom/initializeAPISession.
@@ -98,11 +147,9 @@ export class API {
98
147
  async initializeWorker() {
99
148
  try {
100
149
  const response = await this.client.apiRequest("initialize", null);
101
- const getCanonicalFileName = createGetCanonicalFileName(response.useCaseSensitiveFileNames);
102
- const currentDirectory = response.currentDirectory;
103
- this.getCanonicalFileNameWorker = getCanonicalFileName;
104
- this.currentDirectory = currentDirectory;
105
- this.toPath = (fileName) => toPath(fileName, currentDirectory, getCanonicalFileName);
150
+ this.currentDirectory = response.currentDirectory;
151
+ this.caseSensitivity = response.caseSensitivity;
152
+ this.toPath = (fileName, basePath = response.currentDirectory) => pathKey(toRootedPath(fileName, toRootedDirectoryPath(basePath, response.currentDirectory)), response.caseSensitivity);
106
153
  this.initialized = true;
107
154
  }
108
155
  catch (error) {
@@ -117,10 +164,13 @@ export class API {
117
164
  return this.currentDirectory;
118
165
  }
119
166
  getCanonicalFileName(fileName) {
120
- if (this.getCanonicalFileNameWorker === undefined) {
167
+ return canonicalize(fileName, this.getCaseSensitivity());
168
+ }
169
+ getCaseSensitivity() {
170
+ if (this.caseSensitivity === undefined) {
121
171
  throw new Error("API has not been initialized");
122
172
  }
123
- return this.getCanonicalFileNameWorker(fileName);
173
+ return this.caseSensitivity;
124
174
  }
125
175
  getNewLine() {
126
176
  return "\n";
@@ -130,6 +180,9 @@ export class API {
130
180
  const orchestratorResponse = await this.client.apiRequest("createBuildOrchestrator", {
131
181
  ...buildOrchestratorOptions,
132
182
  ...buildOrchestratorOptions.overrideCompilerOptions,
183
+ cwd: buildOrchestratorOptions.cwd === undefined
184
+ ? undefined
185
+ : toRootedDirectoryPath(buildOrchestratorOptions.cwd, this.getCurrentDirectory()),
133
186
  rootNames,
134
187
  });
135
188
  const orchestrator = new BuildOrchestrator(this.client, orchestratorResponse, () => {
@@ -197,7 +250,7 @@ export class API {
197
250
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
198
251
  const lease = readSourceFileLease(view);
199
252
  try {
200
- const decoded = new RemoteSourceFile(data, this.decoder, this.client.getTimingCollector());
253
+ const decoded = new RemoteSourceFile(data, this.decoder, this.client.getTimingCollector(), this);
201
254
  return this.addSourceFileLease(decoded, lease);
202
255
  }
203
256
  catch (error) {
@@ -215,7 +268,7 @@ export class API {
215
268
  }
216
269
  addSourceFileLease(sourceFile, lease) {
217
270
  const cached = this.sourceFileCache.setForLease(sourceFile, lease);
218
- const retained = new RetainedSourceFile(cached, lease, this.client, () => {
271
+ const retained = new RetainedSourceFile(cached, lease, () => {
219
272
  this.activeSourceFileLeases.delete(lease);
220
273
  this.sourceFileCache.releaseLease(lease);
221
274
  });
@@ -242,7 +295,7 @@ export class API {
242
295
  await this.ensureInitialized();
243
296
  const requestParams = toCreateSnapshotRequest(this.prepareCreateSnapshotParams(params));
244
297
  const data = await this.client.apiRequest("createSnapshot", requestParams);
245
- const snapshot = new Snapshot(data, this.client, this.sourceFileCache, this.toPath, this, () => {
298
+ const snapshot = new Snapshot(data, this.toPath, this, () => {
246
299
  this.activeSnapshots.delete(snapshot.id);
247
300
  this.sourceFileCache.releaseSnapshot(snapshot.id);
248
301
  }, this.createSnapshotUpdater(() => snapshot), undefined);
@@ -263,7 +316,7 @@ export class API {
263
316
  return baseSnapshot;
264
317
  }
265
318
  this.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
266
- const snapshot = new Snapshot(data, this.client, this.sourceFileCache, this.toPath, this, () => {
319
+ const snapshot = new Snapshot(data, this.toPath, this, () => {
267
320
  this.activeSnapshots.delete(snapshot.id);
268
321
  this.sourceFileCache.releaseSnapshot(snapshot.id);
269
322
  }, this.createSnapshotUpdater(() => snapshot), baseSnapshot);
@@ -276,11 +329,15 @@ export class API {
276
329
  const prepareOptions = (options) => {
277
330
  if (!options)
278
331
  return undefined;
279
- const { moduleResolver, ...rest } = options;
332
+ const { moduleResolver, projectReferences, ...rest } = options;
280
333
  moduleResolver?.ensureNotDisposed();
281
334
  return {
282
335
  ...rest,
283
336
  moduleResolver: moduleResolver?.id,
337
+ projectReferences: projectReferences?.map(reference => ({
338
+ ...reference,
339
+ path: toRootedPath(reference.path, this.getCurrentDirectory()),
340
+ })),
284
341
  };
285
342
  };
286
343
  return {
@@ -317,7 +374,7 @@ export class API {
317
374
  if (baseSnapshot) {
318
375
  this.sourceFileCache.retainForSnapshot(data.snapshot, baseSnapshot.id, data.changes);
319
376
  }
320
- const snapshot = new Snapshot(data, this.client, this.sourceFileCache, this.toPath, this, () => {
377
+ const snapshot = new Snapshot(data, this.toPath, this, () => {
321
378
  this.activeSnapshots.delete(snapshot.id);
322
379
  this.sourceFileCache.releaseSnapshot(snapshot.id);
323
380
  }, this.createSnapshotUpdater(() => snapshot), baseSnapshot);
@@ -356,7 +413,7 @@ export class API {
356
413
  : undefined;
357
414
  try {
358
415
  const id = await this.client.apiRequest("createModuleResolver", {
359
- compilerOptions,
416
+ compilerOptions: prepareCompilerOptions(compilerOptions, this.getCurrentDirectory()),
360
417
  moduleResolutions: options?.moduleResolutions,
361
418
  resolveModuleNameCallback: callback?.name,
362
419
  });
@@ -432,18 +489,47 @@ function sourceFileDescriptor(sourceFile) {
432
489
  nodeId: sourceFile.nodeId,
433
490
  };
434
491
  }
492
+ function getRemoteSourceFile(node) {
493
+ if (!(node instanceof RemoteNode))
494
+ return undefined;
495
+ const file = node.getSourceFile();
496
+ return file instanceof RemoteSourceFile && file.api ? file : undefined;
497
+ }
498
+ function getNodeAPI(node) {
499
+ const api = getRemoteSourceFile(node)?.api;
500
+ if (!api)
501
+ return undefined;
502
+ if (!(api instanceof API))
503
+ throw new Error("Source file does not belong to the async API"); // @sync: if (!(api instanceof API)) throw new Error("Source file does not belong to the sync API");
504
+ return api;
505
+ }
506
+ /** Looks up a remote declaration's binder symbol through its API. Throws for non-remote declarations. */
507
+ export async function getSymbol(declaration) {
508
+ const api = getNodeAPI(declaration);
509
+ if (!api)
510
+ throw new Error("Source file not found for declaration");
511
+ return api.getSymbol(declaration);
512
+ }
513
+ // @sync-only-start
514
+ // export declare namespace getSymbol {
515
+ // function gen(declaration: Declaration): Generator<ProtocolRequest, Symbol, ProtocolResponse["result"]>;
516
+ // }
517
+ // getSymbol.gen = function* (declaration: Declaration): Generator<ProtocolRequest, Symbol, ProtocolResponse["result"]> {
518
+ // const api = getNodeAPI(declaration);
519
+ // if (!api) throw new Error("Source file not found for declaration");
520
+ // return yield* api.getSymbol.gen(declaration);
521
+ // };
522
+ // @sync-only-end
435
523
  /** An independently retained source file and its disposable remote-lifetime lease. */
436
524
  export class RetainedSourceFile {
437
525
  sourceFile;
438
526
  lease;
439
- client;
440
527
  onDispose;
441
528
  disposed = false;
442
529
  disposePromise;
443
- constructor(sourceFile, lease, client, onDispose) {
530
+ constructor(sourceFile, lease, onDispose) {
444
531
  this.sourceFile = sourceFile;
445
532
  this.lease = lease;
446
- this.client = client;
447
533
  this.onDispose = onDispose;
448
534
  }
449
535
  [globalThis.Symbol.asyncDispose]() {
@@ -455,9 +541,12 @@ export class RetainedSourceFile {
455
541
  async disposeWorker() {
456
542
  if (this.disposed)
457
543
  return;
544
+ const api = getNodeAPI(this.sourceFile);
545
+ if (!api)
546
+ throw new Error("Retained source file has no owning API");
458
547
  this.disposed = true;
459
548
  try {
460
- await this.client.apiRequest("releaseSourceFile", { lease: this.lease });
549
+ await api.client.apiRequest("releaseSourceFile", { lease: this.lease });
461
550
  }
462
551
  finally {
463
552
  this.onDispose();
@@ -492,7 +581,7 @@ export class Snapshot {
492
581
  operation;
493
582
  projectMap;
494
583
  toPath;
495
- client;
584
+ api;
496
585
  disposed = false;
497
586
  disposePromise;
498
587
  onDispose;
@@ -500,9 +589,12 @@ export class Snapshot {
500
589
  projectDataMap;
501
590
  updateSnapshot;
502
591
  internal;
503
- constructor(data, client, sourceFileCache, toPath, formatDiagnosticsHost, onDispose, updateSnapshot, baseSnapshot) {
592
+ get client() {
593
+ return this.api.client;
594
+ }
595
+ constructor(data, toPath, api, onDispose, updateSnapshot, baseSnapshot) {
504
596
  this.id = data.snapshot;
505
- this.client = client;
597
+ this.api = api;
506
598
  this.toPath = toPath;
507
599
  this.onDispose = onDispose;
508
600
  this.updateSnapshot = updateSnapshot;
@@ -517,14 +609,14 @@ export class Snapshot {
517
609
  this.projectDataMap = new Map([...projectDataMap].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
518
610
  this.snapshotRegistry = new SnapshotObjectRegistry(this.id);
519
611
  for (const projData of this.projectDataMap.values()) {
520
- const project = new Project(projData, this.id, client, sourceFileCache, toPath, formatDiagnosticsHost, this.snapshotRegistry);
612
+ const project = new Project(projData, this.id, toPath, api, this.snapshotRegistry);
521
613
  this.projectMap.set(projData.id, project);
522
614
  }
523
615
  this.operation = {
524
616
  createdPrograms: data.operation.createdPrograms?.map(projectId => this.requireProject(projectId).program),
525
617
  openedFiles: data.operation.openedFiles?.map(result => ({ project: this.requireProject(result.project) })),
526
618
  };
527
- this.internal = new SnapshotInternalAPI(this.id, client);
619
+ this.internal = new SnapshotInternalAPI(this.id, api.client);
528
620
  }
529
621
  getProjects() {
530
622
  this.ensureNotDisposed();
@@ -532,7 +624,8 @@ export class Snapshot {
532
624
  }
533
625
  getConfiguredProject(configFileName) {
534
626
  this.ensureNotDisposed();
535
- return this.projectMap.get(this.toPath(configFileName));
627
+ const id = this.toPath(configFileName);
628
+ return this.projectMap.get(id);
536
629
  }
537
630
  getProject(projectId) {
538
631
  this.ensureNotDisposed();
@@ -674,20 +767,22 @@ class SnapshotObjectRegistry {
674
767
  }
675
768
  }
676
769
  class ProjectObjectRegistry {
677
- client;
678
770
  snapshotId;
679
771
  project;
680
772
  snapshotRegistry;
681
- sourceFileCache;
682
773
  types = new Map();
683
774
  signatures = new Map();
684
775
  disposed = false;
685
- constructor(client, snapshotId, project, snapshotRegistry, sourceFileCache) {
686
- this.client = client;
776
+ get client() {
777
+ return this.project.api.client;
778
+ }
779
+ get sourceFileCache() {
780
+ return this.project.api.sourceFileCache;
781
+ }
782
+ constructor(snapshotId, project, snapshotRegistry) {
687
783
  this.snapshotId = snapshotId;
688
784
  this.project = project;
689
785
  this.snapshotRegistry = snapshotRegistry;
690
- this.sourceFileCache = sourceFileCache;
691
786
  snapshotRegistry.addProjectRegistry(this);
692
787
  }
693
788
  getOrCreateSymbol(data) {
@@ -700,7 +795,7 @@ class ProjectObjectRegistry {
700
795
  const record = this.sourceFileCache.getOrCreateRecord(reference.file, this.snapshotId, this.project.id);
701
796
  return this.sourceFileCache.getOrCreateSymbol(record, reference.file, reference.id, () => new Symbol(data, {
702
797
  kind: SymbolOwnerKind.File,
703
- owner: { record, cache: this.sourceFileCache, client: this.client },
798
+ owner: { record, api: this.project.api },
704
799
  }));
705
800
  }
706
801
  /** Find an already-interned symbol and retain its file record for this registry. */
@@ -710,7 +805,7 @@ class ProjectObjectRegistry {
710
805
  return this.snapshotRegistry.getSymbol(reference.id);
711
806
  }
712
807
  const record = this.sourceFileCache.findRecord(reference.file);
713
- const symbol = record?.symbols.get(reference.id);
808
+ const symbol = record?.symbolsById.get(reference.id);
714
809
  if (record && symbol) {
715
810
  this.sourceFileCache.retainRecord(record, this.snapshotId, this.project.id);
716
811
  }
@@ -926,6 +1021,8 @@ class ProjectObjectRegistry {
926
1021
  }
927
1022
  }
928
1023
  export class Project {
1024
+ /** @internal */
1025
+ api;
929
1026
  id;
930
1027
  configFileName;
931
1028
  currentDirectory;
@@ -938,10 +1035,10 @@ export class Project {
938
1035
  program;
939
1036
  checker;
940
1037
  languageService;
941
- client;
942
1038
  snapshotId;
943
- constructor(data, snapshotId, client, sourceFileCache, toPath, formatDiagnosticsHost, snapshotRegistry) {
1039
+ constructor(data, snapshotId, toPath, api, snapshotRegistry) {
944
1040
  this.id = data.id;
1041
+ this.api = api;
945
1042
  this.configFileName = data.configFileName;
946
1043
  this.currentDirectory = data.currentDirectory;
947
1044
  this.dirty = data.dirty;
@@ -951,12 +1048,11 @@ export class Project {
951
1048
  this.parsedCommandLine = data.parsedCommandLine;
952
1049
  this.compilerOptions = this.parsedCommandLine.options;
953
1050
  this.rootFiles = this.parsedCommandLine.fileNames;
954
- this.client = client;
955
1051
  this.snapshotId = snapshotId;
956
- this.program = new Program(snapshotId, this, client, sourceFileCache, toPath, formatDiagnosticsHost);
957
- const objectRegistry = new ProjectObjectRegistry(client, snapshotId, this, snapshotRegistry, sourceFileCache);
958
- this.checker = new Checker(snapshotId, this, client, objectRegistry);
959
- this.languageService = new LanguageService(snapshotId, this, client, objectRegistry);
1052
+ this.program = new Program(snapshotId, this, toPath);
1053
+ const objectRegistry = new ProjectObjectRegistry(snapshotId, this, snapshotRegistry);
1054
+ this.checker = new Checker(snapshotId, this, objectRegistry);
1055
+ this.languageService = new LanguageService(snapshotId, this, objectRegistry);
960
1056
  }
961
1057
  /** @deprecated Use `languageService.getImportAdderEdits`. */
962
1058
  getImportAdderEdits(file, actions) {
@@ -973,12 +1069,13 @@ export class Project {
973
1069
  export class LanguageService {
974
1070
  snapshotId;
975
1071
  project;
976
- client;
977
1072
  objectRegistry;
978
- constructor(snapshotId, project, client, objectRegistry) {
1073
+ get client() {
1074
+ return this.project.api.client;
1075
+ }
1076
+ constructor(snapshotId, project, objectRegistry) {
979
1077
  this.snapshotId = snapshotId;
980
1078
  this.project = project;
981
- this.client = client;
982
1079
  this.objectRegistry = objectRegistry;
983
1080
  }
984
1081
  async getImportAdderEdits(file, actions) {
@@ -1069,28 +1166,28 @@ export class Program {
1069
1166
  snapshotId;
1070
1167
  id;
1071
1168
  project;
1072
- client;
1073
- sourceFileCache;
1074
1169
  toPath;
1075
- formatDiagnosticsHost;
1076
1170
  decoder = new Wtf8Decoder();
1077
1171
  sourceFileMetadataCache = new Map();
1078
1172
  ownedSnapshot;
1079
1173
  disposePromise;
1080
- constructor(snapshotId, project, client, sourceFileCache, toPath, formatDiagnosticsHost) {
1174
+ get client() {
1175
+ return this.project.api.client;
1176
+ }
1177
+ get sourceFileCache() {
1178
+ return this.project.api.sourceFileCache;
1179
+ }
1180
+ constructor(snapshotId, project, toPath) {
1081
1181
  this.snapshotId = snapshotId;
1082
1182
  this.id = project.id;
1083
1183
  this.project = project;
1084
- this.client = client;
1085
- this.sourceFileCache = sourceFileCache;
1086
1184
  this.toPath = toPath;
1087
- this.formatDiagnosticsHost = formatDiagnosticsHost;
1088
1185
  }
1089
1186
  getCurrentDirectory() {
1090
1187
  return this.project.currentDirectory;
1091
1188
  }
1092
1189
  getCanonicalFileName(fileName) {
1093
- return this.formatDiagnosticsHost.getCanonicalFileName(fileName);
1190
+ return this.project.api.getCanonicalFileName(fileName);
1094
1191
  }
1095
1192
  getNewLine() {
1096
1193
  return this.project.compilerOptions.newLine === NewLineKind.CRLF ? "\r\n" : "\n";
@@ -1116,7 +1213,20 @@ export class Program {
1116
1213
  }
1117
1214
  async getSourceFile(file) {
1118
1215
  const fileName = resolveFileName(file);
1119
- const path = this.toPath(fileName);
1216
+ const path = this.pathKeyForFileName(fileName);
1217
+ return this.getSourceFileWorker(file, path);
1218
+ }
1219
+ /**
1220
+ * Returns the source file for an already-canonical path.
1221
+ *
1222
+ * @internal
1223
+ */
1224
+ getSourceFileByPath(path) {
1225
+ // The wire format is a string, but the cache key remains the supplied
1226
+ // PathKey and is never treated as a RootedPath.
1227
+ return this.getSourceFileWorker(path, path);
1228
+ }
1229
+ async getSourceFileWorker(file, path) {
1120
1230
  // Check if we already have a retained cache entry for this (snapshot, project) pair
1121
1231
  const retained = this.sourceFileCache.getRetained(path, this.snapshotId, this.project.id);
1122
1232
  if (retained) {
@@ -1132,7 +1242,7 @@ export class Program {
1132
1242
  return undefined;
1133
1243
  }
1134
1244
  // Create a new RemoteSourceFile and cache it (set returns existing if hash matches)
1135
- const decoded = new RemoteSourceFile(binaryData, this.decoder, this.client.getTimingCollector());
1245
+ const decoded = new RemoteSourceFile(binaryData, this.decoder, this.client.getTimingCollector(), this.project.api);
1136
1246
  return this.sourceFileCache.set(decoded, this.snapshotId, this.project.id);
1137
1247
  }
1138
1248
  async getResolvedModule(file, moduleName, mode) {
@@ -1203,7 +1313,7 @@ export class Program {
1203
1313
  * `Program` instance.
1204
1314
  */
1205
1315
  getSourceFileMetadata(file) {
1206
- return this.getSourceFileMetadataByPath(this.toPath(resolveFileName(file)));
1316
+ return this.getSourceFileMetadataByPath(this.pathKeyForFileName(resolveFileName(file)));
1207
1317
  }
1208
1318
  /**
1209
1319
  * Returns program-stored metadata for the source file at the given path, or `undefined`
@@ -1220,6 +1330,8 @@ export class Program {
1220
1330
  return metadata;
1221
1331
  }
1222
1332
  async fetchSourceFileMetadata(path) {
1333
+ // PathKey is serialized as a string; the server deliberately treats all
1334
+ // client-provided path text as untrusted input.
1223
1335
  const data = await this.client.apiRequest("getSourceFileMetadata", {
1224
1336
  snapshot: this.snapshotId,
1225
1337
  project: this.project.id,
@@ -1227,6 +1339,9 @@ export class Program {
1227
1339
  });
1228
1340
  return data ?? undefined;
1229
1341
  }
1342
+ pathKeyForFileName(fileName) {
1343
+ return this.toPath(fileName, this.project.currentDirectory);
1344
+ }
1230
1345
  /**
1231
1346
  * Returns whether the given source file was loaded as part of an external library
1232
1347
  * (e.g. a dependency resolved from `node_modules`). The underlying program metadata is
@@ -1269,7 +1384,7 @@ export class Program {
1269
1384
  if (!binaryData) {
1270
1385
  return undefined;
1271
1386
  }
1272
- return new RemoteSourceFile(binaryData, this.decoder);
1387
+ return new RemoteSourceFile(binaryData, this.decoder, undefined, this.project.api);
1273
1388
  }
1274
1389
  /**
1275
1390
  * Get syntactic (parse) diagnostics for specific files or all files.
@@ -1522,19 +1637,60 @@ function toEmitOutput(response) {
1522
1637
  export class Checker {
1523
1638
  snapshotId;
1524
1639
  project;
1525
- client;
1526
1640
  objectRegistry;
1527
1641
  wellKnownSymbols;
1528
1642
  wellKnownSignatures;
1529
- constructor(snapshotId, project, client, objectRegistry) {
1643
+ get client() {
1644
+ return this.project.api.client;
1645
+ }
1646
+ constructor(snapshotId, project, objectRegistry) {
1530
1647
  this.snapshotId = snapshotId;
1531
1648
  this.project = project;
1532
- this.client = client;
1533
1649
  this.objectRegistry = objectRegistry;
1534
1650
  }
1535
1651
  dispose() {
1536
1652
  this.objectRegistry.clear();
1537
1653
  }
1654
+ /** Get the merged symbol, or the original symbol if it has not been merged. */
1655
+ async getMergedSymbol(symbol) {
1656
+ const data = await this.client.apiRequest("getMergedSymbol", {
1657
+ snapshot: this.snapshotId,
1658
+ project: this.project.id,
1659
+ symbol: symbol.reference,
1660
+ });
1661
+ return this.objectRegistry.getOrCreateSymbol(data);
1662
+ }
1663
+ /**
1664
+ * Get a node's merged symbol. For a declaration, prefer
1665
+ * {@link Checker.getSymbolOfDeclaration} for a non-nullable result.
1666
+ */
1667
+ async getSymbolOfNode(node) {
1668
+ const data = await this.client.apiRequest("getSymbolOfNode", {
1669
+ snapshot: this.snapshotId,
1670
+ project: this.project.id,
1671
+ location: getNodeId(node),
1672
+ });
1673
+ return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
1674
+ }
1675
+ /** Get a declaration's merged symbol. */
1676
+ async getSymbolOfDeclaration(node) {
1677
+ const data = await this.client.apiRequest("getSymbolOfDeclarationForChecker", {
1678
+ snapshot: this.snapshotId,
1679
+ project: this.project.id,
1680
+ location: getNodeId(node),
1681
+ });
1682
+ // Declarations normally have symbols, but preserve unexpected null results at runtime.
1683
+ return (data && this.objectRegistry.getOrCreateSymbol(data));
1684
+ }
1685
+ /** Get a symbol's merged parent, if any. */
1686
+ async getParentOfSymbol(symbol) {
1687
+ const data = await this.client.apiRequest("getParentOfSymbolForChecker", {
1688
+ snapshot: this.snapshotId,
1689
+ project: this.project.id,
1690
+ symbol: symbol.reference,
1691
+ });
1692
+ return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined;
1693
+ }
1538
1694
  async getSymbolAtLocation(nodeOrNodes) {
1539
1695
  if (Array.isArray(nodeOrNodes)) {
1540
1696
  const data = await this.client.apiRequest("getSymbolsAtLocations", {
@@ -2326,7 +2482,7 @@ export class NodeHandle {
2326
2482
  kind;
2327
2483
  path;
2328
2484
  constructor(handle, canonicalProject, fileOwner) {
2329
- const parsed = parseNodeHandle(handle);
2485
+ const parsed = parseNodeHandleFromCompiler(handle);
2330
2486
  this.index = parsed.index;
2331
2487
  this.kind = parsed.kind;
2332
2488
  this.path = parsed.path;
@@ -2346,17 +2502,17 @@ export class NodeHandle {
2346
2502
  }
2347
2503
  if (!project)
2348
2504
  throw new Error(`Node handle for '${this.path}' has no project context`);
2349
- const sourceFile = await project.program.getSourceFile(this.path);
2505
+ const sourceFile = await project.program.getSourceFileByPath(this.path);
2350
2506
  if (!sourceFile) {
2351
2507
  return undefined;
2352
2508
  }
2353
2509
  return sourceFile.getOrCreateNodeAtIndex(this.index);
2354
2510
  }
2355
2511
  async fetchOwnerFile(fileOwner) {
2356
- const data = await fileOwner.client.apiRequestBinary("getCachedSourceFile", { file: fileOwner.record.descriptor });
2512
+ const data = await fileOwner.api.client.apiRequestBinary("getCachedSourceFile", { file: fileOwner.record.descriptor });
2357
2513
  if (!data)
2358
2514
  throw new Error(`Source file '${fileOwner.record.descriptor.fileName}' is not available`);
2359
- return fileOwner.cache.attachFile(fileOwner.record, new RemoteSourceFile(data, new Wtf8Decoder(), fileOwner.client.getTimingCollector()));
2515
+ return fileOwner.api.sourceFileCache.attachFile(fileOwner.record, new RemoteSourceFile(data, new Wtf8Decoder(), fileOwner.api.client.getTimingCollector(), fileOwner.api));
2360
2516
  }
2361
2517
  }
2362
2518
  export class Symbol {
@@ -2443,10 +2599,10 @@ export class Symbol {
2443
2599
  }
2444
2600
  const fileOwner = this.storage.owner;
2445
2601
  // A file-owned symbol's relationships are always owned by the same file.
2446
- const cached = reference.file === fileOwner.record.descriptor.nodeId ? fileOwner.record.symbols.get(reference.id) : undefined;
2602
+ const cached = reference.file === fileOwner.record.descriptor.nodeId ? fileOwner.record.symbolsById.get(reference.id) : undefined;
2447
2603
  if (cached)
2448
2604
  return cached;
2449
- const data = await fileOwner.client.apiRequest(method, { symbol: this.reference });
2605
+ const data = await fileOwner.api.client.apiRequest(method, { symbol: this.reference });
2450
2606
  if (!data)
2451
2607
  throw new Error(`${method} returned null symbol for Symbol ${this.id}`);
2452
2608
  return this.internFileSymbol(fileOwner, data);
@@ -2456,7 +2612,7 @@ export class Symbol {
2456
2612
  return this.storage.registry.fetchSymbols(this, method);
2457
2613
  }
2458
2614
  const fileOwner = this.storage.owner;
2459
- const data = await fileOwner.client.apiRequest(method, { symbol: this.reference });
2615
+ const data = await fileOwner.api.client.apiRequest(method, { symbol: this.reference });
2460
2616
  return data?.map(symbol => this.internFileSymbol(fileOwner, symbol)) ?? [];
2461
2617
  }
2462
2618
  internFileSymbol(fileOwner, data) {
@@ -2464,7 +2620,7 @@ export class Symbol {
2464
2620
  const reference = data.reference;
2465
2621
  if (reference.kind !== SymbolOwnerKind.File)
2466
2622
  throw new Error(`Symbol ${reference.id} is not file-owned`);
2467
- return fileOwner.cache.getOrCreateSymbol(fileOwner.record, reference.file, reference.id, () => new Symbol(data, { kind: SymbolOwnerKind.File, owner: fileOwner }));
2623
+ return fileOwner.api.sourceFileCache.getOrCreateSymbol(fileOwner.record, reference.file, reference.id, () => new Symbol(data, { kind: SymbolOwnerKind.File, owner: fileOwner }));
2468
2624
  }
2469
2625
  }
2470
2626
  class TypeObject {