diff --git a/doc/api/cli.md b/doc/api/cli.md index d53052dbdc8e4f..f6589f6264ff63 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -10,7 +10,7 @@ To view this documentation as a manual page in a 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" | :] …` @@ -345,6 +345,17 @@ added: v0.11.15 Specify ICU data load path. (overrides `NODE_ICU_DATA`) + +### `-` + + +Alias for stdin, analogous to the use of - in other command line utilities, +meaning that the script will be read from stdin, and the rest of the options +are passed to that script. + + ### `--` -`node [options] [v8 options] [script.js | -e "script"] [arguments]` +`node [options] [v8 options] [script.js | -e "script" | - ] [arguments]` Please see the [Command Line Options][] document for information about different options and ways to run scripts with Node.js. diff --git a/doc/node.1 b/doc/node.1 index 46771b2faa3992..c7844b67b6b2d2 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -36,7 +36,10 @@ node \- Server-side JavaScript runtime .RI [ v8\ options ] .RI [ script.js \ | .B -e -.RI \&" script \&"] +.RI \&" script \&" +.R | +.B - +.R ] .B [--] .RI [ arguments ] .br @@ -225,6 +228,12 @@ See \fBSSL_CERT_DIR\fR and \fBSSL_CERT_FILE\fR. .BR \-\-icu\-data\-dir =\fIfile\fR Specify ICU data load path. (overrides \fBNODE_ICU_DATA\fR) +.TP +.BR \-\fR +Alias for stdin, analogous to the use of - in other command line utilities, +meaning that the script will be read from stdin, and the rest of the options +are passed to that script. + .TP .BR \-\-\fR Indicate the end of node options. Pass the rest of the arguments to the script. diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index 86875566b0896a..ed1edf7138bc7e 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -123,7 +123,7 @@ const internalModule = NativeModule.require('internal/module'); internalModule.addBuiltinLibsToObject(global); evalScript('[eval]'); - } else if (process.argv[1]) { + } else if (process.argv[1] && process.argv[1] !== '-') { // make process.argv[1] into a full path const path = NativeModule.require('path'); process.argv[1] = path.resolve(process.argv[1]); diff --git a/src/node.cc b/src/node.cc index a5c86d4c3634bf..efa090cf1f85ad 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3592,7 +3592,7 @@ void LoadEnvironment(Environment* env) { static void PrintHelp() { // XXX: If you add an option here, please also add it to doc/node.1 and // doc/api/cli.md - printf("Usage: node [options] [ -e script | script.js ] [arguments]\n" + printf("Usage: node [options] [ -e script | script.js | - ] [arguments]\n" " node inspect script.js [arguments]\n" "\n" "Options:\n" @@ -3604,6 +3604,8 @@ static void PrintHelp() { " does not appear to be a terminal\n" " -r, --require module to preload (option can be " "repeated)\n" + " - script read from stdin (default; " + "interactive mode if a tty)" #if HAVE_INSPECTOR " --inspect[=[host:]port] activate inspector on host:port\n" " (default: 127.0.0.1:9229)\n" @@ -3913,6 +3915,8 @@ static void ParseArgs(int* argc, } else if (strcmp(arg, "--expose-internals") == 0 || strcmp(arg, "--expose_internals") == 0) { config_expose_internals = true; + } else if (strcmp(arg, "-") == 0) { + break; } else if (strcmp(arg, "--") == 0) { index += 1; break; diff --git a/test/parallel/test-stdin-script-child-option.js b/test/parallel/test-stdin-script-child-option.js new file mode 100644 index 00000000000000..5526d66f3f2807 --- /dev/null +++ b/test/parallel/test-stdin-script-child-option.js @@ -0,0 +1,17 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +const expected = '--option-to-be-seen-on-child'; + +const { spawn } = require('child_process'); +const child = spawn(process.execPath, ['-', expected], { stdio: 'pipe' }); + +child.stdin.end('console.log(process.argv[2])'); + +let actual = ''; +child.stdout.setEncoding('utf8'); +child.stdout.on('data', (chunk) => actual += chunk); +child.stdout.on('end', common.mustCall(() => { + assert.strictEqual(actual.trim(), expected); +})); diff --git a/test/parallel/test-stdin-script-child.js b/test/parallel/test-stdin-script-child.js index 81eb3ea5b4aaac..d3d22a9a82fdff 100644 --- a/test/parallel/test-stdin-script-child.js +++ b/test/parallel/test-stdin-script-child.js @@ -2,31 +2,32 @@ const common = require('../common'); const assert = require('assert'); -const spawn = require('child_process').spawn; -const child = spawn(process.execPath, [], { - env: Object.assign(process.env, { - NODE_DEBUG: process.argv[2] - }) -}); -const wanted = `${child.pid}\n`; -let found = ''; +const { spawn } = require('child_process'); +for (const args of [[], ['-']]) { + const child = spawn(process.execPath, args, { + env: Object.assign(process.env, { + NODE_DEBUG: process.argv[2] + }) + }); + const wanted = `${child.pid}\n`; + let found = ''; -child.stdout.setEncoding('utf8'); -child.stdout.on('data', function(c) { - found += c; -}); + child.stdout.setEncoding('utf8'); + child.stdout.on('data', function(c) { + found += c; + }); -child.stderr.setEncoding('utf8'); -child.stderr.on('data', function(c) { - console.error(`> ${c.trim().split(/\n/).join('\n> ')}`); -}); + child.stderr.setEncoding('utf8'); + child.stderr.on('data', function(c) { + console.error(`> ${c.trim().split(/\n/).join('\n> ')}`); + }); -child.on('close', common.mustCall(function(c) { - assert.strictEqual(c, 0); - assert.strictEqual(found, wanted); - console.log('ok'); -})); + child.on('close', common.mustCall(function(c) { + assert.strictEqual(c, 0); + assert.strictEqual(found, wanted); + })); -setTimeout(function() { - child.stdin.end('console.log(process.pid)'); -}, 1); + setTimeout(function() { + child.stdin.end('console.log(process.pid)'); + }, 1); +}