From 3840927221e76f9af8ef4f422b7d963bc5599020 Mon Sep 17 00:00:00 2001 From: gitikavj Date: Fri, 20 Feb 2026 02:01:08 -0500 Subject: [PATCH] fix: avoid DEP0190 warning when spawning subprocesses with shell mode --- src/lib/utils/subprocess.ts | 43 ++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/lib/utils/subprocess.ts b/src/lib/utils/subprocess.ts index 0a8390f3..a95f8de0 100644 --- a/src/lib/utils/subprocess.ts +++ b/src/lib/utils/subprocess.ts @@ -20,13 +20,28 @@ export interface SubprocessOptions { shell?: boolean; } +/** + * When shell mode is enabled, merge args into the command string so that + * Node.js does not receive both a non-empty args array and `shell: true`. + * Passing both triggers DEP0190 on Node ≥ 22 (and a warning on earlier + * versions) because the arguments are concatenated without escaping. + */ +function resolveCommand(command: string, args: string[], useShell: boolean): { cmd: string; cmdArgs: string[] } { + if (useShell) { + return { cmd: [command, ...args].join(' '), cmdArgs: [] }; + } + return { cmd: command, cmdArgs: args }; +} + export async function runSubprocess(command: string, args: string[], options: SubprocessOptions = {}): Promise { + const shell = options.shell ?? isWindows; + const { cmd, cmdArgs } = resolveCommand(command, args, shell); return new Promise((resolve, reject) => { - const child = spawn(command, args, { + const child = spawn(cmd, cmdArgs, { cwd: options.cwd, env: options.env, stdio: options.stdio ?? 'inherit', - shell: options.shell ?? isWindows, + shell, }); child.on('error', reject); @@ -46,12 +61,14 @@ export async function checkSubprocess( args: string[], options: SubprocessOptions = {} ): Promise { + const shell = options.shell ?? isWindows; + const { cmd, cmdArgs } = resolveCommand(command, args, shell); return new Promise(resolve => { - const child = spawn(command, args, { + const child = spawn(cmd, cmdArgs, { cwd: options.cwd, env: options.env, stdio: options.stdio ?? 'ignore', - shell: options.shell ?? isWindows, + shell, }); child.on('error', () => resolve(false)); @@ -71,12 +88,14 @@ export async function runSubprocessCapture( args: string[], options: SubprocessOptions = {} ): Promise { + const shell = options.shell ?? isWindows; + const { cmd, cmdArgs } = resolveCommand(command, args, shell); return new Promise(resolve => { - const child = spawn(command, args, { + const child = spawn(cmd, cmdArgs, { cwd: options.cwd, env: options.env, stdio: 'pipe', - shell: options.shell ?? isWindows, + shell, }); let stdout = ''; @@ -105,11 +124,13 @@ export function runSubprocessCaptureSync( args: string[], options: SubprocessOptions = {} ): SubprocessResult { - const result = spawnSync(command, args, { + const shell = options.shell ?? isWindows; + const { cmd, cmdArgs } = resolveCommand(command, args, shell); + const result = spawnSync(cmd, cmdArgs, { cwd: options.cwd, env: options.env, stdio: 'pipe', - shell: options.shell ?? isWindows, + shell, encoding: 'utf-8', }); @@ -122,12 +143,14 @@ export function runSubprocessCaptureSync( } export function checkSubprocessSync(command: string, args: string[], options: SubprocessOptions = {}): boolean { + const shell = options.shell ?? isWindows; + const { cmd, cmdArgs } = resolveCommand(command, args, shell); try { - const result = spawnSync(command, args, { + const result = spawnSync(cmd, cmdArgs, { cwd: options.cwd, env: options.env, stdio: options.stdio ?? 'ignore', - shell: options.shell ?? isWindows, + shell, }); return result.status === 0; } catch {