@volar/typescript 2.3.0-alpha.1 → 2.3.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/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 +109 -54
- package/lib/node/utils.d.ts +2 -2
- package/lib/node/utils.js +15 -4
- 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, sourceScript] = (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)(sourceScript, 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, sourceScript] = (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)(sourceScript, 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, sourceScript] = (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)(sourceScript, 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>(sourceScript: 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(sourceScript: SourceScript<string
|
|
14
|
-
export declare function transformTextSpan(sourceScript: SourceScript<string
|
|
15
|
-
export declare function toSourceOffset(sourceScript: SourceScript<string>,
|
|
16
|
-
export declare function
|
|
17
|
-
export declare function
|
|
13
|
+
export declare function transformTextChange(sourceScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, textChange: ts.TextChange, filter: (data: CodeInformation) => boolean): [string, ts.TextChange] | undefined;
|
|
14
|
+
export declare function transformTextSpan(sourceScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, textSpan: ts.TextSpan, filter: (data: CodeInformation) => boolean): [string, ts.TextSpan] | undefined;
|
|
15
|
+
export declare function toSourceOffset(sourceScript: SourceScript<string> | undefined, language: Language<string>, serviceScript: TypeScriptServiceScript, position: number, filter: (data: CodeInformation) => boolean): [fileName: string, offset: number] | undefined;
|
|
16
|
+
export declare function toSourceOffsets(sourceScript: 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(sourceScript, 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(sourceScript,
|
|
33
|
-
|
|
33
|
+
const [sourceSpanFileName, sourceSpan] = transformTextSpan(sourceScript, 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,46 @@ function fillSourceFileText(language, sourceFile) {
|
|
|
58
68
|
return;
|
|
59
69
|
}
|
|
60
70
|
transformedSourceFile.add(sourceFile);
|
|
61
|
-
const [serviceScript
|
|
62
|
-
if (serviceScript) {
|
|
71
|
+
const [serviceScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
|
|
72
|
+
if (serviceScript && !serviceScript.preventLeadingOffset) {
|
|
73
|
+
const sourceScript = language.scripts.fromVirtualCode(serviceScript.code);
|
|
63
74
|
sourceFile.text = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength())
|
|
64
75
|
+ sourceFile.text.substring(sourceScript.snapshot.getLength());
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
78
|
exports.fillSourceFileText = fillSourceFileText;
|
|
68
79
|
function transformFileTextChanges(language, changes, filter) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
span: span.textSpan,
|
|
79
|
-
};
|
|
80
|
+
const changesPerFile = {};
|
|
81
|
+
const newFiles = new Set();
|
|
82
|
+
for (const fileChanges of changes) {
|
|
83
|
+
const [_, source] = (0, utils_1.getServiceScript)(language, fileChanges.fileName);
|
|
84
|
+
if (source) {
|
|
85
|
+
fileChanges.textChanges.forEach(c => {
|
|
86
|
+
const { fileName, textSpan } = transformSpan(language, fileChanges.fileName, c.span, filter) ?? {};
|
|
87
|
+
if (fileName && textSpan) {
|
|
88
|
+
(changesPerFile[fileName] ?? (changesPerFile[fileName] = [])).push({ ...c, span: textSpan });
|
|
80
89
|
}
|
|
81
|
-
})
|
|
82
|
-
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const list = (changesPerFile[fileChanges.fileName] ?? (changesPerFile[fileChanges.fileName] = []));
|
|
94
|
+
fileChanges.textChanges.forEach(c => {
|
|
95
|
+
list.push(c);
|
|
96
|
+
});
|
|
97
|
+
if (fileChanges.isNewFile) {
|
|
98
|
+
newFiles.add(fileChanges.fileName);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
83
101
|
}
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
const result = [];
|
|
103
|
+
for (const fileName in changesPerFile) {
|
|
104
|
+
result.push({
|
|
105
|
+
fileName,
|
|
106
|
+
isNewFile: newFiles.has(fileName),
|
|
107
|
+
textChanges: changesPerFile[fileName]
|
|
108
|
+
});
|
|
86
109
|
}
|
|
110
|
+
return result;
|
|
87
111
|
}
|
|
88
112
|
exports.transformFileTextChanges = transformFileTextChanges;
|
|
89
113
|
function transformDocumentSpan(language, documentSpan, filter, shouldFallback) {
|
|
@@ -115,12 +139,12 @@ function transformSpan(language, fileName, textSpan, filter) {
|
|
|
115
139
|
if (!fileName || !textSpan) {
|
|
116
140
|
return;
|
|
117
141
|
}
|
|
118
|
-
const [
|
|
119
|
-
if (
|
|
120
|
-
const sourceSpan = transformTextSpan(
|
|
121
|
-
if (sourceSpan) {
|
|
142
|
+
const [serviceScript] = (0, utils_1.getServiceScript)(language, fileName);
|
|
143
|
+
if (serviceScript) {
|
|
144
|
+
const [sourceSpanFileName, sourceSpan] = transformTextSpan(undefined, language, serviceScript, textSpan, filter) ?? [];
|
|
145
|
+
if (sourceSpan && sourceSpanFileName) {
|
|
122
146
|
return {
|
|
123
|
-
fileName,
|
|
147
|
+
fileName: sourceSpanFileName,
|
|
124
148
|
textSpan: sourceSpan,
|
|
125
149
|
};
|
|
126
150
|
}
|
|
@@ -133,49 +157,80 @@ function transformSpan(language, fileName, textSpan, filter) {
|
|
|
133
157
|
}
|
|
134
158
|
}
|
|
135
159
|
exports.transformSpan = transformSpan;
|
|
136
|
-
function transformTextChange(sourceScript,
|
|
137
|
-
const sourceSpan = transformTextSpan(sourceScript,
|
|
138
|
-
if (sourceSpan) {
|
|
139
|
-
return {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
160
|
+
function transformTextChange(sourceScript, language, serviceScript, textChange, filter) {
|
|
161
|
+
const [sourceSpanFileName, sourceSpan] = transformTextSpan(sourceScript, language, serviceScript, textChange.span, filter) ?? [];
|
|
162
|
+
if (sourceSpan && sourceSpanFileName) {
|
|
163
|
+
return [sourceSpanFileName, {
|
|
164
|
+
newText: textChange.newText,
|
|
165
|
+
span: sourceSpan,
|
|
166
|
+
}];
|
|
143
167
|
}
|
|
168
|
+
return undefined;
|
|
144
169
|
}
|
|
145
170
|
exports.transformTextChange = transformTextChange;
|
|
146
|
-
function transformTextSpan(sourceScript,
|
|
171
|
+
function transformTextSpan(sourceScript, language, serviceScript, textSpan, filter) {
|
|
147
172
|
const start = textSpan.start;
|
|
148
173
|
const end = textSpan.start + textSpan.length;
|
|
149
|
-
const sourceStart
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
174
|
+
for (const sourceStart of toSourceOffsets(sourceScript, language, serviceScript, start, filter)) {
|
|
175
|
+
for (const sourceEnd of toSourceOffsets(sourceScript, language, serviceScript, end, filter)) {
|
|
176
|
+
if (sourceStart[0] === sourceEnd[0]
|
|
177
|
+
&& sourceEnd[1] >= sourceStart[1]) {
|
|
178
|
+
return [sourceStart[0], {
|
|
179
|
+
start: sourceStart[1],
|
|
180
|
+
length: sourceEnd[1] - sourceStart[1],
|
|
181
|
+
}];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
156
184
|
}
|
|
157
185
|
}
|
|
158
186
|
exports.transformTextSpan = transformTextSpan;
|
|
159
|
-
function toSourceOffset(sourceScript,
|
|
160
|
-
for (const
|
|
161
|
-
|
|
162
|
-
return sourceOffset;
|
|
163
|
-
}
|
|
187
|
+
function toSourceOffset(sourceScript, language, serviceScript, position, filter) {
|
|
188
|
+
for (const source of toSourceOffsets(sourceScript, language, serviceScript, position, filter)) {
|
|
189
|
+
return source;
|
|
164
190
|
}
|
|
165
191
|
}
|
|
166
192
|
exports.toSourceOffset = toSourceOffset;
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
193
|
+
function* toSourceOffsets(sourceScript, language, serviceScript, position, filter) {
|
|
194
|
+
if (sourceScript) {
|
|
195
|
+
const map = language.maps.get(serviceScript.code, sourceScript);
|
|
196
|
+
for (const [sourceOffset, mapping] of map.getSourceOffsets(position - getMappingOffset(language, serviceScript))) {
|
|
197
|
+
if (filter(mapping.data)) {
|
|
198
|
+
yield [sourceScript.id, sourceOffset];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
for (const [fileName, _snapshot, map] of language.maps.forEach(serviceScript.code)) {
|
|
204
|
+
for (const [sourceOffset, mapping] of map.getSourceOffsets(position - getMappingOffset(language, serviceScript))) {
|
|
205
|
+
if (filter(mapping.data)) {
|
|
206
|
+
yield [fileName, sourceOffset];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
171
209
|
}
|
|
172
210
|
}
|
|
173
211
|
}
|
|
212
|
+
exports.toSourceOffsets = toSourceOffsets;
|
|
213
|
+
function toGeneratedOffset(language, serviceScript, sourceScript, position, filter) {
|
|
214
|
+
for (const [generateOffset] of toGeneratedOffsets(language, serviceScript, sourceScript, position, filter)) {
|
|
215
|
+
return generateOffset;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
174
218
|
exports.toGeneratedOffset = toGeneratedOffset;
|
|
175
|
-
function* toGeneratedOffsets(sourceScript,
|
|
219
|
+
function* toGeneratedOffsets(language, serviceScript, sourceScript, position, filter) {
|
|
220
|
+
const map = language.maps.get(serviceScript.code, sourceScript);
|
|
176
221
|
for (const [generateOffset, mapping] of map.getGeneratedOffsets(position)) {
|
|
177
|
-
|
|
222
|
+
if (filter(mapping.data)) {
|
|
223
|
+
yield [generateOffset + getMappingOffset(language, serviceScript), mapping];
|
|
224
|
+
}
|
|
178
225
|
}
|
|
179
226
|
}
|
|
180
227
|
exports.toGeneratedOffsets = toGeneratedOffsets;
|
|
228
|
+
function getMappingOffset(language, serviceScript) {
|
|
229
|
+
if (serviceScript.preventLeadingOffset) {
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
const sourceScript = language.scripts.fromVirtualCode(serviceScript.code);
|
|
233
|
+
return sourceScript.snapshot.getLength();
|
|
234
|
+
}
|
|
235
|
+
exports.getMappingOffset = getMappingOffset;
|
|
181
236
|
//# 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): [serviceScript: TypeScriptServiceScript, targetScript: SourceScript<string>, sourceScript: SourceScript<string>] | [serviceScript: undefined, sourceScript: SourceScript<string>, sourceScript: SourceScript<string>] | [serviceScript: undefined, sourceScript: undefined, targetScript: undefined];
|
package/lib/node/utils.js
CHANGED
|
@@ -7,13 +7,24 @@ 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, sourceScript, targetScript];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (sourceScript?.associatedOnly) {
|
|
22
|
+
return [undefined, sourceScript, 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, sourceScript];
|
|
17
28
|
}
|
|
18
29
|
}
|
|
19
30
|
return [undefined, undefined, undefined];
|
|
@@ -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.11",
|
|
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.11",
|
|
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.11"
|
|
23
23
|
},
|
|
24
|
-
"gitHead": "
|
|
24
|
+
"gitHead": "c83f835629496d3a4cc38f4b789bb676d07a2118"
|
|
25
25
|
}
|