text: const signalExit = require('signal-exit')
  /* istanbul ignore next */
  const spawn = process.platform === 'win32' ? require('cross-spawn') : require('child_process').spawn
  
  /**
   * 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 = (done) => 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);
    }
  
    return {program, args, cb};
  }
  
  /**
   *
   * 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) {
      spawnOpts.stdio.push('ipc')
    }
  
    const child = spawn(program, args, spawnOpts)
  
    const unproxySignals = proxySignals(process, child)
    process.on('exit', childHangup)
    function childHangup () {
      child.kill('SIGHUP')
    }
  
    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
  
      let done = false;
      const doneCB = () => {
        if (done) {
          return
        }
  
        done = true
        unproxySignals()
        process.removeListener('exit', childHangup)
        if (signal) {
          // If there is nothing else keeping the event loop alive,
          // then there's a race between a graceful exit and getting
          // the signal to this process.  Put this timeout here to
          // make sure we're still alive to get the signal, and thus
          // exit with the intended signal code.
          /* istanbul ignore next */
          setTimeout(function () {}, 200)
          process.kill(process.pid, signal)
        } else {
          process.exit(process.exitCode)
        }
      };
  
      const result = cb(doneCB);
      if (result && result.then) {
        result.then(doneCB);
      }
    })
  
    if (process.send) {
      process.removeAllListeners('message')
  
      child.on('message', (message, sendHandle) => {
        process.send(message, sendHandle)
      })
  
      process.on('message', (message, sendHandle) => {
        child.send(message, sendHandle)
      })
    }
  
    return child
  }
  
  /**
   * 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()
  
    for (const sig of signalExit.signals()) {
      const listener = () => child.kill(sig)
      listeners.set(sig, listener)
      parent.on(sig, listener)
    }
  
    return function unproxySignals () {
      for (const [sig, listener] of listeners) {
        parent.removeListener(sig, listener)
      }
    }
  }
  
  module.exports = foregroundChild
  