Skip to content

Commit

Permalink
add equal utility
Browse files Browse the repository at this point in the history
  • Loading branch information
marihachi committed Nov 7, 2023
1 parent 5b33c6f commit e91af8d
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
67 changes: 67 additions & 0 deletions src/equal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
export function equal(a: any, b: any): boolean {
return equalWithRefs(a, b, [], []);
}

function equalWithRefs(a: any, b: any, prevRefsA: any[], prevRefsB: any[]): boolean {
if (Object.is(a, b)) return true;

// object
if (a !== null && b !== null && typeof a === 'object' && typeof b === 'object') {
const refsA = [...prevRefsA, a];
const refsB = [...prevRefsB, b];

// 循環チェック
const indexA = refsA.findIndex(x => x === a);
const indexB = refsB.findIndex(x => x === b);
if (indexA != -1 && indexB != -1 && indexA === indexB) {
return true;
}

// array
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (!equalWithRefs(a[i], b[i], refsA, refsB)) return false;
}
return true;
}

// map
if (a instanceof Map && b instanceof Map) {
if (a.size !== b.size) return false;
const aEntries = a.entries();
const bEntries = b.entries();
while (true) {
const entryA = aEntries.next();
const entryB = bEntries.next();
if (entryA.done === false) break;
if (!equalWithRefs(entryA.value[0], entryB.value[0], refsA, refsB)) return false;
if (!equalWithRefs(entryA.value[1], entryB.value[1], refsA, refsB)) return false;
}
return true;
}

// set
if (a instanceof Set && b instanceof Set) {
if (a.size !== b.size) return false;
const aValues = a.values();
const bValues = b.values();
while (true) {
const valueA = aValues.next();
const valueB = bValues.next();
if (valueA.done === false) break;
if (!equalWithRefs(valueA.value, valueB.value, refsA, refsB)) return false;
}
return true;
}

// object keys
const keys = Object.keys(a);
for (const key of keys) {
if (!equalWithRefs(a[key], b[key], refsA, refsB)) return false;
}
return true;
}

return false;
}
21 changes: 21 additions & 0 deletions test/equal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as assert from 'assert';
import { equal } from '../src/equal';

test('all', () => {
assert.strictEqual(equal(null, null), true);
assert.strictEqual(equal(undefined, undefined), true);
assert.strictEqual(equal(NaN, NaN), true);

assert.strictEqual(equal(null, undefined), false);
assert.strictEqual(equal(null, NaN), false);
assert.strictEqual(equal(undefined, NaN), false);

assert.strictEqual(equal({ a: 1 }, { a: 1 }), true);
assert.strictEqual(equal({ a: 1 }, null), false);

let x: any = { n: null };
x.n = x;
let y: any = { n: null };
y.n = y;
assert.strictEqual(equal(x, y), true);
});

0 comments on commit e91af8d

Please sign in to comment.