UNPKG

@rustable/utils

Version:

Essential utilities for object cloning, string manipulation, and value comparison in TypeScript, inspired by Rust's standard library.

131 lines (128 loc) 3.23 kB
'use strict'; "use strict"; function stringifyObject(obj) { const objectRefs = /* @__PURE__ */ new Map(); let nextRefId = 0; function scanObject(value) { if (typeof value !== "object" || value === null) { return; } const existing = objectRefs.get(value); if (existing) { existing.count++; return; } objectRefs.set(value, { count: 1 }); if (value[Symbol.iterator]) { for (const item of value) { scanObject(item); } } else { Object.keys(value).forEach((key) => scanObject(value[key])); } } scanObject(obj); for (const [_, info] of objectRefs) { if (info.count > 1) { info.id = nextRefId++; } } const processedRefs = /* @__PURE__ */ new Set(); function stringifyValue(value) { if (value === null || typeof value === "undefined") { return ""; } if (Object.is(value, NaN)) { return "NaN"; } if (typeof value === "string") { return `"${value}"`; } if (typeof value !== "object") { return value.toString(); } if (value instanceof Date) { return `Date("${value.getTime()}")`; } const ref = objectRefs.get(value); if (ref?.id !== void 0) { if (processedRefs.has(value)) { return "#" + ref.id; } processedRefs.add(value); } let result = ""; if (value[Symbol.iterator]) { const elements = Array.from(value).map(stringifyValue).join(","); const typeName = value.constructor.name; result = typeName !== "Array" ? `${typeName}{${elements}}` : `[${elements}]`; } else { const pairs = Object.keys(value).sort().map((key) => `${key}:${stringifyValue(value[key])}`).join(","); const constructorName = value.constructor && value.constructor.name !== "Object" ? value.constructor.name : null; if (constructorName) { result = `${constructorName}{${pairs}}`; } else { result = "{" + pairs + "}"; } } if (ref?.id !== void 0) { return "#" + ref.id + result; } return result; } return stringifyValue(obj); } function stringify(obj) { if (obj === null || typeof obj === "undefined") { return ""; } if (Object.is(obj, NaN)) { return "NaN"; } if (typeof obj === "string") { return obj; } if (typeof obj === "number") { return obj + ""; } if (typeof obj === "boolean") { return obj ? "true" : "false"; } if (typeof obj === "object") { return stringifyObject(obj); } return obj.toString(); } function stringHash(str) { if (str.length === 0) return 0; let hash2 = 0; let i; let chr; for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); hash2 = (hash2 << 5) - hash2 + chr; hash2 |= 0; } return hash2; } function hash(obj) { if (obj === null || typeof obj === "undefined") { return -1; } if (typeof obj === "boolean") { return obj ? 1 : 0; } if (typeof obj === "number") { return obj; } if (typeof obj === "string") { return stringHash(obj); } if (typeof obj === "object") { return stringHash(stringifyObject(obj)); } return stringHash(obj.toString()); } exports.hash = hash; exports.stringify = stringify;