@volar/typescript 1.6.9 → 1.7.1-patch.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.
@@ -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;