Skip to content

Commit f041c79

Browse files
committed
fix(typescript): virtual file should update based generated snapshot rather than source script version
1 parent 410fa15 commit f041c79

File tree

1 file changed

+55
-32
lines changed

1 file changed

+55
-32
lines changed

packages/typescript/lib/node/decorateLanguageServiceHost.ts

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
import { resolveCommonLanguageId, type FileRegistry } from '@volar/language-core';
1+
import type { FileRegistry } from '@volar/language-core';
22
import type * as ts from 'typescript';
33
import { createResolveModuleName } from '../resolveModuleName';
44

55
export function decorateLanguageServiceHost(
6-
virtualFiles: FileRegistry,
6+
files: FileRegistry,
77
languageServiceHost: ts.LanguageServiceHost,
88
ts: typeof import('typescript'),
99
) {
1010

1111
let extraProjectVersion = 0;
1212

13-
const { languagePlugins } = virtualFiles;
13+
const { languagePlugins } = files;
1414
const exts = languagePlugins
1515
.map(plugin => plugin.typescript?.extraFileExtensions.map(ext => '.' + ext.extension) ?? [])
1616
.flat();
1717
const scripts = new Map<string, {
18-
version: string;
18+
projectVersion: string | undefined;
19+
version: number;
1920
snapshot: ts.IScriptSnapshot | undefined;
2021
kind: ts.ScriptKind;
2122
extension: string;
@@ -26,6 +27,7 @@ export function decorateLanguageServiceHost(
2627
const resolveModuleNames = languageServiceHost.resolveModuleNames?.bind(languageServiceHost);
2728
const getProjectVersion = languageServiceHost.getProjectVersion?.bind(languageServiceHost);
2829
const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
30+
const getScriptVersion = languageServiceHost.getScriptVersion.bind(languageServiceHost);
2931
const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
3032

3133
// path completion
@@ -44,7 +46,7 @@ export function decorateLanguageServiceHost(
4446

4547
if (languagePlugins.some(language => language.typescript?.extraFileExtensions.length)) {
4648

47-
const resolveModuleName = createResolveModuleName(ts, languageServiceHost, languagePlugins, fileName => virtualFiles.get(fileName));
49+
const resolveModuleName = createResolveModuleName(ts, languageServiceHost, languagePlugins, fileName => files.get(fileName));
4850

4951
if (resolveModuleNameLiterals) {
5052
languageServiceHost.resolveModuleNameLiterals = (
@@ -94,6 +96,13 @@ export function decorateLanguageServiceHost(
9496
}
9597
return getScriptSnapshot(fileName);
9698
};
99+
languageServiceHost.getScriptVersion = fileName => {
100+
if (exts.some(ext => fileName.endsWith(ext))) {
101+
updateScript(fileName);
102+
return scripts.get(fileName)?.version.toString() ?? '';
103+
}
104+
return getScriptVersion(fileName);
105+
};
97106

98107
if (getScriptKind) {
99108
languageServiceHost.getScriptKind = fileName => {
@@ -111,45 +120,59 @@ export function decorateLanguageServiceHost(
111120

112121
function updateScript(fileName: string) {
113122

114-
const version = languageServiceHost.getScriptVersion(fileName);
123+
const version = getProjectVersion?.();
124+
const cache = scripts.get(fileName);
115125

116-
if (version !== scripts.get(fileName)?.version) {
126+
if (version === undefined || version !== cache?.projectVersion) {
117127

118-
let extension = '.ts';
119-
let snapshotSnapshot: ts.IScriptSnapshot | undefined;
120-
let scriptKind = ts.ScriptKind.TS;
128+
const file = files.get(fileName);
129+
const script = file?.generated?.languagePlugin.typescript?.getScript(file.generated.code);
121130

122-
const snapshot = getScriptSnapshot(fileName);
131+
if (script?.code.snapshot !== cache?.snapshot) {
132+
133+
let extension = '.ts';
134+
let snapshotSnapshot: ts.IScriptSnapshot | undefined;
135+
let scriptKind = ts.ScriptKind.TS;
123136

124-
if (snapshot) {
125137
extraProjectVersion++;
126-
const sourceFile = virtualFiles.set(fileName, resolveCommonLanguageId(fileName), snapshot);
127-
if (sourceFile.generated) {
128-
const text = snapshot.getText(0, snapshot.getLength());
129-
let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
130-
const script = sourceFile.generated.languagePlugin.typescript?.getScript(sourceFile.generated.code);
131-
if (script) {
138+
139+
if (script) {
140+
if (file?.generated) {
141+
const text = file.snapshot.getText(0, file.snapshot.getLength());
142+
let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
132143
extension = script.extension;
133144
scriptKind = script.scriptKind;
134145
patchedText += script.code.snapshot.getText(0, script.code.snapshot.getLength());
146+
snapshotSnapshot = ts.ScriptSnapshot.fromString(patchedText);
147+
if (file.generated.languagePlugin.typescript?.getExtraScripts) {
148+
console.warn('getExtraScripts() is not available in this use case.');
149+
}
135150
}
136-
snapshotSnapshot = ts.ScriptSnapshot.fromString(patchedText);
137-
if (sourceFile.generated.languagePlugin.typescript?.getExtraScripts) {
138-
console.warn('getExtraScripts() is not available in this use case.');
139-
}
151+
}
152+
else if (files.get(fileName)) {
153+
files.delete(fileName);
154+
}
155+
156+
if (!cache) {
157+
scripts.set(fileName, {
158+
projectVersion: version,
159+
version: 0,
160+
extension,
161+
snapshot: snapshotSnapshot,
162+
kind: scriptKind,
163+
});
164+
}
165+
else {
166+
cache.projectVersion = version;
167+
cache.version++;
168+
cache.extension = extension;
169+
cache.snapshot = snapshotSnapshot;
170+
cache.kind = scriptKind;
140171
}
141172
}
142-
else if (virtualFiles.get(fileName)) {
143-
extraProjectVersion++;
144-
virtualFiles.delete(fileName);
173+
else if (cache) {
174+
cache.projectVersion = version;
145175
}
146-
147-
scripts.set(fileName, {
148-
version,
149-
extension,
150-
snapshot: snapshotSnapshot,
151-
kind: scriptKind,
152-
});
153176
}
154177

155178
return scripts.get(fileName);

0 commit comments

Comments
 (0)