UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

260 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConcreteTypeDescriptor = exports.TypeDescriptor = exports.DataSerializerUtils = void 0; const typedjson_1 = require("typedjson"); const utils_1 = require("./decorators/utils"); /** * Data serializer utilities for managing the ORM mapping */ class DataSerializerUtils { static get META_FIELD() { return '__typedJsonJsonObjectMetadataInformation__'; } /** * Get the own TypedJSON metadata of the prototype * @see {@link https://gist.github.com/krizka/c83fb1966dd57997a1fc02625719387d} * @param {any} proto Prototype of target * @returns {ObjectMetadata} Root object metadata */ static getOwnMetadata(proto) { return typedjson_1.JsonObjectMetadata.getFromConstructor(proto instanceof Function ? proto : proto.constructor); } /** * Get the TypedJSON metadata * @see {@link https://gist.github.com/krizka/c83fb1966dd57997a1fc02625719387d} * @param {any} proto Prototype of target * @returns {ObjectMetadata} Root object metadata */ static getMetadata(proto) { var _a; return (_a = DataSerializerUtils.getOwnMetadata(proto)) !== null && _a !== void 0 ? _a : DataSerializerUtils.getRootMetadata(proto); } static createMetadata(proto) { if (Object.prototype.hasOwnProperty.call(proto, this.META_FIELD)) { return proto[this.META_FIELD]; } // Target has no JsonObjectMetadata associated with it yet, create it now. const objectMetadata = new typedjson_1.JsonObjectMetadata(proto.constructor); // Inherit json members and known types from parent @jsonObject (if any). const parentMetadata = proto[this.META_FIELD]; if (parentMetadata !== undefined) { parentMetadata.dataMembers.forEach((memberMetadata, propKey) => { objectMetadata.dataMembers.set(propKey, memberMetadata); }); parentMetadata.knownTypes.forEach((knownType) => { // Only add if sub type if (knownType === proto.constructor || !(knownType.prototype instanceof proto.constructor)) { return; } objectMetadata.knownTypes.add(knownType); }); // Add sub class to parent parentMetadata.knownTypes.add(objectMetadata.classType); objectMetadata.typeResolver = parentMetadata.typeResolver; objectMetadata.typeHintEmitter = parentMetadata.typeHintEmitter; } Object.defineProperty(proto, this.META_FIELD, { enumerable: false, configurable: false, writable: false, value: objectMetadata, }); return objectMetadata; } /** * Get the root TypedJSON metadata * @see {@link https://gist.github.com/krizka/c83fb1966dd57997a1fc02625719387d} * @param {any} proto Prototype of target * @returns {ObjectMetadata} Root object metadata */ static getRootMetadata(proto) { const protoProto = proto instanceof Function ? proto.prototype : Object.getPrototypeOf(proto); if (!protoProto || !protoProto[DataSerializerUtils.META_FIELD]) { return proto[DataSerializerUtils.META_FIELD]; } return DataSerializerUtils.getRootMetadata(protoProto); } static ensureTypeDescriptor(type) { return type instanceof TypeDescriptor ? type : new ConcreteTypeDescriptor(type); } /** * Get member options of a property in a data type * @param {Constructor} dataType Data type * @param {string} propertyKey Property key * @returns {SerializableMemberOptions} member options */ static getMemberOptions(dataType, propertyKey) { const metadata = DataSerializerUtils.getMetadata(dataType); if (!metadata) { return undefined; } const dataMember = metadata.dataMembers.get(propertyKey); if (!dataMember) { return undefined; } return dataMember.options; } /** * Get member options of an identifier property in a data type * @param {Constructor} dataType Data type * @returns {SerializableMemberOptions} identifier member options */ static getIdentifierMemberOptions(dataType) { const metadata = DataSerializerUtils.getMetadata(dataType); if (!metadata) { return undefined; } return Array.from(metadata.dataMembers.values()).filter((member) => { return member && member.primaryKey; })[0]; } /** * Deep merge member options * @param {unknown} target Target object * @param {string} propertyKey Property key in target * @param {any} options Member options * @returns {any} Merged objects */ static mergeMemberOptions(target, propertyKey, options) { if (typeof options === 'function') { return options; } const memberOptions = DataSerializerUtils.getMemberOptions(target.constructor, propertyKey); if (!memberOptions) { return options; } return mergeDeep(memberOptions, options); } static updateMemberOptions(target, propertyKey, options) { var _a, _b; const reflectPropCtor = Reflect.getMetadata('design:type', target, propertyKey); // Inject additional options if available if (options) { const ownMeta = typedjson_1.JsonObjectMetadata.ensurePresentInPrototype(target); const rootMeta = DataSerializerUtils.getRootMetadata(target.constructor); const ownMemberMetadata = ownMeta.dataMembers.get(propertyKey) || ownMeta.dataMembers.get(options.name); const rootMemberMetadata = rootMeta ? rootMeta.dataMembers.get(propertyKey) || rootMeta.dataMembers.get(options.name) : undefined; if (!ownMemberMetadata) { throw new Error(`Unable to get member metadata for ${target} on property ${propertyKey}!`); } ownMemberMetadata.options = mergeDeep((_a = ownMemberMetadata.options) !== null && _a !== void 0 ? _a : {}, options); if (rootMemberMetadata) { ownMemberMetadata.options = mergeDeep((_b = rootMemberMetadata.options) !== null && _b !== void 0 ? _b : {}, ownMemberMetadata.options); } // Merge known sub types as well rootMeta.knownTypes.forEach((otherType) => { var _a, _b, _c; if (otherType === target.constructor || !(otherType.prototype instanceof target.constructor)) { return; } const otherMeta = (_a = DataSerializerUtils.getMetadata(otherType)) !== null && _a !== void 0 ? _a : typedjson_1.JsonObjectMetadata.ensurePresentInPrototype(otherType); const otherMemberMetadata = otherMeta.dataMembers.get(propertyKey) || otherMeta.dataMembers.get(options.name); if (otherMemberMetadata) { otherMemberMetadata.options = mergeDeep((_b = ownMemberMetadata.options) !== null && _b !== void 0 ? _b : {}, otherMemberMetadata.options); } else { otherMeta.dataMembers.set((_c = options.name) !== null && _c !== void 0 ? _c : propertyKey, (0, utils_1.cloneDeep)(ownMemberMetadata)); } }); // TODO: Possibly need to sync super types as well } // Detect generic types that have no deserialization or constructor specified const meta = typedjson_1.JsonObjectMetadata.ensurePresentInPrototype(target); const existingOptions = meta.dataMembers.get(options ? options.name || propertyKey : propertyKey); if (reflectPropCtor === Object && (!options || (!options.deserializer && !Object.keys(options).includes('constructor')))) { // If the type is Object and no deserializer is specified, it can be any // type of object, including serializable objects. existingOptions.type = () => typedjson_1.AnyT; } else if (existingOptions && typeof options !== 'object' && existingOptions.type() instanceof ConcreteTypeDescriptor) { existingOptions.type = () => new ConcreteTypeDescriptor(reflectPropCtor); } } static updateObjectMetadata(target, options, ownMeta, rootMeta) { var _a, _b, _c; rootMeta.knownTypes.add(target); if (rootMeta.initializerCallback && !ownMeta.initializerCallback) { ownMeta.initializerCallback = rootMeta.initializerCallback; } // Merge options if (options) { ownMeta.options = mergeDeep(ownMeta === rootMeta ? (_a = ownMeta.options) !== null && _a !== void 0 ? _a : {} : (_c = (_b = ownMeta.options) !== null && _b !== void 0 ? _b : rootMeta.options) !== null && _c !== void 0 ? _c : {}, options); // Merge known sub types as well rootMeta.knownTypes.forEach((otherType) => { var _a; if (otherType === target || !(otherType.prototype instanceof target)) { return; } const otherMeta = DataSerializerUtils.getMetadata(otherType); otherMeta.options = mergeDeep((_a = ownMeta.options) !== null && _a !== void 0 ? _a : {}, otherMeta.options); if (!otherMeta.initializerCallback && ownMeta.initializerCallback) { otherMeta.initializerCallback = ownMeta.initializerCallback; } }); } // Sync settings from super types rootMeta.knownTypes.forEach((otherType) => { if (otherType === target || !(target.prototype instanceof otherType)) { return; } const otherMeta = DataSerializerUtils.getMetadata(otherType); if (otherMeta && otherMeta.initializerCallback && !ownMeta.initializerCallback) { ownMeta.initializerCallback = otherMeta.initializerCallback; } }); return ownMeta; } } exports.DataSerializerUtils = DataSerializerUtils; class TypeDescriptor { constructor(ctor) { this.ctor = ctor; } getTypes() { return [this.ctor]; } hasFriendlyName() { return this.ctor.name !== 'Object'; } } exports.TypeDescriptor = TypeDescriptor; class ConcreteTypeDescriptor extends TypeDescriptor { constructor(ctor) { super(ctor); } } exports.ConcreteTypeDescriptor = ConcreteTypeDescriptor; /** * Deep merge objects * @param {any} target Target object * @param {any} source Source object * @returns {any} Merged object */ function mergeDeep(target, source) { const output = (0, utils_1.cloneDeep)(target); if ((0, utils_1.isObject)(target) && (0, utils_1.isObject)(source)) { Object.keys(source).forEach((key) => { if (Array.isArray(source[key])) { output[key] = source[key]; const targetProperty = target[key] !== undefined ? (Array.isArray(target[key]) ? target[key] : [target[key]]) : []; output[key].push(...targetProperty.filter((val) => !source[key].includes(val))); } else if ((0, utils_1.isObject)(source[key])) { if (!(key in target)) Object.assign(output, { [key]: source[key] }); else output[key] = mergeDeep(target[key], source[key]); } else { Object.assign(output, { [key]: source[key] }); } }); } return output; } //# sourceMappingURL=DataSerializerUtils.js.map