foreground-child
Advanced tools
Comparing version 1.5.6 to 2.0.0
# Changes | ||
## v2.0.0 | ||
* BREAKING CHANGE: Require Node 8 | ||
* Internal: Add lock file | ||
* Support async before exit callback | ||
* Update various dependencies | ||
## v1.5.6 | ||
@@ -5,0 +11,0 @@ |
127
index.js
@@ -1,35 +0,49 @@ | ||
var signalExit = require('signal-exit') | ||
var spawn = require('child_process').spawn | ||
if (process.platform === 'win32') { | ||
spawn = require('cross-spawn') | ||
} | ||
const signalExit = require('signal-exit') | ||
/* istanbul ignore next */ | ||
const spawn = process.platform === 'win32' ? require('cross-spawn') : require('child_process').spawn | ||
module.exports = function (program, args, cb) { | ||
var arrayIndex = arguments.length | ||
if (typeof args === 'function') { | ||
cb = args | ||
args = undefined | ||
/** | ||
* Normalizes the arguments passed to `foregroundChild`. | ||
* | ||
* See the signature of `foregroundChild` for the supported arguments. | ||
* | ||
* @param fgArgs Array of arguments passed to `foregroundChild`. | ||
* @return Normalized arguments | ||
* @internal | ||
*/ | ||
function normalizeFgArgs(fgArgs) { | ||
let program, args, cb; | ||
let processArgsEnd = fgArgs.length; | ||
const lastFgArg = fgArgs[fgArgs.length - 1]; | ||
if (typeof lastFgArg === "function") { | ||
cb = lastFgArg; | ||
processArgsEnd -= 1; | ||
} else { | ||
cb = Array.prototype.slice.call(arguments).filter(function (arg, i) { | ||
if (typeof arg === 'function') { | ||
arrayIndex = i | ||
return true | ||
} | ||
})[0] | ||
cb = (done) => done(); | ||
} | ||
cb = cb || function (done) { | ||
return done() | ||
if (Array.isArray(fgArgs[0])) { | ||
[program, ...args] = fgArgs[0]; | ||
} else { | ||
program = fgArgs[0]; | ||
args = Array.isArray(fgArgs[1]) ? fgArgs[1] : fgArgs.slice(1, processArgsEnd); | ||
} | ||
if (Array.isArray(program)) { | ||
args = program.slice(1) | ||
program = program[0] | ||
} else if (!Array.isArray(args)) { | ||
args = [].slice.call(arguments, 1, arrayIndex) | ||
} | ||
return {program, args, cb}; | ||
} | ||
var spawnOpts = { stdio: [0, 1, 2] } | ||
/** | ||
* | ||
* Signatures: | ||
* ``` | ||
* (program: string | string[], cb?: CloseHandler); | ||
* (program: string, args: string[], cb?: CloseHandler); | ||
* (program: string, ...args: string[], cb?: CloseHandler); | ||
* ``` | ||
*/ | ||
function foregroundChild (...fgArgs) { | ||
const {program, args, cb} = normalizeFgArgs(fgArgs); | ||
const spawnOpts = { stdio: [0, 1, 2] } | ||
if (process.send) { | ||
@@ -39,6 +53,5 @@ spawnOpts.stdio.push('ipc') | ||
var child = spawn(program, args, spawnOpts) | ||
const child = spawn(program, args, spawnOpts) | ||
var childExited = false | ||
var unproxySignals = proxySignals(child) | ||
const unproxySignals = proxySignals(process, child) | ||
process.on('exit', childHangup) | ||
@@ -49,10 +62,15 @@ function childHangup () { | ||
child.on('close', function (code, signal) { | ||
child.on('close', (code, signal) => { | ||
// Allow the callback to inspect the child’s exit code and/or modify it. | ||
process.exitCode = signal ? 128 + signal : code | ||
cb(function () { | ||
let done = false; | ||
const doneCB = () => { | ||
if (done) { | ||
return | ||
} | ||
done = true | ||
unproxySignals() | ||
process.removeListener('exit', childHangup) | ||
childExited = true | ||
if (signal) { | ||
@@ -64,9 +82,14 @@ // If there is nothing else keeping the event loop alive, | ||
// exit with the intended signal code. | ||
/* istanbul ignore next */ | ||
setTimeout(function () {}, 200) | ||
process.kill(process.pid, signal) | ||
} else { | ||
// Equivalent to process.exit() on Node.js >= 0.11.8 | ||
process.exit(process.exitCode) | ||
} | ||
}) | ||
}; | ||
const result = cb(doneCB); | ||
if (result && result.then) { | ||
result.then(doneCB); | ||
} | ||
}) | ||
@@ -77,7 +100,7 @@ | ||
child.on('message', function (message, sendHandle) { | ||
child.on('message', (message, sendHandle) => { | ||
process.send(message, sendHandle) | ||
}) | ||
process.on('message', function (message, sendHandle) { | ||
process.on('message', (message, sendHandle) => { | ||
child.send(message, sendHandle) | ||
@@ -90,18 +113,26 @@ }) | ||
function proxySignals (child) { | ||
var listeners = {} | ||
signalExit.signals().forEach(function (sig) { | ||
listeners[sig] = function () { | ||
child.kill(sig) | ||
} | ||
process.on(sig, listeners[sig]) | ||
}) | ||
/** | ||
* Starts forwarding signals to `child` through `parent`. | ||
* | ||
* @param parent Parent process. | ||
* @param child Child Process. | ||
* @return `unproxy` function to stop the forwarding. | ||
* @internal | ||
*/ | ||
function proxySignals (parent, child) { | ||
const listeners = new Map() | ||
return unproxySignals | ||
for (const sig of signalExit.signals()) { | ||
const listener = () => child.kill(sig) | ||
listeners.set(sig, listener) | ||
parent.on(sig, listener) | ||
} | ||
function unproxySignals () { | ||
for (var sig in listeners) { | ||
process.removeListener(sig, listeners[sig]) | ||
return function unproxySignals () { | ||
for (const [sig, listener] of listeners) { | ||
parent.removeListener(sig, listener) | ||
} | ||
} | ||
} | ||
module.exports = foregroundChild |
{ | ||
"name": "foreground-child", | ||
"version": "1.5.6", | ||
"version": "2.0.0", | ||
"description": "Run a child as if it's the foreground process. Give it stdio. Exit when it exits.", | ||
"main": "index.js", | ||
"directories": { | ||
"test": "test" | ||
"engines": { | ||
"node": ">=8.0.0" | ||
}, | ||
"dependencies": { | ||
"cross-spawn": "^4", | ||
"signal-exit": "^3.0.0" | ||
"cross-spawn": "^7.0.0", | ||
"signal-exit": "^3.0.2" | ||
}, | ||
"devDependencies": { | ||
"tap": "^8.0.1" | ||
"tap": "^14.6.1" | ||
}, | ||
"scripts": { | ||
"test": "tap --coverage test/*.js", | ||
"test": "tap", | ||
"changelog": "bash changelog.sh", | ||
"postversion": "npm run changelog && git add CHANGELOG.md && git commit -m 'update changelog - '${npm_package_version}" | ||
}, | ||
"tap": { | ||
"jobs": 1 | ||
}, | ||
"repository": { | ||
@@ -31,2 +34,5 @@ "type": "git", | ||
"homepage": "https://github.com/tapjs/foreground-child#readme", | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"files": [ | ||
@@ -33,0 +39,0 @@ "index.js" |
@@ -35,2 +35,12 @@ # foreground-child | ||
The callback can return a Promise instead of calling `done`: | ||
```js | ||
var child = foreground('cat', [__filename], async function () { | ||
// perform an action. | ||
}) | ||
``` | ||
The callback must not throw or reject. | ||
## Caveats | ||
@@ -37,0 +47,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
9402
113
63
2
+ Addedcross-spawn@7.0.3(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedwhich@2.0.2(transitive)
- Removedcross-spawn@4.0.2(transitive)
- Removedlru-cache@4.1.5(transitive)
- Removedpseudomap@1.0.2(transitive)
- Removedwhich@1.3.1(transitive)
- Removedyallist@2.1.2(transitive)
Updatedcross-spawn@^7.0.0
Updatedsignal-exit@^3.0.2