UNPKG

typescript-injections

Version:

TypeScript Injections is a library, which simplify dependency management in your project.

124 lines (108 loc) 5.5 kB
import TypeScriptInjections from "../../../../abstractions/Domain/TypeScriptInjections/TypeScriptInjections"; import TypeScriptInjectionsConfig from "../../../../abstractions/Domain/DTO/TypeScriptInjectionsConfig/TypeScriptInjectionsConfig"; import AbstractClass from "../../../../abstractions/Infrastructure/AbstractClass/AbstractClass"; import Class from "../../../../abstractions/Infrastructure/Class/Class"; import MappingsMap from "../../../../abstractions/Domain/DTO/MappingsMap/MappingsMap"; import AdditionalInjectionsConfig from "../../../../abstractions/Domain/DTO/ConstructorsMap/AdditionalInjectionsConfig/AdditionalInjectionsConfig"; import ConstructorsMap from "../../../../abstractions/Domain/DTO/ConstructorsMap/ConstructorsMap"; import { ConstructorParamsAsMethodsWithParams } from "../../../../abstractions/Infrastructure/ConstructorParamsAsMethodsWithParams/ConstructorParamsAsMethodsWithParams"; export default class MainTypeScriptInjections implements TypeScriptInjections { public resolve<T>(abstraction: AbstractClass<T>, config: TypeScriptInjectionsConfig): T { const abstractionsToImplementationsSingletons = new Map<AbstractClass<unknown>, {}>(); const implementationsClassToImplementationsSingletons = new Map<Class<unknown, unknown[]>, {}>(); return this.resolveInternal( abstraction, config, abstractionsToImplementationsSingletons, implementationsClassToImplementationsSingletons, ); } public createReference<T>(): AbstractClass<T> { return {} as AbstractClass<T>; } public mappings(): MappingsMap { return new Map(); } public constructors(): ConstructorsMap { return new Map(); } public singletons(): Set<Class<{}, any>> { return new Set(); } private resolveInternal<T>( abstraction: AbstractClass<T>, config: TypeScriptInjectionsConfig, abstractionsToImplementationsSingletons: Map<AbstractClass<unknown>, {}>, implementationsClassToImplementationsSingletons: Map<Class<unknown, unknown[]>, {}>, ): T { if(abstractionsToImplementationsSingletons.has(abstraction)) { return abstractionsToImplementationsSingletons.get(abstraction) as T; } const implementationClass = config.mappings.get(abstraction) as Class<T, unknown[]>; if(!implementationClass) { throw new Error("Unable to resolve given abstraction."); } if(implementationsClassToImplementationsSingletons.has(implementationClass)) { const implementation = implementationsClassToImplementationsSingletons.get(implementationClass) as T; abstractionsToImplementationsSingletons.set(abstraction, implementation); return implementation; } const implementationConstructor = config.constructors?.get(implementationClass); const implementation = this.createImplementation( implementationClass, implementationConstructor, config, abstractionsToImplementationsSingletons, implementationsClassToImplementationsSingletons, ); if(config.singletons && config.singletons.has(implementationClass)) { implementationsClassToImplementationsSingletons.set(implementationClass, implementation); abstractionsToImplementationsSingletons.set(abstraction, implementation); } return implementation; } private createImplementation<C>( implementationClass: Class<C, any[]>, implementationConstructor: ConstructorParamsAsMethodsWithParams<Class<C, any[]>, [ { resolve: <T>( abstraction: AbstractClass<T>, config?: AdditionalInjectionsConfig, ) => T, }, ]> | undefined, config: TypeScriptInjectionsConfig, abstractionsToImplementationsSingletons: Map<AbstractClass<unknown>, {}>, implementationsClassToImplementationsSingletons: Map<Class<unknown, unknown[]>, {}>, ): C { if(!implementationConstructor) { return new implementationClass() as C; } return new implementationClass(...implementationConstructor.map((paramCallable) => paramCallable({ resolve: <T>( abstraction: AbstractClass<T>, additionalConfig?: AdditionalInjectionsConfig, ): T => this.resolveInternal( abstraction, additionalConfig ? { mappings: additionalConfig.mappings ? new Map([...config.mappings, ...additionalConfig.mappings]) : config.mappings, constructors: additionalConfig.constructors && config.constructors ? new Map([...config.constructors, ...additionalConfig.constructors]) as ConstructorsMap : ( additionalConfig.constructors ? additionalConfig.constructors : config.constructors ), } : config, abstractionsToImplementationsSingletons, implementationsClassToImplementationsSingletons, ), }))); } }