@loopback/metadata
Version:
Utilities to help developers implement TypeScript decorators, define/merge metadata, and inspect metadata
194 lines (176 loc) • 5.4 kB
text/typescript
// 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');