@known-as-bmf/hookable
Version:
Function hooking utility.
73 lines (70 loc) • 2.08 kB
JavaScript
/**
* Setup a subscription and save it to provided `Map`.
*
* @param map - The map to save the subscription to.
*
* @internal
*/
const hookInto = (map) => (subscription) => {
// symbol used to uniquely identify this subscription
const symbol = Symbol();
const unsubscribe = () => {
map.delete(symbol);
};
map.set(symbol, subscription(unsubscribe));
};
/**
* Create a hookable function.
*
* @param fn - The function to make hookable.
*
* @public
*/
function createHookable(fn) {
const transformInput = new Map();
const enter = new Map();
const transformOutput = new Map();
const leave = new Map();
return Object.assign(((...initialArgs) => {
// apply input transformations - `TransformInput`
const tArgs = Array.from(transformInput.values()).reduce((args, ti) => ti(...args), initialArgs);
// "entering" function with transformed inputs - `TapInput`
enter.forEach((e) => e(...tArgs));
const initialResult = fn(...tArgs);
// apply output transformations - TransformOutput
const tResult = Array.from(transformOutput.values()).reduce((result, a) => a(result), initialResult);
// "leaving" function with transformed output - TapOutput
leave.forEach((e) => e(tResult));
return tResult;
}), {
transformInput: hookInto(transformInput),
enter: hookInto(enter),
transformOutput: hookInto(transformOutput),
leave: hookInto(leave),
});
}
/**
* Create a hook subscriber that never unsubscribes.
*
* @param fn - The hook to register.
*
* @public
*/
const every = (fn) => () => {
return ((...args) => fn(...args));
};
/**
* Create a hook subscriber that unsubscribes after the first call.
*
* @param fn - The hook to register.
*
* @public
*/
const once = (fn) => (unsub) => {
return ((...args) => {
unsub();
return fn(...args);
});
};
export { createHookable, every, once };
//# sourceMappingURL=index.es.js.map