@openhps/core
Version:
Open Hybrid Positioning System - Core component
296 lines • 17.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Deserializer = void 0;
const deserializer_1 = require("typedjson/lib/cjs/deserializer");
const type_descriptor_1 = require("typedjson/lib/cjs/type-descriptor");
const typedjson_1 = require("typedjson");
const options_base_1 = require("typedjson/lib/cjs/options-base");
const helpers_1 = require("typedjson/lib/cjs/helpers");
const BufferUtils_1 = require("../utils/BufferUtils");
class Deserializer extends deserializer_1.Deserializer {
typeResolver(sourceObject, knownTypes) {
var _a;
return sourceObject['__type'] !== undefined
? knownTypes.get(sourceObject.__type)
: (_a = sourceObject.constructor) !== null && _a !== void 0 ? _a : Object;
}
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.setDeserializationStrategy(Map, this.convertAsMap.bind(this));
this.setDeserializationStrategy(Array, this.convertAsArray.bind(this));
this.setDeserializationStrategy(Set, this.convertAsSet.bind(this));
this.setDeserializationStrategy(Uint8Array, BufferUtils_1.BufferUtils.fromHexString);
this.setDeserializationStrategy(typedjson_1.AnyT.ctor, this.identityDeserializer.bind(this));
}
identityDeserializer(sourceObject, _, knownTypes, ...args) {
// First check typehint
const typeFromTypeHint = this.getTypeResolver()(sourceObject, knownTypes);
if (typeFromTypeHint != null) {
return this.convertSingleValue(sourceObject, (0, type_descriptor_1.ensureTypeDescriptor)(typeFromTypeHint), knownTypes, ...args);
}
return sourceObject;
}
convertSingleValue(sourceObject, typeDescriptor, knownTypes, memberName, memberOptions, serializerOptions) {
return this._convertSingleValue.bind(this)(sourceObject, typeDescriptor, knownTypes, memberName, memberOptions, serializerOptions);
}
_convertSingleValue(sourceObject, typeDescriptor, knownTypes, memberName, memberOptions, serializerOptions) {
if (this.retrievePreserveNull(memberOptions) && sourceObject === null) {
return null;
}
else if (!(0, helpers_1.isValueDefined)(sourceObject)) {
return;
}
const deserializer = this.deserializationStrategy.get(typeDescriptor.ctor);
if (deserializer !== undefined) {
return deserializer(sourceObject, typeDescriptor, knownTypes, memberName, this, memberOptions, serializerOptions);
}
if (typeof sourceObject === 'object') {
return this.convertAsObject(sourceObject, typeDescriptor, knownTypes, memberName, this, memberOptions, serializerOptions);
}
let error = `Could not deserialize '${memberName}'; don't know how to deserialize type`;
if (typeDescriptor.hasFriendlyName()) {
error += ` '${typeDescriptor.ctor.name}'`;
}
this.errorHandler(new TypeError(`${error}.`));
}
convertAsObject(sourceObject, typeDescriptor, knownTypes, memberName, deserializer, memberOptions, serializerOptions) {
if (typeof sourceObject !== 'object' || sourceObject === null) {
deserializer.getErrorHandler()(new TypeError(`Cannot deserialize ${memberName}: 'sourceObject' must be a defined object.`));
return undefined;
}
let expectedSelfType = typeDescriptor.ctor;
let sourceObjectMetadata = typedjson_1.JsonObjectMetadata.getFromConstructor(expectedSelfType);
let typeResolver = deserializer.getTypeResolver();
if (sourceObjectMetadata !== undefined) {
if (sourceObjectMetadata.typeResolver != null) {
typeResolver = sourceObjectMetadata.typeResolver;
}
}
// Check if a type-hint is available from the source object.
const typeFromTypeHint = typeResolver(sourceObject, knownTypes);
if (typeFromTypeHint != null) {
// Check if type hint is a valid subtype of the expected source type.
if ((0, helpers_1.isSubtypeOf)(typeFromTypeHint, expectedSelfType)) {
// Hell yes.
expectedSelfType = typeFromTypeHint;
sourceObjectMetadata = typedjson_1.JsonObjectMetadata.getFromConstructor(typeFromTypeHint);
}
}
if ((sourceObjectMetadata === null || sourceObjectMetadata === void 0 ? void 0 : sourceObjectMetadata.isExplicitlyMarked) === true) {
const sourceMetadata = sourceObjectMetadata;
// Strong-typed deserialization available, get to it.
// First deserialize properties into a temporary object.
const sourceObjectWithDeserializedProperties = {};
const classOptions = (0, options_base_1.mergeOptions)(deserializer.options, sourceMetadata.options);
// Deserialize by expected properties.
sourceMetadata.dataMembers.forEach((objMemberMetadata, propKey) => {
const objMemberValue = sourceObject[propKey];
const objMemberDebugName = `${(0, helpers_1.nameof)(sourceMetadata.classType)}.${propKey}`;
const objMemberOptions = (0, options_base_1.mergeOptions)(classOptions, objMemberMetadata.options);
let revivedValue;
if (objMemberMetadata.deserializer != null) {
revivedValue = objMemberMetadata.deserializer(objMemberValue, {
fallback: (so, td) => deserializer.convertSingleValue(so, (0, type_descriptor_1.ensureTypeDescriptor)(td), knownTypes),
});
}
else if (objMemberMetadata.type == null) {
throw new TypeError(`Cannot deserialize ${objMemberDebugName} there is` +
` no constructor nor deserialization function to use.`);
}
else {
revivedValue = deserializer.convertSingleValue(objMemberValue, objMemberMetadata.type(), knownTypes, objMemberDebugName, objMemberOptions, serializerOptions);
}
// @todo revivedValue will never be null in RHS of ||
if ((0, helpers_1.isValueDefined)(revivedValue) ||
(deserializer.retrievePreserveNull(objMemberOptions) && revivedValue === null)) {
sourceObjectWithDeserializedProperties[objMemberMetadata.key] = revivedValue;
}
else if (objMemberMetadata.isRequired === true) {
deserializer.getErrorHandler()(new TypeError(`Missing required member '${objMemberDebugName}'.`));
}
});
// Next, instantiate target object.
let targetObject;
if (typeof sourceObjectMetadata.initializerCallback === 'function') {
try {
targetObject = sourceObjectMetadata.initializerCallback(sourceObjectWithDeserializedProperties, sourceObject);
// Check the validity of user-defined initializer callback.
if (targetObject == null) {
throw new TypeError(`Cannot deserialize ${memberName}:` +
` 'initializer' function returned undefined/null` +
`, but '${(0, helpers_1.nameof)(sourceObjectMetadata.classType)}' was expected.`);
}
else if (!(targetObject instanceof sourceObjectMetadata.classType)) {
throw new TypeError(`Cannot deserialize ${memberName}:` +
`'initializer' returned '${(0, helpers_1.nameof)(targetObject.constructor)}'` +
`, but '${(0, helpers_1.nameof)(sourceObjectMetadata.classType)}' was expected` +
`, and '${(0, helpers_1.nameof)(targetObject.constructor)}' is not a subtype of` +
` '${(0, helpers_1.nameof)(sourceObjectMetadata.classType)}'`);
}
}
catch (e) {
deserializer.getErrorHandler()(e);
return undefined;
}
}
else {
targetObject = deserializer.instantiateType(expectedSelfType);
}
// Finally, assign deserialized properties to target object.
Object.assign(targetObject, sourceObjectWithDeserializedProperties);
// Call onDeserialized method (if any).
const methodName = sourceObjectMetadata.onDeserializedMethodName;
if (methodName != null) {
if (typeof targetObject[methodName] === 'function') {
// check for member first
targetObject[methodName]();
}
else if (typeof targetObject.constructor[methodName] === 'function') {
// check for static
targetObject.constructor[methodName]();
}
else {
deserializer.getErrorHandler()(new TypeError(`onDeserialized callback` +
`'${(0, helpers_1.nameof)(sourceObjectMetadata.classType)}.${methodName}' is not a method.`));
}
}
return targetObject;
}
else {
// Untyped deserialization into Object instance.
const targetObject = {};
Object.keys(sourceObject).forEach((sourceKey) => {
targetObject[sourceKey] = deserializer.convertSingleValue(sourceObject[sourceKey], new type_descriptor_1.ConcreteTypeDescriptor(sourceObject[sourceKey].constructor), knownTypes, sourceKey, memberOptions, serializerOptions);
});
return targetObject;
}
}
convertAsArray(sourceObject, typeDescriptor, knownTypes, memberName, deserializer, memberOptions, serializableOptions) {
if (!(typeDescriptor instanceof type_descriptor_1.ArrayTypeDescriptor)) {
throw new TypeError(`Could not deserialize ${memberName} as Array: incorrect TypeDescriptor detected,` +
' please use proper annotation or function for this type');
}
if (!Array.isArray(sourceObject)) {
deserializer.getErrorHandler()(new TypeError(this.makeTypeErrorMessage(Array, sourceObject.constructor, memberName)));
return [];
}
if (typeDescriptor.elementType == null) {
deserializer.getErrorHandler()(new TypeError(`Could not deserialize ${memberName} as Array: missing constructor reference of` +
` Array elements.`));
return [];
}
return sourceObject.map((element, i) => {
// If an array element fails to deserialize, substitute with undefined. This is so that the
// original ordering is not interrupted by faulty
// entries, as an Array is ordered.
try {
return deserializer.convertSingleValue(element, typeDescriptor.elementType, knownTypes, `${memberName}[${i}]`, memberOptions, serializableOptions);
}
catch (e) {
deserializer.getErrorHandler()(e);
// Keep filling the array here with undefined to keep original ordering.
// Note: this is just aesthetics, not returning anything produces the same result.
return undefined;
}
});
}
convertAsSet(sourceObject, typeDescriptor, knownTypes, memberName, deserializer, memberOptions, serializableOptions) {
if (!(typeDescriptor instanceof type_descriptor_1.SetTypeDescriptor)) {
throw new TypeError(`Could not deserialize ${memberName} as Set: incorrect TypeDescriptor detected,` +
` please use proper annotation or function for this type`);
}
if (!Array.isArray(sourceObject)) {
deserializer.getErrorHandler()(new TypeError(this.makeTypeErrorMessage(Array, sourceObject.constructor, memberName)));
return new Set();
}
if (typeDescriptor.elementType == null) {
deserializer.getErrorHandler()(new TypeError(`Could not deserialize ${memberName} as Set: missing constructor reference of` + ` Set elements.`));
return new Set();
}
const resultSet = new Set();
sourceObject.forEach((element, i) => {
try {
resultSet.add(deserializer.convertSingleValue(element, typeDescriptor.elementType, knownTypes, `${memberName}[${i}]`, memberOptions, serializableOptions));
}
catch (e) {
// Faulty entries are skipped, because a Set is not ordered, and skipping an entry
// does not affect others.
deserializer.getErrorHandler()(e);
}
});
return resultSet;
}
convertAsMap(sourceObject, typeDescriptor, knownTypes, memberName, deserializer, memberOptions, serializableOptions) {
if (!(typeDescriptor instanceof type_descriptor_1.MapTypeDescriptor)) {
throw new TypeError(`Could not deserialize ${memberName} as Map: incorrect TypeDescriptor detected,` +
'please use proper annotation or function for this type');
}
const expectedShape = typeDescriptor.getCompleteOptions().shape;
if (!this.isExpectedMapShape(sourceObject, expectedShape)) {
const expectedType = expectedShape === 0 ? Array : Object;
deserializer.getErrorHandler()(new TypeError(this.makeTypeErrorMessage(expectedType, sourceObject.constructor, memberName)));
return new Map();
}
if (typeDescriptor.keyType == null) {
deserializer.getErrorHandler()(new TypeError(`Could not deserialize ${memberName} as Map: missing key constructor.`));
return new Map();
}
if (typeDescriptor.valueType == null) {
deserializer.getErrorHandler()(new TypeError(`Could not deserialize ${memberName} as Map: missing value constructor.`));
return new Map();
}
const keyMemberName = `${memberName}[].key`;
const valueMemberName = `${memberName}[].value`;
const resultMap = new Map();
if (expectedShape.name === 'OBJECT') {
Object.keys(sourceObject).forEach((key) => {
try {
const resultKey = deserializer.convertSingleValue(key, typeDescriptor.keyType, knownTypes, keyMemberName, memberOptions, serializableOptions);
if ((0, helpers_1.isValueDefined)(resultKey)) {
resultMap.set(resultKey, deserializer.convertSingleValue(sourceObject[key], typeDescriptor.valueType, knownTypes, valueMemberName, memberOptions, serializableOptions));
}
}
catch (e) {
// Faulty entries are skipped, because a Map is not ordered,
// and skipping an entry does not affect others.
deserializer.getErrorHandler()(e);
}
});
}
else {
sourceObject.forEach((element) => {
try {
const key = deserializer.convertSingleValue(element.key, typeDescriptor.keyType, knownTypes, keyMemberName, memberOptions, serializableOptions);
// Undefined/null keys not supported, skip if so.
if ((0, helpers_1.isValueDefined)(key)) {
resultMap.set(key, deserializer.convertSingleValue(element.value, typeDescriptor.valueType, knownTypes, valueMemberName, memberOptions, serializableOptions));
}
}
catch (e) {
// Faulty entries are skipped, because a Map is not ordered,
// and skipping an entry does not affect others.
deserializer.getErrorHandler()(e);
}
});
}
return resultMap;
}
isExpectedMapShape(source, expectedShape) {
return (expectedShape === 0 && Array.isArray(source)) || (expectedShape === 1 && typeof source === 'object');
}
makeTypeErrorMessage(expectedType, actualType, memberName) {
const expectedTypeName = typeof expectedType === 'function' ? (0, helpers_1.nameof)(expectedType) : expectedType;
const actualTypeName = typeof actualType === 'function' ? (0, helpers_1.nameof)(actualType) : actualType;
return `Could not deserialize ${memberName}: expected '${expectedTypeName}',` + ` got '${actualTypeName}'.`;
}
}
exports.Deserializer = Deserializer;
//# sourceMappingURL=Deserializer.js.map