toWire
tcmts.cli.codec.toWire · #gbf47mon · term · runs anywhere
export function toWire(v: unknown, path: string, seen: Set<object>): unknown {
if (v === undefined) return { $u: 1 };
if (v === null || typeof v === "boolean" || typeof v === "string") return v;
if (typeof v === "number") return Number.isFinite(v) && !Object.is(v, -0) ? v : { $n: Object.is(v, -0) ? "-0" : String(v) };
if (typeof v === "bigint") return { $b: v.toString() };
if (typeof v !== "object") throw new TypeError(`can't send ${typeof v} at ${path} over the network (only plain data crosses)`);
if (seen.has(v)) throw new TypeError(`can't send a circular structure at ${path}`);
seen.add(v);
try {
if (v instanceof Date) return { $d: v.toISOString() };
if (Array.isArray(v)) return v.map((x, i) => toWire(x, `${path}[${i}]`, seen));
if (v instanceof Map) return { $m: [...v].map(([k, x], i) => [toWire(k, `${path}<key ${i}>`, seen), toWire(x, `${path}.get(…)`, seen)]) };
if (v instanceof Set) return { $s: [...v].map((x, i) => toWire(x, `${path}<item ${i}>`, seen)) };
const proto = Object.getPrototypeOf(v);
if (proto !== Object.prototype && proto !== null) {
throw new TypeError(`can't send a ${proto?.constructor?.name ?? "class"} instance at ${path} over the network (only plain data crosses)`);
}
const out: Record<string, unknown> = {};
for (const [k, x] of Object.entries(v)) out[k] = toWire(x, `${path}.${k}`, seen);
// an object that looks like one of our tags is wrapped so it decodes as itself
const keys = Object.keys(out);
return keys.length === 1 && keys[0]!.startsWith("$") ? { $o: out } : out;
} finally {
seen.delete(v);
}
}
used by