Spawn correct command for Win32

This commit is contained in:
Reinier Criel 2026-01-12 12:55:37 -08:00
parent acb4aa1a13
commit 149dcd0202

View file

@ -1,62 +1,6 @@
import { spawn, execSync } from "child_process"; import { spawn, execSync } from "child_process";
import os from "os"; import os from "os";
/**
* @param {string} arg
*
* @returns {string}
*/
function sanitizeShellArgument(arg) {
// If argument contains shell metacharacters, wrap in double quotes
// and escape characters that are special even inside double quotes
if (hasShellMetaChars(arg)) {
// Inside double quotes, we need to escape: " $ ` \
return '"' + escapeDoubleQuoteContent(arg) + '"';
}
return arg;
}
/**
* @param {string} arg
*
* @returns {boolean}
*/
function hasShellMetaChars(arg) {
// Shell metacharacters that need escaping
// These characters have special meaning in shells and need to be quoted
// Whenever one of these characters is present, we should quote the argument
// Characters: space, ", &, ', |, ;, <, >, (, ), $, `, \, !, *, ?, [, ], {, }, ~, #
const shellMetaChars = /[ "&'|;<>()$`\\!*?[\]{}~#]/;
return shellMetaChars.test(arg);
}
/**
* @param {string} arg
*
* @returns {string}
*/
function escapeDoubleQuoteContent(arg) {
// Escape special characters for shell safety
// This escapes ", $, `, and \ by prefixing them with a backslash
return arg.replace(/(["`$\\])/g, "\\$1");
}
/**
* @param {string} command
* @param {string[]} args
*
* @returns {string}
*/
function buildCommand(command, args) {
if (args.length === 0) {
return command;
}
const escapedArgs = args.map(sanitizeShellArgument);
return `${command} ${escapedArgs.join(" ")}`;
}
/** /**
* @param {string} command * @param {string} command
* *
@ -98,8 +42,7 @@ export async function safeSpawn(command, args, options = {}) {
// See: https://nodejs.org/api/child_process.html#child_processspawncommand-args-options // See: https://nodejs.org/api/child_process.html#child_processspawncommand-args-options
let child; let child;
if (os.platform() === "win32") { if (os.platform() === "win32") {
const fullCommand = buildCommand(command, args); child = spawn(command, args, { ...options, shell: true });
child = spawn(fullCommand, { ...options, shell: true });
} else { } else {
const fullPath = resolveCommandPath(command); const fullPath = resolveCommandPath(command);
child = spawn(fullPath, args, options); child = spawn(fullPath, args, options);