import type { Container, Module, ResolveFunction } from "@evyweb/ioctopus"; import { createContainer, createModule } from "@evyweb/ioctopus"; export type ModuleLoader = { token: string | symbol; loadModule: (container: Container) => void }; /** * A type-safe alternative to module.bind(token).toClass(classs, deps) that automatically ensures that all dependencies required by the Class are provided. * It assumes that dependencies are passed to the constructor as an object map(e.g. new MyService(deps)) * * @returns A function that can be used to load the dependencies into the container automatically. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export function bindModuleToClassOnToken any>({ module, token, classs, depsMap, moduleToken, }: { module: Module; moduleToken: string | symbol; token: string | symbol; classs: TClass; depsMap: Record< // eslint-disable-next-line @typescript-eslint/no-explicit-any keyof (TClass extends new (deps: infer TDeps) => any ? TDeps : never), ModuleLoader >; }): (container: Container) => void; /** * A type-safe alternative to module.bind(token).toClass(classs, deps) that automatically ensures that all dependencies required by the Class are provided. * It assumes that there is a single dependency, passed as argument to the constructor * * @returns A function that can be used to load the dependencies into the container automatically. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export function bindModuleToClassOnToken any>({ module, token, classs, dep, moduleToken, }: { module: Module; moduleToken: string | symbol; token: string | symbol; classs: TClass; dep: ModuleLoader; }): (container: Container) => void; /** * A type-safe alternative to module.bind(token).toClass(classs, deps) that automatically ensures that all dependencies required by the Class are provided. * @returns A function that can be used to load the dependencies into the container automatically. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export function bindModuleToClassOnToken any>({ module, token, classs, depsMap, dep, moduleToken, }: { module: Module; moduleToken: string | symbol; token: string | symbol; classs: TClass; /** * When the constructor of the class accept deps as the argument which is a Record of many dependencies */ depsMap?: Record< // eslint-disable-next-line @typescript-eslint/no-explicit-any keyof (TClass extends new (deps: infer TDeps) => any ? TDeps : never), ModuleLoader >; /** * When the constructor of the class accept a single dependency and is the only argument to constructor. */ dep?: ModuleLoader; }) { if (dep && depsMap) { throw new Error( "Cannot provide both 'dep' and 'depsMap'. Use 'dep' for single dependency or 'depsMap' for multiple dependencies." ); } if (!dep && !depsMap) { throw new Error( "Must provide either 'dep' for single dependency or 'depsMap' for multiple dependencies." ); } if (dep) { module.bind(token).toClass(classs, [dep.token]); } else if (depsMap) { const depsObject = Object.fromEntries(Object.entries(depsMap).map(([key, value]) => [key, value.token])); module.bind(token).toClass(classs, depsObject); } return function loadModule(container: Container) { container.load(moduleToken, module); if (dep) { dep.loadModule(container); } else if (depsMap) { for (const key in depsMap) { const loadModule = depsMap[key as keyof typeof depsMap].loadModule; loadModule(container); } } }; } export { createContainer, createModule, type Container, type Module, type ResolveFunction };