Skip to content

Commit e1d1e9b

Browse files
notgitikagitikavj
andauthored
fix: avoid DEP0190 warning when spawning subprocesses with shell mode (#360)
Co-authored-by: gitikavj <gitikavj@amazon.com>
1 parent fd5c9a9 commit e1d1e9b

1 file changed

Lines changed: 33 additions & 10 deletions

File tree

src/lib/utils/subprocess.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,28 @@ export interface SubprocessOptions {
2020
shell?: boolean;
2121
}
2222

23+
/**
24+
* When shell mode is enabled, merge args into the command string so that
25+
* Node.js does not receive both a non-empty args array and `shell: true`.
26+
* Passing both triggers DEP0190 on Node ≥ 22 (and a warning on earlier
27+
* versions) because the arguments are concatenated without escaping.
28+
*/
29+
function resolveCommand(command: string, args: string[], useShell: boolean): { cmd: string; cmdArgs: string[] } {
30+
if (useShell) {
31+
return { cmd: [command, ...args].join(' '), cmdArgs: [] };
32+
}
33+
return { cmd: command, cmdArgs: args };
34+
}
35+
2336
export async function runSubprocess(command: string, args: string[], options: SubprocessOptions = {}): Promise<void> {
37+
const shell = options.shell ?? isWindows;
38+
const { cmd, cmdArgs } = resolveCommand(command, args, shell);
2439
return new Promise((resolve, reject) => {
25-
const child = spawn(command, args, {
40+
const child = spawn(cmd, cmdArgs, {
2641
cwd: options.cwd,
2742
env: options.env,
2843
stdio: options.stdio ?? 'inherit',
29-
shell: options.shell ?? isWindows,
44+
shell,
3045
});
3146

3247
child.on('error', reject);
@@ -46,12 +61,14 @@ export async function checkSubprocess(
4661
args: string[],
4762
options: SubprocessOptions = {}
4863
): Promise<boolean> {
64+
const shell = options.shell ?? isWindows;
65+
const { cmd, cmdArgs } = resolveCommand(command, args, shell);
4966
return new Promise(resolve => {
50-
const child = spawn(command, args, {
67+
const child = spawn(cmd, cmdArgs, {
5168
cwd: options.cwd,
5269
env: options.env,
5370
stdio: options.stdio ?? 'ignore',
54-
shell: options.shell ?? isWindows,
71+
shell,
5572
});
5673

5774
child.on('error', () => resolve(false));
@@ -71,12 +88,14 @@ export async function runSubprocessCapture(
7188
args: string[],
7289
options: SubprocessOptions = {}
7390
): Promise<SubprocessResult> {
91+
const shell = options.shell ?? isWindows;
92+
const { cmd, cmdArgs } = resolveCommand(command, args, shell);
7493
return new Promise(resolve => {
75-
const child = spawn(command, args, {
94+
const child = spawn(cmd, cmdArgs, {
7695
cwd: options.cwd,
7796
env: options.env,
7897
stdio: 'pipe',
79-
shell: options.shell ?? isWindows,
98+
shell,
8099
});
81100

82101
let stdout = '';
@@ -105,11 +124,13 @@ export function runSubprocessCaptureSync(
105124
args: string[],
106125
options: SubprocessOptions = {}
107126
): SubprocessResult {
108-
const result = spawnSync(command, args, {
127+
const shell = options.shell ?? isWindows;
128+
const { cmd, cmdArgs } = resolveCommand(command, args, shell);
129+
const result = spawnSync(cmd, cmdArgs, {
109130
cwd: options.cwd,
110131
env: options.env,
111132
stdio: 'pipe',
112-
shell: options.shell ?? isWindows,
133+
shell,
113134
encoding: 'utf-8',
114135
});
115136

@@ -122,12 +143,14 @@ export function runSubprocessCaptureSync(
122143
}
123144

124145
export function checkSubprocessSync(command: string, args: string[], options: SubprocessOptions = {}): boolean {
146+
const shell = options.shell ?? isWindows;
147+
const { cmd, cmdArgs } = resolveCommand(command, args, shell);
125148
try {
126-
const result = spawnSync(command, args, {
149+
const result = spawnSync(cmd, cmdArgs, {
127150
cwd: options.cwd,
128151
env: options.env,
129152
stdio: options.stdio ?? 'ignore',
130-
shell: options.shell ?? isWindows,
153+
shell,
131154
});
132155
return result.status === 0;
133156
} catch {

0 commit comments

Comments
 (0)