65 lines
1.3 KiB
JavaScript
65 lines
1.3 KiB
JavaScript
|
'use strict'
|
|||
|
|
|||
|
var slice = [].slice
|
|||
|
|
|||
|
module.exports = wrap
|
|||
|
|
|||
|
// Wrap `fn`.
|
|||
|
// Can be sync or async; return a promise, receive a completion handler, return
|
|||
|
// new values and errors.
|
|||
|
function wrap(fn, callback) {
|
|||
|
var invoked
|
|||
|
|
|||
|
return wrapped
|
|||
|
|
|||
|
function wrapped() {
|
|||
|
var params = slice.call(arguments, 0)
|
|||
|
var callback = fn.length > params.length
|
|||
|
var result
|
|||
|
|
|||
|
if (callback) {
|
|||
|
params.push(done)
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
result = fn.apply(null, params)
|
|||
|
} catch (error) {
|
|||
|
// Well, this is quite the pickle.
|
|||
|
// `fn` received a callback and invoked it (thus continuing the pipeline),
|
|||
|
// but later also threw an error.
|
|||
|
// We’re not about to restart the pipeline again, so the only thing left
|
|||
|
// to do is to throw the thing instead.
|
|||
|
if (callback && invoked) {
|
|||
|
throw error
|
|||
|
}
|
|||
|
|
|||
|
return done(error)
|
|||
|
}
|
|||
|
|
|||
|
if (!callback) {
|
|||
|
if (result && typeof result.then === 'function') {
|
|||
|
result.then(then, done)
|
|||
|
} else if (result instanceof Error) {
|
|||
|
done(result)
|
|||
|
} else {
|
|||
|
then(result)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Invoke `next`, only once.
|
|||
|
function done() {
|
|||
|
if (!invoked) {
|
|||
|
invoked = true
|
|||
|
|
|||
|
callback.apply(null, arguments)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Invoke `done` with one value.
|
|||
|
// Tracks if an error is passed, too.
|
|||
|
function then(value) {
|
|||
|
done(null, value)
|
|||
|
}
|
|||
|
}
|