@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.
- package/dist/tests/typeServer/inProcTypeServerTestUtils.d.ts +39 -0
- package/dist/tests/typeServer/inProcTypeServerTestUtils.js +366 -0
- package/dist/tests/typeServer/inProcTypeServerTestUtils.js.map +1 -0
- package/dist/tests/typeServer/notebook.typeServer.test.d.ts +1 -0
- package/dist/tests/typeServer/notebook.typeServer.test.js +315 -0
- package/dist/tests/typeServer/notebook.typeServer.test.js.map +1 -0
- package/dist/tests/typeServer/typeServer.inProc.test.d.ts +1 -0
- package/dist/tests/typeServer/typeServer.inProc.test.js +234 -0
- package/dist/tests/typeServer/typeServer.inProc.test.js.map +1 -0
- package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.d.ts +1 -0
- package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.js +298 -0
- package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.js.map +1 -0
- package/dist/typeServer/cancellation.d.ts +5 -0
- package/dist/typeServer/cancellation.js +14 -0
- package/dist/typeServer/cancellation.js.map +1 -0
- package/dist/typeServer/diagnosticUtils.d.ts +4 -0
- package/dist/typeServer/diagnosticUtils.js +71 -0
- package/dist/typeServer/diagnosticUtils.js.map +1 -0
- package/dist/typeServer/enums.d.ts +14 -0
- package/dist/typeServer/enums.js +524 -0
- package/dist/typeServer/enums.js.map +1 -0
- package/dist/typeServer/eventEmitter.d.ts +12 -0
- package/dist/typeServer/eventEmitter.js +32 -0
- package/dist/typeServer/eventEmitter.js.map +1 -0
- package/dist/typeServer/nodeMain.d.ts +1 -0
- package/dist/typeServer/nodeMain.js +65 -0
- package/dist/typeServer/nodeMain.js.map +1 -0
- package/dist/typeServer/notebookCellChain.d.ts +34 -0
- package/dist/typeServer/notebookCellChain.js +182 -0
- package/dist/typeServer/notebookCellChain.js.map +1 -0
- package/dist/typeServer/notebookDocumentHandler.d.ts +23 -0
- package/dist/typeServer/notebookDocumentHandler.js +158 -0
- package/dist/typeServer/notebookDocumentHandler.js.map +1 -0
- package/dist/typeServer/notebookUriMapper.d.ts +39 -0
- package/dist/typeServer/notebookUriMapper.js +164 -0
- package/dist/typeServer/notebookUriMapper.js.map +1 -0
- package/dist/typeServer/profilingStub.d.ts +10 -0
- package/dist/typeServer/profilingStub.js +12 -0
- package/dist/typeServer/profilingStub.js.map +1 -0
- package/dist/typeServer/programTypes.d.ts +136 -0
- package/dist/typeServer/programTypes.js +3 -0
- package/dist/typeServer/programTypes.js.map +1 -0
- package/dist/typeServer/programWrapper.d.ts +134 -0
- package/dist/typeServer/programWrapper.js +731 -0
- package/dist/typeServer/programWrapper.js.map +1 -0
- package/dist/typeServer/protocol/tspSupplemental.d.ts +43 -0
- package/dist/typeServer/protocol/tspSupplemental.js +48 -0
- package/dist/typeServer/protocol/tspSupplemental.js.map +1 -0
- package/dist/typeServer/protocol/typeServerProtocol.d.ts +1102 -0
- package/dist/typeServer/protocol/typeServerProtocol.js +290 -0
- package/dist/typeServer/protocol/typeServerProtocol.js.map +1 -0
- package/dist/typeServer/server.d.ts +54 -0
- package/dist/typeServer/server.js +620 -0
- package/dist/typeServer/server.js.map +1 -0
- package/dist/typeServer/serverUtils.d.ts +4 -0
- package/dist/typeServer/serverUtils.js +21 -0
- package/dist/typeServer/serverUtils.js.map +1 -0
- package/dist/typeServer/stubGenerator.d.ts +42 -0
- package/dist/typeServer/stubGenerator.js +895 -0
- package/dist/typeServer/stubGenerator.js.map +1 -0
- package/dist/typeServer/typeCache.d.ts +31 -0
- package/dist/typeServer/typeCache.js +54 -0
- package/dist/typeServer/typeCache.js.map +1 -0
- package/dist/typeServer/typeEvalUtils.d.ts +13 -0
- package/dist/typeServer/typeEvalUtils.js +83 -0
- package/dist/typeServer/typeEvalUtils.js.map +1 -0
- package/dist/typeServer/typeGuards.d.ts +3 -0
- package/dist/typeServer/typeGuards.js +55 -0
- package/dist/typeServer/typeGuards.js.map +1 -0
- package/dist/typeServer/typeServerConversionTypes.d.ts +39 -0
- package/dist/typeServer/typeServerConversionTypes.js +448 -0
- package/dist/typeServer/typeServerConversionTypes.js.map +1 -0
- package/dist/typeServer/typeServerConversionUtils.d.ts +35 -0
- package/dist/typeServer/typeServerConversionUtils.js +524 -0
- package/dist/typeServer/typeServerConversionUtils.js.map +1 -0
- package/dist/typeServer/typeServerEvaluator.d.ts +16 -0
- package/dist/typeServer/typeServerEvaluator.js +36 -0
- package/dist/typeServer/typeServerEvaluator.js.map +1 -0
- package/dist/typeServer/typeServerFileSystem.d.ts +47 -0
- package/dist/typeServer/typeServerFileSystem.js +129 -0
- package/dist/typeServer/typeServerFileSystem.js.map +1 -0
- package/dist/typeServer/typeServerProtocolUtils.d.ts +2 -0
- package/dist/typeServer/typeServerProtocolUtils.js +7 -0
- package/dist/typeServer/typeServerProtocolUtils.js.map +1 -0
- package/dist/typeServer/typeServerServiceKeys.d.ts +7 -0
- package/dist/typeServer/typeServerServiceKeys.js +20 -0
- package/dist/typeServer/typeServerServiceKeys.js.map +1 -0
- package/dist/typeServer/typeUtils.d.ts +4 -0
- package/dist/typeServer/typeUtils.js +31 -0
- package/dist/typeServer/typeUtils.js.map +1 -0
- package/dist/typeServer/virtualFileOverlayFileSystem.d.ts +87 -0
- package/dist/typeServer/virtualFileOverlayFileSystem.js +181 -0
- package/dist/typeServer/virtualFileOverlayFileSystem.js.map +1 -0
- 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
|