This commit is contained in:
crusader 2018-05-23 16:40:50 +09:00
parent 529d717588
commit 13721a3814
4 changed files with 122 additions and 176 deletions

6
package-lock.json generated
View File

@ -752,9 +752,9 @@
} }
}, },
"tslint-config-prettier": { "tslint-config-prettier": {
"version": "1.12.0", "version": "1.13.0",
"resolved": "https://nexus.loafle.net/repository/npm-all/tslint-config-prettier/-/tslint-config-prettier-1.12.0.tgz", "resolved": "https://nexus.loafle.net/repository/npm-all/tslint-config-prettier/-/tslint-config-prettier-1.13.0.tgz",
"integrity": "sha512-7zugK8NWpoDPYT6UNGLDGpQOhk0CSodjkyrTNiHOCjwIAleYKlyQunxpsSXBIoGEs/kFVppd6YzZeQZtrJnyRg==", "integrity": "sha512-assE77K7K8Q9j8CVIHiU3d1uoKc8N5v7UPpkQ9IE8BEPWkvSYR37lDuYekDlAMFqR1IpD6CrS+uOJLl6pw7Wdw==",
"dev": true "dev": true
}, },
"tslint-config-standard": { "tslint-config-standard": {

View File

@ -1,24 +1,131 @@
import { import {
Type,
PropertyKeyType, PropertyKeyType,
} from '@loafer/core'; } from '@loafer/core';
import { import {
Annotation, Annotation,
Class,
Constructor,
Field,
Method,
Parameter,
Metadata,
} from '@loafer/core/reflect'; } from '@loafer/core/reflect';
export interface Decorator<Attribute = {}> { import {
classDecorator?: <TFunction extends Function>(target: TFunction) => TFunction | void; TypeUtil,
propertyDecorator?: (target: Object, propertyKey: PropertyKeyType) => void; } from '@loafer/core/util/TypeUtil';
methodDecorator?: <T>(target: Object, propertyKey: PropertyKeyType,
descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void; import { DecoratorType, DecoratorParametersType } from './type';
parameterDecorator?: (target: Object, propertyKey: PropertyKeyType, parameterIndex: number) => void; import { NotSupportedDecoratorError } from './error';
export class Decorator {
public static register<T extends Annotation>(AnnotationClass: Type<Annotation>, _annotation: T, ...decoratorArgs: any[]) {
const annotation: Annotation = Object.assign(new AnnotationClass(), _annotation);
const name: string = AnnotationClass.name;
const decoratorType: DecoratorType = Decorator.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);
} 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);
} 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);
} 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);
} 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.`);
}
} }
export abstract class Decorator<Attribute = {}> extends Annotation { /**
public readonly attribute: Attribute; *
* @param {any[]} args
* @returns {DecoratorType}
*/
public static getDecoratorType(args: any[]): DecoratorType {
const [, propertyKey, descriptor] = args;
public constructor(attribute?: Attribute) { if (typeof descriptor === 'number') {
super(); return DecoratorType.PARAMETER;
this.attribute = attribute; }
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,160 +0,0 @@
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 = Metadata.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(Metadata.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,4 +1,3 @@
export * from './Decorator'; export * from './Decorator';
export * from './DecoratorHelper';
export * from './error'; export * from './error';
export * from './type'; export * from './type';