123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- 'use strict';
-
- /* Drop this dependency once node.js 12 is required. */
- const fromEntries = require('fromentries');
-
- const state = getState(1);
-
- function getState(version) {
- const stateId = Symbol.for('process-on-spawn@*:singletonId');
-
- /* istanbul ignore next: cannot cover this once nyc depends on this module */
- if (stateId in global === false) {
- /* Hopefully version and unwrap forward compatibility is never actually needed */
- Object.defineProperty(global, stateId, {
- writable: true,
- value: {
- version,
- listeners: [],
- unwrap: wrapSpawnFunctions()
- }
- });
- }
-
- return global[stateId];
- }
-
- function wrappedSpawnFunction(fn) {
- return function (options) {
- let env = fromEntries(
- options.envPairs.map(nvp => nvp.split(/^([^=]*)=/).slice(1))
- );
-
- const opts = Object.create(null, {
- env: {
- enumerable: true,
- get() {
- return env;
- },
- set(value) {
- if (!value || typeof value !== 'object') {
- throw new TypeError('env must be an object');
- }
-
- env = value;
- }
- },
- cwd: {
- enumerable: true,
- get() {
- return options.cwd || process.cwd();
- }
- }
- });
-
- const args = [...options.args];
- Object.freeze(args);
- Object.assign(opts, {
- execPath: options.file,
- args,
- detached: Boolean(options.detached),
- uid: options.uid,
- gid: options.gid,
- windowsVerbatimArguments: Boolean(options.windowsVerbatimArguments),
- windowsHide: Boolean(options.windowsHide)
- });
- Object.freeze(opts);
-
- state.listeners.forEach(listener => {
- listener(opts);
- });
-
- options.envPairs = Object.entries(opts.env).map(([name, value]) => `${name}=${value}`);
-
- return fn.call(this, options);
- };
- }
-
- function wrapSpawnFunctions() {
- const {ChildProcess} = require('child_process');
-
- /* eslint-disable-next-line node/no-deprecated-api */
- const spawnSyncBinding = process.binding('spawn_sync');
- const originalSync = spawnSyncBinding.spawn;
- const originalAsync = ChildProcess.prototype.spawn;
-
- spawnSyncBinding.spawn = wrappedSpawnFunction(spawnSyncBinding.spawn);
- ChildProcess.prototype.spawn = wrappedSpawnFunction(ChildProcess.prototype.spawn);
-
- /* istanbul ignore next: forward compatibility code */
- return () => {
- spawnSyncBinding.spawn = originalSync;
- ChildProcess.prototype.spawn = originalAsync;
- };
- }
-
- module.exports = {
- addListener(listener) {
- state.listeners.push(listener);
- },
- prependListener(listener) {
- state.listeners.unshift(listener);
- },
- removeListener(listener) {
- const idx = state.listeners.indexOf(listener);
- if (idx !== -1) {
- state.listeners.splice(idx, 1);
- }
- },
- removeAllListeners() {
- state.listeners = [];
- }
- };
|