UNPKG

@kephas/reflection

Version:

Provides reflection capabilities, like TypeInfoRegistry, ITypeInfo, and IProperty.

475 lines (463 loc) 15.7 kB
import { __decorate, __metadata } from 'tslib'; import { Requires, Serializable, AppService, Priority, SingletonAppServiceContract } from '@kephas/core'; /** * Provides display information. * * @export * @class DisplayInfo */ class DisplayInfo { } /** * Signals a reflection error. * * @export * @class ReflectionError * @extends {Error} */ class ReflectionError extends Error { /** * Creates an instance of ReflectionError. * @param {string} message The error message. * @memberof ReflectionError */ constructor(message) { super(message); } } /** * Provides basic implementation of reflection elements. * * @export * @class ElementInfo */ class ElementInfo { /** * Creates an instance of ElementInfo. * * @param {string} name The element name. * @param {string} [fullName] Optional. The full name of the element. * @param {DisplayInfo} [displayInfo] Optional. The display information. * @param {ITypeInfoRegistry} [registry] The root type info registry. * @memberof ElementInfo */ constructor({ name, fullName, displayInfo, registry, ...args }) { /** * Gets the element name. * * @type {string} * @memberof IElementInfo */ this.name = ''; if (!name) { throw new ReflectionError('The name must be provided.'); } this.name = name; this.fullName = fullName || this.name; this.displayInfo = displayInfo || new DisplayInfo(); Object.assign(this, args); } } /** * Provides a list of well known type names. * * @export * @class TypeName */ class TypeName { } /** * The name of the 'any' type. * * @static * @memberof TypeName */ TypeName.AnyTypeName = 'any'; /** * The name of the 'boolean' type. * * @static * @memberof TypeName */ TypeName.BooleanTypeName = 'boolean'; /** * The name of the 'number' type. * * @static * @memberof TypeName */ TypeName.NumberTypeName = 'number'; /** * The name of the 'string' type. * * @static * @memberof TypeName */ TypeName.StringTypeName = 'string'; /** * The name of the 'array' type. * * @static * @memberof TypeName */ TypeName.ArrayTypeName = 'array'; /** * The name of the 'any[]' type. * * @static * @memberof TypeName */ TypeName.ArrayOfAnyTypeName = 'any[]'; /** * The name of the 'Uint8Array' type. * * @static * @memberof TypeName */ TypeName.ArrayOfByteTypeName = 'Uint8Array'; /** * The name of the 'symbol' type. * * @static * @memberof TypeName */ TypeName.SymbolTypeName = 'symbol'; /** * The name of the 'Date' type. * * @static * @memberof TypeName */ TypeName.DateTypeName = 'Date'; var TypeInfoRegistry_1; /** * Provides centralized access to the application's type system. * * @export * @class TypeInfoRegistry */ let TypeInfoRegistry = TypeInfoRegistry_1 = class TypeInfoRegistry { /** * Creates an instance of TypeInfoRegistry. * @memberof TypeInfoRegistry */ constructor() { /** * Gets the registerd types. * * @type {ITypeInfo[]} * @memberof TypeInfoRegistry */ this.types = []; this._typesByFullName = {}; this._typesByName = {}; this.types = []; this.initialize(this); } /** * Gets the singleton instance of the type registry. * * @static * @type {TypeInfoRegistry} * @memberof TypeInfoRegistry */ static get Instance() { return TypeInfoRegistry_1._instance || (TypeInfoRegistry_1._instance = new TypeInfoRegistry_1()); } /** * Gets the type in the registry by its name. * * @param {string | Function} typeRef The full name of the type or the runtime type. * @param {boolean} [throwOnNotFound=true] True to throw if the type cannot be found. * @returns {TypeInfo} * @memberof TypeInfoRegistry */ getType(typeRef, throwOnNotFound) { Requires.HasValue(typeRef, 'typeRef'); if (throwOnNotFound === undefined) { throwOnNotFound = true; } let fullName = typeof typeRef === 'function' ? Serializable.getTypeFullName(typeRef) : typeRef; if (fullName && fullName.endsWith('[]')) { fullName = TypeName.ArrayOfAnyTypeName; } let type = fullName ? this._typesByFullName[fullName] : undefined; if (!type && fullName) { type = this._typesByName[fullName]; } if (!type && throwOnNotFound) { throw new ReflectionError(`The type with name '${typeRef}' was not found.`); } return type; } /** * Registers the provided types. * * @param {ITypeInfo[]} types The types to register. * @returns {this} This registry. * @memberof TypeInfoRegistry */ register(...types) { if (!types) { return this; } for (const type of types) { const typeKey = type.fullName || type.name; if (this._typesByFullName[typeKey]) { throw new ReflectionError(`The type ${typeKey} is already registered.`); } this._typesByFullName[typeKey] = type; this._typesByName[type.name] = type; } this.types.push.apply(this.types, types); return this; } /** * Initializes the registry. * * @protected * @param {TypeInfoRegistry} registry * @memberof TypeInfoRegistry */ initialize(registry) { } }; TypeInfoRegistry = TypeInfoRegistry_1 = __decorate([ AppService({ overridePriority: Priority.Low, provider: _ => TypeInfoRegistry_1.Instance }), SingletonAppServiceContract(), __metadata("design:paramtypes", []) ], TypeInfoRegistry); /** * Reflective element information holding a value. * * @export * @class ValueElementInfo * @extends {ElementInfo} */ class ValueElementInfo extends ElementInfo { /** * Creates an instance of ValueElementInfo. * * @param {string} name The element name. * @param {string} [fullName] Optional. The full name of the element. * @param {DisplayInfo} [displayInfo] Optional. The display information. * @param {ITypeInfo} [valueType] The value type. * @param {ITypeInfoRegistry} [registry] The root type info registry. * @memberof ValueElementInfo */ constructor({ name, fullName, displayInfo, valueType, registry, ...args }) { super({ name, fullName, displayInfo, registry, ...args }); if (!valueType) { this._valueTypeGetter = () => (this._valueType || (this._valueType = this.getValueType(TypeName.AnyTypeName, registry))); } else if (typeof valueType === 'string') { this._valueTypeGetter = () => (this._valueType || (this._valueType = this.getValueType(valueType, registry))); } else { this._valueType = valueType; } } /** * Gets the type of the element's value. * * @type {TypeInfo} * @memberof ValueElementInfo */ get valueType() { return this._valueType || (this._valueType = this._valueTypeGetter()); } /** * Gets the value type based on the type name. * * @protected * @param {string} valueType The name or full name of the value type. * @param {ITypeInfoRegistry} [registry] The type info registry. If not provided, TypeInfoRegistry.Instance will be used. * @returns * @memberof ValueElementInfo */ getValueType(valueType, registry) { return (registry || TypeInfoRegistry.Instance).getType(valueType); } } /** * Provides reflection information about a property. * * @export * @class PropertyInfo * @extends {ElementInfo} * @implements {IPropertyInfo} */ class PropertyInfo extends ValueElementInfo { /** * Creates an instance of PropertyInfo. * * @param {ITypeInfo} declaringType The declaring type. * @param {string} name The element name. * @param {string} [fullName] Optional. The full name of the element. * @param {DisplayInfo} [displayInfo] Optional. The display information. * @param {ITypeInfo} [valueType] The value type. * @param {boolean} [canRead] True if the property can be read. * @param {boolean} [canWrite] True if the property can be written. * @param {boolean} [isRequired] True if the property requires a value to be set. * @param {*} [defaultValue] The default value of the property. * @param {ITypeInfoRegistry} [registry] The root type info registry. * @memberof PropertyInfo */ constructor({ declaringType, name, fullName, displayInfo, valueType, canRead, canWrite, isRequired, isStatic, defaultValue, registry, ...args }) { super({ name, fullName, displayInfo, valueType, registry, ...args }); /** * Gets a value indicating whether the property can be written to. * * @type {boolean} * @memberof IPropertyInfo */ this.canWrite = true; /** * Gets a value indicating whether the property value can be read. * * @type {boolean} * @memberof IPropertyInfo */ this.canRead = true; /** * Gets a value indicating whether a value is required for this property. * * @type {boolean} * @memberof PropertyInfo */ this.isRequired = false; /** * Gets a value indicating whether this property is class bound, not instance bound. * * @type {boolean} * @memberof PropertyInfo */ this.isStatic = false; if (!declaringType) { throw new ReflectionError('The declaring type is not set.'); } this.declaringType = declaringType; this.canRead = canRead === undefined ? true : canRead; this.canWrite = canWrite === undefined ? true : canWrite; this.isRequired = !!isRequired; this.isStatic = !!isStatic; this.defaultValue = defaultValue; } } /** * Provides reflective information about a type. * * @export * @class TypeInfo * @extends {ElementInfo} */ class TypeInfo extends ElementInfo { /** * Creates an instance of TypeInfo. * * @param {string} name The type name. * @param {string} [namespace] The type namespace. * @param {string} [fullName] Optional. The full name of the type. * @param {DisplayInfo} [displayInfo] Optional. The display information. * @param {IPropertyInfo[]} [properties] Optional. The properties. * @param {Type<*>} [type] Optional. The instantiable type. * @param {boolean} [isArray] Optional. Indicates whether the type is an array. * @param {boolean} [isEnum] Optional. Indicates whether the type is an enumeration. * @param {*} [defaultValue] Optional. The type's default value. * @param {ITypeInfoRegistry} [registry] The root type info registry. * @memberof TypeInfo */ constructor({ name, namespace, fullName, displayInfo, properties, type, isArray, isEnum, defaultValue, registry, ...args }) { super({ name: TypeInfo._getName(name, type), fullName: fullName || TypeInfo._getFullName(name, namespace, type), displayInfo, registry, ...args }); this.type = type; this.namespace = TypeInfo._getNamespace(namespace, type); properties = properties && properties.map(p => new PropertyInfo({ ...p, declaringType: this, registry })); this.properties = (properties || []); if (this.type) { Serializable.setTypeFullName(this.type, this.fullName); } this.isEnum = !!isEnum; this.isArray = !!isArray; this.defaultValue = defaultValue; } /** * Gets a value indicating whether this type is the boolean type. * * @type {boolean} True if the type is the boolean type, false otherwise. * @memberof TypeInfo */ get isBoolean() { return this.fullName === TypeName.BooleanTypeName; } /** * Gets a value indicating whether this type is the number type. * * @type {boolean} True if the type is the number type, false otherwise. * @memberof TypeInfo */ get isNumber() { return this.fullName === TypeName.NumberTypeName; } /** * Gets a value indicating whether this type is the string type. * * @type {boolean} True if the type is the string type, false otherwise. * @memberof TypeInfo */ get isString() { return this.fullName === TypeName.StringTypeName; } /** * Gets a value indicating whether this type is the symbol type. * * @type {boolean} True if the type is the symbol type, false otherwise. * @memberof TypeInfo */ get isSymbol() { return this.fullName === TypeName.SymbolTypeName; } /** * Gets a value indicating whether this type is the any type. * * @type {boolean} True if the type is the any type, false otherwise. * @memberof TypeInfo */ get isAny() { return this.fullName === TypeName.AnyTypeName; } static _getName(name, type) { if (name) { return name; } if (type) { return type.name; } throw new ReflectionError('Either the name or the type name should be provided.'); } static _getFullName(name, namespace, type) { name = TypeInfo._getName(name, type); namespace = TypeInfo._getNamespace(namespace, type); return namespace ? `${namespace}.${name}` : name; } static _getNamespace(namespace, type) { return namespace || (type ? Serializable.getTypeNamespace(type) : undefined); } } TypeInfoRegistry.prototype.initialize = (registry) => { registry.register(new TypeInfo({ name: TypeName.AnyTypeName, fullName: 'System.Object', defaultValue: null, registry }), new TypeInfo({ name: TypeName.BooleanTypeName, fullName: 'System.Boolean', defaultValue: false, registry }), new TypeInfo({ name: TypeName.NumberTypeName, fullName: 'System.Double', defaultValue: 0.0, registry }), new TypeInfo({ name: TypeName.StringTypeName, fullName: 'System.String', defaultValue: null, registry }), new TypeInfo({ name: TypeName.ArrayTypeName, fullName: 'System.Array', defaultValue: null, registry }), new TypeInfo({ name: TypeName.ArrayOfAnyTypeName, fullName: 'System.Array`1[[System.Object]]', defaultValue: null, registry }), new TypeInfo({ name: TypeName.ArrayOfByteTypeName, fullName: 'System.Array`1[[System.Byte]]', defaultValue: null, registry }), new TypeInfo({ name: TypeName.SymbolTypeName, fullName: 'System.Symbol', defaultValue: null, registry }), new TypeInfo({ name: TypeName.DateTypeName, fullName: 'System.DateTime', defaultValue: null, registry })); }; /** * Generated bundle index. Do not edit. */ export { DisplayInfo, ElementInfo, PropertyInfo, ReflectionError, TypeInfo, TypeInfoRegistry, TypeName, ValueElementInfo }; //# sourceMappingURL=kephas-reflection.mjs.map