You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.2 KiB
JavaScript

"use strict";
const defaultValue = require("default-value");
const mapObj = require("map-obj");
const isPlaceholder = require("../util/is-placeholder");
const createPlaceholderManager = require("./placeholder-manager");
function isReference(serializedData) {
return (serializedData != null && serializedData._d_sT === "cTR");
}
/* FIXME: Pass both key and value to custom deserializer */
module.exports = function createDeserializer(topLevelType, topLevelData, typeMap, options = {}) {
let seen = new Map();
let placeholders = createPlaceholderManager();
let customDeserializer = defaultValue(options.deserializer, (value) => value);
function deserializeSequenceItems(itemRule, entries) {
let seenPlaceholder = false;
let items = entries.map((item) => {
let deserializedValue = deserializeEntry(itemRule, item);
if (isPlaceholder(deserializedValue)) {
seenPlaceholder = true;
}
return deserializedValue;
});
return {
items: items,
seenPlaceholder: seenPlaceholder
};
}
function deserializeSet(rule, entries) {
let {items, seenPlaceholder} = deserializeSequenceItems(rule._itemType, entries);
let set = new Set(items);
if (seenPlaceholder) {
placeholders.markSet(set);
}
return set;
}
function deserializeArray(rule, entries) {
let {items, seenPlaceholder} = deserializeSequenceItems(rule._itemType, entries);
if (seenPlaceholder) {
placeholders.markArray(items);
}
return items;
}
function deserializeMap(rule, entries) {
let seenPlaceholder = false;
let map = new Map(entries.map(([itemKey, itemValue]) => {
let deserializedKey = deserializeEntry(rule._keyType, itemKey);
let deserializedValue = deserializeEntry(rule._itemType, itemValue);
if (isPlaceholder(deserializedKey) || isPlaceholder(deserializedValue)) {
seenPlaceholder = true;
}
return [
deserializedKey,
deserializedValue
];
}));
if (seenPlaceholder) {
placeholders.markMap(map);
}
return map;
}
function deserializeEntry(rule, serializedData) {
if (serializedData == null) {
return customDeserializer(serializedData);
} else if (rule._isCustomType) {
return deserializeInstanceOrReference(rule, serializedData);
} else if (rule._isCustomRegistryType) {
return deserializeInstanceOrReference(rule._registry._getType(rule._name), serializedData);
} else if (rule._isRegistryTrait || rule._isTrait) {
return deserializeInstanceFuzzy(serializedData);
} else if (rule._collectionType === "set") {
if (serializedData._d_sT === "gS") {
return deserializeSet(rule, serializedData.entries);
} else {
/* FIXME: Clearer error message */
throw new Error("Expected guarded set, but got something else instead");
}
} else if (rule._collectionType === "map") {
if (serializedData._d_sT === "gM") {
return deserializeMap(rule, serializedData.entries);
} else {
/* FIXME: Clearer error message */
throw new Error("Expected guarded map, but got something else instead");
}
} else if (rule._collectionType === "array") {
if (serializedData._d_sT === "gA") {
return deserializeArray(rule, serializedData.entries);
} else {
/* FIXME: Clearer error message */
throw new Error("Expected guarded array, but got something else instead");
}
} else {
/* This also covers `either` rules where the serializedData is a type instance or reference. */
return deserializeEntryFuzzy(serializedData);
}
}
function deserializeEntryFuzzy(serializedData) {
if (serializedData != null && (serializedData._d_sT === "cT" || serializedData._d_sT === "cTR")) {
return deserializeInstanceFuzzy(serializedData);
} else {
return customDeserializer(serializedData);
}
}
function deserializeInstance(typeFactory, serializedData) {
let placeholderProperties = [];
let deserializedData = mapObj(serializedData.data, (key, value) => {
let rule = typeFactory._cumulativeSchema[key];
let deserializedValue = deserializeEntry(rule, value);
if (isPlaceholder(deserializedValue)) {
placeholderProperties.push(key);
}
return [key, deserializedValue];
});
let instance = typeFactory(deserializedData);
for (let property of placeholderProperties) {
placeholders.markProperty(instance, property);
}
seen.set(serializedData.id, instance);
return instance;
}
function deserializeReference(serializedData) {
return {
_isDeserializationPlaceholder: true,
_deserializationId: serializedData.id
};
}
function deserializeInstanceOrReference(typeFactory, serializedData) {
if (isReference(serializedData)) {
return deserializeReference(serializedData);
} else {
return deserializeInstance(typeFactory, serializedData);
}
}
function deserializeInstanceFuzzy(serializedData) {
if (isReference(serializedData)) {
return deserializeReference(serializedData);
} else if (typeMap.has(serializedData.type)) {
return deserializeInstance(typeMap.get(serializedData.type), serializedData);
} else {
throw new Error(`Encountered instance of an unknown type with hash ${serializedData.type}`);
}
}
let topLevelInstance = deserializeInstance(topLevelType, topLevelData);
placeholders.fillInPlaceholders(seen);
return topLevelInstance;
};