ts-ioc-container
Version:
Typescript IoC container
67 lines (66 loc) • 3.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.runOnDisposeHooks = exports.onDispose = exports.runOnConstructHooks = exports.onConstruct = exports.injectProp = exports.runHooksAsync = exports.runHooks = exports.hook = exports.toHookFn = void 0;
exports.getHooks = getHooks;
exports.hasHooks = hasHooks;
const HookContext_1 = require("./HookContext");
const utils_1 = require("../utils");
const UnexpectedHookResultError_1 = require("../errors/UnexpectedHookResultError");
const inject_1 = require("../injector/inject");
const isHookClassConstructor = (execute) => {
return (0, utils_1.isConstructor)(execute) && execute.prototype.execute;
};
const toHookFn = (execute) => isHookClassConstructor(execute) ? (context) => context.scope.resolveOne(execute).execute(context) : execute;
exports.toHookFn = toHookFn;
const hook = (key, ...fns) => (target, propertyKey) => {
const hooks = Reflect.hasMetadata(key, target.constructor)
? Reflect.getMetadata(key, target.constructor)
: new Map();
hooks.set(propertyKey, (hooks.get(propertyKey) ?? []).concat(fns));
Reflect.defineMetadata(key, hooks, target.constructor);
};
exports.hook = hook;
function getHooks(target, key) {
return Reflect.hasMetadata(key, target.constructor) ? Reflect.getMetadata(key, target.constructor) : new Map();
}
function hasHooks(target, key) {
return Reflect.hasMetadata(key, target.constructor);
}
const runHooks = (target, key, { scope, createContext = HookContext_1.createHookContext, predicate = () => true, }) => {
const hooks = Array.from(getHooks(target, key).entries()).filter(([methodName]) => predicate(methodName));
const runMethodHooks = (methodName, executions) => {
const context = createContext(target, scope, methodName);
for (const execute of executions) {
const result = execute(context);
if (result instanceof Promise) {
throw new UnexpectedHookResultError_1.UnexpectedHookResultError(`Hook ${methodName} returned a promise, use runHooksAsync instead`);
}
}
};
for (const [methodName, executions] of hooks) {
runMethodHooks(methodName, executions.map(exports.toHookFn));
}
};
exports.runHooks = runHooks;
const runHooksAsync = (target, key, { scope, createContext = HookContext_1.createHookContext, predicate = () => true, }) => {
const hooks = Array.from(getHooks(target, key).entries()).filter(([methodName]) => predicate(methodName));
const runMethodHooks = async (methodName, executions) => {
const context = createContext(target, scope, methodName);
for (const execute of executions) {
await (0, utils_1.promisify)(execute(context));
}
};
return Promise.all(hooks.map(([methodName, executions]) => runMethodHooks(methodName, executions.map(exports.toHookFn))));
};
exports.runHooksAsync = runHooksAsync;
const injectProp = (fn) => (context) => context.setProperty((0, inject_1.toInjectFn)(fn));
exports.injectProp = injectProp;
const onConstruct = (fn) => (0, exports.hook)('onConstruct', fn);
exports.onConstruct = onConstruct;
const runOnConstructHooks = (target, scope) => (0, exports.runHooks)(target, 'onConstruct', { scope });
exports.runOnConstructHooks = runOnConstructHooks;
exports.onDispose = (0, exports.hook)('onDispose', (context) => {
context.invokeMethod({});
});
const runOnDisposeHooks = (target, scope) => (0, exports.runHooks)(target, 'onDispose', { scope });
exports.runOnDisposeHooks = runOnDisposeHooks;