import { Logger, type LoggerService } from '@nestjs/common'; import { MODULE_INIT_MESSAGE } from '../helpers/messages.js'; import { GraphInspector } from '../inspector/graph-inspector.js'; import { NestContainer } from './container.js'; import { Injector } from './injector.js'; import { InternalCoreModule } from './internal-core-module/internal-core-module.js'; import { Module } from './module.js'; import type { Controller, Injectable } from '@nestjs/common/internal'; export class InstanceLoader { constructor( protected readonly container: NestContainer, protected readonly injector: TInjector, protected readonly graphInspector: GraphInspector, private logger: LoggerService = new Logger(InstanceLoader.name, { timestamp: true, }), ) {} public setLogger(logger: Logger) { this.logger = logger; } public async createInstancesOfDependencies( modules: Map = this.container.getModules(), ) { this.createPrototypes(modules); try { await this.createInstances(modules); } catch (err) { this.graphInspector.inspectModules(modules); this.graphInspector.registerPartial(err); throw err; } this.graphInspector.inspectModules(modules); } private createPrototypes(modules: Map) { modules.forEach(moduleRef => { this.createPrototypesOfProviders(moduleRef); this.createPrototypesOfInjectables(moduleRef); this.createPrototypesOfControllers(moduleRef); }); } private async createInstances(modules: Map) { await Promise.all( [...modules.values()].map(async moduleRef => { await this.createInstancesOfProviders(moduleRef); await this.createInstancesOfInjectables(moduleRef); await this.createInstancesOfControllers(moduleRef); const { name } = moduleRef; this.isModuleWhitelisted(name) && this.logger.log(MODULE_INIT_MESSAGE`${name}`); }), ); } private createPrototypesOfProviders(moduleRef: Module) { const { providers } = moduleRef; providers.forEach(wrapper => this.injector.loadPrototype(wrapper, providers), ); } private async createInstancesOfProviders(moduleRef: Module) { const { providers } = moduleRef; const wrappers = [...providers.values()]; await Promise.all( wrappers.map(async item => { await this.injector.loadProvider(item, moduleRef); this.graphInspector.inspectInstanceWrapper(item, moduleRef); }), ); } private createPrototypesOfControllers(moduleRef: Module) { const { controllers } = moduleRef; controllers.forEach(wrapper => this.injector.loadPrototype(wrapper, controllers), ); } private async createInstancesOfControllers(moduleRef: Module) { const { controllers } = moduleRef; const wrappers = [...controllers.values()]; await Promise.all( wrappers.map(async item => { await this.injector.loadController(item, moduleRef); this.graphInspector.inspectInstanceWrapper(item, moduleRef); }), ); } private createPrototypesOfInjectables(moduleRef: Module) { const { injectables } = moduleRef; injectables.forEach(wrapper => this.injector.loadPrototype(wrapper, injectables), ); } private async createInstancesOfInjectables(moduleRef: Module) { const { injectables } = moduleRef; const wrappers = [...injectables.values()]; await Promise.all( wrappers.map(async item => { await this.injector.loadInjectable(item, moduleRef); this.graphInspector.inspectInstanceWrapper(item, moduleRef); }), ); } private isModuleWhitelisted(name: string): boolean { return name !== InternalCoreModule.name; } }