differrer
Version:
> Utility to perform deep diff on any data types with smart order detection in arrays and different views implemented for convenience
292 lines (291 loc) • 10.9 kB
JavaScript
const se = (e) => " ".repeat(e * 2), M = (e) => {
const t = w(e);
return t === "string" ? `'${e.replace(/'/g, "\\'")}'` : ["array", "object"].includes(t) ? JSON.stringify(e) : `${e}`;
}, oe = (e) => typeof e == "number" || !e && e !== "" || typeof e != "string" ? "" : /[- ]/.test(e) || e === "" ? `'${e}': ` : `${e}: `, $e = (e) => {
const t = (r, n, s = 0, c) => {
let o = "";
const u = se(s), i = r || r === 0 ? "," : "", j = w(c);
return n.children && (["object", "array"].includes(n.sourceType) || n.added) ? (Array.isArray(n.children) ? o += `[
${n.children.map((y, h) => t(h, y, s + 1, n)).join(`
`)}
${u}]${i}` : o += `{
${Object.entries(n.children).map(([y, h]) => t(y, h, s + 1, n)).join(`
`)}
${u}}${i}`, n.added ? o += " // +" : n.removed ? o += " // -" : n.changed && (o += n.targetType !== n.sourceType ? ` // ~ ${M(n.targetValue)}` : " // ~")) : (n.added ? o += j === "object" ? `${M(n.targetValue)}, // +` : `// + ${M(n.targetValue)}` : o += `${M(n.sourceValue)}${i}`, n.removed && (o += " // -"), !n.removed && !n.added && n.changed && (o += ` // ~ ${M(n.targetValue)}`)), `${u}${oe(r)}${o}`;
};
return t(null, e, 0);
};
const ce = (e) => " ".repeat(e * 2), le = (e) => {
const t = w(e);
return t === "string" ? `'${e.replace(/'/g, "\\'")}'` : ["array", "object"].includes(t) ? JSON.stringify(e) : `${e}`;
}, ue = (e) => typeof e == "number" || !e && e !== "" || typeof e != "string" ? "" : /[- ]/.test(e) || e === "" ? `'${e}': ` : `${e}: `, ye = (e) => {
const t = (r, n, s, c = 0, o, u) => {
const i = r === "source" ? "added" : "removed", j = r === "source" ? "sourceValue" : "targetValue", y = r === "source" ? "sourceType" : "targetType", h = ce(c), E = n || n === 0 ? "," : "";
let p = "";
if (s[i] || u || s.children && !["array", "object"].includes(s[y])) {
const g = s.children && !["array", "object", "undefined"].includes(s[y]) ? `${h}${s[j]}${E}` : "";
return s.children && (Array.isArray(s.children) ? p += `${g}
${s.children.map((m, V) => t(r, V, m, c + 1, s, u)).join(`
`)}
` : p += `${g}
${Object.entries(s.children).map(([m, V]) => t(r, m, V, c + 1, s, u)).join(`
`)}
`), p;
}
return s.children ? Array.isArray(s.children) ? p += `[
${s.children.map((g, m) => t(r, m, g, c + 1)).join(`
`)}
${h}]${E}` : p += `{
${Object.entries(s.children).map(([g, m]) => t(r, g, m, c + 1)).join(`
`)}
${h}}${E}` : p += `${le(s[j])}${E}`, `${h}${ue(n)}${p}`;
};
return {
source: t("source", null, e, 0),
target: t("target", null, e, 0)
};
}, k = Symbol("CustomString"), I = (e, t, r) => {
const n = t === void 0 ? e : t;
return {
length: e.length,
rawValue: e,
pretty: n,
toString: () => n,
search: (s) => e.search(s),
padEnd: (s, c = " ") => {
const o = e.padEnd(s, c), u = o.length - e.length, i = n.padEnd(n.length + u, c);
return I(o, i, r);
},
trimStart: () => {
const s = e.trimStart(), c = n.trimStart();
return I(s, c, r);
},
representedValue: r,
type: k
};
}, F = (e, t = "") => {
const r = e.map((s) => typeof s == "string" ? s : s.rawValue).join(t), n = e.map((s) => typeof s == "string" ? s : s.pretty).join(t);
return I(r, n);
}, L = (e) => (e == null ? void 0 : e.type) === k, ee = 2, te = 0, U = 0, ae = typeof process < "u" && process.versions != null && process.versions.node != null, J = (e) => {
if (ae && typeof require < "u")
return I(
require("util").inspect(e, { colors: !1 }),
require("util").inspect(e, { colors: !0 }),
e
);
const t = typeof e == "string" ? `'${e.replace(/'/g, "\\'")}'` : `${e}`;
return I(
t,
t,
e
);
}, z = (e, t = "") => {
if (typeof e == "number") {
const r = J(e);
return F(["[", r, "]"]);
}
return !e && e !== "" || typeof e != "string" ? I("") : /[- ]/.test(e) || e === "" ? I(`${t}'${e}'`) : I(`${t}${e}`);
}, ie = (e) => {
let t = !1;
return F(e.map((r) => typeof r == "number" ? (t = !1, z(r)) : t ? z(r, ".") : (t = !0, z(r))));
}, Q = (e) => " ".repeat((e && e - 1) * ee), x = (e) => e ? e[e.length - 1] : null, H = (e, t, r = 0) => e.reduce((n, s) => {
let c;
if (L(s))
c = t === null ? s.length : 0;
else {
const o = t !== null ? s[t] : null;
c = t !== null && L(o) ? o.length : 0;
}
return c > n ? c : n;
}, 0) + r, de = (e, t, r = 0) => {
const n = /\S|$/;
return e.reduce((s, c) => {
let o;
return L(c) ? o = t === null ? c.search(n) : 0 : o = t === null ? 0 : J(c[t]).search(n), o > s ? o : s;
}, 0) + r;
}, X = (e, t = 0) => {
if (e.sameValue)
return [];
if (e.children) {
const r = (Array.isArray(e.children) ? e.children.map((n, s) => [s, n]) : Object.entries(e.children)).flatMap(([, n]) => X(n, t + 1));
if (r.length > 0) {
const n = e.retrievedId || x(e.sourcePath) || x(e.targetPath), s = H(r, 0, U + te * ee), c = H(r, 1, U), o = H(r, 2, U);
return [
I(n ? `${Q(t)}${n}` : ""),
...r.map((u) => L(u) ? u : [u[0], u[1], u[2], s, c, o])
];
}
return [];
}
return [[
F([Q(t), ie(e.sourcePath || e.targetPath || [])]),
J(e.sourceValue),
J(e.targetValue)
]];
}, be = (e) => {
const t = X(e), r = de(t, null, te);
return t.map((n) => {
if (L(n))
return n.pretty;
{
const [s, c, o, u, i, j] = n, y = F([Q(r + 1), s.trimStart()]).padEnd(u || 0), h = c.padEnd(i || 0), E = o.padEnd(j || 0);
return `${y}: ${h} -> ${E}`;
}
}).join(`
`);
}, Ie = (e) => X(e).map((r) => {
if (L(r))
return r.rawValue;
{
const [n, s, c] = r;
return [n.rawValue, s.rawValue, c.rawValue];
}
}).filter((r) => r), pe = (e) => e.sort(
(t, r) => `${t}`.localeCompare(`${r}`, void 0, { numeric: !0 })
), ge = (e) => ({
number: e.filter((t) => typeof t[1] == "number"),
string: e.filter((t) => typeof t[1] == "string"),
booleanTrue: e.filter((t) => t[1] === !0),
booleanFalse: e.filter((t) => t[1] === !1),
null: e.filter((t) => t[1] === null),
undefined: e.filter((t) => t[1] === void 0),
object: e.filter((t) => ne(t[1])),
array: e.filter((t) => Array.isArray(t[1]))
}), v = (e) => {
const t = ge(e);
return [
...t.number.sort((r, n) => r[1] - n[1]),
...t.string.sort((r, n) => r[1].localeCompare(n[1], void 0, { numeric: !0 })),
...t.booleanTrue,
...t.booleanFalse,
...t.null,
...t.undefined,
...t.object,
...t.array
];
}, P = (e) => e.filter((t, r) => r === e.indexOf(t)), me = (e, t) => typeof e == "number" && typeof t == "number" ? e === t || e !== e && t !== t : e === t, ne = (e) => Object.prototype.toString.call(e) === "[object Object]" && (e.constructor === void 0 || Object.prototype.toString.call(e.constructor.prototype) === "[object Object]" && e.constructor.prototype.hasOwnProperty("isPrototypeOf")), w = (e) => {
switch (!0) {
case ne(e):
return "object";
case Array.isArray(e):
return "array";
case typeof e == "string":
return "string";
case typeof e == "number":
return "number";
case typeof e == "boolean":
return "boolean";
case e === null:
return "null";
case e === void 0:
return "undefined";
default:
return "unknown";
}
}, he = (e) => (t, r, n) => {
const s = e(t, r, n);
return typeof s == "string" || typeof s == "number" ? s : null;
}, je = ({
sortArrayItems: e = !1,
getArrayElementId: t,
getValue: r
}) => (n, s) => {
const c = he(t), o = (u = [], i = [], j = null, y = null, h, E) => {
const p = r ? r(h, u) : h, g = r ? r(E, i) : E, m = w(p), V = w(g), $ = {
sourcePath: u,
targetPath: i,
sourceValue: p,
targetValue: g,
sameValue: !0,
sameValueZero: !0,
retrievedId: null,
sourceOrder: j,
targetOrder: y,
sameOrder: j === null && y === null ? null : j === y,
sourceType: m,
targetType: V,
sameType: m === V,
added: !1,
removed: !1,
changed: !1,
children: null
};
if (m === "object" || V === "object") {
const Z = m === "object", q = V === "object", S = Z ? Object.keys(p) : null, f = q ? Object.keys(g) : null, D = P([...S || [], ...f || []]).reduce((G, N) => {
const T = Z ? p[N] : void 0, C = q ? g[N] : void 0, _ = S ? S.indexOf(N) : -1, K = f ? f.indexOf(N) : -1, R = o(
u ? [...u, N] : null,
i ? [...i, N] : null,
_ === -1 ? null : _,
K === -1 ? null : K,
T,
C
);
return $.sameValue = $.sameValue && R.sameValue, R.added = _ === -1, R.removed = K === -1, G[N] = R, G;
}, {});
$.children = D;
} else if (m === "array" || V === "array") {
const Z = m === "array", q = V === "array", S = [], f = {};
(Z ? p : []).forEach((l, d) => {
const a = ["object", "array"].includes(w(l)) ? c(l, u ? [...u, d] : null) : null;
a || a === 0 || a === "" ? f[a] = [d, l] : S.push([d, l]);
});
const W = [], D = {};
(q ? g : []).forEach((l, d) => {
const a = ["object", "array"].includes(w(l)) ? c(l, i ? [...i, d] : null) : null;
a || a === 0 || a === "" ? D[a] = [d, l] : W.push([d, l]);
});
const N = pe(P([...Object.keys(f), ...Object.keys(D)])).map((l) => {
const [d, a] = f[l] || [null, void 0], [O, A] = D[l] || [null, void 0], b = o(
d === null || !u ? null : [...u, d],
O === null || !i ? null : [...i, O],
d,
O,
a,
A
);
return b.retrievedId = l, $.sameValue = $.sameValue && b.sameValue, b.added = Boolean(!f[l] && D[l]), b.removed = Boolean(f[l] && !D[l]), b;
}), T = e ? v(S) : S, C = e ? v(W) : W, _ = T.reduce((l, [d], a) => ({
...l,
[d]: a
}), {}), K = C.reduce((l, [d], a) => ({
...l,
[d]: a
}), {}), R = Math.max(T.length, C.length), Y = [], re = (l, d, a, O) => d ? [l, l] : a[l] ? [l, K[a[l][0]]] : [_[O[l][0]], l];
Array(R).fill(null).forEach((l, d) => {
const [a, O] = re(d, e, T, C), A = (a || a === 0) && T[a] || [null, void 0], b = (O || O === 0) && C[O] || [null, void 0], B = o(
A[0] === null || !u ? null : [...u, A[0]],
b[0] === null || !i ? null : [...i, b[0]],
A[0],
b[0],
A[1],
b[1]
);
$.sameValue = $.sameValue && B.sameValue, B.added = A[0] === null && b[0] !== null, B.removed = A[0] !== null && b[0] === null, Y.push(B);
}), $.children = [
...N,
...Y
];
} else
$.sameValue = p === g;
return $.sameValueZero = me(p, g), $.changed = !$.sameValue, $;
};
return o(
[],
[],
null,
null,
n,
s
);
};
export {
je as default,
je as diff,
be as diffChangesViewConsole,
Ie as diffChangesViewRaw,
$e as diffJsView,
ye as diffSortedView,
he as getArrayElementIdWrapper,
w as getType,
ne as isPlainObject
};