@volar/typescript 2.2.0-alpha.1 → 2.2.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/lib/node/decorateLanguageService.js +36 -18
- 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 +138 -94
- package/lib/node/transform.d.ts +2 -1
- package/lib/node/transform.js +24 -10
- package/lib/protocol/createProject.js +1 -1
- package/lib/quickstart/createAsyncLanguageServicePlugin.d.ts +1 -1
- package/lib/quickstart/createAsyncLanguageServicePlugin.js +3 -3
- package/lib/quickstart/createLanguageServicePlugin.d.ts +1 -1
- package/lib/quickstart/createLanguageServicePlugin.js +3 -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
|
@@ -29,7 +29,7 @@ function decorateLanguageService(language, languageService) {
|
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
// methods
|
|
32
|
-
const { findReferences, findRenameLocations, getCompletionEntryDetails, getCompletionsAtPosition, getDefinitionAndBoundSpan, getDefinitionAtPosition, getFileReferences, getFormattingEditsForDocument, getFormattingEditsForRange, getFormattingEditsAfterKeystroke, getImplementationAtPosition, getLinkedEditingRangeAtPosition, getQuickInfoAtPosition, getReferencesAtPosition, getSemanticDiagnostics, getSyntacticDiagnostics, getSuggestionDiagnostics, getTypeDefinitionAtPosition, getEncodedSemanticClassifications, getDocumentHighlights, getApplicableRefactors, getEditsForFileRename, getEditsForRefactor, getRenameInfo, getCodeFixesAtPosition, prepareCallHierarchy, provideCallHierarchyIncomingCalls, provideCallHierarchyOutgoingCalls, provideInlayHints, organizeImports, } = languageService;
|
|
32
|
+
const { findReferences, findRenameLocations, getCompletionEntryDetails, getCompletionsAtPosition, getDefinitionAndBoundSpan, getDefinitionAtPosition, getFileReferences, getFormattingEditsForDocument, getFormattingEditsForRange, getFormattingEditsAfterKeystroke, getImplementationAtPosition, getLinkedEditingRangeAtPosition, getQuickInfoAtPosition, getSignatureHelpItems, getReferencesAtPosition, getSemanticDiagnostics, getSyntacticDiagnostics, getSuggestionDiagnostics, getTypeDefinitionAtPosition, getEncodedSemanticClassifications, getDocumentHighlights, getApplicableRefactors, getEditsForFileRename, getEditsForRefactor, getRenameInfo, getCodeFixesAtPosition, prepareCallHierarchy, provideCallHierarchyIncomingCalls, provideCallHierarchyOutgoingCalls, provideInlayHints, organizeImports, } = languageService;
|
|
33
33
|
languageService.getFormattingEditsForDocument = (fileName, options) => {
|
|
34
34
|
const [serviceScript, sourceScript, map] = (0, utils_1.getServiceScript)(language, fileName);
|
|
35
35
|
if (serviceScript) {
|
|
@@ -200,6 +200,27 @@ function decorateLanguageService(language, languageService) {
|
|
|
200
200
|
return getQuickInfoAtPosition(fileName, position);
|
|
201
201
|
}
|
|
202
202
|
};
|
|
203
|
+
languageService.getSignatureHelpItems = (fileName, position, options) => {
|
|
204
|
+
const [serviceScript, sourceScript, map] = (0, utils_1.getServiceScript)(language, fileName);
|
|
205
|
+
if (serviceScript) {
|
|
206
|
+
const generatePosition = (0, transform_1.toGeneratedOffset)(sourceScript, map, position, language_core_1.isSignatureHelpEnabled);
|
|
207
|
+
if (generatePosition !== undefined) {
|
|
208
|
+
const result = getSignatureHelpItems(fileName, generatePosition, options);
|
|
209
|
+
if (result) {
|
|
210
|
+
const applicableSpan = (0, transform_1.transformTextSpan)(sourceScript, map, result.applicableSpan, language_core_1.isSignatureHelpEnabled);
|
|
211
|
+
if (applicableSpan) {
|
|
212
|
+
return {
|
|
213
|
+
...result,
|
|
214
|
+
applicableSpan,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
return getSignatureHelpItems(fileName, position, options);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
203
224
|
languageService.getDocumentHighlights = (fileName, position, filesToSearch) => {
|
|
204
225
|
const unresolved = linkedCodeFeatureWorker(fileName, position, language_core_1.isHighlightEnabled, position => getDocumentHighlights(fileName, position, filesToSearch), function* (result) {
|
|
205
226
|
for (const ref of result) {
|
|
@@ -356,17 +377,17 @@ function decorateLanguageService(language, languageService) {
|
|
|
356
377
|
};
|
|
357
378
|
languageService.getSyntacticDiagnostics = fileName => {
|
|
358
379
|
return getSyntacticDiagnostics(fileName)
|
|
359
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
380
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, false))
|
|
360
381
|
.filter(utils_1.notEmpty);
|
|
361
382
|
};
|
|
362
383
|
languageService.getSemanticDiagnostics = fileName => {
|
|
363
384
|
return getSemanticDiagnostics(fileName)
|
|
364
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
385
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, false))
|
|
365
386
|
.filter(utils_1.notEmpty);
|
|
366
387
|
};
|
|
367
388
|
languageService.getSuggestionDiagnostics = fileName => {
|
|
368
389
|
return getSuggestionDiagnostics(fileName)
|
|
369
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
390
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, false))
|
|
370
391
|
.filter(utils_1.notEmpty);
|
|
371
392
|
};
|
|
372
393
|
languageService.getDefinitionAndBoundSpan = (fileName, position) => {
|
|
@@ -403,18 +424,15 @@ function decorateLanguageService(language, languageService) {
|
|
|
403
424
|
const resolved = unresolved
|
|
404
425
|
.flat()
|
|
405
426
|
.map(symbol => {
|
|
406
|
-
const definition = (0, transform_1.transformDocumentSpan)(language, symbol.definition, language_core_1.isDefinitionEnabled);
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
})
|
|
416
|
-
.filter(utils_1.notEmpty);
|
|
417
|
-
return (0, dedupe_1.dedupeReferencedSymbols)(resolved);
|
|
427
|
+
const definition = (0, transform_1.transformDocumentSpan)(language, symbol.definition, language_core_1.isDefinitionEnabled, true);
|
|
428
|
+
return {
|
|
429
|
+
definition,
|
|
430
|
+
references: symbol.references
|
|
431
|
+
.map(r => (0, transform_1.transformDocumentSpan)(language, r, language_core_1.isReferencesEnabled))
|
|
432
|
+
.filter(utils_1.notEmpty),
|
|
433
|
+
};
|
|
434
|
+
});
|
|
435
|
+
return resolved;
|
|
418
436
|
};
|
|
419
437
|
languageService.getDefinitionAtPosition = (fileName, position) => {
|
|
420
438
|
const unresolved = linkedCodeFeatureWorker(fileName, position, language_core_1.isDefinitionEnabled, position => getDefinitionAtPosition(fileName, position), function* (result) {
|
|
@@ -587,7 +605,7 @@ function decorateLanguageService(language, languageService) {
|
|
|
587
605
|
return (0, dedupe_1.dedupeDocumentSpans)(resolved);
|
|
588
606
|
};
|
|
589
607
|
function linkedCodeFeatureWorker(fileName, position, filter, worker, getLinkedCodes) {
|
|
590
|
-
|
|
608
|
+
const results = [];
|
|
591
609
|
const processedFilePositions = new Set();
|
|
592
610
|
const [serviceScript, sourceScript, map] = (0, utils_1.getServiceScript)(language, fileName);
|
|
593
611
|
if (serviceScript) {
|
|
@@ -610,7 +628,7 @@ function decorateLanguageService(language, languageService) {
|
|
|
610
628
|
if (!result) {
|
|
611
629
|
return;
|
|
612
630
|
}
|
|
613
|
-
results
|
|
631
|
+
results.push(result);
|
|
614
632
|
for (const ref of getLinkedCodes(result)) {
|
|
615
633
|
processedFilePositions.add(ref[0] + ':' + ref[1]);
|
|
616
634
|
const [virtualFile, sourceScript] = (0, utils_1.getServiceScript)(language, ref[0]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Language } from '@volar/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
|
-
export declare function decorateLanguageServiceHost(language: Language, languageServiceHost: ts.LanguageServiceHost
|
|
3
|
+
export declare function decorateLanguageServiceHost(ts: typeof import('typescript'), language: Language, languageServiceHost: ts.LanguageServiceHost): void;
|
|
4
4
|
export declare function searchExternalFiles(ts: typeof import('typescript'), project: ts.server.Project, exts: string[]): string[];
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.searchExternalFiles = exports.decorateLanguageServiceHost = void 0;
|
|
4
|
-
const language_core_1 = require("@volar/language-core");
|
|
5
4
|
const resolveModuleName_1 = require("../resolveModuleName");
|
|
6
|
-
function decorateLanguageServiceHost(language, languageServiceHost
|
|
7
|
-
|
|
8
|
-
const exts = language.plugins
|
|
5
|
+
function decorateLanguageServiceHost(ts, language, languageServiceHost) {
|
|
6
|
+
const extensions = language.plugins
|
|
9
7
|
.map(plugin => plugin.typescript?.extraFileExtensions.map(ext => '.' + ext.extension) ?? [])
|
|
10
8
|
.flat();
|
|
11
9
|
const scripts = new Map();
|
|
10
|
+
const crashFileNames = new Set();
|
|
12
11
|
const readDirectory = languageServiceHost.readDirectory?.bind(languageServiceHost);
|
|
13
12
|
const resolveModuleNameLiterals = languageServiceHost.resolveModuleNameLiterals?.bind(languageServiceHost);
|
|
14
13
|
const resolveModuleNames = languageServiceHost.resolveModuleNames?.bind(languageServiceHost);
|
|
15
|
-
const getProjectVersion = languageServiceHost.getProjectVersion?.bind(languageServiceHost);
|
|
16
14
|
const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
|
|
17
15
|
const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
|
|
18
16
|
// path completion
|
|
19
17
|
if (readDirectory) {
|
|
20
18
|
languageServiceHost.readDirectory = (path, extensions, exclude, include, depth) => {
|
|
21
19
|
if (extensions) {
|
|
22
|
-
for (const ext of
|
|
20
|
+
for (const ext of extensions) {
|
|
23
21
|
if (!extensions.includes(ext)) {
|
|
24
22
|
extensions = [...extensions, ...ext];
|
|
25
23
|
}
|
|
@@ -28,34 +26,33 @@ function decorateLanguageServiceHost(language, languageServiceHost, ts) {
|
|
|
28
26
|
return readDirectory(path, extensions, exclude, include, depth);
|
|
29
27
|
};
|
|
30
28
|
}
|
|
31
|
-
if (
|
|
29
|
+
if (extensions.length) {
|
|
32
30
|
const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, languageServiceHost, language.plugins, fileName => language.scripts.get(fileName));
|
|
31
|
+
const getCanonicalFileName = languageServiceHost.useCaseSensitiveFileNames?.()
|
|
32
|
+
? (fileName) => fileName
|
|
33
|
+
: (fileName) => fileName.toLowerCase();
|
|
34
|
+
const moduleResolutionCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), getCanonicalFileName, languageServiceHost.getCompilationSettings());
|
|
33
35
|
if (resolveModuleNameLiterals) {
|
|
34
36
|
languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, ...rest) => {
|
|
35
|
-
if (moduleLiterals.every(name => !
|
|
37
|
+
if (moduleLiterals.every(name => !extensions.some(ext => name.text.endsWith(ext)))) {
|
|
36
38
|
return resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, options, ...rest);
|
|
37
39
|
}
|
|
38
40
|
return moduleLiterals.map(moduleLiteral => {
|
|
39
|
-
return resolveModuleName(moduleLiteral.text, containingFile, options,
|
|
41
|
+
return resolveModuleName(moduleLiteral.text, containingFile, options, moduleResolutionCache, redirectedReference);
|
|
40
42
|
});
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
45
|
if (resolveModuleNames) {
|
|
44
46
|
languageServiceHost.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile) => {
|
|
45
|
-
if (moduleNames.every(name => !
|
|
47
|
+
if (moduleNames.every(name => !extensions.some(ext => name.endsWith(ext)))) {
|
|
46
48
|
return resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile);
|
|
47
49
|
}
|
|
48
50
|
return moduleNames.map(moduleName => {
|
|
49
|
-
return resolveModuleName(moduleName, containingFile, options,
|
|
51
|
+
return resolveModuleName(moduleName, containingFile, options, moduleResolutionCache, redirectedReference).resolvedModule;
|
|
50
52
|
});
|
|
51
53
|
};
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
|
-
if (getProjectVersion) {
|
|
55
|
-
languageServiceHost.getProjectVersion = () => {
|
|
56
|
-
return getProjectVersion() + ':' + extraProjectVersion;
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
56
|
languageServiceHost.getScriptSnapshot = fileName => {
|
|
60
57
|
const virtualScript = updateVirtualScript(fileName);
|
|
61
58
|
if (virtualScript) {
|
|
@@ -73,46 +70,44 @@ function decorateLanguageServiceHost(language, languageServiceHost, ts) {
|
|
|
73
70
|
};
|
|
74
71
|
}
|
|
75
72
|
function updateVirtualScript(fileName) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
73
|
+
if (crashFileNames.has(fileName)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let version;
|
|
77
|
+
try {
|
|
78
|
+
version = languageServiceHost.getScriptVersion(fileName);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// fix https://github.com/vuejs/language-tools/issues/4278
|
|
82
|
+
crashFileNames.add(fileName);
|
|
83
|
+
}
|
|
84
|
+
if (version === undefined) {
|
|
85
|
+
// somehow getScriptVersion returns undefined
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
let script = scripts.get(fileName);
|
|
89
|
+
if (!script || script[0] !== version) {
|
|
90
|
+
script = [version];
|
|
91
|
+
const sourceScript = language.scripts.get(fileName);
|
|
92
|
+
if (sourceScript?.generated) {
|
|
93
|
+
const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
|
|
94
|
+
if (serviceScript) {
|
|
95
|
+
const sourceContents = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength());
|
|
96
|
+
let virtualContents = sourceContents.split('\n').map(line => ' '.repeat(line.length)).join('\n');
|
|
97
|
+
virtualContents += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
|
|
98
|
+
script[1] = {
|
|
99
|
+
extension: serviceScript.extension,
|
|
100
|
+
kind: serviceScript.scriptKind,
|
|
101
|
+
snapshot: ts.ScriptSnapshot.fromString(virtualContents),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (sourceScript.generated.languagePlugin.typescript?.getExtraServiceScripts) {
|
|
105
|
+
console.warn('getExtraServiceScripts() is not available in TS plugin.');
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
|
-
|
|
101
|
-
extraProjectVersion++;
|
|
102
|
-
language.scripts.delete(fileName);
|
|
103
|
-
}
|
|
104
|
-
if (snapshotSnapshot) {
|
|
105
|
-
scripts.set(fileName, [
|
|
106
|
-
version,
|
|
107
|
-
{
|
|
108
|
-
extension,
|
|
109
|
-
snapshot: snapshotSnapshot,
|
|
110
|
-
kind: scriptKind,
|
|
111
|
-
}
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
108
|
+
scripts.set(fileName, script);
|
|
114
109
|
}
|
|
115
|
-
return
|
|
110
|
+
return script[1];
|
|
116
111
|
}
|
|
117
112
|
}
|
|
118
113
|
exports.decorateLanguageServiceHost = decorateLanguageServiceHost;
|
|
@@ -9,6 +9,7 @@ function decorateProgram(language, program) {
|
|
|
9
9
|
const getSyntacticDiagnostics = program.getSyntacticDiagnostics;
|
|
10
10
|
const getSemanticDiagnostics = program.getSemanticDiagnostics;
|
|
11
11
|
const getGlobalDiagnostics = program.getGlobalDiagnostics;
|
|
12
|
+
const getSourceFileByPath = program.getSourceFileByPath;
|
|
12
13
|
// for tsc --noEmit --watch
|
|
13
14
|
// @ts-ignore
|
|
14
15
|
const getBindAndCheckDiagnostics = program.getBindAndCheckDiagnostics;
|
|
@@ -17,31 +18,39 @@ function decorateProgram(language, program) {
|
|
|
17
18
|
return {
|
|
18
19
|
...result,
|
|
19
20
|
diagnostics: result.diagnostics
|
|
20
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
21
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
21
22
|
.filter(utils_1.notEmpty),
|
|
22
23
|
};
|
|
23
24
|
};
|
|
24
25
|
program.getSyntacticDiagnostics = (sourceFile, cancellationToken) => {
|
|
25
26
|
return getSyntacticDiagnostics(sourceFile, cancellationToken)
|
|
26
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
27
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
27
28
|
.filter(utils_1.notEmpty);
|
|
28
29
|
};
|
|
29
30
|
program.getSemanticDiagnostics = (sourceFile, cancellationToken) => {
|
|
30
31
|
return getSemanticDiagnostics(sourceFile, cancellationToken)
|
|
31
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
32
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
32
33
|
.filter(utils_1.notEmpty);
|
|
33
34
|
};
|
|
34
35
|
program.getGlobalDiagnostics = cancellationToken => {
|
|
35
36
|
return getGlobalDiagnostics(cancellationToken)
|
|
36
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
37
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
37
38
|
.filter(utils_1.notEmpty);
|
|
38
39
|
};
|
|
39
40
|
// @ts-ignore
|
|
40
41
|
program.getBindAndCheckDiagnostics = (sourceFile, cancellationToken) => {
|
|
41
42
|
return getBindAndCheckDiagnostics(sourceFile, cancellationToken)
|
|
42
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d))
|
|
43
|
+
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
43
44
|
.filter(utils_1.notEmpty);
|
|
44
45
|
};
|
|
46
|
+
// fix https://github.com/vuejs/language-tools/issues/4099 with `incremental`
|
|
47
|
+
program.getSourceFileByPath = path => {
|
|
48
|
+
const sourceFile = getSourceFileByPath(path);
|
|
49
|
+
if (sourceFile) {
|
|
50
|
+
(0, transform_1.fillSourceFileText)(language, sourceFile);
|
|
51
|
+
}
|
|
52
|
+
return sourceFile;
|
|
53
|
+
};
|
|
45
54
|
}
|
|
46
55
|
exports.decorateProgram = decorateProgram;
|
|
47
56
|
//# sourceMappingURL=decorateProgram.js.map
|
package/lib/node/dedupe.d.ts
CHANGED
package/lib/node/dedupe.js
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.dedupeDocumentSpans =
|
|
4
|
-
function dedupeReferencedSymbols(items) {
|
|
5
|
-
return dedupe(items, item => [
|
|
6
|
-
item.definition.fileName,
|
|
7
|
-
item.definition.textSpan.start,
|
|
8
|
-
item.definition.textSpan.length,
|
|
9
|
-
].join(':'));
|
|
10
|
-
}
|
|
11
|
-
exports.dedupeReferencedSymbols = dedupeReferencedSymbols;
|
|
3
|
+
exports.dedupeDocumentSpans = void 0;
|
|
12
4
|
function dedupeDocumentSpans(items) {
|
|
13
5
|
return dedupe(items, item => [
|
|
14
6
|
item.fileName,
|
|
@@ -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[], getLanguageId: (fileName: string) => string): typeof import("typescript").createProgram;
|
|
@@ -1,117 +1,161 @@
|
|
|
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 arrayEqual = (a, b) => {
|
|
8
|
+
if (a.length !== b.length) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
for (let i = 0; i < a.length; i++) {
|
|
12
|
+
if (a[i] !== b[i]) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
18
|
+
const objectEqual = (a, b) => {
|
|
19
|
+
const keysA = Object.keys(a);
|
|
20
|
+
const keysB = Object.keys(b);
|
|
21
|
+
if (keysA.length !== keysB.length) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
for (const key of keysA) {
|
|
25
|
+
if (a[key] !== b[key]) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
};
|
|
31
|
+
function proxyCreateProgram(ts, original, getLanguagePlugins, getLanguageId) {
|
|
32
|
+
const sourceFileSnapshots = new Map();
|
|
33
|
+
const parsedSourceFiles = new WeakMap();
|
|
34
|
+
let lastOptions;
|
|
35
|
+
let languagePlugins;
|
|
36
|
+
let language;
|
|
37
|
+
let moduleResolutionCache;
|
|
7
38
|
return new Proxy(original, {
|
|
8
39
|
apply: (target, thisArg, args) => {
|
|
9
40
|
const options = args[0];
|
|
10
41
|
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
|
-
language.scripts.delete(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]);
|
|
42
|
+
if (!lastOptions
|
|
43
|
+
|| !languagePlugins
|
|
44
|
+
|| !language
|
|
45
|
+
|| !arrayEqual(options.rootNames, lastOptions.rootNames)
|
|
46
|
+
|| !objectEqual(options.options, lastOptions.options)) {
|
|
47
|
+
moduleResolutionCache = ts.createModuleResolutionCache(options.host.getCurrentDirectory(), options.host.getCanonicalFileName, options.options);
|
|
48
|
+
lastOptions = options;
|
|
49
|
+
languagePlugins = getLanguagePlugins(ts, options);
|
|
50
|
+
language = (0, language_core_1.createLanguage)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
|
|
51
|
+
if (!sourceFileSnapshots.has(fileName)) {
|
|
52
|
+
const sourceFileText = originalHost.readFile(fileName);
|
|
53
|
+
if (sourceFileText !== undefined) {
|
|
54
|
+
sourceFileSnapshots.set(fileName, [undefined, {
|
|
55
|
+
getChangeRange() {
|
|
56
|
+
return undefined;
|
|
57
|
+
},
|
|
58
|
+
getLength() {
|
|
59
|
+
return sourceFileText.length;
|
|
60
|
+
},
|
|
61
|
+
getText(start, end) {
|
|
62
|
+
return sourceFileText.substring(start, end);
|
|
63
|
+
},
|
|
64
|
+
}]);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
sourceFileSnapshots.set(fileName, [undefined, undefined]);
|
|
50
68
|
}
|
|
51
69
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
const snapshot = sourceFileSnapshots.get(fileName)?.[1];
|
|
71
|
+
if (snapshot) {
|
|
72
|
+
language.scripts.set(fileName, getLanguageId(fileName), snapshot);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
language.scripts.delete(fileName);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const originalHost = options.host;
|
|
80
|
+
const extensions = languagePlugins
|
|
81
|
+
.map(plugin => plugin.typescript?.extraFileExtensions.map(({ extension }) => `.${extension}`) ?? [])
|
|
82
|
+
.flat();
|
|
55
83
|
options.host = { ...originalHost };
|
|
56
|
-
options.options.allowArbitraryExtensions = true;
|
|
57
84
|
options.host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
|
|
58
85
|
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
|
-
|
|
86
|
+
if (!sourceFileSnapshots.has(fileName)
|
|
87
|
+
|| sourceFileSnapshots.get(fileName)?.[0] !== originalSourceFile) {
|
|
88
|
+
if (originalSourceFile) {
|
|
89
|
+
sourceFileSnapshots.set(fileName, [originalSourceFile, {
|
|
90
|
+
getChangeRange() {
|
|
91
|
+
return undefined;
|
|
92
|
+
},
|
|
93
|
+
getLength() {
|
|
94
|
+
return originalSourceFile.text.length;
|
|
95
|
+
},
|
|
96
|
+
getText(start, end) {
|
|
97
|
+
return originalSourceFile.text.substring(start, end);
|
|
98
|
+
},
|
|
99
|
+
}]);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
sourceFileSnapshots.set(fileName, [undefined, undefined]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!originalSourceFile) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!parsedSourceFiles.has(originalSourceFile)) {
|
|
109
|
+
const sourceScript = language.scripts.get(fileName);
|
|
110
|
+
assert(!!sourceScript, '!!sourceScript');
|
|
111
|
+
parsedSourceFiles.set(originalSourceFile, originalSourceFile);
|
|
112
|
+
if (sourceScript.generated?.languagePlugin.typescript) {
|
|
113
|
+
const { getServiceScript, getExtraServiceScripts } = sourceScript.generated.languagePlugin.typescript;
|
|
114
|
+
const serviceScript = getServiceScript(sourceScript.generated.root);
|
|
115
|
+
if (serviceScript) {
|
|
116
|
+
let patchedText = originalSourceFile.text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
|
|
117
|
+
let scriptKind = ts.ScriptKind.TS;
|
|
118
|
+
scriptKind = serviceScript.scriptKind;
|
|
119
|
+
patchedText += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
|
|
120
|
+
const parsedSourceFile = ts.createSourceFile(fileName, patchedText, languageVersionOrOptions, undefined, scriptKind);
|
|
121
|
+
// @ts-expect-error
|
|
122
|
+
parsedSourceFile.version = originalSourceFile.version;
|
|
123
|
+
parsedSourceFiles.set(originalSourceFile, parsedSourceFile);
|
|
124
|
+
}
|
|
125
|
+
if (getExtraServiceScripts) {
|
|
126
|
+
console.warn('getExtraServiceScripts() is not available in this use case.');
|
|
77
127
|
}
|
|
78
|
-
sourceFile2 = ts.createSourceFile(fileName, patchedText, 99, true, scriptKind);
|
|
79
|
-
// @ts-expect-error
|
|
80
|
-
sourceFile2.version = originalSourceFile.version;
|
|
81
|
-
parsedSourceFiles.set(originalSourceFile, sourceFile2);
|
|
82
128
|
}
|
|
83
|
-
return sourceFile2;
|
|
84
129
|
}
|
|
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
|
-
});
|
|
130
|
+
return parsedSourceFiles.get(originalSourceFile);
|
|
91
131
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
132
|
+
if (extensions.length) {
|
|
133
|
+
options.options.allowArbitraryExtensions = true;
|
|
134
|
+
const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, originalHost, language.plugins, fileName => language.scripts.get(fileName));
|
|
135
|
+
const resolveModuleNameLiterals = originalHost.resolveModuleNameLiterals;
|
|
136
|
+
const resolveModuleNames = originalHost.resolveModuleNames;
|
|
137
|
+
options.host.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, compilerOptions, ...rest) => {
|
|
138
|
+
if (resolveModuleNameLiterals && moduleLiterals.every(name => !extensions.some(ext => name.text.endsWith(ext)))) {
|
|
139
|
+
return resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, compilerOptions, ...rest);
|
|
140
|
+
}
|
|
141
|
+
return moduleLiterals.map(moduleLiteral => {
|
|
142
|
+
return resolveModuleName(moduleLiteral.text, containingFile, compilerOptions, moduleResolutionCache, redirectedReference);
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
options.host.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile) => {
|
|
146
|
+
if (resolveModuleNames && moduleNames.every(name => !extensions.some(ext => name.endsWith(ext)))) {
|
|
147
|
+
return resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile);
|
|
148
|
+
}
|
|
149
|
+
return moduleNames.map(moduleName => {
|
|
150
|
+
return resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionCache, redirectedReference).resolvedModule;
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const program = Reflect.apply(target, thisArg, args);
|
|
98
155
|
(0, decorateProgram_1.decorateProgram)(language, program);
|
|
99
156
|
// TODO: #128
|
|
100
|
-
program.__volar__ = {
|
|
157
|
+
program.__volar__ = { language };
|
|
101
158
|
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
159
|
},
|
|
116
160
|
});
|
|
117
161
|
}
|
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): {
|
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.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;
|
|
@@ -43,7 +43,7 @@ function createTypeScriptLanguage(ts, languagePlugins, projectHost) {
|
|
|
43
43
|
}
|
|
44
44
|
if (languagePlugins.some(language => language.typescript?.extraFileExtensions.length)) {
|
|
45
45
|
// TODO: can this share between monorepo packages?
|
|
46
|
-
const moduleCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), languageServiceHost.useCaseSensitiveFileNames ? s => s : s => s.toLowerCase(), languageServiceHost.getCompilationSettings());
|
|
46
|
+
const moduleCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), languageServiceHost.useCaseSensitiveFileNames?.() ? s => s : s => s.toLowerCase(), languageServiceHost.getCompilationSettings());
|
|
47
47
|
const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, languageServiceHost, languagePlugins, fileName => language.scripts.get(projectHost.fileNameToScriptId(fileName)));
|
|
48
48
|
let lastSysVersion = projectHost.getSystemVersion?.();
|
|
49
49
|
languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, sourceFile) => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type * as ts from 'typescript';
|
|
2
2
|
import { LanguagePlugin } from '@volar/language-core';
|
|
3
|
-
export declare function createAsyncLanguageServicePlugin(extensions: string[], scriptKind: ts.ScriptKind, loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => Promise<LanguagePlugin[]
|
|
3
|
+
export declare function createAsyncLanguageServicePlugin(extensions: string[], scriptKind: ts.ScriptKind, loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => Promise<LanguagePlugin[]>, getLanguageId: (fileName: string) => string): ts.server.PluginModuleFactory;
|
|
@@ -8,7 +8,7 @@ const createLanguageServicePlugin_1 = require("./createLanguageServicePlugin");
|
|
|
8
8
|
const externalFiles = new WeakMap();
|
|
9
9
|
const decoratedLanguageServices = new WeakSet();
|
|
10
10
|
const decoratedLanguageServiceHosts = new WeakSet();
|
|
11
|
-
function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePlugins) {
|
|
11
|
+
function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePlugins, getLanguageId) {
|
|
12
12
|
return modules => {
|
|
13
13
|
const { typescript: ts } = modules;
|
|
14
14
|
const pluginModule = {
|
|
@@ -55,14 +55,14 @@ function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePl
|
|
|
55
55
|
const language = (0, language_core_1.createLanguage)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
|
|
56
56
|
const snapshot = getScriptSnapshot(fileName);
|
|
57
57
|
if (snapshot) {
|
|
58
|
-
language.scripts.set(fileName, (
|
|
58
|
+
language.scripts.set(fileName, getLanguageId(fileName), snapshot);
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
61
61
|
language.scripts.delete(fileName);
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
64
|
(0, decorateLanguageService_1.decorateLanguageService)(language, info.languageService);
|
|
65
|
-
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(language, info.languageServiceHost
|
|
65
|
+
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
|
|
66
66
|
info.project.markAsDirty();
|
|
67
67
|
initialized = true;
|
|
68
68
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type * as ts from 'typescript';
|
|
2
2
|
import { LanguagePlugin } from '@volar/language-core';
|
|
3
|
-
export declare function createLanguageServicePlugin(loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => LanguagePlugin[]): ts.server.PluginModuleFactory;
|
|
3
|
+
export declare function createLanguageServicePlugin(loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => LanguagePlugin[], getLanguageId: (fileName: string) => string): ts.server.PluginModuleFactory;
|
|
4
4
|
export declare function arrayItemsEqual(a: string[], b: string[]): boolean;
|
|
@@ -8,7 +8,7 @@ const externalFiles = new WeakMap();
|
|
|
8
8
|
const projectExternalFileExtensions = new WeakMap();
|
|
9
9
|
const decoratedLanguageServices = new WeakSet();
|
|
10
10
|
const decoratedLanguageServiceHosts = new WeakSet();
|
|
11
|
-
function createLanguageServicePlugin(loadLanguagePlugins) {
|
|
11
|
+
function createLanguageServicePlugin(loadLanguagePlugins, getLanguageId) {
|
|
12
12
|
return modules => {
|
|
13
13
|
const { typescript: ts } = modules;
|
|
14
14
|
const pluginModule = {
|
|
@@ -26,14 +26,14 @@ function createLanguageServicePlugin(loadLanguagePlugins) {
|
|
|
26
26
|
const language = (0, language_core_1.createLanguage)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
|
|
27
27
|
const snapshot = getScriptSnapshot(fileName);
|
|
28
28
|
if (snapshot) {
|
|
29
|
-
language.scripts.set(fileName, (
|
|
29
|
+
language.scripts.set(fileName, getLanguageId(fileName), snapshot);
|
|
30
30
|
}
|
|
31
31
|
else {
|
|
32
32
|
language.scripts.delete(fileName);
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
35
|
(0, decorateLanguageService_1.decorateLanguageService)(language, info.languageService);
|
|
36
|
-
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(language, info.languageServiceHost
|
|
36
|
+
(0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
|
|
37
37
|
}
|
|
38
38
|
return info.languageService;
|
|
39
39
|
},
|
|
@@ -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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volar/typescript",
|
|
3
|
-
"version": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
"directory": "packages/typescript"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@volar/language-core": "2.2.0-alpha.
|
|
15
|
+
"@volar/language-core": "2.2.0-alpha.10",
|
|
16
16
|
"path-browserify": "^1.0.1"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/node": "latest",
|
|
20
20
|
"@types/path-browserify": "latest",
|
|
21
|
-
"@volar/language-service": "2.2.0-alpha.
|
|
21
|
+
"@volar/language-service": "2.2.0-alpha.10"
|
|
22
22
|
},
|
|
23
|
-
"gitHead": "
|
|
23
|
+
"gitHead": "aedd2230883c457f703be93ed150917a3efde75c"
|
|
24
24
|
}
|