import '@abraham/reflection'; import { Container, interfaces, injectable } from 'inversify'; import { buildProviderModule } from 'inversify-binding-decorators'; import { ServiceIdentifier, Constructor, createDecorator } from './decorators'; export interface InstanceAccessor { get(id: ServiceIdentifier): T; } export interface IInstantiationService { get(serviceIdentifier: ServiceIdentifier): T; bind(serviceIdentifier: ServiceIdentifier, constructor: Constructor): void; set(serviceIdentifier: ServiceIdentifier, instance: T): void; invokeFunction( fn: (accessor: InstanceAccessor, ...args: TS) => R, ...args: TS ): R; createInstance(App: T): InstanceType; } export const IInstantiationService = createDecorator('instantiationService'); export class InstantiationService implements IInstantiationService { container: Container; constructor(options?: interfaces.ContainerOptions) { this.container = new Container(options); this.set(IInstantiationService, this); this.container.load(buildProviderModule()); } get(serviceIdentifier: ServiceIdentifier) { return this.container.get(serviceIdentifier.toString()); } set(serviceIdentifier: ServiceIdentifier, instance: T): void { this.container.bind(serviceIdentifier).toConstantValue(instance); } /** * Calls a function with a service accessor. */ invokeFunction( fn: (accessor: InstanceAccessor, ...args: TS) => R, ...args: TS ): R { const accessor: InstanceAccessor = { get: (id) => { return this.get(id); }, }; return fn(accessor, ...args); } bind(serviceIdentifier: ServiceIdentifier, constructor: Constructor) { this.container.bind(serviceIdentifier).to(constructor); } createInstance(App: T) { injectable()(App); return this.container.resolve>(App); } }