@gabliam/web-core
Version:
Gabliam plugin for add web-core
139 lines (138 loc) • 6.39 kB
JavaScript
;
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;