aboutsummaryrefslogtreecommitdiff
path: root/ext/mixed/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-11-09 21:47:25 -0500
committerGitHub <noreply@github.com>2020-11-09 21:47:25 -0500
commit219dfb4917f5b19da19b85ff223de663db561fe7 (patch)
tree5f1763073b4cb2e6b1347b27a6e535c51f524ae6 /ext/mixed/js
parenteb8069a4944c5060e9c3ff15814291c918c04068 (diff)
Add a core deepEqual function (#1018)
* Add a core deepEqual function * Add tests
Diffstat (limited to 'ext/mixed/js')
-rw-r--r--ext/mixed/js/core.js66
1 files changed, 66 insertions, 0 deletions
diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js
index 81330893..72ab7474 100644
--- a/ext/mixed/js/core.js
+++ b/ext/mixed/js/core.js
@@ -176,6 +176,72 @@ const clone = (() => {
return clone;
})();
+const deepEqual = (() => {
+ // eslint-disable-next-line no-shadow
+ function deepEqual(value1, value2) {
+ if (value1 === value2) { return true; }
+
+ const type = typeof value1;
+ if (typeof value2 !== type) { return false; }
+
+ switch (type) {
+ case 'object':
+ case 'function':
+ return deepEqualInternal(value1, value2, new Set());
+ default:
+ return false;
+ }
+ }
+
+ function deepEqualInternal(value1, value2, visited1) {
+ if (value1 === value2) { return true; }
+
+ const type = typeof value1;
+ if (typeof value2 !== type) { return false; }
+
+ switch (type) {
+ case 'object':
+ case 'function':
+ {
+ if (value1 === null || value2 === null) { return false; }
+ const array = Array.isArray(value1);
+ if (array !== Array.isArray(value2)) { return false; }
+ if (visited1.has(value1)) { return false; }
+ visited1.add(value1);
+ return array ? areArraysEqual(value1, value2, visited1) : areObjectsEqual(value1, value2, visited1);
+ }
+ default:
+ return false;
+ }
+ }
+
+ function areObjectsEqual(value1, value2, visited1) {
+ const keys1 = Object.keys(value1);
+ const keys2 = Object.keys(value2);
+ if (keys1.length !== keys2.length) { return false; }
+
+ const keys1Set = new Set(keys1);
+ for (const key of keys2) {
+ if (!keys1Set.has(key) || !deepEqualInternal(value1[key], value2[key], visited1)) { return false; }
+ }
+
+ return true;
+ }
+
+ function areArraysEqual(value1, value2, visited1) {
+ const length = value1.length;
+ if (length !== value2.length) { return false; }
+
+ for (let i = 0; i < length; ++i) {
+ if (!deepEqualInternal(value1[i], value2[i], visited1)) { return false; }
+ }
+
+ return true;
+ }
+
+ return deepEqual;
+})();
+
function generateId(length) {
const array = new Uint8Array(length);
crypto.getRandomValues(array);