This commit is contained in:
crusader 2017-12-21 19:11:10 +09:00
parent 88a2218e17
commit 100a0060bc
15 changed files with 589 additions and 415 deletions

View File

@ -1,8 +1,9 @@
import { import {
MetadataKeyType,
PropertyKeyType, PropertyKeyType,
} from './type'; } from './type';
import * as Util from './util'; import {TypeUtil} from './util';
export class Metadata { export class Metadata {
@ -41,8 +42,8 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static get(key: string, target: any, propertyKey?: PropertyKeyType): any { public static get(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any {
return Reflect.getMetadata(key, Util.getClass(target), propertyKey!); return Reflect.getMetadata(key, TypeUtil.getClass(target), propertyKey!);
} }
/** /**
@ -80,8 +81,8 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getOwn(key: string, target: any, propertyKey?: string | symbol): any { public static getOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): any {
return Reflect.getOwnMetadata(key, Util.getClass(target), propertyKey!); return Reflect.getOwnMetadata(key, TypeUtil.getClass(target), propertyKey!);
} }
/** /**
@ -112,7 +113,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getType(target: any, propertyKey?: string | symbol): any { public static getType(target: any, propertyKey?: PropertyKeyType): any {
return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey!); return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey!);
} }
@ -144,7 +145,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getOwnType(target: any, propertyKey?: string | symbol): any { public static getOwnType(target: any, propertyKey?: PropertyKeyType): any {
return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey!); return Reflect.getMetadata(DESIGN_TYPE, target, propertyKey!);
} }
@ -176,7 +177,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getReturnType(target: any, propertyKey?: string | symbol): any { public static getReturnType(target: any, propertyKey?: PropertyKeyType): any {
return Reflect.getMetadata(DESIGN_RETURN_TYPE, target, propertyKey!); return Reflect.getMetadata(DESIGN_RETURN_TYPE, target, propertyKey!);
} }
@ -208,7 +209,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getOwnReturnType(target: any, propertyKey?: string | symbol): any { public static getOwnReturnType(target: any, propertyKey?: PropertyKeyType): any {
return Reflect.getOwnMetadata(DESIGN_RETURN_TYPE, target, propertyKey!); return Reflect.getOwnMetadata(DESIGN_RETURN_TYPE, target, propertyKey!);
} }
@ -247,8 +248,8 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static has(key: string, target: any, propertyKey?: string | symbol): boolean { public static has(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
return Reflect.hasMetadata(key, Util.getClass(target), propertyKey!); return Reflect.hasMetadata(key, TypeUtil.getClass(target), propertyKey!);
} }
/** /**
@ -286,8 +287,8 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static hasOwn(key: string, target: any, propertyKey?: string | symbol): boolean { public static hasOwn(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
return Reflect.hasOwnMetadata(key, Util.getClass(target), propertyKey!); return Reflect.hasOwnMetadata(key, TypeUtil.getClass(target), propertyKey!);
} }
/** /**
@ -325,8 +326,8 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static delete(key: string, target: any, propertyKey?: string | symbol): boolean { public static delete(key: MetadataKeyType, target: any, propertyKey?: PropertyKeyType): boolean {
return Reflect.deleteMetadata(key, Util.getClass(target), propertyKey!); return Reflect.deleteMetadata(key, TypeUtil.getClass(target), propertyKey!);
} }
/** /**
@ -364,7 +365,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static setParamTypes(target: any, propertyKey: string | symbol, value: any): void { public static setParamTypes(target: any, propertyKey: PropertyKeyType, value: any): void {
return this.set(DESIGN_PARAM_TYPES, value, target.prototype, propertyKey); return this.set(DESIGN_PARAM_TYPES, value, target.prototype, propertyKey);
} }
@ -372,7 +373,7 @@ export class Metadata {
* Get all metadata for a metadataKey. * Get all metadata for a metadataKey.
* @param metadataKey * @param metadataKey
*/ */
public static getTargetsFromPropertyKey = (metadataKey: string | symbol): any[] => public static getTargetsFromPropertyKey = (metadataKey: MetadataKeyType): any[] =>
PROPERTIES.has(metadataKey) ? PROPERTIES.get(metadataKey) || [] : [] PROPERTIES.has(metadataKey) ? PROPERTIES.get(metadataKey) || [] : []
/** /**
@ -415,17 +416,17 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static set(key: string, value: any, target: any, propertyKey?: string | symbol): void { public static set(key: MetadataKeyType, value: any, target: any, propertyKey?: PropertyKeyType): void {
const targets: any[] = PROPERTIES.has(key) ? PROPERTIES.get(key) || [] : []; const targets: any[] = PROPERTIES.has(key) ? PROPERTIES.get(key) || [] : [];
const classConstructor = Util.getClass(target); const classConstructor = TypeUtil.getClass(target);
if (targets.indexOf(classConstructor) === -1) { if (targets.indexOf(classConstructor) === -1) {
targets.push(classConstructor); targets.push(classConstructor);
PROPERTIES.set(key, targets); PROPERTIES.set(key, targets);
} }
Reflect.defineMetadata(key, value, Util.getClass(target), propertyKey!); Reflect.defineMetadata(key, value, TypeUtil.getClass(target), propertyKey!);
} }
/** /**
@ -456,7 +457,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getParamTypes(target: any, propertyKey?: string | symbol): any[] { public static getParamTypes(target: any, propertyKey?: PropertyKeyType): any[] {
return Reflect.getMetadata(DESIGN_PARAM_TYPES, target, propertyKey!) || []; return Reflect.getMetadata(DESIGN_PARAM_TYPES, target, propertyKey!) || [];
} }
@ -488,7 +489,7 @@ export class Metadata {
* ``` * ```
* *
*/ */
public static getOwnParamTypes(target: any, propertyKey?: string | symbol): any[] { public static getOwnParamTypes(target: any, propertyKey?: PropertyKeyType): any[] {
return Reflect.getOwnMetadata(DESIGN_PARAM_TYPES, target, propertyKey!) || []; return Reflect.getOwnMetadata(DESIGN_PARAM_TYPES, target, propertyKey!) || [];
} }
} }
@ -517,4 +518,4 @@ const DESIGN_RETURN_TYPE = 'design:returntype';
* @private * @private
* @type {string} * @type {string}
*/ */
const PROPERTIES: Map<string | symbol, any[]> = new Map<string | symbol, any[]>(); const PROPERTIES: Map<MetadataKeyType, any[]> = new Map<MetadataKeyType, any[]>();

View File

@ -1,8 +1,9 @@
export type IdentityType<T> = T | symbol; export type IdentityType<T> = T | symbol;
export type PropertyKeyType = IdentityType<string>; export type PropertyKeyType = IdentityType<string>;
export type MetadataKeyType = IdentityType<string>;
export const Type = Function; export const ConstructorType = Function;
export interface Type<T> extends Function { export interface ConstructorType<T = {}> extends Function {
new (...args: any[]): T; new (...args: any[]): T;
} }

View File

@ -1,390 +1,408 @@
import { import {
ConstructorType,
DecoratorType, DecoratorType,
DecoratorParametersType, DecoratorParametersType,
PrimitiveType, PrimitiveType,
PropertyKeyType, PropertyKeyType,
} from './type'; } from './type';
/**
* Get the provide constructor. export class TypeUtil {
* @param targetClass /**
*/ * Get the provide constructor.
export const getContructor = (targetClass: any): Function => * @param targetClass
typeof targetClass === 'function' */
public static getContructor(targetClass: any): ConstructorType {
return typeof targetClass === 'function'
? targetClass ? targetClass
: targetClass.constructor; : 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 {PrimitiveType}
*/
export function primitiveOf(target: any): PrimitiveType {
if (isString(target)) {
return PrimitiveType.STRING;
}
if (isNumber(target)) {
return PrimitiveType.NUMBER;
}
if (isBoolean(target)) {
return PrimitiveType.BOOLEAN;
}
return PrimitiveType.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; * Get the provide constructor if target is an instance.
* @param target
* @returns {*}
*/
public static getClass(target: any): any {
return target.prototype ? target : target.constructor;
} }
if (isArrayOrArrayClass(obj)) { /**
out = out || []; *
} else { * @param target
out = out || {}; * @returns {symbol}
*/
public static getClassOrSymbol(target: any): any {
return typeof target === 'symbol' ? target : TypeUtil.getClass(target);
} }
const defaultReducer = reducers.default ? reducers.default : (collection: any[], value: any) => { /**
collection.push(value); * Return true if the given obj is a primitive.
return collection; * @param target
}; * @returns {boolean}
const set = (key: string | number, value: any) => { */
if (isArrayOrArrayClass(obj)) { public static isPrimitiveOrPrimitiveClass(target: any): boolean {
out.push(value); return TypeUtil.isString(target)
} else { || TypeUtil.isNumber(target)
out[key] = value; || TypeUtil.isBoolean(target);
}
};
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 {PrimitiveType}
* */
* @param target public static primitiveOf(target: any): PrimitiveType {
* @returns {boolean} if (TypeUtil.isString(target)) {
*/ return PrimitiveType.STRING;
export function isPromise(target: any): boolean { }
return target === Promise || target instanceof Promise; if (TypeUtil.isNumber(target)) {
} return PrimitiveType.NUMBER;
}
/** if (TypeUtil.isBoolean(target)) {
* return PrimitiveType.BOOLEAN;
* @param target }
* @returns {any} return PrimitiveType.ANY;
*/
export function getInheritedClass(target: any): any {
return Object.getPrototypeOf(target);
}
/**
*
* @param {any[]} args
* @returns {DecoratorType}
*/
export function getDecoratorType(args: any[]): DecoratorType {
const [, propertyKey, descriptor] = args;
if (typeof descriptor === 'number') {
return DecoratorType.PARAMETER;
} }
if (propertyKey && descriptor === undefined || descriptor && (descriptor.get || descriptor.set)) { /**
return DecoratorType.PROPERTY; *
} * @param target
return (descriptor && descriptor.value) ? DecoratorType.METHOD : DecoratorType.CLASS; * @returns {boolean}
} */
public static isString(target: any): boolean {
/** return typeof target === 'string' || target instanceof String || target === String;
* }
* @param target
* @param {PropertyKeyType} propertyKey /**
* @returns {PropertyDescriptor} *
*/ * @param target
export function descriptorOf(target: any, propertyKey: PropertyKeyType): PropertyDescriptor { * @returns {boolean}
return Object.getOwnPropertyDescriptor(target && target.prototype || target, propertyKey)!; */
} public static isNumber(target: any): boolean {
return typeof target === 'number' || target instanceof Number || target === Number;
/** }
*
* @param target /**
* @param {string} propertyKey *
* @returns {DecoratorParametersType} * @param target
*/ * @returns {boolean}
export function decoratorArgs(target: any, propertyKey: string): DecoratorParametersType { */
return [ public static isBoolean(target: any): boolean {
target, return typeof target === 'boolean' || target instanceof Boolean || target === Boolean;
propertyKey, }
descriptorOf(target, propertyKey)!,
]; /**
} *
* @param target
/** * @returns {Boolean}
* */
* @param target public static isArray(target: any): boolean {
* @returns {Array} return Array.isArray(target);
*/ }
export function ancestorsOf(target: any): any[] {
const classes = []; /**
* Return true if the clazz is an array.
let currentTarget = getClass(target); * @param target
* @returns {boolean}
while (nameOf(currentTarget) !== '') { */
classes.unshift(currentTarget); public static isArrayOrArrayClass(target: any): boolean {
currentTarget = getInheritedClass(currentTarget); if (target === Array) {
return true;
}
return TypeUtil.isArray(target);
}
/**
* Return true if the target.
* @param target
* @returns {boolean}
*/
public static isCollection(target: any): boolean {
return TypeUtil.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}
*/
public static isDate(target: any): boolean {
return target === Date || target instanceof Date;
}
/**
*
* @param target
* @returns {boolean}
*/
public static isMethod(target: any, propertyKey: PropertyKeyType): boolean {
if (typeof(target[propertyKey]) === undefined) {
return false;
}
return typeof target[propertyKey] === 'function';
}
/**
*
* @param target
* @returns {boolean}
*/
public static isObject(target: any): boolean {
return target === Object;
}
/**
*
* @param target
* @returns {boolean}
*/
public static isClass(target: any): boolean {
return !TypeUtil.isPrimitiveOrPrimitiveClass(target)
&& !TypeUtil.isObject(target)
&& !TypeUtil.isDate(target)
&& target !== undefined
&& !TypeUtil.isPromise(target);
}
/**
* Return true if the value is an empty string, null or undefined.
* @param value
* @returns {boolean}
*/
public static isEmpty(value: any): boolean {
return value === '' || value === null || value === undefined;
}
/**
* Get object name
*/
public static nameOf(obj: any): string {
switch (typeof obj) {
default:
return '' + obj;
case 'symbol':
return TypeUtil.nameOfSymbol(obj);
case 'function':
return TypeUtil.nameOfClass(obj);
}
}
/**
* Get the provide name.
* @param targetClass
*/
public static nameOfClass(targetClass: any): string {
return typeof targetClass === 'function'
? targetClass.name
: targetClass.constructor.name;
}
/**
* Get symbol name.
* @param sym
*/
public static nameOfSymbol(sym: symbol): string {
return sym.toString().replace('Symbol(', '').replace(')', '');
}
/**
*
* @param out
* @param obj
* @param {{[p: string]: (collection: any[], value: any) => any}} reducers
* @returns {any}
*/
public static deepExtends(out: any, obj: any, reducers: { [key: string]: (collection: any[], value: any) => any } = {}): any {
if (obj === undefined || obj === null) {
return obj;
}
if (TypeUtil.isPrimitiveOrPrimitiveClass(obj) || typeof obj === 'symbol' || typeof obj === 'function') {
return obj;
}
if (TypeUtil.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 (TypeUtil.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 (TypeUtil.isPrimitiveOrPrimitiveClass(value) || typeof value === 'function') {
set(key, value);
return;
}
if (TypeUtil.isArrayOrArrayClass(value)) {
value = value.map((v: any) => TypeUtil.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 (TypeUtil.isArrayOrArrayClass(obj)) {
set(key, TypeUtil.deepExtends(undefined, value, reducers));
} else {
set(key, TypeUtil.deepExtends(out[key], value, reducers));
}
});
if (TypeUtil.isArrayOrArrayClass(out)) {
out.reduce((collection: any[], value: any) => defaultReducer(collection, value), []);
}
return out;
}
/**
*
* @param target
* @returns {boolean}
*/
public static isPromise(target: any): boolean {
return target === Promise || target instanceof Promise;
}
/**
*
* @param target
* @returns {any}
*/
public static getInheritedClass(target: any): any {
return Object.getPrototypeOf(target);
}
/**
*
* @param {any[]} args
* @returns {DecoratorType}
*/
public static getDecoratorType(args: any[]): DecoratorType {
const [, propertyKey, descriptor] = args;
if (typeof descriptor === 'number') {
return DecoratorType.PARAMETER;
}
if (propertyKey && descriptor === undefined || descriptor && (descriptor.get || descriptor.set)) {
return DecoratorType.PROPERTY;
}
return (descriptor && descriptor.value) ? DecoratorType.METHOD : DecoratorType.CLASS;
}
/**
*
* @param target
* @param {PropertyKeyType} propertyKey
* @returns {PropertyDescriptor}
*/
public static descriptorOf(target: any, propertyKey: PropertyKeyType): PropertyDescriptor {
return Object.getOwnPropertyDescriptor(target && target.prototype || target, propertyKey)!;
}
/**
*
* @param target
* @param {string} propertyKey
* @returns {DecoratorParametersType}
*/
public static decoratorArgs(target: any, propertyKey: string): DecoratorParametersType {
return [
target,
propertyKey,
TypeUtil.descriptorOf(target, propertyKey)!,
];
}
/**
*
* @param target
* @returns {Array}
*/
public static ancestorsOf(target: any): any[] {
const classes = [];
let currentTarget = TypeUtil.getClass(target);
while (TypeUtil.nameOf(currentTarget) !== '') {
classes.unshift(currentTarget);
currentTarget = TypeUtil.getInheritedClass(currentTarget);
}
return classes;
}
/**
*
* @param target
* @param {string} name
* @param {Function} callback
*/
public static 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>}
*/
public static 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),
]);
} }
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),
]);
} }

