@volar/typescript 2.0.0-alpha.3 → 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,12 +3,13 @@ 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) {
8
9
  // ignored methods
9
10
  const { getNavigationTree, getOutliningSpans, } = languageService;
10
11
  languageService.getNavigationTree = (fileName) => {
11
- const [virtualFile] = getVirtualFileAndMap(fileName);
12
+ const [virtualFile] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
12
13
  if (virtualFile) {
13
14
  const tree = getNavigationTree(fileName);
14
15
  tree.childItems = undefined;
@@ -19,7 +20,7 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
19
20
  }
20
21
  };
21
22
  languageService.getOutliningSpans = (fileName) => {
22
- const [virtualFile] = getVirtualFileAndMap(fileName);
23
+ const [virtualFile] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
23
24
  if (virtualFile) {
24
25
  return [];
25
26
  }
@@ -30,16 +31,16 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
30
31
  // methods
31
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;
32
33
  languageService.prepareCallHierarchy = (fileName, position) => {
33
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
34
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
34
35
  if (virtualFile) {
35
36
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
36
37
  if ((0, language_core_1.isCallHierarchyEnabled)(mapping.data)) {
37
- const item = prepareCallHierarchy(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
38
+ const item = prepareCallHierarchy(fileName, generateOffset + sourceFile.snapshot.getLength());
38
39
  if (Array.isArray(item)) {
39
- 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));
40
41
  }
41
42
  else if (item) {
42
- return transformCallHierarchyItem(item, language_core_1.isCallHierarchyEnabled);
43
+ return (0, transform_1.transformCallHierarchyItem)(files, item, language_core_1.isCallHierarchyEnabled);
43
44
  }
44
45
  }
45
46
  }
@@ -50,11 +51,11 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
50
51
  };
51
52
  languageService.provideCallHierarchyIncomingCalls = (fileName, position) => {
52
53
  let calls = [];
53
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
54
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
54
55
  if (virtualFile) {
55
56
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
56
57
  if ((0, language_core_1.isCallHierarchyEnabled)(mapping.data)) {
57
- calls = provideCallHierarchyIncomingCalls(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
58
+ calls = provideCallHierarchyIncomingCalls(fileName, generateOffset + sourceFile.snapshot.getLength());
58
59
  }
59
60
  }
60
61
  }
@@ -63,10 +64,10 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
63
64
  }
64
65
  return calls
65
66
  .map(call => {
66
- const from = transformCallHierarchyItem(call.from, language_core_1.isCallHierarchyEnabled);
67
+ const from = (0, transform_1.transformCallHierarchyItem)(files, call.from, language_core_1.isCallHierarchyEnabled);
67
68
  const fromSpans = call.fromSpans
68
- .map(span => transformSpan(call.from.file, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
69
- .filter(notEmpty);
69
+ .map(span => (0, transform_1.transformSpan)(files, call.from.file, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
70
+ .filter(utils_1.notEmpty);
70
71
  return {
71
72
  from,
72
73
  fromSpans,
@@ -75,11 +76,11 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
75
76
  };
76
77
  languageService.provideCallHierarchyOutgoingCalls = (fileName, position) => {
77
78
  let calls = [];
78
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
79
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
79
80
  if (virtualFile) {
80
81
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
81
82
  if ((0, language_core_1.isCallHierarchyEnabled)(mapping.data)) {
82
- calls = provideCallHierarchyOutgoingCalls(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
83
+ calls = provideCallHierarchyOutgoingCalls(fileName, generateOffset + sourceFile.snapshot.getLength());
83
84
  }
84
85
  }
85
86
  }
@@ -88,10 +89,10 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
88
89
  }
89
90
  return calls
90
91
  .map(call => {
91
- const to = transformCallHierarchyItem(call.to, language_core_1.isCallHierarchyEnabled);
92
+ const to = (0, transform_1.transformCallHierarchyItem)(files, call.to, language_core_1.isCallHierarchyEnabled);
92
93
  const fromSpans = call.fromSpans
93
- .map(span => transformSpan(fileName, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
94
- .filter(notEmpty);
94
+ .map(span => (0, transform_1.transformSpan)(files, fileName, span, language_core_1.isCallHierarchyEnabled)?.textSpan)
95
+ .filter(utils_1.notEmpty);
95
96
  return {
96
97
  to,
97
98
  fromSpans,
@@ -101,18 +102,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
101
102
  languageService.organizeImports = (args, formatOptions, preferences) => {
102
103
  const unresolved = organizeImports(args, formatOptions, preferences);
103
104
  const resolved = unresolved
104
- .map(changes => transformFileTextChanges(changes, language_core_1.isCodeActionsEnabled))
105
- .filter(notEmpty);
105
+ .map(changes => (0, transform_1.transformFileTextChanges)(files, changes, language_core_1.isCodeActionsEnabled))
106
+ .filter(utils_1.notEmpty);
106
107
  return resolved;
107
108
  };
108
109
  languageService.getQuickInfoAtPosition = (fileName, position) => {
109
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
110
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
110
111
  if (virtualFile) {
111
112
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
112
113
  if ((0, language_core_1.isHoverEnabled)(mapping.data)) {
113
- const result = getQuickInfoAtPosition(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
114
+ const result = getQuickInfoAtPosition(fileName, generateOffset + sourceFile.snapshot.getLength());
114
115
  if (result) {
115
- 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;
116
117
  if (textSpan) {
117
118
  return {
118
119
  ...result,
@@ -142,30 +143,30 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
142
143
  ...highlights,
143
144
  highlightSpans: highlights.highlightSpans
144
145
  .map(span => {
145
- 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;
146
147
  if (textSpan) {
147
148
  return {
148
149
  ...span,
149
- 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,
150
151
  textSpan,
151
152
  };
152
153
  }
153
154
  })
154
- .filter(notEmpty),
155
+ .filter(utils_1.notEmpty),
155
156
  };
156
157
  });
157
158
  return resolved;
158
159
  };
159
160
  languageService.getApplicableRefactors = (fileName, positionOrRange, preferences, triggerReason, kind, includeInteractiveActions) => {
160
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
161
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
161
162
  if (virtualFile) {
162
163
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(typeof positionOrRange === 'number' ? positionOrRange : positionOrRange.pos)) {
163
164
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
164
165
  const por = typeof positionOrRange === 'number'
165
- ? generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0)
166
+ ? generateOffset + sourceFile.snapshot.getLength()
166
167
  : {
167
- pos: generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0),
168
- 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(),
169
170
  };
170
171
  return getApplicableRefactors(fileName, por, preferences, triggerReason, kind, includeInteractiveActions);
171
172
  }
@@ -178,15 +179,15 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
178
179
  };
179
180
  languageService.getEditsForRefactor = (fileName, formatOptions, positionOrRange, refactorName, actionName, preferences) => {
180
181
  let edits;
181
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
182
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
182
183
  if (virtualFile) {
183
184
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(typeof positionOrRange === 'number' ? positionOrRange : positionOrRange.pos)) {
184
185
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
185
186
  const por = typeof positionOrRange === 'number'
186
- ? generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0)
187
+ ? generateOffset + sourceFile.snapshot.getLength()
187
188
  : {
188
- pos: generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0),
189
- 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(),
190
191
  };
191
192
  edits = getEditsForRefactor(fileName, formatOptions, por, refactorName, actionName, preferences);
192
193
  }
@@ -197,19 +198,19 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
197
198
  }
198
199
  if (edits) {
199
200
  edits.edits = edits.edits
200
- .map(edit => transformFileTextChanges(edit, language_core_1.isCodeActionsEnabled))
201
- .filter(notEmpty);
201
+ .map(edit => (0, transform_1.transformFileTextChanges)(files, edit, language_core_1.isCodeActionsEnabled))
202
+ .filter(utils_1.notEmpty);
202
203
  return edits;
203
204
  }
204
205
  };
205
206
  languageService.getRenameInfo = (fileName, position, options) => {
206
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
207
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
207
208
  if (virtualFile) {
208
209
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
209
210
  if ((0, language_core_1.isRenameEnabled)(mapping.data)) {
210
- const info = getRenameInfo(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0), options);
211
+ const info = getRenameInfo(fileName, generateOffset + sourceFile.snapshot.getLength(), options);
211
212
  if (info.canRename) {
212
- 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);
213
214
  if (span) {
214
215
  info.triggerSpan = span.textSpan;
215
216
  return info;
@@ -231,13 +232,13 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
231
232
  };
232
233
  languageService.getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences) => {
233
234
  let fixes = [];
234
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
235
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
235
236
  if (virtualFile) {
236
237
  for (const [generateStart, mapping] of map.getGeneratedOffsets(start)) {
237
238
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
238
239
  for (const [generateEnd, mapping] of map.getGeneratedOffsets(end)) {
239
240
  if ((0, language_core_1.isCodeActionsEnabled)(mapping.data)) {
240
- 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);
241
242
  break;
242
243
  }
243
244
  }
@@ -249,13 +250,13 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
249
250
  fixes = getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences);
250
251
  }
251
252
  fixes = fixes.map(fix => {
252
- 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);
253
254
  return fix;
254
255
  });
255
256
  return fixes;
256
257
  };
257
258
  languageService.getEncodedSemanticClassifications = (fileName, span, format) => {
258
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
259
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
259
260
  if (virtualFile) {
260
261
  let start;
261
262
  let end;
@@ -271,16 +272,14 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
271
272
  start = 0;
272
273
  end = 0;
273
274
  }
274
- if (isTsPlugin) {
275
- start += sourceFile.snapshot.getLength();
276
- end += sourceFile.snapshot.getLength();
277
- }
275
+ start += sourceFile.snapshot.getLength();
276
+ end += sourceFile.snapshot.getLength();
278
277
  const result = getEncodedSemanticClassifications(fileName, { start, length: end - start }, format);
279
278
  const spans = [];
280
279
  for (let i = 0; i < result.spans.length; i += 3) {
281
- 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())) {
282
281
  if ((0, language_core_1.isSemanticTokensEnabled)(mapping.data)) {
283
- 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())) {
284
283
  if ((0, language_core_1.isSemanticTokensEnabled)(mapping.data)) {
285
284
  spans.push(sourceStart, sourceEnd - sourceStart, result.spans[i + 2]);
286
285
  break;
@@ -299,18 +298,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
299
298
  };
300
299
  languageService.getSyntacticDiagnostics = (fileName) => {
301
300
  return getSyntacticDiagnostics(fileName)
302
- .map(diagnostic => transformDiagnostic(diagnostic))
303
- .filter(notEmpty);
301
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
302
+ .filter(utils_1.notEmpty);
304
303
  };
305
304
  languageService.getSemanticDiagnostics = (fileName) => {
306
305
  return getSemanticDiagnostics(fileName)
307
- .map(diagnostic => transformDiagnostic(diagnostic))
308
- .filter(notEmpty);
306
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
307
+ .filter(utils_1.notEmpty);
309
308
  };
310
309
  languageService.getSuggestionDiagnostics = (fileName) => {
311
310
  return getSuggestionDiagnostics(fileName)
312
- .map(diagnostic => transformDiagnostic(diagnostic))
313
- .filter(notEmpty);
311
+ .map(d => (0, transform_1.transformDiagnostic)(files, d))
312
+ .filter(utils_1.notEmpty);
314
313
  };
315
314
  languageService.getDefinitionAndBoundSpan = (fileName, position) => {
316
315
  const unresolved = linkedCodeFeatureWorker(fileName, position, language_core_1.isDefinitionEnabled, position => getDefinitionAndBoundSpan(fileName, position), function* (result) {
@@ -319,15 +318,15 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
319
318
  }
320
319
  });
321
320
  const textSpan = unresolved
322
- .map(s => transformSpan(fileName, s.textSpan, language_core_1.isDefinitionEnabled)?.textSpan)
323
- .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];
324
323
  if (!textSpan)
325
324
  return;
326
325
  const definitions = unresolved
327
326
  .map(s => s.definitions
328
- ?.map(s => transformDocumentSpan(s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
329
- .filter(notEmpty))
330
- .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)
331
330
  .flat();
332
331
  return {
333
332
  textSpan,
@@ -345,17 +344,17 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
345
344
  const resolved = unresolved
346
345
  .flat()
347
346
  .map(symbol => {
348
- const definition = transformDocumentSpan(symbol.definition, language_core_1.isDefinitionEnabled);
347
+ const definition = (0, transform_1.transformDocumentSpan)(files, symbol.definition, language_core_1.isDefinitionEnabled);
349
348
  if (definition) {
350
349
  return {
351
350
  definition,
352
351
  references: symbol.references
353
- .map(r => transformDocumentSpan(r, language_core_1.isReferencesEnabled))
354
- .filter(notEmpty),
352
+ .map(r => (0, transform_1.transformDocumentSpan)(files, r, language_core_1.isReferencesEnabled))
353
+ .filter(utils_1.notEmpty),
355
354
  };
356
355
  }
357
356
  })
358
- .filter(notEmpty);
357
+ .filter(utils_1.notEmpty);
359
358
  return (0, dedupe_1.dedupeReferencedSymbols)(resolved);
360
359
  };
361
360
  languageService.getDefinitionAtPosition = (fileName, position) => {
@@ -366,8 +365,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
366
365
  });
367
366
  const resolved = unresolved
368
367
  .flat()
369
- .map(s => transformDocumentSpan(s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
370
- .filter(notEmpty);
368
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isDefinitionEnabled, s.fileName !== fileName))
369
+ .filter(utils_1.notEmpty);
371
370
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
372
371
  };
373
372
  languageService.getTypeDefinitionAtPosition = (fileName, position) => {
@@ -378,8 +377,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
378
377
  });
379
378
  const resolved = unresolved
380
379
  .flat()
381
- .map(s => transformDocumentSpan(s, language_core_1.isTypeDefinitionEnabled))
382
- .filter(notEmpty);
380
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isTypeDefinitionEnabled))
381
+ .filter(utils_1.notEmpty);
383
382
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
384
383
  };
385
384
  languageService.getImplementationAtPosition = (fileName, position) => {
@@ -390,8 +389,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
390
389
  });
391
390
  const resolved = unresolved
392
391
  .flat()
393
- .map(s => transformDocumentSpan(s, language_core_1.isImplementationEnabled))
394
- .filter(notEmpty);
392
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isImplementationEnabled))
393
+ .filter(utils_1.notEmpty);
395
394
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
396
395
  };
