From b2d89388507b36772d973b5662bd4590949a3e4d Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 10 Nov 2025 10:30:48 -0600 Subject: [PATCH 1/2] fix: web support for treeContainer without cwd --- src/resolve/treeContainers.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/resolve/treeContainers.ts b/src/resolve/treeContainers.ts index a49abae3b..0e5493d83 100644 --- a/src/resolve/treeContainers.ts +++ b/src/resolve/treeContainers.ts @@ -36,6 +36,12 @@ const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sd * Extend this base class to implement a custom container. */ export abstract class TreeContainer { + protected cwd: string; + + /** specify a cwd to use instead of the real cwd. Useful for tests and web environments where process.cwd is undefined */ + public constructor(cwd: string = process.cwd()) { + this.cwd = cwd; + } /** * Searches for a metadata component file in a container directory. * @@ -104,31 +110,31 @@ export abstract class TreeContainer { export class NodeFSTreeContainer extends TreeContainer { public isDirectory(fsPath: SourcePath): boolean { // use stat instead of lstat to follow symlinks - return statSync(fsPath).isDirectory(); + return statSync(join(this.cwd, fsPath)).isDirectory(); } public exists(fsPath: SourcePath): boolean { - return existsSync(fsPath); + return existsSync(join(this.cwd, fsPath)); } public readDirectory(fsPath: SourcePath): string[] { - return readdirSync(fsPath); + return readdirSync(join(this.cwd, fsPath)); } public readFile(fsPath: SourcePath): Promise { // significant enough performance increase using sync instead of fs.promise version - return Promise.resolve(readFileSync(fsPath)); + return Promise.resolve(readFileSync(join(this.cwd, fsPath))); } public readFileSync(fsPath: SourcePath): Buffer { - return readFileSync(fsPath); + return readFileSync(join(this.cwd, fsPath)); } public stream(fsPath: SourcePath): Readable { if (!this.exists(fsPath)) { throw new Error(`File not found: ${fsPath}`); } - return createReadStream(fsPath); + return createReadStream(join(this.cwd, fsPath)); } } From 1e44fc9c7809d9e999d5b5e14ddc65c8e86f781f Mon Sep 17 00:00:00 2001 From: mshanemc Date: Mon, 10 Nov 2025 10:59:08 -0600 Subject: [PATCH 2/2] fix: only apply cwd if provided --- src/resolve/treeContainers.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/resolve/treeContainers.ts b/src/resolve/treeContainers.ts index 0e5493d83..24192686a 100644 --- a/src/resolve/treeContainers.ts +++ b/src/resolve/treeContainers.ts @@ -36,10 +36,10 @@ const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sd * Extend this base class to implement a custom container. */ export abstract class TreeContainer { - protected cwd: string; + protected cwd?: string; /** specify a cwd to use instead of the real cwd. Useful for tests and web environments where process.cwd is undefined */ - public constructor(cwd: string = process.cwd()) { + public constructor(cwd?: string) { this.cwd = cwd; } /** @@ -52,14 +52,20 @@ export abstract class TreeContainer { */ public find(fileType: 'content' | 'metadataXml', name: string, directory: string): string | undefined { const fileName = this.readDirectory(directory).find((entry) => { - const parsed = parseMetadataXml(join(directory, entry)); + const parsed = parseMetadataXml(this.getUpdatedFsPath(join(directory, entry))); const metaXmlCondition = fileType === 'metadataXml' ? !!parsed : !parsed; return baseName(entry) === name && metaXmlCondition; }); if (fileName) { - return join(directory, fileName); + return this.getUpdatedFsPath(join(directory, fileName)); } } + + /** if the container has cwd set, apply it to the path */ + protected getUpdatedFsPath(fsPath: SourcePath): string { + return this.cwd ? join(this.cwd, fsPath) : fsPath; + } + /** * Whether or not a file path exists in the container. * @@ -110,31 +116,31 @@ export abstract class TreeContainer { export class NodeFSTreeContainer extends TreeContainer { public isDirectory(fsPath: SourcePath): boolean { // use stat instead of lstat to follow symlinks - return statSync(join(this.cwd, fsPath)).isDirectory(); + return statSync(this.getUpdatedFsPath(fsPath)).isDirectory(); } public exists(fsPath: SourcePath): boolean { - return existsSync(join(this.cwd, fsPath)); + return existsSync(this.getUpdatedFsPath(fsPath)); } public readDirectory(fsPath: SourcePath): string[] { - return readdirSync(join(this.cwd, fsPath)); + return readdirSync(this.getUpdatedFsPath(fsPath)); } public readFile(fsPath: SourcePath): Promise { // significant enough performance increase using sync instead of fs.promise version - return Promise.resolve(readFileSync(join(this.cwd, fsPath))); + return Promise.resolve(readFileSync(this.getUpdatedFsPath(fsPath))); } public readFileSync(fsPath: SourcePath): Buffer { - return readFileSync(join(this.cwd, fsPath)); + return readFileSync(this.getUpdatedFsPath(fsPath)); } public stream(fsPath: SourcePath): Readable { if (!this.exists(fsPath)) { throw new Error(`File not found: ${fsPath}`); } - return createReadStream(join(this.cwd, fsPath)); + return createReadStream(this.getUpdatedFsPath(fsPath)); } }