UNPKG

@gabliam/web-core

Version:
139 lines (138 loc) 6.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.compose = exports.setContext = exports.getContext = exports.extractControllerMetadata = exports.getExtractArgs = exports.cleanPath = void 0; const core_1 = require("@gabliam/core"); const constants_1 = require("./constants"); const errors_1 = require("./errors"); const interceptors_1 = require("./interceptors"); const metadatas_1 = require("./metadatas"); const pipe_1 = require("./pipe"); const cleanPath = (path) => path.replace(/\/+/gi, '/'); exports.cleanPath = cleanPath; const getExtractArgs = (container, controller, propKey, isInterceptor) => { const params = core_1.reflection.parameters(controller.constructor, propKey); if (params.length === 0) { return (ctx, execCtx, next) => Promise.resolve([ctx.request, ctx.response, next]); } const parameters = (params.map((meta, index) => { let type; if (meta.length >= 2) { type = meta[0]; } const pipe = (0, pipe_1.extractPipes)(container, controller, propKey, index, !isInterceptor); const webParamDecorator = meta .slice(-1) .filter((m) => typeof m.handler === 'function' && m.args)[0]; // if there is no webParamDecorator => error if (webParamDecorator === undefined) { throw new Error('No webParamDecorator exist'); } return [type, webParamDecorator, pipe]; })); return async (ctx, execCtx, next) => { const extractedParams = await Promise.all(parameters.map(([type, decorator, pipe]) => pipe(decorator.handler(decorator.args, ctx, type, execCtx, next), type))); return extractedParams; }; }; exports.getExtractArgs = getExtractArgs; /** * Build all controllers * * @param {Container} container * @param {Registry} registry */ const extractControllerMetadata = (container, registry) => { const restConfig = container.get(constants_1.WEB_PLUGIN_CONFIG); const valueExtractor = container.get(core_1.VALUE_EXTRACTOR); const controllerIds = registry.get(constants_1.TYPE.Controller); const restMetadata = Object.assign(Object.assign({}, restConfig), { controllerInfo: new Map() }); controllerIds.forEach(({ id: controllerId }) => { const controller = container.get(controllerId); const [controllerMetadata,] = core_1.reflection .annotationsOfDecorator(controller.constructor, constants_1.METADATA_KEY.controller) .slice(-1); const controllerInterceptors = (0, interceptors_1.extractInterceptors)(container, controller.constructor); const methodMetadatas = core_1.reflection.propMetadataOfDecorator(controller.constructor, constants_1.METADATA_KEY.controllerMethod); // if the controller has controllerMetadata and methodMetadatas if (controllerMetadata && methodMetadatas) { const controllerPath = valueExtractor(controllerMetadata.path, controllerMetadata.path); const methods = []; restMetadata.controllerInfo.set(controllerId, { controllerPath, methods, }); for (const [methodName, metas] of Object.entries(methodMetadatas)) { const [methodMetadata] = metas.slice(-1); let methodPath = (0, exports.cleanPath)(valueExtractor(methodMetadata.path, methodMetadata.path)); if (methodPath[0] !== '/') { methodPath = `/${methodPath}`; } const methodInterceptors = (0, interceptors_1.extractInterceptors)(container, controller.constructor, methodName); const globalInterceptors = (0, interceptors_1.getGlobalInterceptors)(container); const methodJson = core_1.reflection.propMetadataOfDecorator(controller.constructor, metadatas_1.ResponseBody)[methodName] !== undefined ? true : undefined; const interceptors = [ ...globalInterceptors, ...controllerInterceptors, ...methodInterceptors, ]; // if method is true or controller is true and method undefined const json = methodJson || (controllerMetadata.json && methodJson === undefined); methods.push({ controllerId, methodName, json, extractArgs: (0, exports.getExtractArgs)(container, controller, methodName, false), methodPath, method: methodMetadata.method, interceptors, }); } } }); return restMetadata; }; exports.extractControllerMetadata = extractControllerMetadata; const getContext = (req) => req[constants_1.CONTEXT]; exports.getContext = getContext; const setContext = (req, context) => { req[constants_1.CONTEXT] = context; }; exports.setContext = setContext; function compose(interceptors, converterValue) { return async function composed(ctx, execCtx, next) { let index = -1; async function dispatch(i) { if (i <= index) { throw new errors_1.NextCalledMulipleError(); } index = i; const interceptor = interceptors[i]; if (i === interceptors.length) { const nextRes = converterValue(ctx, execCtx, await next()); return Promise.resolve(nextRes); } if (!interceptor) { return Promise.resolve(); } const { instance, extractArgs } = interceptor; const callNext = dispatch.bind(null, i + 1); let wasCalled = false; const nextFn = async () => { wasCalled = true; await callNext(); }; const interceptorArgs = await (0, core_1.toPromise)(extractArgs(ctx, execCtx, nextFn)); const res = await (0, core_1.toPromise)(instance.intercept(...interceptorArgs)); converterValue(ctx, execCtx, res); // call next if interceptor not use next if (!wasCalled) { await callNext(); } return Promise.resolve(); } return dispatch(0); }; } exports.compose = compose;