diff --git a/fixtures/ipc-process b/fixtures/ipc-process new file mode 100755 index 0000000000..1b50adf93d --- /dev/null +++ b/fixtures/ipc-process @@ -0,0 +1,9 @@ +#!/usr/bin/env node +'use strict'; +process.on('message', m => { + if (m === 'ping') { + process.send('pong'); + } else { + process.send('rainbow'); + } +}); diff --git a/index.js b/index.js index a69159416f..63f323aed9 100644 --- a/index.js +++ b/index.js @@ -278,6 +278,20 @@ module.exports = (cmd, args, opts) => { return spawned; }; +module.exports.fork = function (cmd, args, opts) { + opts = Object.assign({ + stdio: 'ipc' + }, opts); + + if (opts.stdio === 'ipc') { + opts.stdio = [0, 1, 2, 'ipc']; + } + + // TODO throw `new TypeError('Forked processes must have an IPC channel')` if no IPC channel is provided + // TODO throw `new Error('Child process can have only one IPC pipe')` when multiple IPC channels are provided + return module.exports(cmd, args, opts); +}; + module.exports.stdout = function () { // TODO: set `stderr: 'ignore'` when that option is implemented return module.exports.apply(null, arguments).then(x => x.stdout); diff --git a/test.js b/test.js index 42c2c42df7..db63357302 100644 --- a/test.js +++ b/test.js @@ -109,6 +109,17 @@ test('execa.shellSync()', t => { t.is(stdout, 'foo'); }); +test.cb('execa.fork()', t => { + const cp = m.fork('fixtures/ipc-process'); + + cp.on('message', m => { + t.is(m, 'pong'); + t.end(); + }); + + cp.send('ping'); +}); + test('stripEof option', async t => { const {stdout} = await m('noop', ['foo'], {stripEof: false}); t.is(stdout, 'foo\n');