@malagu/core
Version:
102 lines (90 loc) • 3.71 kB
text/typescript
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!);
}
}