@volar/typescript 2.0.0-alpha.0 → 2.0.0-alpha.10

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.
@@ -116,12 +116,12 @@ function decorateLanguageServiceHost(virtualFiles, languageServiceHost, ts, exts
116
116
  const snapshot = getScriptSnapshot(fileName);
117
117
  if (snapshot) {
118
118
  extraProjectVersion++;
119
- const sourceFile = virtualFiles.updateSourceFile(fileName, snapshot, (0, language_service_1.resolveCommonLanguageId)(fileName));
119
+ const sourceFile = virtualFiles.updateSourceFile(fileName, (0, language_service_1.resolveCommonLanguageId)(fileName), snapshot);
120
120
  if (sourceFile.virtualFile) {
121
121
  const text = snapshot.getText(0, snapshot.getLength());
122
122
  let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
123
123
  for (const file of (0, language_core_1.forEachEmbeddedFile)(sourceFile.virtualFile[0])) {
124
- const ext = file.id.substring(fileName.length);
124
+ const ext = file.fileName.substring(fileName.length);
125
125
  if (file.typescript && (ext === '.d.ts' || ext.match(/^\.(js|ts)x?$/))) {
126
126
  extension = ext;
127
127
  scriptKind = file.typescript.scriptKind;
@@ -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 sourceFileToSnapshotMap = new WeakMap();
12
+ const files = (0, language_core_1.createFileProvider)(getLanguagePlugins(ts, options), ts.sys.useCaseSensitiveFileNames, fileName => {
13
+ let snapshot;
14
+ assert(originalSourceFiles.has(fileName), `originalSourceFiles.has(${fileName})`);
15
+ const sourceFile = originalSourceFiles.get(fileName);
16
+ if (sourceFile) {
17
+ snapshot = sourceFileToSnapshotMap.get(sourceFile);
18
+ if (!snapshot) {
19
+ snapshot = {
20
+ getChangeRange() {
21
+ return undefined;
22
+ },
23
+ getLength() {
24
+ return sourceFile.text.length;
25
+ },
26
+ getText(start, end) {
27
+ return sourceFile.text.substring(start, end);
28
+ },
29
+ };
30
+ sourceFileToSnapshotMap.set(sourceFile, snapshot);
31
+ }
32
+ }
33
+ if (snapshot) {
34
+ files.updateSourceFile(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
35
+ }
36
+ else {
37
+ files.deleteSourceFile(fileName);
38
+ }
39
+ });
40
+ const originalSourceFiles = new Map();
41
+ const parsedSourceFiles = new WeakMap();
42
+ const arbitraryExtensions = extensions.map(ext => `.d${ext}.ts`);
43
+ const originalHost = options.host;
44
+ const moduleResolutionHost = {
45
+ ...originalHost,
46
+ fileExists(fileName) {
47
+ for (let i = 0; i < arbitraryExtensions.length; i++) {
48
+ if (fileName.endsWith(arbitraryExtensions[i])) {
49
+ return originalHost.fileExists(fileName.slice(0, -arbitraryExtensions[i].length) + extensions[i]);
50
+ }
51
+ }
52
+ return originalHost.fileExists(fileName);
53
+ },
54
+ };
55
+ options.host = { ...originalHost };
56
+ options.options.allowArbitraryExtensions = true;
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[0] >= sourceStart[0] && 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
@@ -8,8 +8,7 @@ const utilities_1 = require("../typescript/utilities");
8
8
  const scriptVersions = new Map();
9
9
  const fsFileSnapshots = new Map();
10
10
  function createLanguage(ts, sys, languages, configFileName, projectHost) {
11
- const files = (0, language_core_1.createFileProvider)(languages, sys.useCaseSensitiveFileNames, (id) => {
12
- const fileName = projectHost.getFileName(id);
11
+ const files = (0, language_core_1.createFileProvider)(languages, sys.useCaseSensitiveFileNames, fileName => {
13
12
  // opened files
14
13
  let snapshot = projectHost.getScriptSnapshot(fileName);
15
14
  if (!snapshot) {
@@ -29,10 +28,10 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
29
28
  snapshot = fsFileSnapshots.get(fileName)?.[1];
30
29
  }
31
30
  if (snapshot) {
32
- files.updateSourceFile(id, snapshot, projectHost.getLanguageId(id));
31
+ files.updateSourceFile(fileName, projectHost.getLanguageId(fileName), snapshot);
33
32
  }
34
33
  else {
35
- files.deleteSourceFile(id);
34
+ files.deleteSourceFile(fileName);
36
35
  }
37
36
  });
38
37
  let languageServiceHost = createLanguageServiceHost();
@@ -95,7 +94,6 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
95
94
  ...sys,
96
95
  getCurrentDirectory: projectHost.getCurrentDirectory,
97
96
  getCompilationSettings: projectHost.getCompilationSettings,
98
- getCancellationToken: projectHost.getCancellationToken,
99
97
  getLocalizedDiagnosticMessages: projectHost.getLocalizedDiagnosticMessages,
100
98
  getProjectReferences: projectHost.getProjectReferences,
101
99
  getDefaultLibFileName: (options) => {
@@ -153,9 +151,9 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
153
151
  };
154
152
  }, sys?.realpath ? (path => sys.realpath(path)) : (path => path));
155
153
  matches = matches.map(match => {
156
- const [_, source] = files.getVirtualFile(projectHost.getFileId(match));
154
+ const [_, source] = files.getVirtualFile(match);
157
155
  if (source) {
158
- return projectHost.getFileName(source.id);
156
+ return source.fileName;
159
157
  }
160
158
  return match;
161
159
  });
@@ -174,11 +172,11 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
174
172
  },
175
173
  getScriptKind(fileName) {
176
174
  syncSourceFile(fileName);
177
- const virtualFile = files.getVirtualFile(projectHost.getFileId(fileName))[0];
175
+ const virtualFile = files.getVirtualFile(fileName)[0];
178
176
  if (virtualFile?.typescript) {
179
177
  return virtualFile.typescript.scriptKind;
180
178
  }
181
- const sourceFile = files.getSourceFile(projectHost.getFileId(fileName));
179
+ const sourceFile = files.getSourceFile(fileName);
182
180
  if (sourceFile?.virtualFile) {
183
181
  return ts.ScriptKind.Deferred;
184
182
  }
@@ -209,7 +207,7 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
209
207
  for (const language of languages) {
210
208
  const sourceFileName = language.typescript?.resolveSourceFileName(tsFileName);
211
209
  if (sourceFileName) {
212
- files.getSourceFile(projectHost.getFileId(sourceFileName)); // trigger sync
210
+ files.getSourceFile(sourceFileName); // trigger sync
213
211
  }
214
212
  }
215
213
  }
@@ -223,13 +221,12 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
223
221
  const newOtherVirtualFileSnapshots = new Set();
224
222
  const tsFileNamesSet = new Set();
225
223
  for (const fileName of projectHost.getScriptFileNames()) {
226
- const uri = projectHost.getFileId(fileName);
227
- const sourceFile = files.getSourceFile(uri);
224
+ const sourceFile = files.getSourceFile(fileName);
228
225
  if (sourceFile?.virtualFile) {
229
226
  for (const file of (0, language_core_2.forEachEmbeddedFile)(sourceFile.virtualFile[0])) {
230
227
  if (file.typescript) {
231
228
  newTsVirtualFileSnapshots.add(file.snapshot);
232
- tsFileNamesSet.add(projectHost.getFileName(file.id)); // virtual .ts
229
+ tsFileNamesSet.add(file.fileName); // virtual .ts
233
230
  }
234
231
  else {
235
232
  newOtherVirtualFileSnapshots.add(file.snapshot);
@@ -256,12 +253,11 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
256
253
  }
257
254
  function getScriptSnapshot(fileName) {
258
255
  syncSourceFile(fileName);
259
- const uri = projectHost.getFileId(fileName);
260
- const virtualFile = files.getVirtualFile(uri)[0];
256
+ const virtualFile = files.getVirtualFile(fileName)[0];
261
257
  if (virtualFile) {
262
258
  return virtualFile.snapshot;
263
259
  }
264
- const sourceFile = files.getSourceFile(uri);
260
+ const sourceFile = files.getSourceFile(fileName);
265
261
  if (sourceFile && !sourceFile.virtualFile) {
266
262
  return sourceFile.snapshot;
267
263
  }
@@ -272,7 +268,7 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
272
268
  scriptVersions.set(fileName, { lastVersion: 0, map: new WeakMap() });
273
269
  }
274
270
  const version = scriptVersions.get(fileName);
275
- const virtualFile = files.getVirtualFile(projectHost.getFileId(fileName))[0];
271
+ const virtualFile = files.getVirtualFile(fileName)[0];
276
272
  if (virtualFile) {
277
273
  if (!version.map.has(virtualFile.snapshot)) {
278
274
  version.map.set(virtualFile.snapshot, version.lastVersion++);
@@ -281,7 +277,7 @@ function createLanguage(ts, sys, languages, configFileName, projectHost) {
281
277
  }
282
278
  const isOpenedFile = !!projectHost.getScriptSnapshot(fileName);
283
279
  if (isOpenedFile) {
284
- const sourceFile = files.getSourceFile(projectHost.getFileId(fileName));
280
+ const sourceFile = files.getSourceFile(fileName);
285
281
  if (sourceFile && !sourceFile.virtualFile) {
286
282
  if (!version.map.has(sourceFile.snapshot)) {
287
283
  version.map.set(sourceFile.snapshot, version.lastVersion++);
@@ -1,6 +1,3 @@
1
1
  import { type FileProvider } from '@volar/language-core';
2
2
  import type * as ts from 'typescript/lib/tsserverlibrary';
3
- export declare function getProgram(ts: typeof import('typescript/lib/tsserverlibrary'), files: FileProvider, { getFileId, getFileName }: {
4
- getFileId(fileName: string): string;
5
- getFileName(id: string): string;
6
- }, ls: ts.LanguageService, sys: ts.System): ts.Program;
3
+ export declare function getProgram(ts: typeof import('typescript/lib/tsserverlibrary'), files: FileProvider, ls: ts.LanguageService, sys: ts.System): ts.Program;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getProgram = void 0;
4
4
  const language_core_1 = require("@volar/language-core");
5
- function getProgram(ts, files, { getFileId, getFileName }, ls, sys) {
5
+ function getProgram(ts, files, ls, sys) {
6
6
  const proxy = {
7
7
  getRootFileNames,
8
8
  emit,
@@ -50,8 +50,7 @@ function getProgram(ts, files, { getFileId, getFileName }, ls, sys) {
50
50
  }
51
51
  function getSourceFileDiagnosticsWorker(sourceFile, cancellationToken, api) {
52
52
  if (sourceFile) {
53
- const uri = getFileId(sourceFile.fileName);
54
- const [virtualFile, source] = files.getVirtualFile(uri);
53
+ const [virtualFile, source] = files.getVirtualFile(sourceFile.fileName);
55
54
  if (virtualFile && source) {
56
55
  if (!virtualFile.mappings.some(mapping => (0, language_core_1.isDiagnosticsEnabled)(mapping.data)))
57
56
  return [];
@@ -79,11 +78,9 @@ function getProgram(ts, files, { getFileId, getFileName }, ls, sys) {
79
78
  if (diagnostic.file !== undefined
80
79
  && diagnostic.start !== undefined
81
80
  && diagnostic.length !== undefined) {
82
- const uri = getFileId(diagnostic.file.fileName);
83
- const [virtualFile, source] = files.getVirtualFile(uri);
81
+ const [virtualFile, source] = files.getVirtualFile(diagnostic.file.fileName);
84
82
  if (virtualFile && source) {
85
- const sourceFileName = getFileName(source.id);
86
- if (sys.fileExists?.(sourceFileName) === false)
83
+ if (sys.fileExists?.(source.fileName) === false)
87
84
  continue;
88
85
  for (const [_, [sourceSnapshot, map]] of files.getMaps(virtualFile)) {
89
86
  if (sourceSnapshot !== source.snapshot)
@@ -94,7 +91,7 @@ function getProgram(ts, files, { getFileId, getFileName }, ls, sys) {
94
91
  for (const end of map.getSourceOffsets(diagnostic.start + diagnostic.length)) {
95
92
  if (!(0, language_core_1.shouldReportDiagnostics)(end[1].data))
96
93
  continue;
97
- onMapping(diagnostic, sourceFileName, start[0], end[0], source.snapshot.getText(0, source.snapshot.getLength()));
94
+ onMapping(diagnostic, source.fileName, start[0], end[0], source.snapshot.getText(0, source.snapshot.getLength()));
98
95
  break;
99
96
  }
100
97
  break;
@@ -118,8 +115,7 @@ function getProgram(ts, files, { getFileId, getFileName }, ls, sys) {
118
115
  : undefined;
119
116
  if (!file) {
120
117
  if (docText === undefined) {
121
- const uri = getFileId(fileName);
122
- const snapshot = files.getSourceFile(uri)?.snapshot;
118
+ const snapshot = files.getSourceFile(fileName)?.snapshot;
123
119
  if (snapshot) {
124
120
  docText = snapshot.getText(0, snapshot.getLength());
125
121
  }
@@ -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;