From b09c25ba5eb3c699884128c946f0ec5c5b5d3f30 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 6 Apr 2026 07:21:05 +0000 Subject: [PATCH] fix: scope addRootPath to document's workspace folder in multi-root workspaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a user has a multi-root workspace with per-folder phpcbf settings, addRootPath() was iterating over ALL workspace folders to resolve a relative executablePath. If multiple folders contained an executable at the same relative path, the last one iterated would win — regardless of which document was actually being formatted. Fix: accept an optional configUri parameter and, when provided, resolve the relative path against that document's workspace folder only. This ensures folder A's document always uses folder A's resolved executable, not folder B's. Also replace the deprecated asynchronous fs.exists() callback with the synchronous fs.existsSync(), eliminating the async race condition where format() could be called before the callback had set executablePath. Relates to: #36 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- extension.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/extension.js b/extension.js index 6457e71..aac66e5 100644 --- a/extension.js +++ b/extension.js @@ -45,13 +45,13 @@ class PHPCBF { // ${workspaceRoot} is deprecated if (this.executablePath.startsWith("${workspaceRoot}")) { - this.addRootPath("${workspaceRoot}"); + this.addRootPath("${workspaceRoot}", configUri); } if (this.executablePath.startsWith("${workspaceFolder}")) { - this.addRootPath("${workspaceFolder}"); + this.addRootPath("${workspaceFolder}", configUri); } if (this.executablePath.startsWith(".")) { - this.addRootPath("."); + this.addRootPath(".", configUri); } if (this.executablePath.startsWith("~")) { this.executablePath = this.executablePath.replace( @@ -226,16 +226,23 @@ class PHPCBF { return promise; } - addRootPath(prefix) { - const resources = []; - if (workspace.workspaceFolders) { + addRootPath(prefix, configUri) { + // Determine the workspace folder for the document being formatted. + // When configUri is provided, use that folder (correct for multi-root + // workspaces where each folder may have its own per-folder executablePath). + // Fall back to iterating all workspace folders when no URI is available + // (e.g. at extension activation before any document is formatted). + let resources = []; + if (configUri) { + resources = [configUri]; + } else if (workspace.workspaceFolders) { for (let wsFolder of workspace.workspaceFolders) { resources.push(wsFolder.uri); } } else { const editor = window.activeTextEditor; if (editor) { - resources.push(editor.document.uri); + resources = [editor.document.uri]; } } for (let resource of resources) { @@ -247,11 +254,9 @@ class PHPCBF { prefix, rootPath ); - fs.exists(tmpExecutablePath, exists => { - if (exists) { - this.executablePath = tmpExecutablePath; - } - }); + if (fs.existsSync(tmpExecutablePath)) { + this.executablePath = tmpExecutablePath; + } } } }