UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

263 lines 15.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Serializer = void 0; const serializer_1 = require("typedjson/lib/cjs/serializer"); const type_descriptor_1 = require("typedjson/lib/cjs/type-descriptor"); const typedjson_1 = require("typedjson"); const helpers_1 = require("typedjson/lib/cjs/helpers"); const options_base_1 = require("typedjson/lib/cjs/options-base"); const BufferUtils_1 = require("../utils/BufferUtils"); class Serializer extends serializer_1.Serializer { constructor() { super(); this.errorHandler = (e) => { e.message = e.message.replace('@jsonObject', '@SerializableObject()'); e.message = e.message.replace('@jsonMember', '@SerializableMember()'); e.message = e.message.replace('@jsonSetMember', '@SerializableSetMember()'); e.message = e.message.replace('@jsonMapMember', '@SerializableMapMember()'); e.message = e.message.replace('@jsonArrayMember', '@SerializableArrayMember()'); throw e; }; this.setSerializationStrategy(Map, this.convertAsMap.bind(this)); this.setSerializationStrategy(Array, this.convertAsArray.bind(this)); this.setSerializationStrategy(Set, this.convertAsSet.bind(this)); this.setSerializationStrategy(Uint8Array, BufferUtils_1.BufferUtils.toHexString); } convertSingleValue(sourceObject, typeDescriptor, memberName, memberOptions, serializerOptions) { const targetObject = this._convertSingleValue.bind(this)(sourceObject, typeDescriptor, memberName, memberOptions, serializerOptions); if (memberName === undefined && typeof targetObject === 'object') { targetObject.__type = typeDescriptor.ctor.name; } return targetObject; } _convertSingleValue(sourceObject, typeDescriptor, memberName, memberOptions, serializerOptions) { if (this.retrievePreserveNull(memberOptions) && sourceObject === null) { return null; } if (!(0, helpers_1.isValueDefined)(sourceObject)) { return; } if (!(0, helpers_1.isInstanceOf)(sourceObject, typeDescriptor.ctor)) { const expectedName = (0, helpers_1.nameof)(typeDescriptor.ctor); const actualName = (0, helpers_1.nameof)(sourceObject.constructor); this.errorHandler(new TypeError(`Could not serialize '${memberName}': expected '${expectedName}',` + ` got '${actualName}'.`)); return; } const serializer = this.serializationStrategy.get(typeDescriptor.ctor); if (serializer !== undefined) { return serializer(sourceObject, typeDescriptor, memberName, this, memberOptions, serializerOptions); } // if not present in the strategy do property by property serialization if (typeof sourceObject === 'object') { return this.convertAsObject(sourceObject, typeDescriptor, memberName, this, memberOptions, serializerOptions); } let error = `Could not serialize '${memberName}'; don't know how to serialize type`; if (typeDescriptor.hasFriendlyName()) { error += ` '${typeDescriptor.ctor.name}'`; } this.errorHandler(new TypeError(`${error}.`)); } convertAsObject(sourceObject, typeDescriptor, memberName, serializer, memberOptions, serializerOptions) { let sourceTypeMetadata; let targetObject; let typeHintEmitter = serializer.getTypeHintEmitter(); if (sourceObject.constructor !== typeDescriptor.ctor && sourceObject instanceof typeDescriptor.ctor) { // The source object is not of the expected type, but it is a valid subtype. // This is OK, and we'll proceed to gather object metadata from the subtype instead. sourceTypeMetadata = typedjson_1.JsonObjectMetadata.getFromConstructor(sourceObject.constructor); } else { sourceTypeMetadata = typedjson_1.JsonObjectMetadata.getFromConstructor(typeDescriptor.ctor); } if (sourceTypeMetadata === undefined) { // Untyped serialization, "as-is", we'll just pass the object on. // We'll clone the source object, because type hints are added to the object itself, and we // don't want to modify // to the original object. targetObject = Object.assign({}, sourceObject); } else { const beforeSerializationMethodName = sourceTypeMetadata.beforeSerializationMethodName; if (beforeSerializationMethodName != null) { if (typeof sourceObject[beforeSerializationMethodName] === 'function') { // check for member first sourceObject[beforeSerializationMethodName](); } else if (typeof sourceObject.constructor[beforeSerializationMethodName] === 'function') { // check for static sourceObject.constructor[beforeSerializationMethodName](); } else { serializer.getErrorHandler()(new TypeError(`beforeSerialization callback '` + `${(0, helpers_1.nameof)(sourceTypeMetadata.classType)}.${beforeSerializationMethodName}` + `' is not a method.`)); } } const sourceMeta = sourceTypeMetadata; // Strong-typed serialization available. // We'll serialize by members that have been marked with @jsonMember (including // array/set/map members), and perform recursive conversion on each of them. The converted // objects are put on the 'targetObject', which is what will be put into 'JSON.stringify' // finally. targetObject = {}; const classOptions = (0, options_base_1.mergeOptions)(serializer.options, sourceMeta.options); if (sourceMeta.typeHintEmitter != null) { typeHintEmitter = sourceMeta.typeHintEmitter; } sourceMeta.dataMembers.forEach((objMemberMetadata) => { const objMemberOptions = (0, options_base_1.mergeOptions)(classOptions, objMemberMetadata.options); let serialized; const value = sourceObject[objMemberMetadata.key]; if (objMemberMetadata.serializer != null) { serialized = objMemberMetadata.serializer(value, { fallback: (so, td) => serializer.convertSingleValue(so, (0, type_descriptor_1.ensureTypeDescriptor)(td)), }); } else if (objMemberMetadata.type == null) { throw new TypeError(`Could not serialize ${objMemberMetadata.name}, there is` + ` no constructor nor serialization function to use.`); } else if (objMemberMetadata.type() === typedjson_1.AnyT && value !== null && value !== undefined) { // Any type, serialize as an unknown object const globalDataType = Object.getPrototypeOf(value).constructor; serialized = serializer.convertSingleValue(value, globalDataType ? (0, type_descriptor_1.ensureTypeDescriptor)(globalDataType) : objMemberMetadata.type(), `${(0, helpers_1.nameof)(sourceMeta.classType)}.${objMemberMetadata.key}`, objMemberOptions, serializerOptions); if (typeof serialized === 'object' && serialized !== null) { serialized.__type = globalDataType ? globalDataType.name : 'Object'; } } else { serialized = serializer.convertSingleValue(value, objMemberMetadata.type(), `${(0, helpers_1.nameof)(sourceMeta.classType)}.${objMemberMetadata.key}`, objMemberOptions, serializerOptions); } if ((serializer.retrievePreserveNull(objMemberOptions) && serialized === null) || (0, helpers_1.isValueDefined)(serialized)) { targetObject[objMemberMetadata.name] = serialized; } }); } // Add type-hint. typeHintEmitter(targetObject, sourceObject, typeDescriptor.ctor, sourceTypeMetadata); return targetObject; } /** * Performs the conversion of an array of typed objects (or primitive values) to an array of simple * javascript objects * (or primitive values) for serialization. * @param sourceObject Source object to convert * @param typeDescriptor Type descriptor of source object * @param memberName Member name to convert * @param serializer Serializer * @param memberOptions Member options of memberName * @param serializerOptions Custom serializer options */ convertAsArray(sourceObject, typeDescriptor, memberName, serializer, memberOptions, serializerOptions) { if (!(typeDescriptor instanceof type_descriptor_1.ArrayTypeDescriptor)) { throw new TypeError(`Could not serialize ${memberName} as Array: incorrect TypeDescriptor detected, please` + ' use proper annotation or function for this type'); } if (typeDescriptor.elementType == null) { throw new TypeError(`Could not serialize ${memberName} as Array: missing element type definition.`); } // Check the type of each element, individually. // If at least one array element type is incorrect, we return undefined, which results in no // value emitted during serialization. This is so that invalid element types don't unexpectedly // alter the ordering of other, valid elements, and that no unexpected undefined values are in // the emitted array. sourceObject.forEach((element, i) => { if (!(serializer.retrievePreserveNull(memberOptions) && element === null) && !(0, helpers_1.isInstanceOf)(element, typeDescriptor.elementType.ctor)) { const expectedTypeName = (0, helpers_1.nameof)(typeDescriptor.elementType.ctor); const actualTypeName = element && (0, helpers_1.nameof)(element.constructor); throw new TypeError(`Could not serialize ${memberName}[${i}]:` + ` expected '${expectedTypeName}', got '${actualTypeName}'.`); } }); return sourceObject.map((element, i) => { return serializer.convertSingleValue(element, typeDescriptor.elementType, `${memberName}[${i}]`, memberOptions, serializerOptions); }); } /** * Performs the conversion of a set of typed objects (or primitive values) into an array * of simple javascript objects. * @param sourceObject * @param typeDescriptor * @param memberName * @param serializer * @param memberOptions * @param serializerOptions * @returns */ convertAsSet(sourceObject, typeDescriptor, memberName, serializer, memberOptions, serializerOptions) { if (!(typeDescriptor instanceof type_descriptor_1.SetTypeDescriptor)) { throw new TypeError(`Could not serialize ${memberName} as Set: incorrect TypeDescriptor detected, please` + ' use proper annotation or function for this type'); } if (typeDescriptor.elementType == null) { throw new TypeError(`Could not serialize ${memberName} as Set: missing element type definition.`); } memberName += '[]'; const resultArray = []; // Convert each element of the set, and put it into an output array. // The output array is the one serialized, as JSON.stringify does not support Set serialization. // (TODO: clarification needed) sourceObject.forEach((element) => { const resultElement = serializer.convertSingleValue(element, typeDescriptor.elementType, memberName, memberOptions, serializerOptions); // Add to output if the source element was undefined, OR the converted element is defined. // This will add intentionally undefined values to output, but not values that became // undefined DURING serializing (usually because of a type-error). if (!(0, helpers_1.isValueDefined)(element) || (0, helpers_1.isValueDefined)(resultElement)) { resultArray.push(resultElement); } }); return resultArray; } /** * Performs the conversion of a map of typed objects (or primitive values) into an array * of simple javascript objects with `key` and `value` properties. * @param sourceObject * @param typeDescriptor * @param memberName * @param serializer * @param memberOptions * @param serializerOptions */ convertAsMap(sourceObject, typeDescriptor, memberName, serializer, memberOptions, serializerOptions) { if (!(typeDescriptor instanceof type_descriptor_1.MapTypeDescriptor)) { // Serialize as object return serializer.convertAsObject(sourceObject, typeDescriptor, memberName, serializer, memberOptions); } if (typeDescriptor.valueType == null) { // @todo Check type throw new TypeError(`Could not serialize ${memberName} as Map: missing value type definition.`); } if (typeDescriptor.keyType == null) { // @todo Check type throw new TypeError(`Could not serialize ${memberName} as Map: missing key type definition.`); } const keyMemberName = `${memberName}[].key`; const valueMemberName = `${memberName}[].value`; const resultShape = typeDescriptor.getCompleteOptions().shape; const result = resultShape === 1 ? {} : []; const preserveNull = serializer.retrievePreserveNull(memberOptions); // Convert each *entry* in the map to a simple javascript object with key and value properties. sourceObject.forEach((value, key) => { const resultKeyValuePairObj = { key: serializer.convertSingleValue(key, typeDescriptor.keyType, keyMemberName, memberOptions, serializerOptions), value: serializer.convertSingleValue(value, typeDescriptor.valueType, valueMemberName, memberOptions, serializerOptions), }; // We are not going to emit entries with undefined keys OR undefined values. const keyDefined = (0, helpers_1.isValueDefined)(resultKeyValuePairObj.key); const valueDefined = (resultKeyValuePairObj.value === null && preserveNull) || (0, helpers_1.isValueDefined)(resultKeyValuePairObj.value); if (keyDefined && valueDefined) { if (resultShape === 1) { result[resultKeyValuePairObj.key] = resultKeyValuePairObj.value; } else { result.push(resultKeyValuePairObj); } } }); return result; } } exports.Serializer = Serializer; //# sourceMappingURL=Serializer.js.map