Created
March 15, 2017 19:23
-
-
Save JeffRMoore/e921845d397f14feb76c937f8aa9c2fd to your computer and use it in GitHub Desktop.
Experimental version of compose
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function compose (middleware) { | |
if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!') | |
for (const fn of middleware) { | |
if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') | |
} | |
return function (context, next, skipNext) { | |
if (next !== undefined && typeof next !== 'function') { | |
throw new TypeError('Next must be a function when specified') | |
} | |
if (skipNext !== undefined && typeof skipNext !== 'function') { | |
throw new TypeError('skipNext must be a function when specified') | |
} | |
let maxDispatched = -1; | |
let hasTerminated = false; | |
let dispatchTo = -1; | |
return dispatchNext() | |
function dispatchSkipNext() { | |
if (hasTerminated) { | |
throw new Error('middleware called skipNext() more than once'); | |
} | |
hasTerminated = true; | |
if (skipNext) { | |
return skipNext() | |
} | |
return Promise.resolve() | |
} | |
function checkResolvedValue(value) { | |
if (!hasTerminated) { | |
throw new Error('middleware has not called next() or skipNext()'); | |
} | |
return value; | |
} | |
function dispatchNext() { | |
if (hasTerminated) { | |
throw new Error('middleware chain has terminated more than once'); | |
} | |
dispatchTo++; | |
if (dispatchTo <= maxDispatched) { | |
throw new Error('middleware called next() more than once'); | |
} | |
maxDispatched = dispatchTo; | |
try { | |
let result; | |
if (dispatchTo < middleware.length) { | |
result = middleware[dispatchTo](context, dispatchNext, dispatchSkipNext); | |
} else { | |
const terminate = next || dispatchSkipNext | |
result = terminate(); | |
hasTerminated = true; | |
} | |
if (typeof result === 'object' && result !== null && typeof result.then === 'function') { | |
return result.then(checkResolvedValue); | |
} | |
return Promise.reject(new TypeError('Middleware must return a Promise')); | |
} catch (err) { | |
return Promise.reject(err); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment