This commit is contained in:
crusader 2018-05-21 00:24:19 +09:00
parent a5e0efff15
commit da4e5c50a8
6 changed files with 327 additions and 5880 deletions

5884
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,11 @@ export interface Decorator<Attribute = {}> {
parameterDecorator?: (target: Object, propertyKey: PropertyKeyType, parameterIndex: number) => void;
}
export abstract class Decorator<Attribute = {}> extends Annotation<Attribute> {
export abstract class Decorator<Attribute = {}> extends Annotation {
public readonly attribute: Attribute;
public constructor(attribute?: Attribute) {
super(attribute);
super();
this.attribute = attribute;
}
}

View File

@ -1,105 +0,0 @@
import {
Type,
} from '@loafer/core';
import {
Class,
Constructor,
Field,
Method,
Parameter,
Metadata,
} from '@loafer/core/reflect';
import {
TypeUtil,
} from '@loafer/core/util/TypeUtil';
import { Decorator } from './Decorator';
import { DecoratorUtil } from './util';
import { DecoratorType } from './type';
import { NotSupportedDecoratorError } from './error';
export class DecoratorFactory {
public static create = <Attribute = {}>(DecoratorClass: Type<Decorator<Attribute>>) => {
return (attribute: Attribute) => {
const annotation: Decorator<Attribute> = new DecoratorClass(attribute);
const name: string = DecoratorClass.name;
return (...decoratorArgs: any[]) => {
const decoratorType: DecoratorType = DecoratorUtil.getDecoratorType(decoratorArgs);
const [target, propertyKey, descriptorOrParameterIndex] = decoratorArgs;
const clazz: Class = Class._defineClass(TypeUtil.getType(target));
let field: Field = null;
let method: Method = null;
let parameter: Parameter = null;
let cons: Constructor = null;
switch (decoratorType) {
case DecoratorType.CLASS:
try {
cons = clazz._defineConstructor(Metadata.getOwnParamTypes(target));
clazz._addAnnotation(annotation);
return annotation.classDecorator.call(annotation, target);
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Class.`);
}
throw e;
}
case DecoratorType.PROPERTY:
try {
field = clazz._defineField(propertyKey, Metadata.getOwnType(target, propertyKey));
field._addAnnotation(annotation);
return annotation.propertyDecorator.call(annotation, target, propertyKey);
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Property.`);
}
throw e;
}
case DecoratorType.METHOD:
try {
method = clazz._defineMethod(propertyKey,
Metadata.getOwnParamTypes(target, propertyKey),
Metadata.getOwnReturnType(target, propertyKey));
method._addAnnotation(annotation);
return annotation.methodDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Method.`);
}
throw e;
}
case DecoratorType.PARAMETER:
try {
if (undefined === propertyKey) {
cons = clazz.getConstructor();
parameter = cons.getParameter(descriptorOrParameterIndex);
} else {
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);
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Parameter.`);
}
throw e;
}
default:
throw new NotSupportedDecoratorError(`Cannot determine decorator[@${name}] type.`);
}
};
};
}
}

160
src/DecoratorHelper.ts Normal file
View File