View File

@ -1,8 +1,10 @@
import { import {
MetadataKeyType,
PropertyKeyType, PropertyKeyType,
} from '@overflow/commons/core/type'; } from '@overflow/commons/core/type';
export interface Annotation { export interface Annotation {
metadataKey(): MetadataKeyType;
classDecorator?<TFunction extends Function>(target: TFunction): TFunction | void; classDecorator?<TFunction extends Function>(target: TFunction): TFunction | void;
propertyDecorator?(target: Object, propertyKey: PropertyKeyType): void; propertyDecorator?(target: Object, propertyKey: PropertyKeyType): void;
methodDecorator?<T>(target: Object, propertyKey: PropertyKeyType, methodDecorator?<T>(target: Object, propertyKey: PropertyKeyType,

View File

@ -1,17 +1,18 @@
import { import {
ConstructorType,
DecoratorType, DecoratorType,
Type, MetadataKeyType,
Metadata,
TypeUtil,
} from '@overflow/commons/core/type'; } from '@overflow/commons/core/type';
import * as TypeUtil from '@overflow/commons/core/type/util';
import * as Constants from './constants'; import * as Constants from './constants';
import { import {
Annotation, Annotation,
} from './annotation'; } from './annotation';
export class Decorator { export class Decorator {
public static create = (AnnotationClass: Type<Annotation>) => { public static create = (AnnotationClass: ConstructorType<Annotation>) => {
return (...handlerArgs: any[]) => { return (...handlerArgs: any[]) => {
let annotation: Annotation = new AnnotationClass(...handlerArgs); let annotation: Annotation = new AnnotationClass(...handlerArgs);
@ -20,8 +21,15 @@ export class Decorator {
return (...decoratorArgs: any[]) => { return (...decoratorArgs: any[]) => {
let decoratorType: DecoratorType = TypeUtil.getDecoratorType(decoratorArgs); let decoratorType: DecoratorType = TypeUtil.getDecoratorType(decoratorArgs);
const [target, propertyKey, descriptorOrParameterIndex] = decoratorArgs;
// let type = typeof decoratorArgs[0] === 'function' ? decoratorArgs[0].prototype : decoratorArgs[0]; // let type = typeof decoratorArgs[0] === 'function' ? decoratorArgs[0].prototype : decoratorArgs[0];
// let clazz = TypeUtil.getClass(decoratorArgs[0]); // let clazz = TypeUtil.getClass(decoratorArgs[0]);
if (typeof(annotation.metadataKey) === 'undefined') {
throw new Error(`Annotation[@${name}] must be implements metadataKey().`);
}
let metadataKey: MetadataKeyType = annotation.metadataKey.call(annotation);
Metadata.set(metadataKey, annotation, target, propertyKey);
switch(decoratorType) { switch(decoratorType) {
case DecoratorType.CLASS: case DecoratorType.CLASS:
@ -29,26 +37,27 @@ export class Decorator {
throw new Error(`Cannot apply @${name} decorator on Class.`); throw new Error(`Cannot apply @${name} decorator on Class.`);
} }
return annotation.classDecorator.call(annotation, decoratorArgs[0]); return annotation.classDecorator.call(annotation, target);
case DecoratorType.PROPERTY: case DecoratorType.PROPERTY:
if (typeof(annotation.propertyDecorator) === 'undefined') { if (typeof(annotation.propertyDecorator) === 'undefined') {
throw new Error(`Cannot apply @${name} decorator on Property.`); throw new Error(`Cannot apply @${name} decorator on Property.`);
} }
return annotation.propertyDecorator.call(annotation, decoratorArgs[0], decoratorArgs[1]); return annotation.propertyDecorator.call(annotation, target, propertyKey);
case DecoratorType.METHOD: case DecoratorType.METHOD:
if (typeof(annotation.methodDecorator) === 'undefined') { if (typeof(annotation.methodDecorator) === 'undefined') {
throw new Error(`Cannot apply @${name} decorator on Method.`); throw new Error(`Cannot apply @${name} decorator on Method.`);
} }
return annotation.methodDecorator.call(annotation, decoratorArgs[0], decoratorArgs[1], decoratorArgs[2]); return annotation.methodDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
case DecoratorType.PARAMETER: case DecoratorType.PARAMETER:
if (typeof(annotation.parameterDecorator) === 'undefined') { if (typeof(annotation.parameterDecorator) === 'undefined') {
throw new Error(`Cannot apply @${name} decorator on Parameter.`); throw new Error(`Cannot apply @${name} decorator on Parameter.`);
} }
return annotation.parameterDecorator.call(annotation, decoratorArgs[0], decoratorArgs[1], decoratorArgs[2]); return annotation.parameterDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
default: default:
throw new Error(`Cannot determine decorator[@${name}] type.`);
} }
}; };
}; };

View File

@ -0,0 +1,52 @@
import {
MetadataKeyType,
PropertyKeyType,
TypeUtil,
} from '@overflow/commons/core/type';
import {
Annotation,
Decorator,
} from '@overflow/commons/decorator';
export const ActionMappingMetadataKey = Symbol('ActionMappingAnnotation');
export interface ActionMappingAnnotationAttributes {
value: string;
}
export class ActionMappingAnnotation extends Annotation {
public readonly attributes: ActionMappingAnnotationAttributes;
public constructor(value: string | ActionMappingAnnotationAttributes) {
super();
if (undefined === value) {
throw new Error(`value attribute must be specified.`);
}
if (TypeUtil.isString(value)) {
this.attributes = {
value: <string>value,
};
} else {
this.attributes = <ActionMappingAnnotationAttributes>value;
}
}
public metadataKey(): MetadataKeyType {
return ActionMappingMetadataKey;
}
public classDecorator<TFunction extends Function>(target: TFunction): TFunction | void {
console.log('ActionMapping');
}
public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType,
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void {
console.log('ActionMapping');
}
}
export const ActionMapping = Decorator.create(ActionMappingAnnotation);

View File

@ -1,3 +1,4 @@
export * from './action_mapping';
export * from './reducer'; export * from './reducer';
export * from './rest_api'; export * from './rest_api';
export * from './rpc_api'; export * from './rpc_api';

View File

@ -1,13 +1,17 @@
import * as TypeUtil from '@overflow/commons/core/type/util'; import {
MetadataKeyType,
TypeUtil,
} from '@overflow/commons/core/type';
import { import {
Annotation, Annotation,
Decorator, Decorator,
} from '@overflow/commons/decorator'; } from '@overflow/commons/decorator';
export const ReducerMetadataKey = Symbol('ReducerAnnotation');
export interface ReducerAnnotationAttributes { export interface ReducerAnnotationAttributes {
name: string; name?: string;
} }
export class ReducerAnnotation extends Annotation { export class ReducerAnnotation extends Annotation {
@ -15,6 +19,14 @@ export class ReducerAnnotation extends Annotation {
public constructor(name: string | ReducerAnnotationAttributes) { public constructor(name: string | ReducerAnnotationAttributes) {
super(); super();
if (undefined === name) {
this.attributes = {
name: '',
};
return;
}
if (TypeUtil.isString(name)) { if (TypeUtil.isString(name)) {
this.attributes = { this.attributes = {
name: <string>name, name: <string>name,
@ -24,6 +36,10 @@ export class ReducerAnnotation extends Annotation {
} }
} }
public metadataKey(): MetadataKeyType {
return ReducerMetadataKey;
}
public classDecorator<TFunction extends Function>(target: TFunction): TFunction | void { public classDecorator<TFunction extends Function>(target: TFunction): TFunction | void {
console.log('Reducer'); console.log('Reducer');
} }

View File

@ -1,9 +1,15 @@
import * as TypeUtil from '@overflow/commons/core/type/util'; import {
MetadataKeyType,
PropertyKeyType,
TypeUtil,
} from '@overflow/commons/core/type';
import { import {
Annotation, Annotation,
Decorator, Decorator,
} from '@overflow/commons/decorator'; } from '@overflow/commons/decorator';
import { PropertyKeyType } from '@overflow/commons/core/type';
export const RestAPIMetadataKey = Symbol('RestAPIAnnotation');
export interface RestAPIAnnotationAttributes { export interface RestAPIAnnotationAttributes {
entryPath: string; entryPath: string;
@ -14,6 +20,11 @@ export class RestAPIAnnotation extends Annotation {
public constructor(entryPath: string | RestAPIAnnotationAttributes) { public constructor(entryPath: string | RestAPIAnnotationAttributes) {
super(); super();
if (undefined === entryPath) {
throw new Error(`entryPath attribute must be specified.`);
}
if (TypeUtil.isString(entryPath)) { if (TypeUtil.isString(entryPath)) {
this.attributes = { this.attributes = {
entryPath: <string>entryPath, entryPath: <string>entryPath,
@ -23,6 +34,10 @@ export class RestAPIAnnotation extends Annotation {
} }
} }
public metadataKey(): MetadataKeyType {
return RestAPIMetadataKey;
}
public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType, public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType,
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void { descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void {
console.log('RestAPI'); console.log('RestAPI');

View File

@ -1,9 +1,15 @@
import * as TypeUtil from '@overflow/commons/core/type/util'; import {
MetadataKeyType,
PropertyKeyType,
TypeUtil,
} from '@overflow/commons/core/type';
import { import {
Annotation, Annotation,
Decorator, Decorator,
} from '@overflow/commons/decorator'; } from '@overflow/commons/decorator';
import { PropertyKeyType } from '@overflow/commons/core/type';
export const RpcAPIMetadataKey = Symbol('RpcAPIAnnotation');
export interface RpcAPIAnnotationAttributes { export interface RpcAPIAnnotationAttributes {
method: string; method: string;
@ -14,6 +20,11 @@ export class RpcAPIAnnotation extends Annotation {
public constructor(method: string | RpcAPIAnnotationAttributes) { public constructor(method: string | RpcAPIAnnotationAttributes) {
super(); super();
if (undefined === method) {
throw new Error(`method attribute must be specified.`);
}
if (TypeUtil.isString(method)) { if (TypeUtil.isString(method)) {
this.attributes = { this.attributes = {
method: <string>method, method: <string>method,
@ -23,6 +34,10 @@ export class RpcAPIAnnotation extends Annotation {
} }
} }
public metadataKey(): MetadataKeyType {
return RpcAPIMetadataKey;
}
public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType, public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType,
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void { descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void {
console.log('RestAPI'); console.log('RestAPI');

View File

@ -1,6 +1,17 @@
import { import {
Action, Action,
} from './action'; } from './action';
import {
ConstructorType,
Metadata,
TypeUtil,
} from '@overflow/commons/core/type';
import {
ActionMappingAnnotation,
ActionMappingMetadataKey,
ReducerMetadataKey,
ReducerAnnotation,
} from '@overflow/commons/redux/decorators';
export default class LPCReducer { export default class LPCReducer {
@ -32,11 +43,38 @@ export default class LPCReducer {
} }
/** /**
* registerReducer * registerReducers
*/ */
public registerReducer(reducerType: any): void { public registerReducers(reducerTypes: ConstructorType[]): void {
console.log(``); for (let reducerType of reducerTypes) {
let ra: ReducerAnnotation = Metadata.get(ReducerMetadataKey, reducerType);
if (undefined === ra) {
continue;
}
console.log(`name: ${ra.attributes.name}`);
let ama: ActionMappingAnnotation = Metadata.get(ActionMappingMetadataKey, reducerType);
if (undefined === ama) {
continue;
}
console.log(`actionMapping-value: ${ama.attributes.value}`);
let properties = Object.keys(reducerType.prototype);
for (let propertyKey of properties) {
if (!TypeUtil.isMethod(reducerType.prototype, propertyKey)) {
console.log(`property: ${propertyKey}`);
continue;
}
console.log(`method: ${propertyKey}`);
}
}
} }
/**
* registerReducer
*/
public registerReducer(reducerType: ConstructorType): void {
console.log(``);
}
} }

View File

@ -1,14 +1,18 @@
import { import {
ActionMapping,
Reducer, Reducer,
RestAPI, RestAPI,
} from '@overflow/commons/redux/decorators'; } from '@overflow/commons/redux/decorators';
@Reducer('@overflow/modules/member/MemberReducer') @Reducer()
@ActionMapping('@overflow/modules/member/MemberReducer')
export default class MemberReducer { export default class MemberReducer {
public path: string;
/** /**
* signin * signin
*/ */
@RestAPI('/account/signin') @RestAPI('/account/signin')
@ActionMapping('/signin')
public signin(state: any, result: any, error: any): any { public signin(state: any, result: any, error: any): any {
return state; return state;

View File

@ -1,7 +1,8 @@
import { ConstructorType } from '@overflow/commons/core/type';
import MemberReducer from '@overflow/modules/member/reducer/member_reducer'; import MemberReducer from '@overflow/modules/member/reducer/member_reducer';
const reducers: any[] = [ const reducers: ConstructorType[] = [
MemberReducer, MemberReducer,
]; ];
@ -11,7 +12,7 @@ const state: any = {
export interface ReduxConfig { export interface ReduxConfig {
state: any; state: any;
reducers: any[]; reducers: ConstructorType[];
} }
const reduxConfig: ReduxConfig = { const reduxConfig: ReduxConfig = {

View File

@ -58,6 +58,7 @@ class WebAppApplication {
try { try {
this.renderLoading(); this.renderLoading();
let reducer: WebAppReducer = WebAppReducer.getInstance(); let reducer: WebAppReducer = WebAppReducer.getInstance();
reducer.registerReducers(config.redux.reducers);
this.store = createStore(reducer.reducer, config.redux.state); this.store = createStore(reducer.reducer, config.redux.state);
this.renderApp(); this.renderApp();

View File

@ -14,7 +14,7 @@ class WebApp extends React.Component<Props, State> {
public render(): JSX.Element { public render(): JSX.Element {
return ( return (
<b>Hello...</b> <b>Hello.</b>
); );
} }
} }