UNPKG

moost

Version:
958 lines (931 loc) 33.5 kB
import { Mate, getConstructor, isConstructor } from "@prostojs/mate"; import { ContextInjector, EventLogger, createAsyncEventContext, getContextInjector, replaceContextInjector, useAsyncEventContext, useEventId, useEventLogger, useRouteParams } from "@wooksjs/event-core"; import { Infact, createProvideRegistry, createReplaceRegistry } from "@prostojs/infact"; import { ProstoLogger, coloredConsole, createConsoleTransort } from "@prostojs/logger"; import { Hookable } from "hookable"; import { clearGlobalWooks, getGlobalWooks } from "wooks"; //#region packages/moost/src/logger.ts let defaultLogger; function setDefaultLogger(logger) { defaultLogger = logger; } function getDefaultLogger(topic) { if (!defaultLogger) defaultLogger = new ProstoLogger({ level: 4, transports: [createConsoleTransort({ format: coloredConsole })] }); return topic && defaultLogger instanceof ProstoLogger ? defaultLogger.createTopic(topic) : defaultLogger; } //#endregion //#region packages/moost/src/pipes/run-pipes.ts async function runPipes(pipes, initialValue, metas, level) { let v = initialValue; for (const pipe of pipes) v = await pipe.handler(v, metas, level); return v; } //#endregion //#region packages/moost/src/metadata/moost-metadata.ts const METADATA_WORKSPACE = "moost"; const moostMate = new Mate(METADATA_WORKSPACE, { readType: true, readReturnType: true, collectPropKeys: true, inherit(classMeta, targetMeta, level) { if (level === "CLASS") return !!classMeta?.inherit; if (level === "PROP") return !!targetMeta?.inherit || !!(classMeta?.inherit && !targetMeta); return !!targetMeta?.inherit; } }); function getMoostMate() { return moostMate; } //#endregion //#region packages/moost/src/metadata/infact.ts const sharedMoostInfact = getNewMoostInfact(); const INFACT_BANNER = `${"\x1B[2m\x1B[35m"}infact`; let loggingOptions = { newInstance: "SINGLETON", warn: true, error: true }; function setInfactLoggingOptions(options) { loggingOptions = { ...loggingOptions, ...options }; } function getMoostInfact() { return sharedMoostInfact; } const scopeVarsMap = new Map(); function defineInfactScope(name, scopeVars) { scopeVarsMap.set(name, scopeVars); getMoostInfact().registerScope(name); } function getInfactScopeVars(name) { return scopeVarsMap.get(name); } function getNewMoostInfact() { return new Infact({ describeClass(classConstructor) { const meta = getMoostMate().read(classConstructor); return { injectable: !!meta?.injectable, global: false, constructorParams: meta?.params || [], provide: meta?.provide, properties: meta?.properties || [], scopeId: meta?.injectable === "FOR_EVENT" ? useEventId().getId() : undefined }; }, resolveParam({ paramMeta, customData, classConstructor, index, scopeId }) { if (paramMeta && customData?.pipes) return runPipes(customData.pipes, undefined, { paramMeta, type: classConstructor, key: "constructor", scopeId, classMeta: getMoostMate().read(classConstructor), index, targetMeta: paramMeta }, "PARAM"); }, describeProp(classConstructor, key) { const meta = getMoostMate().read(classConstructor, key); return meta; }, resolveProp({ instance, key, initialValue, propMeta, scopeId, classMeta, customData, classConstructor }) { if (propMeta && customData?.pipes) return runPipes(customData.pipes, initialValue, { instance, type: classConstructor, key, scopeId, propMeta, targetMeta: propMeta, classMeta }, "PROP"); }, storeProvideRegByInstance: true, on: (event, targetClass, message, args) => { switch (event) { case "new-instance": { const scope = getMoostMate().read(targetClass)?.injectable || "SINGLETON"; if (loggingOptions.newInstance === false || !(loggingOptions.newInstance === scope || loggingOptions.newInstance === "SINGLETON" && scope === true)) return; break; } case "warn": { if (!loggingOptions.warn) return; break; } case "error": { if (!loggingOptions.error) return; break; } } let logger; try { logger = event === "error" ? getDefaultLogger(INFACT_BANNER) : useEventLogger(INFACT_BANNER); } catch (error) { logger = getDefaultLogger(INFACT_BANNER); } const instance = `${"\x1B[4m"}${targetClass.name}${"\x1B[24m"}`; switch (event) { case "new-instance": { const params = args?.map((a) => { switch (typeof a) { case "number": case "boolean": return `${"\x1B[33m"}${a}${"\x1B[2m\x1B[34m"}`; case "string": return `${"\x1B[92m"}"${a.slice(0, 1)}..."${"\x1B[2m\x1B[34m"}`; case "object": { if (Array.isArray(a)) return `[${a.length}]`; if (getConstructor(a)) return getConstructor(a).name; return "{}"; } default: return "*"; } }).map((a) => `${"\x1B[2m\x1B[1m"}${a}${"\x1B[22m\x1B[2m"}`).join(", ") || ""; logger.info(`new ${instance}${"\x1B[2m\x1B[34m"}(${params})`); break; } case "warn": { const hier = `${"\x1B[2m\x1B[34m"}${args?.map(String).join(" → ") || ""}`; logger.warn(`${instance} - ${message} ${hier}`); break; } case "error": { const hier = `${"\x1B[2m\x1B[34m"}${args?.map(String).join(" → ") || ""}`; logger.error(`Failed to instantiate ${instance}. ${message} ${hier}`); break; } default: break; } } }); } //#endregion //#region packages/moost/src/composables/controller.composable.ts function setControllerContext(controller, method, route) { const { store } = useAsyncEventContext(); const { set } = store("controller"); set("instance", controller); set("method", method); set("route", route); } function useControllerContext() { const { store } = useAsyncEventContext(); const { get } = store("controller"); const getController = () => get("instance"); const getMethod = () => get("method"); const getRoute = () => get("route"); const getControllerMeta = () => getMoostMate().read(getController()); const getMethodMeta = (name) => getMoostMate().read(getController(), name || getMethod()); function instantiate(c) { return getMoostInfact().getForInstance(getController(), c); } return { instantiate, getRoute, getController, getMethod, getControllerMeta, getMethodMeta, getPropertiesList: () => getControllerMeta()?.properties || [], getScope: () => getControllerMeta()?.injectable || "SINGLETON", getParamsMeta: () => getMethodMeta()?.params || [], getPropMeta: (name) => getMethodMeta(name) }; } //#endregion //#region packages/moost/src/adapter-utils.ts const infact = getMoostInfact(); function registerEventScope(scopeId) { infact.registerScope(scopeId); return () => { infact.unregisterScope(scopeId); }; } function defineMoostEventHandler(options) { const ci = getContextInjector(); return async () => { const scopeId = useEventId().getId(); const logger = useEventLogger(options.loggerTitle); const unscope = registerEventScope(scopeId); let response; const hookOptions = { scopeId, logger, unscope, method: options.controllerMethod, getResponse: () => response, reply: (r) => response = r }; if (options.hooks?.init) await options.hooks.init(hookOptions); const instance = await options.getControllerInstance(); if (instance) { setControllerContext(instance, options.controllerMethod || "", options.targetPath); ci.hook(options.handlerType, "Controller:registered"); } const interceptorHandler = await options.getIterceptorHandler(); if (interceptorHandler?.count) try { response = await ci.with("Interceptors:init", () => interceptorHandler.init()); if (response !== undefined) return await endWithResponse(); } catch (error) { options.logErrors && logger.error(error); response = error; return endWithResponse(true); } let args = []; if (options.resolveArgs) try { args = await ci.with("Arguments:resolve", () => options.resolveArgs()); } catch (error) { options.logErrors && logger.error(error); response = error; return endWithResponse(true); } if (interceptorHandler?.countBefore) { response = await ci.with("Interceptors:before", () => interceptorHandler.fireBefore(response)); if (response !== undefined) return endWithResponse(); } const callControllerMethod = () => { if (options.callControllerMethod) return options.callControllerMethod(args); else if (instance && options.controllerMethod && typeof instance[options.controllerMethod] === "function") return instance[options.controllerMethod](...args); }; try { response = await ci.with(`Handler:${options.targetPath}`, { "moost.handler": options.controllerMethod || "", "moost.controller": getConstructor(instance).name }, () => callControllerMethod()); } catch (error) { options.logErrors && logger.error(error); response = error; return endWithResponse(true); } async function endWithResponse(raise = false) { if (interceptorHandler?.countAfter || interceptorHandler?.countOnError) try { response = await ci.with("Interceptors:after", () => interceptorHandler.fireAfter(response)); } catch (error) { options.logErrors && logger.error(error); if (!options.manualUnscope) unscope(); throw error; } if (!options.manualUnscope) unscope(); if (options.hooks?.end) await options.hooks.end(hookOptions); if (raise) throw response; return response; } return endWithResponse(); }; } //#endregion //#region packages/moost/src/binding/utils.ts function getInstanceOwnMethods(instance) { const proto = Object.getPrototypeOf(instance); return [ ...getParentProps(getConstructor(instance)), ...Object.getOwnPropertyNames(proto), ...Object.getOwnPropertyNames(instance) ].filter((m) => typeof instance[m] === "function"); } function getInstanceOwnProps(instance) { const proto = Object.getPrototypeOf(instance); return [ ...getParentProps(getConstructor(instance)), ...Object.getOwnPropertyNames(proto), ...Object.getOwnPropertyNames(instance) ].filter((m) => typeof instance[m] !== "function"); } const fnProto = Object.getPrototypeOf(Function); function getParentProps(constructor) { const parent = Object.getPrototypeOf(constructor); if (typeof parent === "function" && parent !== fnProto && parent !== constructor && parent.prototype) return [...getParentProps(parent), ...Object.getOwnPropertyNames(parent.prototype)]; return []; } //#endregion //#region packages/moost/src/class-function/class-function.ts async function getCallableFn(targetInstance, fn, pipes, logger) { const mate$1 = getMoostMate(); const meta = mate$1.read(fn); if (meta?.injectable) { const infact$1 = getMoostInfact(); const instance = await infact$1.getForInstance(targetInstance, fn, { customData: { pipes: [...pipes || [], ...meta.pipes || []].sort((a, b) => a.priority - b.priority) } }); return (...args) => instance.handler(...args); } if (typeof fn === "function") return fn; const e = new Error(`getCallableFn failed for "${getConstructor(targetInstance).name}" because the passed arg is not a Function nor TClassFunction`); logger.error(e); throw e; } //#endregion //#region packages/moost/src/interceptor-handler.ts function _define_property$1(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } var InterceptorHandler = class { get count() { return this.handlers.length; } get countBefore() { return this.before.length; } get countAfter() { return this.after.length; } get countOnError() { return this.onError.length; } replyFn(reply) { this.response = reply; this.responseOverwritten = true; } async init() { const ci = getContextInjector(); for (const { handler, name } of this.handlers) { const response = await ci.with(`Interceptor:${name}`, { "moost.interceptor.stage": "init" }, () => handler((fn) => { this.before.push({ name, fn }); }, (fn) => { this.after.unshift({ name, fn }); }, (fn) => { this.onError.unshift({ name, fn }); })); if (response !== undefined) return response; } } async fireBefore(response) { const ci = getContextInjector(); this.response = response; for (const { name, fn } of this.before) { await ci.with(`Interceptor:${name}`, { "moost.interceptor.stage": "before" }, () => fn(this.replyFn.bind(this))); if (this.responseOverwritten) break; } return this.response; } async fireAfter(response) { const ci = getContextInjector(); this.response = response; if (response instanceof Error) for (const { name, fn } of this.onError) await ci.with(`Interceptor:${name}`, { "moost.interceptor.stage": "after" }, () => fn(response, this.replyFn.bind(this))); else for (const { name, fn } of this.after) await ci.with(`Interceptor:${name}`, { "moost.interceptor.stage": "onError" }, () => fn(response, this.replyFn.bind(this))); return this.response; } constructor(handlers) { _define_property$1(this, "handlers", void 0); _define_property$1(this, "before", void 0); _define_property$1(this, "after", void 0); _define_property$1(this, "onError", void 0); _define_property$1(this, "response", void 0); _define_property$1(this, "responseOverwritten", void 0); this.handlers = handlers; this.before = []; this.after = []; this.onError = []; this.responseOverwritten = false; } }; //#endregion //#region packages/moost/src/utils.ts const mate = getMoostMate(); function getIterceptorHandlerFactory(interceptors, getTargetInstance, pipes, logger) { return () => { const interceptorHandlers = []; for (const { handler, name } of interceptors) { const interceptorMeta = mate.read(handler); if (interceptorMeta?.injectable) interceptorHandlers.push({ handler: async (...args) => { const targetInstance = await getTargetInstance(); return (await getCallableFn(targetInstance, handler, pipes, logger))(...args); }, name }); else interceptorHandlers.push({ handler, name }); } return Promise.resolve(new InterceptorHandler(interceptorHandlers)); }; } //#endregion //#region packages/moost/src/binding/bind-controller.ts async function bindControllerMethods(options) { const opts = options || {}; const { getInstance } = opts; const { classConstructor } = opts; const { adapters } = opts; opts.globalPrefix = opts.globalPrefix || ""; opts.provide = opts.provide || {}; const fakeInstance = Object.create(classConstructor.prototype); const methods = getInstanceOwnMethods(fakeInstance); const mate$1 = getMoostMate(); const meta = mate$1.read(classConstructor) || {}; const ownPrefix = typeof opts.replaceOwnPrefix === "string" ? opts.replaceOwnPrefix : meta.controller?.prefix || ""; const prefix = `${opts.globalPrefix}/${ownPrefix}`; const controllerOverview = { meta, computedPrefix: prefix, type: classConstructor, handlers: [] }; for (const method of methods) { const methodMeta = getMoostMate().read(fakeInstance, method) || {}; if (!methodMeta.handlers?.length) continue; const pipes = [...opts.pipes || [], ...methodMeta.pipes || []].sort((a, b) => a.priority - b.priority); const interceptors = [ ...opts.interceptors || [], ...meta.interceptors || [], ...methodMeta.interceptors || [] ].sort((a, b) => a.priority - b.priority); const getIterceptorHandler = getIterceptorHandlerFactory(interceptors, getInstance, pipes, options.logger); const argsPipes = []; for (const p of methodMeta.params || []) argsPipes.push({ meta: p, pipes: [...pipes, ...p.pipes || []].sort((a, b) => a.priority - b.priority) }); const resolveArgs = async () => { const args = []; for (const [i, { pipes: pipes$1, meta: paramMeta }] of argsPipes.entries()) args[i] = await runPipes(pipes$1, undefined, { classMeta: meta, methodMeta, paramMeta, type: classConstructor, key: method, index: i, targetMeta: paramMeta }, "PARAM"); return args; }; const wm = new WeakMap(); controllerOverview.handlers.push(...methodMeta.handlers.map((h) => { const data = { meta: methodMeta, path: h.path, type: h.type, method, handler: h, registeredAs: [] }; wm.set(h, data); return data; })); for (const adapter of adapters) await adapter.bindHandler({ prefix, fakeInstance, getInstance, method, handlers: methodMeta.handlers, getIterceptorHandler, resolveArgs, logHandler: (eventName) => { options.moostInstance.logMappedHandler(eventName, classConstructor, method); }, register(h, path, args) { const data = wm.get(h); if (data) data.registeredAs.push({ path, args }); } }); } return controllerOverview; } //#endregion //#region packages/moost/src/decorators/circular.decorator.ts function Circular(resolver) { return getMoostMate().decorate("circular", resolver); } //#endregion //#region packages/moost/src/decorators/common.decorator.ts function Label(value) { return getMoostMate().decorate("label", value); } function Description(value) { return getMoostMate().decorate("description", value); } function Value(value) { return getMoostMate().decorate("value", value); } function Id(value) { return getMoostMate().decorate("id", value); } function Optional() { return getMoostMate().decorate("optional", true); } function Required() { const mate$1 = getMoostMate(); return mate$1.apply(mate$1.decorate("required", true), mate$1.decorateClass((meta, level, key, index) => { if (typeof index !== "number" && meta && ["string", "symbol"].includes(typeof key)) { meta.requiredProps = meta.requiredProps || []; meta.requiredProps.push(key); } return meta; })); } //#endregion //#region packages/moost/src/decorators/injectable.decorator.ts function Injectable(scope = true) { return getMoostMate().decorate("injectable", scope); } const insureInjectable = getMoostMate().decorate((meta) => { if (!meta.injectable) meta.injectable = true; return meta; }); //#endregion //#region packages/moost/src/decorators/controller.decorator.ts function Controller(prefix) { const mate$1 = getMoostMate(); return mate$1.apply(insureInjectable, mate$1.decorate("controller", { prefix: prefix || "" })); } function ImportController(prefix, controller, provide) { return getMoostMate().decorate("importController", { prefix: typeof prefix === "string" ? prefix : undefined, typeResolver: typeof prefix === "string" ? controller : prefix, provide: typeof prefix === "string" ? provide || undefined : controller || undefined }, true); } //#endregion //#region packages/moost/src/decorators/inherit.decorator.ts const Inherit = () => getMoostMate().decorate("inherit", true); //#endregion //#region packages/moost/src/decorators/intercept.decorator.ts var TInterceptorPriority = /*#__PURE__*/ function(TInterceptorPriority$1) { TInterceptorPriority$1[TInterceptorPriority$1["BEFORE_ALL"] = 0] = "BEFORE_ALL"; TInterceptorPriority$1[TInterceptorPriority$1["BEFORE_GUARD"] = 1] = "BEFORE_GUARD"; TInterceptorPriority$1[TInterceptorPriority$1["GUARD"] = 2] = "GUARD"; TInterceptorPriority$1[TInterceptorPriority$1["AFTER_GUARD"] = 3] = "AFTER_GUARD"; TInterceptorPriority$1[TInterceptorPriority$1["INTERCEPTOR"] = 4] = "INTERCEPTOR"; TInterceptorPriority$1[TInterceptorPriority$1["CATCH_ERROR"] = 5] = "CATCH_ERROR"; TInterceptorPriority$1[TInterceptorPriority$1["AFTER_ALL"] = 6] = "AFTER_ALL"; return TInterceptorPriority$1; }({}); function Intercept(handler, priority, name) { return getMoostMate().decorate("interceptors", { handler, priority: priority || handler.priority || 4, name: name || handler._name || handler.name }, true); } //#endregion //#region packages/moost/src/decorators/resolve.decorator.ts function Resolve(resolver, label) { return (target, key, index) => { const i = typeof index === "number" ? index : undefined; getMoostMate().decorate("resolver", (metas, level) => { let newLabel = label; if (!newLabel && level === "PROP" && typeof metas.key === "string") newLabel = metas.key; fillLabel(target, key || "", i, newLabel); return resolver(metas, level); })(target, key, i); }; } function Param(name) { return getMoostMate().apply(getMoostMate().decorate("paramSource", "ROUTE"), getMoostMate().decorate("paramName", name), Resolve(() => useRouteParams().get(name), name)); } function Params() { return Resolve(() => useRouteParams().params, "params"); } function Const(value, label) { return Resolve(() => value, label); } function ConstFactory(factory, label) { return Resolve(async () => factory(), label); } function fillLabel(target, key, index, name) { if (name) { const meta = getMoostMate().read(target, key); if (typeof index === "number") { if (!meta?.params?.[index]?.label) Label(name)(target, key, index); } else if (!meta?.label) Label(name)(target, key); } } //#endregion //#region packages/moost/src/decorators/logger.decorator.ts function InjectEventLogger(topic) { return Resolve(() => useEventLogger(topic)); } function InjectMoostLogger(topic) { return Resolve(async (metas) => { const { instantiate, getController } = useControllerContext(); const controller = getController(); const moostApp = controller instanceof Moost ? controller : await instantiate(Moost); const meta = metas.classMeta; return moostApp.getLogger(meta?.loggerTopic || topic || meta?.id); }); } function LoggerTopic(topic) { return getMoostMate().decorate("loggerTopic", topic); } //#endregion //#region packages/moost/src/pipes/types.ts var TPipePriority = /*#__PURE__*/ function(TPipePriority$1) { TPipePriority$1[TPipePriority$1["BEFORE_RESOLVE"] = 0] = "BEFORE_RESOLVE"; TPipePriority$1[TPipePriority$1["RESOLVE"] = 1] = "RESOLVE"; TPipePriority$1[TPipePriority$1["AFTER_RESOLVE"] = 2] = "AFTER_RESOLVE"; TPipePriority$1[TPipePriority$1["BEFORE_TRANSFORM"] = 3] = "BEFORE_TRANSFORM"; TPipePriority$1[TPipePriority$1["TRANSFORM"] = 4] = "TRANSFORM"; TPipePriority$1[TPipePriority$1["AFTER_TRANSFORM"] = 5] = "AFTER_TRANSFORM"; TPipePriority$1[TPipePriority$1["BEFORE_VALIDATE"] = 6] = "BEFORE_VALIDATE"; TPipePriority$1[TPipePriority$1["VALIDATE"] = 7] = "VALIDATE"; TPipePriority$1[TPipePriority$1["AFTER_VALIDATE"] = 8] = "AFTER_VALIDATE"; return TPipePriority$1; }({}); //#endregion //#region packages/moost/src/decorators/pipe.decorator.ts function Pipe(handler, priority) { if (typeof priority !== "number") priority = typeof handler.priority === "number" ? handler.priority : TPipePriority.TRANSFORM; return getMoostMate().decorate("pipes", { handler, priority }, true); } //#endregion //#region packages/moost/src/decorators/provide.decorator.ts function Provide(type, fn) { return getMoostMate().decorate((meta) => { meta.provide = meta.provide || {}; Object.assign(meta.provide, createProvideRegistry([type, fn])); return meta; }); } function Replace(type, newType) { return getMoostMate().decorate((meta) => { meta.replace = meta.replace || {}; Object.assign(meta.replace, createReplaceRegistry([type, newType])); return meta; }); } function Inject(type) { return getMoostMate().decorate("inject", type); } function InjectFromScope(name) { return getMoostMate().decorate("fromScope", name); } function InjectScopeVars(name) { return Resolve(({ scopeId }) => { if (scopeId) return name ? getInfactScopeVars(scopeId)?.[name] : getInfactScopeVars(scopeId); return undefined; }); } //#endregion //#region packages/moost/src/define.ts function defineInterceptorFn(fn, priority = TInterceptorPriority.INTERCEPTOR) { fn.priority = priority; return fn; } function definePipeFn(fn, priority = TPipePriority.TRANSFORM) { fn.priority = priority; return fn; } //#endregion //#region packages/moost/src/pipes/resolve.pipe.ts const resolvePipe = definePipeFn((_value, metas, level) => { const resolver = metas.targetMeta?.resolver; if (resolver) return resolver(metas, level); return undefined; }, TPipePriority.RESOLVE); //#endregion //#region packages/moost/src/pipes/shared-pipes.ts const sharedPipes = [{ handler: resolvePipe, priority: TPipePriority.RESOLVE }]; //#endregion //#region packages/moost/src/moost.ts function _define_property(obj, key, value) { if (key in obj) Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); else obj[key] = value; return obj; } var Moost = class Moost extends Hookable { _fireEventStart(source) { this.callHook("event-start", source); } _fireEventEnd(source) { this.callHook("event-end", source); } /** * ### getLogger * Provides application logger * ```js * // get logger with topic = "App" * const logger = app.getLogger('App') * logger.log('...') * ``` * @param topic * @returns */ getLogger(topic) { if (topic && this.logger instanceof ProstoLogger) return this.logger.createTopic(topic); return this.logger; } adapter(a) { this.adapters.push(a); return a; } getControllersOverview() { return this.controllersOverview; } /** * ### init * Ititializes adapter. Must be called after adapters are attached. */ async init() { this.setProvideRegistry(createProvideRegistry([Moost, () => this], [ProstoLogger, () => this.logger], ["MOOST_LOGGER", () => this.logger])); for (const a of this.adapters) { const constructor = getConstructor(a); if (constructor) this.setProvideRegistry(createProvideRegistry([constructor, () => a])); if (typeof a.getProvideRegistry === "function") this.setProvideRegistry(a.getProvideRegistry()); } this.unregisteredControllers.unshift(this); await this.bindControllers(); for (const a of this.adapters) await (a.onInit && a.onInit(this)); } async bindControllers() { const meta = getMoostMate(); const thisMeta = meta.read(this); const provide = { ...thisMeta?.provide, ...this.provide }; const replace = { ...thisMeta?.replace, ...this.replace }; for (const _controller of this.unregisteredControllers) { let newPrefix; let controller = _controller; if (Array.isArray(_controller) && typeof _controller[0] === "string") { newPrefix = _controller[0]; controller = _controller[1]; } await this.bindController(controller, provide, replace, this.options?.globalPrefix || "", newPrefix); } this.unregisteredControllers = []; } async bindController(controller, provide, replace, globalPrefix, replaceOwnPrefix) { const mate$1 = getMoostMate(); const classMeta = mate$1.read(controller); const infact$1 = getMoostInfact(); const isControllerConsructor = isConstructor(controller); const pipes = [...this.pipes, ...classMeta?.pipes || []].sort((a, b) => a.priority - b.priority); let instance; const infactOpts = { provide, replace, customData: { pipes } }; if (isControllerConsructor && (classMeta?.injectable === "SINGLETON" || classMeta?.injectable === true)) await createAsyncEventContext({ event: { type: "init" }, options: {} })(async () => { setControllerContext(this, "bindController", ""); instance = await infact$1.get(controller, infactOpts); }); else if (!isControllerConsructor) { instance = controller; infact$1.setInstanceRegistries(instance, provide, replace, { pipes }); } const getInstance = instance ? () => Promise.resolve(instance) : async () => await infact$1.get(controller, { ...infactOpts }); const classConstructor = isConstructor(controller) ? controller : getConstructor(controller); this.controllersOverview.push(await bindControllerMethods({ getInstance, classConstructor, adapters: this.adapters, globalPrefix, replaceOwnPrefix, interceptors: Array.from(this.interceptors), pipes, provide: classMeta?.provide, replace: classMeta?.replace, logger: this.logger, moostInstance: this })); if (classMeta?.importController) { const prefix = typeof replaceOwnPrefix === "string" ? replaceOwnPrefix : classMeta.controller?.prefix; const mergedProvide = { ...provide, ...classMeta.provide }; const mergedReplace = { ...this.replace, ...classMeta.replace }; for (const ic of classMeta.importController) if (ic.typeResolver) { const isConstr = isConstructor(ic.typeResolver); const isFunc = typeof ic.typeResolver === "function"; await this.bindController( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument isConstr ? ic.typeResolver : isFunc ? await ic.typeResolver() : ic.typeResolver, ic.provide ? { ...mergedProvide, ...ic.provide } : mergedProvide, mergedReplace, `${globalPrefix}/${prefix || ""}`, ic.prefix ); } } } applyGlobalPipes(...items) { for (const item of items) if (typeof item === "function") this.pipes.push({ handler: item, priority: typeof item.priority === "number" ? item.priority : TPipePriority.TRANSFORM }); else this.pipes.push({ handler: item.handler, priority: item.priority }); this.globalInterceptorHandler = undefined; return this; } /** * Provides InterceptorHandler with global interceptors and pipes. * Used to process interceptors when event handler was not found. * * @returns IterceptorHandler */ getGlobalInterceptorHandler() { if (!this.globalInterceptorHandler) { const mate$1 = getMoostMate(); const thisMeta = mate$1.read(this); const pipes = [...this.pipes || [], ...thisMeta?.pipes || []].sort((a, b) => a.priority - b.priority); const interceptors = [...this.interceptors, ...thisMeta?.interceptors || []].sort((a, b) => a.priority - b.priority); this.globalInterceptorHandler = getIterceptorHandlerFactory(interceptors, () => Promise.resolve(this), pipes, this.logger); } return this.globalInterceptorHandler(); } applyGlobalInterceptors(...items) { for (const item of items) if (typeof item === "function") this.interceptors.push({ handler: item, priority: typeof item.priority === "number" ? item.priority : TInterceptorPriority.INTERCEPTOR, name: item._name || item.name || "<anonymous>" }); else this.interceptors.push({ handler: item.handler, priority: item.priority, name: item.name || item.handler._name || item.handler.name || "<anonymous>" }); this.globalInterceptorHandler = undefined; return this; } /** * Register new entries to provide as dependency injections * @param provide - Provide Registry (use createProvideRegistry from '\@prostojs/infact') * @returns */ setProvideRegistry(provide) { this.provide = { ...this.provide, ...provide }; return this; } /** * Register replace classes to provide as dependency injections * @param replace - Replace Registry (use createReplaceRegistry from '\@prostojs/infact') * @returns */ setReplaceRegistry(replace) { this.replace = { ...this.replace, ...replace }; return this; } /** * Register controllers (similar to @ImportController decorator) * @param controllers - list of target controllers (instances) * @returns */ registerControllers(...controllers) { this.unregisteredControllers.push(...controllers); return this; } logMappedHandler(eventName, classConstructor, method, stroke, prefix) { const c = stroke ? "\x1B[9m" : ""; const coff = stroke ? "\x1B[29m" : ""; this.logger.info(`${prefix || ""}${c}${eventName} ${"\x1B[0m\x1B[2m\x1B[32m" + c}${classConstructor.name}.${"\x1B[36m" + c}${method}${"\x1B[32m"}()${coff}`); } constructor(options) { super(), _define_property(this, "options", void 0), _define_property(this, "logger", void 0), _define_property(this, "pipes", void 0), _define_property(this, "interceptors", void 0), _define_property(this, "adapters", void 0), _define_property(this, "controllersOverview", void 0), _define_property(this, "provide", void 0), _define_property(this, "replace", void 0), _define_property(this, "unregisteredControllers", void 0), _define_property(this, "globalInterceptorHandler", void 0), this.options = options, this.pipes = Array.from(sharedPipes), this.interceptors = [], this.adapters = [], this.controllersOverview = [], this.provide = createProvideRegistry([Infact, getMoostInfact], [Mate, getMoostMate]), this.replace = {}, this.unregisteredControllers = []; this.logger = options?.logger || getDefaultLogger(`${"\x1B[2m\x1B[35m"}moost`); setDefaultLogger(this.logger); const mate$1 = getMoostMate(); Object.assign(mate$1, { logger: this.getLogger("mate") }); } }; //#endregion export { Circular, Const, ConstFactory, ContextInjector, Controller, Description, EventLogger, Id, ImportController, Inherit, Inject, InjectEventLogger, InjectFromScope, InjectMoostLogger, InjectScopeVars, Injectable, Intercept, InterceptorHandler, Label, LoggerTopic, Moost, Optional, Param, Params, Pipe, ProstoLogger, Provide, Replace, Required, Resolve, TInterceptorPriority, TPipePriority, Value, clearGlobalWooks, createProvideRegistry, createReplaceRegistry, defineInfactScope, defineInterceptorFn, defineMoostEventHandler, definePipeFn, getConstructor, getContextInjector, getGlobalWooks, getInfactScopeVars, getInstanceOwnMethods, getInstanceOwnProps, getMoostInfact, getMoostMate, getNewMoostInfact, isConstructor, registerEventScope, replaceContextInjector, resolvePipe, setControllerContext, setInfactLoggingOptions, useAsyncEventContext, useControllerContext, useEventLogger };