105 lines
2.4 KiB
JavaScript
105 lines
2.4 KiB
JavaScript
module.exports = register
|
|
|
|
function register (state, name, options, method) {
|
|
if (arguments.length === 3) {
|
|
method = options
|
|
options = {}
|
|
}
|
|
|
|
if (typeof method !== 'function') {
|
|
throw new Error('method for before hook must be a function')
|
|
}
|
|
|
|
if (typeof options !== 'object') {
|
|
throw new Error('options for before hook must be an object')
|
|
}
|
|
|
|
if (Array.isArray(name)) {
|
|
return name.reverse().reduce(function (callback, name) {
|
|
return register.bind(null, state, name, options, callback)
|
|
}, method)()
|
|
}
|
|
|
|
var hooks = state.registry[name]
|
|
|
|
if (!hooks) {
|
|
return invokeMethod(options, method)
|
|
}
|
|
|
|
var beforeHooks = hooks.before
|
|
var errorHooks = hooks.error
|
|
var afterHooks = hooks.after
|
|
|
|
// 1. run "before hooks" which may mutate options
|
|
return Promise.all(beforeHooks.map(invokeBeforeHook.bind(null, options)))
|
|
|
|
// 2. Once all finish without error, call the method with the (mutated) options
|
|
.then(function () {
|
|
return method(options)
|
|
})
|
|
|
|
// 3. If an error occurs in 1. or 2. run the "error hooks" which may mutate
|
|
// the error object. If one of them does not return an error then set the
|
|
// result to that. Otherwise throw (mutated) error.
|
|
.catch(function (error) {
|
|
return Promise.all(errorHooks.map(invokeErrorHook.bind(null, error, options)))
|
|
|
|
.then(function (results) {
|
|
var nonErrorResults = results.filter(isntError)
|
|
|
|
if (nonErrorResults.length) {
|
|
return nonErrorResults[0]
|
|
}
|
|
|
|
throw error
|
|
})
|
|
})
|
|
|
|
// 4. Run the "after hooks". They may mutate the result
|
|
.then(function (result) {
|
|
return Promise.all(afterHooks.map(invokeAfterHook.bind(null, result, options)))
|
|
|
|
.then(function () {
|
|
return result
|
|
})
|
|
})
|
|
}
|
|
|
|
function invokeMethod (options, method) {
|
|
try {
|
|
return Promise.resolve(method(options))
|
|
} catch (error) {
|
|
return Promise.reject(error)
|
|
}
|
|
}
|
|
|
|
function invokeBeforeHook (options, method) {
|
|
try {
|
|
return method(options)
|
|
} catch (error) {
|
|
return Promise.reject(error)
|
|
}
|
|
}
|
|
|
|
function invokeErrorHook (result, options, errorHook) {
|
|
try {
|
|
return Promise.resolve(errorHook(result, options))
|
|
|
|
.catch(function (error) { return error })
|
|
} catch (error) {
|
|
return Promise.resolve(error)
|
|
}
|
|
}
|
|
|
|
function invokeAfterHook (result, options, method) {
|
|
try {
|
|
return method(result, options)
|
|
} catch (error) {
|
|
return Promise.reject(error)
|
|
}
|
|
}
|
|
|
|
function isntError (result) {
|
|
return !(result instanceof Error)
|
|
}
|