import type { Abstract, ClassProvider, DynamicModule, ExistingProvider, FactoryProvider, InjectionToken, OptionalFactoryDependency, Provider, Type, ValueProvider, } from '@nestjs/common'; import { MODULE_METADATA } from '@nestjs/common/constants'; import { DependenciesScanner } from '@nestjs/core/scanner'; import { Assert } from './assert'; export type NestModuleDefinition = DynamicModule | Type; /** * Хелпер для работы с объявлением модуля nest. * Получения провайдеров и импортов */ export class NestDefinition { constructor(private definition: NestModuleDefinition) {} static extractDeps( value: | DynamicModule | ClassProvider | ValueProvider | FactoryProvider | ExistingProvider | Type | Abstract // eslint-disable-next-line @typescript-eslint/ban-types | Function, ): (InjectionToken | OptionalFactoryDependency)[] { const designParamTypes = Reflect.getMetadata('design:paramtypes', value); if (designParamTypes) { return designParamTypes; } if (this.hasInjectDeps(value)) { return this.extractInjectDeps(value); } return []; } static extractInjectDeps( value: | DynamicModule | ClassProvider | ValueProvider | FactoryProvider | ExistingProvider | Type | Abstract // eslint-disable-next-line @typescript-eslint/ban-types | Function, ): (InjectionToken | OptionalFactoryDependency)[] { if (!this.hasInjectDeps(value)) { throw new Error('Incorrect argument, expected FactoryProvider'); } return value.inject.map((obj) => { if (Assert.isObjectOrCtor(obj) && 'token' in obj) { return obj.token as InjectionToken; } return obj; }); } static hasInjectDeps( value: | DynamicModule | ClassProvider | ValueProvider | FactoryProvider | ExistingProvider | Type | Abstract // eslint-disable-next-line @typescript-eslint/ban-types | Function, ): value is FactoryProvider & Required> { return 'inject' in value && Boolean(value.inject); } getProviders(): Provider[] | undefined { return DependenciesScanner.prototype.isDynamicModule(this.definition) ? [ ...this.reflectMetadata( MODULE_METADATA.PROVIDERS, this.definition.module, ), ...(this.definition.providers || []), ] : this.reflectMetadata(MODULE_METADATA.PROVIDERS, this.definition); } getImports(): NestModuleDefinition[] | undefined { return DependenciesScanner.prototype.isDynamicModule(this.definition) ? [ ...this.reflectMetadata( MODULE_METADATA.IMPORTS, this.definition.module, ), ...(this.definition.imports || []), ] : this.reflectMetadata(MODULE_METADATA.IMPORTS, this.definition); } getControllers(): Type[] | undefined { return DependenciesScanner.prototype.isDynamicModule(this.definition) ? [ ...this.reflectMetadata( MODULE_METADATA.CONTROLLERS, this.definition.module, ), ...(this.definition.controllers || []), ] : this.reflectMetadata(MODULE_METADATA.CONTROLLERS, this.definition); } getExports(): (Type | InjectionToken)[] | undefined { return DependenciesScanner.prototype.isDynamicModule(this.definition) ? [ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment ...this.reflectMetadata( MODULE_METADATA.EXPORTS, this.definition.module, ), ...(this.definition.exports || []), ] : this.reflectMetadata(MODULE_METADATA.EXPORTS, this.definition); } private reflectMetadata(metadataKey: string, metatype: Type): T[] { return Reflect.getMetadata(metadataKey, metatype) || []; } }