@volar/typescript 2.0.0-alpha.2 → 2.0.0-alpha.4

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/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './lib/documentRegistry';
2
2
  export * from './lib/node/decorateLanguageService';
3
3
  export * from './lib/node/decorateLanguageServiceHost';
4
+ export * from './lib/node/decorateProgram';
5
+ export * from './lib/node/proxyCreateProgram';
4
6
  export * from './lib/protocol/createProject';
5
7
  export * from './lib/protocol/createSys';
6
- export * from './lib/protocol/getProgram';
package/index.js CHANGED
@@ -17,7 +17,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./lib/documentRegistry"), exports);
18
18
  __exportStar(require("./lib/node/decorateLanguageService"), exports);
19
19
  __exportStar(require("./lib/node/decorateLanguageServiceHost"), exports);
20
+ __exportStar(require("./lib/node/decorateProgram"), exports);
21
+ __exportStar(require("./lib/node/proxyCreateProgram"), exports);
20
22
  __exportStar(require("./lib/protocol/createProject"), exports);
21
23
  __exportStar(require("./lib/protocol/createSys"), exports);
22
- __exportStar(require("./lib/protocol/getProgram"), exports);
23
24
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,3 @@
1
1
  import { FileProvider } from '@volar/language-core';
2
2
  import type * as ts from 'typescript/lib/tsserverlibrary';
3
- export declare function decorateLanguageService(virtualFiles: FileProvider, languageService: ts.LanguageService, isTsPlugin: boolean): void;
3
+ export declare function decorateLanguageService(files: FileProvider, languageService: ts.LanguageService): void;
@@ -3,20 +3,44 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.decorateLanguageService = void 0;
4
4
  const language_core_1 = require("@volar/language-core");
5
5
  const dedupe_1 = require("./dedupe");
