import type { InjectionToken, Provider } from '@nestjs/common'; import type { Promisable } from 'type-fest'; import { Assert } from './assert'; import { NestDefinitionType } from './constants'; import { FalsyValueInNestModuleTree, UnexpectedNestModuleDefinitionValue, } from './exception'; import type { NestModuleDefinition } from './nest-definition'; import { NestDefinition } from './nest-definition'; export class NestDefinitionIterator { constructor(private nestModuleDefinition: Promisable) {} /** * By default dont iterate by exports * @param type */ async *iterate( type?: NestDefinitionType, ): AsyncIterableIterator { const iterateAll = type === undefined; const iterateByModule = iterateAll || type & NestDefinitionType.Module; const awaitedNestModuleDefinition = await this.nestModuleDefinition; if (!awaitedNestModuleDefinition) { throw new FalsyValueInNestModuleTree(awaitedNestModuleDefinition); } if (iterateByModule) { yield awaitedNestModuleDefinition; if ('module' in awaitedNestModuleDefinition) { yield awaitedNestModuleDefinition.module; } } const nestDefinition = new NestDefinition(awaitedNestModuleDefinition); const nestImports = nestDefinition.getImports(); const iterateProviders = iterateAll || type & NestDefinitionType.Providers; if (iterateProviders) { const providers = nestDefinition.getProviders(); for (const provider of providers ?? []) { yield provider; } } const iterateExports = type !== undefined && type & NestDefinitionType.Exports; if (iterateExports) { const exports = nestDefinition.getExports(); for (const nestExport of exports ?? []) { yield nestExport; } } const iterateControllers = iterateAll || type & NestDefinitionType.Controllers; if (iterateControllers) { const controllers = nestDefinition.getControllers(); for (const controller of controllers ?? []) { yield controller; } } for (const nestImport of nestImports ?? []) { yield* new NestDefinitionIterator(nestImport).iterate(type); } } async find( predicate: ( // eslint-disable-next-line @typescript-eslint/ban-types definition: NestModuleDefinition | Provider | Function, ) => boolean, type?: NestDefinitionType, ): Promise { for await (const definition of this.iterate(type)) { if (!Assert.isObjectOrCtor(definition)) { throw new UnexpectedNestModuleDefinitionValue(definition); } const isNeeded = predicate(definition); if (isNeeded) { return definition as R; } } return null; } }