-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.ts
68 lines (55 loc) · 2.87 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { Newable } from '../../../implementation';
import { AbstractDecoratorDefinition } from './abstract-decorator-definition';
import { AbstractDefinitionContainer } from './definition-container';
export const DEFINITION_SYMBOL = Symbol('DEFINITION_SYMBOL');
export type Decorator = (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export type ClassLevelDecorator = (constructor: Function) => void;
export type ValueSetterDecoratorFactory<T, R> = (value?: T) => R;
export class DefinitionNotAvailableException extends Error {
constructor(newable: Newable<any>) {
super(`Definition not found on class: ${newable}.`);
}
}
export function definitionCreatorFactory<D>(definitionContainerClass: Newable<D>) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): void {
target[DEFINITION_SYMBOL] = target[DEFINITION_SYMBOL] || new definitionContainerClass();
};
}
export function propertyLevelDefinition<T, D extends AbstractDecoratorDefinition>(definitionProperty: keyof D,
definitionContainerClass: Newable<AbstractDefinitionContainer<D>>): ValueSetterDecoratorFactory<T, Decorator> {
return function (value: T): Decorator {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): void {
definitionCreatorFactory(definitionContainerClass)(target, propertyKey, descriptor);
const definitionContainer: AbstractDefinitionContainer<D> = target[DEFINITION_SYMBOL];
const definition: D = definitionContainer.createOrGetDefinitionToDecoratedProperty(propertyKey);
if (value !== undefined) {
definition[definitionProperty] = value as any;
}
};
};
}
export function classLevelDefinition<T, D>(definitionProperty: keyof D, definitionClass: Newable<D>): ValueSetterDecoratorFactory<T, ClassLevelDecorator> {
return function (value: T): ClassLevelDecorator {
return function (constructor: Function): void {
definitionCreatorFactory(definitionClass)(constructor.prototype, undefined, undefined);
const definition: D = constructor.prototype[DEFINITION_SYMBOL];
if (value !== undefined) {
definition[definitionProperty] = value as any;
}
};
};
}
export function getPropertyLevelDefinitionsFromClass<T extends AbstractDecoratorDefinition>(newable: Newable<any>): T[] {
const defContainer: AbstractDefinitionContainer<T> = (<AbstractDefinitionContainer<T>>newable.prototype[DEFINITION_SYMBOL]);
if (defContainer) {
return defContainer.toArray();
}
throw new DefinitionNotAvailableException(newable);
}
export function getClassLevelDefinitionsFromClass<T>(newable: Newable<any>): T {
const definition: T = newable.prototype[DEFINITION_SYMBOL] as T;
if (definition) {
return definition;
}
throw new DefinitionNotAvailableException(newable);
}