From 28f9fba57b9d3f95112e18cca04e38073e9def72 Mon Sep 17 00:00:00 2001 From: Sysix <3897725+Sysix@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:27:01 +0000 Subject: [PATCH] fix(vscode): fix nested search for binaries (#17832) I broke the search with the `{}` pattern. This PR fixes it by searching sequentially up the directories. Now the test is working too. --- editors/vscode/client/ConfigService.ts | 41 +++++++++++-------- .../vscode/tests/unit/ConfigService.spec.ts | 4 +- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/editors/vscode/client/ConfigService.ts b/editors/vscode/client/ConfigService.ts index 63f766bc4c53b..1fcf596d847b9 100644 --- a/editors/vscode/client/ConfigService.ts +++ b/editors/vscode/client/ConfigService.ts @@ -184,25 +184,32 @@ export class ConfigService implements IDisposable { */ private async searchNodeModulesBin(binaryName: string): Promise { const cts = new CancellationTokenSource(); - setTimeout(() => cts.cancel(), 10000); // cancel after 10 seconds + setTimeout(() => cts.cancel(), 20000); // cancel after 20 seconds try { - // bun package manager uses `.exe` extension on Windows - // search for both with and without `.exe` extension - const extension = process.platform === "win32" ? "{,.exe}" : ""; - // maybe use `tinyglobby` later for better performance, VSCode can be slow on globbing large projects. - const files = await workspace.findFiles( - // search workspace root plus up to 3 subdirectory levels for the binary path - `{,*/,*/*,*/*/*}/node_modules/.bin/${binaryName}${extension}`, - undefined, - 1, - cts.token, - ); - - return files.length > 0 ? files[0].fsPath : undefined; - } catch { - return undefined; - } + // search workspace root plus up to 3 subdirectory levels for the binary path + let patterns = [ + `node_modules/.bin/${binaryName}`, + `*/node_modules/.bin/${binaryName}`, + `*/*/node_modules/.bin/${binaryName}`, + `*/*/*/node_modules/.bin/${binaryName}`, + ]; + + if (process.platform === "win32") { + // bun package manager uses `.exe` extension on Windows + // search for both with and without `.exe` extension + patterns = patterns.flatMap((pattern) => [`${pattern}`, `${pattern}.exe`]); + } + + for (const pattern of patterns) { + // maybe use `tinyglobby` later for better performance, VSCode can be slow on globbing large projects. + // oxlint-disable-next-line no-await-in-loop -- search sequentially up the directories + const files = await workspace.findFiles(pattern, null, 1, cts.token); + if (files.length > 0) { + return files[0].fsPath; + } + } + } catch {} } private async onVscodeConfigChange(event: ConfigurationChangeEvent): Promise { diff --git a/editors/vscode/tests/unit/ConfigService.spec.ts b/editors/vscode/tests/unit/ConfigService.spec.ts index 9b81884e19567..44520ae8bb711 100644 --- a/editors/vscode/tests/unit/ConfigService.spec.ts +++ b/editors/vscode/tests/unit/ConfigService.spec.ts @@ -154,8 +154,7 @@ suite("ConfigService", () => { strictEqual(relativeServerPath, `${workspace_path}\\relative\\oxlint`); }); - // Skipped due to Test API limitation? - test.skip("resolves binary path in multi-folder workspace", async () => { + test("resolves binary path in multi-folder workspace", async () => { const service = new ConfigService(); const workspace_path = getWorkspaceFolderPlatformSafe(); @@ -163,7 +162,6 @@ suite("ConfigService", () => { await createWorkspaceFolderFileUri("node_modules/.bin/oxlint", WORKSPACE_SECOND_FOLDER); const absoluteServerPath = await service.getOxlintServerBinPath(); - // returns undefined, but it should search with glob and return the first found binary strictEqual(absoluteServerPath, `${workspace_path}/node_modules/.bin/oxlint`); await deleteWorkspaceFolderFileUri("node_modules/.bin/oxlint");