@@ -234,104 +234,129 @@ export const iterableEquality = (
234234 iterableEqualityWithStack ,
235235 ] ;
236236
237- try {
238- if ( a . size !== undefined ) {
239- if ( a . size !== b . size ) {
240- return false ;
241- } else if ( isA < Set < unknown > > ( 'Set' , a ) || isImmutableUnorderedSet ( a ) ) {
242- let allFound = true ;
243- for ( const aValue of a ) {
244- if ( ! b . has ( aValue ) ) {
245- let has = false ;
246- for ( const bValue of b ) {
247- const isEqual = equals ( aValue , bValue , filteredCustomTesters ) ;
248- if ( isEqual === true ) {
249- has = true ;
250- }
237+ if ( a . size !== undefined ) {
238+ if ( a . size !== b . size ) {
239+ aStack . pop ( ) ;
240+ bStack . pop ( ) ;
241+ return false ;
242+ } else if ( isA < Set < unknown > > ( 'Set' , a ) || isImmutableUnorderedSet ( a ) ) {
243+ let allFound = true ;
244+ for ( const aValue of a ) {
245+ if ( ! b . has ( aValue ) ) {
246+ let has = false ;
247+ for ( const bValue of b ) {
248+ const isEqual = equals ( aValue , bValue , filteredCustomTesters ) ;
249+ if ( isEqual === true ) {
250+ has = true ;
251251 }
252+ }
252253
253- if ( has === false ) {
254- allFound = false ;
255- break ;
256- }
254+ if ( has === false ) {
255+ allFound = false ;
256+ break ;
257257 }
258258 }
259- return allFound ;
260- } else if (
261- isA < Map < unknown , unknown > > ( 'Map' , a ) ||
262- isImmutableUnorderedKeyed ( a )
263- ) {
264- let allFound = true ;
265- for ( const aEntry of a ) {
266- if (
267- ! b . has ( aEntry [ 0 ] ) ||
268- ! equals ( aEntry [ 1 ] , b . get ( aEntry [ 0 ] ) , filteredCustomTesters )
269- ) {
270- let has = false ;
271- for ( const bEntry of b ) {
272- const matchedKey = equals (
273- aEntry [ 0 ] ,
274- bEntry [ 0 ] ,
259+ }
260+ // Remove the first value from the stack of traversed values.
261+ aStack . pop ( ) ;
262+ bStack . pop ( ) ;
263+ return allFound ;
264+ } else if (
265+ isA < Map < unknown , unknown > > ( 'Map' , a ) ||
266+ isImmutableUnorderedKeyed ( a )
267+ ) {
268+ let allFound = true ;
269+ for ( const aEntry of a ) {
270+ if (
271+ ! b . has ( aEntry [ 0 ] ) ||
272+ ! equals ( aEntry [ 1 ] , b . get ( aEntry [ 0 ] ) , filteredCustomTesters )
273+ ) {
274+ let has = false ;
275+ for ( const bEntry of b ) {
276+ const matchedKey = equals (
277+ aEntry [ 0 ] ,
278+ bEntry [ 0 ] ,
279+ filteredCustomTesters ,
280+ ) ;
281+
282+ let matchedValue = false ;
283+ if ( matchedKey === true ) {
284+ matchedValue = equals (
285+ aEntry [ 1 ] ,
286+ bEntry [ 1 ] ,
275287 filteredCustomTesters ,
276288 ) ;
277-
278- let matchedValue = false ;
279- if ( matchedKey === true ) {
280- matchedValue = equals (
281- aEntry [ 1 ] ,
282- bEntry [ 1 ] ,
283- filteredCustomTesters ,
284- ) ;
285- }
286- if ( matchedValue === true ) {
287- has = true ;
288- }
289289 }
290-
291- if ( has === false ) {
292- allFound = false ;
293- break ;
290+ if ( matchedValue === true ) {
291+ has = true ;
294292 }
295293 }
294+
295+ if ( has === false ) {
296+ allFound = false ;
297+ break ;
298+ }
296299 }
297- return allFound ;
298300 }
301+ // Remove the first value from the stack of traversed values.
302+ aStack . pop ( ) ;
303+ bStack . pop ( ) ;
304+ return allFound ;
299305 }
306+ }
300307
301- const bIterator = b [ IteratorSymbol ] ( ) ;
302-
303- for ( const aValue of a ) {
304- const nextB = bIterator . next ( ) ;
305- if ( nextB . done || ! equals ( aValue , nextB . value , filteredCustomTesters ) ) {
306- return false ;
307- }
308- }
309- if ( ! bIterator . next ( ) . done ) {
310- return false ;
311- }
308+ let aIterator : Iterator < unknown > ;
309+ let bIterator : Iterator < unknown > ;
310+ try {
311+ aIterator = a [ IteratorSymbol ] ( ) ;
312+ bIterator = b [ IteratorSymbol ] ( ) ;
313+ } catch {
314+ // If the iterator factory itself throws (e.g. a TypedArray method used as
315+ // [Symbol.iterator] on a plain object), we cannot compare as iterables.
316+ // Return undefined so equals() falls through to Object.is / property checks.
317+ aStack . pop ( ) ;
318+ bStack . pop ( ) ;
319+ return undefined ;
320+ }
312321
322+ let aStep = aIterator . next ( ) ;
323+ while ( ! aStep . done ) {
324+ const bStep = bIterator . next ( ) ;
313325 if (
314- ! isImmutableList ( a ) &&
315- ! isImmutableOrderedKeyed ( a ) &&
316- ! isImmutableOrderedSet ( a ) &&
317- ! isImmutableRecord ( a )
326+ bStep . done ||
327+ ! equals ( aStep . value , bStep . value , filteredCustomTesters )
318328 ) {
319- const aEntries = entries ( a ) ;
320- const bEntries = entries ( b ) ;
321- if ( ! equals ( aEntries , bEntries ) ) {
322- return false ;
323- }
329+ aStack . pop ( ) ;
330+ bStack . pop ( ) ;
331+ return false ;
324332 }
325-
326- return true ;
327- } catch {
328- // If an exotic iterator/getter throws (DOM objects, proxies, host objects),
329- // treat it as "not equal" rather than crashing the matcher.
330- return false ;
331- } finally {
333+ aStep = aIterator . next ( ) ;
334+ }
335+ if ( ! bIterator . next ( ) . done ) {
332336 aStack . pop ( ) ;
333337 bStack . pop ( ) ;
338+ return false ;
334339 }
340+
341+ if (
342+ ! isImmutableList ( a ) &&
343+ ! isImmutableOrderedKeyed ( a ) &&
344+ ! isImmutableOrderedSet ( a ) &&
345+ ! isImmutableRecord ( a )
346+ ) {
347+ const aEntries = entries ( a ) ;
348+ const bEntries = entries ( b ) ;
349+ if ( ! equals ( aEntries , bEntries ) ) {
350+ aStack . pop ( ) ;
351+ bStack . pop ( ) ;
352+ return false ;
353+ }
354+ }
355+
356+ // Remove the first value from the stack of traversed values.
357+ aStack . pop ( ) ;
358+ bStack . pop ( ) ;
359+ return true ;
335360} ;
336361
337362const entries = ( obj : any ) => {
0 commit comments