UNPKG

@loopback/metadata

Version:

Utilities to help developers implement TypeScript decorators, define/merge metadata, and inspect metadata

194 lines (176 loc) 5.4 kB
// Copyright IBM Corp. and LoopBack contributors 2017,2019. All Rights Reserved. // Node module: @loopback/metadata // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT import 'reflect-metadata'; /* eslint-disable @typescript-eslint/no-explicit-any */ /* * namespaced wrapper to handle reflect api */ export class NamespacedReflect { /** * @param namespace - Namespace to bind this reflect context */ constructor(private namespace?: string) {} private getMetadataKey(metadataKey: string): string { // prefix namespace, if provided, to the metadata key return this.namespace ? this.namespace + ':' + metadataKey : metadataKey; } /** * define metadata for a target class or it's property/method */ defineMetadata( metadataKey: string, metadataValue: any, target: Object, propertyKey?: string, ) { metadataKey = this.getMetadataKey(metadataKey); if (propertyKey) { Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey); } else { Reflect.defineMetadata(metadataKey, metadataValue, target); } } /** * lookup metadata from a target object and its prototype chain */ getMetadata(metadataKey: string, target: Object, propertyKey?: string): any { metadataKey = this.getMetadataKey(metadataKey); if (propertyKey) { return Reflect.getMetadata(metadataKey, target, propertyKey); } return Reflect.getMetadata(metadataKey, target); } /** * get own metadata for a target object or it's property/method */ getOwnMetadata( metadataKey: string, target: Object, propertyKey?: string, ): any { metadataKey = this.getMetadataKey(metadataKey); if (propertyKey) { return Reflect.getOwnMetadata(metadataKey, target, propertyKey); } return Reflect.getOwnMetadata(metadataKey, target); } /** * Check if the target has corresponding metadata * @param metadataKey - Key * @param target - Target * @param propertyKey - Optional property key */ hasMetadata( metadataKey: string, target: Object, propertyKey?: string, ): boolean { metadataKey = this.getMetadataKey(metadataKey); if (propertyKey) { return Reflect.hasMetadata(metadataKey, target, propertyKey); } return Reflect.hasMetadata(metadataKey, target); } hasOwnMetadata( metadataKey: string, target: Object, propertyKey?: string, ): boolean { metadataKey = this.getMetadataKey(metadataKey); if (propertyKey) { return Reflect.hasOwnMetadata(metadataKey, target, propertyKey); } return Reflect.hasOwnMetadata(metadataKey, target); } deleteMetadata( metadataKey: string, target: Object, propertyKey?: string, ): boolean { metadataKey = this.getMetadataKey(metadataKey); if (propertyKey) { return Reflect.deleteMetadata(metadataKey, target, propertyKey); } return Reflect.deleteMetadata(metadataKey, target); } getMetadataKeys(target: Object, propertyKey?: string): string[] { let keys: string[]; if (propertyKey) { keys = Reflect.getMetadataKeys(target, propertyKey); } else { keys = Reflect.getMetadataKeys(target); } const metaKeys = []; if (keys) { if (!this.namespace) return keys; // No normalization is needed const prefix = this.namespace + ':'; for (const key of keys) { if (key.indexOf(prefix) === 0) { // Only add keys with the namespace prefix metaKeys.push(key.slice(prefix.length)); } } } return metaKeys; } getOwnMetadataKeys(target: Object, propertyKey?: string): string[] { let keys: string[]; if (propertyKey) { keys = Reflect.getOwnMetadataKeys(target, propertyKey); } else { keys = Reflect.getOwnMetadataKeys(target); } const metaKeys = []; if (keys) { if (!this.namespace) return keys; // No normalization is needed const prefix = this.namespace + ':'; for (const key of keys) { if (key.indexOf(prefix) === 0) { // Only add keys with the namespace prefix metaKeys.push(key.slice(prefix.length)); } } } return metaKeys; } decorate( decorators: (PropertyDecorator | MethodDecorator)[], target: Object, targetKey?: string | symbol, descriptor?: PropertyDescriptor, ): PropertyDescriptor | Function; decorate( decorators: ClassDecorator[], target: Object, ): PropertyDescriptor | Function; decorate( decorators: (PropertyDecorator | MethodDecorator)[] | ClassDecorator[], target: Object, targetKey?: string | symbol, descriptor?: PropertyDescriptor, ): PropertyDescriptor | Function { if (targetKey) { return Reflect.decorate( <(PropertyDecorator | MethodDecorator)[]>decorators, target, targetKey, descriptor, ); } else { return Reflect.decorate(<ClassDecorator[]>decorators, <Function>target); } } metadata( metadataKey: string, metadataValue: any, ): { (target: Function): void; (target: Object, targetKey: string | symbol): void; } { metadataKey = this.getMetadataKey(metadataKey); return Reflect.metadata(metadataKey, metadataValue); } } export const Reflector = new NamespacedReflect('loopback');