6
- function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
7
- const transformedDiagnostics = new WeakMap();
6
+ const utils_1 = require("./utils");
7
+ const transform_1 = require("./transform");
8
+ function decorateLanguageService(files, languageService) {
9
+ // ignored methods
10
+ const { getNavigationTree, getOutliningSpans, } = languageService;
11
+ languageService.getNavigationTree = (fileName) => {
12
+ const [virtualFile] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
13
+ if (virtualFile) {
14
+ const tree = getNavigationTree(fileName);
15
+ tree.childItems = undefined;
16
+ return tree;
17
+ }
18
+ else {
19
+ return getNavigationTree(fileName);
20
+ }
21
+ };
22
+ languageService.getOutliningSpans = (fileName) => {
23
+ const [virtualFile] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
24
+ if (virtualFile) {
25
+ return [];
26
+ }
27
+ else {
28
+ return getOutliningSpans(fileName);
29
+ }
30
+ };
31
+ // methods
8
32
  const { findReferences, findRenameLocations, getCompletionEntryDetails, getCompletionsAtPosition, getDefinitionAndBoundSpan, getDefinitionAtPosition, getFileReferences, getImplementationAtPosition, getQuickInfoAtPosition, getReferencesAtPosition, getSemanticDiagnostics, getSyntacticDiagnostics, getSuggestionDiagnostics, getTypeDefinitionAtPosition, getEncodedSemanticClassifications, getDocumentHighlights, getApplicableRefactors, getEditsForRefactor, getRenameInfo, getCodeFixesAtPosition, prepareCallHierarchy, provideCallHierarchyIncomingCalls, provideCallHierarchyOutgoingCalls, provideInlayHints, organizeImports, } = languageService;
9
33
  languageService.prepareCallHierarchy = (fileName, position) => {
10
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
34
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
11
35
  if (virtualFile) {
12
36
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
13
37
  if ((0, language_core_1.isCallHierarchyEnabled)(mapping.data)) {
14
- const item = prepareCallHierarchy(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
38
+ const item = prepareCallHierarchy(fileName, generateOffset + sourceFile.snapshot.getLength());
15
39
  if (Array.isArray(item)) {
16
- return item.map(item => transformCallHierarchyItem(item, language_core_1.isCallHierarchyEnabled));
40
+ return item.map(item => (0, transform_1.transformCallHierarchyItem)(files, item, language_core_1.isCallHierarchyEnabled));
17
41
  }
18
42
  else if (item) {
19
- return transformCallHierarchyItem(item, language_core_1.isCallHierarchyEnabled);
43
+ return (0, transform_1.transformCallHierarchyItem)(files, item, language_core_1.isCallHierarchyEnabled);
20
44
  }
21
45
  }
22
46
  }
@@ -27,11 +51,11 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
27
51
  };
28
52
  languageService.provideCallHierarchyIncomingCalls = (fileName, position) => {
29
53
  let calls = [];
30
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
54
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
31
55
  if (virtualFile) {
32
56
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
33
57
  if ((0, language_core_1.isCallHierarchyEnabled)(mapping.data)) {
34
- calls = provideCallHierarchyIncomingCalls(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
58
+ calls = provideCallHierarchyIncomingCalls(fileName, generateOffset + sourceFile.snapshot.getLength());
35
59
  }
36
60
  }
37
61
  }
@@ -40,10 +64,10 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
40
64
  }
41
65
  return calls
42
66
  .map(call => {
43
- const from = transformCallHierarchyItem(call.from, language_core_1.isCallHierarchyEnabled);
67
+ const from = (0, transform_1.transformCallHierarchyItem)(files, call.from, language_core_1.isCallHierarchyEnabled);
44
68
  const fromSpans = call.fromSpans
45
- .map(span => transformSpan(call.from.file, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
46
- .filter(notEmpty);
69
+ .map(span => (0, transform_1.transformSpan)(files, call.from.file, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
70
+ .filter(utils_1.notEmpty);
47
71
  return {
48
72
  from,
49
73
  fromSpans,
@@ -52,11 +76,11 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
52
76
  };
53
77
  languageService.provideCallHierarchyOutgoingCalls = (fileName, position) => {
54
78
  let calls = [];
55
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
79
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
56
80
  if (virtualFile) {
57
81
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
58
82
  if ((0, language_core_1.isCallHierarchyEnabled)(mapping.data)) {
59
- calls = provideCallHierarchyOutgoingCalls(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
83
+ calls = provideCallHierarchyOutgoingCalls(fileName, generateOffset + sourceFile.snapshot.getLength());
60
84
  }
61
85
  }
62
86
  }
@@ -65,10 +89,10 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
65
89
  }
66
90
  return calls
67
91
  .map(call => {
68
- const to = transformCallHierarchyItem(call.to, language_core_1.isCallHierarchyEnabled);
92
+ const to = (0, transform_1.transformCallHierarchyItem)(files, call.to, language_core_1.isCallHierarchyEnabled);
69
93
  const fromSpans = call.fromSpans
70
- .map(span => transformSpan(fileName, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
71
- .filter(notEmpty);
94
+ .map(span => (0, transform_1.transformSpan)(files, fileName, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
95
+ .filter(utils_1.notEmpty);
72
96
  return {
73
97
  to,
74
98
  fromSpans,
@@ -78,18 +102,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
78
102
  languageService.organizeImports = (args, formatOptions, preferences) => {
79
103
  const unresolved = organizeImports(args, formatOptions, preferences);
80
104
  const resolved = unresolved
81
- .map(changes => transformFileTextChanges(changes, language_core_1.isCodeActionsEnabled))
82
- .filter(notEmpty);
105
+ .map(changes => (0, transform_1.transformFileTextChanges)(files, changes, language_core_1.isCodeActionsEnabled))
106
+ .filter(utils_1.notEmpty);
83
107
  return resolved;
84
108
  };
85
109
  languageService.getQuickInfoAtPosition = (fileName, position) => {
86
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
110
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
87
111
  if (virtualFile) {
88
112
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
89
113
  if ((0, language_core_1.isHoverEnabled)(mapping.data)) {
90
- const result = getQuickInfoAtPosition(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
114
+ const result = getQuickInfoAtPosition(fileName, generateOffset + sourceFile.snapshot.getLength());
91
115
  if (result) {
92
- const textSpan = transformSpan(fileName, result.textSpan, language_core_1.isHoverEnabled)?.textSpan;
116
+ const textSpan = (0, transform_1.transformSpan)(files, fileName, result.textSpan, language_core_1.isHoverEnabled)?.textSpan;
93
117
  if (textSpan) {
94
118
  return {
95
119
  ...result,
@@ -119,30 +143,30 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
119
143
  ...highlights,
120
144
  highlightSpans: highlights.highlightSpans
121
145
  .map(span => {
122
- const textSpan = transformSpan(span.fileName ?? highlights.fileName, span.textSpan, language_core_1.isHighlightEnabled)?.textSpan;
146
+ const textSpan = (0, transform_1.transformSpan)(files, span.fileName ?? highlights.fileName, span.textSpan, language_core_1.isHighlightEnabled)?.textSpan;
123
147
  if (textSpan) {
124
148
  return {
125
149
  ...span,
126
- contextSpan: transformSpan(span.fileName ?? highlights.fileName, span.contextSpan, language_core_1.isHighlightEnabled)?.textSpan,
150
+ contextSpan: (0, transform_1.transformSpan)(files, span.fileName ?? highlights.fileName, span.contextSpan, language_core_1.isHighlightEnabled)?.textSpan,
127
151
  textSpan,
128
152
  };
129
153
  }
130
154
  })
131
- .filter(notEmpty),
155
+ .filter(utils_1.notEmpty),
132
156
  };
133
157
  });
134
158
  return resolved;
135
159
  };
136
160
  languageService.getApplicableRefactors = (fileName, positionOrRange, preferences, triggerReason, kind, includeInteractiveActions) => {
137
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
161
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
138
162
  if (virtualFile) {
139
163
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(typeof positionOrRange === 'number' ? positionOrRange : positionOrRange.pos)) {
140
164
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
141
165
  const por = typeof positionOrRange === 'number'
142
- ? generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0)
166
+ ? generateOffset + sourceFile.snapshot.getLength()
143
167
  : {
144
- pos: generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0),
145
- end: generateOffset + positionOrRange.end - positionOrRange.pos + (isTsPlugin ? sourceFile.snapshot.getLength() : 0),
168
+ pos: generateOffset + sourceFile.snapshot.getLength(),
169
+ end: generateOffset + positionOrRange.end - positionOrRange.pos + sourceFile.snapshot.getLength(),
146
170
  };
147
171
  return getApplicableRefactors(fileName, por, preferences, triggerReason, kind, includeInteractiveActions);
148
172
  }
@@ -155,15 +179,15 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
155
179
  };
156
180
  languageService.getEditsForRefactor = (fileName, formatOptions, positionOrRange, refactorName, actionName, preferences) => {
157
181
  let edits;
158
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
182
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
159
183
  if (virtualFile) {
160
184
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(typeof positionOrRange === 'number' ? positionOrRange : positionOrRange.pos)) {
161
185
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
162
186
  const por = typeof positionOrRange === 'number'
163
- ? generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0)
187
+ ? generateOffset + sourceFile.snapshot.getLength()
164
188
  : {
165
- pos: generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0),
166
- end: generateOffset + positionOrRange.end - positionOrRange.pos + (isTsPlugin ? sourceFile.snapshot.getLength() : 0),
189
+ pos: generateOffset + sourceFile.snapshot.getLength(),
190
+ end: generateOffset + positionOrRange.end - positionOrRange.pos + sourceFile.snapshot.getLength(),
167
191
  };
168
192
  edits = getEditsForRefactor(fileName, formatOptions, por, refactorName, actionName, preferences);
169
193
  }
@@ -174,19 +198,19 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
174
198
  }
175
199
  if (edits) {
176
200
  edits.edits = edits.edits
177
- .map(edit => transformFileTextChanges(edit, language_core_1.isCodeActionsEnabled))
178
- .filter(notEmpty);
201
+ .map(edit => (0, transform_1.transformFileTextChanges)(files, edit, language_core_1.isCodeActionsEnabled))
202
+ .filter(utils_1.notEmpty);
179
203
  return edits;
180
204
  }
181
205
  };
182
206
  languageService.getRenameInfo = (fileName, position, options) => {
183
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
207
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
184
208
  if (virtualFile) {
185
209
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
186
210
  if ((0, language_core_1.isRenameEnabled)(mapping.data)) {
187
- const info = getRenameInfo(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0), options);
211
+ const info = getRenameInfo(fileName, generateOffset + sourceFile.snapshot.getLength(), options);
188
212
  if (info.canRename) {
189
- const span = transformSpan(fileName, info.triggerSpan, language_core_1.isRenameEnabled);
213
+ const span = (0, transform_1.transformSpan)(files, fileName, info.triggerSpan, language_core_1.isRenameEnabled);
190
214
  if (span) {
191
215
  info.triggerSpan = span.textSpan;
192
216
  return info;
@@ -208,13 +232,13 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
208
232
  };
209
233
  languageService.getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences) => {
210
234
  let fixes = [];
211
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
235
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
212
236
  if (virtualFile) {
213
237
  for (const [generateStart, mapping] of map.getGeneratedOffsets(start)) {
214
238
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
215
239
  for (const [generateEnd, mapping] of map.getGeneratedOffsets(end)) {
216
240
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
217
- fixes = getCodeFixesAtPosition(fileName, generateStart + (isTsPlugin ? sourceFile.snapshot.getLength() : 0), generateEnd + (isTsPlugin ? sourceFile.snapshot.getLength() : 0), errorCodes, formatOptions, preferences);
241
+ fixes = getCodeFixesAtPosition(fileName, generateStart + sourceFile.snapshot.getLength(), generateEnd + sourceFile.snapshot.getLength(), errorCodes, formatOptions, preferences);
218
242
  break;
219
243
  }
220
244
  }
@@ -226,13 +250,13 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
226
250
  fixes = getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences);
227
251
  }
228
252
  fixes = fixes.map(fix => {
229
- fix.changes = fix.changes.map(edit => transformFileTextChanges(edit, language_core_1.isCodeActionsEnabled)).filter(notEmpty);
253
+ fix.changes = fix.changes.map(edit => (0, transform_1.transformFileTextChanges)(files, edit, language_core_1.isCodeActionsEnabled)).filter(utils_1.notEmpty);
230
254
  return fix;
231
255
  });
232
256
  return fixes;
233
257
  };
234
258
  languageService.getEncodedSemanticClassifications = (fileName, span, format) => {
235
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
259
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
236
260
  if (virtualFile) {
237
261
  let start;
238
262
  let end;
@@ -248,16 +272,14 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
248
272
  start = 0;
249
273
  end = 0;
250
274
  }
251
- if (isTsPlugin) {
252
- start += sourceFile.snapshot.getLength();
253
- end += sourceFile.snapshot.getLength();
254
- }
275
+ start += sourceFile.snapshot.getLength();
276
+ end += sourceFile.snapshot.getLength();
255
277
  const result = getEncodedSemanticClassifications(fileName, { start, length: end - start }, format);
256
278
  const spans = [];
257
279
  for (let i = 0; i < result.spans.length; i += 3) {
258
- for (const [sourceStart, mapping] of map.getSourceOffsets(result.spans[i] - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
280
+ for (const [sourceStart, mapping] of map.getSourceOffsets(result.spans[i] - sourceFile.snapshot.getLength())) {
259
281
  if ((0, language_core_1.isSemanticTokensEnabled)(mapping.data)) {
260
- for (const [sourceEnd, mapping] of map.getSourceOffsets(result.spans[i] + result.spans[i + 1] - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
282
+ for (const [sourceEnd, mapping] of map.getSourceOffsets(result.spans[i] + result.spans[i + 1] - sourceFile.snapshot.getLength())) {
261
283
  if ((0, language_core_1.isSemanticTokensEnabled)(mapping.data)) {
262
284
  spans.push(sourceStart, sourceEnd - sourceStart, result.spans[i + 2]);
263
285
  break;
@@ -276,18 +298,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
276
298
  };
277
299
  languageService.getSyntacticDiagnostics = (fileName) => {
278
300
  return getSyntacticDiagnostics(fileName)
279
- .map(diagnostic => transformDiagnostic(diagnostic))
280
- .filter(notEmpty);
301
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
302
+ .filter(utils_1.notEmpty);
281
303
  };
282
304
  languageService.getSemanticDiagnostics = (fileName) => {
283
305
  return getSemanticDiagnostics(fileName)
284
- .map(diagnostic => transformDiagnostic(diagnostic))
285
- .filter(notEmpty);
306
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
307
+ .filter(utils_1.notEmpty);
286
308
  };
287
309
  languageService.getSuggestionDiagnostics = (fileName) => {
288
310
  return getSuggestionDiagnostics(fileName)
289
- .map(diagnostic => transformDiagnostic(diagnostic))
290
- .filter(notEmpty);
311
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
312
+ .filter(utils_1.notEmpty);
291
313
  };
292
314
  languageService.getDefinitionAndBoundSpan = (fileName, position) => {
293
315
  const unresolved = linkedCodeFeatureWorker(fileName, position, language_core_1.isDefinitionEnabled, position => getDefinitionAndBoundSpan(fileName, position), function* (result) {
@@ -296,15 +318,15 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
296
318
  }
297
319
  });
298
320
  const textSpan = unresolved
299
- .map(s => transformSpan(fileName, s.textSpan, language_core_1.isDefinitionEnabled)?.textSpan)
300
- .filter(notEmpty)[0];
321
+ .map(s => (0, transform_1.transformSpan)(files, fileName, s.textSpan, language_core_1.isDefinitionEnabled)?.textSpan)
322
+ .filter(utils_1.notEmpty)[0];
301
323
  if (!textSpan)
302
324
  return;
303
325
  const definitions = unresolved
304
326
  .map(s => s.definitions
305
- ?.map(s => transformDocumentSpan(s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
306
- .filter(notEmpty))
307
- .filter(notEmpty)
327
+ ?.map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
328
+ .filter(utils_1.notEmpty))
329
+ .filter(utils_1.notEmpty)
308
330
  .flat();
309
331
  return {
310
332
  textSpan,
@@ -322,17 +344,17 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
322
344
  const resolved = unresolved
323
345
  .flat()
324
346
  .map(symbol => {
325
- const definition = transformDocumentSpan(symbol.definition, language_core_1.isDefinitionEnabled);
347
+ const definition = (0, transform_1.transformDocumentSpan)(files, symbol.definition, language_core_1.isDefinitionEnabled);
326
348
  if (definition) {
327
349
  return {
328
350
  definition,
329
351
  references: symbol.references
330
- .map(r => transformDocumentSpan(r, language_core_1.isReferencesEnabled))
331
- .filter(notEmpty),
352
+ .map(r => (0, transform_1.transformDocumentSpan)(files, r, language_core_1.isReferencesEnabled))
353
+ .filter(utils_1.notEmpty),
332
354
  };
333
355
  }
334
356
  })
335
- .filter(notEmpty);
357
+ .filter(utils_1.notEmpty);
336
358
  return (0, dedupe_1.dedupeReferencedSymbols)(resolved);
337
359
  };
338
360
  languageService.getDefinitionAtPosition = (fileName, position) => {
@@ -343,8 +365,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
343
365
  });
344
366
  const resolved = unresolved
345
367
  .flat()
346
- .map(s => transformDocumentSpan(s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
347
- .filter(notEmpty);
368
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
369
+ .filter(utils_1.notEmpty);
348
370
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
349
371
  };
350
372
  languageService.getTypeDefinitionAtPosition = (fileName, position) => {
@@ -355,8 +377,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
355
377
  });
356
378
  const resolved = unresolved
357
379
  .flat()
358
- .map(s => transformDocumentSpan(s, language_core_1.isTypeDefinitionEnabled))
359
- .filter(notEmpty);
380
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isTypeDefinitionEnabled))
381
+ .filter(utils_1.notEmpty);
360
382
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
361
383
  };
362
384
  languageService.getImplementationAtPosition = (fileName, position) => {
@@ -367,8 +389,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
367
389
  });
368
390
  const resolved = unresolved
369
391
  .flat()
370
- .map(s => transformDocumentSpan(s, language_core_1.isImplementationEnabled))
371
- .filter(notEmpty);
392
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isImplementationEnabled))
393
+ .filter(utils_1.notEmpty);
372
394
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
373
395
  };
374
396
  languageService.findRenameLocations = (fileName, position, findInStrings, findInComments, preferences) => {
@@ -379,8 +401,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
379
401
  });
380
402
  const resolved = unresolved
381
403
  .flat()
382
- .map(s => transformDocumentSpan(s, language_core_1.isRenameEnabled))
383
- .filter(notEmpty);
404
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isRenameEnabled))
405
+ .filter(utils_1.notEmpty);
384
406
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
385
407
  };
386
408
  languageService.getReferencesAtPosition = (fileName, position) => {
@@ -391,21 +413,21 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
391
413
  });
392
414
  const resolved = unresolved
393
415
  .flat()
394
- .map(s => transformDocumentSpan(s, language_core_1.isReferencesEnabled))
395
- .filter(notEmpty);
416
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isReferencesEnabled))
417
+ .filter(utils_1.notEmpty);
396
418
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
397
419
  };
398
420
  languageService.getCompletionsAtPosition = (fileName, position, options, formattingSettings) => {
399
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
421
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
400
422
  if (virtualFile) {
401
423
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
402
424
  if ((0, language_core_1.isCompletionEnabled)(mapping.data)) {
403
- const result = getCompletionsAtPosition(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0), options, formattingSettings);
425
+ const result = getCompletionsAtPosition(fileName, generateOffset + sourceFile.snapshot.getLength(), options, formattingSettings);
404
426
  if (result) {
405
427
  for (const entry of result.entries) {
406
- entry.replacementSpan = transformSpan(fileName, entry.replacementSpan, language_core_1.isCompletionEnabled)?.textSpan;
428
+ entry.replacementSpan = (0, transform_1.transformSpan)(files, fileName, entry.replacementSpan, language_core_1.isCompletionEnabled)?.textSpan;
407
429
  }
408
- result.optionalReplacementSpan = transformSpan(fileName, result.optionalReplacementSpan, language_core_1.isCompletionEnabled)?.textSpan;
430
+ result.optionalReplacementSpan = (0, transform_1.transformSpan)(files, fileName, result.optionalReplacementSpan, language_core_1.isCompletionEnabled)?.textSpan;
409
431
  }
410
432
  return result;
411
433
  }
@@ -419,13 +441,13 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
419
441
  const details = getCompletionEntryDetails(fileName, position, entryName, formatOptions, source, preferences, data);
420
442
  if (details?.codeActions) {
421
443
  for (const codeAction of details.codeActions) {
422
- codeAction.changes = codeAction.changes.map(edit => transformFileTextChanges(edit, language_core_1.isCodeLensEnabled)).filter(notEmpty);
444
+ codeAction.changes = codeAction.changes.map(edit => (0, transform_1.transformFileTextChanges)(files, edit, language_core_1.isCodeLensEnabled)).filter(utils_1.notEmpty);
423
445
  }
424
446
  }
425
447
  return details;
426
448
  };
427
449
  languageService.provideInlayHints = (fileName, span, preferences) => {
428
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
450
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
429
451
  if (virtualFile) {
430
452
  let start;
431
453
  let end;
@@ -441,14 +463,12 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
441
463
  start = 0;
442
464
  end = 0;
443
465
  }
444
- if (isTsPlugin) {
445
- start += sourceFile.snapshot.getLength();
446
- end += sourceFile.snapshot.getLength();
447
- }
466
+ start += sourceFile.snapshot.getLength();
467
+ end += sourceFile.snapshot.getLength();
448
468
  const result = provideInlayHints(fileName, { start, length: end - start }, preferences);
449
469
  const hints = [];
450
470
  for (const hint of result) {
451
- for (const [sourcePosition, mapping] of map.getSourceOffsets(hint.position - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
471
+ for (const [sourcePosition, mapping] of map.getSourceOffsets(hint.position - sourceFile.snapshot.getLength())) {
452
472
  if ((0, language_core_1.isInlayHintsEnabled)(mapping.data)) {
453
473
  hints.push({
454
474
  ...hint,
@@ -467,18 +487,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
467
487
  languageService.getFileReferences = (fileName) => {
468
488
  const unresolved = getFileReferences(fileName);
469
489
  const resolved = unresolved
470
- .map(s => transformDocumentSpan(s, language_core_1.isReferencesEnabled))
471
- .filter(notEmpty);
490
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isReferencesEnabled))
491
+ .filter(utils_1.notEmpty);
472
492
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
473
493
  };
474
494
  function linkedCodeFeatureWorker(fileName, position, filter, worker, getLinkedCodes) {
475
495
  let results = [];
476
496
  const processedFilePositions = new Set();
477
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
497
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
478
498
  if (virtualFile) {
479
499
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
480
500
  if (filter(mapping.data)) {
481
- process(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
501
+ process(fileName, generateOffset + sourceFile.snapshot.getLength());
482
502
  }
483
503
  }
484
504
  }
@@ -496,167 +516,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
496
516
  results = results.concat(result);
497
517
  for (const ref of getLinkedCodes(result)) {
498
518
  processedFilePositions.add(ref[0] + ':' + ref[1]);
499
- const [virtualFile, sourceFile] = getVirtualFileAndMap(ref[0]);
519
+ const [virtualFile, sourceFile] = (0, utils_1.getVirtualFileAndMap)(files, ref[0]);
500
520
  if (!virtualFile)
501
521
  continue;
502
- const linkedCodeMap = virtualFiles.getLinkedCodeMap(virtualFile);
522
+ const linkedCodeMap = files.getLinkedCodeMap(virtualFile);
503
523
  if (!linkedCodeMap)
504
524
  continue;
505
- for (const linkedCodeOffset of linkedCodeMap.getLinkedOffsets(ref[1] - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
506
- process(ref[0], linkedCodeOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
507
- }
508
- }
509
- }
510
- }
511
- // transforms
512
- function transformCallHierarchyItem(item, filter) {
513
- const span = transformSpan(item.file, item.span, filter);
514
- const selectionSpan = transformSpan(item.file, item.selectionSpan, filter);
515
- return {
516
- ...item,
517
- span: span?.textSpan ?? { start: 0, length: 0 },
518
- selectionSpan: selectionSpan?.textSpan ?? { start: 0, length: 0 },
519
- };
520
- }
521
- function transformDiagnostic(diagnostic) {
522
- if (!transformedDiagnostics.has(diagnostic)) {
523
- if (diagnostic.start !== undefined && diagnostic.file) {
524
- transformedDiagnostics.set(diagnostic, undefined);
525
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(diagnostic.file?.fileName);
526
- if (virtualFile) {
527
- for (const [sourceOffset, mapping] of map.getSourceOffsets(diagnostic.start - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
528
- if ((0, language_core_1.shouldReportDiagnostics)(mapping.data)) {
529
- transformedDiagnostics.set(diagnostic, {
530
- ...diagnostic,
531
- start: sourceOffset,
532
- });
533
- break;
534
- }
535
- }
536
- }
537
- else {
538
- transformedDiagnostics.set(diagnostic, diagnostic);
539
- }
540
- }
541
- else {
542
- transformedDiagnostics.set(diagnostic, diagnostic);
543
- }
544
- if (diagnostic.relatedInformation) {
545
- diagnostic.relatedInformation = diagnostic.relatedInformation
546
- .map(transformDiagnostic)
547
- .filter(notEmpty);
548
- }
549
- }
550
- return transformedDiagnostics.get(diagnostic);
551
- }
552
- function transformFileTextChanges(changes, filter) {
553
- const [_, source] = getVirtualFileAndMap(changes.fileName);
554
- if (source) {
555
- return {
556
- ...changes,
557
- fileName: source.fileName,
558
- textChanges: changes.textChanges.map(c => {
559
- const span = transformSpan(changes.fileName, c.span, filter);
560
- if (span) {
561
- return {
562
- ...c,
563
- span: span.textSpan,
564
- };
565
- }
566
- }).filter(notEmpty),
567
- };
568
- }
569
- else {
570
- return changes;
571
- }
572
- }
573
- function transformDocumentSpan(documentSpan, filter, shouldFallback) {
574
- let textSpan = transformSpan(documentSpan.fileName, documentSpan.textSpan, filter);
575
- if (!textSpan && shouldFallback) {
576
- const [virtualFile, source] = getVirtualFileAndMap(documentSpan.fileName);
577
- if (virtualFile) {
578
- textSpan = {
579
- fileName: source.fileName,
580
- textSpan: { start: 0, length: 0 },
581
- };
582
- }
583
- }
584
- if (!textSpan)
585
- return;
586
- const contextSpan = transformSpan(documentSpan.fileName, documentSpan.contextSpan, filter);
587
- const originalTextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalTextSpan, filter);
588
- const originalContextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalContextSpan, filter);
589
- return {
590
- ...documentSpan,
591
- fileName: textSpan.fileName,
592
- textSpan: textSpan.textSpan,
593
- contextSpan: contextSpan?.textSpan,
594
- originalFileName: originalTextSpan?.fileName,
595
- originalTextSpan: originalTextSpan?.textSpan,
596
- originalContextSpan: originalContextSpan?.textSpan,
597
- };
598
- }
599
- function transformSpan(fileName, textSpan, filter) {
600
- if (!fileName)
601
- return;
602
- if (!textSpan)
603
- return;
604
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
605
- if (virtualFile) {
606
- for (const sourceStart of map.getSourceOffsets(textSpan.start - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
607
- if (filter(sourceStart[1].data)) {
608
- for (const sourceEnd of map.getSourceOffsets(textSpan.start + textSpan.length - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
609
- if (filter(sourceEnd[1].data)) {
610
- return {
611
- fileName: sourceFile.fileName,
612
- textSpan: {
613
- start: sourceStart[0],
614
- length: sourceEnd[0] - sourceStart[0],
615
- },
616
- };
617
- }
618
- }
619
- }
620
- }
621
- }
622
- else {
623
- return {
624
- fileName,
625
- textSpan,
626
- };
627
- }
628
- }
629
- function getVirtualFileAndMap(fileName) {
630
- if (isTsPlugin) {
631
- const sourceFile = virtualFiles.getSourceFile(fileName);
632
- if (sourceFile?.virtualFile) {
633
- for (const virtualFile of (0, language_core_1.forEachEmbeddedFile)(sourceFile.virtualFile[0])) {
634
- const ext = virtualFile.fileName.substring(fileName.length);
635
- if (virtualFile.typescript && (ext === '.d.ts' || ext.match(/^\.(js|ts)x?$/))) {
636
- for (const map of virtualFiles.getMaps(virtualFile)) {
637
- if (map[1][0] === sourceFile.snapshot) {
638
- return [virtualFile, sourceFile, map[1][1]];
639
- }
640
- }
641
- }
525
+ for (const linkedCodeOffset of linkedCodeMap.getLinkedOffsets(ref[1] - sourceFile.snapshot.getLength())) {
526
+ process(ref[0], linkedCodeOffset + sourceFile.snapshot.getLength());
642
527
  }
643
528
  }
644
529
  }
645
- else {
646
- const [virtualFile, sourceFile] = virtualFiles.getVirtualFile(fileName);
647
- if (virtualFile) {
648
- for (const map of virtualFiles.getMaps(virtualFile)) {
649
- if (map[1][0] === sourceFile.snapshot) {
650
- return [virtualFile, sourceFile, map[1][1]];
651
- }
652
- }
653
- }
654
- }
655
- return [undefined, undefined, undefined];
656
530
  }
657
531
  }
658
532
  exports.decorateLanguageService = decorateLanguageService;
659
- function notEmpty(value) {
660
- return value !== null && value !== undefined;
661
- }
662
533
  //# sourceMappingURL=decorateLanguageService.js.map
@@ -0,0 +1,3 @@
1
+ import type { FileProvider } from '@volar/language-core';
2
+ import type * as ts from 'typescript/lib/tsserverlibrary';
3
+ export declare function decorateProgram(files: FileProvider, program: ts.Program): void;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decorateProgram = void 0;
4
+ const utils_1 = require("./utils");
5
+ const transform_1 = require("./transform");
6
+ function decorateProgram(files, program) {
7
+ const emit = program.emit;
8
+ // for tsc --noEmit
9
+ const getSyntacticDiagnostics = program.getSyntacticDiagnostics;
10
+ const getSemanticDiagnostics = program.getSemanticDiagnostics;
11
+ const getGlobalDiagnostics = program.getGlobalDiagnostics;
12
+ // for tsc --noEmit --watch
13
+ // @ts-ignore
14
+ const getBindAndCheckDiagnostics = program.getBindAndCheckDiagnostics;
15
+ program.emit = (targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) => {
16
+ const result = emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
17
+ return {
18
+ emitSkipped: result.emitSkipped,
19
+ emittedFiles: result.emittedFiles,
20
+ diagnostics: result.diagnostics
21
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
22
+ .filter(utils_1.notEmpty),
23
+ };
24
+ };
25
+ program.getSyntacticDiagnostics = (sourceFile, cancellationToken) => {
26
+ return getSyntacticDiagnostics(sourceFile, cancellationToken)
27
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
28
+ .filter(utils_1.notEmpty);
29
+ };
30
+ program.getSemanticDiagnostics = (sourceFile, cancellationToken) => {
31
+ return getSemanticDiagnostics(sourceFile, cancellationToken)
32
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
33
+ .filter(utils_1.notEmpty);
34
+ };
35
+ program.getGlobalDiagnostics = (cancellationToken) => {
36
+ return getGlobalDiagnostics(cancellationToken)
37
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
38
+ .filter(utils_1.notEmpty);
39
+ };
40
+ // @ts-ignore
41
+ program.getBindAndCheckDiagnostics = (sourceFile, cancellationToken) => {
42
+ return getBindAndCheckDiagnostics(sourceFile, cancellationToken)
43
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
44
+ .filter(utils_1.notEmpty);
45
+ };
46
+ }
47
+ exports.decorateProgram = decorateProgram;
48
+ //# sourceMappingURL=decorateProgram.js.map
@@ -0,0 +1,3 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
+ import { LanguagePlugin } from '@volar/language-core';
3
+ export declare function proxyCreateProgram(ts: typeof import('typescript'), original: typeof ts['createProgram'], extensions: string[], getLanguagePlugins: (ts: typeof import('typescript/lib/tsserverlibrary'), options: ts.CreateProgramOptions) => LanguagePlugin[]): typeof import("typescript").createProgram;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.proxyCreateProgram = void 0;
4
+ const decorateProgram_1 = require("./decorateProgram");
5
+ const language_core_1 = require("@volar/language-core");
6
+ function proxyCreateProgram(ts, original, extensions, getLanguagePlugins) {
7
+ return new Proxy(original, {
8
+ apply: (target, thisArg, args) => {
9
+ const options = args[0];
10
+ assert(!!options.host, '!!options.host');
11
+ const originalHost = options.host;
12
+ options.host = { ...originalHost };
13
+ options.options.allowArbitraryExtensions = true;
14
+ const sourceFileToSnapshotMap = new WeakMap();
15
+ const files = (0, language_core_1.createFileProvider)(getLanguagePlugins(ts, options), ts.sys.useCaseSensitiveFileNames, fileName => {
16
+ let snapshot;
17
+ assert(originalSourceFiles.has(fileName), `originalSourceFiles.has(${fileName})`);
18
+ const sourceFile = originalSourceFiles.get(fileName);
19
+ if (sourceFile) {
20
+ snapshot = sourceFileToSnapshotMap.get(sourceFile);
21
+ if (!snapshot) {
22
+ snapshot = {
23
+ getChangeRange() {
24
+ return undefined;
25
+ },
26
+ getLength() {
27
+ return sourceFile.text.length;
28
+ },
29
+ getText(start, end) {
30
+ return sourceFile.text.substring(start, end);
31
+ },
32
+ };
33
+ sourceFileToSnapshotMap.set(sourceFile, snapshot);
34
+ }
35
+ }
36
+ if (snapshot) {
37
+ files.updateSourceFile(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
38
+ }
39
+ else {
40
+ files.deleteSourceFile(fileName);
41
+ }
42
+ });
43
+ const originalSourceFiles = new Map();
44
+ const parsedSourceFiles = new WeakMap();
45
+ const arbitraryExtensions = extensions.map(ext => `.d${ext}.ts`);
46
+ const moduleResolutionHost = {
47
+ ...originalHost,
48
+ fileExists(fileName) {
49
+ for (let i = 0; i < arbitraryExtensions.length; i++) {
50
+ if (fileName.endsWith(arbitraryExtensions[i])) {
51
+ return originalHost.fileExists(fileName.slice(0, -arbitraryExtensions[i].length) + extensions[i]);
52
+ }
53
+ }
54
+ return originalHost.fileExists(fileName);
55
+ },
56
+ };
57
+ options.host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
58
+ const originalSourceFile = originalHost.getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
59
+ originalSourceFiles.set(fileName, originalSourceFile);
60
+ if (originalSourceFile && extensions.some(ext => fileName.endsWith(ext))) {
61
+ let sourceFile2 = parsedSourceFiles.get(originalSourceFile);
62
+ if (!sourceFile2) {
63
+ const sourceFile = files.getSourceFile(fileName);
64
+ assert(!!sourceFile, '!!sourceFile');
65
+ let patchedText = originalSourceFile.text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
66
+ let scriptKind = ts.ScriptKind.TS;
67
+ const virtualFile = sourceFile.virtualFile?.[0];
68
+ if (virtualFile) {
69
+ for (const file of (0, language_core_1.forEachEmbeddedFile)(virtualFile)) {
70
+ if (file.typescript) {
71
+ scriptKind = file.typescript.scriptKind;
72
+ patchedText += file.snapshot.getText(0, file.snapshot.getLength());
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ sourceFile2 = ts.createSourceFile(sourceFile.fileName, patchedText, 99, true, scriptKind);
78
+ // @ts-expect-error
79
+ sourceFile2.version = originalSourceFile.version;
80
+ parsedSourceFiles.set(originalSourceFile, sourceFile2);
81
+ }
82
+ return sourceFile2;
83
+ }
84
+ return originalSourceFile;
85
+ };
86
+ options.host.resolveModuleNameLiterals = (moduleNames, containingFile, redirectedReference, options) => {
87
+ return moduleNames.map(name => {
88
+ return resolveModuleName(name.text, containingFile, options, redirectedReference);
89
+ });
90
+ };
91
+ options.host.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference, options) => {
92
+ return moduleNames.map(name => {
93
+ return resolveModuleName(name, containingFile, options, redirectedReference).resolvedModule;
94
+ });
95
+ };
96
+ const program = Reflect.apply(target, thisArg, [options]);
97
+ (0, decorateProgram_1.decorateProgram)(files, program);
98
+ return program;
99
+ function resolveModuleName(name, containingFile, options, redirectedReference) {
100
+ const resolved = ts.resolveModuleName(name, containingFile, options, moduleResolutionHost, originalHost.getModuleResolutionCache?.(), redirectedReference);
101
+ if (resolved.resolvedModule) {
102
+ for (let i = 0; i < arbitraryExtensions.length; i++) {
103
+ if (resolved.resolvedModule.resolvedFileName.endsWith(arbitraryExtensions[i])) {
104
+ const sourceFileName = resolved.resolvedModule.resolvedFileName.slice(0, -arbitraryExtensions[i].length) + extensions[i];
105
+ resolved.resolvedModule.resolvedFileName = sourceFileName;
106
+ resolved.resolvedModule.extension = extensions[i];
107
+ }
108
+ }
109
+ }
110
+ return resolved;
111
+ }
112
+ },
113
+ });
114
+ }
115
+ exports.proxyCreateProgram = proxyCreateProgram;
116
+ function assert(condition, message) {
117
+ if (!condition) {
118
+ console.error(message);
119
+ throw new Error(message);
120
+ }
121
+ }
122
+ //# sourceMappingURL=proxyCreateProgram.js.map
@@ -0,0 +1,10 @@
1
+ import { FileProvider, CodeInformation } from '@volar/language-core';
2
+ import type * as ts from 'typescript/lib/tsserverlibrary';
3
+ export declare function transformCallHierarchyItem(files: FileProvider, item: ts.CallHierarchyItem, filter: (data: CodeInformation) => boolean): ts.CallHierarchyItem;
4
+ export declare function transformDiagnostic<T extends ts.Diagnostic>(files: FileProvider, diagnostic: T): T | undefined;
5
+ export declare function transformFileTextChanges(files: FileProvider, changes: ts.FileTextChanges, filter: (data: CodeInformation) => boolean): ts.FileTextChanges | undefined;
6
+ export declare function transformDocumentSpan<T extends ts.DocumentSpan>(files: FileProvider, documentSpan: T, filter: (data: CodeInformation) => boolean, shouldFallback?: boolean): T | undefined;
7
+ export declare function transformSpan(files: FileProvider, fileName: string | undefined, textSpan: ts.TextSpan | undefined, filter: (data: CodeInformation) => boolean): {
8
+ fileName: string;
9
+ textSpan: ts.TextSpan;
10
+ } | undefined;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformSpan = exports.transformDocumentSpan = exports.transformFileTextChanges = exports.transformDiagnostic = exports.transformCallHierarchyItem = void 0;
4
+ const language_core_1 = require("@volar/language-core");
5
+ const utils_1 = require("./utils");
6
+ const transformedDiagnostics = new WeakMap();
7
+ function transformCallHierarchyItem(files, item, filter) {
8
+ const span = transformSpan(files, item.file, item.span, filter);
9
+ const selectionSpan = transformSpan(files, item.file, item.selectionSpan, filter);
10
+ return {
11
+ ...item,
12
+ span: span?.textSpan ?? { start: 0, length: 0 },
13
+ selectionSpan: selectionSpan?.textSpan ?? { start: 0, length: 0 },
14
+ };
15
+ }
16
+ exports.transformCallHierarchyItem = transformCallHierarchyItem;
17
+ function transformDiagnostic(files, diagnostic) {
18
+ if (!transformedDiagnostics.has(diagnostic)) {
19
+ transformedDiagnostics.set(diagnostic, undefined);
20
+ const { relatedInformation } = diagnostic;
21
+ if (relatedInformation) {
22
+ diagnostic.relatedInformation = relatedInformation
23
+ .map(d => transformDiagnostic(files, d))
24
+ .filter(utils_1.notEmpty);
25
+ }
26
+ if (diagnostic.file !== undefined
27
+ && diagnostic.start !== undefined
28
+ && diagnostic.length !== undefined) {
29
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, diagnostic.file.fileName);
30
+ if (virtualFile) {
31
+ const sourceRange = transformRange(sourceFile, map, diagnostic.start, diagnostic.start + diagnostic.length, language_core_1.shouldReportDiagnostics);
32
+ if (sourceRange) {
33
+ transformedDiagnostics.set(diagnostic, {
34
+ ...diagnostic,
35
+ start: sourceRange[0],
36
+ length: sourceRange[1] - sourceRange[0],
37
+ });
38
+ }
39
+ }
40
+ else {
41
+ transformedDiagnostics.set(diagnostic, diagnostic);
42
+ }
43
+ }
44
+ else {
45
+ transformedDiagnostics.set(diagnostic, diagnostic);
46
+ }
47
+ }
48
+ return transformedDiagnostics.get(diagnostic);
49
+ }
50
+ exports.transformDiagnostic = transformDiagnostic;
51
+ function transformFileTextChanges(files, changes, filter) {
52
+ const [_, source] = (0, utils_1.getVirtualFileAndMap)(files, changes.fileName);
53
+ if (source) {
54
+ return {
55
+ ...changes,
56
+ fileName: source.fileName,
57
+ textChanges: changes.textChanges.map(c => {
58
+ const span = transformSpan(files, changes.fileName, c.span, filter);
59
+ if (span) {
60
+ return {
61
+ ...c,
62
+ span: span.textSpan,
63
+ };
64
+ }
65
+ }).filter(utils_1.notEmpty),
66
+ };
67
+ }
68
+ else {
69
+ return changes;
70
+ }
71
+ }
72
+ exports.transformFileTextChanges = transformFileTextChanges;
73
+ function transformDocumentSpan(files, documentSpan, filter, shouldFallback) {
74
+ let textSpan = transformSpan(files, documentSpan.fileName, documentSpan.textSpan, filter);
75
+ if (!textSpan && shouldFallback) {
76
+ const [virtualFile, source] = (0, utils_1.getVirtualFileAndMap)(files, documentSpan.fileName);
77
+ if (virtualFile) {
78
+ textSpan = {
79
+ fileName: source.fileName,
80
+ textSpan: { start: 0, length: 0 },
81
+ };
82
+ }
83
+ }
84
+ if (!textSpan)
85
+ return;
86
+ const contextSpan = transformSpan(files, documentSpan.fileName, documentSpan.contextSpan, filter);
87
+ const originalTextSpan = transformSpan(files, documentSpan.originalFileName, documentSpan.originalTextSpan, filter);
88
+ const originalContextSpan = transformSpan(files, documentSpan.originalFileName, documentSpan.originalContextSpan, filter);
89
+ return {
90
+ ...documentSpan,
91
+ fileName: textSpan.fileName,
92
+ textSpan: textSpan.textSpan,
93
+ contextSpan: contextSpan?.textSpan,
94
+ originalFileName: originalTextSpan?.fileName,
95
+ originalTextSpan: originalTextSpan?.textSpan,
96
+ originalContextSpan: originalContextSpan?.textSpan,
97
+ };
98
+ }
99
+ exports.transformDocumentSpan = transformDocumentSpan;
100
+ function transformSpan(files, fileName, textSpan, filter) {
101
+ if (!fileName)
102
+ return;
103
+ if (!textSpan)
104
+ return;
105
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
106
+ if (virtualFile) {
107
+ const sourceRange = transformRange(sourceFile, map, textSpan.start, textSpan.start + textSpan.length, filter);
108
+ if (sourceRange) {
109
+ return {
110
+ fileName: sourceFile.fileName,
111
+ textSpan: {
112
+ start: sourceRange[0],
113
+ length: sourceRange[1] - sourceRange[0],
114
+ },
115
+ };
116
+ }
117
+ }
118
+ else {
119
+ return {
120
+ fileName,
121
+ textSpan,
122
+ };
123
+ }
124
+ }
125
+ exports.transformSpan = transformSpan;
126
+ function transformRange(sourceFile, map, start, end, filter) {
127
+ for (const sourceStart of map.getSourceOffsets(start - sourceFile.snapshot.getLength())) {
128
+ if (filter(sourceStart[1].data)) {
129
+ for (const sourceEnd of map.getSourceOffsets(end - sourceFile.snapshot.getLength())) {
130
+ if (sourceEnd > sourceStart && filter(sourceEnd[1].data)) {
131
+ return [sourceStart[0], sourceEnd[0]];
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1,3 @@
1
+ import { FileProvider } from '@volar/language-core';
2
+ export declare function notEmpty<T>(value: T | null | undefined): value is T;
3
+ export declare function getVirtualFileAndMap(files: FileProvider, fileName: string): readonly [import("@volar/language-core").VirtualFile, import("@volar/language-core").SourceFile, import("@volar/language-core").SourceMap<import("@volar/language-core").CodeInformation>] | readonly [undefined, undefined, undefined];
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getVirtualFileAndMap = exports.notEmpty = void 0;
4
+ const language_core_1 = require("@volar/language-core");
5
+ function notEmpty(value) {
6
+ return value !== null && value !== undefined;
7
+ }
8
+ exports.notEmpty = notEmpty;
9
+ function getVirtualFileAndMap(files, fileName) {
10
+ const sourceFile = files.getSourceFile(fileName);
11
+ if (sourceFile?.virtualFile) {
12
+ for (const virtualFile of (0, language_core_1.forEachEmbeddedFile)(sourceFile.virtualFile[0])) {
13
+ const ext = virtualFile.fileName.substring(fileName.length);
14
+ if (virtualFile.typescript && (ext === '.d.ts' || ext.match(/^\.(js|ts)x?$/))) {
15
+ for (const map of files.getMaps(virtualFile)) {
16
+ if (map[1][0] === sourceFile.snapshot) {
17
+ return [virtualFile, sourceFile, map[1][1]];
18
+ }
19
+ }
20
+ }
21
+ }
22
+ }
23
+ return [undefined, undefined, undefined];
24
+ }
25
+ exports.getVirtualFileAndMap = getVirtualFileAndMap;
26
+ //# sourceMappingURL=utils.js.map
@@ -94,7 +94,6 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
94
94
  ...sys,
95
95
  getCurrentDirectory: projectHost.getCurrentDirectory,
96
96
  getCompilationSettings: projectHost.getCompilationSettings,
97
- getCancellationToken: projectHost.getCancellationToken,
98
97
  getLocalizedDiagnosticMessages: projectHost.getLocalizedDiagnosticMessages,
99
98
  getProjectReferences: projectHost.getProjectReferences,
100
99
  getDefaultLibFileName: (options) => {
@@ -0,0 +1,3 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
+ import { LanguagePlugin } from '@volar/language-core';
3
+ export declare function createAsyncTSServerPlugin(extensions: string[], scriptKind: ts.ScriptKind, loadLanguagePlugins: (ts: typeof import('typescript/lib/tsserverlibrary'), info: ts.server.PluginCreateInfo) => Promise<LanguagePlugin[]>): ts.server.PluginModuleFactory;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAsyncTSServerPlugin = void 0;
4
+ const decorateLanguageService_1 = require("../node/decorateLanguageService");
5
+ const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
6
+ const language_core_1 = require("@volar/language-core");
7
+ const createTSServerPlugin_1 = require("./createTSServerPlugin");
8
+ const externalFiles = new WeakMap();
9
+ function createAsyncTSServerPlugin(extensions, scriptKind, loadLanguagePlugins) {
10
+ return (modules) => {
11
+ const { typescript: ts } = modules;
12
+ const pluginModule = {
13
+ create(info) {
14
+ const emptySnapshot = ts.ScriptSnapshot.fromString('');
15
+ const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
16
+ const getScriptVersion = info.languageServiceHost.getScriptVersion.bind(info.languageServiceHost);
17
+ const getScriptKind = info.languageServiceHost.getScriptKind?.bind(info.languageServiceHost);
18
+ const getProjectVersion = info.languageServiceHost.getProjectVersion?.bind(info.languageServiceHost);
19
+ let initialized = false;
20
+ info.languageServiceHost.getScriptSnapshot = (fileName) => {
21
+ if (!initialized && extensions.some(ext => fileName.endsWith(ext))) {
22
+ return emptySnapshot;
23
+ }
24
+ return getScriptSnapshot(fileName);
25
+ };
26
+ info.languageServiceHost.getScriptVersion = (fileName) => {
27
+ if (!initialized && extensions.some(ext => fileName.endsWith(ext))) {
28
+ return 'initializing...';
29
+ }
30
+ return getScriptVersion(fileName);
31
+ };
32
+ if (getScriptKind) {
33
+ info.languageServiceHost.getScriptKind = (fileName) => {
34
+ if (!initialized && extensions.some(ext => fileName.endsWith(ext))) {
35
+ return scriptKind; // TODO: bypass upstream bug
36
+ }
37
+ return getScriptKind(fileName);
38
+ };
39
+ }
40
+ if (getProjectVersion) {
41
+ info.languageServiceHost.getProjectVersion = () => {
42
+ if (!initialized) {
43
+ return getProjectVersion() + ',initializing...';
44
+ }
45
+ return getProjectVersion();
46
+ };
47
+ }
48
+ loadLanguagePlugins(ts, info).then(languagePlugins => {
49
+ const files = (0, language_core_1.createFileProvider)(languagePlugins, ts.sys.useCaseSensitiveFileNames, (fileName) => {
50
+ const snapshot = getScriptSnapshot(fileName);
51
+ if (snapshot) {
52
+ files.updateSourceFile(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
53
+ }
54
+ else {
55
+ files.deleteSourceFile(fileName);
56
+ }
57
+ });
58
+ (0, decorateLanguageService_1.decorateLanguageService)(files, info.languageService);
59
+ (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(files, info.languageServiceHost, ts, extensions);
60
+ info.project.markAsDirty();
61
+ initialized = true;
62
+ });
63
+ return info.languageService;
64
+ },
65
+ getExternalFiles(project, updateLevel = 0) {
66
+ if (updateLevel >= (1)
67
+ || !externalFiles.has(project)) {
68
+ const oldFiles = externalFiles.get(project);
69
+ const newFiles = (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions);
70
+ externalFiles.set(project, newFiles);
71
+ if (oldFiles && !(0, createTSServerPlugin_1.arrayItemsEqual)(oldFiles, newFiles)) {
72
+ project.refreshDiagnostics();
73
+ }
74
+ }
75
+ return externalFiles.get(project);
76
+ },
77
+ };
78
+ return pluginModule;
79
+ };
80
+ }
81
+ exports.createAsyncTSServerPlugin = createAsyncTSServerPlugin;
82
+ //# sourceMappingURL=createAsyncTSServerPlugin.js.map
@@ -0,0 +1,7 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
+ import { LanguagePlugin } from '@volar/language-core';
3
+ export declare function createTSServerPlugin(init: (ts: typeof import('typescript/lib/tsserverlibrary'), info: ts.server.PluginCreateInfo) => {
4
+ languagePlugins: LanguagePlugin[];
5
+ extensions: string[];
6
+ }): ts.server.PluginModuleFactory;
7
+ export declare function arrayItemsEqual(a: string[], b: string[]): boolean;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.arrayItemsEqual = exports.createTSServerPlugin = void 0;
4
+ const decorateLanguageService_1 = require("../node/decorateLanguageService");
5
+ const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
6
+ const language_core_1 = require("@volar/language-core");
7
+ const externalFiles = new WeakMap();
8
+ const projectExternalFileExtensions = new WeakMap();
9
+ function createTSServerPlugin(init) {
10
+ return (modules) => {
11
+ const { typescript: ts } = modules;
12
+ const pluginModule = {
13
+ create(info) {
14
+ const { languagePlugins, extensions } = init(ts, info);
15
+ projectExternalFileExtensions.set(info.project, extensions);
16
+ const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
17
+ const files = (0, language_core_1.createFileProvider)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
18
+ const snapshot = getScriptSnapshot(fileName);
19
+ if (snapshot) {
20
+ files.updateSourceFile(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
21
+ }
22
+ else {
23
+ files.deleteSourceFile(fileName);
24
+ }
25
+ });
26
+ (0, decorateLanguageService_1.decorateLanguageService)(files, info.languageService);
27
+ (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(files, info.languageServiceHost, ts, extensions);
28
+ return info.languageService;
29
+ },
30
+ getExternalFiles(project, updateLevel = 0) {
31
+ if (updateLevel >= (1)
32
+ || !externalFiles.has(project)) {
33
+ const oldFiles = externalFiles.get(project);
34
+ const newFiles = (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, projectExternalFileExtensions.get(project));
35
+ externalFiles.set(project, newFiles);
36
+ if (oldFiles && !arrayItemsEqual(oldFiles, newFiles)) {
37
+ project.refreshDiagnostics();
38
+ }
39
+ }
40
+ return externalFiles.get(project);
41
+ },
42
+ };
43
+ return pluginModule;
44
+ };
45
+ }
46
+ exports.createTSServerPlugin = createTSServerPlugin;
47
+ function arrayItemsEqual(a, b) {
48
+ if (a.length !== b.length) {
49
+ return false;
50
+ }
51
+ const set = new Set(a);
52
+ for (const file of b) {
53
+ if (!set.has(file)) {
54
+ return false;
55
+ }
56
+ }
57
+ return true;
58
+ }
59
+ exports.arrayItemsEqual = arrayItemsEqual;
60
+ //# sourceMappingURL=createTSServerPlugin.js.map
@@ -0,0 +1,4 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary';
2
+ import type { LanguagePlugin } from '@volar/language-core';
3
+ export declare let getLanguagePlugins: (ts: typeof import('typescript/lib/tsserverlibrary'), options: ts.CreateProgramOptions) => LanguagePlugin[];
4
+ export declare function runTsc(tscPath: string, extensions: string[], _getLanguagePlugins: typeof getLanguagePlugins): void;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runTsc = exports.getLanguagePlugins = void 0;
4
+ const fs = require("fs");
5
+ let getLanguagePlugins = () => [];
6
+ exports.getLanguagePlugins = getLanguagePlugins;
7
+ function runTsc(tscPath, extensions, _getLanguagePlugins) {
8
+ exports.getLanguagePlugins = _getLanguagePlugins;
9
+ const proxyApiPath = require.resolve('../node/proxyCreateProgram');
10
+ const currentFilePath = require.resolve('./runTsc');
11
+ const readFileSync = fs.readFileSync;
12
+ fs.readFileSync = (...args) => {
13
+ if (args[0] === tscPath) {
14
+ let tsc = readFileSync(...args);
15
+ // add allow extensions
16
+ const extsText = extensions.map(ext => `"${ext}"`).join(', ');
17
+ tsc = replace(tsc, /supportedTSExtensions = .*(?=;)/, s => s + `.concat([[${extsText}]])`);
18
+ tsc = replace(tsc, /supportedJSExtensions = .*(?=;)/, s => s + `.concat([[${extsText}]])`);
19
+ tsc = replace(tsc, /allSupportedExtensions = .*(?=;)/, s => s + `.concat([[${extsText}]])`);
20
+ // proxy createProgram
21
+ tsc = replace(tsc, /function createProgram\(.+\) {/, s => `var createProgram = require(${JSON.stringify(proxyApiPath)}).proxyCreateProgram(`
22
+ + `new Proxy({}, { get(_target, p, _receiver) {return eval(p); } } ), `
23
+ + `_createProgram, `
24
+ + `[${extsText}], `
25
+ + `require(${JSON.stringify(currentFilePath)}).getLanguagePlugins`
26
+ + `);\n`
27
+ + s.replace('createProgram', '_createProgram'));
28
+ return tsc;
29
+ }
30
+ return readFileSync(...args);
31
+ };
32
+ require(tscPath);
33
+ }
34
+ exports.runTsc = runTsc;
35
+ function replace(text, ...[search, replace]) {
36
+ const before = text;
37
+ text = text.replace(search, replace);
38
+ const after = text;
39
+ if (after === before) {
40
+ throw 'Search string not found: ' + JSON.stringify(search.toString());
41
+ }
42
+ return after;
43
+ }
44
+ //# sourceMappingURL=runTsc.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volar/typescript",
3
- "version": "2.0.0-alpha.2",
3
+ "version": "2.0.0-alpha.4",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -12,12 +12,13 @@
12
12
  "directory": "packages/typescript"
13
13
  },
14
14
  "dependencies": {
15
- "@volar/language-core": "2.0.0-alpha.2",
15
+ "@volar/language-core": "2.0.0-alpha.4",
16
16
  "path-browserify": "^1.0.1"
17
17
  },
18
18
  "devDependencies": {
19
+ "@types/node": "latest",
19
20
  "@types/path-browserify": "latest",
20
- "@volar/language-service": "2.0.0-alpha.2"
21
+ "@volar/language-service": "2.0.0-alpha.4"
21
22
  },
22
- "gitHead": "88e80b9f00541ab9478b9c7b7af213813fc8cb20"
23
+ "gitHead": "4d07249613d0cc5de4197e90c741a64adf92b84b"
23
24
  }