@@ -10,17 +10,17 @@ const {
1010 Error,
1111 NumberIsNaN,
1212 NumberPrototypeValueOf,
13- ObjectGetOwnPropertySymbols,
13+ ObjectGetOwnPropertySymbols : getOwnSymbols ,
1414 ObjectGetPrototypeOf,
1515 ObjectIs,
1616 ObjectKeys,
17- ObjectPrototypeHasOwnProperty,
18- ObjectPrototypePropertyIsEnumerable,
17+ ObjectPrototypeHasOwnProperty : hasOwn ,
18+ ObjectPrototypePropertyIsEnumerable : hasEnumerable ,
1919 ObjectPrototypeToString,
2020 SafeSet,
2121 StringPrototypeValueOf,
2222 SymbolPrototypeValueOf,
23- TypedArrayPrototypeGetByteLength,
23+ TypedArrayPrototypeGetByteLength : getByteLength ,
2424 TypedArrayPrototypeGetSymbolToStringTag,
2525 Uint8Array,
2626} = primordials ;
@@ -76,8 +76,8 @@ function areSimilarRegExps(a, b) {
7676}
7777
7878function isPartialUint8Array ( a , b ) {
79- const lenA = TypedArrayPrototypeGetByteLength ( a ) ;
80- const lenB = TypedArrayPrototypeGetByteLength ( b ) ;
79+ const lenA = getByteLength ( a ) ;
80+ const lenB = getByteLength ( b ) ;
8181 if ( lenA < lenB ) {
8282 return false ;
8383 }
@@ -105,10 +105,10 @@ function isPartialArrayBufferView(a, b) {
105105}
106106
107107function areSimilarFloatArrays ( a , b ) {
108- if ( a . byteLength !== b . byteLength ) {
108+ const len = getByteLength ( a ) ;
109+ if ( len !== getByteLength ( b ) ) {
109110 return false ;
110111 }
111- const len = TypedArrayPrototypeGetByteLength ( a ) ;
112112 for ( let offset = 0 ; offset < len ; offset ++ ) {
113113 if ( a [ offset ] !== b [ offset ] ) {
114114 return false ;
@@ -156,6 +156,12 @@ function isEqualBoxedPrimitive(val1, val2) {
156156 assert . fail ( `Unknown boxed type ${ val1 } ` ) ;
157157}
158158
159+ function isEnumerableOrIdentical ( val1 , val2 , prop , mode , memos , method ) {
160+ return hasEnumerable ( val2 , prop ) || // This is handled by Object.keys()
161+ ( mode === kPartial && ( val2 [ prop ] === undefined || ( prop === 'message' && val2 [ prop ] === '' ) ) ) ||
162+ innerDeepEqual ( val1 [ prop ] , val2 [ prop ] , mode , memos ) ;
163+ }
164+
159165// Notes: Type tags are historical [[Class]] properties that can be set by
160166// FunctionTemplate::SetClassName() in C++ or Symbol.toStringTag in JS
161167// and retrieved using Object.prototype.toString.call(obj) in JS
@@ -261,8 +267,7 @@ function innerDeepEqual(val1, val2, mode, memos) {
261267 ( val1 . size !== val2 . size && ( mode !== kPartial || val1 . size < val2 . size ) ) ) {
262268 return false ;
263269 }
264- const result = keyCheck ( val1 , val2 , mode , memos , kIsSet ) ;
265- return result ;
270+ return keyCheck ( val1 , val2 , mode , memos , kIsSet ) ;
266271 } else if ( isMap ( val1 ) ) {
267272 if ( ! isMap ( val2 ) ||
268273 ( val1 . size !== val2 . size && ( mode !== kPartial || val1 . size < val2 . size ) ) ) {
@@ -283,26 +288,15 @@ function innerDeepEqual(val1, val2, mode, memos) {
283288 } else if ( isError ( val1 ) ) {
284289 // Do not compare the stack as it might differ even though the error itself
285290 // is otherwise identical.
286- if ( ! isError ( val2 ) ) {
291+ if ( ! isError ( val2 ) ||
292+ ! isEnumerableOrIdentical ( val1 , val2 , 'message' , mode , memos ) ||
293+ ! isEnumerableOrIdentical ( val1 , val2 , 'name' , mode , memos ) ||
294+ ! isEnumerableOrIdentical ( val1 , val2 , 'cause' , mode , memos ) ||
295+ ! isEnumerableOrIdentical ( val1 , val2 , 'errors' , mode , memos ) ) {
287296 return false ;
288297 }
289-
290- const message1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'message' ) ;
291- const name1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'name' ) ;
292- // TODO(BridgeAR): Adjust cause and errors properties for partial mode.
293- const cause1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'cause' ) ;
294- const errors1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'errors' ) ;
295-
296- if ( ( message1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'message' ) ||
297- ( ! message1Enumerable && val1 . message !== val2 . message ) ) ||
298- ( name1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'name' ) ||
299- ( ! name1Enumerable && val1 . name !== val2 . name ) ) ||
300- ( cause1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'cause' ) ||
301- ( ! cause1Enumerable && (
302- ObjectPrototypeHasOwnProperty ( val1 , 'cause' ) !== ObjectPrototypeHasOwnProperty ( val2 , 'cause' ) ||
303- ! innerDeepEqual ( val1 . cause , val2 . cause , mode , memos ) ) ) ) ||
304- ( errors1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'errors' ) ||
305- ( ! errors1Enumerable && ! innerDeepEqual ( val1 . errors , val2 . errors , mode , memos ) ) ) ) {
298+ const hasOwnVal2Cause = hasOwn ( val2 , 'cause' ) ;
299+ if ( ( hasOwnVal2Cause !== hasOwn ( val1 , 'cause' ) && ( mode !== kPartial || hasOwnVal2Cause ) ) ) {
306300 return false ;
307301 }
308302 } else if ( isBoxedPrimitive ( val1 ) ) {
@@ -344,10 +338,7 @@ function innerDeepEqual(val1, val2, mode, memos) {
344338}
345339
346340function getEnumerables ( val , keys ) {
347- return ArrayPrototypeFilter (
348- keys ,
349- ( k ) => ObjectPrototypePropertyIsEnumerable ( val , k ) ,
350- ) ;
341+ return ArrayPrototypeFilter ( keys , ( key ) => hasEnumerable ( val , key ) ) ;
351342}
352343
353344function keyCheck ( val1 , val2 , mode , memos , iterationType , keys2 ) {
@@ -367,7 +358,7 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
367358 // Cheap key test
368359 if ( keys2 . length > 0 ) {
369360 for ( const key of keys2 ) {
370- if ( ! ObjectPrototypePropertyIsEnumerable ( val1 , key ) ) {
361+ if ( ! hasEnumerable ( val1 , key ) ) {
371362 return false ;
372363 }
373364 }
@@ -376,11 +367,11 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
376367 if ( ! isArrayLikeObject ) {
377368 // The pair must have the same number of owned properties.
378369 if ( mode === kPartial ) {
379- const symbolKeys = ObjectGetOwnPropertySymbols ( val2 ) ;
370+ const symbolKeys = getOwnSymbols ( val2 ) ;
380371 if ( symbolKeys . length !== 0 ) {
381372 for ( const key of symbolKeys ) {
382- if ( ObjectPrototypePropertyIsEnumerable ( val2 , key ) ) {
383- if ( ! ObjectPrototypePropertyIsEnumerable ( val1 , key ) ) {
373+ if ( hasEnumerable ( val2 , key ) ) {
374+ if ( ! hasEnumerable ( val1 , key ) ) {
384375 return false ;
385376 }
386377 ArrayPrototypePush ( keys2 , key ) ;
@@ -392,27 +383,27 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
392383 }
393384
394385 if ( mode === kStrict ) {
395- const symbolKeysA = ObjectGetOwnPropertySymbols ( val1 ) ;
386+ const symbolKeysA = getOwnSymbols ( val1 ) ;
396387 if ( symbolKeysA . length !== 0 ) {
397388 let count = 0 ;
398389 for ( const key of symbolKeysA ) {
399- if ( ObjectPrototypePropertyIsEnumerable ( val1 , key ) ) {
400- if ( ! ObjectPrototypePropertyIsEnumerable ( val2 , key ) ) {
390+ if ( hasEnumerable ( val1 , key ) ) {
391+ if ( ! hasEnumerable ( val2 , key ) ) {
401392 return false ;
402393 }
403394 ArrayPrototypePush ( keys2 , key ) ;
404395 count ++ ;
405- } else if ( ObjectPrototypePropertyIsEnumerable ( val2 , key ) ) {
396+ } else if ( hasEnumerable ( val2 , key ) ) {
406397 return false ;
407398 }
408399 }
409- const symbolKeysB = ObjectGetOwnPropertySymbols ( val2 ) ;
400+ const symbolKeysB = getOwnSymbols ( val2 ) ;
410401 if ( symbolKeysA . length !== symbolKeysB . length &&
411402 getEnumerables ( val2 , symbolKeysB ) . length !== count ) {
412403 return false ;
413404 }
414405 } else {
415- const symbolKeysB = ObjectGetOwnPropertySymbols ( val2 ) ;
406+ const symbolKeysB = getOwnSymbols ( val2 ) ;
416407 if ( symbolKeysB . length !== 0 &&
417408 getEnumerables ( val2 , symbolKeysB ) . length !== 0 ) {
418409 return false ;
@@ -437,7 +428,6 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
437428 c : undefined ,
438429 d : undefined ,
439430 deep : false ,
440- deleteFailures : false ,
441431 } ;
442432 return objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
443433 }
@@ -472,27 +462,21 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
472462
473463 const areEq = objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
474464
475- if ( areEq || memos . deleteFailures ) {
476- set . delete ( val1 ) ;
477- set . delete ( val2 ) ;
478- }
465+ set . delete ( val1 ) ;
466+ set . delete ( val2 ) ;
479467
480468 return areEq ;
481469}
482470
483471function setHasEqualElement ( set , val1 , mode , memo ) {
484- const { deleteFailures } = memo ;
485- memo . deleteFailures = true ;
486472 for ( const val2 of set ) {
487473 if ( innerDeepEqual ( val1 , val2 , mode , memo ) ) {
488474 // Remove the matching element to make sure we do not check that again.
489475 set . delete ( val2 ) ;
490- memo . deleteFailures = deleteFailures ;
491476 return true ;
492477 }
493478 }
494479
495- memo . deleteFailures = deleteFailures ;
496480 return false ;
497481}
498482
@@ -553,6 +537,8 @@ function partialObjectSetEquiv(a, b, mode, set, memo) {
553537 return false ;
554538 }
555539 }
540+ /* c8 ignore next */
541+ assert . fail ( 'Unreachable code' ) ;
556542}
557543
558544function setObjectEquiv ( a , b , mode , set , memo ) {
@@ -619,18 +605,14 @@ function mapHasEqualEntry(set, map, key1, item1, mode, memo) {
619605 // To be able to handle cases like:
620606 // Map([[{}, 'a'], [{}, 'b']]) vs Map([[{}, 'b'], [{}, 'a']])
621607 // ... we need to consider *all* matching keys, not just the first we find.
622- const { deleteFailures } = memo ;
623- memo . deleteFailures = true ;
624608 for ( const key2 of set ) {
625609 if ( innerDeepEqual ( key1 , key2 , mode , memo ) &&
626610 innerDeepEqual ( item1 , map . get ( key2 ) , mode , memo ) ) {
627611 set . delete ( key2 ) ;
628- memo . deleteFailures = deleteFailures ;
629612 return true ;
630613 }
631614 }
632615
633- memo . deleteFailures = deleteFailures ;
634616 return false ;
635617}
636618
@@ -648,6 +630,8 @@ function partialObjectMapEquiv(a, b, mode, set, memo) {
648630 return false ;
649631 }
650632 }
633+ /* c8 ignore next */
634+ assert . fail ( 'Unreachable code' ) ;
651635}
652636
653637function mapObjectEquivalence ( a , b , mode , set , memo ) {
@@ -743,11 +727,11 @@ function partialSparseArrayEquiv(a, b, mode, memos, startA, startB) {
743727function partialArrayEquiv ( a , b , mode , memos ) {
744728 let aPos = 0 ;
745729 for ( let i = 0 ; i < b . length ; i ++ ) {
746- let isSparse = b [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( b , i ) ;
730+ let isSparse = b [ i ] === undefined && ! hasOwn ( b , i ) ;
747731 if ( isSparse ) {
748732 return partialSparseArrayEquiv ( a , b , mode , memos , aPos , i ) ;
749733 }
750- while ( ! ( isSparse = a [ aPos ] === undefined && ! ObjectPrototypeHasOwnProperty ( a , aPos ) ) &&
734+ while ( ! ( isSparse = a [ aPos ] === undefined && ! hasOwn ( a , aPos ) ) &&
751735 ! innerDeepEqual ( a [ aPos ] , b [ i ] , mode , memos ) ) {
752736 aPos ++ ;
753737 if ( aPos > a . length - b . length + i ) {
@@ -772,8 +756,7 @@ function sparseArrayEquiv(a, b, mode, memos, i) {
772756 }
773757 for ( ; i < keysA . length ; i ++ ) {
774758 const key = keysA [ i ] ;
775- if ( ! ObjectPrototypeHasOwnProperty ( b , key ) ||
776- ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
759+ if ( ! hasOwn ( b , key ) || ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
777760 return false ;
778761 }
779762 }
@@ -798,8 +781,8 @@ function objEquiv(a, b, mode, keys2, memos, iterationType) {
798781 if ( ! innerDeepEqual ( a [ i ] , b [ i ] , mode , memos ) ) {
799782 return false ;
800783 }
801- const isSparseA = a [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( a , i ) ;
802- const isSparseB = b [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( b , i ) ;
784+ const isSparseA = a [ i ] === undefined && ! hasOwn ( a , i ) ;
785+ const isSparseB = b [ i ] === undefined && ! hasOwn ( b , i ) ;
803786 if ( isSparseA !== isSparseB ) {
804787 return false ;
805788 }
0 commit comments