This commit is contained in:
crusader 2017-12-23 03:09:21 +09:00
parent 100a0060bc
commit 8bea46c526
22 changed files with 443 additions and 83 deletions

View File

@ -0,0 +1,41 @@
import {
ClassType,
} from '@overflow/commons/core/type';
import {
AnnotatedElement,
Annotation,
} from '@overflow/commons/core/reflect';
export abstract class AccessibleObject implements AnnotatedElement {
private _annotations: Map<any, Annotation>;
protected constructor() {
this._annotations = new Map();
}
public _addAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): void {
this._annotations.set((<any>annotation).prototype, annotation);
}
public isAnnotationPresent<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): boolean {
return null !== this.getAnnotation(annotationClass);
}
public getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType {
return <AnnotationType>this._annotations.get(annotationClass.prototype);
}
public getOwnAnnotations(): Map<any, Annotation> {
return this._annotations;
}
public getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType {
return this.getOwnAnnotation(annotationClass);
}
public getAnnotations(): Map<any, Annotation> {
return this.getOwnAnnotations();
}
}

View File

@ -0,0 +1,17 @@
import {
ClassType,
} from '@overflow/commons/core/type';
import {
Annotation,
} from '@overflow/commons/core/reflect';
export interface AnnotatedElement {
_addAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): void;
isAnnotationPresent<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): boolean;
getOwnAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType;
getOwnAnnotations(): Map<any, Annotation>;
getAnnotation<AnnotationType extends Annotation>(annotationClass: ClassType<AnnotationType>): AnnotationType;
getAnnotations(): Map<any, Annotation>;
}

View File

