You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							153 lines
						
					
					
						
							4.1 KiB
						
					
					
				
			
		
		
	
	
							153 lines
						
					
					
						
							4.1 KiB
						
					
					
				var RSVP = require('rsvp'); | 
						|
 | 
						|
var exit; | 
						|
var handlers = []; | 
						|
var lastTime; | 
						|
var isExiting = false; | 
						|
 | 
						|
process.on('beforeExit', function (code) { | 
						|
  if (handlers.length === 0) { return; } | 
						|
 | 
						|
  var own = lastTime = module.exports._flush(lastTime, code) | 
						|
    .finally(function () { | 
						|
      // if an onExit handler has called process.exit, do not disturb | 
						|
      // `lastTime`. | 
						|
      // | 
						|
      // Otherwise, clear `lastTime` so that we know to synchronously call the | 
						|
      // real `process.exit` with the given exit code, when our captured | 
						|
      // `process.exit` is called during a `process.on('exit')` handler | 
						|
      // | 
						|
      // This is impossible to reason about, don't feel bad.  Just look at | 
						|
      // test-natural-exit-subprocess-error.js | 
						|
      if (own === lastTime) { | 
						|
        lastTime = undefined; | 
						|
      } | 
						|
    }); | 
						|
}); | 
						|
 | 
						|
// This exists only for testing | 
						|
module.exports._reset = function () { | 
						|
  module.exports.releaseExit(); | 
						|
  handlers = []; | 
						|
  lastTime = undefined; | 
						|
  isExiting = false; | 
						|
  firstExitCode = undefined; | 
						|
} | 
						|
 | 
						|
/* | 
						|
 * To allow cooperative async exit handlers, we unfortunately must hijack | 
						|
 * process.exit. | 
						|
 * | 
						|
 * It allows a handler to ensure exit, without that exit handler impeding other | 
						|
 * similar handlers | 
						|
 * | 
						|
 * for example, see: https://github.com/sindresorhus/ora/issues/27 | 
						|
 * | 
						|
 */ | 
						|
module.exports.releaseExit = function() { | 
						|
  if (exit) { | 
						|
    process.exit = exit; | 
						|
    exit = null; | 
						|
  } | 
						|
}; | 
						|
 | 
						|
var firstExitCode; | 
						|
 | 
						|
module.exports.captureExit = function() { | 
						|
  if (exit) { | 
						|
    // already captured, no need to do more work | 
						|
    return; | 
						|
  } | 
						|
  exit = process.exit; | 
						|
 | 
						|
  process.exit = function(code) { | 
						|
    if (handlers.length === 0 && lastTime === undefined) { | 
						|
      // synchronously exit. | 
						|
      // | 
						|
      // We do this brecause either | 
						|
      // | 
						|
      //  1.  The process exited due to a call to `process.exit` but we have no | 
						|
      //      async work to do because no handlers had been attached.  It | 
						|
      //      doesn't really matter whether we take this branch or not in this | 
						|
      //      case. | 
						|
      // | 
						|
      //  2.  The process exited naturally.  We did our async work during | 
						|
      //      `beforeExit` and are in this function because someone else has | 
						|
      //      called `process.exit` during an `on('exit')` hook.  The only way | 
						|
      //      for us to preserve the exit code in this case is to exit | 
						|
      //      synchronously. | 
						|
      // | 
						|
      return exit.call(process, code); | 
						|
    } | 
						|
 | 
						|
    if (firstExitCode === undefined) { | 
						|
      firstExitCode = code; | 
						|
    } | 
						|
    var own = lastTime = module.exports._flush(lastTime, firstExitCode) | 
						|
      .then(function() { | 
						|
        // if another chain has started, let it exit | 
						|
        if (own !== lastTime) { return; } | 
						|
        exit.call(process, firstExitCode); | 
						|
      }) | 
						|
      .catch(function(error) { | 
						|
        // if another chain has started, let it exit | 
						|
        if (own !== lastTime) { | 
						|
          throw error; | 
						|
        } | 
						|
        console.error(error); | 
						|
        exit.call(process, 1); | 
						|
      }); | 
						|
  }; | 
						|
}; | 
						|
 | 
						|
module.exports._handlers = handlers; | 
						|
module.exports._flush = function(lastTime, code) { | 
						|
  isExiting = true; | 
						|
  var work = handlers.splice(0, handlers.length); | 
						|
 | 
						|
  return RSVP.Promise.resolve(lastTime). | 
						|
    then(function() { | 
						|
      var firstRejected; | 
						|
      return RSVP.allSettled(work.map(function(handler) { | 
						|
        return RSVP.resolve(handler.call(null, code)).catch(function(e) { | 
						|
          if (!firstRejected) { | 
						|
            firstRejected = e; | 
						|
          } | 
						|
          throw e; | 
						|
        }); | 
						|
      })).then(function(results) { | 
						|
        if (firstRejected) { | 
						|
          throw firstRejected; | 
						|
        } | 
						|
      }); | 
						|
    }); | 
						|
}; | 
						|
 | 
						|
module.exports.onExit = function(cb) { | 
						|
  if (!exit) { | 
						|
    throw new Error('Cannot install handler when exit is not captured.  Call `captureExit()` first'); | 
						|
  } | 
						|
  if (isExiting) { | 
						|
    throw new Error('Cannot install handler while `onExit` handlers are running.'); | 
						|
  } | 
						|
  var index = handlers.indexOf(cb); | 
						|
 | 
						|
  if (index > -1) { return; } | 
						|
  handlers.push(cb); | 
						|
}; | 
						|
 | 
						|
module.exports.offExit = function(cb) { | 
						|
  var index = handlers.indexOf(cb); | 
						|
 | 
						|
  if (index < 0) { return; } | 
						|
 | 
						|
  handlers.splice(index, 1); | 
						|
}; | 
						|
 | 
						|
module.exports.exit  = function() { | 
						|
  exit.apply(process, arguments); | 
						|
}; | 
						|
 | 
						|
module.exports.listenerCount = function() { | 
						|
  return handlers.length; | 
						|
};
 | 
						|
 |