Skip to content

Commit

Permalink
[v5] Rewrite shallow to support iterables (#2427)
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi authored Mar 23, 2024
1 parent bfbbacc commit 4ac0950
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 17 deletions.
56 changes: 39 additions & 17 deletions src/vanilla/shallow.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
export function shallow<T>(objA: T, objB: T) {
const isIterable = (obj: object): obj is Iterable<unknown> =>
Symbol.iterator in obj

const compareMapLike = (
iterableA: Iterable<[unknown, unknown]>,
iterableB: Iterable<[unknown, unknown]>,
) => {
const mapA = iterableA instanceof Map ? iterableA : new Map(iterableA)
const mapB = iterableB instanceof Map ? iterableB : new Map(iterableB)
if (mapA.size !== mapB.size) return false
for (const [key, value] of mapA) {
if (!Object.is(value, mapB.get(key))) {
return false
}
}
return true
}

export function shallow<T>(objA: T, objB: T): boolean {
if (Object.is(objA, objB)) {
return true
}
Expand All @@ -11,26 +29,30 @@ export function shallow<T>(objA: T, objB: T) {
return false
}

if (objA instanceof Map && objB instanceof Map) {
if (objA.size !== objB.size) return false

for (const [key, value] of objA) {
if (!Object.is(value, objB.get(key))) {
return false
}
if (isIterable(objA) && isIterable(objB)) {
const iteratorA = objA[Symbol.iterator]()
const iteratorB = objB[Symbol.iterator]()
let nextA = iteratorA.next()
let nextB = iteratorB.next()
if (
Array.isArray(nextA.value) &&
Array.isArray(nextB.value) &&
nextA.value.length === 2 &&
nextB.value.length === 2
) {
return compareMapLike(
objA as Iterable<[unknown, unknown]>,
objB as Iterable<[unknown, unknown]>,
)
}
return true
}

if (objA instanceof Set && objB instanceof Set) {
if (objA.size !== objB.size) return false

for (const value of objA) {
if (!objB.has(value)) {
while (!nextA.done && !nextB.done) {
if (!Object.is(nextA.value, nextB.value)) {
return false
}
nextA = iteratorA.next()
nextB = iteratorB.next()
}
return true
return !!nextA.done && !!nextB.done
}

const keysA = Object.keys(objA)
Expand Down
6 changes: 6 additions & 0 deletions tests/vanilla/shallow.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ describe('shallow', () => {

expect(shallow(firstFnCompare, secondFnCompare)).toBe(false)
})

it('compares URLSearchParams', () => {
const a = new URLSearchParams({ hello: 'world' })
const b = new URLSearchParams({ zustand: 'shallow' })
expect(shallow(a, b)).toBe(false)
})
})

describe('unsupported cases', () => {
Expand Down

0 comments on commit 4ac0950

Please sign in to comment.