@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.
- package/index.d.ts +2 -1
- package/index.js +2 -1
- package/lib/node/decorateLanguageService.d.ts +1 -1
- package/lib/node/decorateLanguageService.js +127 -242
- package/lib/node/decorateLanguageServiceHost.js +2 -2
- package/lib/node/decorateProgram.d.ts +3 -0
- package/lib/node/decorateProgram.js +48 -0
- package/lib/node/proxyCreateProgram.d.ts +3 -0
- package/lib/node/proxyCreateProgram.js +122 -0
- package/lib/node/transform.d.ts +10 -0
- package/lib/node/transform.js +137 -0
- package/lib/node/utils.d.ts +3 -0
- package/lib/node/utils.js +26 -0
- package/lib/protocol/createProject.js +14 -18
- package/lib/protocol/getProgram.d.ts +1 -4
- package/lib/protocol/getProgram.js +6 -10
- package/lib/starters/createAsyncTSServerPlugin.d.ts +3 -0
- package/lib/starters/createAsyncTSServerPlugin.js +82 -0
- package/lib/starters/createTSServerPlugin.d.ts +7 -0
- package/lib/starters/createTSServerPlugin.js +60 -0
- package/lib/starters/runTsc.d.ts +4 -0
- package/lib/starters/runTsc.js +49 -0
- package/package.json +5 -4
|
@@ -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,
|
|
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.
|
|
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,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,
|
|
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(
|
|
31
|
+
files.updateSourceFile(fileName, projectHost.getLanguageId(fileName), snapshot);
|
|
33
32
|
}
|
|
34
33
|
else {
|
|
35
|
-
files.deleteSourceFile(
|
|
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(
|
|
154
|
+
const [_, source] = files.getVirtualFile(match);
|
|
157
155
|
if (source) {
|
|
158
|
-
return
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
83
|
-
const [virtualFile, source] = files.getVirtualFile(uri);
|
|
81
|
+
const [virtualFile, source] = files.getVirtualFile(diagnostic.file.fileName);
|
|
84
82
|
if (virtualFile && source) {
|
|
85
|
-
|
|
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,
|
|
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
|
|
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;
|