@zzzen/pyright-internal 1.2.0-dev.20260705 → 1.2.0-dev.20260712

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 (94) hide show
  1. package/dist/tests/typeServer/inProcTypeServerTestUtils.d.ts +39 -0
  2. package/dist/tests/typeServer/inProcTypeServerTestUtils.js +366 -0
  3. package/dist/tests/typeServer/inProcTypeServerTestUtils.js.map +1 -0
  4. package/dist/tests/typeServer/notebook.typeServer.test.d.ts +1 -0
  5. package/dist/tests/typeServer/notebook.typeServer.test.js +315 -0
  6. package/dist/tests/typeServer/notebook.typeServer.test.js.map +1 -0
  7. package/dist/tests/typeServer/typeServer.inProc.test.d.ts +1 -0
  8. package/dist/tests/typeServer/typeServer.inProc.test.js +234 -0
  9. package/dist/tests/typeServer/typeServer.inProc.test.js.map +1 -0
  10. package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.d.ts +1 -0
  11. package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.js +298 -0
  12. package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.js.map +1 -0
  13. package/dist/typeServer/cancellation.d.ts +5 -0
  14. package/dist/typeServer/cancellation.js +14 -0
  15. package/dist/typeServer/cancellation.js.map +1 -0
  16. package/dist/typeServer/diagnosticUtils.d.ts +4 -0
  17. package/dist/typeServer/diagnosticUtils.js +71 -0
  18. package/dist/typeServer/diagnosticUtils.js.map +1 -0
  19. package/dist/typeServer/enums.d.ts +14 -0
  20. package/dist/typeServer/enums.js +524 -0
  21. package/dist/typeServer/enums.js.map +1 -0
  22. package/dist/typeServer/eventEmitter.d.ts +12 -0
  23. package/dist/typeServer/eventEmitter.js +32 -0
  24. package/dist/typeServer/eventEmitter.js.map +1 -0
  25. package/dist/typeServer/nodeMain.d.ts +1 -0
  26. package/dist/typeServer/nodeMain.js +65 -0
  27. package/dist/typeServer/nodeMain.js.map +1 -0
  28. package/dist/typeServer/notebookCellChain.d.ts +34 -0
  29. package/dist/typeServer/notebookCellChain.js +182 -0
  30. package/dist/typeServer/notebookCellChain.js.map +1 -0
  31. package/dist/typeServer/notebookDocumentHandler.d.ts +23 -0
  32. package/dist/typeServer/notebookDocumentHandler.js +158 -0
  33. package/dist/typeServer/notebookDocumentHandler.js.map +1 -0
  34. package/dist/typeServer/notebookUriMapper.d.ts +39 -0
  35. package/dist/typeServer/notebookUriMapper.js +164 -0
  36. package/dist/typeServer/notebookUriMapper.js.map +1 -0
  37. package/dist/typeServer/profilingStub.d.ts +10 -0
  38. package/dist/typeServer/profilingStub.js +12 -0
  39. package/dist/typeServer/profilingStub.js.map +1 -0
  40. package/dist/typeServer/programTypes.d.ts +136 -0
  41. package/dist/typeServer/programTypes.js +3 -0
  42. package/dist/typeServer/programTypes.js.map +1 -0
  43. package/dist/typeServer/programWrapper.d.ts +134 -0
  44. package/dist/typeServer/programWrapper.js +731 -0
  45. package/dist/typeServer/programWrapper.js.map +1 -0
  46. package/dist/typeServer/protocol/tspSupplemental.d.ts +43 -0
  47. package/dist/typeServer/protocol/tspSupplemental.js +48 -0
  48. package/dist/typeServer/protocol/tspSupplemental.js.map +1 -0
  49. package/dist/typeServer/protocol/typeServerProtocol.d.ts +1102 -0
  50. package/dist/typeServer/protocol/typeServerProtocol.js +290 -0
  51. package/dist/typeServer/protocol/typeServerProtocol.js.map +1 -0
  52. package/dist/typeServer/server.d.ts +54 -0
  53. package/dist/typeServer/server.js +620 -0
  54. package/dist/typeServer/server.js.map +1 -0
  55. package/dist/typeServer/serverUtils.d.ts +4 -0
  56. package/dist/typeServer/serverUtils.js +21 -0
  57. package/dist/typeServer/serverUtils.js.map +1 -0
  58. package/dist/typeServer/stubGenerator.d.ts +42 -0
  59. package/dist/typeServer/stubGenerator.js +895 -0
  60. package/dist/typeServer/stubGenerator.js.map +1 -0
  61. package/dist/typeServer/typeCache.d.ts +31 -0
  62. package/dist/typeServer/typeCache.js +54 -0
  63. package/dist/typeServer/typeCache.js.map +1 -0
  64. package/dist/typeServer/typeEvalUtils.d.ts +13 -0
  65. package/dist/typeServer/typeEvalUtils.js +83 -0
  66. package/dist/typeServer/typeEvalUtils.js.map +1 -0
  67. package/dist/typeServer/typeGuards.d.ts +3 -0
  68. package/dist/typeServer/typeGuards.js +55 -0
  69. package/dist/typeServer/typeGuards.js.map +1 -0
  70. package/dist/typeServer/typeServerConversionTypes.d.ts +39 -0
  71. package/dist/typeServer/typeServerConversionTypes.js +448 -0
  72. package/dist/typeServer/typeServerConversionTypes.js.map +1 -0
  73. package/dist/typeServer/typeServerConversionUtils.d.ts +35 -0
  74. package/dist/typeServer/typeServerConversionUtils.js +524 -0
  75. package/dist/typeServer/typeServerConversionUtils.js.map +1 -0
  76. package/dist/typeServer/typeServerEvaluator.d.ts +16 -0
  77. package/dist/typeServer/typeServerEvaluator.js +36 -0
  78. package/dist/typeServer/typeServerEvaluator.js.map +1 -0
  79. package/dist/typeServer/typeServerFileSystem.d.ts +47 -0
  80. package/dist/typeServer/typeServerFileSystem.js +129 -0
  81. package/dist/typeServer/typeServerFileSystem.js.map +1 -0
  82. package/dist/typeServer/typeServerProtocolUtils.d.ts +2 -0
  83. package/dist/typeServer/typeServerProtocolUtils.js +7 -0
  84. package/dist/typeServer/typeServerProtocolUtils.js.map +1 -0
  85. package/dist/typeServer/typeServerServiceKeys.d.ts +7 -0
  86. package/dist/typeServer/typeServerServiceKeys.js +20 -0
  87. package/dist/typeServer/typeServerServiceKeys.js.map +1 -0
  88. package/dist/typeServer/typeUtils.d.ts +4 -0
  89. package/dist/typeServer/typeUtils.js +31 -0
  90. package/dist/typeServer/typeUtils.js.map +1 -0
  91. package/dist/typeServer/virtualFileOverlayFileSystem.d.ts +87 -0
  92. package/dist/typeServer/virtualFileOverlayFileSystem.js +181 -0
  93. package/dist/typeServer/virtualFileOverlayFileSystem.js.map +1 -0
  94. package/package.json +1 -1
