Skip to content

Instantly share code, notes, and snippets.

@igrek8
Created June 29, 2023 10:13
Show Gist options
  • Save igrek8/00b39aeba03f2be8d4dbf6e0d7463812 to your computer and use it in GitHub Desktop.
Save igrek8/00b39aeba03f2be8d4dbf6e0d7463812 to your computer and use it in GitHub Desktop.
Pack and unpack JSON value
export function packJSON(object: unknown) {
const fragments: object[] = [];
const indices = new Map<string, number>();
function next(node: unknown): unknown {
if (node && typeof node === "object") {
let fragment: object;
if (Array.isArray(node)) {
fragment = node.map((el) => next(el));
} else {
fragment = Object.entries(node).reduce<Record<string, unknown>>((obj, [key, value]) => {
obj[key] = next(value);
return obj;
}, {});
}
const id = JSON.stringify(fragment);
let index = indices.get(id);
if (index !== undefined) return `#<${index}>`;
index = fragments.push(fragment) - 1;
indices.set(id, index);
return `#<${index}>`;
}
return node;
}
next(object);
return fragments;
}
const pattern = /^#\<\d+\>$/;
function next(node: unknown, context: unknown[]): unknown {
switch (typeof node) {
case "string":
if (pattern.test(node)) {
const index = Number.parseInt(node.slice(2, -1));
return next(context[index], context);
}
return node;
case "object":
if (node === null) {
return null;
}
if (Array.isArray(node)) {
return node.map((el) => next(el, context));
}
return Object.keys(node)
.sort()
.reduce<Record<string, unknown>>((obj, key) => {
const value = (node as Record<string, unknown>)[key];
obj[key] = next(value, context);
return obj;
}, {});
default:
return node;
}
}
export function unpackJSON(data: unknown[]) {
return next(data[data.length - 1], data);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment