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; private _constructor: Constructor | undefined; private _fields: Map; private _methods: Map; /** * forClass */ public static forType(type: Type): Class | undefined { return SystemClassRegistry.get(type); } /** * _defineClass */ public static _defineClass(type: Type): 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) { 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 { 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 { return this._fields; } public getField(propertyKey: PropertyKeyType): Field | undefined { const fields = this.getFields(); return fields.get(propertyKey); } public getFields(): Map { const fields: Map = 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 { return this._methods; } public getMethod(propertyKey: PropertyKeyType): Method | undefined { const methods = this.getMethods(); return methods.get(propertyKey); } public getMethods(): Map { const methods: Map = 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(annotationClass: Type): AnnotationType | undefined { const annotations = this.getAnnotations(); return annotations.get(annotationClass) as AnnotationType; } public getAnnotations(): Map, Annotation> { const annotations: Map, 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): void => { annotations.set(key, value); }); } return annotations; } public getAnnotationsByType(annotationClass: Type) : 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; } }