core/src/reflect/Metadata.ts
crusader 06967e23c9 ing
2018-05-16 15:57:12 +09:00

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[]>();