397
396
  languageService.findRenameLocations = (fileName, position, findInStrings, findInComments, preferences) => {
@@ -402,8 +401,8 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
402
401
  });
403
402
  const resolved = unresolved
404
403
  .flat()
405
- .map(s => transformDocumentSpan(s, language_core_1.isRenameEnabled))
406
- .filter(notEmpty);
404
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isRenameEnabled))
405
+ .filter(utils_1.notEmpty);
407
406
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
408
407
  };
409
408
  languageService.getReferencesAtPosition = (fileName, position) => {
@@ -414,21 +413,21 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
414
413
  });
415
414
  const resolved = unresolved
416
415
  .flat()
417
- .map(s => transformDocumentSpan(s, language_core_1.isReferencesEnabled))
418
- .filter(notEmpty);
416
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isReferencesEnabled))
417
+ .filter(utils_1.notEmpty);
419
418
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
420
419
  };
421
420
  languageService.getCompletionsAtPosition = (fileName, position, options, formattingSettings) => {
422
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
421
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
423
422
  if (virtualFile) {
424
423
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
425
424
  if ((0, language_core_1.isCompletionEnabled)(mapping.data)) {
426
- const result = getCompletionsAtPosition(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0), options, formattingSettings);
425
+ const result = getCompletionsAtPosition(fileName, generateOffset + sourceFile.snapshot.getLength(), options, formattingSettings);
427
426
  if (result) {
428
427
  for (const entry of result.entries) {
429
- 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;
430
429
  }
431
- 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;
432
431
  }
433
432
  return result;
434
433
  }
@@ -442,13 +441,13 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
442
441
  const details = getCompletionEntryDetails(fileName, position, entryName, formatOptions, source, preferences, data);
443
442
  if (details?.codeActions) {
444
443
  for (const codeAction of details.codeActions) {
445
- 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);
446
445
  }
447
446
  }
