UNPKG

pause-fn

Version:

Pause/resume execution of a function

118 lines (86 loc) 2.83 kB
'use strict'; const {inspect} = require('util'); const inspectWithKind = require('inspect-with-kind'); const ARG_ERROR = 'Expected 1 argument (<Function>)'; const PAUSE_ERROR = 'Expected a <Function> returned by `pauseFn()`'; const argsAndOriginalFns = new WeakMap(); const resumed = new WeakSet(); function validateArgumentLength(args) { const argLen = args.length; if (argLen === 0) { const error = new RangeError(`${ARG_ERROR}, but got no arguments.`); error.code = 'ERR_MISSING_ARGS'; Error.captureStackTrace(error, pauseFn); throw error; } if (argLen !== 1) { const error = new RangeError(`${ARG_ERROR}, but got ${argLen} arguments.`); error.code = 'ERR_TOO_MANY_ARGS'; Error.captureStackTrace(error, pauseFn); throw error; } } function apply(args) { return this(...args); } function pauseFn(...args) { validateArgumentLength(args); const [fn] = args; if (typeof fn !== 'function') { const error = new TypeError(`Expected a <Function>, but got a non-function value ${inspectWithKind(fn)}.`); error.code = 'ERR_INVALID_ARG_TYPE'; throw error; } if (argsAndOriginalFns.has(fn)) { const error = new Error(`Expected a <Function> which hasn't been paused by \`pauseFn()\`, but got an already paused one ${inspect(fn, {breakLength: Infinity})}.`); error.code = 'ERR_INVALID_ARG_VALUE'; throw error; } function paused(...fnArgs) { if (argsAndOriginalFns.has(paused)) { argsAndOriginalFns.get(paused).bufferedArgs.push(fnArgs); return undefined; } return fn(...fnArgs); } argsAndOriginalFns.set(paused, { original: fn, bufferedArgs: [] }); resumed.delete(paused); return paused; } module.exports = pauseFn; Object.defineProperties(module.exports, { pause: { enumerable: true, value: pauseFn }, resume: { enumerable: true, value: function resume(...args) { validateArgumentLength(args); const [paused] = args; if (typeof paused !== 'function') { const error = new TypeError(`${PAUSE_ERROR}, but got a non-function value ${inspectWithKind(paused)}.`); error.code = 'ERR_INVALID_ARG_TYPE'; throw error; } if (resumed.has(paused)) { const error = new TypeError(`${PAUSE_ERROR}, but got an already resume()-ed one ${inspect(paused, {breakLength: Infinity})}.`); error.code = 'ERR_INVALID_ARG_VALUE'; throw error; } if (!argsAndOriginalFns.has(paused)) { const error = new TypeError(`${PAUSE_ERROR}, but got ${inspect(paused, {breakLength: Infinity})} which is not returned by \`pauseFn()\`.`); error.code = 'ERR_INVALID_ARG_VALUE'; throw error; } const {original, bufferedArgs} = argsAndOriginalFns.get(paused); const returnValues = bufferedArgs.map(apply, original); argsAndOriginalFns.delete(paused); resumed.add(paused); return returnValues; } } });