metarize
Version:
A lightweight, ESM-compatible TypeScript metadata library for creating and inspecting decorators with zero dependencies
163 lines (148 loc) • 5.07 kB
text/typescript
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('metarize');