Allow hooks to be defined and invoked in order based on its names.
By default, named-hooks
use filenames and -
as delimiters to define hook invoke order.
Inside ./hooks/
// master.js
module.exports = {
// sync hook
hook1: function (data/*, context */) {
// manipulate `data`
data.count += 1;
// return new `data`
return data;
},
// async hooks take a `resolve` parameter
hook2: function (data, context, resolve) {
// manipulate `data`
resolve(data);
},
// async hooks take a `reject` parameter too
hook3: function (data, context, resolve, reject) {
// manipulate `data`
reject(data);
}
// as many other hooks as you want
};
// Flow1.js
module.exports = {
hook1Flow1: function (data) {
// manipulate `data`
data.count += 1;
// return new `data`
return data;
}
// ...
};
// Flow1-v2.js
module.exports = {
hook1Flow1v2: function (data, context, resolve) {
// make an async operation, like calling a service
setTimeout(function () {
// manipulate `data` after response
data.count += 1;
// resolve hook
resolve(data);
}, 1000);
}
// ...
};
Using named-hooks
var myHooks = require('named-hooks')('myHooks');
// Load hooks from `hooks` folder
myHooks.init('./hooks');
var data = {
count: 0
};
// `invoke` will call hooks defined in `./hooks/` folder and return a promise
// hooks called:
// 1. 'hook1'
// 2. 'hook1Flow1'
// 3. 'hook1Flow1v2'
myHooks.invoke('hook1', 'Flow1-v2', data/*, context*/).then(function (result) {
console.log(data); // { count: 0 }
console.log(result); // { count: 3 }
});
Load all files from folder
synchronously and populate hooks, you'll probably do this only once.
Returns an Array with all possible hook names defined by the combination of these arguments.
If the order doesn't make sense to your project and you have other business rules, you can define your own way to resolve the hook names.
Use invoke
if any hook is async, it returns a promise with the transformed data. It'll invoke all hooks returned by #getPossibleHookNames(hookName, identifier)
that are defined repassing all arguments provided. Arguments are passed by value, so each hook needs to return the new modified value if synchronous or resolve the promise if asynchronous. context
is a way to make local variables available to hook implementations and it's optional.
Returns a transform function that will resolve a promise chain. Works the same way as #invoke
.
// master.js
module.exports = {
// async hook
hookName: function (data, context, resolve, reject) {
console.log(context.foo); // 'bar'
setTimeout(resolve, 1000, data + 5);
}
};
In the middle of a promise chain:
// example using `q` module for promises, it'll work with
// any promise implementation that complies with A+
q(5)
.then(namedHooks.invokeChain('hookName', 'indentifier', { foo: 'bar' }))
.then(console.log);
// outputs `10`
Works the same way as #invoke
, but returns the actual transformed data instead of a promise, useful if all hooks are exclusively synchronous.All hooks needs to return the new modified value.
Any PR is more than welcome, just make sure your stuff is tested and that all tests are passing.
tl;dr: npm test
must be green and if I delete your code it should be red :)
MIT