@volar/typescript 2.3.0-alpha.1 → 2.3.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 +185 -122
- package/lib/node/decorateLanguageServiceHost.js +18 -9
- package/lib/node/decorateProgram.js +39 -12
- package/lib/node/proxyCreateProgram.js +4 -8
- package/lib/node/transform.d.ts +10 -8
- package/lib/node/transform.js +110 -56
- package/lib/node/utils.d.ts +2 -2
- package/lib/node/utils.js +16 -5
- package/lib/protocol/createProject.d.ts +2 -2
- package/lib/protocol/createProject.js +4 -4
- package/lib/quickstart/createAsyncLanguageServicePlugin.js +2 -6
- package/lib/quickstart/createLanguageServicePlugin.js +3 -6
- package/lib/resolveModuleName.js +18 -0
- package/package.json +4 -4
|
@@ -64,7 +64,7 @@ function decorateLanguageServiceHost(ts, language, languageServiceHost) {
|
|
|
64
64
|
languageServiceHost.getScriptKind = fileName => {
|
|
65
65
|
const virtualScript = updateVirtualScript(fileName);
|
|
66
66
|
if (virtualScript) {
|
|
67
|
-
return virtualScript.
|
|
67
|
+
return virtualScript.scriptKind;
|
|
68
68
|
}
|
|
69
69
|
return getScriptKind(fileName);
|
|
70
70
|
};
|
|
@@ -92,14 +92,23 @@ function decorateLanguageServiceHost(ts, language, languageServiceHost) {
|
|
|
92
92
|
if (sourceScript?.generated) {
|
|
93
93
|
const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
|
|
94
94
|
if (serviceScript) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
if (serviceScript.preventLeadingOffset) {
|
|
96
|
+
script[1] = {
|
|
97
|
+
extension: serviceScript.extension,
|
|
98
|
+
scriptKind: serviceScript.scriptKind,
|
|
99
|
+
snapshot: serviceScript.code.snapshot,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const sourceContents = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength());
|
|
104
|
+
const virtualContents = sourceContents.split('\n').map(line => ' '.repeat(line.length)).join('\n')
|
|
105
|
+
+ serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
|
|
106
|
+
script[1] = {
|
|
107
|
+
extension: serviceScript.extension,
|
|
108
|
+
scriptKind: serviceScript.scriptKind,
|
|
109
|
+
snapshot: ts.ScriptSnapshot.fromString(virtualContents),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
103
112
|
}
|
|
104
113
|
if (sourceScript.generated.languagePlugin.typescript?.getExtraServiceScripts) {
|
|
105
114
|
console.warn('getExtraServiceScripts() is not available in TS plugin.');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.decorateProgram = void 0;
|
|
4
|
-
const utils_1 = require("./utils");
|
|
5
4
|
const transform_1 = require("./transform");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
6
|
function decorateProgram(language, program) {
|
|
7
7
|
const emit = program.emit;
|
|
8
8
|
// for tsc --noEmit
|
|
@@ -18,30 +18,57 @@ function decorateProgram(language, program) {
|
|
|
18
18
|
return {
|
|
19
19
|
...result,
|
|
20
20
|
diagnostics: result.diagnostics
|
|
21
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
21
|
+
.map(d => (0, transform_1.transformDiagnostic)(undefined, language, d, program, true))
|
|
22
22
|
.filter(utils_1.notEmpty),
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
25
|
program.getSyntacticDiagnostics = (sourceFile, cancellationToken) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
if (!sourceFile) {
|
|
27
|
+
return getSyntacticDiagnostics(undefined, cancellationToken)
|
|
28
|
+
.map(d => (0, transform_1.transformDiagnostic)(undefined, language, d, program, true))
|
|
29
|
+
.filter(utils_1.notEmpty);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const [_serviceScript, targetScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
|
|
33
|
+
const actualSourceFile = targetScript ? program.getSourceFile(targetScript.id) : sourceFile;
|
|
34
|
+
return getSyntacticDiagnostics(actualSourceFile, cancellationToken)
|
|
35
|
+
.map(d => (0, transform_1.transformDiagnostic)(targetScript, language, d, program, true))
|
|
36
|
+
.filter(utils_1.notEmpty);
|
|
37
|
+
}
|
|
29
38
|
};
|
|
30
39
|
program.getSemanticDiagnostics = (sourceFile, cancellationToken) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
if (!sourceFile) {
|
|
41
|
+
return getSemanticDiagnostics(undefined, cancellationToken)
|
|
42
|
+
.map(d => (0, transform_1.transformDiagnostic)(undefined, language, d, program, true))
|
|
43
|
+
.filter(utils_1.notEmpty);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const [_serviceScript, targetScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
|
|
47
|
+
const actualSourceFile = targetScript ? program.getSourceFile(targetScript.id) : sourceFile;
|
|
48
|
+
return getSemanticDiagnostics(actualSourceFile, cancellationToken)
|
|
49
|
+
.map(d => (0, transform_1.transformDiagnostic)(targetScript, language, d, program, true))
|
|
50
|
+
.filter(utils_1.notEmpty);
|
|
51
|
+
}
|
|
34
52
|
};
|
|
35
53
|
program.getGlobalDiagnostics = cancellationToken => {
|
|
36
54
|
return getGlobalDiagnostics(cancellationToken)
|
|
37
|
-
.map(d => (0, transform_1.transformDiagnostic)(language, d, true))
|
|
55
|
+
.map(d => (0, transform_1.transformDiagnostic)(undefined, language, d, program, true))
|
|
38
56
|
.filter(utils_1.notEmpty);
|
|
39
57
|
};
|
|
40
58
|
// @ts-ignore
|
|
41
59
|
program.getBindAndCheckDiagnostics = (sourceFile, cancellationToken) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
60
|
+
if (!sourceFile) {
|
|
61
|
+
return getBindAndCheckDiagnostics(undefined, cancellationToken)
|
|
62
|
+
.map(d => (0, transform_1.transformDiagnostic)(undefined, language, d, program, true))
|
|
63
|
+
.filter(utils_1.notEmpty);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const [_serviceScript, targetScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
|
|
67
|
+
const actualSourceFile = targetScript ? program.getSourceFile(targetScript.id) : sourceFile;
|
|
68
|
+
return getBindAndCheckDiagnostics(actualSourceFile, cancellationToken)
|
|
69
|
+
.map(d => (0, transform_1.transformDiagnostic)(targetScript, language, d, program, true))
|
|
70
|
+
.filter(utils_1.notEmpty);
|
|
71
|
+
}
|
|
45
72
|
};
|
|
46
73
|
// fix https://github.com/vuejs/language-tools/issues/4099 with `incremental`
|
|
47
74
|
program.getSourceFileByPath = path => {
|
|
@@ -50,11 +50,7 @@ function proxyCreateProgram(ts, original, getLanguagePlugins) {
|
|
|
50
50
|
languagePlugins = getLanguagePlugins(ts, options);
|
|
51
51
|
language = (0, language_core_1.createLanguage)([
|
|
52
52
|
...languagePlugins,
|
|
53
|
-
{
|
|
54
|
-
getLanguageId(fileName) {
|
|
55
|
-
return (0, common_1.resolveFileLanguageId)(fileName);
|
|
56
|
-
},
|
|
57
|
-
},
|
|
53
|
+
{ getLanguageId: common_1.resolveFileLanguageId },
|
|
58
54
|
], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), fileName => {
|
|
59
55
|
if (!sourceFileSnapshots.has(fileName)) {
|
|
60
56
|
const sourceFileText = originalHost.readFile(fileName);
|
|
@@ -116,11 +112,11 @@ function proxyCreateProgram(ts, original, getLanguagePlugins) {
|
|
|
116
112
|
if (!parsedSourceFiles.has(originalSourceFile)) {
|
|
117
113
|
const sourceScript = language.scripts.get(fileName);
|
|
118
114
|
assert(!!sourceScript, '!!sourceScript');
|
|
119
|
-
parsedSourceFiles.set(originalSourceFile,
|
|
115
|
+
parsedSourceFiles.set(originalSourceFile, undefined);
|
|
120
116
|
if (sourceScript.generated?.languagePlugin.typescript) {
|
|
121
117
|
const { getServiceScript, getExtraServiceScripts } = sourceScript.generated.languagePlugin.typescript;
|
|
122
118
|
const serviceScript = getServiceScript(sourceScript.generated.root);
|
|
123
|
-
if (serviceScript) {
|
|
119
|
+
if (serviceScript && !serviceScript.preventLeadingOffset) {
|
|
124
120
|
let patchedText = originalSourceFile.text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
|
|
125
121
|
let scriptKind = ts.ScriptKind.TS;
|
|
126
122
|
scriptKind = serviceScript.scriptKind;
|
|
@@ -135,7 +131,7 @@ function proxyCreateProgram(ts, original, getLanguagePlugins) {
|
|
|
135
131
|
}
|
|
136
132
|
}
|
|
137
133
|
}
|
|
138
|
-
return parsedSourceFiles.get(originalSourceFile);
|
|
134
|
+
return parsedSourceFiles.get(originalSourceFile) ?? originalSourceFile;
|
|
139
135
|
};
|
|
140
136
|
if (extensions.length) {
|
|
141
137
|
options.options.allowArbitraryExtensions = true;
|
package/lib/node/transform.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import type { CodeInformation,
|
|
1
|
+
import type { CodeInformation, SourceScript, TypeScriptServiceScript } from '@volar/language-core';
|
|
2
2
|
import { Language } from '@volar/language-core';
|
|
3
3
|
import type * as ts from 'typescript';
|
|
4
4
|
export declare function transformCallHierarchyItem(language: Language<string>, item: ts.CallHierarchyItem, filter: (data: CodeInformation) => boolean): ts.CallHierarchyItem;
|
|
5
|
-
export declare function transformDiagnostic<T extends ts.Diagnostic>(language: Language<string>, diagnostic: T, isTsc: boolean): T | undefined;
|
|
5
|
+
export declare function transformDiagnostic<T extends ts.Diagnostic>(targetScript: SourceScript<string> | undefined, language: Language<string>, diagnostic: T, program: ts.Program | undefined, isTsc: boolean): T | undefined;
|
|
6
6
|
export declare function fillSourceFileText(language: Language<string>, sourceFile: ts.SourceFile): void;
|
|
7
|
-
export declare function transformFileTextChanges(language: Language<string>, changes: ts.FileTextChanges, filter: (data: CodeInformation) => boolean): ts.FileTextChanges
|
|
7
|
+
export declare function transformFileTextChanges(language: Language<string>, changes: readonly ts.FileTextChanges[], filter: (data: CodeInformation) => boolean): ts.FileTextChanges[];
|
|
8
8
|
export declare function transformDocumentSpan<T extends ts.DocumentSpan>(language: Language<string>, documentSpan: T, filter: (data: CodeInformation) => boolean, shouldFallback?: boolean): T | undefined;
|
|
9
9
|
export declare function transformSpan(language: Language<string>, fileName: string | undefined, textSpan: ts.TextSpan | undefined, filter: (data: CodeInformation) => boolean): {
|
|
10
10
|
fileName: string;
|
|
11
11
|
textSpan: ts.TextSpan;
|
|
12
12
|
} | undefined;
|
|
13
|
-
export declare function transformTextChange(
|
|
14
|
-
export declare function transformTextSpan(
|
|
15
|
-
export declare function toSourceOffset(
|
|
16
|
-
export declare function
|
|
17
|
-
export declare function
|
|
13
|
+
export declare function transformTextChange(targetScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, textChange: ts.TextChange, filter: (data: CodeInformation) => boolean): [string, ts.TextChange] | undefined;
|
|
14
|
+
export declare function transformTextSpan(targetScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, textSpan: ts.TextSpan, filter: (data: CodeInformation) => boolean): [string, ts.TextSpan] | undefined;
|
|
15
|
+
export declare function toSourceOffset(targetScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, position: number, filter: (data: CodeInformation) => boolean): [fileName: string, offset: number] | undefined;
|
|
16
|
+
export declare function toSourceOffsets(targetScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, position: number, filter: (data: CodeInformation) => boolean): Generator<[fileName: string, offset: number]>;
|
|
17
|
+
export declare function toGeneratedOffset(language: Language, serviceScript: TypeScriptServiceScript, sourceScript: SourceScript<string>, position: number, filter: (data: CodeInformation) => boolean): number | undefined;
|
|
18
|
+
export declare function toGeneratedOffsets(language: Language, serviceScript: TypeScriptServiceScript, sourceScript: SourceScript<string>, position: number, filter: (data: CodeInformation) => boolean): Generator<readonly [number, import("@volar/language-core").Mapping<CodeInformation>], void, unknown>;
|
|
19
|
+
export declare function getMappingOffset(language: Language, serviceScript: TypeScriptServiceScript): number;
|
package/lib/node/transform.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toGeneratedOffsets = exports.toGeneratedOffset = exports.toSourceOffset = exports.transformTextSpan = exports.transformTextChange = exports.transformSpan = exports.transformDocumentSpan = exports.transformFileTextChanges = exports.fillSourceFileText = exports.transformDiagnostic = exports.transformCallHierarchyItem = void 0;
|
|
3
|
+
exports.getMappingOffset = exports.toGeneratedOffsets = exports.toGeneratedOffset = exports.toSourceOffsets = 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();
|
|
@@ -10,32 +10,42 @@ function transformCallHierarchyItem(language, item, filter) {
|
|
|
10
10
|
const selectionSpan = transformSpan(language, item.file, item.selectionSpan, filter);
|
|
11
11
|
return {
|
|
12
12
|
...item,
|
|
13
|
+
file: span?.fileName ?? item.file,
|
|
13
14
|
span: span?.textSpan ?? { start: 0, length: 0 },
|
|
14
15
|
selectionSpan: selectionSpan?.textSpan ?? { start: 0, length: 0 },
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
18
|
exports.transformCallHierarchyItem = transformCallHierarchyItem;
|
|
18
|
-
function transformDiagnostic(language, diagnostic, isTsc) {
|
|
19
|
+
function transformDiagnostic(targetScript, language, diagnostic, program, isTsc) {
|
|
19
20
|
if (!transformedDiagnostics.has(diagnostic)) {
|
|
20
21
|
transformedDiagnostics.set(diagnostic, undefined);
|
|
21
22
|
const { relatedInformation } = diagnostic;
|
|
22
23
|
if (relatedInformation) {
|
|
23
24
|
diagnostic.relatedInformation = relatedInformation
|
|
24
|
-
.map(d => transformDiagnostic(language, d, isTsc))
|
|
25
|
+
.map(d => transformDiagnostic(undefined, language, d, program, isTsc))
|
|
25
26
|
.filter(utils_1.notEmpty);
|
|
26
27
|
}
|
|
27
28
|
if (diagnostic.file !== undefined
|
|
28
29
|
&& diagnostic.start !== undefined
|
|
29
30
|
&& diagnostic.length !== undefined) {
|
|
30
|
-
const [serviceScript
|
|
31
|
+
const [serviceScript] = (0, utils_1.getServiceScript)(language, diagnostic.file.fileName);
|
|
31
32
|
if (serviceScript) {
|
|
32
|
-
const sourceSpan = transformTextSpan(
|
|
33
|
-
|
|
33
|
+
const [sourceSpanFileName, sourceSpan] = transformTextSpan(targetScript, language, serviceScript, {
|
|
34
|
+
start: diagnostic.start,
|
|
35
|
+
length: diagnostic.length
|
|
36
|
+
}, language_core_1.shouldReportDiagnostics) ?? [];
|
|
37
|
+
const actualDiagnosticFile = sourceSpanFileName
|
|
38
|
+
? diagnostic.file.fileName === sourceSpanFileName
|
|
39
|
+
? diagnostic.file
|
|
40
|
+
: program?.getSourceFile(sourceSpanFileName)
|
|
41
|
+
: undefined;
|
|
42
|
+
if (sourceSpan && actualDiagnosticFile) {
|
|
34
43
|
if (isTsc) {
|
|
35
44
|
fillSourceFileText(language, diagnostic.file);
|
|
36
45
|
}
|
|
37
46
|
transformedDiagnostics.set(diagnostic, {
|
|
38
47
|
...diagnostic,
|
|
48
|
+
file: actualDiagnosticFile,
|
|
39
49
|
start: sourceSpan.start,
|
|
40
50
|
length: sourceSpan.length,
|
|
41
51
|
});
|
|
@@ -58,32 +68,45 @@ function fillSourceFileText(language, sourceFile) {
|
|
|
58
68
|
return;
|
|
59
69
|
}
|
|
60
70
|
transformedSourceFile.add(sourceFile);
|
|
61
|
-
const [serviceScript,
|
|
62
|
-
if (serviceScript) {
|
|
63
|
-
sourceFile.text =
|
|
64
|
-
+ sourceFile.text.substring(
|
|
71
|
+
const [serviceScript, targetScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
|
|
72
|
+
if (serviceScript && !serviceScript.preventLeadingOffset) {
|
|
73
|
+
sourceFile.text = targetScript.snapshot.getText(0, targetScript.snapshot.getLength())
|
|
74
|
+
+ sourceFile.text.substring(targetScript.snapshot.getLength());
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
77
|
exports.fillSourceFileText = fillSourceFileText;
|
|
68
78
|
function transformFileTextChanges(language, changes, filter) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
span: span.textSpan,
|
|
79
|
-
};
|
|
79
|
+
const changesPerFile = {};
|
|
80
|
+
const newFiles = new Set();
|
|
81
|
+
for (const fileChanges of changes) {
|
|
82
|
+
const [_, source] = (0, utils_1.getServiceScript)(language, fileChanges.fileName);
|
|
83
|
+
if (source) {
|
|
84
|
+
fileChanges.textChanges.forEach(c => {
|
|
85
|
+
const { fileName, textSpan } = transformSpan(language, fileChanges.fileName, c.span, filter) ?? {};
|
|
86
|
+
if (fileName && textSpan) {
|
|
87
|
+
(changesPerFile[fileName] ?? (changesPerFile[fileName] = [])).push({ ...c, span: textSpan });
|
|
80
88
|
}
|
|
81
|
-
})
|
|
82
|
-
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const list = (changesPerFile[fileChanges.fileName] ?? (changesPerFile[fileChanges.fileName] = []));
|
|
93
|
+
fileChanges.textChanges.forEach(c => {
|
|
94
|
+
list.push(c);
|
|
95
|
+
});
|
|
96
|
+
if (fileChanges.isNewFile) {
|
|
97
|
+
newFiles.add(fileChanges.fileName);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
83
100
|
}
|
|
84
|
-
|
|
85
|
-
|
|
101
|
+
const result = [];
|
|
102
|
+
for (const fileName in changesPerFile) {
|
|
103
|
+
result.push({
|
|
104
|
+
fileName,
|
|
105
|
+
isNewFile: newFiles.has(fileName),
|
|
106
|
+
textChanges: changesPerFile[fileName]
|
|
107
|
+
});
|
|
86
108
|
}
|
|
109
|
+
return result;
|
|
87
110
|
}
|
|
88
111
|
exports.transformFileTextChanges = transformFileTextChanges;
|
|
89
112
|
function transformDocumentSpan(language, documentSpan, filter, shouldFallback) {
|
|
@@ -115,12 +138,12 @@ function transformSpan(language, fileName, textSpan, filter) {
|
|
|
115
138
|
if (!fileName || !textSpan) {
|
|
116
139
|
return;
|
|
117
140
|
}
|
|
118
|
-
const [
|
|
119
|
-
if (
|
|
120
|
-
const sourceSpan = transformTextSpan(
|
|
121
|
-
if (sourceSpan) {
|
|
141
|
+
const [serviceScript] = (0, utils_1.getServiceScript)(language, fileName);
|
|
142
|
+
if (serviceScript) {
|
|
143
|
+
const [sourceSpanFileName, sourceSpan] = transformTextSpan(undefined, language, serviceScript, textSpan, filter) ?? [];
|
|
144
|
+
if (sourceSpan && sourceSpanFileName) {
|
|
122
145
|
return {
|
|
123
|
-
fileName,
|
|
146
|
+
fileName: sourceSpanFileName,
|
|
124
147
|
textSpan: sourceSpan,
|
|
125
148
|
};
|
|
126
149
|
}
|
|
@@ -133,49 +156,80 @@ function transformSpan(language, fileName, textSpan, filter) {
|
|
|
133
156
|
}
|
|
134
157
|
}
|
|
135
158
|
exports.transformSpan = transformSpan;
|
|
136
|
-
function transformTextChange(
|
|
137
|
-
const sourceSpan = transformTextSpan(
|
|
138
|
-
if (sourceSpan) {
|
|
139
|
-
return {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
159
|
+
function transformTextChange(targetScript, language, serviceScript, textChange, filter) {
|
|
160
|
+
const [sourceSpanFileName, sourceSpan] = transformTextSpan(targetScript, language, serviceScript, textChange.span, filter) ?? [];
|
|
161
|
+
if (sourceSpan && sourceSpanFileName) {
|
|
162
|
+
return [sourceSpanFileName, {
|
|
163
|
+
newText: textChange.newText,
|
|
164
|
+
span: sourceSpan,
|
|
165
|
+
}];
|
|
143
166
|
}
|
|
167
|
+
return undefined;
|
|
144
168
|
}
|
|
145
169
|
exports.transformTextChange = transformTextChange;
|
|
146
|
-
function transformTextSpan(
|
|
170
|
+
function transformTextSpan(targetScript, language, serviceScript, textSpan, filter) {
|
|
147
171
|
const start = textSpan.start;
|
|
148
172
|
const end = textSpan.start + textSpan.length;
|
|
149
|
-
const sourceStart
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
173
|
+
for (const sourceStart of toSourceOffsets(targetScript, language, serviceScript, start, filter)) {
|
|
174
|
+
for (const sourceEnd of toSourceOffsets(targetScript, language, serviceScript, end, filter)) {
|
|
175
|
+
if (sourceStart[0] === sourceEnd[0]
|
|
176
|
+
&& sourceEnd[1] >= sourceStart[1]) {
|
|
177
|
+
return [sourceStart[0], {
|
|
178
|
+
start: sourceStart[1],
|
|
179
|
+
length: sourceEnd[1] - sourceStart[1],
|
|
180
|
+
}];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
156
183
|
}
|
|
157
184
|
}
|
|
158
185
|
exports.transformTextSpan = transformTextSpan;
|
|
159
|
-
function toSourceOffset(
|
|
160
|
-
for (const
|
|
161
|
-
|
|
162
|
-
return sourceOffset;
|
|
163
|
-
}
|
|
186
|
+
function toSourceOffset(targetScript, language, serviceScript, position, filter) {
|
|
187
|
+
for (const source of toSourceOffsets(targetScript, language, serviceScript, position, filter)) {
|
|
188
|
+
return source;
|
|
164
189
|
}
|
|
165
190
|
}
|
|
166
191
|
exports.toSourceOffset = toSourceOffset;
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
192
|
+
function* toSourceOffsets(targetScript, language, serviceScript, position, filter) {
|
|
193
|
+
if (targetScript) {
|
|
194
|
+
const map = language.maps.get(serviceScript.code, targetScript);
|
|
195
|
+
for (const [sourceOffset, mapping] of map.getSourceOffsets(position - getMappingOffset(language, serviceScript))) {
|
|
196
|
+
if (filter(mapping.data)) {
|
|
197
|
+
yield [targetScript.id, sourceOffset];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
for (const [fileName, _snapshot, map] of language.maps.forEach(serviceScript.code)) {
|
|
203
|
+
for (const [sourceOffset, mapping] of map.getSourceOffsets(position - getMappingOffset(language, serviceScript))) {
|
|
204
|
+
if (filter(mapping.data)) {
|
|
205
|
+
yield [fileName, sourceOffset];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
171
208
|
}
|
|
172
209
|
}
|
|
173
210
|
}
|
|
211
|
+
exports.toSourceOffsets = toSourceOffsets;
|
|
212
|
+
function toGeneratedOffset(language, serviceScript, sourceScript, position, filter) {
|
|
213
|
+
for (const [generateOffset] of toGeneratedOffsets(language, serviceScript, sourceScript, position, filter)) {
|
|
214
|
+
return generateOffset;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
174
217
|
exports.toGeneratedOffset = toGeneratedOffset;
|
|
175
|
-
function* toGeneratedOffsets(sourceScript,
|
|
218
|
+
function* toGeneratedOffsets(language, serviceScript, sourceScript, position, filter) {
|
|
219
|
+
const map = language.maps.get(serviceScript.code, sourceScript);
|
|
176
220
|
for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
|
|
177
|
-
|
|
221
|
+
if (filter(mapping.data)) {
|
|
222
|
+
yield [generateOffset + getMappingOffset(language, serviceScript), mapping];
|
|
223
|
+
}
|
|
178
224
|
}
|
|
179
225
|
}
|
|
180
226
|
exports.toGeneratedOffsets = toGeneratedOffsets;
|
|
227
|
+
function getMappingOffset(language, serviceScript) {
|
|
228
|
+
if (serviceScript.preventLeadingOffset) {
|
|
229
|
+
return 0;
|
|
230
|
+
}
|
|
231
|
+
const sourceScript = language.scripts.fromVirtualCode(serviceScript.code);
|
|
232
|
+
return sourceScript.snapshot.getLength();
|
|
233
|
+
}
|
|
234
|
+
exports.getMappingOffset = getMappingOffset;
|
|
181
235
|
//# sourceMappingURL=transform.js.map
|
package/lib/node/utils.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { Language } from '@volar/language-core';
|
|
1
|
+
import type { Language, SourceScript, TypeScriptServiceScript } from '@volar/language-core';
|
|
2
2
|
export declare function notEmpty<T>(value: T | null | undefined): value is T;
|
|
3
|
-
export declare function getServiceScript(language: Language<string>, fileName: string):
|
|
3
|
+
export declare function getServiceScript(language: Language<string>, fileName: string): [serviceService: TypeScriptServiceScript, targetScript: SourceScript<string>] | [undefined, SourceScript<string>] | [undefined, undefined];
|
package/lib/node/utils.js
CHANGED
|
@@ -7,16 +7,27 @@ function notEmpty(value) {
|
|
|
7
7
|
exports.notEmpty = notEmpty;
|
|
8
8
|
function getServiceScript(language, fileName) {
|
|
9
9
|
const sourceScript = language.scripts.get(fileName);
|
|
10
|
+
if (sourceScript?.targetIds.size) {
|
|
11
|
+
for (const targetId of sourceScript.targetIds) {
|
|
12
|
+
const targetScript = language.scripts.get(targetId);
|
|
13
|
+
if (targetScript?.generated) {
|
|
14
|
+
const serviceScript = targetScript.generated.languagePlugin.typescript?.getServiceScript(targetScript.generated.root);
|
|
15
|
+
if (serviceScript) {
|
|
16
|
+
return [serviceScript, targetScript];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (sourceScript?.associatedOnly) {
|
|
22
|
+
return [undefined, sourceScript];
|
|
23
|
+
}
|
|
10
24
|
if (sourceScript?.generated) {
|
|
11
25
|
const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
|
|
12
26
|
if (serviceScript) {
|
|
13
|
-
|
|
14
|
-
if (map) {
|
|
15
|
-
return [serviceScript, sourceScript, map];
|
|
16
|
-
}
|
|
27
|
+
return [serviceScript, sourceScript];
|
|
17
28
|
}
|
|
18
29
|
}
|
|
19
|
-
return [undefined, undefined
|
|
30
|
+
return [undefined, undefined];
|
|
20
31
|
}
|
|
21
32
|
exports.getServiceScript = getServiceScript;
|
|
22
33
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Language,
|
|
1
|
+
import { Language, TypeScriptExtraServiceScript } from '@volar/language-core';
|
|
2
2
|
import type * as ts from 'typescript';
|
|
3
3
|
import type { createSys } from './createSys';
|
|
4
4
|
export interface TypeScriptProjectHost extends Pick<ts.LanguageServiceHost, 'getLocalizedDiagnosticMessages' | 'getCurrentDirectory' | 'getCompilationSettings' | 'getProjectReferences' | 'getScriptFileNames' | 'getProjectVersion' | 'getScriptSnapshot'> {
|
|
5
5
|
}
|
|
6
6
|
export declare function createLanguageServiceHost<T>(ts: typeof import('typescript'), sys: ReturnType<typeof createSys> | ts.System, language: Language<T>, asScrpitId: (fileName: string) => T, projectHost: TypeScriptProjectHost): {
|
|
7
7
|
languageServiceHost: ts.LanguageServiceHost;
|
|
8
|
-
getExtraServiceScript: (fileName: string) =>
|
|
8
|
+
getExtraServiceScript: (fileName: string) => TypeScriptExtraServiceScript | undefined;
|
|
9
9
|
};
|
|
@@ -80,7 +80,7 @@ function createLanguageServiceHost(ts, sys, language, asScrpitId, projectHost) {
|
|
|
80
80
|
getScriptKind(fileName) {
|
|
81
81
|
sync();
|
|
82
82
|
if (extraScriptRegistry.has(fileName)) {
|
|
83
|
-
return extraScriptRegistry.get(fileName)
|
|
83
|
+
return extraScriptRegistry.get(fileName).scriptKind;
|
|
84
84
|
}
|
|
85
85
|
const sourceScript = language.scripts.get(asScrpitId(fileName));
|
|
86
86
|
if (sourceScript?.generated) {
|
|
@@ -170,7 +170,7 @@ function createLanguageServiceHost(ts, sys, language, asScrpitId, projectHost) {
|
|
|
170
170
|
for (const extraServiceScript of sourceScript.generated.languagePlugin.typescript?.getExtraServiceScripts?.(fileName, sourceScript.generated.root) ?? []) {
|
|
171
171
|
newTsVirtualFileSnapshots.add(extraServiceScript.code.snapshot);
|
|
172
172
|
tsFileNamesSet.add(extraServiceScript.fileName);
|
|
173
|
-
extraScriptRegistry.set(extraServiceScript.fileName,
|
|
173
|
+
extraScriptRegistry.set(extraServiceScript.fileName, extraServiceScript);
|
|
174
174
|
}
|
|
175
175
|
for (const code of (0, language_core_1.forEachEmbeddedCode)(sourceScript.generated.root)) {
|
|
176
176
|
newOtherVirtualFileSnapshots.add(code.snapshot);
|
|
@@ -197,7 +197,7 @@ function createLanguageServiceHost(ts, sys, language, asScrpitId, projectHost) {
|
|
|
197
197
|
function getScriptSnapshot(fileName) {
|
|
198
198
|
sync();
|
|
199
199
|
if (extraScriptRegistry.has(fileName)) {
|
|
200
|
-
return extraScriptRegistry.get(fileName)
|
|
200
|
+
return extraScriptRegistry.get(fileName).code.snapshot;
|
|
201
201
|
}
|
|
202
202
|
const sourceScript = language.scripts.get(asScrpitId(fileName));
|
|
203
203
|
if (sourceScript?.generated) {
|
|
@@ -217,7 +217,7 @@ function createLanguageServiceHost(ts, sys, language, asScrpitId, projectHost) {
|
|
|
217
217
|
}
|
|
218
218
|
const version = scriptVersions.get(fileName);
|
|
219
219
|
if (extraScriptRegistry.has(fileName)) {
|
|
220
|
-
const snapshot = extraScriptRegistry.get(fileName)
|
|
220
|
+
const snapshot = extraScriptRegistry.get(fileName).code.snapshot;
|
|
221
221
|
if (!version.map.has(snapshot)) {
|
|
222
222
|
version.map.set(snapshot, version.lastVersion++);
|
|
223
223
|
}
|
|
@@ -56,11 +56,7 @@ function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePl
|
|
|
56
56
|
const syncedScriptVersions = new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames);
|
|
57
57
|
const language = (0, language_core_1.createLanguage)([
|
|
58
58
|
...languagePlugins,
|
|
59
|
-
{
|
|
60
|
-
getLanguageId(fileName) {
|
|
61
|
-
return (0, common_1.resolveFileLanguageId)(fileName);
|
|
62
|
-
},
|
|
63
|
-
},
|
|
59
|
+
{ getLanguageId: common_1.resolveFileLanguageId },
|
|
64
60
|
], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), fileName => {
|
|
65
61
|
const version = getScriptVersion(fileName);
|
|
66
62
|
if (syncedScriptVersions.get(fileName) === version) {
|
|
@@ -87,7 +83,7 @@ function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePl
|
|
|
87
83
|
if (updateLevel >= (1)
|
|
88
84
|
|| !externalFiles.has(project)) {
|
|
89
85
|
const oldFiles = externalFiles.get(project);
|
|
90
|
-
const newFiles = (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions);
|
|
86
|
+
const newFiles = extensions.length ? (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions) : [];
|
|
91
87
|
externalFiles.set(project, newFiles);
|
|
92
88
|
if (oldFiles && !(0, createLanguageServicePlugin_1.arrayItemsEqual)(oldFiles, newFiles)) {
|
|
93
89
|
project.refreshDiagnostics();
|
|
@@ -28,11 +28,7 @@ function createLanguageServicePlugin(loadLanguagePlugins) {
|
|
|
28
28
|
const syncedScriptVersions = new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames);
|
|
29
29
|
const language = (0, language_core_1.createLanguage)([
|
|
30
30
|
...languagePlugins,
|
|
31
|
-
{
|
|
32
|
-
getLanguageId(fileName) {
|
|
33
|
-
return (0, common_1.resolveFileLanguageId)(fileName);
|
|
34
|
-
},
|
|
35
|
-
},
|
|
31
|
+
{ getLanguageId: common_1.resolveFileLanguageId },
|
|
36
32
|
], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), fileName => {
|
|
37
33
|
const version = getScriptVersion(fileName);
|
|
38
34
|
if (syncedScriptVersions.get(fileName) === version) {
|
|
@@ -56,7 +52,8 @@ function createLanguageServicePlugin(loadLanguagePlugins) {
|
|
|
56
52
|
if (updateLevel >= (1)
|
|
57
53
|
|| !externalFiles.has(project)) {
|
|
58
54
|
const oldFiles = externalFiles.get(project);
|
|
59
|
-
const
|
|
55
|
+
const extensions = projectExternalFileExtensions.get(project);
|
|
56
|
+
const newFiles = extensions?.length ? (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions) : [];
|
|
60
57
|
externalFiles.set(project, newFiles);
|
|
61
58
|
if (oldFiles && !arrayItemsEqual(oldFiles, newFiles)) {
|
|
62
59
|
project.refreshDiagnostics();
|
package/lib/resolveModuleName.js
CHANGED
|
@@ -44,6 +44,24 @@ function createResolveModuleName(ts, host, languagePlugins, getSourceScript) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
if (typescript.resolveHiddenExtensions && fileName.endsWith(`.d.ts`)) {
|
|
48
|
+
for (const { extension } of typescript.extraFileExtensions) {
|
|
49
|
+
const sourceFileName = fileName.slice(0, -`.d.ts`.length) + `.${extension}`;
|
|
50
|
+
if (fileExists(sourceFileName)) {
|
|
51
|
+
const sourceScript = getSourceScript(sourceFileName);
|
|
52
|
+
if (sourceScript?.generated) {
|
|
53
|
+
const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
|
|
54
|
+
if (serviceScript) {
|
|
55
|
+
toSourceFileInfo.set(fileName, {
|
|
56
|
+
sourceFileName,
|
|
57
|
+
extension: serviceScript.extension,
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
47
65
|
}
|
|
48
66
|
return host.fileExists(fileName);
|
|
49
67
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volar/typescript",
|
|
3
|
-
"version": "2.3.0-alpha.
|
|
3
|
+
"version": "2.3.0-alpha.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
"directory": "packages/typescript"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@volar/language-core": "2.3.0-alpha.
|
|
15
|
+
"@volar/language-core": "2.3.0-alpha.10",
|
|
16
16
|
"path-browserify": "^1.0.1",
|
|
17
17
|
"vscode-uri": "^3.0.8"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "latest",
|
|
21
21
|
"@types/path-browserify": "latest",
|
|
22
|
-
"@volar/language-service": "2.3.0-alpha.
|
|
22
|
+
"@volar/language-service": "2.3.0-alpha.10"
|
|
23
23
|
},
|
|
24
|
-
"gitHead": "
|
|
24
|
+
"gitHead": "44fffdc323ca3ff55818a8656a2726867df53a76"
|
|
25
25
|
}
|