@denostack/superserial@0.3.5
latest
This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers




JSR Score
58%
Published
a year ago (0.3.5)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244// deno-lint-ignore-file no-explicit-any import { toSerialize } from "./symbol.ts"; import type { ConstructType } from "./types.ts"; export interface SerializeOptions { classNames?: Map<ConstructType<unknown>, string>; prettify?: boolean; } export function serialize(value: any, options: SerializeOptions = {}): string { let output = ""; let inc = 0; const prettify = options.prettify ?? false; let depth = 0; const objectMap = new Map<number, any>(); const objectIndexMap = new Map<any, number>(); function _stringifyString(value: string): boolean { output += JSON.stringify(value); // fastest way return true; } function _stringifyScalar(value: any): boolean { if (value === null) { output += "null"; return true; } const typeofValue = typeof value; if (typeofValue === "undefined") { output += "undefined"; return true; } if (typeofValue === "number") { if (Number.isNaN(value)) { output += "NaN"; return true; } if (!Number.isFinite(value)) { output += value > 0 ? "Infinity" : "-Infinity"; return true; } output += `${value}`; return true; } if (typeofValue === "bigint") { output += `${value}n`; return true; } if (typeofValue === "boolean") { output += value ? "true" : "false"; return true; } if (typeofValue === "string") { return _stringifyString(value); } return false; } function _stringifyRoot(value: any): boolean { if (_stringifyScalar(value)) { return true; } return _stringifyRef(value); } function _stringifyAny(value: any): boolean { if (_stringifyScalar(value)) { return true; } let oIdx = objectIndexMap.get(value); if (typeof oIdx !== "number") { oIdx = inc++; objectIndexMap.set(value, oIdx); objectMap.set(oIdx, value); } output += `$${oIdx}`; return true; } function _stringifyRef(value: any): boolean { // simple :-) if (typeof value === "symbol") { output += "Symbol("; if (value.description) { _stringifyString(value.description); } output += ")"; return true; } if (value instanceof RegExp) { output += value.toString(); return true; } if (value instanceof Date) { output += "Date("; _stringifyAny(value.getTime()); output += ")"; return true; } // complex :D if (prettify) { output += " ".repeat(depth); } if (Array.isArray(value)) { _stringifyListStart("["); _stringifyList(value); _stringifyListEnd("]"); return true; } if (value instanceof Map) { _stringifyListStart("Map("); _stringifyMap([...value.entries()]); _stringifyListEnd(")"); return true; } if (value instanceof Set) { _stringifyListStart("Set("); _stringifyList([...value]); _stringifyListEnd(")"); return true; } const name = value.constructor && value.constructor !== Object && value.constructor !== Function ? (options.classNames?.get(value.constructor) ?? value.constructor.name) : ""; _stringifyListStart(prettify && name ? `${name} {` : `${name}{`); _stringifyKv( Object.entries( typeof value[toSerialize] === "function" ? value[toSerialize]() : value, ), ); _stringifyListEnd("}"); return true; } const _stringifyListStart = prettify ? (name: string) => { output += name; output += "\n"; depth++; } : (name: string) => { output += name; depth++; }; const _stringifyListEnd = prettify ? (name: string) => { depth--; output += "\n"; output += " ".repeat(depth); output += name; } : (name: string) => { depth--; output += name; }; const _stringifyList = prettify ? (value: any[]) => { for (let i = 0; i < value.length; i++) { if (i > 0) { output += ",\n"; } output += " ".repeat(depth); _stringifyAny(value[i]); } } : (value: any[]) => { for (let i = 0; i < value.length; i++) { if (i > 0) { output += ","; } _stringifyAny(value[i]); } }; const _stringifyMap = prettify ? (value: [string, any][]) => { for (let i = 0; i < value.length; i++) { if (i > 0) { output += ",\n"; } output += " ".repeat(depth); _stringifyAny(value[i][0]); output += " => "; _stringifyAny(value[i][1]); } } : (value: [string, any][]) => { for (let i = 0; i < value.length; i++) { if (i > 0) { output += ","; } _stringifyAny(value[i][0]); output += "=>"; _stringifyAny(value[i][1]); } }; const _stringifyKv = prettify ? (value: [string, any][]) => { for (let i = 0; i < value.length; i++) { if (i > 0) { output += ",\n"; } output += " ".repeat(depth); _stringifyString(value[i][0]); output += ": "; _stringifyAny(value[i][1]); } } : (value: [string, any][]) => { for (let i = 0; i < value.length; i++) { if (i > 0) { output += ","; } _stringifyString(value[i][0]); output += ":"; _stringifyAny(value[i][1]); } }; inc++; objectIndexMap.set(value, 0); objectMap.set(0, value); _stringifyRoot(value); for (let i = 1; i < inc; i++) { output += ";"; if (prettify) { output += "\n"; } _stringifyRoot(objectMap.get(i)); } return output; }