448
447
  return details;
449
448
  };
450
449
  languageService.provideInlayHints = (fileName, span, preferences) => {
451
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
450
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
452
451
  if (virtualFile) {
453
452
  let start;
454
453
  let end;
@@ -464,14 +463,12 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
464
463
  start = 0;
465
464
  end = 0;
466
465
  }
467
- if (isTsPlugin) {
468
- start += sourceFile.snapshot.getLength();
469
- end += sourceFile.snapshot.getLength();
470
- }
466
+ start += sourceFile.snapshot.getLength();
467
+ end += sourceFile.snapshot.getLength();
471
468
  const result = provideInlayHints(fileName, { start, length: end - start }, preferences);
472
469
  const hints = [];
473
470
  for (const hint of result) {
474
- 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())) {
475
472
  if ((0, language_core_1.isInlayHintsEnabled)(mapping.data)) {
476
473
  hints.push({
477
474
  ...hint,
@@ -490,18 +487,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
490
487
  languageService.getFileReferences = (fileName) => {
491
488
  const unresolved = getFileReferences(fileName);
492
489
  const resolved = unresolved
493
- .map(s => transformDocumentSpan(s, language_core_1.isReferencesEnabled))
494
- .filter(notEmpty);
490
+ .map(s => (0, transform_1.transformDocumentSpan)(files, s, language_core_1.isReferencesEnabled))
491
+ .filter(utils_1.notEmpty);
495
492
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
496
493
  };
497
494
  function linkedCodeFeatureWorker(fileName, position, filter, worker, getLinkedCodes) {
498
495
  let results = [];
499
496
  const processedFilePositions = new Set();
500
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
497
+ const [virtualFile, sourceFile, map] = (0, utils_1.getVirtualFileAndMap)(files, fileName);
501
498
  if (virtualFile) {
502
499
  for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
503
500
  if (filter(mapping.data)) {
504
- process(fileName, generateOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
501
+ process(fileName, generateOffset + sourceFile.snapshot.getLength());
505
502
  }
506
503
  }
507
504
  }
@@ -519,167 +516,18 @@ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
519
516
  results = results.concat(result);
520
517
  for (const ref of getLinkedCodes(result)) {
521
518
  processedFilePositions.add(ref[0] + ':' + ref[1]);
522
- const [virtualFile, sourceFile] = getVirtualFileAndMap(ref[0]);
519
+ const [virtualFile, sourceFile] = (0, utils_1.getVirtualFileAndMap)(files, ref[0]);
523
520
  if (!virtualFile)
524
521
  continue;
525
- const linkedCodeMap = virtualFiles.getLinkedCodeMap(virtualFile);
522
+ const linkedCodeMap = files.getLinkedCodeMap(virtualFile);
526
523
  if (!linkedCodeMap)
527
524
  continue;
528
- for (const linkedCodeOffset of linkedCodeMap.getLinkedOffsets(ref[1] - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
529
- process(ref[0], linkedCodeOffset + (isTsPlugin ? sourceFile.snapshot.getLength() : 0));
530
- }
531
- }
532
- }
533
- }
534
- // transforms
535
- function transformCallHierarchyItem(item, filter) {
536
- const span = transformSpan(item.file, item.span, filter);
537
- const selectionSpan = transformSpan(item.file, item.selectionSpan, filter);
538
- return {
539
- ...item,
540
- span: span?.textSpan ?? { start: 0, length: 0 },
541
- selectionSpan: selectionSpan?.textSpan ?? { start: 0, length: 0 },
542
- };
543
- }
544
- function transformDiagnostic(diagnostic) {
545
- if (!transformedDiagnostics.has(diagnostic)) {
546
- if (diagnostic.start !== undefined && diagnostic.file) {
547
- transformedDiagnostics.set(diagnostic, undefined);
548
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(diagnostic.file?.fileName);
549
- if (virtualFile) {
550
- for (const [sourceOffset, mapping] of map.getSourceOffsets(diagnostic.start - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
551
- if ((0, language_core_1.shouldReportDiagnostics)(mapping.data)) {
552
- transformedDiagnostics.set(diagnostic, {
553
- ...diagnostic,
554
- start: sourceOffset,
555
- });
556
- break;
557
- }
558
- }
525
+ for (const linkedCodeOffset of linkedCodeMap.getLinkedOffsets(ref[1] - sourceFile.snapshot.getLength())) {
526
+ process(ref[0], linkedCodeOffset + sourceFile.snapshot.getLength());
559
527
  }
560
- else {
561
- transformedDiagnostics.set(diagnostic, diagnostic);
562
- }
563
- }
564
- else {
565
- transformedDiagnostics.set(diagnostic, diagnostic);
566
- }
567
- if (diagnostic.relatedInformation) {
568
- diagnostic.relatedInformation = diagnostic.relatedInformation
569
- .map(transformDiagnostic)
570
- .filter(notEmpty);
571
528
  }
572
529
  }
573
- return transformedDiagnostics.get(diagnostic);
574
- }
575
- function transformFileTextChanges(changes, filter) {
576
- const [_, source] = getVirtualFileAndMap(changes.fileName);
577
- if (source) {
578
- return {
579
- ...changes,
580
- fileName: source.fileName,
581
- textChanges: changes.textChanges.map(c => {
582
- const span = transformSpan(changes.fileName, c.span, filter);
583
- if (span) {
584
- return {
585
- ...c,
586
- span: span.textSpan,
587
- };
588
- }
589
- }).filter(notEmpty),
590
- };
591
- }
592
- else {
593
- return changes;
594
- }
595
- }
596
- function transformDocumentSpan(documentSpan, filter, shouldFallback) {
597
- let textSpan = transformSpan(documentSpan.fileName, documentSpan.textSpan, filter);
598
- if (!textSpan && shouldFallback) {
599
- const [virtualFile, source] = getVirtualFileAndMap(documentSpan.fileName);
600
- if (virtualFile) {
601
- textSpan = {
602
- fileName: source.fileName,
603
- textSpan: { start: 0, length: 0 },
604
- };
605
- }
606
- }
607
- if (!textSpan)
608
- return;
609
- const contextSpan = transformSpan(documentSpan.fileName, documentSpan.contextSpan, filter);
610
- const originalTextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalTextSpan, filter);
611
- const originalContextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalContextSpan, filter);
612
- return {
613
- ...documentSpan,
614
- fileName: textSpan.fileName,
615
- textSpan: textSpan.textSpan,
616
- contextSpan: contextSpan?.textSpan,
617
- originalFileName: originalTextSpan?.fileName,
618
- originalTextSpan: originalTextSpan?.textSpan,
619
- originalContextSpan: originalContextSpan?.textSpan,
620
- };
621
- }
622
- function transformSpan(fileName, textSpan, filter) {
623
- if (!fileName)
624
- return;
625
- if (!textSpan)
626
- return;
627
- const [virtualFile, sourceFile, map] = getVirtualFileAndMap(fileName);
628
- if (virtualFile) {
629
- for (const sourceStart of map.getSourceOffsets(textSpan.start - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
630
- if (filter(sourceStart[1].data)) {
631
- for (const sourceEnd of map.getSourceOffsets(textSpan.start + textSpan.length - (isTsPlugin ? sourceFile.snapshot.getLength() : 0))) {
632
- if (filter(sourceEnd[1].data)) {
633
- return {
634
- fileName: sourceFile.fileName,
635
- textSpan: {
636
- start: sourceStart[0],
637
- length: sourceEnd[0] - sourceStart[0],
638
- },
639
- };
640
- }
641
- }
642
- }
643
- }
644
- }
645
- else {
646
- return {
647
- fileName,
648
- textSpan,
649
- };
650
- }
651
- }
652
- function getVirtualFileAndMap(fileName) {
653
- if (isTsPlugin) {
654
- const sourceFile = virtualFiles.getSourceFile(fileName);
655
- if (sourceFile?.virtualFile) {
656
- for (const virtualFile of (0, language_core_1.forEachEmbeddedFile)(sourceFile.virtualFile[0])) {
657
- const ext = virtualFile.fileName.substring(fileName.length);
658
- if (virtualFile.typescript && (ext === '.d.ts' || ext.match(/^\.(js|ts)x?$/))) {
659
- for (const map of virtualFiles.getMaps(virtualFile)) {
660
- if (map[1][0] === sourceFile.snapshot) {
661
- return [virtualFile, sourceFile, map[1][1]];
662
- }
663
- }
664
- }
665
- }
666
- }
667
- }
668
- else {
669
- const [virtualFile, sourceFile] = virtualFiles.getVirtualFile(fileName);
670
- if (virtualFile) {
671
- for (const map of virtualFiles.getMaps(virtualFile)) {
672
- if (map[1][0] === sourceFile.snapshot) {
673
- return [virtualFile, sourceFile, map[1][1]];
674
- }
675
- }
676
- }
677
- }
678
- return [undefined, undefined, undefined];
679
530
  }
680
531
  }
681
532
  exports.decorateLanguageService = decorateLanguageService;
682
- function notEmpty(value) {
683
- return value !== null && value !== undefined;
684
- }
685
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
@@ -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.3",
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.3",
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.3"
21
+ "@volar/language-service": "2.0.0-alpha.4"
21
22
  },
22
- "gitHead": "0bb685a72cff180bb9b3420aaf3136c8e899c908"
23
+ "gitHead": "4d07249613d0cc5de4197e90c741a64adf92b84b"
23
24
  }