UNPKG

@essential-projects/metadata

Version:

the core metadata service for using the metadata from inside the domain

165 lines (112 loc) 4.71 kB
import {IMetadataProvider, MetadataType} from '@essential-projects/metadata_contracts'; import {Logger} from 'loggerhythm'; import * as merge from 'deepmerge'; import 'reflect-metadata'; const logger: Logger = new Logger('MetadataProvider'); const GLOBAL_METADATA_STORE_KEY: string = '$metadata'; declare var global: any; declare var window: any; let globalVariable: any; if (typeof global !== 'undefined') { globalVariable = global; } else { globalVariable = window; } function getGlobalMetadataStore(): any { if (!globalVariable[GLOBAL_METADATA_STORE_KEY]) { globalVariable[GLOBAL_METADATA_STORE_KEY] = {}; } return globalVariable[GLOBAL_METADATA_STORE_KEY]; } if (typeof globalVariable.existingMetadataProvider === 'undefined') { globalVariable.existingMetadataProvider = { getForInstance(metadataKey: MetadataType, namespace: string, target: any, targetKey?: string): any { if (!isObject(target)) { return undefined; } let result: any = MetadataProvider.getForOwnInstance(metadataKey, namespace, target, targetKey); if (result === undefined) { result = MetadataProvider.getForInstance(metadataKey, Object.getPrototypeOf(target), targetKey); } return result; }, getForOwnInstance(metadataKey: MetadataType, namespace: string, target: any, targetKey?: string): any { if (!isObject(target)) { return undefined; } const type: string = target.constructor.name; let metadataForType: any = {}; // fetching the metadata for Object would result in a stack overflow if (type !== 'Object') { metadataForType = MetadataProvider.getForType(metadataKey, namespace, type, targetKey); } const ownMetadata: any = Reflect.getOwnMetadata(metadataKey, target, targetKey); let result: any; if (metadataForType === undefined) { result = ownMetadata; } else if (ownMetadata === undefined) { result = metadataForType; } else { result = merge(metadataForType, ownMetadata); } return result; }, getForType(metadataKey: MetadataType, namespace: string, type: string, targetKey?: string): any { const allTypeMetadata: any = getGlobalMetadataStore(); const namespaceMetadata: any = allTypeMetadata[namespace]; if (!namespaceMetadata) { return undefined; } const typeMetadata: any = namespaceMetadata[type]; if (!typeMetadata) { return undefined; } const typeMetadataForKey: any = typeMetadata[metadataKey]; if (!typeMetadataForKey) { return undefined; } const typeMetadataForProperty: any = typeMetadataForKey[targetKey]; return typeMetadataForProperty; }, getAllForType(metadataKey: MetadataType, namespace: string, type: string): any { const allTypeMetadata: any = getGlobalMetadataStore(); const namespaceMetadata: any = allTypeMetadata[namespace]; if (!namespaceMetadata) { return undefined; } const typeMetadata: any = namespaceMetadata[type]; if (!typeMetadata) { return undefined; } const typeMetadataForKey: any = typeMetadata[metadataKey]; return typeMetadataForKey; }, setForInstance(metadataKey: MetadataType, metadataValue: any, target: any, targetKey?: string): void { Reflect.defineMetadata(metadataKey, metadataValue, target, targetKey); }, hasType(namespace: string, type: string): boolean { const allTypeMetadata: any = getGlobalMetadataStore(); return allTypeMetadata[namespace][type] !== undefined; }, setForType(metadataKey: MetadataType, metadataValue: any, namespace: string, type: string, targetKey?: string): void { const allTypeMetadata: any = getGlobalMetadataStore(); if (!allTypeMetadata[namespace]) { allTypeMetadata[namespace] = {}; } if (!allTypeMetadata[namespace][type]) { allTypeMetadata[namespace][type] = {}; } if (!allTypeMetadata[namespace][type][metadataKey]) { allTypeMetadata[namespace][type][metadataKey] = {}; } if (metadataValue && !allTypeMetadata[namespace][type][metadataKey][targetKey]) { allTypeMetadata[namespace][type][metadataKey][targetKey] = {}; } allTypeMetadata[namespace][type][metadataKey][targetKey] = merge(metadataValue, allTypeMetadata[namespace][type][metadataKey][targetKey]); }, }; } function isObject(value: any): boolean { return value && (typeof value === 'function' || typeof value === 'object'); } export const MetadataProvider: IMetadataProvider = globalVariable.existingMetadataProvider;