@ -0,0 +1,160 @@
import {
Type,
PropertyKeyType,
} from '@loafer/core';
import {
Annotation,
Class,
Constructor,
Field,
Method,
Parameter,
Metadata,
} from '@loafer/core/reflect';
import {
TypeUtil,
} from '@loafer/core/util/TypeUtil';
import { Decorator } from './Decorator';
import { DecoratorType, DecoratorParametersType } from './type';
import { NotSupportedDecoratorError } from './error';
export class DecoratorHelper {
public static register<AnnotationType extends Annotation>(annotation: AnnotationType, ...decoratorArgs: any[]) {
const annotationClass = TypeUtil.getType(annotation);
const name: string = annotationClass.name;
DecoratorHelper.registerAnnotation(name, annotation, decoratorArgs);
}
public static create = <Attribute = {}>(DecoratorClass: Type<Decorator<Attribute>>) => {
return (attribute: Attribute) => {
const annotation: Decorator<Attribute> = new DecoratorClass(attribute);
const name: string = DecoratorClass.name;
return (...decoratorArgs: any[]) => {
return DecoratorHelper.registerAnnotation(name, annotation, decoratorArgs);
};
};
}
private static registerAnnotation(name: string, annotation: any, decoratorArgs: any[]) {
const decoratorType: DecoratorType = DecoratorHelper.getDecoratorType(decoratorArgs);
const [target, propertyKey, descriptorOrParameterIndex] = decoratorArgs;
const clazz: Class = Class._defineClass(TypeUtil.getType(target));
let field: Field = null;
let method: Method = null;
let parameter: Parameter = null;
let cons: Constructor = null;
switch (decoratorType) {
case DecoratorType.CLASS:
try {
cons = clazz._defineConstructor(Metadata.getOwnParamTypes(target));
clazz._addAnnotation(annotation);
if (annotation instanceof Decorator) {
return annotation.classDecorator.call(annotation, target);
}
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Class.`);
}
throw e;
}
break;
case DecoratorType.PROPERTY:
try {
field = clazz._defineField(propertyKey, Metadata.getOwnType(target, propertyKey));
field._addAnnotation(annotation);
if (annotation instanceof Decorator) {
return annotation.propertyDecorator.call(annotation, target, propertyKey);
}
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Property.`);
}
throw e;
}
break;
case DecoratorType.METHOD:
try {
method = clazz._defineMethod(propertyKey,
Metadata.getOwnParamTypes(target, propertyKey),
Metadata.getOwnReturnType(target, propertyKey));
method._addAnnotation(annotation);
if (annotation instanceof Decorator) {
return annotation.methodDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
}
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Method.`);
}
throw e;
}
break;
case DecoratorType.PARAMETER:
try {
if (undefined === propertyKey) {
cons = clazz.getConstructor();
parameter = cons.getParameter(descriptorOrParameterIndex);
} else {
method = clazz._defineMethod(propertyKey,
Metadata.getOwnParamTypes(target, propertyKey),
Metadata.getOwnReturnType(target, propertyKey));
parameter = method.getParameter(descriptorOrParameterIndex);
}
parameter._addAnnotation(annotation);
if (annotation instanceof Decorator) {
return annotation.parameterDecorator.call(annotation, target, propertyKey, descriptorOrParameterIndex);
}
} catch (e) {
if (e instanceof NotSupportedDecoratorError) {
throw new NotSupportedDecoratorError(`Cannot apply @${name} decorator on Parameter.`);
}
throw e;
}
break;
default:
throw new NotSupportedDecoratorError(`Cannot determine decorator[@${name}] type.`);
}
}
/**
*
* @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 {string} propertyKey
* @returns {DecoratorParametersType}
*/
public static decoratorArgs(target: any, propertyKey: PropertyKeyType): DecoratorParametersType {
return [
target,
propertyKey,
TypeUtil.descriptorOf(target, propertyKey),
];
}
}

View File

@ -1,5 +1,4 @@
export * from './Decorator';
export * from './DecoratorFactory';
export * from './DecoratorHelper';
export * from './error';
export * from './type';
export * from './util';

View File

@ -1,48 +0,0 @@
import {
PropertyKeyType,
} from '@loafer/core';
import {
TypeUtil,
} from '@loafer/core/util/TypeUtil';
import {
DecoratorType,
DecoratorParametersType,
} from './type';
export class DecoratorUtil {
/**
*
* @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 {string} propertyKey
* @returns {DecoratorParametersType}
*/
public static decoratorArgs(target: any, propertyKey: PropertyKeyType): DecoratorParametersType {
return [
target,
propertyKey,
TypeUtil.descriptorOf(target, propertyKey),
];
}
}