Skip to content

Commit 66d16b4

Browse files
committed
fix: add better compatibility for yarn and pnpm binaries
Signed-off-by: Ruben Romero Montes <[email protected]>
1 parent 33d79db commit 66d16b4

File tree

2 files changed

+67
-5
lines changed

2 files changed

+67
-5
lines changed

src/providers/base_javascript.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import fs from 'node:fs'
22
import os from "node:os";
33
import path from 'node:path'
44

5-
import { getCustomPath, invokeCommand, toPurl, toPurlFromString } from "../tools.js";
5+
import { getCustom, getCustomPath, invokeCommand, toPurl, toPurlFromString } from "../tools.js";
66
import Sbom from '../sbom.js'
77
import Manifest from './manifest.js';
88

@@ -314,10 +314,56 @@ export default class Base_javascript {
314314
if(!opts.cwd) {
315315
opts.cwd = path.dirname(this.#manifest.manifestPath);
316316
}
317-
return invokeCommand(this.#cmd, args, opts);
317+
318+
// Add version manager paths for JavaScript package managers
319+
if (process.platform !== 'win32') {
320+
const versionManagerPaths = [];
321+
322+
// Add fnm path if available
323+
const fnmDir = getCustom('FNM_DIR', null, opts);
324+
if (fnmDir) {
325+
versionManagerPaths.push(`${fnmDir}/current/bin`);
326+
}
327+
328+
// Add nvm path if available
329+
const nvmDir = getCustom('NVM_DIR', null, opts);
330+
if (nvmDir) {
331+
versionManagerPaths.push(`${nvmDir}/current/bin`);
332+
}
333+
334+
// Add local node_modules/.bin path
335+
const localBinPath = path.join(opts.cwd, 'node_modules', '.bin');
336+
if (fs.existsSync(localBinPath)) {
337+
versionManagerPaths.push(localBinPath);
338+
}
339+
340+
if (versionManagerPaths.length > 0) {
341+
opts = {
342+
...opts,
343+
env: {
344+
...opts.env,
345+
PATH: `${versionManagerPaths.join(':')}:${process.env.PATH}`
346+
}
347+
};
348+
}
349+
}
350+
351+
// Try to find the command in the following order:
352+
// 1. Custom path from environment/opts (via getCustomPath)
353+
// 2. Local node_modules/.bin
354+
// 3. Global installation
355+
let cmd = this.#cmd;
356+
if (!fs.existsSync(cmd)) {
357+
const localCmd = path.join(opts.cwd, 'node_modules', '.bin', this._cmdName());
358+
if (fs.existsSync(localCmd)) {
359+
cmd = localCmd;
360+
}
361+
}
362+
363+
return invokeCommand(cmd, args, opts);
318364
} catch (error) {
319365
if (error.code === 'ENOENT') {
320-
throw new Error(`${this.#cmd} is not accessible.`);
366+
throw new Error(`${this.#cmd} is not accessible. Please ensure it is installed via npm, corepack, or your version manager.`);
321367
}
322368
if (error.code === 'EACCES') {
323369
throw new Error(`Permission denied when executing ${this.#cmd}. Please check file permissions.`);

src/tools.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,25 @@ export function invokeCommand(bin, args, opts={}) {
161161
// https://github.com/nodejs/node/issues/52681#issuecomment-2076426887
162162
if (process.platform === 'win32') {
163163
opts = {...opts, shell: true}
164-
args = args.map(arg => handleSpacesInPath(arg))
165-
bin = handleSpacesInPath(bin)
166164
}
165+
// Handle spaces in paths for all platforms
166+
args = args.map(arg => handleSpacesInPath(arg))
167+
bin = handleSpacesInPath(bin)
168+
169+
opts = {
170+
...opts,
171+
env: {
172+
...process.env,
173+
PATH: process.env.PATH
174+
}
175+
};
176+
177+
178+
// Add maxBuffer option to handle large outputs
179+
opts = {
180+
...opts,
181+
maxBuffer: 10 * 1024 * 1024 // 10MB buffer
182+
};
167183

168184
return execFileSync(bin, args, {...{stdio: 'pipe', encoding: 'utf-8'}, ...opts})
169185
}

0 commit comments

Comments
 (0)