core-js/src/reflect/Class.ts
2018-09-05 19:01:59 +09:00

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;
}
}