diff --git a/packages/typescript/lib/node/decorateLanguageServiceHost.ts b/packages/typescript/lib/node/decorateLanguageServiceHost.ts index a131ec5b..70c3e151 100644 --- a/packages/typescript/lib/node/decorateLanguageServiceHost.ts +++ b/packages/typescript/lib/node/decorateLanguageServiceHost.ts @@ -1,21 +1,22 @@ -import { resolveCommonLanguageId, type FileRegistry } from '@volar/language-core'; +import type { FileRegistry } from '@volar/language-core'; import type * as ts from 'typescript'; import { createResolveModuleName } from '../resolveModuleName'; export function decorateLanguageServiceHost( - virtualFiles: FileRegistry, + files: FileRegistry, languageServiceHost: ts.LanguageServiceHost, ts: typeof import('typescript'), ) { let extraProjectVersion = 0; - const { languagePlugins } = virtualFiles; + const { languagePlugins } = files; const exts = languagePlugins .map(plugin => plugin.typescript?.extraFileExtensions.map(ext => '.' + ext.extension) ?? []) .flat(); const scripts = new Map language.typescript?.extraFileExtensions.length)) { - const resolveModuleName = createResolveModuleName(ts, languageServiceHost, languagePlugins, fileName => virtualFiles.get(fileName)); + const resolveModuleName = createResolveModuleName(ts, languageServiceHost, languagePlugins, fileName => files.get(fileName)); if (resolveModuleNameLiterals) { languageServiceHost.resolveModuleNameLiterals = ( @@ -94,6 +96,13 @@ export function decorateLanguageServiceHost( } return getScriptSnapshot(fileName); }; + languageServiceHost.getScriptVersion = fileName => { + if (exts.some(ext => fileName.endsWith(ext))) { + updateScript(fileName); + return scripts.get(fileName)?.version.toString() ?? ''; + } + return getScriptVersion(fileName); + }; if (getScriptKind) { languageServiceHost.getScriptKind = fileName => { @@ -111,45 +120,59 @@ export function decorateLanguageServiceHost( function updateScript(fileName: string) { - const version = languageServiceHost.getScriptVersion(fileName); + const version = getProjectVersion?.(); + const cache = scripts.get(fileName); - if (version !== scripts.get(fileName)?.version) { + if (version === undefined || version !== cache?.projectVersion) { - let extension = '.ts'; - let snapshotSnapshot: ts.IScriptSnapshot | undefined; - let scriptKind = ts.ScriptKind.TS; + const file = files.get(fileName); + const script = file?.generated?.languagePlugin.typescript?.getScript(file.generated.code); - const snapshot = getScriptSnapshot(fileName); + if (script?.code.snapshot !== cache?.snapshot) { + + let extension = '.ts'; + let snapshotSnapshot: ts.IScriptSnapshot | undefined; + let scriptKind = ts.ScriptKind.TS; - if (snapshot) { extraProjectVersion++; - const sourceFile = virtualFiles.set(fileName, resolveCommonLanguageId(fileName), snapshot); - if (sourceFile.generated) { - const text = snapshot.getText(0, snapshot.getLength()); - let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n'); - const script = sourceFile.generated.languagePlugin.typescript?.getScript(sourceFile.generated.code); - if (script) { + + if (script) { + if (file?.generated) { + const text = file.snapshot.getText(0, file.snapshot.getLength()); + let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n'); extension = script.extension; scriptKind = script.scriptKind; patchedText += script.code.snapshot.getText(0, script.code.snapshot.getLength()); + snapshotSnapshot = ts.ScriptSnapshot.fromString(patchedText); + if (file.generated.languagePlugin.typescript?.getExtraScripts) { + console.warn('getExtraScripts() is not available in this use case.'); + } } - snapshotSnapshot = ts.ScriptSnapshot.fromString(patchedText); - if (sourceFile.generated.languagePlugin.typescript?.getExtraScripts) { - console.warn('getExtraScripts() is not available in this use case.'); - } + } + else if (files.get(fileName)) { + files.delete(fileName); + } + + if (!cache) { + scripts.set(fileName, { + projectVersion: version, + version: 0, + extension, + snapshot: snapshotSnapshot, + kind: scriptKind, + }); + } + else { + cache.projectVersion = version; + cache.version++; + cache.extension = extension; + cache.snapshot = snapshotSnapshot; + cache.kind = scriptKind; } } - else if (virtualFiles.get(fileName)) { - extraProjectVersion++; - virtualFiles.delete(fileName); + else if (cache) { + cache.projectVersion = version; } - - scripts.set(fileName, { - version, - extension, - snapshot: snapshotSnapshot, - kind: scriptKind, - }); } return scripts.get(fileName);