UNPKG

value-semantics

Version:

Mimic value semantics for JavaScript objects with deep cloning and equality functions

467 lines (466 loc) 11.3 kB
Symbol.metadata ?? (Symbol.metadata = Symbol("Symbol.metadata")); const d = Symbol.for("meta-not-found"); function p(e, t) { if ("constructor" in e && Symbol.metadata in e.constructor) { const n = e.constructor[Symbol.metadata]; if (typeof n == "object" && n && t in n) return n[t]; } return d; } function O(e, t, n) { var r; e[r = Symbol.metadata] ?? (e[r] = {}), e[Symbol.metadata][t] = n; } const U = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array ], S = Symbol.for("clone-method"), P = Symbol.for("equals-method"), m = Symbol.for("clone-include-props"), g = Symbol.for("clone-exclude-props"), M = Symbol.for("equals-include-props"), j = Symbol.for("equals-exclude-props"), h = Symbol.for("constructor-props"); function q(e) { return /* @__PURE__ */ new Set([...Object.getOwnPropertyNames(e), ...Object.getOwnPropertySymbols(e)]); } function F(e, t, n, r = !1) { if (t === "include") { let a = q(e); const u = p(e, n === "clone" ? g : j); if (u !== d && (a = a.difference(u)), n === "clone") { const c = p(e, h); if (c !== d && r) for (const _ of c) a.delete(_); const k = p(e, m); k !== d && (a = a.union(k)); } return a; } const f = p(e, n === "clone" ? m : M); return f !== d ? f : /* @__PURE__ */ new Set(); } const v = { ErrorOnClone: "Instances of class % cannot be cloned", IncludeAndExclude: "A field cannot be decorated with both `@include` and `@exclude`" }; class K extends Error { constructor(t, n = "") { const r = v[t].replace("%", n); super(r), this.type = t; } } const B = Symbol.for("error-on-clone"); function G(e) { const t = e.constructor; let n = p(e, h); n === d && (n = []); const r = n.map((o) => e[o]); return new t(...r); } function Q(e) { return Object.create(Object.getPrototypeOf(e)); } function H(e, t, n, r) { for (const o of e) { const f = Object.getOwnPropertyDescriptor(n, o); f.get || f.set ? Object.defineProperty(t, o, f) : Object.defineProperty( t, o, { value: w(n[o], r), writable: f.writable, configurable: f.configurable, enumerable: f.enumerable } ); } } const s = (e, t) => { O(e, S, t); }; s(Array, function(e) { const t = []; return e.set(this, t), this.forEach((n, r) => t[r] = w(n, e)), t; }); s(Set, function(e) { const t = /* @__PURE__ */ new Set(); return e.set(this, t), this.forEach((n) => t.add(w(n, e))), t; }); s(Map, function(e) { const t = /* @__PURE__ */ new Map(); return e.set(this, t), this.forEach((n, r) => t.set(w(r, e), w(n, e))), t; }); s(RegExp, function(e) { const t = new RegExp(this); return e.set(this, t), t; }); s(Date, function(e) { const t = new Date(this); return e.set(this, t), t; }); s(ArrayBuffer, function(e) { const t = this.slice(0); return e.set(this, t), t; }); s(SharedArrayBuffer, function(e) { const t = this.slice(0); return e.set(this, t), t; }); s(DataView, function(e) { const t = new DataView(A(this.buffer), this.byteOffset, this.byteLength); return e.set(this, t), t; }); for (const e of U) s( e, function(t) { const n = new e(A(this.buffer), this.byteOffset, this.length); return t.set(this, n), n; } ); function C(e) { s(e, function(t) { return t.set(this, this), this; }); } C(Boolean); C(Number); C(String); O(BigInt, S, function(e) { return e.set(this, this), this; }); O(Symbol, S, function(e) { return e.set(this, this), this; }); function R(e) { O(e, B, e.name); } R(WeakSet); R(WeakMap); R(WeakRef); function A(e) { return w(e, /* @__PURE__ */ new Map()); } function w(e, t) { if (typeof e == "object") { if (e === null) return null; const n = p(e, B); if (typeof n == "string") throw new K("ErrorOnClone", n); if (t.has(e)) return t.get(e); const r = p(e, S); if (r !== d) return r.call(e, t); const o = Object.getPrototypeOf(e), f = Object.create(o); return t.set(e, f), H(q(e), f, e, t), f; } return e; } const I = ["deep", "returnOriginal", "errorOnClone"]; function J(e, t) { const n = typeof e == "string" ? e : "deep"; t || (typeof e == "object" ? t = e : t = {}); const r = { runConstructor: !1, propDefault: "include", ...t }, o = function(a) { const i = r.runConstructor ? G(this) : Q(this); a.set(this, i); const u = F(this, r.propDefault, "clone", r.runConstructor); return H(u, i, this, a), i; }, f = function(a) { return a.set(this, this), this; }; return function(a, i) { if (n === "returnOriginal") i.metadata[S] = f; else if (n === "errorOnClone") i.metadata[B] = i.name ?? "(Anonymous class)"; else { const u = i.metadata[m] ?? /* @__PURE__ */ new Set(), c = i.metadata[g] ?? /* @__PURE__ */ new Set(); if (!u.isDisjointFrom(c)) throw new K("IncludeAndExclude"); i.metadata[S] = o; } }; } ((e) => { function t(o, f) { var a; (a = f.metadata)[m] ?? (a[m] = /* @__PURE__ */ new Set()), f.metadata[m].add(f.name); } e.include = t; function n(o, f) { var a; (a = f.metadata)[g] ?? (a[g] = /* @__PURE__ */ new Set()), f.metadata[g].add(f.name); } e.exclude = n; function r(o, f) { var a; (a = f.metadata)[h] ?? (a[h] = []), f.metadata[h].push(f.name); } e.constructorParam = r; })(A || (A = {})); const V = Symbol.for("ref-equals"), Z = [Boolean, Number, BigInt, String, Symbol]; function $(e, t) { return e.map((n, r) => [n, t[r]]); } function L(e, t, n) { const r = p(e, P); if (r !== d) throw r.call(e, t, n); } function N(e, t) { if (p(e, V) !== d) throw e === t; } function X(e, t, n) { const r = n.get(e); if (r !== void 0) { const o = r.get(t); if (o !== void 0) return o; } return null; } function E(e, t, n, r) { let o = n.get(e); o === void 0 && (o = /* @__PURE__ */ new Map(), n.set(e, o)), o.set(t, r); let f = n.get(t); f === void 0 && (f = /* @__PURE__ */ new Map(), n.set(t, f)), f.set(e, r); } const l = (e, t) => { O(e, P, t); }, Y = (e) => { O(e, V, !0); }; function y(e, t) { return Object.getPrototypeOf(e) === t.prototype; } function W(e, t) { for (const n of Z) if (e instanceof n) return e.valueOf() === t; return !1; } function ee(e, t, n) { e: for (const r of e) { for (const o of t) if (b(r, o, n)) continue e; return !1; } return !0; } function te(e, t, n) { e: for (const r of e.keys()) { for (const o of t.keys()) if (b(r, o, n)) { if (!b(e.get(r), t.get(o), n)) return !1; continue e; } return !1; } return !0; } l( Array, function(e, t) { return !y(e, Array) || this.length !== e.length ? !1 : $(this, e).every(([n, r]) => b(n, r, t)); } ); l( Set, function(e, t) { return !y(e, Set) || this.size !== e.size ? !1 : ee(this, e, t); } ); l( Map, function(e, t) { return !y(e, Map) || this.size !== e.size ? !1 : te(this, e, t); } ); l( RegExp, function(e, t) { return y(e, RegExp) ? this.toString() === e.toString() : !1; } ); l( Date, function(e, t) { return y(e, Date) ? +this == +e : !1; } ); l( ArrayBuffer, function(e, t) { if (!y(e, ArrayBuffer) || this.byteLength !== e.byteLength) return !1; const n = new Uint8Array(this), r = new Uint8Array(e); for (let o = 0; o < this.byteLength; o++) if (n[o] !== r[o]) return !1; return !0; } ); l( SharedArrayBuffer, function(e, t) { if (!y(e, SharedArrayBuffer) || this.byteLength !== e.byteLength) return !1; const n = new Uint8Array(this), r = new Uint8Array(e); for (let o = 0; o < this.byteLength; o++) if (n[o] !== r[o]) return !1; return !0; } ); l( DataView, function(e, t) { if (!y(e, DataView) || this.byteLength !== e.byteLength) return !1; for (let n = 0; n < this.byteLength; n++) if (this.getInt8(n) !== e.getInt8(n)) return !1; return !0; } ); for (const e of U) l( e, function(t, n) { if (!y(t, e) || this.byteLength !== t.byteLength) return !1; for (let r = 0; r < this.byteLength; r++) if (this[r] !== t[r]) return !1; return !0; } ); l( WeakRef, function(e, t) { return y(e, WeakRef) ? b(this.deref(), e.deref(), t) : !1; } ); Y(WeakSet); Y(WeakMap); function D(e, t) { return b(e, t, /* @__PURE__ */ new Map()); } function b(e, t, n) { if (e === t) return !0; if (e === null || t === null) return !1; if (typeof e != "object") return typeof e == "number" && isNaN(e) ? typeof t == "number" && isNaN(t) : typeof t == "object" ? W(t, e) : !1; if (typeof t != "object") return W(e, t); const r = X(e, t, n); if (r !== null) return r; E(e, t, n, !0); try { L(e, t, n), L(t, e, n), N(e, t), N(t, e); } catch (a) { if (typeof a == "boolean") return E(e, t, n, a), a; throw a; } if (Object.getPrototypeOf(e) !== Object.getPrototypeOf(t)) return E(e, t, n, !1), !1; const o = q(e), f = q(t); if (o.size !== f.size || o.intersection(f).size !== o.size) return !1; for (const a of o) if (!b(e[a], t[a], n)) return E(e, t, n, !1), !1; return E(e, t, n, !0), !0; } const x = ["value", "ref"]; function ne(e, t) { return Object.getPrototypeOf(e) === Object.getPrototypeOf(t); } function re(e, t) { const n = typeof e == "string" ? e : "value"; t || (typeof e == "object" ? t = e : t = {}); const r = { propDefault: "include", ...t }; return function(o, f) { if (n === "ref") { f.metadata[V] = !0; return; } f.metadata[P] = function(a, i) { if (!ne(this, a)) return !1; const u = F(this, r.propDefault, "equals"); for (const c of u) if (!b(this[c], a[c], i)) return !1; return !0; }; }; } ((e) => { function t(r, o) { var f; (f = o.metadata)[M] ?? (f[M] = /* @__PURE__ */ new Set()), o.metadata[M].add(o.name); } e.include = t; function n(r, o) { var f; (f = o.metadata)[j] ?? (f[j] = /* @__PURE__ */ new Set()), o.metadata[j].add(o.name); } e.exclude = n; })(D || (D = {})); var T; ((e) => { e.clone = J, e.equals = re; function t(n, r, o) { return function(f, a) { let i = "deep", u = "value", c = {}; typeof n == "string" ? (I.includes(n) && (i = n), x.includes(n) && (u = n)) : n && (c = n), typeof r == "string" ? (I.includes(r) && (i = r), x.includes(r) && (u = r)) : r && (c = r), o && (c = o); const k = { runConstructor: !1, propDefault: "include", ...c }, _ = { propDefault: "include", ...c }; i === "deep" ? e.clone("deep", k)(f, a) : e.clone(i)(f, a), u === "value" ? e.equals("value", _)(f, a) : e.equals(u)(f, a); }; } e.value = t; })(T || (T = {})); var z; ((e) => { function t(r, o) { A.include(r, o), D.include(r, o); } e.include = t; function n(r, o) { A.exclude(r, o), D.exclude(r, o); } e.exclude = n; })(z || (z = {})); export { A as clone, T as customize, D as equals, z as value };