@nestjs/core
Version:
Nest - modern, fast, powerful node.js web framework (@core)
233 lines (232 loc) • 11 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
const unknown_dependencies_exception_1 = require("../errors/exceptions/unknown-dependencies.exception");
const runtime_exception_1 = require("../errors/exceptions/runtime.exception");
const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
const constants_1 = require("@nestjs/common/constants");
const undefined_dependency_exception_1 = require("./../errors/exceptions/undefined-dependency.exception");
class Injector {
loadInstanceOfMiddleware(wrapper, collection, module) {
return __awaiter(this, void 0, void 0, function* () {
const { metatype } = wrapper;
const currentMetatype = collection.get(metatype.name);
if (currentMetatype.instance !== null)
return;
yield this.resolveConstructorParams(wrapper, module, null, null, instances => {
collection.set(metatype.name, {
instance: new metatype(...instances),
metatype,
});
});
});
}
loadInstanceOfRoute(wrapper, module) {
return __awaiter(this, void 0, void 0, function* () {
const routes = module.routes;
yield this.loadInstance(wrapper, routes, module);
});
}
loadInstanceOfInjectable(wrapper, module) {
return __awaiter(this, void 0, void 0, function* () {
const injectables = module.injectables;
yield 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))
return null;
collection.set(name, Object.assign({}, collection.get(name), { instance: Object.create(metatype.prototype) }));
}
loadInstanceOfComponent(wrapper, module, context = []) {
return __awaiter(this, void 0, void 0, function* () {
const components = module.components;
yield this.loadInstance(wrapper, components, module, context);
});
}
applyDoneSubject(wrapper) {
let done;
wrapper.done$ = new Promise((resolve, reject) => {
done = resolve;
});
wrapper.isPending = true;
return done;
}
loadInstance(wrapper, collection, module, context = []) {
return __awaiter(this, void 0, void 0, function* () {
if (wrapper.isPending) {
return yield 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;
yield this.resolveConstructorParams(wrapper, module, inject, context, (instances) => __awaiter(this, void 0, void 0, function* () {
if (shared_utils_1.isNil(inject)) {
currentMetatype.instance = Object.assign(currentMetatype.instance, new metatype(...instances));
}
else {
const factoryResult = currentMetatype.metatype(...instances);
currentMetatype.instance = yield this.resolveFactoryInstance(factoryResult);
}
currentMetatype.isResolved = true;
done();
}));
});
}
resolveConstructorParams(wrapper, module, inject, context, callback) {
return __awaiter(this, void 0, void 0, function* () {
let isResolved = true;
const args = shared_utils_1.isNil(inject)
? this.reflectConstructorParams(wrapper.metatype)
: inject;
const instances = yield Promise.all(args.map((param, index) => __awaiter(this, void 0, void 0, function* () {
const paramWrapper = yield this.resolveSingleParam(wrapper, param, { index, length: args.length }, module, context);
if (!paramWrapper.isResolved && !paramWrapper.forwardRef) {
isResolved = false;
}
return paramWrapper.instance;
})));
isResolved && (yield 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) || [];
}
resolveSingleParam(wrapper, param, { index, length }, module, context) {
return __awaiter(this, void 0, void 0, function* () {
if (shared_utils_1.isUndefined(param)) {
throw new undefined_dependency_exception_1.UndefinedDependencyException(wrapper.name, index, length);
}
const token = this.resolveParamToken(wrapper, param);
return yield this.resolveComponentInstance(module, shared_utils_1.isFunction(token) ? token.name : token, { index, length }, wrapper, context);
});
}
resolveParamToken(wrapper, param) {
if (!param.forwardRef) {
return param;
}
wrapper.forwardRef = true;
return param.forwardRef();
}
resolveComponentInstance(module, name, { index, length }, wrapper, context) {
return __awaiter(this, void 0, void 0, function* () {
const components = module.components;
const instanceWrapper = yield this.scanForComponent(components, module, { name, index, length }, wrapper, context);
if (!instanceWrapper.isResolved && !instanceWrapper.forwardRef) {
yield this.loadInstanceOfComponent(instanceWrapper, module);
}
if (instanceWrapper.async) {
instanceWrapper.instance = yield instanceWrapper.instance;
}
return instanceWrapper;
});
}
scanForComponent(components, module, { name, index, length }, { metatype }, context = []) {
return __awaiter(this, void 0, void 0, function* () {
const component = yield this.scanForComponentInScopes(context, { name, index, length }, metatype);
if (component) {
return component;
}
const scanInExports = () => this.scanForComponentInExports(components, { name, index, length }, module, metatype, context);
return components.has(name) ? components.get(name) : yield scanInExports();
});
}
scanForComponentInExports(components, { name, index, length }, module, metatype, context = []) {
return __awaiter(this, void 0, void 0, function* () {
const instanceWrapper = yield this.scanForComponentInRelatedModules(module, name, context);
if (shared_utils_1.isNil(instanceWrapper)) {
throw new unknown_dependencies_exception_1.UnknownDependenciesException(metatype.name, index, length);
}
return instanceWrapper;
});
}
scanForComponentInScopes(context, { name, index, length }, metatype) {
return __awaiter(this, void 0, void 0, function* () {
context = context || [];
for (const ctx of context) {
const component = yield this.scanForComponentInScope(ctx, { name, index, length }, metatype);
if (component)
return component;
}
return null;
});
}
scanForComponentInScope(context, { name, index, length }, metatype) {
return __awaiter(this, void 0, void 0, function* () {
try {
const component = yield this.scanForComponent(context.components, context, { name, index, length }, { metatype }, null);
if (!component.isResolved && !component.forwardRef) {
yield this.loadInstanceOfComponent(component, context);
}
return component;
}
catch (e) {
if (e instanceof undefined_dependency_exception_1.UndefinedDependencyException) {
throw e;
}
return null;
}
});
}
scanForComponentInRelatedModules(module, name, context) {
return __awaiter(this, void 0, void 0, function* () {
let component = null;
const relatedModules = module.relatedModules || [];
for (const relatedModule of this.flatMap([...relatedModules.values()])) {
const { components, exports } = relatedModule;
const isInScope = context === null;
if ((!exports.has(name) && !isInScope) || !components.has(name)) {
continue;
}
component = components.get(name);
if (!component.isResolved && !component.forwardRef) {
const ctx = isInScope ? [module] : [].concat(context, module);
yield this.loadInstanceOfComponent(component, relatedModule, ctx);
break;
}
}
return component;
});
}
resolveFactoryInstance(factoryResult) {
return __awaiter(this, void 0, void 0, function* () {
if (!(factoryResult instanceof Promise)) {
return factoryResult;
}
const result = yield factoryResult;
return result;
});
}
flatMap(modules) {
return modules.concat.apply(modules, modules.map((module) => {
const { relatedModules, exports } = module;
return this.flatMap([...relatedModules.values()].filter(related => {
const { metatype } = related;
return exports.has(metatype.name);
}));
}));
}
}
exports.Injector = Injector;