ing
This commit is contained in:
parent
036d91898d
commit
e81ce83303
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@overflow/core-js",
|
"name": "@overflow/core-js",
|
||||||
"version": "0.0.4",
|
"version": "0.0.7",
|
||||||
"description": "TypeScript library setup for multiple compilation targets using tsc and webpack",
|
"description": "TypeScript library setup for multiple compilation targets using tsc and webpack",
|
||||||
"main": "./bundles/index.umd.js",
|
"main": "./bundles/index.umd.js",
|
||||||
"module": "./esm5/index.js",
|
"module": "./esm5/index.js",
|
||||||
|
|
|
@ -4,3 +4,17 @@ export class IllegalArgumentError extends Error {
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NotSupportedDecoratorError extends Error {
|
||||||
|
public constructor(message?: string) {
|
||||||
|
super(message);
|
||||||
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NotDecoratedClassError extends Error {
|
||||||
|
public constructor(message?: string) {
|
||||||
|
super(message);
|
||||||
|
Object.setPrototypeOf(this, new.target.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,3 +14,12 @@ export enum PrimitiveType {
|
||||||
NUMBER = 'number',
|
NUMBER = 'number',
|
||||||
BOOLEAN = 'boolean',
|
BOOLEAN = 'boolean',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum DecoratorType {
|
||||||
|
CLASS = 'Clazz',
|
||||||
|
PROPERTY = 'Property',
|
||||||
|
METHOD = 'Method',
|
||||||
|
PARAMETER = 'Parameter',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DecoratorParametersType = [any, string | symbol, number | PropertyDescriptor | undefined];
|
||||||
|
|
23
src/decorator/Decorator.ts
Normal file
23
src/decorator/Decorator.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import {
|
||||||
|
PropertyKeyType,
|
||||||
|
} from '../core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Annotation,
|
||||||
|
} from '../reflect';
|
||||||
|
|
||||||
|
export interface Decorator<Attribute = {}> {
|
||||||
|
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 Decorator<Attribute = {}> extends Annotation {
|
||||||
|
|
||||||
|
public constructor(attribute?: Attribute) {
|
||||||
|
super(attribute);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
163
src/decorator/DecoratorHelper.ts
Normal file
163
src/decorator/DecoratorHelper.ts
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
import {
|
||||||
|
DecoratorParametersType,
|
||||||
|
DecoratorType,
|
||||||
|
NotSupportedDecoratorError,
|
||||||
|
PropertyKeyType, Type,
|
||||||
|
} from '../core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Annotation,
|
||||||
|
Class,
|
||||||
|
Constructor,
|
||||||
|
Field,
|
||||||
|
Metadata,
|
||||||
|
Method,
|
||||||
|
Parameter,
|
||||||
|
} from '../reflect';
|
||||||
|
|
||||||
|
import {
|
||||||
|
TypeUtil,
|
||||||
|
} from '../util';
|
||||||
|
|
||||||
|
import { Decorator } from './Decorator';
|
||||||
|
|
||||||
|
export class DecoratorHelper {
|
||||||
|
|
||||||
|
public static register<AttributeType>(attribute: AttributeType, ...decoratorArgs: any[]) {
|
||||||
|
const annotation = new Annotation<AttributeType>(attribute);
|
||||||
|
const name: string = Annotation.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;
|
||||||
|
let method: Method;
|
||||||
|
let parameter: Parameter | undefined;
|
||||||
|
let cons: Constructor | null = null;
|
||||||
|
|
||||||
|
switch (decoratorType) {
|
||||||
|
case DecoratorType.CLASS:
|
||||||
|
try {
|
||||||
|
cons = clazz._defineConstructor(Metadata.getOwnParamTypes(target));
|
||||||
|
clazz._addAnnotation(annotation);
|
||||||
|
if (annotation instanceof Decorator && undefined !== annotation.classDecorator) {
|
||||||
|
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 && undefined !== annotation.propertyDecorator) {
|
||||||
|
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 && undefined !== annotation.methodDecorator) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (undefined !== parameter) {
|
||||||
|
parameter._addAnnotation(annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotation instanceof Decorator && undefined !== annotation.parameterDecorator) {
|
||||||
|
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),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
2
src/decorator/index.ts
Normal file
2
src/decorator/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './Decorator';
|
||||||
|
export * from './DecoratorHelper';
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './core';
|
export * from './core';
|
||||||
|
export * from './decorator';
|
||||||
export * from './reflect';
|
export * from './reflect';
|
||||||
export * from './util';
|
export * from './util';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export abstract class Annotation<Attribute = {}> {
|
export class Annotation<Attribute = {}> {
|
||||||
public readonly attribute: Attribute | undefined;
|
public readonly attribute: Attribute | undefined;
|
||||||
|
|
||||||
public constructor(attribute?: Attribute) {
|
public constructor(attribute?: Attribute) {
|
||||||
|
|
32
src/util/ReflectionUtil.ts
Normal file
32
src/util/ReflectionUtil.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { Method } from '../reflect';
|
||||||
|
|
||||||
|
export abstract class ReflectionUtil {
|
||||||
|
public static getParamTypes(method: Method): any[] {
|
||||||
|
if (0 === method.getParameterCount()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parameters = method.getParameters();
|
||||||
|
if (undefined === parameters) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const results: any[] = [];
|
||||||
|
for (let indexI = 0; indexI < parameters.length; indexI++) {
|
||||||
|
const paramType = parameters[indexI].getType();
|
||||||
|
results.push(paramType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getParamTypeStrings(method: Method): string[] {
|
||||||
|
const paramTypes = ReflectionUtil.getParamTypes(method);
|
||||||
|
|
||||||
|
const results: string[] = [];
|
||||||
|
paramTypes.forEach(paramType => {
|
||||||
|
results.push(paramType.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './AnnotationUtil';
|
export * from './AnnotationUtil';
|
||||||
|
export * from './ReflectionUtil';
|
||||||
export * from './Registry';
|
export * from './Registry';
|
||||||
export * from './TypeUtil';
|
export * from './TypeUtil';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user