UNPKG

@malagu/core

Version:
102 lines (90 loc) 3.71 kB
import { interfaces, ContainerModule } from 'inversify'; import { METADATA_KEY } from '../constants'; import { ComponentMetadata, ConstantOption } from '../annotation'; import { ConfigUtil } from '../config/config-util'; import { AopProxyFactory, ClassFilter } from '../aop/aop-protocol'; import { ContainerUtil } from './container-util'; import { Scope } from './scope'; export function manualBind(registry?: interfaces.ContainerModuleCallBack): interfaces.ContainerModule { return new ContainerModule((bind, unbind, isBound, rebind, ...rest) => { if (registry) { registry(bind, unbind, isBound, rebind, ...rest); } }); } export function autoBind(registry?: interfaces.ContainerModuleCallBack): interfaces.ContainerModule { const metadatas: ComponentMetadata[] = Reflect.getMetadata(METADATA_KEY.component, Reflect) || []; const constantMetadata: ConstantOption[] = Reflect.getMetadata(METADATA_KEY.constantValue, Reflect) || []; Reflect.defineMetadata(METADATA_KEY.component, [], Reflect); Reflect.defineMetadata(METADATA_KEY.constantValue, [], Reflect); return new ContainerModule((bind, unbind, isBound, rebind, ...rest) => { for (let index = metadatas!.length - 1; index >= 0; index--) { const metadata = metadatas![index]; resolve(metadata, bind, rebind); } constantMetadata!.map(metadata => resolveConstant(metadata, bind, rebind)); if (registry) { registry(bind, unbind, isBound, rebind, ...rest); } }); } function doProxyIfNeed(metadata: ComponentMetadata, target: any) { const enabled = ConfigUtil.getRaw().malagu?.aop?.enabled; if (enabled && metadata.proxy) { const classFilter = ContainerUtil.get<ClassFilter>(ClassFilter); if (target.constructor && classFilter.matches(target.constructor, metadata)) { const aopProxyFactory = ContainerUtil.get<AopProxyFactory>(AopProxyFactory); return aopProxyFactory.create({ target, metadata }).getProxy(); } } return target; } function resolve(metadata: ComponentMetadata, bind: interfaces.Bind, rebind: interfaces.Rebind): void { let mid: any; const { ids, scope, name, tag, when, proxy, onActivation, target } = metadata; const _ids = [...ids]; const id = _ids.shift()!; if (metadata.rebind) { const id2 = _ids.shift(); mid = rebind(id2 || id).to(target); } else { mid = bind(id).to(target); } if (scope === Scope.Singleton) { mid = mid.inSingletonScope(); } else if (scope === Scope.Transient) { mid = mid.inTransientScope(); } if (name) { mid = mid.whenTargetNamed(name); } else if (tag) { mid = mid.whenTargetTagged(tag.tag, tag.value); } else if (metadata.default) { mid = mid.whenTargetIsDefault(); } else if (when) { mid = mid.when(when); } if (onActivation) { mid.onActivation(onActivation); } else if (proxy) { mid.onActivation((context: interfaces.Context, t: any) => doProxyIfNeed(metadata, t)); } for (const item of _ids) { bind(item).toService(id); } } function resolveConstant(metadata: ConstantOption, bind: interfaces.Bind, rebind: interfaces.Rebind): void { const ids = Array.isArray(metadata.id) ? [...metadata.id] : [ metadata.id ]; const id = ids.shift(); if (metadata.rebind) { rebind(id!).toConstantValue(metadata.constantValue); } else { bind(id!).toConstantValue(metadata.constantValue); } for (const item of ids) { bind(item!).toService(id!); } }