From 7c76ec560698e9db6343329bd978d5a24cd03a90 Mon Sep 17 00:00:00 2001 From: "Lyu, Wei-Da" <36730922+jasonlyu123@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:46:16 +0800 Subject: [PATCH] fix: check project files update more aggressively before assigning service (#2518) #2516 Most of the time, the didOpen request is earlier than the watcher event. So if the file doesn't exist in the GlobalSnapshotManager we manually invoke the project file update check. This won't cause 2 project files check because if the file already is a project file we won't check project files. --- .../src/plugins/typescript/service.ts | 22 ++++++++++++--- .../test/plugins/typescript/service.test.ts | 27 +++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/packages/language-server/src/plugins/typescript/service.ts b/packages/language-server/src/plugins/typescript/service.ts index 0e0d0f27a..caf8f0350 100644 --- a/packages/language-server/src/plugins/typescript/service.ts +++ b/packages/language-server/src/plugins/typescript/service.ts @@ -40,7 +40,7 @@ export interface LanguageServiceContainer { deleteSnapshot(filePath: string): void; invalidateModuleCache(filePath: string[]): void; scheduleProjectFileUpdate(watcherNewFiles: string[]): void; - ensureProjectFileUpdates(): void; + ensureProjectFileUpdates(newFile?: string): void; updateTsOrJsFile(fileName: string, changes?: TextDocumentContentChangeEvent[]): void; /** * Checks if a file is present in the project. @@ -225,7 +225,7 @@ export async function getService( service: LanguageServiceContainer, triedTsConfig: Set ): Promise { - service.ensureProjectFileUpdates(); + service.ensureProjectFileUpdates(path); if (service.snapshotManager.isProjectFile(path)) { return service; } @@ -648,9 +648,23 @@ async function createLanguageService( } } - function ensureProjectFileUpdates(): void { + function ensureProjectFileUpdates(newFile?: string): void { const info = parsedTsConfigInfo.get(tsconfigPath); - if (!info || !info.pendingProjectFileUpdate) { + if (!info) { + return; + } + + if ( + newFile && + !info.pendingProjectFileUpdate && + // no global snapshots yet when initial load pending + !snapshotManager.isProjectFile(newFile) && + !docContext.globalSnapshotsManager.get(newFile) + ) { + scheduleProjectFileUpdate([newFile]); + } + + if (!info.pendingProjectFileUpdate) { return; } const projectFileCountBefore = snapshotManager.getProjectFileNames().length; diff --git a/packages/language-server/test/plugins/typescript/service.test.ts b/packages/language-server/test/plugins/typescript/service.test.ts index 71db7f064..e0aa9ffd4 100644 --- a/packages/language-server/test/plugins/typescript/service.test.ts +++ b/packages/language-server/test/plugins/typescript/service.test.ts @@ -657,6 +657,33 @@ describe('service', () => { assert.deepStrictEqual(findError(ls2), undefined); }); + it('assigns newly created files to the right service before the watcher trigger', async () => { + const dirPath = getRandomVirtualDirPath(testDir); + const { virtualSystem, lsDocumentContext, rootUris } = setup(); + + const tsconfigPath = path.join(dirPath, 'tsconfig.json'); + virtualSystem.writeFile( + tsconfigPath, + JSON.stringify({ + compilerOptions: {} + }) + ); + + const svelteFilePath = path.join(dirPath, 'random.svelte'); + + virtualSystem.writeFile(svelteFilePath, ''); + + const ls = await getService(svelteFilePath, rootUris, lsDocumentContext); + + assert.equal(normalizePath(ls.tsconfigPath), normalizePath(tsconfigPath)); + + const svelteFilePath2 = path.join(dirPath, 'random2.svelte'); + virtualSystem.writeFile(svelteFilePath2, ''); + + const ls2 = await getService(svelteFilePath2, rootUris, lsDocumentContext); + assert.equal(normalizePath(ls2.tsconfigPath), normalizePath(tsconfigPath)); + }); + function getSemanticDiagnosticsMessages(ls: LanguageServiceContainer, filePath: string) { return ls .getService()