diff --git a/doc/api/cli.md b/doc/api/cli.md index 53cfe5a96b..94e4f250c9 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -10,7 +10,7 @@ To view this documentation as a manual page in your terminal, run `man node`. ## Synopsis -`node [options] [v8 options] [script.js | -e "script"] [arguments]` +`node [options] [v8 options] [script.js | -e "script"] [--] [arguments]` `node debug [script.js | -e "script" | :] …` @@ -251,6 +251,15 @@ added: v0.11.15 Specify ICU data load path. (overrides `NODE_ICU_DATA`) +### `--` + + +Indicate the end of node options. Pass the rest of the arguments to the script. +If no script filename or eval/print script is supplied prior to this, then +the next argument will be used as a script filename. + ## Environment Variables ### `NODE_DEBUG=module[,…]` diff --git a/doc/node.1 b/doc/node.1 index ec41a44c75..7b39ef05ce 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -37,6 +37,7 @@ node \- Server-side JavaScript runtime .RI [ script.js \ | .B -e .RI \&" script \&"] +.B [--] .RI [ arguments ] .br .B node debug @@ -175,6 +176,13 @@ used to enable FIPS-compliant crypto if Node.js is built with .BR \-\-icu\-data\-dir =\fIfile\fR Specify ICU data load path. (overrides \fBNODE_ICU_DATA\fR) +.TP +.BR \-\-\fR +Indicate the end of node options. Pass the rest of the arguments to the script. + +If no script filename or eval/print script is supplied prior to this, then +the next argument will be used as a script filename. + .SH ENVIRONMENT VARIABLES .TP diff --git a/src/node.cc b/src/node.cc index 28eeb61cbe..f353438058 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3860,6 +3860,9 @@ static void ParseArgs(int* argc, } else if (strcmp(arg, "--expose-internals") == 0 || strcmp(arg, "--expose_internals") == 0) { // consumed in js + } else if (strcmp(arg, "--") == 0) { + index += 1; + break; } else { // V8 option. Pass through as-is. new_v8_argv[new_v8_argc] = arg; diff --git a/test/parallel/test-cli-eval.js b/test/parallel/test-cli-eval.js index b19dfd3283..93de319a56 100644 --- a/test/parallel/test-cli-eval.js +++ b/test/parallel/test-cli-eval.js @@ -12,6 +12,11 @@ const child = require('child_process'); const path = require('path'); const nodejs = `"${process.execPath}"`; +if (process.argv.length > 2) { + console.log(process.argv.slice(2).join(' ')); + process.exit(0); +} + // Assert that nothing is written to stdout. child.exec(`${nodejs} --eval 42`, common.mustCall((err, stdout, stderr) => { assert.ifError(err); @@ -163,3 +168,38 @@ child.exec(`${nodejs} --use-strict -p process.execArgv`, }); proc.send('ping'); } + +[ '-arg1', + '-arg1 arg2 --arg3', + '--', + 'arg1 -- arg2', +].forEach(function(args) { + + // Ensure that arguments are successfully passed to eval. + const opt = ' --eval "console.log(process.argv.slice(1).join(\' \'))"'; + const cmd = `${nodejs}${opt} -- ${args}`; + child.exec(cmd, common.mustCall(function(err, stdout, stderr) { + assert.strictEqual(stdout, args + '\n'); + assert.strictEqual(stderr, ''); + assert.strictEqual(err, null); + })); + + // Ensure that arguments are successfully passed to print. + const popt = ' --print "process.argv.slice(1).join(\' \')"'; + const pcmd = `${nodejs}${popt} -- ${args}`; + child.exec(pcmd, common.mustCall(function(err, stdout, stderr) { + assert.strictEqual(stdout, args + '\n'); + assert.strictEqual(stderr, ''); + assert.strictEqual(err, null); + })); + + // Ensure that arguments are successfully passed to a script. + // The first argument after '--' should be interpreted as a script + // filename. + const filecmd = `${nodejs} -- ${__filename} ${args}`; + child.exec(filecmd, common.mustCall(function(err, stdout, stderr) { + assert.strictEqual(stdout, args + '\n'); + assert.strictEqual(stderr, ''); + assert.strictEqual(err, null); + })); +});