@ -4,15 +4,9 @@ import {
} from '@overflow/commons/core/type';
export interface Annotation {
metadataKey(): MetadataKeyType;
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;

View File

@ -0,0 +1,112 @@
import {
ClassType,
PropertyKeyType,
Metadata,
} from '@overflow/commons/core/type';
import {
AccessibleObject,
Field,
Method,
} from '@overflow/commons/core/reflect';
export class Class extends AccessibleObject {
private _clazzType: ClassType;
private _fields: Map<PropertyKeyType, Field>;
private _methods: Map<PropertyKeyType, Method>;
/**
* forClass
*/
public static forClass(clazzType: ClassType): Class {
return Metadata.get(LOAFER_CLASS, clazzType);
}
/**
* _defineClass
*/
public static _defineClass(clazzType: ClassType): Class {
let clazz: Class = Metadata.get(LOAFER_CLASS, clazzType);
if (undefined === clazz) {
clazz = new Class(clazzType);
Metadata.set(LOAFER_CLASS, clazz, clazzType);
}
return clazz;
}
private constructor(clazzType: ClassType) {
super();
this._clazzType = clazzType;
this._fields = new Map();
this._methods = new Map();
}
/**
* _defineField
*/
public _defineField(propertyKey: PropertyKeyType, propertyType: any): Field {
let field: Field = this._fields.get(propertyKey);
if (undefined === field) {
field = new Field(this, propertyKey, propertyType);
this._fields.set(propertyKey, field);
}
return field;
}
/**
* _defineMethod
*/
public _defineMethod(propertyKey: PropertyKeyType, parameterTypes: any[], returnType: any): Method {
let method: Method = this._methods.get(propertyKey);
if (undefined === method) {
method = new Method(this, propertyKey, parameterTypes, returnType);
this._methods.set(propertyKey, method);
}
return method;
}
public getOwnField(propertyKey: PropertyKeyType): Field {
return this._fields.get(propertyKey);
}
public getOwnFields(): Map<PropertyKeyType, Field> {
return this._fields;
}
public getField(propertyKey: PropertyKeyType): Field {
return null;
}
public getFields(): Field[] {
return null;
}
public getOwnMethod(propertyKey: PropertyKeyType): Method {
return this._methods.get(propertyKey);
}
public getOwnMethods(): Map<PropertyKeyType, Method> {
return this._methods;
}
public getMethod(propertyKey: PropertyKeyType): Method {
return null;
}
public getMethods(): Method[] {
return null;
}
public getName(): string {
return null;
}
}
/**
* Metadata key
* @private
* @type {string}
*/
const LOAFER_CLASS = Symbol('loafer:class');

View File

@ -0,0 +1,19 @@
import {
PropertyKeyType,
} from '@overflow/commons/core/type';
import {
Class,
Executable,
} from '@overflow/commons/core/reflect';
export class Constructor extends Executable {
public constructor(declaringClazz: Class, parameterTypes: any[]) {
super(declaringClazz, parameterTypes);
}
public getName(): PropertyKeyType {
return this.getDeclaringClass().getName();
}
}

View File

@ -0,0 +1,64 @@
import {
PropertyKeyType,
} from '@overflow/commons/core/type';
import {
AccessibleObject,
Class,
Member,
Parameter,
} from '@overflow/commons/core/reflect';
export abstract class Executable extends AccessibleObject implements Member {
private _clazz: Class;
private _parameters: Parameter[];
protected constructor(declaringClazz: Class, parameterTypes: any[]) {
super();
this._clazz = declaringClazz;
if (null === parameterTypes) {
return;
}
this._parameters = [];
for (let i = 0; i < parameterTypes.length; i++) {
const parameterType = parameterTypes[i];
let parameter: Parameter = new Parameter(this, parameterType, i);
this._parameters.push(parameter);
}
}
public getDeclaringClass(): Class {
return this._clazz;
}
public abstract getName(): PropertyKeyType;
/**
* getParameterCount
*/
public getParameterCount(): number {
if (null === this._parameters) {
return 0;
}
return this._parameters.length;
}
/**
* getParameters
*/
public getParameters(): Parameter[] {
return this._parameters;
}
/**
* getParameter
*/
public getParameter(index: number): Parameter {
if (null === this._parameters) {
return null;
}
if (0 > index || this._parameters.length <= index) {
return null;
}
return this._parameters[index];
}
}

View File

@ -0,0 +1,35 @@
import {
PropertyKeyType,
} from '@overflow/commons/core/type';
import {
AccessibleObject,
Class,
Member,
} from '@overflow/commons/core/reflect';
export class Field extends AccessibleObject implements Member {
private _clazz: Class;
private _name: PropertyKeyType;
private _type: any;
public constructor(declaringClazz: Class, name: PropertyKeyType, fieldType: any) {
super();
this._clazz = declaringClazz;
this._name = name;
this._type = fieldType;
}
public getDeclaringClass(): Class {
return this._clazz;
}
public getName(): PropertyKeyType {
return this._name;
}
public getType(): any {
return this._type;
}
}

View File

@ -0,0 +1,10 @@
export * from './accessible_object';
export * from './annotated_element';
export * from './annotation';
export * from './class';
export * from './constructor';
export * from './executable';
export * from './field';
export * from './member';
export * from './method';
export * from './parameter';

View File

@ -0,0 +1,12 @@
import {
Class,
} from '@overflow/commons/core/reflect';
import {
PropertyKeyType,
} from '@overflow/commons/core/type';
export interface Member {
getDeclaringClass(): Class;
getName(): PropertyKeyType;
}

View File

@ -0,0 +1,27 @@
import {
PropertyKeyType,
} from '@overflow/commons/core/type';
import {
Class,
Executable,
} from '@overflow/commons/core/reflect';
export class Method extends Executable {
private _name: PropertyKeyType;
private _returnType: any;
public constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes: any[], returnType: any) {
super(declaringClazz, parameterTypes);
this._name = name;
this._returnType = returnType;
}
public getName(): PropertyKeyType {
return this._name;
}
public getReturnType(): any {
return this._returnType;
}
}

View File

@ -0,0 +1,29 @@
import {
AccessibleObject,
Executable,
} from '@overflow/commons/core/reflect';
export class Parameter extends AccessibleObject {
private _executable: Executable;
private _type: any;
private _index: number;
public constructor(executable: Executable, parameterType: any, index: number) {
super();
this._executable = executable;
this._type = parameterType;
this._index = index;
}
public getDeclaringExecutable(): Executable {
return this._executable;
}
public getType(): any {
return this._type;
}
public getIndex(): number {
return this._index;
}
}

View File

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

View File

