mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
174 lines
7.5 KiB
JavaScript
174 lines
7.5 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const constants_1 = require("@nestjs/common/constants");
|
|
const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
|
|
require("reflect-metadata");
|
|
const runtime_exception_1 = require("../errors/exceptions/runtime.exception");
|
|
const unknown_dependencies_exception_1 = require("../errors/exceptions/unknown-dependencies.exception");
|
|
const undefined_dependency_exception_1 = require("./../errors/exceptions/undefined-dependency.exception");
|
|
class Injector {
|
|
async loadInstanceOfMiddleware(wrapper, collection, module) {
|
|
const { metatype } = wrapper;
|
|
const currentMetatype = collection.get(metatype.name);
|
|
if (currentMetatype.instance !== null)
|
|
return;
|
|
await this.resolveConstructorParams(wrapper, module, null, instances => {
|
|
collection.set(metatype.name, {
|
|
instance: new metatype(...instances),
|
|
metatype,
|
|
});
|
|
});
|
|
}
|
|
async loadInstanceOfRoute(wrapper, module) {
|
|
const routes = module.routes;
|
|
await this.loadInstance(wrapper, routes, module);
|
|
}
|
|
async loadInstanceOfInjectable(wrapper, module) {
|
|
const injectables = module.injectables;
|
|
await this.loadInstance(wrapper, injectables, module);
|
|
}
|
|
loadPrototypeOfInstance({ metatype, name }, collection) {
|
|
if (!collection)
|
|
return null;
|
|
const target = collection.get(name);
|
|
if (target.isResolved || !shared_utils_1.isNil(target.inject) || !metatype.prototype)
|
|
return null;
|
|
collection.set(name, Object.assign({}, collection.get(name), { instance: Object.create(metatype.prototype) }));
|
|
}
|
|
async loadInstanceOfComponent(wrapper, module) {
|
|
const components = module.components;
|
|
await this.loadInstance(wrapper, components, module);
|
|
}
|
|
applyDoneSubject(wrapper) {
|
|
let done;
|
|
wrapper.done$ = new Promise((resolve, reject) => {
|
|
done = resolve;
|
|
});
|
|
wrapper.isPending = true;
|
|
return done;
|
|
}
|
|
async loadInstance(wrapper, collection, module) {
|
|
if (wrapper.isPending) {
|
|
return await wrapper.done$;
|
|
}
|
|
const done = this.applyDoneSubject(wrapper);
|
|
const { metatype, name, inject } = wrapper;
|
|
const currentMetatype = collection.get(name);
|
|
if (shared_utils_1.isUndefined(currentMetatype)) {
|
|
throw new runtime_exception_1.RuntimeException();
|
|
}
|
|
if (currentMetatype.isResolved)
|
|
return null;
|
|
await this.resolveConstructorParams(wrapper, module, inject, async (instances) => {
|
|
if (shared_utils_1.isNil(inject)) {
|
|
currentMetatype.instance = Object.assign(currentMetatype.instance, new metatype(...instances));
|
|
}
|
|
else {
|
|
const factoryResult = currentMetatype.metatype(...instances);
|
|
currentMetatype.instance = await this.resolveFactoryInstance(factoryResult);
|
|
}
|
|
currentMetatype.isResolved = true;
|
|
done();
|
|
});
|
|
}
|
|
async resolveConstructorParams(wrapper, module, inject, callback) {
|
|
let isResolved = true;
|
|
const dependencies = shared_utils_1.isNil(inject)
|
|
? this.reflectConstructorParams(wrapper.metatype)
|
|
: inject;
|
|
const instances = await Promise.all(dependencies.map(async (param, index) => {
|
|
const paramWrapper = await this.resolveSingleParam(wrapper, param, { index, dependencies }, module);
|
|
if (!paramWrapper.isResolved && !paramWrapper.forwardRef) {
|
|
isResolved = false;
|
|
}
|
|
return paramWrapper.instance;
|
|
}));
|
|
isResolved && (await callback(instances));
|
|
}
|
|
reflectConstructorParams(type) {
|
|
const paramtypes = Reflect.getMetadata(constants_1.PARAMTYPES_METADATA, type) || [];
|
|
const selfParams = this.reflectSelfParams(type);
|
|
selfParams.forEach(({ index, param }) => (paramtypes[index] = param));
|
|
return paramtypes;
|
|
}
|
|
reflectSelfParams(type) {
|
|
return Reflect.getMetadata(constants_1.SELF_DECLARED_DEPS_METADATA, type) || [];
|
|
}
|
|
async resolveSingleParam(wrapper, param, dependencyContext, module) {
|
|
if (shared_utils_1.isUndefined(param)) {
|
|
throw new undefined_dependency_exception_1.UndefinedDependencyException(wrapper.name, dependencyContext);
|
|
}
|
|
const token = this.resolveParamToken(wrapper, param);
|
|
return await this.resolveComponentInstance(module, shared_utils_1.isFunction(token) ? token.name : token, dependencyContext, wrapper);
|
|
}
|
|
resolveParamToken(wrapper, param) {
|
|
if (!param.forwardRef) {
|
|
return param;
|
|
}
|
|
wrapper.forwardRef = true;
|
|
return param.forwardRef();
|
|
}
|
|
async resolveComponentInstance(module, name, dependencyContext, wrapper) {
|
|
const components = module.components;
|
|
const instanceWrapper = await this.lookupComponent(components, module, Object.assign({ name }, dependencyContext), wrapper);
|
|
if (!instanceWrapper.isResolved && !instanceWrapper.forwardRef) {
|
|
await this.loadInstanceOfComponent(instanceWrapper, module);
|
|
}
|
|
if (instanceWrapper.async) {
|
|
instanceWrapper.instance = await instanceWrapper.instance;
|
|
}
|
|
return instanceWrapper;
|
|
}
|
|
async lookupComponent(components, module, dependencyContext, wrapper) {
|
|
const { name } = dependencyContext;
|
|
const scanInExports = () => this.lookupComponentInExports(components, dependencyContext, module, wrapper);
|
|
return components.has(name) ? components.get(name) : await scanInExports();
|
|
}
|
|
async lookupComponentInExports(components, dependencyContext, module, wrapper) {
|
|
const instanceWrapper = await this.lookupComponentInRelatedModules(module, dependencyContext.name);
|
|
if (shared_utils_1.isNil(instanceWrapper)) {
|
|
throw new unknown_dependencies_exception_1.UnknownDependenciesException(wrapper.name, dependencyContext);
|
|
}
|
|
return instanceWrapper;
|
|
}
|
|
async lookupComponentInRelatedModules(module, name) {
|
|
let component = null;
|
|
const relatedModules = module.relatedModules || [];
|
|
for (const relatedModule of this.flatMap([...relatedModules.values()])) {
|
|
const { components, exports } = relatedModule;
|
|
if (!exports.has(name) || !components.has(name)) {
|
|
continue;
|
|
}
|
|
component = components.get(name);
|
|
if (!component.isResolved && !component.forwardRef) {
|
|
await this.loadInstanceOfComponent(component, relatedModule);
|
|
break;
|
|
}
|
|
}
|
|
return component;
|
|
}
|
|
async resolveFactoryInstance(factoryResult) {
|
|
if (!(factoryResult instanceof Promise)) {
|
|
return factoryResult;
|
|
}
|
|
const result = await factoryResult;
|
|
return result;
|
|
}
|
|
flatMap(modules) {
|
|
if (!modules) {
|
|
return [];
|
|
}
|
|
const flatten = (module) => {
|
|
const { relatedModules, exports } = module;
|
|
return this.flatMap([...relatedModules.values()]
|
|
.filter(related => related)
|
|
.filter(related => {
|
|
const { metatype } = related;
|
|
return exports.has(metatype.name);
|
|
}));
|
|
};
|
|
return modules.concat.apply(modules, modules.map(flatten));
|
|
}
|
|
}
|
|
exports.Injector = Injector;
|