232 lines
6.0 KiB
TypeScript
232 lines
6.0 KiB
TypeScript
import {
|
|
PropertyKeyType,
|
|
Type,
|
|
} from '../core';
|
|
|
|
import {
|
|
TypeUtil,
|
|
} from '../util/TypeUtil';
|
|
|
|
import { AccessibleObject } from './AccessibleObject';
|
|
import { Annotation } from './Annotation';
|
|
import { SystemClassRegistry } from './ClassRegistry';
|
|
import { Constructor } from './Constructor';
|
|
import { Field } from './Field';
|
|
import { Metadata } from './Metadata';
|
|
import { Method } from './Method';
|
|
|
|
export class Class extends AccessibleObject {
|
|
private _type: Type<any>;
|
|
private _constructor: Constructor | undefined;
|
|
private _fields: Map<PropertyKeyType, Field>;
|
|
private _methods: Map<PropertyKeyType, Method>;
|
|
|
|
/**
|
|
* forClass
|
|
*/
|
|
public static forType(type: Type<any>): Class | undefined {
|
|
return SystemClassRegistry.get(type);
|
|
}
|
|
|
|
/**
|
|
* _defineClass
|
|
*/
|
|
public static _defineClass(type: Type<any>): Class {
|
|
let clazz: Class | undefined = Class.forType(type);
|
|
if (undefined === clazz) {
|
|
clazz = new Class(type);
|
|
SystemClassRegistry.set(type, clazz);
|
|
}
|
|
|
|
if (null === clazz._constructor) {
|
|
const parameterTypes = Metadata.getOwnParamTypes(type);
|
|
if (undefined !== parameterTypes) {
|
|
clazz._constructor = new Constructor(clazz, parameterTypes);
|
|
}
|
|
}
|
|
|
|
return clazz;
|
|
}
|
|
|
|
private constructor(type: Type<any>) {
|
|
super();
|
|
this._type = type;
|
|
this._fields = new Map();
|
|
this._methods = new Map();
|
|
}
|
|
|
|
/**
|
|
* _defineField
|
|
*/
|
|
public _defineConstructor(parameterTypes: any[]): Constructor | null {
|
|
let cons: Constructor | undefined = this._constructor;
|
|
if (undefined === cons) {
|
|
cons = new Constructor(this, parameterTypes);
|
|
this._constructor = cons;
|
|
}
|
|
|
|
return cons;
|
|
}
|
|
|
|
/**
|
|
* _defineField
|
|
*/
|
|
public _defineField(propertyKey: PropertyKeyType, propertyType: any): Field {
|
|
let field: Field | undefined = this._fields.get(propertyKey);
|
|
if (undefined === field) {
|
|
field = new Field(this, propertyKey, propertyType);
|
|
this._fields.set(propertyKey, field);
|
|
}
|
|
|
|
return field;
|
|
}
|
|
|
|
/**
|
|
* _defineMethod
|
|
*/
|
|
public _defineMethod(propertyKey: PropertyKeyType, parameterTypes: any[], returnType: any): Method {
|
|
let method: Method | undefined = this._methods.get(propertyKey);
|
|
if (undefined === method) {
|
|
method = new Method(this, propertyKey, parameterTypes, returnType);
|
|
this._methods.set(propertyKey, method);
|
|
}
|
|
|
|
return method;
|
|
}
|
|
|
|
public getType(): Type<any> {
|
|
return this._type;
|
|
}
|
|
|
|
public getConstructor(): Constructor {
|
|
if (undefined === this._constructor) {
|
|
this._constructor = new Constructor(this, undefined);
|
|
}
|
|
|
|
return this._constructor;
|
|
}
|
|
|
|
public getOwnField(propertyKey: PropertyKeyType): Field | undefined {
|
|
return this._fields.get(propertyKey);
|
|
}
|
|
|
|
public getOwnFields(): Map<PropertyKeyType, Field> {
|
|
return this._fields;
|
|
}
|
|
|
|
public getField(propertyKey: PropertyKeyType): Field | undefined {
|
|
const fields = this.getFields();
|
|
|
|
return fields.get(propertyKey);
|
|
}
|
|
|
|
public getFields(): Map<PropertyKeyType, Field> {
|
|
const fields: Map<PropertyKeyType, Field> = new Map();
|
|
|
|
const types = TypeUtil.ancestorsOf(this._type);
|
|
if (null === types || 0 === types.length) {
|
|
return fields;
|
|
}
|
|
for (let i = 0; i < types.length; i++) {
|
|
const tType = types[i];
|
|
const tClazz = Class.forType(tType);
|
|
if (undefined === tClazz) {
|
|
continue;
|
|
}
|
|
|
|
tClazz.getOwnFields().forEach((value: Field, key: PropertyKeyType): void => {
|
|
fields.set(key, value);
|
|
});
|
|
}
|
|
|
|
return fields;
|
|
}
|
|
|
|
public getOwnMethod(propertyKey: PropertyKeyType): Method | undefined {
|
|
return this._methods.get(propertyKey);
|
|
}
|
|
|
|
public getOwnMethods(): Map<PropertyKeyType, Method> {
|
|
return this._methods;
|
|
}
|
|
|
|
public getMethod(propertyKey: PropertyKeyType): Method | undefined {
|
|
const methods = this.getMethods();
|
|
|
|
return methods.get(propertyKey);
|
|
}
|
|
|
|
public getMethods(): Map<PropertyKeyType, Method> {
|
|
const methods: Map<PropertyKeyType, Method> = new Map();
|
|
|
|
const types = TypeUtil.ancestorsOf(this._type);
|
|
if (null === types || 0 === types.length) {
|
|
return methods;
|
|
}
|
|
for (let i = 0; i < types.length; i++) {
|
|
const tClazzType = types[i];
|
|
const tClazz = Class.forType(tClazzType);
|
|
if (undefined === tClazz) {
|
|
continue;
|
|
}
|
|
|
|
tClazz.getOwnMethods().forEach((value: Method, key: PropertyKeyType): void => {
|
|
methods.set(key, value);
|
|
});
|
|
}
|
|
|
|
return methods;
|
|
}
|
|
|
|
public getAnnotation<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>): AnnotationType | undefined {
|
|
const annotations = this.getAnnotations();
|
|
|
|
return annotations.get(annotationClass) as AnnotationType;
|
|
}
|
|
|
|
public getAnnotations(): Map<Type<any>, Annotation> {
|
|
const annotations: Map<Type<any>, Annotation> = new Map();
|
|
|
|
const types = TypeUtil.ancestorsOf(this._type);
|
|
if (null === types || 0 === types.length) {
|
|
return annotations;
|
|
}
|
|
for (let i = 0; i < types.length; i++) {
|
|
const tClazzType = types[i];
|
|
const tClazz = Class.forType(tClazzType);
|
|
if (undefined === tClazz) {
|
|
continue;
|
|
}
|
|
|
|
tClazz.getOwnAnnotations().forEach((value: Annotation, key: Type<any>): void => {
|
|
annotations.set(key, value);
|
|
});
|
|
}
|
|
|
|
return annotations;
|
|
}
|
|
|
|
public getAnnotationsByType<AnnotationType extends Annotation>(annotationClass: Type<AnnotationType>)
|
|
: AnnotationType[] | undefined {
|
|
const annotations = this.getAnnotations();
|
|
if (0 === annotations.size) {
|
|
return undefined;
|
|
}
|
|
const results: AnnotationType[] = [];
|
|
for (const classType of Array.from(annotations.keys())) {
|
|
if (classType === annotationClass) {
|
|
results.push(annotations.get(classType) as AnnotationType);
|
|
}
|
|
}
|
|
if (0 === results.length) {
|
|
return undefined;
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
public getName(): string {
|
|
return this._type.name;
|
|
}
|
|
}
|