Skip to content

Commit 9d64e13

Browse files
committed
fix(util): correctly handle --eval in parseArgs
1 parent 05f8772 commit 9d64e13

File tree

2 files changed

+74
-15
lines changed

2 files changed

+74
-15
lines changed

lib/internal/util/parse_args/parse_args.js

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ function getMainArgs() {
6363
return ArrayPrototypeSlice(process.argv, 1);
6464
}
6565

66+
// Fallback: check process.execArgv for --eval=... or --print=...
67+
// getOptionValue might miss these if they are one token in execArgv.
68+
for (let i = 0; i < process.execArgv.length; i++) {
69+
const arg = process.execArgv[i];
70+
if (StringPrototypeStartsWith(arg, '--eval=') ||
71+
StringPrototypeStartsWith(arg, '--print=')) {
72+
return ArrayPrototypeSlice(process.argv, 1);
73+
}
74+
}
75+
6676
return ArrayPrototypeSlice(process.argv, 2);
6777
}
6878

@@ -217,15 +227,17 @@ function argsToTokens(args, options) {
217227
let value;
218228
let inlineValue;
219229
if (optionsGetOwn(options, longOption, 'type') === 'string' &&
220-
isOptionValue(nextArg)) {
230+
isOptionValue(nextArg)) {
221231
// e.g. '-f', 'bar'
222232
value = ArrayPrototypeShift(remainingArgs);
223233
inlineValue = false;
224234
}
225235
ArrayPrototypePush(
226236
tokens,
227-
{ kind: 'option', name: longOption, rawName: arg,
228-
index, value, inlineValue });
237+
{
238+
kind: 'option', name: longOption, rawName: arg,
239+
index, value, inlineValue
240+
});
229241
if (value != null) ++index;
230242
continue;
231243
}
@@ -259,8 +271,10 @@ function argsToTokens(args, options) {
259271
const value = StringPrototypeSlice(arg, 2);
260272
ArrayPrototypePush(
261273
tokens,
262-
{ kind: 'option', name: longOption, rawName: `-${shortOption}`,
263-
index, value, inlineValue: true });
274+
{
275+
kind: 'option', name: longOption, rawName: `-${shortOption}`,
276+
index, value, inlineValue: true
277+
});
264278
continue;
265279
}
266280

@@ -270,15 +284,17 @@ function argsToTokens(args, options) {
270284
let value;
271285
let inlineValue;
272286
if (optionsGetOwn(options, longOption, 'type') === 'string' &&
273-
isOptionValue(nextArg)) {
287+
isOptionValue(nextArg)) {
274288
// e.g. '--foo', 'bar'
275289
value = ArrayPrototypeShift(remainingArgs);
276290
inlineValue = false;
277291
}
278292
ArrayPrototypePush(
279293
tokens,
280-
{ kind: 'option', name: longOption, rawName: arg,
281-
index, value, inlineValue });
294+
{
295+
kind: 'option', name: longOption, rawName: arg,
296+
index, value, inlineValue
297+
});
282298
if (value != null) ++index;
283299
continue;
284300
}
@@ -290,8 +306,10 @@ function argsToTokens(args, options) {
290306
const value = StringPrototypeSlice(arg, equalIndex + 1);
291307
ArrayPrototypePush(
292308
tokens,
293-
{ kind: 'option', name: longOption, rawName: `--${longOption}`,
294-
index, value, inlineValue: true });
309+
{
310+
kind: 'option', name: longOption, rawName: `--${longOption}`,
311+
index, value, inlineValue: true
312+
});
295313
continue;
296314
}
297315

@@ -388,14 +406,14 @@ const parseArgs = (config = kEmptyObject) => {
388406

389407
// Phase 3: fill in default values for missing args
390408
ArrayPrototypeForEach(ObjectEntries(options), ({ 0: longOption,
391-
1: optionConfig }) => {
409+
1: optionConfig }) => {
392410
const mustSetDefault = useDefaultValueOption(longOption,
393-
optionConfig,
394-
result.values);
411+
optionConfig,
412+
result.values);
395413
if (mustSetDefault) {
396414
storeDefaultOption(longOption,
397-
objectGetOwn(optionConfig, 'default'),
398-
result.values);
415+
objectGetOwn(optionConfig, 'default'),
416+
result.values);
399417
}
400418
});
401419

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
'use strict';
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const child = require('child_process');
6+
7+
// Regression test for https://github.com/nodejs/node/issues/60808
8+
// verify that util.parseArgs works correctly with --eval=...
9+
10+
if (process.argv[2] === 'child') {
11+
const { parseArgs } = require('util');
12+
const { positionals } = parseArgs({ allowPositionals: true });
13+
console.log(JSON.stringify(positionals));
14+
return;
15+
}
16+
17+
{
18+
const code = 'console.log(JSON.stringify(require("util").parseArgs({allowPositionals:true}).positionals))';
19+
20+
// Test with --eval=... syntax
21+
child.execFile(process.execPath, [
22+
`--eval=${code}`,
23+
'--',
24+
'arg1',
25+
'arg2'
26+
], common.mustSucceed((stdout) => {
27+
assert.strictEqual(stdout.trim(), '["arg1","arg2"]');
28+
}));
29+
30+
31+
// Test with --print=... syntax
32+
const codePrint = 'JSON.stringify(require("util").parseArgs({allowPositionals:true}).positionals)';
33+
child.execFile(process.execPath, [
34+
`--print=${codePrint}`,
35+
'--',
36+
'arg1',
37+
'arg2'
38+
], common.mustSucceed((stdout) => {
39+
assert.strictEqual(stdout.trim(), '["arg1","arg2"]');
40+
}));
41+
}

0 commit comments

Comments
 (0)