UNPKG

@travetto/di

Version:

Dependency registration/management and injection support.

80 lines (72 loc) 2.74 kB
import { asConstructable, asFull, TypedFunction, type Class } from '@travetto/runtime'; import { InjectableFactoryConfig, InjectableConfig, Dependency } from './types'; import { DependencyRegistry, ResolutionType } from './registry'; function collapseConfig<T extends { qualifier?: symbol }>(...args: (symbol | Partial<InjectConfig> | undefined)[]): T { let out: Partial<T> = {}; if (args) { if (Array.isArray(args)) { for (const arg of args) { if (typeof arg === 'symbol') { out.qualifier = arg; } else if (arg) { Object.assign(out, arg); } } } else { out = args; } } return asFull(out); } /** * Indicate that a class is able to be injected * * @augments `@travetto/di:Injectable` */ export function Injectable(first?: Partial<InjectableConfig> | symbol, ...args: (Partial<InjectableConfig> | undefined)[]) { return <T extends Class>(target: T): T => { const config = { ...collapseConfig<Partial<InjectableConfig>>(first, ...args), class: target }; DependencyRegistry.registerClass(target, config); return target; }; } export type InjectConfig = { qualifier?: symbol, optional?: boolean, resolution?: ResolutionType }; export function InjectArgs(configs?: InjectConfig[][]) { return <T extends Class>(target: T): void => { DependencyRegistry.registerConstructor(target, configs?.map(x => collapseConfig(...x))); }; } /** * Indicate that a field is able to be injected * * @augments `@travetto/di:Inject` */ export function Inject(first?: InjectConfig | symbol, ...args: (InjectConfig | undefined)[]) { return (target: unknown, propertyKey?: string, idx?: number | PropertyDescriptor): void => { if (typeof idx !== 'number') { // Only register if on property const config = collapseConfig<Dependency>(first, ...args); DependencyRegistry.registerProperty( asConstructable(target).constructor, propertyKey!, config ); } }; } /** * Identifies a static method that is able to produce a dependency * * @augments `@travetto/di:InjectableFactory` */ export function InjectableFactory(first?: Partial<InjectableFactoryConfig> | symbol, ...args: (Partial<InjectableFactoryConfig> | undefined)[]) { return <T extends Class>(target: T, property: string | symbol, descriptor: TypedPropertyDescriptor<TypedFunction>): void => { const config: InjectableFactoryConfig = collapseConfig(first, ...args); DependencyRegistry.registerFactory({ ...config, dependencies: config.dependencies?.map(x => Array.isArray(x) ? collapseConfig(...x) : collapseConfig(x)), fn: descriptor.value!, id: `${target.Ⲑid}#${property.toString()}` }); }; }