@malagu/core
Version:
124 lines (106 loc) • 3.64 kB
text/typescript
import { decorate, injectable, interfaces, METADATA_KEY as inversify_METADATA_KEY } from 'inversify';
import { METADATA_KEY } from '../constants';
import { ConfigUtil } from '../config/config-util';
import { AnnotationUtil } from '../utils';
export type ComponentId = interfaces.ServiceIdentifier<any>;
export const COMPONENT_TAG = 'Component';
export enum Scope {
Request, Singleton, Transient
}
export interface ComponentOption {
id?: ComponentId | ComponentId[];
scope?: Scope;
name?: string | number | symbol;
tag?: { tag: string | number | symbol, value: any };
default?: boolean;
when?: (request: interfaces.Request) => boolean;
rebind?: boolean;
proxy?: boolean;
sysTags?: string[];
onActivation?: (context: interfaces.Context, t: any) => any;
}
export interface ComponentMetadata {
ids: ComponentId[];
scope: Scope;
name?: string | number | symbol;
tag?: { tag: string | number | symbol, value: any },
default?: boolean;
when?: (request: interfaces.Request) => boolean
rebind: boolean;
proxy: boolean;
sysTags: string[]
onActivation?: (context: interfaces.Context, t: any) => any;
target: any;
}
export type IdOrComponentOption = ComponentId | ComponentId[] | ComponentOption;
export interface ComponentDecorator {
(idOrOption?: IdOrComponentOption): ClassDecorator;
(...ids: ComponentId[]): ClassDecorator;
}
export const Component = <ComponentDecorator>function (...idOrOption: any): ClassDecorator {
return (t: any) => {
const option = parseComponentOption(t, idOrOption);
applyComponentDecorator(option, t);
};
};
const defaultComponentOption: ComponentOption = {
scope: Scope.Singleton,
rebind: false,
proxy: false,
...ConfigUtil.getRaw().malagu?.annotation?.Component
};
export function parseComponentOption(target: any, idOrOption: any) {
if (Array.isArray(idOrOption)) {
if (idOrOption.length === 1) {
idOrOption = idOrOption[0];
} else if (idOrOption.length === 0) {
idOrOption = undefined;
}
}
const option = AnnotationUtil.getValueOrOption<ComponentOption>(idOrOption);
const parsed = { ...defaultComponentOption, ...option };
let ids: ComponentId[];
if (Array.isArray(parsed.id)) {
ids = parsed.id;
} else if (parsed.id && parsed.id !== target) {
ids = [ parsed.id, target ];
} else {
ids = [ target ];
}
parsed.id = ids;
parsed.sysTags = [ ...new Set<string>([ COMPONENT_TAG, ...parsed.sysTags || []]) ];
return parsed;
}
export function applyComponentDecorator(option: ComponentOption, target: any) {
const isAlreadyDecorated = Reflect.hasOwnMetadata(inversify_METADATA_KEY.PARAM_TYPES, target);
if (!isAlreadyDecorated) {
decorate(injectable(), target);
}
const metadata: ComponentMetadata = {
target,
ids: Array.isArray(option.id) ? option.id : [ option.id || target ],
sysTags: option.sysTags!,
rebind: option.rebind!,
proxy: option.proxy!,
scope: option.scope!,
name: option.name,
tag: option.tag,
default: option.default,
when: option.when,
onActivation: option.onActivation
};
let metadatas: ComponentMetadata[] = Reflect.getMetadata(
METADATA_KEY.component,
Reflect
);
if (!metadatas) {
metadatas = [];
Reflect.defineMetadata(
METADATA_KEY.component,
metadatas,
Reflect
);
}
metadatas.push(metadata);
return metadata;
}