( a: unknown, b: unknown, seen = new WeakMap<WeakKey, unknown>(), )
| 12 | } |
| 13 | |
| 14 | export function deepEqualIgnoringFns( |
| 15 | a: unknown, |
| 16 | b: unknown, |
| 17 | seen = new WeakMap<WeakKey, unknown>(), |
| 18 | ): boolean { |
| 19 | if (Object.is(a, b)) return true; |
| 20 | |
| 21 | // Functions: ignore identity/body differences entirely |
| 22 | if (typeof a === 'function' && typeof b === 'function') { |
| 23 | return typeof a === typeof b; |
| 24 | } |
| 25 | |
| 26 | if (!isPlainObjectOrArray(a) || !isPlainObjectOrArray(b)) { |
| 27 | return false; |
| 28 | } |
| 29 | |
| 30 | // Cycles |
| 31 | const mapped = seen.get(a); |
| 32 | if (mapped && mapped === b) return true; |
| 33 | seen.set(a, b); |
| 34 | |
| 35 | // Arrays |
| 36 | if (Array.isArray(a) || Array.isArray(b)) { |
| 37 | if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) |
| 38 | return false; |
| 39 | for (let i = 0; i < a.length; i++) { |
| 40 | if (!deepEqualIgnoringFns(a[i], b[i], seen)) return false; |
| 41 | } |
| 42 | return true; |
| 43 | } |
| 44 | |
| 45 | // Plain objects (Maps/Sets/Dates: treat as unequal unless same ref) |
| 46 | const aKeys = Object.keys(a); |
| 47 | const bKeys = Object.keys(b); |
| 48 | if (aKeys.length !== bKeys.length) return false; |
| 49 | |
| 50 | for (let i = 0; i < aKeys.length; i++) { |
| 51 | const k = aKeys[i]; |
| 52 | if (!Object.prototype.hasOwnProperty.call(b, k)) return false; |
| 53 | |
| 54 | const av = (a as Record<string, unknown>)[k]; |
| 55 | const bv = (b as Record<string, unknown>)[k]; |
| 56 | |
| 57 | if (!deepEqualIgnoringFns(av, bv, seen)) return false; |
| 58 | } |
| 59 | |
| 60 | return true; |
| 61 | } |
| 62 | |
| 63 | export function withLatestFunctionWrappers<T extends Record<string, any>>(ref: { |
| 64 | current: T; |
no test coverage detected