@@ -0,0 +1,731 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProgramWrapper = void 0;
4
+ exports.makeProgram = makeProgram;
5
+ const analyzerNodeInfo_1 = require("../analyzer/analyzerNodeInfo");
6
+ const parseTreeUtils_1 = require("../analyzer/parseTreeUtils");
7
+ const scopeUtils_1 = require("../analyzer/scopeUtils");
8
+ const sourceFile_1 = require("../analyzer/sourceFile");
9
+ const typeEvaluatorTypes_1 = require("../analyzer/typeEvaluatorTypes");
10
+ const types_1 = require("../analyzer/types");
11
+ const debug_1 = require("../common/debug");
12
+ const uri_1 = require("../common/uri/uri");
13
+ const uriMap_1 = require("../common/uri/uriMap");
14
+ const uriUtils_1 = require("../common/uri/uriUtils");
15
+ const parseNodes_1 = require("../parser/parseNodes");
16
+ const typeServerEvaluator_1 = require("./typeServerEvaluator");
17
+ const typeEvalUtils_1 = require("./typeEvalUtils");
18
+ const diagnosticUtils_1 = require("./diagnosticUtils");
19
+ const typeServerConversionTypes_1 = require("./typeServerConversionTypes");
20
+ const typeServerServiceKeys_1 = require("./typeServerServiceKeys");
21
+ const typeServerConversionUtils_1 = require("./typeServerConversionUtils");
22
+ const cancellation_1 = require("./cancellation");
23
+ const typeCache_1 = require("./typeCache");
24
+ /**
25
+ * Adapter that lets the in-proc Pyright `Program` (which is mutable and has no
26
+ * native snapshot concept) satisfy the `IProgram` contract the type server's
27
+ * conversion layer is written against.
28
+ *
29
+ * - `run` runs the callback over the live `Program` via `_program.run(...)`.
30
+ * Because Pyright's evaluator is synchronous the callback executes atomically,
31
+ * so it simply receives `this` — there is no copy-on-write snapshot view.
32
+ * - A monotonic `snapshot` counter (on the shared `ITypeCache`) is bumped by the
33
+ * mutating methods below. It is a protocol-level content version: the server
34
+ * hands it to clients via `typeServer/getSnapshot`, rejects stale requests at
35
+ * the request boundary, and fires `SnapshotChangedNotification` on change.
36
+ * - Cross-request state (`_declTypeCache`, `_protocolDeclCache`, `_addedStubs`, …)
37
+ * lives on the wrapper, not on the `Program`, which has nowhere to put it, and
38
+ * is invalidated when the snapshot increments.
39
+ */
40
+ class ProgramWrapper {
41
+ constructor(_program, _cache) {
42
+ this._program = _program;
43
+ this._cache = _cache;
44
+ this._declTypeCache = new WeakMap();
45
+ this._protocolDeclCache = new Map();
46
+ this._disableSnapshotIncrement = false;
47
+ this._addedStubs = new uriMap_1.UriMap();
48
+ this._inEditMode = false;
49
+ // Overwrite a bunch of the program's methods so we can update the snapshot.
50
+ const originalSetFileOpened = this._program.setFileOpened.bind(this._program);
51
+ this._program.setFileOpened = (fileUri, version, contents, options) => {
52
+ originalSetFileOpened(fileUri, version, contents, options);
53
+ this._incrementSnapshot();
54
+ };
55
+ const originalSetFileClosed = this._program.setFileClosed.bind(this._program);
56
+ this._program.setFileClosed = (fileUri) => {
57
+ const result = originalSetFileClosed(fileUri);
58
+ this._incrementSnapshot();
59
+ return result;
60
+ };
61
+ const originalUpdateChainedUri = this._program.updateChainedUri.bind(this._program);
62
+ this._program.updateChainedUri = (fileUri, chainedFileUri) => {
63
+ originalUpdateChainedUri(fileUri, chainedFileUri);
64
+ this._incrementSnapshot();
65
+ };
66
+ const originalMarkFilesDirty = this._program.markFilesDirty.bind(this._program);
67
+ this._program.markFilesDirty = (fileUris, evenIfContentsAreSame) => {
68
+ originalMarkFilesDirty(fileUris, evenIfContentsAreSame);
69
+ this._incrementSnapshot();
70
+ };
71
+ const originalMarkAllFilesDirty = this._program.markAllFilesDirty.bind(this._program);
72
+ this._program.markAllFilesDirty = (evenIfContentsAreSame) => {
73
+ originalMarkAllFilesDirty(evenIfContentsAreSame);
74
+ this._incrementSnapshot();
75
+ };
76
+ const originalSetConfigOptions = this._program.setConfigOptions.bind(this._program);
77
+ this._program.setConfigOptions = (configOptions) => {
78
+ originalSetConfigOptions(configOptions);
79
+ this._cachedSearchPaths = undefined;
80
+ this._incrementSnapshot();
81
+ };
82
+ const originalSetImportResolver = this._program.setImportResolver.bind(this._program);
83
+ this._program.setImportResolver = (importResolver) => {
84
+ originalSetImportResolver(importResolver);
85
+ this._cachedSearchPaths = undefined;
86
+ this._incrementSnapshot();
87
+ };
88
+ }
89
+ get id() {
90
+ return this._program.id;
91
+ }
92
+ get typeCache() {
93
+ return this._cache;
94
+ }
95
+ get rootPath() {
96
+ return this._program.rootPath;
97
+ }
98
+ get console() {
99
+ return this._program.console;
100
+ }
101
+ get configOptions() {
102
+ return this._program.configOptions;
103
+ }
104
+ get fs() {
105
+ return this._program.fileSystem;
106
+ }
107
+ get fileSystem() {
108
+ return this._program.fileSystem;
109
+ }
110
+ get serviceProvider() {
111
+ return this._program.serviceProvider;
112
+ }
113
+ get uriMapper() {
114
+ return this._program.serviceProvider.tryGet(typeServerServiceKeys_1.TypeServerServiceKeys.uriMapper);
115
+ }
116
+ get isAlive() {
117
+ return true;
118
+ }
119
+ get isPyright() {
120
+ return true;
121
+ }
122
+ get performsAnalysis() {
123
+ return true;
124
+ }
125
+ get supportsPullDiagnostics() {
126
+ return true;
127
+ }
128
+ get symbolLookup() {
129
+ const symbolLookup = {
130
+ getFileInfo: (node) => {
131
+ // Ensure the file is bound before reading AnalyzerInfo off the node.
132
+ // Without this, nodes from files that haven't been bound yet (e.g.
133
+ // freshly-discovered modules during a code-action request) return
134
+ // undefined fileInfo and crash downstream readers.
135
+ const fileUri = this._cache.getUri(node);
136
+ this._program.getBoundSourceFileInfo(fileUri);
137
+ return (0, analyzerNodeInfo_1.getFileInfo)(node);
138
+ },
139
+ getImportInfo: (node) => {
140
+ return (0, analyzerNodeInfo_1.getImportInfo)(node);
141
+ },
142
+ getDeclaration: (node) => {
143
+ return (0, analyzerNodeInfo_1.getDeclaration)(node);
144
+ },
145
+ getFlowNode: (node) => {
146
+ return (0, analyzerNodeInfo_1.getFlowNode)(node);
147
+ },
148
+ getScope(node) {
149
+ return (0, analyzerNodeInfo_1.getScope)(node);
150
+ },
151
+ getScopeIdForNode(node) {
152
+ return (0, parseTreeUtils_1.getScopeIdForNode)(node);
153
+ },
154
+ getDunderAllInfo(node) {
155
+ return (0, analyzerNodeInfo_1.getDunderAllInfo)(node);
156
+ },
157
+ getSymbolsForFile: (fileUri, skipFileNeededCheck = false) => {
158
+ // The underlying sync `Program` has only one version of any file, and there is
159
+ // no snapshot view to pin to. Callers expect this to return a symbol table even
160
+ // if the file hasn't been analyzed yet, so ensure the file is present and bound.
161
+ this._program.addInterimFile(fileUri);
162
+ this._program.getBoundSourceFileInfo(fileUri, undefined, skipFileNeededCheck);
163
+ return this._program.getModuleSymbolTable(fileUri);
164
+ },
165
+ getSymbolsForNode: (node) => {
166
+ const scope = (0, scopeUtils_1.getScopeForNode)(node);
167
+ return scope?.symbolTable;
168
+ },
169
+ lookupSymbol: (scopingNode, name, _skipFileNeededCheck) => {
170
+ return (0, typeEvalUtils_1.getSymbolFromScope)(scopingNode, name);
171
+ },
172
+ getMatchingFileInfos: (fileId) => {
173
+ const parseTrees = this._program
174
+ .getSourceFileInfoList()
175
+ .map((f) => f.sourceFile.getParseResults()?.parserOutput.parseTree)
176
+ .filter((t) => !!t);
177
+ const fileInfos = parseTrees.map((p) => (0, analyzerNodeInfo_1.getFileInfo)(p)).filter((f) => f.fileId === fileId);
178
+ return fileInfos;
179
+ },
180
+ };
181
+ return symbolLookup;
182
+ }
183
+ runEditMode(callback, token) {
184
+ let results = [];
185
+ if (this._inEditMode) {
186
+ throw new cancellation_1.ServerCanceledException();
187
+ }
188
+ this._inEditMode = true;
189
+ this._program.enterEditMode();
190
+ try {
191
+ this._program.evaluator?.runWithCancellationToken(token, () => callback(this));
192
+ }
193
+ finally {
194
+ results = this._program.exitEditMode();
195
+ this._inEditMode = false;
196
+ }
197
+ return results;
198
+ }
199
+ enterEditMode() {
200
+ this._program.enterEditMode();
201
+ }
202
+ exitEditMode() {
203
+ return this._program.exitEditMode();
204
+ }
205
+ run(callback, token) {
206
+ return this._program.run(() => callback(this), token);
207
+ }
208
+ createEvaluator() {
209
+ return (0, typeServerEvaluator_1.createTypeServerEvaluator)(this._program, this.symbolLookup);
210
+ }
211
+ getCachedTypeForDeclaration(decl) {
212
+ return this._declTypeCache.get(decl.node);
213
+ }
214
+ setCachedTypeForDeclaration(decl, type) {
215
+ this._declTypeCache.set(decl.node, type);
216
+ }
217
+ getCachedProtocolDecl(tspDecl) {
218
+ return this._protocolDeclCache.get((0, typeServerConversionTypes_1.getProtocolDeclKey)(tspDecl));
219
+ }
220
+ setCachedProtocolDecl(tspDecl, decl) {
221
+ this._protocolDeclCache.set((0, typeServerConversionTypes_1.getProtocolDeclKey)(tspDecl), decl);
222
+ }
223
+ getSourceMapper(fileUri, mapCompiled, preferStubs, token) {
224
+ const sourceMapper = this._program.getSourceMapper(fileUri, token, mapCompiled, preferStubs);
225
+ const wrapper = {
226
+ findDeclarations: (decl) => {
227
+ return sourceMapper ? sourceMapper.findDeclarations(decl) : [];
228
+ },
229
+ findDeclarationsByType: (originatedPath, type, useTypeAlias) => {
230
+ return sourceMapper ? sourceMapper.findDeclarationsByType(originatedPath, type, useTypeAlias) : [];
231
+ },
232
+ findClassDeclarationsByType: (uri, type) => {
233
+ return sourceMapper ? sourceMapper.findClassDeclarationsByType(uri, type) : [];
234
+ },
235
+ findFunctionDeclarations: (decl) => {
236
+ return sourceMapper ? sourceMapper.findFunctionDeclarations(decl) : [];
237
+ },
238
+ getSourcePathsFromStub: (stubUri, fromFile) => {
239
+ return sourceMapper ? sourceMapper.getSourcePathsFromStub(stubUri, fromFile) : [];
240
+ },
241
+ getModuleNode: (uri) => {
242
+ return sourceMapper ? sourceMapper.getModuleNode(uri) : undefined;
243
+ },
244
+ findModules: (stubFile) => {
245
+ return sourceMapper ? sourceMapper.findModules(stubFile) : [];
246
+ },
247
+ getFileInfo: (node) => {
248
+ // Ensure the file is bound before reading AnalyzerInfo off the node.
249
+ const fileUri = this._cache.getUri(node);
250
+ this._program.getBoundSourceFileInfo(fileUri);
251
+ return (0, analyzerNodeInfo_1.getFileInfo)(node);
252
+ },
253
+ };
254
+ return wrapper;
255
+ }
256
+ getUri(node) {
257
+ return this._cache.getUri(node);
258
+ }
259
+ isCaseSensitive(uri) {
260
+ return this._cache.isCaseSensitive(uri);
261
+ }
262
+ /**
263
+ * Ensures the file is analyzed and the evaluator's prefetched type cache is warmed up.
264
+ * This avoids expensive re-evaluation when the cache is cold (e.g., first request for a file
265
+ * that imports large libraries).
266
+ */
267
+ ensureFileAnalyzed(fileUri, token) {
268
+ const sourceFile = this._program.getSourceFile(fileUri);
269
+ if (!sourceFile) {
270
+ return;
271
+ }
272
+ // Analyze the file if needed
273
+ this._program.analyzeFile(fileUri, token);
274
+ // Warm up the evaluator's prefetched type cache by calling getType on the first expression.
275
+ // This triggers initializePrefetchedTypes which caches built-in types like object, bool, int, etc.
276
+ // Without this, the first call to getExpectedType/getType would be slow.
277
+ const parserOutput = this._program.getParserOutput(fileUri);
278
+ if (parserOutput?.parseTree) {
279
+ this._program.run((p) => {
280
+ // Find the first expression node in the parse tree
281
+ const firstExpr = (0, typeServerConversionUtils_1.findFirstExpression)(parserOutput.parseTree);
282
+ if (firstExpr) {
283
+ // This will trigger initializePrefetchedTypes
284
+ p.evaluator?.getType(firstExpr);
285
+ }
286
+ }, token);
287
+ }
288
+ }
289
+ getComputedType(arg, token) {
290
+ const result = this._program.run((p) => {
291
+ if ((0, typeEvalUtils_1.isDeclaration)(arg)) {
292
+ return (0, typeEvalUtils_1.getEffectiveTypeOfDeclaration)(p.evaluator, arg);
293
+ }
294
+ if ((0, parseNodes_1.isExpressionNode)(arg)) {
295
+ return p.evaluator?.getType(arg);
296
+ }
297
+ return undefined;
298
+ }, token);
299
+ // Massage the result to ensure compatibility with the protocol.
300
+ return this._massageTypeResult(result);
301
+ }
302
+ getExpectedType(arg, token) {
303
+ const result = this._program.run((p) => {
304
+ if ((0, typeEvalUtils_1.isDeclaration)(arg)) {
305
+ const type = p.evaluator?.getTypeForDeclaration(arg)?.type;
306
+ return type
307
+ ? {
308
+ type,
309
+ node: arg.node,
310
+ candidates: [],
311
+ }
312
+ : undefined;
313
+ }
314
+ if ((0, parseNodes_1.isExpressionNode)(arg)) {
315
+ return p.evaluator?.getExpectedType(arg);
316
+ }
317
+ return undefined;
318
+ }, token);
319
+ return this._massageExpectedTypeResult(result);
320
+ }
321
+ getDeclaredType(arg, token) {
322
+ const result = this._program.run((p) => {
323
+ if ((0, typeEvalUtils_1.isDeclaration)(arg)) {
324
+ return p.evaluator?.getTypeForDeclaration(arg)?.type;
325
+ }
326
+ if ((0, parseNodes_1.isExpressionNode)(arg)) {
327
+ return p.evaluator?.getType(arg);
328
+ }
329
+ return undefined;
330
+ }, token);
331
+ // Massage the result to ensure compatibility with the protocol.
332
+ return this._massageTypeResult(result);
333
+ }
334
+ startProfiling() {
335
+ const localProfiler = this.serviceProvider.tryGet(typeServerServiceKeys_1.TypeServerServiceKeys.profilingService);
336
+ return localProfiler?.startProfiling();
337
+ }
338
+ stopProfiling() {
339
+ const localProfiler = this.serviceProvider.tryGet(typeServerServiceKeys_1.TypeServerServiceKeys.profilingService);
340
+ return localProfiler?.stopProfiling();
341
+ }
342
+ startWorkspaceDiagnostics(partialResultToken) {
343
+ // No-op for internal program
344
+ }
345
+ stopWorkspaceDiagnostics() {
346
+ // No-op for internal program
347
+ }
348
+ getPythonSearchPaths(token) {
349
+ const execEnv = this._getExecEnv(this._program.rootPath);
350
+ if (!this._cachedSearchPaths) {
351
+ this._cachedSearchPaths = this._program.importResolver.getImportRoots(execEnv);
352
+ }
353
+ return this._cachedSearchPaths;
354
+ }
355
+ lookupImport(fileUriOrModule, options) {
356
+ return this._program.lookUpImport(fileUriOrModule, options);
357
+ }
358
+ owns(uri) {
359
+ return this._program.owns(uri);
360
+ }
361
+ getParserOutput(fileUri) {
362
+ let results = this._program.getParserOutput(fileUri);
363
+ if (!results) {
364
+ // Try making an interim file instead.
365
+ if (this.fileSystem.existsSync(fileUri)) {
366
+ this._program.addInterimFile(fileUri);
367
+ results = this._program.getParserOutput(fileUri);
368
+ }
369
+ }
370
+ return results;
371
+ }
372
+ getParseResults(fileUri) {
373
+ let results = this._program.getParseResults(fileUri);
374
+ if (!results) {
375
+ // Try making an interim file instead.
376
+ if (this.fileSystem.existsSync(fileUri)) {
377
+ this._program.addInterimFile(fileUri);
378
+ results = this._program.getParseResults(fileUri);
379
+ }
380
+ }
381
+ if (!results) {
382
+ return undefined;
383
+ }
384
+ // Sync `ProgramView.getParseResults` returns the upstream `ParseFileResults`; the
385
+ // type server's `ParseResults` adds `moduleName` and `uri`. Synthesize them so the
386
+ // wrapper satisfies the shared `IProgram` contract used by snapshot-aware callers.
387
+ return {
388
+ ...results,
389
+ moduleName: this.getModuleName(fileUri) ?? '',
390
+ uri: fileUri,
391
+ };
392
+ }
393
+ addStubCode(code, directoryUri) {
394
+ // Generate a unique stub URI
395
+ // If directoryUri is provided, create the stub in that directory so imports resolve correctly
396
+ const stubFileName = `__stub_${Date.now()}_${Math.random().toString(36).substring(7)}.pyi`;
397
+ const stubUri = directoryUri
398
+ ? directoryUri.resolvePaths(stubFileName)
399
+ : uri_1.Uri.file(`/${stubFileName}`, this.serviceProvider);
400
+ // Disable snapshot increment while adding stub files since they're dynamically generated
401
+ // and don't invalidate existing type analysis
402
+ this._disableSnapshotIncrement = true;
403
+ try {
404
+ // Add as an interim file to the underlying program
405
+ // This allows the program to parse and track the file
406
+ this._program.setFileOpened(stubUri, 0, code, {
407
+ ipythonMode: sourceFile_1.IPythonMode.None,
408
+ chainedFileUri: undefined,
409
+ isVirtual: true,
410
+ });
411
+ this._program.addInterimFile(stubUri);
412
+ // Get the parse results from the program
413
+ const parseResults = this._program.getParseResults(stubUri);
414
+ if (!parseResults) {
415
+ throw new Error('Failed to parse stub code');
416
+ }
417
+ this._addedStubs.set(stubUri, true);
418
+ return {
419
+ uri: stubUri,
420
+ parseResults: { ...parseResults, moduleName: this.getModuleName(stubUri) ?? '', uri: stubUri },
421
+ };
422
+ }
423
+ finally {
424
+ this._disableSnapshotIncrement = false;
425
+ }
426
+ }
427
+ getModuleName(fileUri) {
428
+ // Use the import resolver to get the module name, matching the sync Program._getModuleName() behavior.
429
+ // This ensures proper module name resolution for operations like rename module.
430
+ // If this looks like a directory path (no extension or ends with __init__), determine the target file.
431
+ // We don't require the file/directory to exist - the import resolver computes module names from paths.
432
+ let targetUri = fileUri;
433
+ // Check if it's an existing directory
434
+ if (this._program.fileSystem.existsSync(fileUri) && !(0, uriUtils_1.isFile)(this._program.fileSystem, fileUri)) {
435
+ // It's an existing directory - look for __init__.pyi first, then __init__.py
436
+ let initFile = fileUri.initPyiUri;
437
+ if (!this._program.fileSystem.existsSync(initFile)) {
438
+ initFile = fileUri.initPyUri;
439
+ if (!this._program.fileSystem.existsSync(initFile)) {
440
+ // No __init__ file found, can't determine module name for this package
441
+ return undefined;
442
+ }
443
+ }
444
+ targetUri = initFile;
445
+ }
446
+ else if (!this._program.fileSystem.existsSync(fileUri)) {
447
+ // File doesn't exist yet (e.g., new file path for rename/move)
448
+ // The import resolver can still compute the module name from the path
449
+ // For directories being created, assume __init__.py will be created
450
+ const ext = fileUri.lastExtension;
451
+ if (!ext) {
452
+ // No extension suggests it's a directory - use __init__.py path for module name
453
+ targetUri = fileUri.initPyUri;
454
+ }
455
+ // Otherwise, use the file path as-is
456
+ }
457
+ const execEnv = this._program.configOptions.findExecEnvironment(targetUri);
458
+ const moduleNameAndType = this._program.importResolver.getModuleNameForImport(targetUri, execEnv,
459
+ /* allowIllegalModuleName */ true,
460
+ /* detectPyTyped */ true);
461
+ return moduleNameAndType.moduleName || undefined;
462
+ }
463
+ getSourceFileInfo(fileUri) {
464
+ const result = this._program.getSourceFileInfo(fileUri);
465
+ if (result) {
466
+ return this._makeSourceFileInfo(result);
467
+ }
468
+ return undefined;
469
+ }
470
+ hasSourceFile(fileUri) {
471
+ // Sync `Program.getSourceFileInfo` does not lazily materialize, so a
472
+ // simple existence check is safe.
473
+ return !!this._program.getSourceFileInfo(fileUri);
474
+ }
475
+ getTrackedFileList() {
476
+ return this._program.getSourceFileInfoList().map((s) => this._makeSourceFileInfo(s));
477
+ }
478
+ updateFileContents(uri, newContents) {
479
+ let fileInfo = this._program.getSourceFileInfo(uri);
480
+ if (!fileInfo) {
481
+ fileInfo = this._program.addInterimFile(uri);
482
+ }
483
+ if (fileInfo) {
484
+ const version = fileInfo.clientVersion || 0;
485
+ const chainedFileUri = fileInfo ? fileInfo.chainedSourceFile?.uri : undefined;
486
+ const ipythonMode = fileInfo ? fileInfo.ipythonMode : sourceFile_1.IPythonMode.None;
487
+ this._program.setFileOpened(uri, version + 1, newContents, { chainedFileUri, ipythonMode });
488
+ }
489
+ }
490
+ addTrackedFile(uri, isThirdPartyImport, isInPyTypedPackage) {
491
+ this._program.addTrackedFile(uri, isThirdPartyImport, isInPyTypedPackage);
492
+ }
493
+ setTrackedFiles(uris) {
494
+ this._program.setTrackedFiles(uris);
495
+ }
496
+ handleMemoryHighUsage() {
497
+ this._program.handleMemoryHighUsage();
498
+ }
499
+ getSnapshot(token) {
500
+ return this._cache.snapshot;
501
+ }
502
+ getDocumentDiagnostics(uri, previousResultId, token) {
503
+ const sourceFile = this._program.getSourceFile(uri);
504
+ if (sourceFile) {
505
+ // Analyze the file if it needs to be analyzed
506
+ if (sourceFile.isCheckingRequired() || sourceFile.isBindingRequired()) {
507
+ this._program.analyzeFile(uri, token);
508
+ }
509
+ }
510
+ const parseResults = this._program.getParseResults(uri);
511
+ let diagnostics = [];
512
+ let versionStr = undefined;
513
+ if (sourceFile && parseResults) {
514
+ const range = {
515
+ start: { line: 0, character: 0 },
516
+ end: { line: parseResults.tokenizerOutput.lines.count, character: 0 },
517
+ };
518
+ diagnostics = this._program
519
+ .getDiagnosticsForRange(uri, range)
520
+ .map((d) => (0, diagnosticUtils_1.convertFromPyrightDiagnostic)(d, this._program.fileSystem, true, true) || d);
521
+ versionStr = sourceFile.getDiagnosticVersion().toString();
522
+ }
523
+ return { kind: 'full', resultId: versionStr, items: diagnostics };
524
+ }
525
+ resolveImport(source, moduleDescriptor, token) {
526
+ const realModuleDescriptor = {
527
+ ...moduleDescriptor,
528
+ importedSymbols: new Set(),
529
+ };
530
+ const results = this._program.importResolver.resolveImport(source, this._getExecEnv(source), realModuleDescriptor);
531
+ const uris = results.resolvedUris.filter((uri) => uri !== undefined && !uri.isEmpty());
532
+ if (uris && results.isImportFound) {
533
+ // Make sure to pick the last one. It's the most specific.
534
+ return uris[uris.length - 1];
535
+ }
536
+ return undefined;
537
+ }
538
+ changedWatchedFiles(changes) {
539
+ // Not necessary for the normal program.
540
+ }
541
+ addInterimFile(uri) {
542
+ this._program.addInterimFile(uri);
543
+ return this;
544
+ }
545
+ dispose() {
546
+ // Don't dispose of the program. The caller is responsible for that.
547
+ }
548
+ _massageTypeResult(result) {
549
+ // For function types, make sure we inferred the return type if not
550
+ // already.
551
+ if (result && (0, types_1.isFunctionOrOverloaded)(result)) {
552
+ this._program.evaluator?.inferReturnTypeIfNecessary(result);
553
+ }
554
+ // Temporary problem. If this is a class, the protocol compatibility
555
+ // map stores Pyright types in it. Remove it.
556
+ if (result && (0, types_1.isClass)(result) && result.shared.protocolCompatibility) {
557
+ result = { ...result, shared: { ...result.shared, protocolCompatibility: undefined } };
558
+ }
559
+ // Remove all cached values. They need to be recomputed on the client side.
560
+ if (result && result.cached) {
561
+ result = { ...result, cached: undefined };
562
+ }
563
+ return result;
564
+ }
565
+ _massageExpectedTypeResult(result) {
566
+ if (!result) {
567
+ return undefined;
568
+ }
569
+ const type = this._massageTypeResult(result.type);
570
+ if (!type) {
571
+ return undefined;
572
+ }
573
+ const candidates = result.candidates
574
+ .map((candidate) => this._massageTypeResult(candidate))
575
+ .filter((candidate) => !!candidate);
576
+ return {
577
+ type,
578
+ node: result.node,
579
+ candidates: (0, typeEvaluatorTypes_1.ensureExpectedTypeCandidates)(type, candidates),
580
+ };
581
+ }
582
+ _makeSourceFileInfo(s) {
583
+ // Create an anonymous class that wraps a SourceFileInfo and provides the ISourceFileInfo interface
584
+ return new (class {
585
+ constructor(_parentWrapper, _s) {
586
+ this._parentWrapper = _parentWrapper;
587
+ this._s = _s;
588
+ this._makeSourceFileInfo = (sf) => {
589
+ return this._parentWrapper._makeSourceFileInfo(sf);
590
+ };
591
+ }
592
+ // Implement all properties from SourceFileInfo as getters
593
+ get uri() {
594
+ return this._s.uri;
595
+ }
596
+ get contents() {
597
+ return this._s.contents;
598
+ }
599
+ get ipythonMode() {
600
+ return this._s.ipythonMode;
601
+ }
602
+ get isTypeshedFile() {
603
+ return this._s.isTypeshedFile;
604
+ }
605
+ get isThirdPartyImport() {
606
+ return this._s.isThirdPartyImport;
607
+ }
608
+ get isThirdPartyPyTypedPresent() {
609
+ return this._s.isThirdPartyPyTypedPresent;
610
+ }
611
+ get isTypingStubFile() {
612
+ return this._s.isTypingStubFile;
613
+ }
614
+ get hasTypeAnnotations() {
615
+ return this._s.hasTypeAnnotations;
616
+ }
617
+ get diagnosticsVersion() {
618
+ return this._s.diagnosticsVersion;
619
+ }
620
+ get semanticVersion() {
621
+ return this._s.semanticVersion;
622
+ }
623
+ get clientVersion() {
624
+ return this._s.clientVersion;
625
+ }
626
+ get chainedSourceFile() {
627
+ return this._s.chainedSourceFile;
628
+ }
629
+ get isTracked() {
630
+ return this._s.isTracked;
631
+ }
632
+ get isOpenByClient() {
633
+ return this._s.isOpenByClient;
634
+ }
635
+ get isVirtual() {
636
+ return this._s.isVirtual;
637
+ }
638
+ get imports() {
639
+ return this._s.imports;
640
+ }
641
+ get areImportsComputed() {
642
+ return true;
643
+ }
644
+ get importedBy() {
645
+ return this._s.importedBy;
646
+ }
647
+ get shadows() {
648
+ return this._s.shadows;
649
+ }
650
+ get shadowedBy() {
651
+ return this._s.shadowedBy;
652
+ }
653
+ getImports() {
654
+ return s.imports.map(this._makeSourceFileInfo);
655
+ }
656
+ getImportedBy() {
657
+ return s.importedBy.map(this._makeSourceFileInfo);
658
+ }
659
+ getImplicitImport() {
660
+ if (s.builtinsImport === s) {
661
+ return undefined;
662
+ }
663
+ if (s.chainedSourceFile && !s.chainedSourceFile.sourceFile.isFileDeleted()) {
664
+ return this._makeSourceFileInfo(s.chainedSourceFile);
665
+ }
666
+ return s.builtinsImport ? this._makeSourceFileInfo(s.builtinsImport) : undefined;
667
+ }
668
+ getBuiltinsImport() {
669
+ return s.builtinsImport ? this._makeSourceFileInfo(s.builtinsImport) : undefined;
670
+ }
671
+ // Binding-specialized methods: in the wrapper path, imports are always
672
+ // synchronously available so these delegate to the full-import versions.
673
+ getBuiltinsImportForBinding() {
674
+ return this.getBuiltinsImport();
675
+ }
676
+ getImplicitImportForBinding() {
677
+ return this.getImplicitImport();
678
+ }
679
+ })(this, s);
680
+ }
681
+ _incrementSnapshot() {
682
+ if (this._disableSnapshotIncrement) {
683
+ return;
684
+ }
685
+ this._cache.incrementSnapshot();
686
+ this._cachedSearchPaths = undefined;
687
+ // Drop the declaration→Type cache; entries are tied to parse-tree
688
+ // nodes that may be replaced by re-parsed source files.
689
+ this._declTypeCache = new WeakMap();
690
+ // Drop the protocol-declaration cache; the resolved Pyright Declaration
691
+ // it points to may reference parse nodes that no longer exist.
692
+ this._protocolDeclCache = new Map();
693
+ // Remove all added stubs from our tracking map
694
+ this._disableSnapshotIncrement = true;
695
+ try {
696
+ this._addedStubs.forEach((_, uri) => {
697
+ this._program.setFileClosed(uri);
698
+ });
699
+ this._addedStubs.clear();
700
+ }
701
+ finally {
702
+ this._disableSnapshotIncrement = false;
703
+ }
704
+ }
705
+ _getExecEnv(uri) {
706
+ const env = this._program.configOptions
707
+ .getExecutionEnvironments()
708
+ .find((env) => env.root && (env.root.equals(uri) || uri.isChild(env.root)));
709
+ return env ?? this._program.configOptions.getDefaultExecEnvironment();
710
+ }
711
+ }
712
+ exports.ProgramWrapper = ProgramWrapper;
713
+ const programWrappers = new WeakMap();
714
+ function makeProgram(program, cache) {
715
+ // Cache the wrapper for the program. This lets us avoid creating multiple wrappers for the
716
+ // same program and use the same wrapper as the key into other maps.
717
+ let wrapper = programWrappers.get(program);
718
+ if (!wrapper) {
719
+ wrapper = new ProgramWrapper(program, cache ?? new typeCache_1.TypeCache(program.serviceProvider, (uri) => program.getParserOutput(uri)));
720
+ programWrappers.set(program, wrapper);
721
+ }
722
+ else if (cache && wrapper instanceof ProgramWrapper && wrapper.typeCache !== cache) {
723
+ // Enforce the snapshot invariant: a program must not be re-wrapped with a different
724
+ // type cache. If it were, `server._onGetSnapshot()` (which reads the global cache) and
725
+ // the request handlers (which read the wrapper's cache) would report divergent
726
+ // snapshots and livelock the client on permanent `ServerCancelled`.
727
+ (0, debug_1.fail)('makeProgram called with a different type cache for an already-wrapped program');
728
+ }
729
+ return wrapper;
730
+ }
731
+ //# sourceMappingURL=programWrapper.js.map