@volar/typescript 2.2.0-alpha.1 → 2.2.0-alpha.11
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/lib/common.d.ts +2 -0
- package/lib/common.js +19 -0
- package/lib/node/decorateLanguageService.js +105 -52
- package/lib/node/decorateLanguageServiceHost.d.ts +2 -2
- package/lib/node/decorateLanguageServiceHost.js +48 -53
- package/lib/node/decorateProgram.js +14 -5
- package/lib/node/dedupe.d.ts +0 -1
- package/lib/node/dedupe.js +1 -9
- package/lib/node/proxyCreateProgram.d.ts +2 -2
- package/lib/node/proxyCreateProgram.js +142 -94
- package/lib/node/transform.d.ts +3 -1
- package/lib/node/transform.js +32 -10
- package/lib/protocol/createProject.js +7 -3
- package/lib/quickstart/createAsyncLanguageServicePlugin.js +13 -3
- package/lib/quickstart/createLanguageServicePlugin.js +14 -3
- package/lib/quickstart/runTsc.d.ts +2 -1
- package/lib/quickstart/runTsc.js +11 -6
- package/lib/resolveModuleName.d.ts +1 -1
- package/lib/resolveModuleName.js +41 -24
- package/package.json +4 -4
- package/lib/documentRegistry.d.ts +0 -2
- package/lib/documentRegistry.js +0 -14
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type * as ts from 'typescript';
|
|
2
1
|
import { LanguagePlugin } from '@volar/language-core';
|
|
3
|
-
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
|
+
export declare function proxyCreateProgram(ts: typeof import('typescript'), original: typeof ts['createProgram'], getLanguagePlugins: (ts: typeof import('typescript'), options: ts.CreateProgramOptions) => LanguagePlugin[]): typeof import("typescript").createProgram;
|
|
@@ -1,117 +1,165 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.proxyCreateProgram = void 0;
|
|
4
|
-
const decorateProgram_1 = require("./decorateProgram");
|
|
5
4
|
const language_core_1 = require("@volar/language-core");
|
|
6
|
-
|
|
5
|
+
const resolveModuleName_1 = require("../resolveModuleName");
|
|
6
|
+
const decorateProgram_1 = require("./decorateProgram");
|
|
7
|
+
const common_1 = require("../common");
|
|
8
|
+
const arrayEqual = (a, b) => {
|
|
9
|
+
if (a.length !== b.length) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
for (let i = 0; i < a.length; i++) {
|
|
13
|
+
if (a[i] !== b[i]) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
};
|
|
19
|
+
const objectEqual = (a, b) => {
|
|
20
|
+
const keysA = Object.keys(a);
|
|
21
|
+
const keysB = Object.keys(b);
|
|
22
|
+
if (keysA.length !== keysB.length) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
for (const key of keysA) {
|
|
26
|
+
if (a[key] !== b[key]) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
function proxyCreateProgram(ts, original, getLanguagePlugins) {
|
|
33
|
+
const sourceFileSnapshots = new Map();
|
|
34
|
+
const parsedSourceFiles = new WeakMap();
|
|
35
|
+
let lastOptions;
|
|
36
|
+
let languagePlugins;
|
|
37
|
+
let language;
|
|
38
|
+
let moduleResolutionCache;
|
|
7
39
|
return new Proxy(original, {
|
|
8
40
|
apply: (target, thisArg, args) => {
|
|
9
41
|
const options = args[0];
|
|
10
42
|
assert(!!options.host, '!!options.host');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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]);
|
|
43
|
+
if (!lastOptions
|
|
44
|
+
|| !languagePlugins
|
|
45
|
+
|| !language
|
|
46
|
+
|| !arrayEqual(options.rootNames, lastOptions.rootNames)
|
|
47
|
+
|| !objectEqual(options.options, lastOptions.options)) {
|
|
48
|
+
moduleResolutionCache = ts.createModuleResolutionCache(options.host.getCurrentDirectory(), options.host.getCanonicalFileName, options.options);
|
|
49
|
+
lastOptions = options;
|
|
50
|
+
languagePlugins = getLanguagePlugins(ts, options);
|
|
51
|
+
language = (0, language_core_1.createLanguage)([
|
|
52
|
+
...languagePlugins,
|
|
53
|
+
common_1.fileLanguageIdProviderPlugin,
|
|
54
|
+
], ts.sys.useCaseSensitiveFileNames, fileName => {
|
|
55
|
+
if (!sourceFileSnapshots.has(fileName)) {
|
|
56
|
+
const sourceFileText = originalHost.readFile(fileName);
|
|
57
|
+
if (sourceFileText !== undefined) {
|
|
58
|
+
sourceFileSnapshots.set(fileName, [undefined, {
|
|
59
|
+
getChangeRange() {
|
|
60
|
+
return undefined;
|
|
61
|
+
},
|
|
62
|
+
getLength() {
|
|
63
|
+
return sourceFileText.length;
|
|
64
|
+
},
|
|
65
|
+
getText(start, end) {
|
|
66
|
+
return sourceFileText.substring(start, end);
|
|
67
|
+
},
|
|
68
|
+
}]);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
sourceFileSnapshots.set(fileName, [undefined, undefined]);
|
|
50
72
|
}
|
|
51
73
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
74
|
+
const snapshot = sourceFileSnapshots.get(fileName)?.[1];
|
|
75
|
+
if (snapshot) {
|
|
76
|
+
language.scripts.set(fileName, snapshot);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
language.scripts.delete(fileName);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const originalHost = options.host;
|
|
84
|
+
const extensions = languagePlugins
|
|
85
|
+
.map(plugin => plugin.typescript?.extraFileExtensions.map(({ extension }) => `.${extension}`) ?? [])
|
|
86
|
+
.flat();
|
|
55
87
|
options.host = { ...originalHost };
|
|
56
|
-
options.options.allowArbitraryExtensions = true;
|
|
57
88
|
options.host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
|
|
58
89
|
const originalSourceFile = originalHost.getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
if (!sourceFileSnapshots.has(fileName)
|
|
91
|
+
|| sourceFileSnapshots.get(fileName)?.[0] !== originalSourceFile) {
|
|
92
|
+
if (originalSourceFile) {
|
|
93
|
+
sourceFileSnapshots.set(fileName, [originalSourceFile, {
|
|
94
|
+
getChangeRange() {
|
|
95
|
+
return undefined;
|
|
96
|
+
},
|
|
97
|
+
getLength() {
|
|
98
|
+
return originalSourceFile.text.length;
|
|
99
|
+
},
|
|
100
|
+
getText(start, end) {
|
|
101
|
+
return originalSourceFile.text.substring(start, end);
|
|
102
|
+
},
|
|
103
|
+
}]);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
sourceFileSnapshots.set(fileName, [undefined, undefined]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!originalSourceFile) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!parsedSourceFiles.has(originalSourceFile)) {
|
|
113
|
+
const sourceScript = language.scripts.get(fileName);
|
|
114
|
+
assert(!!sourceScript, '!!sourceScript');
|
|
115
|
+
parsedSourceFiles.set(originalSourceFile, originalSourceFile);
|
|
116
|
+
if (sourceScript.generated?.languagePlugin.typescript) {
|
|
117
|
+
const { getServiceScript, getExtraServiceScripts } = sourceScript.generated.languagePlugin.typescript;
|
|
118
|
+
const serviceScript = getServiceScript(sourceScript.generated.root);
|
|
119
|
+
if (serviceScript) {
|
|
120
|
+
let patchedText = originalSourceFile.text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
|
|
121
|
+
let scriptKind = ts.ScriptKind.TS;
|
|
122
|
+
scriptKind = serviceScript.scriptKind;
|
|
123
|
+
patchedText += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
|
|
124
|
+
const parsedSourceFile = ts.createSourceFile(fileName, patchedText, languageVersionOrOptions, undefined, scriptKind);
|
|
125
|
+
// @ts-expect-error
|
|
126
|
+
parsedSourceFile.version = originalSourceFile.version;
|
|
127
|
+
parsedSourceFiles.set(originalSourceFile, parsedSourceFile);
|
|
128
|
+
}
|
|
129
|
+
if (getExtraServiceScripts) {
|
|
130
|
+
console.warn('getExtraServiceScripts() is not available in this use case.');
|
|
77
131
|
}
|
|
78
|
-
sourceFile2 = ts.createSourceFile(fileName, patchedText, 99, true, scriptKind);
|
|
79
|
-
// @ts-expect-error
|
|
80
|
-
sourceFile2.version = originalSourceFile.version;
|
|
81
|
-
parsedSourceFiles.set(originalSourceFile, sourceFile2);
|
|
82
132
|
}
|
|
83
|
-
return sourceFile2;
|
|
84
133
|
}
|
|
85
|
-
return originalSourceFile;
|
|
86
|
-
};
|
|
87
|
-
options.host.resolveModuleNameLiterals = (moduleNames, containingFile, redirectedReference, options) => {
|
|
88
|
-
return moduleNames.map(name => {
|
|
89
|
-
return resolveModuleName(name.text, containingFile, options, redirectedReference);
|
|
90
|
-
});
|
|
134
|
+
return parsedSourceFiles.get(originalSourceFile);
|
|
91
135
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
136
|
+
if (extensions.length) {
|
|
137
|
+
options.options.allowArbitraryExtensions = true;
|
|
138
|
+
const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, originalHost, language.plugins, fileName => language.scripts.get(fileName));
|
|
139
|
+
const resolveModuleNameLiterals = originalHost.resolveModuleNameLiterals;
|
|
140
|
+
const resolveModuleNames = originalHost.resolveModuleNames;
|
|
141
|
+
options.host.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, compilerOptions, ...rest) => {
|
|
142
|
+
if (resolveModuleNameLiterals && moduleLiterals.every(name => !extensions.some(ext => name.text.endsWith(ext)))) {
|
|
143
|
+
return resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, compilerOptions, ...rest);
|
|
144
|
+
}
|
|
145
|
+
return moduleLiterals.map(moduleLiteral => {
|
|
146
|
+
return resolveModuleName(moduleLiteral.text, containingFile, compilerOptions, moduleResolutionCache, redirectedReference);
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
options.host.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile) => {
|
|
150
|
+
if (resolveModuleNames && moduleNames.every(name => !extensions.some(ext => name.endsWith(ext)))) {
|
|
151
|
+
return resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile);
|
|
152
|
+
}
|
|
153
|
+
return moduleNames.map(moduleName => {
|
|
154
|
+
return resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionCache, redirectedReference).resolvedModule;
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const program = Reflect.apply(target, thisArg, args);
|
|
98
159
|
(0, decorateProgram_1.decorateProgram)(language, program);
|
|
99
160
|
// TODO: #128
|
|
100
|
-
program.__volar__ = {
|
|
161
|
+
program.__volar__ = { language };
|
|
101
162
|
return program;
|
|
102
|
-
function resolveModuleName(name, containingFile, options, redirectedReference) {
|
|
103
|
-
const resolved = ts.resolveModuleName(name, containingFile, options, moduleResolutionHost, originalHost.getModuleResolutionCache?.(), redirectedReference);
|
|
104
|
-
if (resolved.resolvedModule) {
|
|
105
|
-
for (let i = 0; i < arbitraryExtensions.length; i++) {
|
|
106
|
-
if (resolved.resolvedModule.resolvedFileName.endsWith(arbitraryExtensions[i])) {
|
|
107
|
-
const sourceFileName = resolved.resolvedModule.resolvedFileName.slice(0, -arbitraryExtensions[i].length) + extensions[i];
|
|
108
|
-
resolved.resolvedModule.resolvedFileName = sourceFileName;
|
|
109
|
-
resolved.resolvedModule.extension = extensions[i];
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return resolved;
|
|
114
|
-
}
|
|
115
163
|
},
|
|
116
164
|
});
|
|
117
165
|
}
|
package/lib/node/transform.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Language, CodeInformation, SourceMap, SourceScript } from '@volar/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
3
|
export declare function transformCallHierarchyItem(language: Language, item: ts.CallHierarchyItem, filter: (data: CodeInformation) => boolean): ts.CallHierarchyItem;
|
|
4
|
-
export declare function transformDiagnostic<T extends ts.Diagnostic>(language: Language, diagnostic: T): T | undefined;
|
|
4
|
+
export declare function transformDiagnostic<T extends ts.Diagnostic>(language: Language, diagnostic: T, isTsc: boolean): T | undefined;
|
|
5
|
+
export declare function fillSourceFileText(language: Language, sourceFile: ts.SourceFile): void;
|
|
5
6
|
export declare function transformFileTextChanges(language: Language, changes: ts.FileTextChanges, filter: (data: CodeInformation) => boolean): ts.FileTextChanges | undefined;
|
|
6
7
|
export declare function transformDocumentSpan<T extends ts.DocumentSpan>(language: Language, documentSpan: T, filter: (data: CodeInformation) => boolean, shouldFallback?: boolean): T | undefined;
|
|
7
8
|
export declare function transformSpan(language: Language, fileName: string | undefined, textSpan: ts.TextSpan | undefined, filter: (data: CodeInformation) => boolean): {
|
|
@@ -12,3 +13,4 @@ export declare function transformTextChange(sourceScript: SourceScript, map: Sou
|
|
|
12
13
|
export declare function transformTextSpan(sourceScript: SourceScript, map: SourceMap<CodeInformation>, textSpan: ts.TextSpan, filter: (data: CodeInformation) => boolean): ts.TextSpan | undefined;
|
|
13
14
|
export declare function toSourceOffset(sourceScript: SourceScript, map: SourceMap, position: number, filter: (data: CodeInformation) => boolean): number | undefined;
|
|
14
15
|
export declare function toGeneratedOffset(sourceScript: SourceScript, map: SourceMap, position: number, filter: (data: CodeInformation) => boolean): number | undefined;
|
|
16
|
+
export declare function forEachGeneratedOffset(sourceScript: SourceScript, map: SourceMap, position: number, filter: (data: CodeInformation) => boolean): Generator<number, void, unknown>;
|
package/lib/node/transform.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toGeneratedOffset = exports.toSourceOffset = exports.transformTextSpan = exports.transformTextChange = exports.transformSpan = exports.transformDocumentSpan = exports.transformFileTextChanges = exports.transformDiagnostic = exports.transformCallHierarchyItem = void 0;
|
|
3
|
+
exports.forEachGeneratedOffset = exports.toGeneratedOffset = exports.toSourceOffset = exports.transformTextSpan = exports.transformTextChange = exports.transformSpan = exports.transformDocumentSpan = exports.transformFileTextChanges = exports.fillSourceFileText = exports.transformDiagnostic = exports.transformCallHierarchyItem = void 0;
|
|
4
4
|
const language_core_1 = require("@volar/language-core");
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
6
|
const transformedDiagnostics = new WeakMap();
|
|
7
|
+
const transformedSourceFile = new WeakSet();
|
|
7
8
|
function transformCallHierarchyItem(language, item, filter) {
|
|
8
9
|
const span = transformSpan(language, item.file, item.span, filter);
|
|
9
10
|
const selectionSpan = transformSpan(language, item.file, item.selectionSpan, filter);
|
|
@@ -14,13 +15,13 @@ function transformCallHierarchyItem(language, item, filter) {
|
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
17
|
exports.transformCallHierarchyItem = transformCallHierarchyItem;
|
|
17
|
-
function transformDiagnostic(language, diagnostic) {
|
|
18
|
+
function transformDiagnostic(language, diagnostic, isTsc) {
|
|
18
19
|
if (!transformedDiagnostics.has(diagnostic)) {
|
|
19
20
|
transformedDiagnostics.set(diagnostic, undefined);
|
|
20
21
|
const { relatedInformation } = diagnostic;
|
|
21
22
|
if (relatedInformation) {
|
|
22
23
|
diagnostic.relatedInformation = relatedInformation
|
|
23
|
-
.map(d => transformDiagnostic(language, d))
|
|
24
|
+
.map(d => transformDiagnostic(language, d, isTsc))
|
|
24
25
|
.filter(utils_1.notEmpty);
|
|
25
26
|
}
|
|
26
27
|
if (diagnostic.file !== undefined
|
|
@@ -30,6 +31,9 @@ function transformDiagnostic(language, diagnostic) {
|
|
|
30
31
|
if (serviceScript) {
|
|
31
32
|
const sourceSpan = transformTextSpan(sourceScript, map, { start: diagnostic.start, length: diagnostic.length }, language_core_1.shouldReportDiagnostics);
|
|
32
33
|
if (sourceSpan) {
|
|
34
|
+
if (isTsc) {
|
|
35
|
+
fillSourceFileText(language, diagnostic.file);
|
|
36
|
+
}
|
|
33
37
|
transformedDiagnostics.set(diagnostic, {
|
|
34
38
|
...diagnostic,
|
|
35
39
|
start: sourceSpan.start,
|
|
@@ -48,6 +52,19 @@ function transformDiagnostic(language, diagnostic) {
|
|
|
48
52
|
return transformedDiagnostics.get(diagnostic);
|
|
49
53
|
}
|
|
50
54
|
exports.transformDiagnostic = transformDiagnostic;
|
|
55
|
+
// fix https://github.com/vuejs/language-tools/issues/4099 without `incremental`
|
|
56
|
+
function fillSourceFileText(language, sourceFile) {
|
|
57
|
+
if (transformedSourceFile.has(sourceFile)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
transformedSourceFile.add(sourceFile);
|
|
61
|
+
const [serviceScript, sourceScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
|
|
62
|
+
if (serviceScript) {
|
|
63
|
+
sourceFile.text = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength())
|
|
64
|
+
+ sourceFile.text.substring(sourceScript.snapshot.getLength());
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.fillSourceFileText = fillSourceFileText;
|
|
51
68
|
function transformFileTextChanges(language, changes, filter) {
|
|
52
69
|
const [_, source] = (0, utils_1.getServiceScript)(language, changes.fileName);
|
|
53
70
|
if (source) {
|
|
@@ -72,13 +89,10 @@ exports.transformFileTextChanges = transformFileTextChanges;
|
|
|
72
89
|
function transformDocumentSpan(language, documentSpan, filter, shouldFallback) {
|
|
73
90
|
let textSpan = transformSpan(language, documentSpan.fileName, documentSpan.textSpan, filter);
|
|
74
91
|
if (!textSpan && shouldFallback) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
textSpan
|
|
78
|
-
|
|
79
|
-
textSpan: { start: 0, length: 0 },
|
|
80
|
-
};
|
|
81
|
-
}
|
|
92
|
+
textSpan = {
|
|
93
|
+
fileName: documentSpan.fileName,
|
|
94
|
+
textSpan: { start: 0, length: 0 },
|
|
95
|
+
};
|
|
82
96
|
}
|
|
83
97
|
if (!textSpan) {
|
|
84
98
|
return;
|
|
@@ -158,4 +172,12 @@ function toGeneratedOffset(sourceScript, map, position, filter) {
|
|
|
158
172
|
}
|
|
159
173
|
}
|
|
160
174
|
exports.toGeneratedOffset = toGeneratedOffset;
|
|
175
|
+
function* forEachGeneratedOffset(sourceScript, map, position, filter) {
|
|
176
|
+
for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
|
|
177
|
+
if (filter(mapping.data)) {
|
|
178
|
+
yield generateOffset + sourceScript.snapshot.getLength();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
exports.forEachGeneratedOffset = forEachGeneratedOffset;
|
|
161
183
|
//# sourceMappingURL=transform.js.map
|
|
@@ -5,10 +5,14 @@ const language_core_1 = require("@volar/language-core");
|
|
|
5
5
|
const language_core_2 = require("@volar/language-core");
|
|
6
6
|
const path = require("path-browserify");
|
|
7
7
|
const resolveModuleName_1 = require("../resolveModuleName");
|
|
8
|
+
const common_1 = require("../common");
|
|
8
9
|
const scriptVersions = new Map();
|
|
9
10
|
const fsFileSnapshots = new Map();
|
|
10
11
|
function createTypeScriptLanguage(ts, languagePlugins, projectHost) {
|
|
11
|
-
const language = (0, language_core_1.createLanguage)(
|
|
12
|
+
const language = (0, language_core_1.createLanguage)([
|
|
13
|
+
...languagePlugins,
|
|
14
|
+
common_1.fileLanguageIdProviderPlugin,
|
|
15
|
+
], projectHost.useCaseSensitiveFileNames, scriptId => {
|
|
12
16
|
const fileName = projectHost.scriptIdToFileName(scriptId);
|
|
13
17
|
// opened files
|
|
14
18
|
let snapshot = projectHost.getScriptSnapshot(fileName);
|
|
@@ -29,7 +33,7 @@ function createTypeScriptLanguage(ts, languagePlugins, projectHost) {
|
|
|
29
33
|
snapshot = fsFileSnapshots.get(fileName)?.[1];
|
|
30
34
|
}
|
|
31
35
|
if (snapshot) {
|
|
32
|
-
language.scripts.set(scriptId,
|
|
36
|
+
language.scripts.set(scriptId, snapshot);
|
|
33
37
|
}
|
|
34
38
|
else {
|
|
35
39
|
language.scripts.delete(scriptId);
|
|
@@ -43,7 +47,7 @@ function createTypeScriptLanguage(ts, languagePlugins, projectHost) {
|
|
|
43
47
|
}
|
|
44
48
|
if (languagePlugins.some(language => language.typescript?.extraFileExtensions.length)) {
|
|
45
49
|
// TODO: can this share between monorepo packages?
|
|
46
|
-
const moduleCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), languageServiceHost.useCaseSensitiveFileNames ? s => s : s => s.toLowerCase(), languageServiceHost.getCompilationSettings());
|
|
50
|
+
const moduleCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), languageServiceHost.useCaseSensitiveFileNames?.() ? s => s : s => s.toLowerCase(), languageServiceHost.getCompilationSettings());
|
|
47
51
|
const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, languageServiceHost, languagePlugins, fileName => language.scripts.get(projectHost.fileNameToScriptId(fileName)));
|
|
48
52
|
let lastSysVersion = projectHost.getSystemVersion?.();
|
|
49
53
|
languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, sourceFile) => {
|
|
@@ -5,6 +5,7 @@ const decorateLanguageService_1 = require("../node/decorateLanguageService");
|
|
|
5
5
|
const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
|
|
6
6
|
const language_core_1 = require("@volar/language-core");
|
|
7
7
|
const createLanguageServicePlugin_1 = require("./createLanguageServicePlugin");
|
|
8
|
+
const common_1 = require("../common");
|
|
8
9
|
const externalFiles = new WeakMap();
|
|
9
10
|
const decoratedLanguageServices = new WeakSet();
|
|
10
11
|
const decoratedLanguageServiceHosts = new WeakSet();
|
|
@@ -52,17 +53,26 @@ function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePl
|
|
|
52
53
|
};
|
|
53
54
|
}
|
|
54
55
|
loadLanguagePlugins(ts, info).then(languagePlugins => {
|
|
55
|
-
const
|
|
56
|
+
const syncedScriptVersions = new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames);
|
|
57
|
+
const language = (0, language_core_1.createLanguage)([
|
|
58
|
+
...languagePlugins,
|
|
59
|
+
common_1.fileLanguageIdProviderPlugin,
|
|
60
|
+
], ts.sys.useCaseSensitiveFileNames, fileName => {
|
|
61
|
+
const version = getScriptVersion(fileName);
|
|
62
|
+
if (syncedScriptVersions.get(fileName) === version) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
syncedScriptVersions.set(fileName, version);
|
|
56
66
|
const snapshot = getScriptSnapshot(fileName);
|
|
57
67
|
if (snapshot) {
|
|
58
|
-
language.scripts.set(fileName,
|
|
68
|
+
language.scripts.set(fileName, snapshot);
|
|
59
69
|
}
|
|
60
70
|
else {
|
|
61
71
|
language.scripts.delete(fileName);
|
|
62
72
|
}
|
|
63
73
|
});
|
|
64
74
|
(0, decorateLanguageService_1.decorateLanguageService)(language, info.languageService);
|
|
65
|
-
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(language, info.languageServiceHost
|
|
75
|
+
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
|
|
66
76
|
info.project.markAsDirty();
|
|
67
77
|
initialized = true;
|
|
68
78
|
});
|
|
@@ -4,6 +4,7 @@ exports.arrayItemsEqual = exports.createLanguageServicePlugin = void 0;
|
|
|
4
4
|
const decorateLanguageService_1 = require("../node/decorateLanguageService");
|
|
5
5
|
const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
|
|
6
6
|
const language_core_1 = require("@volar/language-core");
|
|
7
|
+
const common_1 = require("../common");
|
|
7
8
|
const externalFiles = new WeakMap();
|
|
8
9
|
const projectExternalFileExtensions = new WeakMap();
|
|
9
10
|
const decoratedLanguageServices = new WeakSet();
|
|
@@ -23,17 +24,27 @@ function createLanguageServicePlugin(loadLanguagePlugins) {
|
|
|
23
24
|
.flat();
|
|
24
25
|
projectExternalFileExtensions.set(info.project, extensions);
|
|
25
26
|
const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
|
|
26
|
-
const
|
|
27
|
+
const getScriptVersion = info.languageServiceHost.getScriptVersion.bind(info.languageServiceHost);
|
|
28
|
+
const syncedScriptVersions = new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames);
|
|
29
|
+
const language = (0, language_core_1.createLanguage)([
|
|
30
|
+
...languagePlugins,
|
|
31
|
+
common_1.fileLanguageIdProviderPlugin,
|
|
32
|
+
], ts.sys.useCaseSensitiveFileNames, fileName => {
|
|
33
|
+
const version = getScriptVersion(fileName);
|
|
34
|
+
if (syncedScriptVersions.get(fileName) === version) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
syncedScriptVersions.set(fileName, version);
|
|
27
38
|
const snapshot = getScriptSnapshot(fileName);
|
|
28
39
|
if (snapshot) {
|
|
29
|
-
language.scripts.set(fileName,
|
|
40
|
+
language.scripts.set(fileName, snapshot);
|
|
30
41
|
}
|
|
31
42
|
else {
|
|
32
43
|
language.scripts.delete(fileName);
|
|
33
44
|
}
|
|
34
45
|
});
|
|
35
46
|
(0, decorateLanguageService_1.decorateLanguageService)(language, info.languageService);
|
|
36
|
-
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(language, info.languageServiceHost
|
|
47
|
+
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
|
|
37
48
|
}
|
|
38
49
|
return info.languageService;
|
|
39
50
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type * as ts from 'typescript';
|
|
2
2
|
import type { LanguagePlugin } from '@volar/language-core';
|
|
3
3
|
export declare let getLanguagePlugins: (ts: typeof import('typescript'), options: ts.CreateProgramOptions) => LanguagePlugin[];
|
|
4
|
-
export declare
|
|
4
|
+
export declare let getLanguageId: (fileName: string) => string;
|
|
5
|
+
export declare function runTsc(tscPath: string, extensions: string[], _getLanguagePlugins: typeof getLanguagePlugins, _getLanguageId: typeof getLanguageId): void;
|
package/lib/quickstart/runTsc.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runTsc = exports.getLanguagePlugins = void 0;
|
|
3
|
+
exports.runTsc = exports.getLanguageId = exports.getLanguagePlugins = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
let getLanguagePlugins = () => [];
|
|
6
6
|
exports.getLanguagePlugins = getLanguagePlugins;
|
|
7
|
-
|
|
7
|
+
let getLanguageId = () => 'ts';
|
|
8
|
+
exports.getLanguageId = getLanguageId;
|
|
9
|
+
function runTsc(tscPath, extensions, _getLanguagePlugins, _getLanguageId) {
|
|
8
10
|
exports.getLanguagePlugins = _getLanguagePlugins;
|
|
11
|
+
exports.getLanguageId = _getLanguageId;
|
|
9
12
|
const proxyApiPath = require.resolve('../node/proxyCreateProgram');
|
|
10
13
|
const readFileSync = fs.readFileSync;
|
|
11
14
|
fs.readFileSync = (...args) => {
|
|
@@ -18,10 +21,12 @@ function runTsc(tscPath, extensions, _getLanguagePlugins) {
|
|
|
18
21
|
tsc = replace(tsc, /allSupportedExtensions = .*(?=;)/, s => s + `.concat([[${extsText}]])`);
|
|
19
22
|
// proxy createProgram
|
|
20
23
|
tsc = replace(tsc, /function createProgram\(.+\) {/, s => `var createProgram = require(${JSON.stringify(proxyApiPath)}).proxyCreateProgram(`
|
|
21
|
-
+
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
+ [
|
|
25
|
+
`new Proxy({}, { get(_target, p, _receiver) { return eval(p); } } )`,
|
|
26
|
+
`_createProgram`,
|
|
27
|
+
`require(${JSON.stringify(__filename)}).getLanguagePlugins`,
|
|
28
|
+
`require(${JSON.stringify(__filename)}).getLanguageId`,
|
|
29
|
+
].join(', ')
|
|
25
30
|
+ `);\n`
|
|
26
31
|
+ s.replace('createProgram', '_createProgram'));
|
|
27
32
|
return tsc;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { LanguagePlugin, SourceScript } from '@volar/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export declare function createResolveModuleName(ts: typeof import('typescript'),
|
|
3
|
+
export declare function createResolveModuleName(ts: typeof import('typescript'), host: ts.ModuleResolutionHost, languagePlugins: LanguagePlugin<any>[], getSourceScript: (fileName: string) => SourceScript | undefined): (moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions, cache?: ts.ModuleResolutionCache, redirectedReference?: ts.ResolvedProjectReference, resolutionMode?: ts.ResolutionMode) => ts.ResolvedModuleWithFailedLookupLocations;
|
package/lib/resolveModuleName.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createResolveModuleName = void 0;
|
|
4
|
-
function createResolveModuleName(ts,
|
|
5
|
-
const
|
|
4
|
+
function createResolveModuleName(ts, host, languagePlugins, getSourceScript) {
|
|
5
|
+
const toSourceFileInfo = new Map();
|
|
6
6
|
const moduleResolutionHost = {
|
|
7
|
-
readFile:
|
|
8
|
-
directoryExists:
|
|
9
|
-
realpath:
|
|
10
|
-
getCurrentDirectory:
|
|
11
|
-
getDirectories:
|
|
12
|
-
useCaseSensitiveFileNames:
|
|
7
|
+
readFile: host.readFile.bind(host),
|
|
8
|
+
directoryExists: host.directoryExists?.bind(host),
|
|
9
|
+
realpath: host.realpath?.bind(host),
|
|
10
|
+
getCurrentDirectory: host.getCurrentDirectory?.bind(host),
|
|
11
|
+
getDirectories: host.getDirectories?.bind(host),
|
|
12
|
+
useCaseSensitiveFileNames: typeof host.useCaseSensitiveFileNames === 'function'
|
|
13
|
+
? host.useCaseSensitiveFileNames.bind(host)
|
|
14
|
+
: host.useCaseSensitiveFileNames,
|
|
13
15
|
fileExists(fileName) {
|
|
14
16
|
for (const { typescript } of languagePlugins) {
|
|
15
17
|
if (!typescript) {
|
|
@@ -17,36 +19,51 @@ function createResolveModuleName(ts, languageServiceHost, languagePlugins, getSo
|
|
|
17
19
|
}
|
|
18
20
|
for (const { extension } of typescript.extraFileExtensions) {
|
|
19
21
|
if (fileName.endsWith(`.d.${extension}.ts`)) {
|
|
20
|
-
const
|
|
21
|
-
if (fileExists(
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const sourceFileName = fileName.slice(0, -`.d.${extension}.ts`.length) + `.${extension}`;
|
|
23
|
+
if (fileExists(sourceFileName)) {
|
|
24
|
+
const sourceScript = getSourceScript(sourceFileName);
|
|
25
|
+
if (sourceScript?.generated) {
|
|
26
|
+
const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
|
|
27
|
+
if (serviceScript) {
|
|
28
|
+
const dtsPath = sourceFileName + '.d.ts';
|
|
29
|
+
if ((serviceScript.extension === '.js' || serviceScript.extension === '.jsx') && fileExists(dtsPath)) {
|
|
30
|
+
toSourceFileInfo.set(fileName, {
|
|
31
|
+
sourceFileName: dtsPath,
|
|
32
|
+
extension: '.ts',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
toSourceFileInfo.set(fileName, {
|
|
37
|
+
sourceFileName,
|
|
38
|
+
extension: serviceScript.extension,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
24
44
|
}
|
|
25
45
|
}
|
|
26
46
|
}
|
|
27
47
|
}
|
|
28
|
-
return
|
|
48
|
+
return host.fileExists(fileName);
|
|
29
49
|
},
|
|
30
50
|
};
|
|
31
51
|
return (moduleName, containingFile, compilerOptions, cache, redirectedReference, resolutionMode) => {
|
|
32
52
|
const result = ts.resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost, cache, redirectedReference, resolutionMode);
|
|
33
|
-
if (result.resolvedModule
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (serviceScript) {
|
|
39
|
-
result.resolvedModule.extension = serviceScript.extension;
|
|
40
|
-
}
|
|
53
|
+
if (result.resolvedModule) {
|
|
54
|
+
const sourceFileInfo = toSourceFileInfo.get(result.resolvedModule.resolvedFileName);
|
|
55
|
+
if (sourceFileInfo) {
|
|
56
|
+
result.resolvedModule.resolvedFileName = sourceFileInfo.sourceFileName;
|
|
57
|
+
result.resolvedModule.extension = sourceFileInfo.extension;
|
|
41
58
|
}
|
|
42
59
|
}
|
|
43
|
-
|
|
60
|
+
toSourceFileInfo.clear();
|
|
44
61
|
return result;
|
|
45
62
|
};
|
|
46
63
|
// fix https://github.com/vuejs/language-tools/issues/3332
|
|
47
64
|
function fileExists(fileName) {
|
|
48
|
-
if (
|
|
49
|
-
const fileSize = ts.sys.getFileSize?.(fileName) ??
|
|
65
|
+
if (host.fileExists(fileName)) {
|
|
66
|
+
const fileSize = ts.sys.getFileSize?.(fileName) ?? host.readFile(fileName)?.length ?? 0;
|
|
50
67
|
return fileSize < 4 * 1024 * 1024;
|
|
51
68
|
}
|
|
52
69
|
return false;
|