522 lines
17 KiB
TypeScript
522 lines
17 KiB
TypeScript
import {
|
|
MetadataKeyType,
|
|
PropertyKeyType,
|
|
} from '../type';
|
|
|
|
import { TypeUtil } from '../util/TypeUtil';
|
|
|
|
|
|
export class Metadata {
|
|
/**
|
|
* Gets the metadata value for the provided metadata key on the target object or its prototype chain.
|
|
* @param key A key used to store and retrieve metadata.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // constructor
|
|
* result = Metadata.get("custom:annotation", Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.get("custom:annotation", Example, "staticProperty");
|
|
*
|
|
* // property (on prototype)
|
|
* result = Metadata.get("custom:annotation", Example.prototype, "property");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.get("custom:annotation", Example, "staticMethod");
|
|
*
|
|
* // method (on prototype)
|
|
* result = Metadata.get("custom:annotation", Example.prototype, "method");
|
|
* ```
|
|
*
|
|
*/
|
|
public static get(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any {
|
|
return Reflect.getMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata key on the target object or its prototype chain.
|
|
* @param key A key used to store and retrieve metadata.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // constructor
|
|
* result = Metadata.getOwn("custom:annotation", Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getOwn("custom:annotation", Example, "staticProperty");
|
|
*
|
|
* // property (on prototype)
|
|
* result = Metadata.getOwn("custom:annotation", Example.prototype, "property");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getOwn("custom:annotation", Example, "staticMethod");
|
|
*
|
|
* // method (on prototype)
|
|
* result = Metadata.getOwn("custom:annotation", Example.prototype, "method");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any {
|
|
return Reflect.getOwnMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata DESIGN_TYPE on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.getType(Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getType(Example, "staticProperty");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getType(Example, "staticMethod");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getType(target: any, propertyKey?: PropertyKeyType): any {
|
|
return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata DESIGN_TYPE on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.getOwnType(Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getOwnType(Example, "staticProperty");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getOwnType(Example, "staticMethod");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getOwnType(target: any, propertyKey?: PropertyKeyType): any {
|
|
return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata DESIGN_RETURN_TYPE on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.getReturnType(Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getReturnType(Example, "staticProperty");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getReturnType(Example, "staticMethod");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getReturnType(target: any, propertyKey?: PropertyKeyType): any {
|
|
return Reflect.getMetadata(DESIGN_RETURN_TYPE, target, propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata DESIGN_RETURN_TYPE on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.getOwnReturnType(Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getOwnReturnType(Example, "staticProperty");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getOwnReturnType(Example, "staticMethod");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getOwnReturnType(target: any, propertyKey?: PropertyKeyType): any {
|
|
return Reflect.getOwnMetadata(DESIGN_RETURN_TYPE, target, propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined.
|
|
* @param key A key used to store and retrieve metadata.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // constructor
|
|
* result = Metadata.has("custom:annotation", Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.has("custom:annotation", Example, "staticProperty");
|
|
*
|
|
* // property (on prototype)
|
|
* result = Metadata.has("custom:annotation", Example.prototype, "property");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.has("custom:annotation", Example, "staticMethod");
|
|
*
|
|
* // method (on prototype)
|
|
* result = Metadata.has("custom:annotation", Example.prototype, "method");
|
|
* ```
|
|
*
|
|
*/
|
|
public static has(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
|
|
return Reflect.hasMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets a value indicating whether the target object or its prototype chain has the provided metadata key defined.
|
|
* @param key A key used to store and retrieve metadata.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns `true` if the metadata key was defined on the target object or its prototype chain; otherwise, `false`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // constructor
|
|
* result = Metadata.has("custom:annotation", Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.hasOwn("custom:annotation", Example, "staticProperty");
|
|
*
|
|
* // property (on prototype)
|
|
* result = Metadata.hasOwn("custom:annotation", Example.prototype, "property");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.hasOwn("custom:annotation", Example, "staticMethod");
|
|
*
|
|
* // method (on prototype)
|
|
* result = Metadata.hasOwn("custom:annotation", Example.prototype, "method");
|
|
* ```
|
|
*
|
|
*/
|
|
public static hasOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
|
|
return Reflect.hasOwnMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Deletes the metadata entry from the target object with the provided key.
|
|
* @param key A key used to store and retrieve metadata.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns `true` if the metadata entry was found and deleted; otherwise, false.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // constructor
|
|
* result = Metadata.delete("custom:annotation", Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.delete("custom:annotation", Example, "staticProperty");
|
|
*
|
|
* // property (on prototype)
|
|
* result = Metadata.delete("custom:annotation", Example.prototype, "property");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.delete("custom:annotation", Example, "staticMethod");
|
|
*
|
|
* // method (on prototype)
|
|
* result = Metadata.delete("custom:annotation", Example.prototype, "method");
|
|
* ```
|
|
*
|
|
*/
|
|
public static delete(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
|
|
return Reflect.deleteMetadata(key, TypeUtil.getType(target), propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Set the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @param value A value that contains attached metadata.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.setParamTypes(Example, undefined, [Object]);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.setParamTypes(Example, "staticProperty", [Object]);
|
|
*
|
|
* // property (on prototype)
|
|
* result = Metadata.setParamTypes(Example.prototype, "property", [Object]);
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.setParamTypes(Example, "staticMethod", [Object]);
|
|
*
|
|
* // method (on prototype)
|
|
* result = Metadata.setParamTypes(Example.prototype, "method", [Object]);
|
|
* ```
|
|
*
|
|
*/
|
|
public static setParamTypes(target: any, propertyKey: PropertyKeyType, value: any): void {
|
|
return this.set(DESIGN_PARAM_TYPES, value, target.prototype, propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Get all metadata for a metadataKey.
|
|
* @param metadataKey
|
|
*/
|
|
public static getTargetsFromPropertyKey = (metadataKey: MetadataKeyType): any[] =>
|
|
PROPERTIES.has(metadataKey) ? PROPERTIES.get(metadataKey) || [] : []
|
|
|
|
/**
|
|
* Define a unique metadata entry on the target.
|
|
* @param key A key used to store and retrieve metadata.
|
|
* @param value A value that contains attached metadata.
|
|
* @param target The target object on which to define metadata.
|
|
* @param propertyKey The property key for the target.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // constructor
|
|
* Reflect.defineMetadata("custom:annotation", options, Example);
|
|
*
|
|
* // property (on constructor)
|
|
* Reflect.defineMetadata("custom:annotation", Number, Example, "staticProperty");
|
|
*
|
|
* // property (on prototype)
|
|
* Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "property");
|
|
*
|
|
* // method (on constructor)
|
|
* Reflect.defineMetadata("custom:annotation", Number, Example, "staticMethod");
|
|
*
|
|
* // method (on prototype)
|
|
* Reflect.defineMetadata("custom:annotation", Number, Example.prototype, "method");
|
|
*
|
|
* // decorator factory as metadata-producing annotation.
|
|
* function MyAnnotation(options): PropertyDecorator {
|
|
* return (target, key) => Reflect.defineMetadata("custom:annotation", options, target, key);
|
|
* }
|
|
* ```
|
|
*
|
|
*/
|
|
public static set(key: MetadataKeyType, value: any, target: any, propertyKey?: PropertyKeyType): void {
|
|
|
|
const targets: any[] = PROPERTIES.has(key) ? PROPERTIES.get(key) || [] : [];
|
|
const classConstructor = TypeUtil.getType(target);
|
|
|
|
if (targets.indexOf(classConstructor) === -1) {
|
|
targets.push(classConstructor);
|
|
PROPERTIES.set(key, targets);
|
|
}
|
|
|
|
Reflect.defineMetadata(key, value, TypeUtil.getType(target), propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.getParamTypes(Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getParamTypes(Example, "staticProperty");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getParamTypes(Example, "staticMethod");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getParamTypes(target: any, propertyKey?: PropertyKeyType): any[] {
|
|
return Reflect.getMetadata(DESIGN_PARAM_TYPES, target, propertyKey);
|
|
}
|
|
|
|
/**
|
|
* Gets the metadata value for the provided metadata DESIGN_PARAM_TYPES on the target object or its prototype chain.
|
|
* @param target The target object on which the metadata is defined.
|
|
* @param propertyKey The property key for the target.
|
|
* @returns The metadata value for the metadata key if found; otherwise, `undefined`.
|
|
* @example
|
|
*
|
|
* ```typescript
|
|
* class Example {
|
|
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
* // static staticProperty;
|
|
* // property;
|
|
*
|
|
* static staticMethod(p) { }
|
|
* method(p) { }
|
|
* }
|
|
*
|
|
* // on contructor
|
|
* result = Metadata.getParamTypes(Example);
|
|
*
|
|
* // property (on constructor)
|
|
* result = Metadata.getParamTypes(Example, "staticProperty");
|
|
*
|
|
* // method (on constructor)
|
|
* result = Metadata.getParamTypes(Example, "staticMethod");
|
|
* ```
|
|
*
|
|
*/
|
|
public static getOwnParamTypes(target: any, propertyKey?: PropertyKeyType): any[] {
|
|
return Reflect.getOwnMetadata(DESIGN_PARAM_TYPES, target, propertyKey);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Metadata key
|
|
* @private
|
|
* @type {string}
|
|
*/
|
|
const DESIGN_PARAM_TYPES = 'design:paramtypes';
|
|
/**
|
|
* Metadata key
|
|
* @private
|
|
* @type {string}
|
|
*/
|
|
const DESIGN_TYPE = 'design:type';
|
|
/**
|
|
* Metadata key
|
|
* @private
|
|
* @type {string}
|
|
*/
|
|
const DESIGN_RETURN_TYPE = 'design:returntype';
|
|
/**
|
|
* Properties collections
|
|
* @private
|
|
* @type {string}
|
|
*/
|
|
const PROPERTIES: Map<MetadataKeyType, any[]> = new Map<MetadataKeyType, any[]>();
|