ing
This commit is contained in:
parent
19cd72fdde
commit
e987227a37
3
src/ts/@overflow/commons/core/type/index.ts
Normal file
3
src/ts/@overflow/commons/core/type/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './metadata';
|
||||
export * from './type';
|
||||
export * from './util';
|
520
src/ts/@overflow/commons/core/type/metadata.ts
Normal file
520
src/ts/@overflow/commons/core/type/metadata.ts
Normal file
|
@ -0,0 +1,520 @@
|
|||
import {
|
||||
PropertyKeyType,
|
||||
} from './type';
|
||||
|
||||
import * as Util from './util';
|
||||
|
||||
|
||||
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: string, target: any, propertyKey?: PropertyKeyType): any {
|
||||
return Reflect.getMetadata(key, Util.getClass(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: string, target: any, propertyKey?: string | symbol): any {
|
||||
return Reflect.getOwnMetadata(key, Util.getClass(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?: string | symbol): 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?: string | symbol): 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?: string | symbol): 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?: string | symbol): 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: string, target: any, propertyKey?: string | symbol): boolean {
|
||||
return Reflect.hasMetadata(key, Util.getClass(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: string, target: any, propertyKey?: string | symbol): boolean {
|
||||
return Reflect.hasOwnMetadata(key, Util.getClass(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: string, target: any, propertyKey?: string | symbol): boolean {
|
||||
return Reflect.deleteMetadata(key, Util.getClass(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: string | symbol, 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: string | symbol): 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: string, value: any, target: any, propertyKey?: string | symbol): void {
|
||||
|
||||
const targets: any[] = PROPERTIES.has(key) ? PROPERTIES.get(key) || [] : [];
|
||||
const classConstructor = Util.getClass(target);
|
||||
|
||||
if (targets.indexOf(classConstructor) === -1) {
|
||||
targets.push(classConstructor);
|
||||
PROPERTIES.set(key, targets);
|
||||
}
|
||||
|
||||
Reflect.defineMetadata(key, value, Util.getClass(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?: string | symbol): 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?: string | symbol): 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<string | symbol, any[]> = new Map<string | symbol, any[]>();
|
9
src/ts/@overflow/commons/core/type/type.ts
Normal file
9
src/ts/@overflow/commons/core/type/type.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export type IdentityType<T> = T | symbol;
|
||||
export type PropertyKeyType = IdentityType<string>;
|
||||
|
||||
export const Type = Function;
|
||||
export interface Type<T> extends Function {
|
||||
new (...args: any[]): T;
|
||||
}
|
||||
|
||||
export type DecoratorParametersType = [any, string | symbol, number | PropertyDescriptor];
|
388
src/ts/@overflow/commons/core/type/util.ts
Normal file
388
src/ts/@overflow/commons/core/type/util.ts
Normal file
|
@ -0,0 +1,388 @@
|
|||
import {
|
||||
DecoratorParametersType,
|
||||
PropertyKeyType,
|
||||
} from './type';
|
||||
|
||||
/**
|
||||
* Get the provide constructor.
|
||||
* @param targetClass
|
||||
*/
|
||||
export const getContructor = (targetClass: any): Function =>
|
||||
typeof targetClass === 'function'
|
||||
? targetClass
|
||||
: targetClass.constructor;
|
||||
|
||||
/**
|
||||
* Get the provide constructor if target is an instance.
|
||||
* @param target
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getClass(target: any): any {
|
||||
return target.prototype ? target : target.constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {symbol}
|
||||
*/
|
||||
export function getClassOrSymbol(target: any): any {
|
||||
return typeof target === 'symbol' ? target : getClass(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given obj is a primitive.
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPrimitiveOrPrimitiveClass(target: any): boolean {
|
||||
return isString(target)
|
||||
|| isNumber(target)
|
||||
|| isBoolean(target);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {'string' | 'number' | 'boolean' | 'any'}
|
||||
*/
|
||||
export function primitiveOf(target: any): 'string' | 'number' | 'boolean' | 'any' {
|
||||
if (isString(target)) {
|
||||
return 'string';
|
||||
}
|
||||
if (isNumber(target)) {
|
||||
return 'number';
|
||||
}
|
||||
if (isBoolean(target)) {
|
||||
return 'boolean';
|
||||
}
|
||||
return 'any';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isString(target: any): boolean {
|
||||
return typeof target === 'string' || target instanceof String || target === String;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isNumber(target: any): boolean {
|
||||
return typeof target === 'number' || target instanceof Number || target === Number;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isBoolean(target: any): boolean {
|
||||
return typeof target === 'boolean' || target instanceof Boolean || target === Boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function isArray(target: any): boolean {
|
||||
return Array.isArray(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the clazz is an array.
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isArrayOrArrayClass(target: any): boolean {
|
||||
if (target === Array) {
|
||||
return true;
|
||||
}
|
||||
return isArray(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the target.
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isCollection(target: any): boolean {
|
||||
return isArrayOrArrayClass(target)
|
||||
|| target === Map
|
||||
|| target instanceof Map
|
||||
|| target === Set
|
||||
|| target instanceof Set
|
||||
|| target === WeakMap
|
||||
|| target instanceof WeakMap
|
||||
|| target === WeakSet
|
||||
|| target instanceof WeakSet;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isDate(target: any): boolean {
|
||||
return target === Date || target instanceof Date;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isObject(target: any): boolean {
|
||||
return target === Object;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isClass(target: any): boolean {
|
||||
return !isPrimitiveOrPrimitiveClass(target)
|
||||
&& !isObject(target)
|
||||
&& !isDate(target)
|
||||
&& target !== undefined
|
||||
&& !isPromise(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the value is an empty string, null or undefined.
|
||||
* @param value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isEmpty(value: any): boolean {
|
||||
return value === '' || value === null || value === undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object name
|
||||
*/
|
||||
export const nameOf = (obj: any): string => {
|
||||
switch (typeof obj) {
|
||||
default:
|
||||
return '' + obj;
|
||||
case 'symbol':
|
||||
return nameOfSymbol(obj);
|
||||
case 'function':
|
||||
return nameOfClass(obj);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the provide name.
|
||||
* @param targetClass
|
||||
*/
|
||||
export const nameOfClass = (targetClass: any) => {
|
||||
return typeof targetClass === 'function'
|
||||
? targetClass.name
|
||||
: targetClass.constructor.name;
|
||||
};
|
||||
/**
|
||||
* Get symbol name.
|
||||
* @param sym
|
||||
*/
|
||||
export const nameOfSymbol = (sym: symbol): string =>
|
||||
sym.toString().replace('Symbol(', '').replace(')', '');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param out
|
||||
* @param obj
|
||||
* @param {{[p: string]: (collection: any[], value: any) => any}} reducers
|
||||
* @returns {any}
|
||||
*/
|
||||
export function deepExtends(out: any, obj: any, reducers: { [key: string]: (collection: any[], value: any) => any } = {}): any {
|
||||
|
||||
if (obj === undefined || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (isPrimitiveOrPrimitiveClass(obj) || typeof obj === 'symbol' || typeof obj === 'function') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (isArrayOrArrayClass(obj)) {
|
||||
out = out || [];
|
||||
} else {
|
||||
out = out || {};
|
||||
}
|
||||
|
||||
const defaultReducer = reducers.default ? reducers.default : (collection: any[], value: any) => {
|
||||
collection.push(value);
|
||||
return collection;
|
||||
};
|
||||
const set = (key: string | number, value: any) => {
|
||||
if (isArrayOrArrayClass(obj)) {
|
||||
out.push(value);
|
||||
} else {
|
||||
out[key] = value;
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(obj).forEach(key => {
|
||||
let value = obj[key];
|
||||
|
||||
if (value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === '' && out[key] !== '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPrimitiveOrPrimitiveClass(value) || typeof value === 'function') {
|
||||
set(key, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isArrayOrArrayClass(value)) {
|
||||
|
||||
value = value.map((v: any) => deepExtends(undefined, v));
|
||||
|
||||
set(key, []
|
||||
.concat(out[key] || [], value)
|
||||
.reduce((collection: any[], v: any) =>
|
||||
reducers[key] ? reducers[key](collection, v) : defaultReducer(collection, v),
|
||||
[]));
|
||||
return;
|
||||
}
|
||||
|
||||
// Object
|
||||
if (isArrayOrArrayClass(obj)) {
|
||||
set(key, deepExtends(undefined, value, reducers));
|
||||
} else {
|
||||
set(key, deepExtends(out[key], value, reducers));
|
||||
}
|
||||
});
|
||||
|
||||
if (isArrayOrArrayClass(out)) {
|
||||
out.reduce((collection: any[], value: any) => defaultReducer(collection, value), []);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPromise(target: any): boolean {
|
||||
return target === Promise || target instanceof Promise;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {any}
|
||||
*/
|
||||
export function getInheritedClass(target: any): any {
|
||||
return Object.getPrototypeOf(target);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any[]} args
|
||||
* @returns {'parameter' | 'property' | 'method' | 'class'}
|
||||
*/
|
||||
export function getDecoratorType(args: any[]): 'parameter' | 'property' | 'method' | 'class' {
|
||||
const [, propertyKey, descriptor] = args;
|
||||
|
||||
if (typeof descriptor === 'number') {
|
||||
return 'parameter';
|
||||
}
|
||||
|
||||
if (propertyKey && descriptor === undefined || descriptor && (descriptor.get || descriptor.set)) {
|
||||
return 'property';
|
||||
}
|
||||
return (descriptor && descriptor.value) ? 'method' : 'class';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param {PropertyKeyType} propertyKey
|
||||
* @returns {PropertyDescriptor}
|
||||
*/
|
||||
export function descriptorOf(target: any, propertyKey: PropertyKeyType): PropertyDescriptor {
|
||||
return Object.getOwnPropertyDescriptor(target && target.prototype || target, propertyKey)!;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param {string} propertyKey
|
||||
* @returns {DecoratorParametersType}
|
||||
*/
|
||||
export function decoratorArgs(target: any, propertyKey: string): DecoratorParametersType {
|
||||
return [
|
||||
target,
|
||||
propertyKey,
|
||||
descriptorOf(target, propertyKey)!,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @returns {Array}
|
||||
*/
|
||||
export function ancestorsOf(target: any): any[] {
|
||||
const classes = [];
|
||||
|
||||
let currentTarget = getClass(target);
|
||||
|
||||
while (nameOf(currentTarget) !== '') {
|
||||
classes.unshift(currentTarget);
|
||||
currentTarget = getInheritedClass(currentTarget);
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param {string} name
|
||||
* @param {Function} callback
|
||||
*/
|
||||
export function applyBefore(target: any, name: string, callback: Function): void {
|
||||
const original = target[name];
|
||||
target[name] = function (...args: any[]): any {
|
||||
callback(...args);
|
||||
return original.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Promise<any>} promise
|
||||
* @param {number} time
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function promiseTimeout(promise: Promise<any>, time: number = 1000): Promise<{ ok: boolean, response: any }> {
|
||||
const timeout = (p: Promise<any>, t: number) => new Promise((resolve) => {
|
||||
p.then((response) => {
|
||||
resolve();
|
||||
return response;
|
||||
});
|
||||
setTimeout(() => resolve({ok: false}), t);
|
||||
});
|
||||
|
||||
promise = promise.then((response) => ({ok: true, response}));
|
||||
|
||||
return Promise.race([
|
||||
promise,
|
||||
timeout(promise, time),
|
||||
]);
|
||||
}
|
16
src/ts/@overflow/commons/decorator/annotation/annotation.ts
Normal file
16
src/ts/@overflow/commons/decorator/annotation/annotation.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import {
|
||||
PropertyKeyType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
export interface Annotation {
|
||||
classDecorator?: <TFunction extends Function>(target: TFunction) => TFunction | void;
|
||||
propertyDecorator?: (target: Object, propertyKey: PropertyKeyType) => void;
|
||||
methodDecorator?: <T>(target: Object, propertyKey: PropertyKeyType,
|
||||
descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
|
||||
parameterDecorator?: (target: Object, propertyKey: PropertyKeyType, parameterIndex: number) => void;
|
||||
}
|
||||
|
||||
export abstract class Annotation {
|
||||
}
|
||||
|
||||
export default Annotation;
|
1
src/ts/@overflow/commons/decorator/annotation/index.ts
Normal file
1
src/ts/@overflow/commons/decorator/annotation/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './annotation';
|
11
src/ts/@overflow/commons/decorator/constants.ts
Normal file
11
src/ts/@overflow/commons/decorator/constants.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export const ANNOTATION_HANDLER_CLASS: string = 'classDecorator';
|
||||
export const ANNOTATION_HANDLER_PROPERTY: string = 'propertyDecorator';
|
||||
export const ANNOTATION_HANDLER_METHOD: string = 'methodDecorator';
|
||||
export const ANNOTATION_HANDLER_PARAMETER: string = 'parameterDecorator';
|
||||
|
||||
export enum DecoratorType {
|
||||
CLASS = 'Class',
|
||||
PROPERTY = 'Property',
|
||||
METHOD = 'Method',
|
||||
PARAMETER = 'Parameter',
|
||||
}
|
76
src/ts/@overflow/commons/decorator/decorator.ts
Normal file
76
src/ts/@overflow/commons/decorator/decorator.ts
Normal file
|
@ -0,0 +1,76 @@
|
|||
import {
|
||||
Type,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import * as TypeUtil from '@overflow/commons/core/type/util';
|
||||
|
||||
import * as Constants from './constants';
|
||||
import {
|
||||
Annotation,
|
||||
} from './annotation';
|
||||
|
||||
export class Decorator {
|
||||
public static create = (AnnotationClass: Type<Annotation>) => {
|
||||
|
||||
return (...handlerArgs: any[]) => {
|
||||
let annotation: Annotation = new AnnotationClass(...handlerArgs);
|
||||
|
||||
return (...decoratorArgs: any[]) => {
|
||||
let decoratorType: Constants.DecoratorType = Decorator._detectDecoratorType(name, annotation, decoratorArgs);
|
||||
// let type = typeof decoratorArgs[0] === 'function' ? decoratorArgs[0].prototype : decoratorArgs[0];
|
||||
let clazz = TypeUtil.getClass(decoratorArgs[0]);
|
||||
|
||||
switch(decoratorType) {
|
||||
case Constants.DecoratorType.CLASS:
|
||||
return annotation.classDecorator.call(annotation, clazz, decoratorArgs[0]);
|
||||
case Constants.DecoratorType.PROPERTY:
|
||||
return annotation.propertyDecorator.call(annotation, clazz, decoratorArgs[0], decoratorArgs[1]);
|
||||
case Constants.DecoratorType.METHOD:
|
||||
return annotation.methodDecorator.call(annotation, clazz, decoratorArgs[0], decoratorArgs[1], decoratorArgs[2]);
|
||||
case Constants.DecoratorType.PARAMETER:
|
||||
return annotation.parameterDecorator.call(annotation, clazz, decoratorArgs[0], decoratorArgs[1], decoratorArgs[2]);
|
||||
default:
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private static _detectDecoratorType(name: string, annotation: any, args: any[]): Constants.DecoratorType {
|
||||
let params = [];
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i]) {
|
||||
params.push(args[i]);
|
||||
}
|
||||
}
|
||||
const paramCount = params.length;
|
||||
let decoratorType: Constants.DecoratorType;
|
||||
|
||||
if (1 === paramCount) {
|
||||
if (Constants.ANNOTATION_HANDLER_CLASS in annotation) {
|
||||
throw new Error(`Cannot apply @${name} decorator on Class.`);
|
||||
}
|
||||
decoratorType = Constants.DecoratorType.CLASS;
|
||||
} else if (2 === paramCount) {
|
||||
if (Constants.ANNOTATION_HANDLER_PROPERTY in annotation) {
|
||||
throw new Error(`Cannot apply @${name} decorator on Property.`);
|
||||
}
|
||||
decoratorType = Constants.DecoratorType.PROPERTY;
|
||||
} else if (3 === paramCount) {
|
||||
if(typeof args[2] === 'number') {
|
||||
if (Constants.ANNOTATION_HANDLER_PARAMETER in annotation) {
|
||||
throw new Error(`Cannot apply @${name} decorator on Parameter.`);
|
||||
}
|
||||
decoratorType = Constants.DecoratorType.PARAMETER;
|
||||
} else {
|
||||
if (Constants.ANNOTATION_HANDLER_METHOD in annotation) {
|
||||
throw new Error(`Cannot apply @${name} decorator on Method.`);
|
||||
}
|
||||
decoratorType = Constants.DecoratorType.METHOD;
|
||||
}
|
||||
} else {
|
||||
throw new Error(`@${name} decorator is not valid here!`);
|
||||
}
|
||||
|
||||
return decoratorType;
|
||||
}
|
||||
}
|
4
src/ts/@overflow/commons/decorator/index.ts
Normal file
4
src/ts/@overflow/commons/decorator/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from './constants';
|
||||
export * from './decorator';
|
||||
|
||||
export * from './annotation';
|
14
src/ts/@overflow/commons/redux/action.ts
Normal file
14
src/ts/@overflow/commons/redux/action.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import * as Redux from 'redux';
|
||||
|
||||
export interface Action<Payload = {}> extends Redux.Action {
|
||||
payload?: Payload;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
export type actions = (method: string, ...params: any[]) => Action<any[]>;
|
||||
export const actions: actions = (method: string, ...params: any[]): Action<any[]> => {
|
||||
return {
|
||||
type: method,
|
||||
payload: params,
|
||||
};
|
||||
};
|
23
src/ts/@overflow/commons/redux/api_async_action.ts
Normal file
23
src/ts/@overflow/commons/redux/api_async_action.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
Action,
|
||||
} from './action';
|
||||
|
||||
// API Action Type
|
||||
export type ASYNC_REQUEST = '@overflow/commons/async/REQUEST';
|
||||
export const ASYNC_REQUEST: ASYNC_REQUEST = '@overflow/commons/async/REQUEST';
|
||||
|
||||
export interface AsyncRequestPayload {
|
||||
method: string;
|
||||
params?: any[];
|
||||
}
|
||||
|
||||
export type asyncRequestActions = (method: string, ...params: any[]) => Action<AsyncRequestPayload>;
|
||||
export const asyncRequestActions: asyncRequestActions = (method: string, ...params: any[]): Action<AsyncRequestPayload> => {
|
||||
return {
|
||||
type: ASYNC_REQUEST,
|
||||
payload: {
|
||||
method: method,
|
||||
params: params,
|
||||
},
|
||||
};
|
||||
};
|
23
src/ts/@overflow/commons/redux/api_rest_action.ts
Normal file
23
src/ts/@overflow/commons/redux/api_rest_action.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
Action,
|
||||
} from './action';
|
||||
|
||||
// REST Action Type
|
||||
export type REST_REQUEST = '@overflow/commons/rest/REQUEST';
|
||||
export const REST_REQUEST: REST_REQUEST = '@overflow/commons/rest/REQUEST';
|
||||
|
||||
export interface RESTRequestPayload {
|
||||
entry: string;
|
||||
params?: any[];
|
||||
}
|
||||
|
||||
export type restRequestActions = (entry: string, ...params: any[]) => Action<RESTRequestPayload>;
|
||||
export const restRequestActions: restRequestActions = (entry: string, ...params: any[]): Action<RESTRequestPayload> => {
|
||||
return {
|
||||
type: REST_REQUEST,
|
||||
payload: {
|
||||
entry: entry,
|
||||
params: params,
|
||||
},
|
||||
};
|
||||
};
|
34
src/ts/@overflow/commons/redux/decorators/reducer.ts
Normal file
34
src/ts/@overflow/commons/redux/decorators/reducer.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import * as TypeUtil from '@overflow/commons/core/type/util';
|
||||
import {
|
||||
Annotation,
|
||||
Decorator,
|
||||
} from '@overflow/commons/decorator';
|
||||
|
||||
|
||||
|
||||
export interface ReducerAnnotationAttributes {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export class ReducerAnnotation extends Annotation {
|
||||
public readonly attributes: ReducerAnnotationAttributes;
|
||||
|
||||
public constructor(name: string | ReducerAnnotationAttributes) {
|
||||
super();
|
||||
if (TypeUtil.isString(name)) {
|
||||
this.attributes = {
|
||||
name: <string>name,
|
||||
};
|
||||
} else {
|
||||
this.attributes = <ReducerAnnotationAttributes>name;
|
||||
}
|
||||
}
|
||||
|
||||
public classDecorator = <TFunction extends Function>(target: TFunction): TFunction | void => {
|
||||
console.log('Reducer');
|
||||
}
|
||||
}
|
||||
|
||||
export const Reducer = Decorator.create(ReducerAnnotation);
|
||||
|
||||
export default Reducer;
|
6
src/ts/@overflow/commons/redux/decorators/rest.ts
Normal file
6
src/ts/@overflow/commons/redux/decorators/rest.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
export function Rest(path: string): Function {
|
||||
return Use(...['get', path].concat(args));
|
||||
}
|
||||
|
6
src/ts/@overflow/commons/redux/decorators/rpc.ts
Normal file
6
src/ts/@overflow/commons/redux/decorators/rpc.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
export function RPC(method: string): Function {
|
||||
return Use(...['get', path].concat(args));
|
||||
}
|
||||
|
35
src/ts/@overflow/commons/redux/lpc_reducer.ts
Normal file
35
src/ts/@overflow/commons/redux/lpc_reducer.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import {
|
||||
Action,
|
||||
} from './action';
|
||||
|
||||
class LPCReducer {
|
||||
|
||||
private reducerMap: Map<string, any[]>;
|
||||
|
||||
private constructor() {
|
||||
this.reducerMap = new Map();
|
||||
}
|
||||
|
||||
public reducer<State>(state: State, action: Action): State {
|
||||
let rm: string[] = action.type.split('.');
|
||||
if (null == rm || 2 !== rm.length) {
|
||||
console.log(`Method[${action.type}] is not valid.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const reducerName: string = rm[0];
|
||||
const methodName: string = rm[1];
|
||||
|
||||
if (this.reducerMap.has(reducerName)) {
|
||||
let reducers = this.reducerMap.get(reducerName);
|
||||
for (let reducer of reducers) {
|
||||
|
||||
state = reducer(state, action);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
10
src/ts/@overflow/modules/member/reducer/member_reducer.ts
Normal file
10
src/ts/@overflow/modules/member/reducer/member_reducer.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
export default class MemberReducer {
|
||||
/**
|
||||
* signin
|
||||
*/
|
||||
public signin(state: any, result: any, error: any): any {
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
0
src/ts/@overflow/webapp/config/index.ts
Normal file
0
src/ts/@overflow/webapp/config/index.ts
Normal file
11
src/ts/@overflow/webapp/redux/webapp_reducer.ts
Normal file
11
src/ts/@overflow/webapp/redux/webapp_reducer.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import {
|
||||
LPCReducer,
|
||||
} from '@overflow/commons/redux/lpc_reducer';
|
||||
|
||||
class WebAppReducer extends LPCReducer {
|
||||
private static readonly instance: WebAppReducer = new WebAppReducer();
|
||||
public static getInstance(): WebAppReducer {
|
||||
return WebAppReducer.instance;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user