diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 124c3da9dd65b7..a9499171f3c921 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -265,10 +265,10 @@ added: v0.5.0 piped to the parent, otherwise they will be inherited from the parent, see the `'pipe'` and `'inherit'` options for [`child_process.spawn()`][]'s [`stdio`][] for more details (Default: `false`) - * `stdio` {Array} Supports the array version of [`child_process.spawn()`][]'s - [`stdio`][] option. When this option is provided, it overrides `silent`. - The array must contain exactly one item with value `'ipc'` or an error will - be thrown. For instance `[0, 1, 2, 'ipc']`. + * `stdio` {Array|String} See [`child_process.spawn()`][]'s [`stdio`][]. + When this option is provided, it overrides `silent`. If the array variant + is used, it must contain exactly one item with value `'ipc'` or an error + will be thrown. For instance `[0, 1, 2, 'ipc']`. * `uid` {Number} Sets the user identity of the process. (See setuid(2).) * `gid` {Number} Sets the group identity of the process. (See setgid(2).) * Returns: {ChildProcess} diff --git a/lib/child_process.js b/lib/child_process.js index e9cf426b9ecfbb..b00e3829b455a9 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -17,6 +17,10 @@ const _validateStdio = child_process._validateStdio; const setupChannel = child_process.setupChannel; const ChildProcess = exports.ChildProcess = child_process.ChildProcess; +function stdioStringToArray(option) { + return [option, option, option, 'ipc']; +} + exports.fork = function(modulePath /*, args, options*/) { // Get options and args arguments. @@ -50,11 +54,21 @@ exports.fork = function(modulePath /*, args, options*/) { args = execArgv.concat([modulePath], args); - if (!Array.isArray(options.stdio)) { + if (typeof options.stdio === 'string') { + switch (options.stdio) { + case 'ignore': + case 'pipe': + case 'inherit': + options.stdio = stdioStringToArray(options.stdio); + break; + default: + throw new TypeError('Unknown stdio option'); + } + } else if (!Array.isArray(options.stdio)) { // Use a separate fd=3 for the IPC channel. Inherit stdin, stdout, // and stderr from the parent if silent isn't set. - options.stdio = options.silent ? ['pipe', 'pipe', 'pipe', 'ipc'] : - [0, 1, 2, 'ipc']; + options.stdio = options.silent ? stdioStringToArray('pipe') : + stdioStringToArray('inherit'); } else if (options.stdio.indexOf('ipc') === -1) { throw new TypeError('Forked processes must have an IPC channel'); } diff --git a/test/parallel/test-child-process-fork-stdio-string-variant.js b/test/parallel/test-child-process-fork-stdio-string-variant.js new file mode 100644 index 00000000000000..93676892b632dc --- /dev/null +++ b/test/parallel/test-child-process-fork-stdio-string-variant.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); + +// Ensures that child_process.fork can accept string +// variant of stdio parameter in options object and +// throws a TypeError when given an unexpected string + +const assert = require('assert'); +const fork = require('child_process').fork; + +const childScript = `${common.fixturesDir}/child-process-spawn-node`; +const errorRegexp = /^TypeError: Unknown stdio option$/; +const malFormedOpts = {stdio: '33'}; +const payload = {hello: 'world'}; +const stringOpts = {stdio: 'pipe'}; + +assert.throws(() => fork(childScript, malFormedOpts), errorRegexp); + +const child = fork(childScript, stringOpts); + +child.on('message', (message) => { + assert.deepStrictEqual(message, {foo: 'bar'}); +}); + +child.send(payload); + +child.on('exit', common.mustCall((code) => assert.strictEqual(code, 0)));