@ -1,5 +1,5 @@
import {
ConstructorType,
ClassType,
DecoratorType,
DecoratorParametersType,
PrimitiveType,
@ -12,7 +12,7 @@ export class TypeUtil {
* Get the provide constructor.
* @param targetClass
*/
public static getContructor(targetClass: any): ConstructorType {
public static getContructor(targetClass: any): ClassType {
return typeof targetClass === 'function'
? targetClass
: targetClass.constructor;
@ -23,7 +23,7 @@ export class TypeUtil {
* @param target
* @returns {*}
*/
public static getClass(target: any): any {
public static getClass(target: any): ClassType {
return target.prototype ? target : target.constructor;
}

View File

@ -1 +0,0 @@
export * from './annotation';

View File

@ -1,5 +1,13 @@
import {
ConstructorType,
Annotation,
Class,
Field,
Method,
Parameter,
} from '@overflow/commons/core/reflect';
import {
ClassType,
DecoratorType,
MetadataKeyType,
Metadata,
@ -7,12 +15,10 @@ import {
} from '@overflow/commons/core/type';
import * as Constants from './constants';
import {
Annotation,
} from './annotation';
export class Decorator {
public static create = (AnnotationClass: ConstructorType<Annotation>) => {
public static create = (AnnotationClass: ClassType<Annotation>) => {
return (...handlerArgs: any[]) => {
let annotation: Annotation = new AnnotationClass(...handlerArgs);
@ -23,13 +29,10 @@ export class Decorator {
const [target, propertyKey, descriptorOrParameterIndex] = decoratorArgs;
// let type = typeof decoratorArgs[0] === 'function' ? decoratorArgs[0].prototype : 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);
let clazz: Class = Class._defineClass(TypeUtil.getClass(target));
let field: Field = null;
let method: Method = null;
let parameter: Parameter = null;
switch(decoratorType) {
case DecoratorType.CLASS:
@ -37,24 +40,40 @@ export class Decorator {
throw new Error(`Cannot apply @${name} decorator on Class.`);
}
clazz._addAnnotation(annotation);
return annotation.classDecorator.call(annotation, target);
case DecoratorType.PROPERTY:
if (typeof(annotation.propertyDecorator) === 'undefined') {
throw new Error(`Cannot apply @${name} decorator on Property.`);
}
field = clazz._defineField(propertyKey, Metadata.getOwnType(target, propertyKey));
field._addAnnotation(annotation);
return annotation.propertyDecorator.call(annotation, target, propertyKey);
case DecoratorType.METHOD:
if (typeof(annotation.methodDecorator) === 'undefined') {
throw new Error(`Cannot apply @${name} decorator on Method.`);
}
method = clazz._defineMethod(propertyKey,
Metadata.getOwnParamTypes(target, propertyKey),
Metadata.getOwnReturnType(target, propertyKey));
method._addAnnotation(annotation);
return annotation.methodDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
case DecoratorType.PARAMETER:
if (typeof(annotation.parameterDecorator) === 'undefined') {
throw new Error(`Cannot apply @${name} decorator on Parameter.`);
}
method = clazz._defineMethod(propertyKey,
Metadata.getOwnParamTypes(target, propertyKey),
Metadata.getOwnReturnType(target, propertyKey));
parameter = method.getParameter(descriptorOrParameterIndex);
parameter._addAnnotation(annotation);
return annotation.parameterDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
default:
throw new Error(`Cannot determine decorator[@${name}] type.`);

View File

@ -1,4 +1,2 @@
export * from './constants';
export * from './decorator';
export * from './annotation';

View File

@ -1,3 +1,7 @@
import {
Annotation,
} from '@overflow/commons/core/reflect';
import {
MetadataKeyType,
PropertyKeyType,
@ -5,21 +9,17 @@ import {
} 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 {
export class ActionMappingAnnotation implements Annotation {
public readonly attributes: ActionMappingAnnotationAttributes;
public constructor(value: string | ActionMappingAnnotationAttributes) {
super();
if (undefined === value) {
throw new Error(`value attribute must be specified.`);
@ -34,10 +34,6 @@ export class ActionMappingAnnotation extends Annotation {
}
}
public metadataKey(): MetadataKeyType {
return ActionMappingMetadataKey;
}
public classDecorator<TFunction extends Function>(target: TFunction): TFunction | void {
console.log('ActionMapping');
}

View File

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

View File

@ -1,3 +1,7 @@
import {
Annotation,
} from '@overflow/commons/core/reflect';
import {
MetadataKeyType,
PropertyKeyType,
@ -5,22 +9,17 @@ import {
} from '@overflow/commons/core/type';
import {
Annotation,
Decorator,
} from '@overflow/commons/decorator';
export const RestAPIMetadataKey = Symbol('RestAPIAnnotation');
export interface RestAPIAnnotationAttributes {
entryPath: string;
}
export class RestAPIAnnotation extends Annotation {
export class RestAPIAnnotation implements Annotation {
public readonly attributes: RestAPIAnnotationAttributes;
public constructor(entryPath: string | RestAPIAnnotationAttributes) {
super();
if (undefined === entryPath) {
throw new Error(`entryPath attribute must be specified.`);
}
@ -34,10 +33,6 @@ export class RestAPIAnnotation extends Annotation {
}
}
public metadataKey(): MetadataKeyType {
return RestAPIMetadataKey;
}
public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType,
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void {
console.log('RestAPI');

View File

@ -1,3 +1,7 @@
import {
Annotation,
} from '@overflow/commons/core/reflect';
import {
MetadataKeyType,
PropertyKeyType,
@ -5,22 +9,17 @@ import {
} from '@overflow/commons/core/type';
import {
Annotation,
Decorator,
} from '@overflow/commons/decorator';
export const RpcAPIMetadataKey = Symbol('RpcAPIAnnotation');
export interface RpcAPIAnnotationAttributes {
method: string;
}
export class RpcAPIAnnotation extends Annotation {
export class RpcAPIAnnotation implements Annotation {
public readonly attributes: RpcAPIAnnotationAttributes;
public constructor(method: string | RpcAPIAnnotationAttributes) {
super();
if (undefined === method) {
throw new Error(`method attribute must be specified.`);
}
@ -34,10 +33,6 @@ export class RpcAPIAnnotation extends Annotation {
}
}
public metadataKey(): MetadataKeyType {
return RpcAPIMetadataKey;
}
public methodDecorator<T>(target: Object, propertyKey: PropertyKeyType,
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void {
console.log('RestAPI');

View File

@ -1,17 +1,17 @@
import {
Action,
} from './action';
import {
ConstructorType,
ClassType,
Metadata,
TypeUtil,
} from '@overflow/commons/core/type';
import {
ActionMappingAnnotation,
ActionMappingMetadataKey,
ReducerMetadataKey,
ReducerAnnotation,
RestAPIAnnotation,
RpcAPIAnnotation,
} from '@overflow/commons/redux/decorators';
import { Class } from '@overflow/commons/core/reflect';
import { Action } from '@overflow/commons/redux/action';
export default class LPCReducer {
@ -45,27 +45,31 @@ export default class LPCReducer {
/**
* registerReducers
*/
public registerReducers(reducerTypes: ConstructorType[]): void {
public registerReducers(reducerTypes: ClassType[]): void {
for (let reducerType of reducerTypes) {
let ra: ReducerAnnotation = Metadata.get(ReducerMetadataKey, reducerType);
let clazz: Class = Class.forClass(reducerType);
let ra: ReducerAnnotation = clazz.getOwnAnnotation(ReducerAnnotation);
if (undefined === ra) {
continue;
}
console.log(`name: ${ra.attributes.name}`);
let ama: ActionMappingAnnotation = Metadata.get(ActionMappingMetadataKey, reducerType);
let ama: ActionMappingAnnotation = clazz.getOwnAnnotation(ActionMappingAnnotation);
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;
clazz.getMethods().forEach(method => {
let restAPIAnnotation: RestAPIAnnotation = method.getOwnAnnotation(RestAPIAnnotation);
let rpcAPIAnnotation: RpcAPIAnnotation = method.getOwnAnnotation(RpcAPIAnnotation);
if (restAPIAnnotation) {
console.log(`restAPI: ${restAPIAnnotation.attributes.entryPath}`);
}
console.log(`method: ${propertyKey}`);
if (rpcAPIAnnotation) {
console.log(`restAPI: ${rpcAPIAnnotation.attributes.method}`);
}
});
}
}
@ -73,7 +77,7 @@ export default class LPCReducer {
/**
* registerReducer
*/
public registerReducer(reducerType: ConstructorType): void {
public registerReducer(reducerType: ClassType): void {
console.log(``);
}

View File

@ -7,7 +7,6 @@ import {
@Reducer()
@ActionMapping('@overflow/modules/member/MemberReducer')
export default class MemberReducer {
public path: string;
/**
* signin
*/