'use strict' const refs = { exit: [], beforeExit: [] } const functions = { exit: onExit, beforeExit: onBeforeExit } const registry = new FinalizationRegistry(clear) function install (event) { if (refs[event].length > 0) { return } process.on(event, functions[event]) } function uninstall (event) { if (refs[event].length > 0) { return } process.removeListener(event, functions[event]) } function onExit () { callRefs('exit') } function onBeforeExit () { callRefs('beforeExit') } function callRefs (event) { for (const ref of refs[event]) { const obj = ref.deref() const fn = ref.fn // This should always happen, however GC is // undeterministic so it might not happen. /* istanbul ignore else */ if (obj !== undefined) { fn(obj, event) } } } function clear (ref) { for (const event of ['exit', 'beforeExit']) { const index = refs[event].indexOf(ref) refs[event].splice(index, index + 1) uninstall(event) } } function _register (event, obj, fn) { if (obj === undefined) { throw new Error('the object can\'t be undefined') } install(event) const ref = new WeakRef(obj) ref.fn = fn registry.register(obj, ref) refs[event].push(ref) } function register (obj, fn) { _register('exit', obj, fn) } function registerBeforeExit (obj, fn) { _register('beforeExit', obj, fn) } function unregister (obj) { registry.unregister(obj) for (const event of ['exit', 'beforeExit']) { refs[event] = refs[event].filter((ref) => { const _obj = ref.deref() return _obj && _obj !== obj }) uninstall(event) } } module.exports = { register, registerBeforeExit, unregister }