UNPKG

@malagu/core

Version:
124 lines (106 loc) 3.64 kB
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; }