UNPKG

@nestjs/core

Version:

Nest - modern, fast, powerful node.js web framework (@core)

170 lines (169 loc) 9.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const common_1 = require("@nestjs/common"); const constants_1 = require("@nestjs/common/constants"); const shared_utils_1 = require("@nestjs/common/utils/shared.utils"); const constants_2 = require("../guards/constants"); const guards_consumer_1 = require("../guards/guards-consumer"); const guards_context_creator_1 = require("../guards/guards-context-creator"); const interceptors_consumer_1 = require("../interceptors/interceptors-consumer"); const interceptors_context_creator_1 = require("../interceptors/interceptors-context-creator"); const pipes_consumer_1 = require("../pipes/pipes-consumer"); const pipes_context_creator_1 = require("../pipes/pipes-context-creator"); const external_exception_filter_context_1 = require("./../exceptions/external-exception-filter-context"); const constants_3 = require("./../injector/constants"); const context_utils_1 = require("./context-utils"); const external_proxy_1 = require("./external-proxy"); const handler_metadata_storage_1 = require("./handler-metadata-storage"); class ExternalContextCreator { constructor(guardsContextCreator, guardsConsumer, interceptorsContextCreator, interceptorsConsumer, modulesContainer, pipesContextCreator, pipesConsumer, filtersContextCreator) { this.guardsContextCreator = guardsContextCreator; this.guardsConsumer = guardsConsumer; this.interceptorsContextCreator = interceptorsContextCreator; this.interceptorsConsumer = interceptorsConsumer; this.modulesContainer = modulesContainer; this.pipesContextCreator = pipesContextCreator; this.pipesConsumer = pipesConsumer; this.filtersContextCreator = filtersContextCreator; this.contextUtils = new context_utils_1.ContextUtils(); this.externalErrorProxy = new external_proxy_1.ExternalErrorProxy(); this.handlerMetadataStorage = new handler_metadata_storage_1.HandlerMetadataStorage(); } static fromContainer(container) { const guardsContextCreator = new guards_context_creator_1.GuardsContextCreator(container, container.applicationConfig); const guardsConsumer = new guards_consumer_1.GuardsConsumer(); const interceptorsContextCreator = new interceptors_context_creator_1.InterceptorsContextCreator(container, container.applicationConfig); const interceptorsConsumer = new interceptors_consumer_1.InterceptorsConsumer(); const pipesContextCreator = new pipes_context_creator_1.PipesContextCreator(container, container.applicationConfig); const pipesConsumer = new pipes_consumer_1.PipesConsumer(); const filtersContextCreator = new external_exception_filter_context_1.ExternalExceptionFilterContext(container, container.applicationConfig); return new ExternalContextCreator(guardsContextCreator, guardsConsumer, interceptorsContextCreator, interceptorsConsumer, container.getModules(), pipesContextCreator, pipesConsumer, filtersContextCreator); } create(instance, callback, methodName, metadataKey, paramsFactory, contextId = constants_3.STATIC_CONTEXT, inquirerId, options = { interceptors: true, guards: true, filters: true, }) { const module = this.findContextModuleName(instance.constructor); const { argsLength, paramtypes, getParamsMetadata } = this.getMetadata(instance, methodName, metadataKey, paramsFactory); const pipes = this.pipesContextCreator.create(instance, callback, module, contextId, inquirerId); const guards = this.guardsContextCreator.create(instance, callback, module, contextId, inquirerId); const exceptionFilter = this.filtersContextCreator.create(instance, callback, module, contextId, inquirerId); const interceptors = options.interceptors ? this.interceptorsContextCreator.create(instance, callback, module, contextId, inquirerId) : []; const paramsMetadata = getParamsMetadata(module, contextId, inquirerId); const paramsOptions = paramsMetadata ? this.contextUtils.mergeParamsMetatypes(paramsMetadata, paramtypes) : []; const fnCanActivate = options.guards ? this.createGuardsFn(guards, instance, callback) : null; const fnApplyPipes = this.createPipesFn(pipes, paramsOptions); const handler = (initialArgs, ...args) => async () => { if (fnApplyPipes) { await fnApplyPipes(initialArgs, ...args); return callback.apply(instance, initialArgs); } return callback.apply(instance, args); }; const target = async (...args) => { const initialArgs = this.contextUtils.createNullArray(argsLength); fnCanActivate && (await fnCanActivate(args)); const result = await this.interceptorsConsumer.intercept(interceptors, args, instance, callback, handler(initialArgs, ...args)); return this.transformToResult(result); }; return options.filters ? this.externalErrorProxy.createProxy(target, exceptionFilter) : target; } getMetadata(instance, methodName, metadataKey, paramsFactory) { const cacheMetadata = this.handlerMetadataStorage.get(instance, methodName); if (cacheMetadata) { return cacheMetadata; } const metadata = this.contextUtils.reflectCallbackMetadata(instance, methodName, metadataKey || '') || {}; const keys = Object.keys(metadata); const argsLength = this.contextUtils.getArgumentsLength(keys, metadata); const paramtypes = this.contextUtils.reflectCallbackParamtypes(instance, methodName); const getParamsMetadata = (moduleKey, contextId = constants_3.STATIC_CONTEXT, inquirerId) => paramsFactory ? this.exchangeKeysForValues(keys, metadata, moduleKey, paramsFactory, contextId, inquirerId) : null; const handlerMetadata = { argsLength, paramtypes, getParamsMetadata, }; this.handlerMetadataStorage.set(instance, methodName, handlerMetadata); return handlerMetadata; } findContextModuleName(constructor) { const className = constructor.name; if (!className) { return ''; } for (const [key, module] of [...this.modulesContainer.entries()]) { if (this.findProviderByClassName(module, className)) { return key; } } return ''; } findProviderByClassName(module, className) { const { providers } = module; const hasProvider = [...providers.keys()].some(provider => provider === className); return hasProvider; } exchangeKeysForValues(keys, metadata, moduleContext, paramsFactory, contextId = constants_3.STATIC_CONTEXT, inquirerId) { this.pipesContextCreator.setModuleContext(moduleContext); return keys.map(key => { const { index, data, pipes: pipesCollection } = metadata[key]; const pipes = this.pipesContextCreator.createConcreteContext(pipesCollection, contextId, inquirerId); const type = this.contextUtils.mapParamType(key); if (key.includes(constants_1.CUSTOM_ROUTE_AGRS_METADATA)) { const { factory } = metadata[key]; const customExtractValue = this.getCustomFactory(factory, data); return { index, extractValue: customExtractValue, type, data, pipes }; } const numericType = Number(type); const extractValue = (...args) => paramsFactory.exchangeKeyForValue(numericType, data, args); return { index, extractValue, type: numericType, data, pipes }; }); } getCustomFactory(factory, data) { return shared_utils_1.isFunction(factory) ? (...args) => factory(data, args) : () => null; } createPipesFn(pipes, paramsOptions) { const pipesFn = async (args, ...params) => { await Promise.all(paramsOptions.map(async (param) => { const { index, extractValue, type, data, metatype, pipes: paramPipes, } = param; const value = extractValue(...params); args[index] = await this.getParamValue(value, { metatype, type, data }, pipes.concat(paramPipes)); })); }; return paramsOptions.length ? pipesFn : null; } async getParamValue(value, { metatype, type, data }, pipes) { return shared_utils_1.isEmpty(pipes) ? value : this.pipesConsumer.apply(value, { metatype, type, data }, pipes); } async transformToResult(resultOrDeffered) { if (resultOrDeffered && shared_utils_1.isFunction(resultOrDeffered.subscribe)) { return resultOrDeffered.toPromise(); } return resultOrDeffered; } createGuardsFn(guards, instance, callback) { const canActivateFn = async (args) => { const canActivate = await this.guardsConsumer.tryActivate(guards, args, instance, callback); if (!canActivate) { throw new common_1.ForbiddenException(constants_2.FORBIDDEN_MESSAGE); } }; return guards.length ? canActivateFn : null; } } exports.ExternalContextCreator = ExternalContextCreator;