"use strict"; const isPlaceholder = require("../util/is-placeholder"); module.exports = function createPlaceholderManager() { let placeholders = []; return { markProperty: function (object, property) { placeholders.push({ type: "property", object: object, property: property }); }, markSet: function (set) { placeholders.push({ type: "set", set: set }); }, markArray: function (array) { placeholders.push({ type: "array", array: array }); }, markMap: function (map) { placeholders.push({ type: "map", map: map }); }, fillInPlaceholders: function (seen) { function getSeenItem(placeholder) { if (seen.has(placeholder._deserializationId)) { return seen.get(placeholder._deserializationId); } else { throw new Error(`Did not encounter an object with the ID ${placeholder._deserializationId}`); } } function fillInSetPlaceholders(set) { let originalItems = Array.from(set.values()); set.clear(); for (let item of originalItems) { if (isPlaceholder(item)) { set.add(getSeenItem(item)); } else { set.add(item); } } } function fillInArrayPlaceholders(array) { array.forEach((item, i) => { if (isPlaceholder(item)) { array[i] = getSeenItem(item); } }); } function fillInMapPlaceholders(map) { let originalItems = Array.from(map.entries()); map.clear(); for (let [key, value] of originalItems) { let newKey, newValue; if (isPlaceholder(key)) { newKey = getSeenItem(key); } else { newKey = key; } if (isPlaceholder(value)) { newValue = getSeenItem(value); } else { newValue = value; } map.set(newKey, newValue); } } function fillInPlaceholderProperty(object, property) { object[property] = getSeenItem(object[property]); } placeholders.forEach((marker) => { /* NOTE: The Set/Map implementations below are probably slow. Maybe there's a faster implementation? */ if (marker.type === "set") { fillInSetPlaceholders(marker.set); } else if (marker.type === "array") { fillInArrayPlaceholders(marker.array); } else if (marker.type === "map") { fillInMapPlaceholders(marker.map); } else if (marker.type === "property") { fillInPlaceholderProperty(marker.object, marker.property); } else { throw new Error(`Unrecognized placeholder marker type: ${marker.type}`); } }); /* To ensure that any accidental future invocations of this function will fail loudly. */ placeholders = null; } }; };