@nestjs/core
Version:
Nest - modern, fast, powerful node.js web framework (@core)
140 lines (139 loc) • 8.11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("@nestjs/common/constants");
const logger_service_1 = require("@nestjs/common/services/logger.service");
const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
const unknown_request_mapping_exception_1 = require("../errors/exceptions/unknown-request-mapping.exception");
const guards_consumer_1 = require("../guards/guards-consumer");
const guards_context_creator_1 = require("../guards/guards-context-creator");
const context_id_factory_1 = require("../helpers/context-id-factory");
const execution_context_host_1 = require("../helpers/execution-context-host");
const messages_1 = require("../helpers/messages");
const router_method_factory_1 = require("../helpers/router-method-factory");
const constants_2 = require("../injector/constants");
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 request_1 = require("./request");
const request_constants_1 = require("./request/request-constants");
const route_params_factory_1 = require("./route-params-factory");
const router_execution_context_1 = require("./router-execution-context");
class RouterExplorer {
constructor(metadataScanner, container, injector, routerProxy, exceptionsFilter, config) {
this.metadataScanner = metadataScanner;
this.container = container;
this.injector = injector;
this.routerProxy = routerProxy;
this.exceptionsFilter = exceptionsFilter;
this.routerMethodFactory = new router_method_factory_1.RouterMethodFactory();
this.logger = new logger_service_1.Logger(RouterExplorer.name, true);
this.exceptionFiltersCache = new WeakMap();
this.executionContextCreator = new router_execution_context_1.RouterExecutionContext(new route_params_factory_1.RouteParamsFactory(), new pipes_context_creator_1.PipesContextCreator(container, config), new pipes_consumer_1.PipesConsumer(), new guards_context_creator_1.GuardsContextCreator(container, config), new guards_consumer_1.GuardsConsumer(), new interceptors_context_creator_1.InterceptorsContextCreator(container, config), new interceptors_consumer_1.InterceptorsConsumer(), container.getHttpAdapterRef());
}
explore(instanceWrapper, module, applicationRef, basePath) {
const { instance } = instanceWrapper;
const routerPaths = this.scanForPaths(instance);
this.applyPathsToRouterProxy(applicationRef, routerPaths, instanceWrapper, module, basePath);
}
extractRouterPath(metatype, prefix) {
let path = Reflect.getMetadata(constants_1.PATH_METADATA, metatype);
if (prefix)
path = prefix + this.validateRoutePath(path);
return this.validateRoutePath(path);
}
validateRoutePath(path) {
if (shared_utils_1.isUndefined(path)) {
throw new unknown_request_mapping_exception_1.UnknownRequestMappingException();
}
return shared_utils_1.validatePath(path);
}
scanForPaths(instance, prototype) {
const instancePrototype = shared_utils_1.isUndefined(prototype)
? Object.getPrototypeOf(instance)
: prototype;
return this.metadataScanner.scanFromPrototype(instance, instancePrototype, method => this.exploreMethodMetadata(instance, instancePrototype, method));
}
exploreMethodMetadata(instance, instancePrototype, methodName) {
const targetCallback = instancePrototype[methodName];
const routePath = Reflect.getMetadata(constants_1.PATH_METADATA, targetCallback);
if (shared_utils_1.isUndefined(routePath)) {
return null;
}
const requestMethod = Reflect.getMetadata(constants_1.METHOD_METADATA, targetCallback);
const path = shared_utils_1.isString(routePath)
? [this.validateRoutePath(routePath)]
: routePath.map(p => this.validateRoutePath(p));
return {
path,
requestMethod,
targetCallback,
methodName,
};
}
applyPathsToRouterProxy(router, routePaths, instanceWrapper, module, basePath) {
(routePaths || []).forEach(pathProperties => {
const { path, requestMethod } = pathProperties;
this.applyCallbackToRouter(router, pathProperties, instanceWrapper, module, basePath);
path.forEach(p => this.logger.log(messages_1.ROUTE_MAPPED_MESSAGE(p, requestMethod)));
});
}
applyCallbackToRouter(router, pathProperties, instanceWrapper, moduleKey, basePath) {
const { path: paths, requestMethod, targetCallback, methodName, } = pathProperties;
const { instance } = instanceWrapper;
const routerMethod = this.routerMethodFactory
.get(router, requestMethod)
.bind(router);
const stripSlash = (str) => str[str.length - 1] === '/' ? str.slice(0, str.length - 1) : str;
const isRequestScoped = !instanceWrapper.isDependencyTreeStatic();
const module = this.container.getModuleByKey(moduleKey);
if (isRequestScoped) {
const handler = this.createRequestScopedHandler(instanceWrapper, requestMethod, module, moduleKey, methodName);
paths.forEach(path => {
const fullPath = stripSlash(basePath) + path;
routerMethod(stripSlash(fullPath) || '/', handler);
});
return;
}
const proxy = this.createCallbackProxy(instance, targetCallback, methodName, moduleKey, requestMethod);
paths.forEach(path => {
const fullPath = stripSlash(basePath) + path;
routerMethod(stripSlash(fullPath) || '/', proxy);
});
}
createCallbackProxy(instance, callback, methodName, module, requestMethod, contextId = constants_2.STATIC_CONTEXT, inquirerId) {
const executionContext = this.executionContextCreator.create(instance, callback, methodName, module, requestMethod, contextId, inquirerId);
const exceptionFilter = this.exceptionsFilter.create(instance, callback, module, contextId, inquirerId);
return this.routerProxy.createProxy(executionContext, exceptionFilter);
}
createRequestScopedHandler(instanceWrapper, requestMethod, module, moduleKey, methodName) {
const { instance } = instanceWrapper;
const collection = module.controllers;
return async (req, res, next) => {
try {
const contextId = req[request_constants_1.REQUEST_CONTEXT_ID] || context_id_factory_1.createContextId();
this.registerRequestProvider(req, contextId);
const contextInstance = await this.injector.loadPerContext(instance, module, collection, contextId);
this.createCallbackProxy(contextInstance, contextInstance[methodName], methodName, moduleKey, requestMethod, contextId, instanceWrapper.id)(req, res, next);
}
catch (err) {
let exceptionFilter = this.exceptionFiltersCache.get(instance[methodName]);
if (!exceptionFilter) {
exceptionFilter = this.exceptionsFilter.create(instance, instance[methodName], moduleKey);
this.exceptionFiltersCache.set(instance[methodName], exceptionFilter);
}
const host = new execution_context_host_1.ExecutionContextHost([req, res, next]);
exceptionFilter.next(err, host);
}
};
}
registerRequestProvider(request, contextId) {
const coreModuleRef = this.container.getInternalCoreModuleRef();
const wrapper = coreModuleRef.getProviderByKey(request_1.REQUEST);
wrapper.setInstanceByContextId(contextId, {
instance: request,
isResolved: true,
});
}
}
exports.RouterExplorer = RouterExplorer;