ing
This commit is contained in:
parent
d08a77a279
commit
4992e39e3f
6
src/ts/@loafer/core/constants/decorator.ts
Normal file
6
src/ts/@loafer/core/constants/decorator.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export enum DecoratorType {
|
||||||
|
CLASS,
|
||||||
|
PROPERTY,
|
||||||
|
PARAMETER,
|
||||||
|
METHOD,
|
||||||
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './types';
|
|
||||||
export * from './reflect';
|
|
|
@ -4,3 +4,6 @@ export const DESIGN_TYPE = 'design:type';
|
||||||
export const DESIGN_PARAMTYPES = 'design:paramtypes';
|
export const DESIGN_PARAMTYPES = 'design:paramtypes';
|
||||||
// used to access design time return type
|
// used to access design time return type
|
||||||
export const DESIGN_RETURNTYPE = 'design:returntype';
|
export const DESIGN_RETURNTYPE = 'design:returntype';
|
||||||
|
|
||||||
|
// used to access design time return type
|
||||||
|
export const REFLECT_META = 'loafer:reflectmeta';
|
||||||
|
|
|
@ -1,10 +1,3 @@
|
||||||
export type Construtorable<T> = {new(...args: any[]): T};
|
export type Construtorable<T> = {new(...args: any[]): T};
|
||||||
export type ClassType = Object;
|
export type ClassType = Object;
|
||||||
export type PropertyType = string | symbol;
|
export type PropertyType = string | symbol;
|
||||||
|
|
||||||
export enum DecoratorType {
|
|
||||||
CLASS,
|
|
||||||
PROPERTY,
|
|
||||||
PARAMETER,
|
|
||||||
METHOD,
|
|
||||||
}
|
|
||||||
|
|
90
src/ts/@loafer/core/decorator/Decorator.ts
Normal file
90
src/ts/@loafer/core/decorator/Decorator.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
Construtorable,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
import * as ReflectConstants from '@loafer/core/constants/reflect';
|
||||||
|
import Reflection from '@loafer/core/reflect/Reflection';
|
||||||
|
import Class from '@loafer/core/reflect/Class';
|
||||||
|
import DecoratorType from './DecoratorType';
|
||||||
|
|
||||||
|
export class Decorator {
|
||||||
|
public static create = (Annotation: Construtorable<any>) => {
|
||||||
|
return (...handlerArgs: any[]) => {
|
||||||
|
let annotation = new Annotation(...handlerArgs);
|
||||||
|
|
||||||
|
return (...decoratorArgs: any[]) => {
|
||||||
|
let decoratorType: DecoratorType = Decorator._detectDecoratorType(name, annotation, decoratorArgs);
|
||||||
|
let type = typeof decoratorArgs[0] === 'function' ? decoratorArgs[0].prototype : decoratorArgs[0];
|
||||||
|
|
||||||
|
let reflection: Reflection = Reflect.getMetadata(ReflectConstants.REFLECT_META, type);
|
||||||
|
if (undefined === reflection) {
|
||||||
|
reflection = new Reflection(type);
|
||||||
|
Reflect.defineMetadata(ReflectConstants.REFLECT_META, reflection, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(decoratorType) {
|
||||||
|
case DecoratorType.CLASS:
|
||||||
|
reflection.addClassAnnotation(annotation);
|
||||||
|
return annotation.onClassDecorator.apply(annotation, decoratorArgs);
|
||||||
|
case DecoratorType.PROPERTY:
|
||||||
|
reflection.addPropertyAnnotation(annotation, decoratorArgs[1]);
|
||||||
|
return annotation.onPropertyDecorator.apply(annotation, decoratorArgs);
|
||||||
|
case DecoratorType.METHOD:
|
||||||
|
reflection.addMethodAnnotation(annotation, decoratorArgs[1]);
|
||||||
|
return annotation.onMethodDecorator.apply(annotation, decoratorArgs);
|
||||||
|
case DecoratorType.PARAMETER:
|
||||||
|
reflection.addParameterAnnotation(annotation, decoratorArgs[1], decoratorArgs[2]);
|
||||||
|
return annotation.onParameterDecorator.apply(annotation, decoratorArgs);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get = (targetType: ClassType) => {
|
||||||
|
let reflection: Reflection = Reflect.getMetadata(ReflectConstants.REFLECT_META, targetType);
|
||||||
|
if (undefined === reflection) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return reflection.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _detectDecoratorType(name: string, annotation: any, args: any[]): DecoratorType {
|
||||||
|
let params = [];
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i]) {
|
||||||
|
params.push(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const paramCount = params.length;
|
||||||
|
let decoratorType: DecoratorType;
|
||||||
|
|
||||||
|
if (1 === paramCount) {
|
||||||
|
if ('onClassDecorator' in annotation) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator on Class.`);
|
||||||
|
}
|
||||||
|
decoratorType = DecoratorType.CLASS;
|
||||||
|
} else if (2 === paramCount) {
|
||||||
|
if ('onPropertyDecorator' in annotation) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator on Property.`);
|
||||||
|
}
|
||||||
|
decoratorType = DecoratorType.PROPERTY;
|
||||||
|
} else if (3 === paramCount) {
|
||||||
|
if(typeof args[2] === 'number') {
|
||||||
|
if ('onParameterDecorator' in annotation) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator on Parameter.`);
|
||||||
|
}
|
||||||
|
decoratorType = DecoratorType.PARAMETER;
|
||||||
|
} else {
|
||||||
|
if ('onMethodDecorator' in annotation) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator on Method.`);
|
||||||
|
}
|
||||||
|
decoratorType = DecoratorType.METHOD;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`@${name} decorator is not valid here!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoratorType;
|
||||||
|
}
|
||||||
|
}
|
9
src/ts/@loafer/core/decorator/DecoratorHandler.ts
Normal file
9
src/ts/@loafer/core/decorator/DecoratorHandler.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export interface DecoratorHandler {
|
||||||
|
onClassDecorator?: <TFunction extends Function>(target: TFunction) => TFunction | void;
|
||||||
|
onPropertyDecorator?: (target: Object, propertyKey: string | symbol) => void;
|
||||||
|
onMethodDecorator?: <T>(target: Object, propertyKey: string | symbol,
|
||||||
|
descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
|
||||||
|
onParameterDecorator?: (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DecoratorHandler;
|
8
src/ts/@loafer/core/decorator/DecoratorType.ts
Normal file
8
src/ts/@loafer/core/decorator/DecoratorType.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export enum DecoratorType {
|
||||||
|
CLASS = 'Class',
|
||||||
|
PROPERTY = 'Property',
|
||||||
|
METHOD = 'Method',
|
||||||
|
PARAMETER = 'Parameter',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DecoratorType;
|
3
src/ts/@loafer/core/decorator/index.ts
Normal file
3
src/ts/@loafer/core/decorator/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export * from './Decorator';
|
||||||
|
export * from './DecoratorHandler';
|
||||||
|
export * from './DecoratorType';
|
33
src/ts/@loafer/core/reflect/AnnotatedElement.ts
Normal file
33
src/ts/@loafer/core/reflect/AnnotatedElement.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
export abstract class AnnotatedElement {
|
||||||
|
private _annotationMap: Map<ClassType, any>;
|
||||||
|
|
||||||
|
protected constructor() {
|
||||||
|
this._annotationMap = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDeclaredAnnotation(type: ClassType): any {
|
||||||
|
return this._annotationMap.get(type);
|
||||||
|
}
|
||||||
|
public getDeclaredAnnotations(): IterableIterator<any> {
|
||||||
|
return this._annotationMap.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public addAnnotation(annotation: any): void {
|
||||||
|
const type: ClassType = Object.getPrototypeOf(annotation);
|
||||||
|
this._annotationMap.set(type, annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasAnnotation(type: ClassType): boolean {
|
||||||
|
return this._annotationMap.has(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public abstract getAnnotation(type: ClassType): any;
|
||||||
|
// public abstract getAnnotations(): IterableIterator<any>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AnnotatedElement;
|
75
src/ts/@loafer/core/reflect/Class.ts
Normal file
75
src/ts/@loafer/core/reflect/Class.ts
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
PropertyType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import AnnotatedElement from './AnnotatedElement';
|
||||||
|
import Constructor from './Constructor';
|
||||||
|
import Property from './Property';
|
||||||
|
import Method from './Method';
|
||||||
|
|
||||||
|
|
||||||
|
export class Class extends AnnotatedElement {
|
||||||
|
private _type: ClassType;
|
||||||
|
private _name: PropertyType;
|
||||||
|
private _constructor: Constructor;
|
||||||
|
private _properties: Map<PropertyType, Property>;
|
||||||
|
private _methodes: Map<PropertyType, Method>;
|
||||||
|
|
||||||
|
public constructor(type: ClassType, parameterTypes: ClassType[]) {
|
||||||
|
super();
|
||||||
|
this._type = type;
|
||||||
|
this._name = this._type.constructor.name;
|
||||||
|
this._constructor = new Constructor(parameterTypes);
|
||||||
|
this._properties = new Map();
|
||||||
|
this._methodes = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Type(): ClassType {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Name(): PropertyType {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Constructor(): Constructor {
|
||||||
|
return this._constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addProperty(propertyKey: PropertyType, type: ClassType): Property {
|
||||||
|
if (this._properties.has(propertyKey)) {
|
||||||
|
throw new Error(`Property[${propertyKey}:${type.constructor.name}] on Class[${this._name}] is exist already`);
|
||||||
|
}
|
||||||
|
let proerty = new Property(type, propertyKey);
|
||||||
|
this._properties.set(propertyKey, proerty);
|
||||||
|
return proerty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getProperty(propertyKey: PropertyType): Property {
|
||||||
|
return this._properties.get(propertyKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasProperty(propertyKey: PropertyType): boolean {
|
||||||
|
return this._properties.has(propertyKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMethod(propertyKey: PropertyType, parameterTypes: ClassType[], returnType: ClassType): Method {
|
||||||
|
if (this._methodes.has(propertyKey)) {
|
||||||
|
throw new Error(`Method[${propertyKey}:${returnType.constructor.name}] on Class[${this._name}] is exist already`);
|
||||||
|
}
|
||||||
|
let method = new Method(propertyKey, parameterTypes, returnType);
|
||||||
|
this._methodes.set(propertyKey, method);
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMethod(propertyKey: PropertyType): Method {
|
||||||
|
return this._methodes.get(propertyKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasMethod(propertyKey: PropertyType): boolean {
|
||||||
|
return this._methodes.has(propertyKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Class;
|
15
src/ts/@loafer/core/reflect/Constructor.ts
Normal file
15
src/ts/@loafer/core/reflect/Constructor.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import Executable from '@loafer/core/reflect/Executable';
|
||||||
|
|
||||||
|
|
||||||
|
export class Constructor extends Executable {
|
||||||
|
|
||||||
|
public constructor(parameterTypes: ClassType[]) {
|
||||||
|
super(parameterTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Constructor;
|
30
src/ts/@loafer/core/reflect/Executable.ts
Normal file
30
src/ts/@loafer/core/reflect/Executable.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import AnnotatedElement from './AnnotatedElement';
|
||||||
|
import Parameter from '@loafer/core/reflect/Parameter';
|
||||||
|
|
||||||
|
export abstract class Executable extends AnnotatedElement {
|
||||||
|
protected _parameters: Parameter[];
|
||||||
|
|
||||||
|
public constructor(parameterTypes: ClassType[]) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._parameters = [];
|
||||||
|
parameterTypes.forEach((currentValue, index, array) => {
|
||||||
|
this._parameters.push(new Parameter(currentValue, index));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Parameters(): Parameter[] {
|
||||||
|
return this._parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParameter(index: number): Parameter {
|
||||||
|
return this._parameters[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Executable;
|
32
src/ts/@loafer/core/reflect/Method.ts
Normal file
32
src/ts/@loafer/core/reflect/Method.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
PropertyType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import Executable from '@loafer/core/reflect/Executable';
|
||||||
|
|
||||||
|
|
||||||
|
export class Method extends Executable {
|
||||||
|
private _name: PropertyType;
|
||||||
|
private _returnType: ClassType;
|
||||||
|
|
||||||
|
public constructor(name: PropertyType, parameterTypes: ClassType[], returnType: ClassType) {
|
||||||
|
super(parameterTypes);
|
||||||
|
this._name = name;
|
||||||
|
this._returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Name(): PropertyType {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
public get ReturnType(): ClassType {
|
||||||
|
return this._returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set ReturnType(returnType: ClassType) {
|
||||||
|
this._returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Method;
|
29
src/ts/@loafer/core/reflect/Parameter.ts
Normal file
29
src/ts/@loafer/core/reflect/Parameter.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import AnnotatedElement from './AnnotatedElement';
|
||||||
|
import Constructor from './Constructor';
|
||||||
|
|
||||||
|
|
||||||
|
export class Parameter extends AnnotatedElement {
|
||||||
|
private _type: ClassType;
|
||||||
|
private _index: number;
|
||||||
|
|
||||||
|
public constructor(type: ClassType, index: number) {
|
||||||
|
super();
|
||||||
|
this._type = type;
|
||||||
|
this._index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Type(): ClassType {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Index(): number {
|
||||||
|
return this._index;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Parameter;
|
29
src/ts/@loafer/core/reflect/Property.ts
Normal file
29
src/ts/@loafer/core/reflect/Property.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
PropertyType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import AnnotatedElement from './AnnotatedElement';
|
||||||
|
import Constructor from './Constructor';
|
||||||
|
|
||||||
|
|
||||||
|
export class Property extends AnnotatedElement {
|
||||||
|
private _type: ClassType;
|
||||||
|
private _name: PropertyType;
|
||||||
|
|
||||||
|
public constructor(type: ClassType, name: PropertyType) {
|
||||||
|
super();
|
||||||
|
this._type = type;
|
||||||
|
this._name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Name(): PropertyType {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Type(): ClassType {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Property;
|
106
src/ts/@loafer/core/reflect/Reflection.ts
Normal file
106
src/ts/@loafer/core/reflect/Reflection.ts
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
PropertyType,
|
||||||
|
} from '@loafer/core/constants/types';
|
||||||
|
|
||||||
|
import * as ReflectConstants from '@loafer/core/constants/reflect';
|
||||||
|
|
||||||
|
import AnnotatedElement from './AnnotatedElement';
|
||||||
|
import Class from './Class';
|
||||||
|
|
||||||
|
export class Reflection {
|
||||||
|
private _clazz: Class;
|
||||||
|
|
||||||
|
public constructor(type: ClassType) {
|
||||||
|
let parameterTypes: any[] = Reflect.getMetadata(ReflectConstants.DESIGN_PARAMTYPES, type.constructor);
|
||||||
|
|
||||||
|
this._clazz = new Class(type, this.convertParamTypes(parameterTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getClass
|
||||||
|
*/
|
||||||
|
public getClass(): Class {
|
||||||
|
return this._clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addClassAnnotation(annotation: any): void {
|
||||||
|
let parameterTypes: any[] = Reflect.getMetadata(ReflectConstants.DESIGN_PARAMTYPES, this._clazz.Type);
|
||||||
|
|
||||||
|
const {valid, name} = this.validateAnnotation(annotation, this._clazz);
|
||||||
|
if (!valid) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator multiple times on Class[${this._clazz.Name}].`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._clazz.addAnnotation(annotation);
|
||||||
|
}
|
||||||
|
public addPropertyAnnotation(annotation: any, propertyKey: PropertyType): void {
|
||||||
|
let propertyType: any = Reflect.getMetadata(ReflectConstants.DESIGN_TYPE, this._clazz.Type, propertyKey);
|
||||||
|
|
||||||
|
let property = this._clazz.getProperty(propertyKey);
|
||||||
|
if (undefined === property) {
|
||||||
|
property = this._clazz.addProperty(propertyKey, propertyType.prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
const {valid, name} = this.validateAnnotation(annotation, property);
|
||||||
|
if (!valid) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator multiple times on Property[${this._clazz.Name}:${propertyKey}].`);
|
||||||
|
}
|
||||||
|
|
||||||
|
property.addAnnotation(annotation);
|
||||||
|
}
|
||||||
|
public addMethodAnnotation(annotation: any, propertyKey: PropertyType): void {
|
||||||
|
let parameterTypes: any[] = Reflect.getMetadata(ReflectConstants.DESIGN_PARAMTYPES, this._clazz.Type, propertyKey);
|
||||||
|
let returnType: any = Reflect.getMetadata(ReflectConstants.DESIGN_RETURNTYPE, this._clazz.Type, propertyKey);
|
||||||
|
|
||||||
|
let method = this._clazz.getMethod(propertyKey);
|
||||||
|
if (undefined === method) {
|
||||||
|
method = this._clazz.addMethod(propertyKey, this.convertParamTypes(parameterTypes), returnType.prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
const {valid, name} = this.validateAnnotation(annotation, method);
|
||||||
|
if (!valid) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator multiple times on Method[${this._clazz.Name}:${propertyKey}].`);
|
||||||
|
}
|
||||||
|
|
||||||
|
method.addAnnotation(annotation);
|
||||||
|
}
|
||||||
|
public addParameterAnnotation(annotation: any, propertyKey: PropertyType, parameterIndex: number): void {
|
||||||
|
let parameterTypes: any[] = Reflect.getMetadata(ReflectConstants.DESIGN_PARAMTYPES, this._clazz.Type, propertyKey);
|
||||||
|
let returnType: any = Reflect.getMetadata(ReflectConstants.DESIGN_RETURNTYPE, this._clazz.Type, propertyKey);
|
||||||
|
|
||||||
|
let method = this._clazz.getMethod(propertyKey);
|
||||||
|
if (undefined === method) {
|
||||||
|
method = this._clazz.addMethod(propertyKey, this.convertParamTypes(parameterTypes), returnType.prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parameter = method.getParameter(parameterIndex);
|
||||||
|
|
||||||
|
const {valid, name} = this.validateAnnotation(annotation, parameter);
|
||||||
|
if (!valid) {
|
||||||
|
throw new Error(`Cannot apply @${name} decorator multiple times on Parameter[${this._clazz.Name}:${propertyKey}(${parameterIndex}})].`);
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter.addAnnotation(annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateAnnotation(annotation: any, element: AnnotatedElement): {valid: boolean, name: string} {
|
||||||
|
const annotationType: ClassType = Object.getPrototypeOf(annotation);
|
||||||
|
const name: string = annotationType.constructor.name;
|
||||||
|
|
||||||
|
if (element.hasAnnotation(annotationType)) {
|
||||||
|
return {valid: false, name: name};
|
||||||
|
}
|
||||||
|
return {valid: true, name: name};
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertParamTypes(parameterTypes: any[]): ClassType[] {
|
||||||
|
let returnTypes: ClassType[] = [];
|
||||||
|
parameterTypes.forEach((currentValue, index, array) => {
|
||||||
|
returnTypes.push(currentValue.prototype);
|
||||||
|
});
|
||||||
|
return returnTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Reflection;
|
8
src/ts/@loafer/core/reflect/index.ts
Normal file
8
src/ts/@loafer/core/reflect/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export * from './AnnotatedElement';
|
||||||
|
export * from './Class';
|
||||||
|
export * from './Constructor';
|
||||||
|
export * from './Executable';
|
||||||
|
export * from './Method';
|
||||||
|
export * from './Parameter';
|
||||||
|
export * from './Property';
|
||||||
|
export * from './Reflection';
|
|
@ -1,46 +0,0 @@
|
||||||
export interface DecoratorFactory {
|
|
||||||
classDecorator?: ClassDecorator;
|
|
||||||
propertyDecorator?: PropertyDecorator;
|
|
||||||
parameterDecorator?: ParameterDecorator;
|
|
||||||
methodDecorator?: MethodDecorator;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createDecorator = (name: string, decoratorFactory: DecoratorFactory) => {
|
|
||||||
return (...args: any[]) => {
|
|
||||||
let params = [];
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (args[i]) {
|
|
||||||
params.push(args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(params.length) {
|
|
||||||
case 1:
|
|
||||||
if (undefined !== decoratorFactory.classDecorator) {
|
|
||||||
return decoratorFactory.classDecorator.apply(this, args);
|
|
||||||
}
|
|
||||||
throw new Error(`Cannot apply @${name} decorator on Class.`);
|
|
||||||
case 2:
|
|
||||||
case 1:
|
|
||||||
if (undefined !== decoratorFactory.propertyDecorator) {
|
|
||||||
return decoratorFactory.propertyDecorator.apply(this, args);
|
|
||||||
}
|
|
||||||
throw new Error(`Cannot apply @${name} decorator on Property.`);
|
|
||||||
case 3:
|
|
||||||
if(typeof args[2] === 'number') {
|
|
||||||
if (undefined !== decoratorFactory.parameterDecorator) {
|
|
||||||
return decoratorFactory.parameterDecorator.apply(this, args);
|
|
||||||
}
|
|
||||||
throw new Error(`Cannot apply @${name} decorator on Parameter.`);
|
|
||||||
}
|
|
||||||
if (undefined !== decoratorFactory.methodDecorator) {
|
|
||||||
return decoratorFactory.methodDecorator.apply(this, args);
|
|
||||||
}
|
|
||||||
throw new Error(`Cannot apply @${name} decorator on Method.`);
|
|
||||||
default:
|
|
||||||
throw new Error(`@${name} decorators are not valid here!`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default createDecorator;
|
|
|
@ -1,27 +0,0 @@
|
||||||
import {
|
|
||||||
ClassType,
|
|
||||||
} from '@loafer/core/constants';
|
|
||||||
|
|
||||||
export type MetadataDefinable<T> = {new(clazz: ClassType): T};
|
|
||||||
|
|
||||||
const getClassMetadata = <DefinitionType>(clazz: ClassType,
|
|
||||||
metadataKey: any,
|
|
||||||
definitionType: MetadataDefinable<DefinitionType>,
|
|
||||||
isCreate: boolean = false): DefinitionType => {
|
|
||||||
|
|
||||||
let definition: DefinitionType;
|
|
||||||
if (Reflect.hasOwnMetadata(metadataKey, clazz) !== true) {
|
|
||||||
if (!isCreate) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
definition = Object.create(definitionType.prototype);
|
|
||||||
definition.constructor.call(definition, clazz);
|
|
||||||
|
|
||||||
Reflect.defineMetadata(metadataKey, definition, clazz);
|
|
||||||
} else {
|
|
||||||
definition = Reflect.getMetadata(metadataKey, clazz);
|
|
||||||
}
|
|
||||||
return definition;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getClassMetadata;
|
|
|
@ -2,7 +2,11 @@ import InjectConfig from '@loafer/pouches/decorator/InjectConfig';
|
||||||
import InjectDefinition from '@loafer/pouches/definition/InjectDefinition';
|
import InjectDefinition from '@loafer/pouches/definition/InjectDefinition';
|
||||||
import createDecorator from '@loafer/core/util/decorators/createDecorator';
|
import createDecorator from '@loafer/core/util/decorators/createDecorator';
|
||||||
import { getInjectDefinition } from '@loafer/pouches/util/metadata';
|
import { getInjectDefinition } from '@loafer/pouches/util/metadata';
|
||||||
|
import {
|
||||||
|
ClassType,
|
||||||
|
DESIGN_TYPE,
|
||||||
|
PropertyType,
|
||||||
|
} from '@loafer/core/constants';
|
||||||
const Inject = (injectConfig: InjectConfig = {}) => createDecorator('Inject', {
|
const Inject = (injectConfig: InjectConfig = {}) => createDecorator('Inject', {
|
||||||
propertyDecorator: (target: Object, propertyKey: string | symbol): void => {
|
propertyDecorator: (target: Object, propertyKey: string | symbol): void => {
|
||||||
let injectDefinition: InjectDefinition = getInjectDefinition(target, InjectDefinition, true);
|
let injectDefinition: InjectDefinition = getInjectDefinition(target, InjectDefinition, true);
|
||||||
|
@ -16,3 +20,6 @@ const Inject = (injectConfig: InjectConfig = {}) => createDecorator('Inject', {
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Inject;
|
export default Inject;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user