const rand = () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); type CSValue = CSLiteral | CSRef; type CSLiteral = string | number | boolean | null; type CSRef = [string]; export function analyzeRefs(obj: any) { const reference = new Map(); // Build reference table JSON.stringify(obj, (key, value) => { if(typeof(value) === "object" && value !== null) { if(reference.has(value)) { return null; } else { reference.set(value, value === obj ? "entry" : rand()); return value; } } else return null; }); const deCircularized: Record | CSValue[]> = {}; for(const [value, key] of reference) { if(Array.isArray(value)) { const thisObj: CSValue[] = value.map((arrItem) => { if(typeof(arrItem) === "object") { return [reference.get(arrItem)!]; } else { return arrItem; } }); deCircularized[key] = thisObj; } else { const thisObj: Record = {}; for(const entry of Object.entries(value)) { if(typeof(entry[1]) === "object") { thisObj[entry[0]] = [reference.get(entry[1])!]; } else { thisObj[entry[0]] = entry[1]; } } deCircularized[key] = thisObj; } } return deCircularized; } export function reconstructRefs(deCircularized: Record | CSValue[]>) { const reconstructedRefs = new Map(); const entries = Object.entries(deCircularized); // Create empty variables first, to allow for circular nesting upon population for(const [key, serialized] of entries) { reconstructedRefs.set(key, Array.isArray(serialized) ? [] : {}); } // Populate for(const [key, serialized] of entries) { // Get current referenced object const newVar = reconstructedRefs.get(key)!; if(Array.isArray(serialized) && Array.isArray(newVar)) { newVar.push(...serialized.map((ptr) => { if(typeof(ptr) !== "object" || ptr === null) { return ptr; } else { return reconstructedRefs.get(ptr[0]); } })); } else { for(const entry of Object.entries(serialized)) { if(typeof(entry[1]) !== "object" || entry[1] === null) { newVar[entry[0]] = entry[1]; } else { newVar[entry[0]] = reconstructedRefs.get(entry[1][0]); } } } } return reconstructedRefs.get("entry"); }