@volar/typescript 1.6.9 → 1.7.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.
- package/out/documentRegistry.d.ts +2 -0
- package/out/documentRegistry.js +14 -0
- package/out/dtsHost.d.ts +26 -0
- package/out/dtsHost.js +190 -0
- package/out/getProgram.d.ts +1 -1
- package/out/getProgram.js +8 -8
- package/out/index.d.ts +5 -8
- package/out/index.js +19 -285
- package/out/languageService.d.ts +9 -0
- package/out/languageService.js +292 -0
- package/out/languageServiceHost.d.ts +5 -0
- package/out/languageServiceHost.js +210 -0
- package/out/sys.d.ts +7 -0
- package/out/sys.js +325 -0
- package/out/typescript/core.d.ts +83 -0
- package/out/typescript/core.js +320 -0
- package/out/typescript/corePublic.d.ts +91 -0
- package/out/typescript/corePublic.js +51 -0
- package/out/typescript/path.d.ts +112 -0
- package/out/typescript/path.js +417 -0
- package/out/typescript/types.d.ts +129 -0
- package/out/typescript/types.js +3 -0
- package/out/typescript/utilities.d.ts +7 -0
- package/out/typescript/utilities.js +250 -0
- package/package.json +6 -3
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLanguageService = void 0;
|
|
4
|
+
const language_core_1 = require("@volar/language-core");
|
|
5
|
+
const getProgram_1 = require("./getProgram");
|
|
6
|
+
const languageServiceHost_1 = require("./languageServiceHost");
|
|
7
|
+
const documentRegistry_1 = require("./documentRegistry");
|
|
8
|
+
function createLanguageService(core, ts, sys) {
|
|
9
|
+
if (!ts) {
|
|
10
|
+
throw new Error('TypeScript module not provided.');
|
|
11
|
+
}
|
|
12
|
+
const lsHost = (0, languageServiceHost_1.createLanguageServiceHost)(core, ts, sys);
|
|
13
|
+
const ls = ts.createLanguageService(lsHost, (0, documentRegistry_1.getDocumentRegistry)(ts, sys.useCaseSensitiveFileNames, core.host.getCurrentDirectory()));
|
|
14
|
+
return new Proxy({
|
|
15
|
+
organizeImports,
|
|
16
|
+
// only support for .ts for now, not support for .vue
|
|
17
|
+
getDefinitionAtPosition,
|
|
18
|
+
getDefinitionAndBoundSpan,
|
|
19
|
+
getTypeDefinitionAtPosition,
|
|
20
|
+
getImplementationAtPosition,
|
|
21
|
+
findRenameLocations,
|
|
22
|
+
getReferencesAtPosition,
|
|
23
|
+
findReferences,
|
|
24
|
+
// TODO: now is handled by vue server
|
|
25
|
+
// prepareCallHierarchy: tsLanguageService.rawLs.prepareCallHierarchy,
|
|
26
|
+
// provideCallHierarchyIncomingCalls: tsLanguageService.rawLs.provideCallHierarchyIncomingCalls,
|
|
27
|
+
// provideCallHierarchyOutgoingCalls: tsLanguageService.rawLs.provideCallHierarchyOutgoingCalls,
|
|
28
|
+
// getEditsForFileRename: tsLanguageService.rawLs.getEditsForFileRename,
|
|
29
|
+
// TODO
|
|
30
|
+
// getCodeFixesAtPosition: tsLanguageService.rawLs.getCodeFixesAtPosition,
|
|
31
|
+
// getCombinedCodeFix: tsLanguageService.rawLs.getCombinedCodeFix,
|
|
32
|
+
// applyCodeActionCommand: tsLanguageService.rawLs.applyCodeActionCommand,
|
|
33
|
+
// getApplicableRefactors: tsLanguageService.rawLs.getApplicableRefactors,
|
|
34
|
+
// getEditsForRefactor: tsLanguageService.rawLs.getEditsForRefactor,
|
|
35
|
+
getProgram: () => (0, getProgram_1.getProgram)(ts, core, ls, lsHost),
|
|
36
|
+
__internal__: {
|
|
37
|
+
context: core,
|
|
38
|
+
languageService: ls,
|
|
39
|
+
languageServiceHost: lsHost,
|
|
40
|
+
},
|
|
41
|
+
}, {
|
|
42
|
+
get: (target, property) => {
|
|
43
|
+
if (property in target) {
|
|
44
|
+
return target[property];
|
|
45
|
+
}
|
|
46
|
+
return ls[property];
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
// apis
|
|
50
|
+
function organizeImports(args, formatOptions, preferences) {
|
|
51
|
+
let edits = [];
|
|
52
|
+
const file = core.virtualFiles.getSource(args.fileName)?.root;
|
|
53
|
+
if (file) {
|
|
54
|
+
(0, language_core_1.forEachEmbeddedFile)(file, embeddedFile => {
|
|
55
|
+
if (embeddedFile.kind === language_core_1.FileKind.TypeScriptHostFile && embeddedFile.capabilities.codeAction) {
|
|
56
|
+
edits = edits.concat(ls.organizeImports({
|
|
57
|
+
...args,
|
|
58
|
+
fileName: embeddedFile.fileName,
|
|
59
|
+
}, formatOptions, preferences));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return ls.organizeImports(args, formatOptions, preferences);
|
|
65
|
+
}
|
|
66
|
+
return edits.map(transformFileTextChanges).filter(notEmpty);
|
|
67
|
+
}
|
|
68
|
+
function getReferencesAtPosition(fileName, position) {
|
|
69
|
+
return findLocations(fileName, position, 'references');
|
|
70
|
+
}
|
|
71
|
+
function getDefinitionAtPosition(fileName, position) {
|
|
72
|
+
return findLocations(fileName, position, 'definition');
|
|
73
|
+
}
|
|
74
|
+
function getTypeDefinitionAtPosition(fileName, position) {
|
|
75
|
+
return findLocations(fileName, position, 'typeDefinition');
|
|
76
|
+
}
|
|
77
|
+
function getImplementationAtPosition(fileName, position) {
|
|
78
|
+
return findLocations(fileName, position, 'implementation');
|
|
79
|
+
}
|
|
80
|
+
function findRenameLocations(fileName, position, findInStrings, findInComments, preferences) {
|
|
81
|
+
return findLocations(fileName, position, 'rename', findInStrings, findInComments, preferences);
|
|
82
|
+
}
|
|
83
|
+
function findLocations(fileName, position, mode, findInStrings = false, findInComments = false, preferences) {
|
|
84
|
+
const loopChecker = new Set();
|
|
85
|
+
let symbols = [];
|
|
86
|
+
withMirrors(fileName, position);
|
|
87
|
+
return symbols.map(s => transformDocumentSpanLike(s)).filter(notEmpty);
|
|
88
|
+
function withMirrors(fileName, position) {
|
|
89
|
+
if (loopChecker.has(fileName + ':' + position))
|
|
90
|
+
return;
|
|
91
|
+
loopChecker.add(fileName + ':' + position);
|
|
92
|
+
const _symbols = mode === 'definition' ? ls.getDefinitionAtPosition(fileName, position)
|
|
93
|
+
: mode === 'typeDefinition' ? ls.getTypeDefinitionAtPosition(fileName, position)
|
|
94
|
+
: mode === 'references' ? ls.getReferencesAtPosition(fileName, position)
|
|
95
|
+
: mode === 'implementation' ? ls.getImplementationAtPosition(fileName, position)
|
|
96
|
+
// @ts-expect-error
|
|
97
|
+
: mode === 'rename' && preferences ? ls.findRenameLocations(fileName, position, findInStrings, findInComments, preferences)
|
|
98
|
+
: undefined;
|
|
99
|
+
if (!_symbols)
|
|
100
|
+
return;
|
|
101
|
+
symbols = symbols.concat(_symbols);
|
|
102
|
+
for (const ref of _symbols) {
|
|
103
|
+
loopChecker.add(ref.fileName + ':' + ref.textSpan.start);
|
|
104
|
+
const [virtualFile] = core.virtualFiles.getVirtualFile(ref.fileName);
|
|
105
|
+
if (!virtualFile)
|
|
106
|
+
continue;
|
|
107
|
+
const mirrorMap = core.virtualFiles.getMirrorMap(virtualFile);
|
|
108
|
+
if (!mirrorMap)
|
|
109
|
+
continue;
|
|
110
|
+
for (const [mirrorOffset, data] of mirrorMap.findMirrorOffsets(ref.textSpan.start)) {
|
|
111
|
+
if ((mode === 'definition' || mode === 'typeDefinition' || mode === 'implementation') && !data.definition)
|
|
112
|
+
continue;
|
|
113
|
+
if ((mode === 'references') && !data.references)
|
|
114
|
+
continue;
|
|
115
|
+
if ((mode === 'rename') && !data.rename)
|
|
116
|
+
continue;
|
|
117
|
+
if (loopChecker.has(ref.fileName + ':' + mirrorOffset))
|
|
118
|
+
continue;
|
|
119
|
+
withMirrors(ref.fileName, mirrorOffset);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function getDefinitionAndBoundSpan(fileName, position) {
|
|
125
|
+
const loopChecker = new Set();
|
|
126
|
+
let textSpan;
|
|
127
|
+
let symbols = [];
|
|
128
|
+
withMirrors(fileName, position);
|
|
129
|
+
if (!textSpan)
|
|
130
|
+
return;
|
|
131
|
+
return {
|
|
132
|
+
textSpan: textSpan,
|
|
133
|
+
definitions: symbols?.map(s => transformDocumentSpanLike(s)).filter(notEmpty),
|
|
134
|
+
};
|
|
135
|
+
function withMirrors(fileName, position) {
|
|
136
|
+
if (loopChecker.has(fileName + ':' + position))
|
|
137
|
+
return;
|
|
138
|
+
loopChecker.add(fileName + ':' + position);
|
|
139
|
+
const _symbols = ls.getDefinitionAndBoundSpan(fileName, position);
|
|
140
|
+
if (!_symbols)
|
|
141
|
+
return;
|
|
142
|
+
if (!textSpan) {
|
|
143
|
+
textSpan = _symbols.textSpan;
|
|
144
|
+
}
|
|
145
|
+
if (!_symbols.definitions)
|
|
146
|
+
return;
|
|
147
|
+
symbols = symbols.concat(_symbols.definitions);
|
|
148
|
+
for (const ref of _symbols.definitions) {
|
|
149
|
+
loopChecker.add(ref.fileName + ':' + ref.textSpan.start);
|
|
150
|
+
const [virtualFile] = core.virtualFiles.getVirtualFile(ref.fileName);
|
|
151
|
+
if (!virtualFile)
|
|
152
|
+
continue;
|
|
153
|
+
const mirrorMap = core.virtualFiles.getMirrorMap(virtualFile);
|
|
154
|
+
if (!mirrorMap)
|
|
155
|
+
continue;
|
|
156
|
+
for (const [mirrorOffset, data] of mirrorMap.findMirrorOffsets(ref.textSpan.start)) {
|
|
157
|
+
if (!data.definition)
|
|
158
|
+
continue;
|
|
159
|
+
if (loopChecker.has(ref.fileName + ':' + mirrorOffset))
|
|
160
|
+
continue;
|
|
161
|
+
withMirrors(ref.fileName, mirrorOffset);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function findReferences(fileName, position) {
|
|
167
|
+
const loopChecker = new Set();
|
|
168
|
+
let symbols = [];
|
|
169
|
+
withMirrors(fileName, position);
|
|
170
|
+
return symbols.map(s => transformReferencedSymbol(s)).filter(notEmpty);
|
|
171
|
+
function withMirrors(fileName, position) {
|
|
172
|
+
if (loopChecker.has(fileName + ':' + position))
|
|
173
|
+
return;
|
|
174
|
+
loopChecker.add(fileName + ':' + position);
|
|
175
|
+
const _symbols = ls.findReferences(fileName, position);
|
|
176
|
+
if (!_symbols)
|
|
177
|
+
return;
|
|
178
|
+
symbols = symbols.concat(_symbols);
|
|
179
|
+
for (const symbol of _symbols) {
|
|
180
|
+
for (const ref of symbol.references) {
|
|
181
|
+
loopChecker.add(ref.fileName + ':' + ref.textSpan.start);
|
|
182
|
+
const [virtualFile] = core.virtualFiles.getVirtualFile(ref.fileName);
|
|
183
|
+
if (!virtualFile)
|
|
184
|
+
continue;
|
|
185
|
+
const mirrorMap = core.virtualFiles.getMirrorMap(virtualFile);
|
|
186
|
+
if (!mirrorMap)
|
|
187
|
+
continue;
|
|
188
|
+
for (const [mirrorOffset, data] of mirrorMap.findMirrorOffsets(ref.textSpan.start)) {
|
|
189
|
+
if (!data.references)
|
|
190
|
+
continue;
|
|
191
|
+
if (loopChecker.has(ref.fileName + ':' + mirrorOffset))
|
|
192
|
+
continue;
|
|
193
|
+
withMirrors(ref.fileName, mirrorOffset);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// transforms
|
|
200
|
+
function transformFileTextChanges(changes) {
|
|
201
|
+
const [_, source] = core.virtualFiles.getVirtualFile(changes.fileName);
|
|
202
|
+
if (source) {
|
|
203
|
+
return {
|
|
204
|
+
...changes,
|
|
205
|
+
fileName: source.fileName,
|
|
206
|
+
textChanges: changes.textChanges.map(c => {
|
|
207
|
+
const span = transformSpan(changes.fileName, c.span);
|
|
208
|
+
if (span) {
|
|
209
|
+
return {
|
|
210
|
+
...c,
|
|
211
|
+
span: span.textSpan,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}).filter(notEmpty),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
return changes;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function transformReferencedSymbol(symbol) {
|
|
222
|
+
const definition = transformDocumentSpanLike(symbol.definition);
|
|
223
|
+
const references = symbol.references.map(r => transformDocumentSpanLike(r)).filter(notEmpty);
|
|
224
|
+
if (definition) {
|
|
225
|
+
return {
|
|
226
|
+
definition,
|
|
227
|
+
references,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
else if (references.length) { // TODO: remove patching
|
|
231
|
+
return {
|
|
232
|
+
definition: {
|
|
233
|
+
...symbol.definition,
|
|
234
|
+
fileName: references[0].fileName,
|
|
235
|
+
textSpan: references[0].textSpan,
|
|
236
|
+
},
|
|
237
|
+
references,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function transformDocumentSpanLike(documentSpan) {
|
|
242
|
+
const textSpan = transformSpan(documentSpan.fileName, documentSpan.textSpan);
|
|
243
|
+
if (!textSpan)
|
|
244
|
+
return;
|
|
245
|
+
const contextSpan = transformSpan(documentSpan.fileName, documentSpan.contextSpan);
|
|
246
|
+
const originalTextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalTextSpan);
|
|
247
|
+
const originalContextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalContextSpan);
|
|
248
|
+
return {
|
|
249
|
+
...documentSpan,
|
|
250
|
+
fileName: textSpan.fileName,
|
|
251
|
+
textSpan: textSpan.textSpan,
|
|
252
|
+
contextSpan: contextSpan?.textSpan,
|
|
253
|
+
originalFileName: originalTextSpan?.fileName,
|
|
254
|
+
originalTextSpan: originalTextSpan?.textSpan,
|
|
255
|
+
originalContextSpan: originalContextSpan?.textSpan,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function transformSpan(fileName, textSpan) {
|
|
259
|
+
if (!fileName)
|
|
260
|
+
return;
|
|
261
|
+
if (!textSpan)
|
|
262
|
+
return;
|
|
263
|
+
const [virtualFile, source] = core.virtualFiles.getVirtualFile(fileName);
|
|
264
|
+
if (virtualFile && source) {
|
|
265
|
+
for (const [_, [sourceSnapshot, map]] of core.virtualFiles.getMaps(virtualFile)) {
|
|
266
|
+
if (source.snapshot !== sourceSnapshot)
|
|
267
|
+
continue;
|
|
268
|
+
const sourceLoc = map.toSourceOffset(textSpan.start);
|
|
269
|
+
if (sourceLoc) {
|
|
270
|
+
return {
|
|
271
|
+
fileName: source.fileName,
|
|
272
|
+
textSpan: {
|
|
273
|
+
start: sourceLoc[0],
|
|
274
|
+
length: textSpan.length,
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
return {
|
|
282
|
+
fileName,
|
|
283
|
+
textSpan,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
exports.createLanguageService = createLanguageService;
|
|
289
|
+
function notEmpty(value) {
|
|
290
|
+
return value !== null && value !== undefined;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=languageService.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LanguageContext } from '@volar/language-service';
|
|
2
|
+
import type * as ts from 'typescript/lib/tsserverlibrary';
|
|
3
|
+
export declare function createLanguageServiceHost(ctx: LanguageContext, ts: typeof import('typescript/lib/tsserverlibrary'), sys: ts.System & {
|
|
4
|
+
version?: number;
|
|
5
|
+
}): ts.LanguageServiceHost;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLanguageServiceHost = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
function createLanguageServiceHost(ctx, ts, sys) {
|
|
6
|
+
let lastProjectVersion;
|
|
7
|
+
let tsProjectVersion = 0;
|
|
8
|
+
const _tsHost = {
|
|
9
|
+
...sys,
|
|
10
|
+
getCurrentDirectory: ctx.host.getCurrentDirectory,
|
|
11
|
+
getCancellationToken: ctx.host.getCancellationToken,
|
|
12
|
+
getLocalizedDiagnosticMessages: ctx.host.getLocalizedDiagnosticMessages,
|
|
13
|
+
getCompilationSettings: ctx.host.getCompilationSettings,
|
|
14
|
+
getProjectReferences: ctx.host.getProjectReferences,
|
|
15
|
+
getDefaultLibFileName: (options) => {
|
|
16
|
+
try {
|
|
17
|
+
return ts.getDefaultLibFilePath(options);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// web
|
|
21
|
+
return `/node_modules/typescript/lib/${ts.getDefaultLibFileName(options)}`;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
|
25
|
+
getNewLine: () => sys.newLine,
|
|
26
|
+
readFile: fileName => {
|
|
27
|
+
const snapshot = getScriptSnapshot(fileName);
|
|
28
|
+
if (snapshot) {
|
|
29
|
+
return snapshot.getText(0, snapshot.getLength());
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
fileExists,
|
|
33
|
+
getProjectVersion: () => {
|
|
34
|
+
return tsProjectVersion.toString() + ':' + sys.version;
|
|
35
|
+
},
|
|
36
|
+
getTypeRootsVersion: () => {
|
|
37
|
+
return sys.version ?? -1; // TODO: only update for /node_modules changes?
|
|
38
|
+
},
|
|
39
|
+
getScriptFileNames,
|
|
40
|
+
getScriptVersion,
|
|
41
|
+
getScriptSnapshot,
|
|
42
|
+
getScriptKind(fileName) {
|
|
43
|
+
if (ts) {
|
|
44
|
+
if (ctx.virtualFiles.hasSource(fileName))
|
|
45
|
+
return ts.ScriptKind.Deferred;
|
|
46
|
+
switch (path_1.posix.extname(fileName)) {
|
|
47
|
+
case '.js': return ts.ScriptKind.JS;
|
|
48
|
+
case '.cjs': return ts.ScriptKind.JS;
|
|
49
|
+
case '.mjs': return ts.ScriptKind.JS;
|
|
50
|
+
case '.jsx': return ts.ScriptKind.JSX;
|
|
51
|
+
case '.ts': return ts.ScriptKind.TS;
|
|
52
|
+
case '.cts': return ts.ScriptKind.TS;
|
|
53
|
+
case '.mts': return ts.ScriptKind.TS;
|
|
54
|
+
case '.tsx': return ts.ScriptKind.TSX;
|
|
55
|
+
case '.json': return ts.ScriptKind.JSON;
|
|
56
|
+
default: return ts.ScriptKind.Unknown;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const fsFileSnapshots = new Map();
|
|
63
|
+
const fileVersions = new Map();
|
|
64
|
+
let oldTsVirtualFileSnapshots = new Set();
|
|
65
|
+
let oldOtherVirtualFileSnapshots = new Set();
|
|
66
|
+
return new Proxy(_tsHost, {
|
|
67
|
+
get: (target, property) => {
|
|
68
|
+
sync();
|
|
69
|
+
return target[property];
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
function sync() {
|
|
73
|
+
const newProjectVersion = ctx.host.getProjectVersion();
|
|
74
|
+
const shouldUpdate = newProjectVersion !== lastProjectVersion;
|
|
75
|
+
if (!shouldUpdate)
|
|
76
|
+
return;
|
|
77
|
+
lastProjectVersion = newProjectVersion;
|
|
78
|
+
const newTsVirtualFileSnapshots = new Set();
|
|
79
|
+
const newOtherVirtualFileSnapshots = new Set();
|
|
80
|
+
for (const { root } of ctx.virtualFiles.allSources()) {
|
|
81
|
+
forEachEmbeddedFile(root, embedded => {
|
|
82
|
+
if (embedded.kind === 1) {
|
|
83
|
+
newTsVirtualFileSnapshots.add(embedded.snapshot);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
newOtherVirtualFileSnapshots.add(embedded.snapshot);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (!setEquals(oldTsVirtualFileSnapshots, newTsVirtualFileSnapshots)) {
|
|
91
|
+
tsProjectVersion++;
|
|
92
|
+
}
|
|
93
|
+
else if (setEquals(oldOtherVirtualFileSnapshots, newOtherVirtualFileSnapshots)) {
|
|
94
|
+
// no any meta language files update, it mean project version was update by source files this time
|
|
95
|
+
tsProjectVersion++;
|
|
96
|
+
}
|
|
97
|
+
oldTsVirtualFileSnapshots = newTsVirtualFileSnapshots;
|
|
98
|
+
oldOtherVirtualFileSnapshots = newOtherVirtualFileSnapshots;
|
|
99
|
+
}
|
|
100
|
+
function getScriptFileNames() {
|
|
101
|
+
const tsFileNames = new Set();
|
|
102
|
+
for (const { root } of ctx.virtualFiles.allSources()) {
|
|
103
|
+
forEachEmbeddedFile(root, embedded => {
|
|
104
|
+
if (embedded.kind === 1) {
|
|
105
|
+
tsFileNames.add(embedded.fileName); // virtual .ts
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
for (const fileName of ctx.host.getScriptFileNames()) {
|
|
110
|
+
if (!ctx.virtualFiles.hasSource(fileName)) {
|
|
111
|
+
tsFileNames.add(fileName); // .ts
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return [...tsFileNames];
|
|
115
|
+
}
|
|
116
|
+
function getScriptSnapshot(fileName) {
|
|
117
|
+
// virtual files
|
|
118
|
+
const [virtualFile] = ctx.virtualFiles.getVirtualFile(fileName);
|
|
119
|
+
if (virtualFile) {
|
|
120
|
+
return virtualFile.snapshot;
|
|
121
|
+
}
|
|
122
|
+
// root files / opened files
|
|
123
|
+
const tsScript = ctx.host.getScriptSnapshot(fileName);
|
|
124
|
+
if (tsScript) {
|
|
125
|
+
return tsScript;
|
|
126
|
+
}
|
|
127
|
+
// fs files
|
|
128
|
+
const cache = fsFileSnapshots.get(fileName);
|
|
129
|
+
const modifiedTime = sys.getModifiedTime?.(fileName)?.valueOf();
|
|
130
|
+
if (!cache || cache[0] !== modifiedTime) {
|
|
131
|
+
if (sys.fileExists(fileName)) {
|
|
132
|
+
const text = sys.readFile(fileName);
|
|
133
|
+
const snapshot = text !== undefined ? ts.ScriptSnapshot.fromString(text) : undefined;
|
|
134
|
+
fsFileSnapshots.set(fileName, [modifiedTime, snapshot]);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
fsFileSnapshots.set(fileName, [modifiedTime, undefined]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return fsFileSnapshots.get(fileName)?.[1];
|
|
141
|
+
}
|
|
142
|
+
function getScriptVersion(fileName) {
|
|
143
|
+
// virtual files / root files / opened files
|
|
144
|
+
const [virtualFile] = ctx.virtualFiles.getVirtualFile(fileName);
|
|
145
|
+
const snapshot = virtualFile?.snapshot ?? ctx.host.getScriptSnapshot(fileName);
|
|
146
|
+
if (snapshot) {
|
|
147
|
+
if (!fileVersions.has(fileName)) {
|
|
148
|
+
fileVersions.set(fileName, { value: 0, snapshot });
|
|
149
|
+
}
|
|
150
|
+
const version = fileVersions.get(fileName);
|
|
151
|
+
if (version.snapshot !== snapshot) {
|
|
152
|
+
version.value++;
|
|
153
|
+
version.snapshot = snapshot;
|
|
154
|
+
}
|
|
155
|
+
return version.value.toString();
|
|
156
|
+
}
|
|
157
|
+
// fs files
|
|
158
|
+
return sys.getModifiedTime?.(fileName)?.valueOf().toString() ?? '';
|
|
159
|
+
}
|
|
160
|
+
function fileExists(fileName) {
|
|
161
|
+
// fill external virtual files
|
|
162
|
+
const ext = fileName.substring(fileName.lastIndexOf('.'));
|
|
163
|
+
if (ext === '.js'
|
|
164
|
+
|| ext === '.ts'
|
|
165
|
+
|| ext === '.jsx'
|
|
166
|
+
|| ext === '.tsx') {
|
|
167
|
+
/**
|
|
168
|
+
* If try to access a external .vue file that outside of the project,
|
|
169
|
+
* the file will not process by language service host,
|
|
170
|
+
* so virtual file will not be created.
|
|
171
|
+
*
|
|
172
|
+
* We try to create virtual file here.
|
|
173
|
+
*/
|
|
174
|
+
const sourceFileName = fileName.substring(0, fileName.lastIndexOf('.'));
|
|
175
|
+
if (!ctx.virtualFiles.hasSource(sourceFileName)) {
|
|
176
|
+
const scriptSnapshot = getScriptSnapshot(sourceFileName);
|
|
177
|
+
if (scriptSnapshot) {
|
|
178
|
+
ctx.virtualFiles.updateSource(sourceFileName, scriptSnapshot, ctx.host.getLanguageId?.(sourceFileName));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// virtual files
|
|
183
|
+
if (ctx.virtualFiles.hasVirtualFile(fileName)) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
// root files
|
|
187
|
+
if (ctx.host.getScriptSnapshot(fileName)) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
// fs files
|
|
191
|
+
return !!sys.fileExists(fileName);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.createLanguageServiceHost = createLanguageServiceHost;
|
|
195
|
+
function setEquals(a, b) {
|
|
196
|
+
if (a.size !== b.size)
|
|
197
|
+
return false;
|
|
198
|
+
for (const item of a) {
|
|
199
|
+
if (!b.has(item))
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
function forEachEmbeddedFile(file, cb) {
|
|
205
|
+
cb(file);
|
|
206
|
+
for (const embeddedFile of file.embeddedFiles) {
|
|
207
|
+
forEachEmbeddedFile(embeddedFile, cb);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=languageServiceHost.js.map
|
package/out/sys.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServiceEnvironment, Disposable, LanguageContext } from '@volar/language-service';
|
|
2
|
+
import type * as ts from 'typescript/lib/tsserverlibrary';
|
|
3
|
+
import { IDtsHost } from './dtsHost';
|
|
4
|
+
export declare function createSys(ctx: LanguageContext | undefined, ts: typeof import('typescript/lib/tsserverlibrary'), env: ServiceEnvironment, dtsHost?: IDtsHost): ts.System & {
|
|
5
|
+
version: number;
|
|
6
|
+
sync(): Promise<number>;
|
|
7
|
+
} & Disposable;
|