@@ -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 ;
@@ -78,8 +78,8 @@ function areSimilarRegExps(a, b) {
7878}
7979
8080function isPartialUint8Array ( a , b ) {
81- const lenA = TypedArrayPrototypeGetByteLength ( a ) ;
82- const lenB = TypedArrayPrototypeGetByteLength ( b ) ;
81+ const lenA = getByteLength ( a ) ;
82+ const lenB = getByteLength ( b ) ;
8383if ( lenA < lenB ) {
8484return false ;
8585}
@@ -107,10 +107,10 @@ function isPartialArrayBufferView(a, b) {
107107}
108108
109109function areSimilarFloatArrays ( a , b ) {
110- if ( a . byteLength !== b . byteLength ) {
110+ const len = getByteLength ( a ) ;
111+ if ( len !== getByteLength ( b ) ) {
111112return false ;
112113}
113- const len = TypedArrayPrototypeGetByteLength ( a ) ;
114114for ( let offset = 0 ; offset < len ; offset ++ ) {
115115if ( a [ offset ] !== b [ offset ] ) {
116116return false ;
@@ -158,6 +158,12 @@ function isEqualBoxedPrimitive(val1, val2) {
158158assert . fail ( `Unknown boxed type ${ val1 } ` ) ;
159159}
160160
161+ function isEnumerableOrIdentical ( val1 , val2 , prop , mode , memos , method ) {
162+ return hasEnumerable ( val2 , prop ) || // This is handled by Object.keys()
163+ ( mode === kPartial && ( val2 [ prop ] === undefined || ( prop === 'message' && val2 [ prop ] === '' ) ) ) ||
164+ innerDeepEqual ( val1 [ prop ] , val2 [ prop ] , mode , memos ) ;
165+ }
166+
161167// Notes: Type tags are historical [[Class]] properties that can be set by
162168// FunctionTemplate::SetClassName() in C++ or Symbol.toStringTag in JS
163169// and retrieved using Object.prototype.toString.call(obj) in JS
@@ -263,8 +269,7 @@ function innerDeepEqual(val1, val2, mode, memos) {
263269( val1 . size !== val2 . size && ( mode !== kPartial || val1 . size < val2 . size ) ) ) {
264270return false ;
265271}
266- const result = keyCheck ( val1 , val2 , mode , memos , kIsSet ) ;
267- return result ;
272+ return keyCheck ( val1 , val2 , mode , memos , kIsSet ) ;
268273} else if ( isMap ( val1 ) ) {
269274if ( ! isMap ( val2 ) ||
270275( val1 . size !== val2 . size && ( mode !== kPartial || val1 . size < val2 . size ) ) ) {
@@ -285,26 +290,15 @@ function innerDeepEqual(val1, val2, mode, memos) {
285290} else if ( isError ( val1 ) ) {
286291// Do not compare the stack as it might differ even though the error itself
287292// is otherwise identical.
288- if ( ! isError ( val2 ) ) {
293+ if ( ! isError ( val2 ) ||
294+ ! isEnumerableOrIdentical ( val1 , val2 , 'message' , mode , memos ) ||
295+ ! isEnumerableOrIdentical ( val1 , val2 , 'name' , mode , memos ) ||
296+ ! isEnumerableOrIdentical ( val1 , val2 , 'cause' , mode , memos ) ||
297+ ! isEnumerableOrIdentical ( val1 , val2 , 'errors' , mode , memos ) ) {
289298return false ;
290299}
291-
292- const message1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'message' ) ;
293- const name1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'name' ) ;
294- // TODO(BridgeAR): Adjust cause and errors properties for partial mode.
295- const cause1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'cause' ) ;
296- const errors1Enumerable = ObjectPrototypePropertyIsEnumerable ( val1 , 'errors' ) ;
297-
298- if ( ( message1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'message' ) ||
299- ( ! message1Enumerable && val1 . message !== val2 . message ) ) ||
300- ( name1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'name' ) ||
301- ( ! name1Enumerable && val1 . name !== val2 . name ) ) ||
302- ( cause1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'cause' ) ||
303- ( ! cause1Enumerable && (
304- ObjectPrototypeHasOwnProperty ( val1 , 'cause' ) !== ObjectPrototypeHasOwnProperty ( val2 , 'cause' ) ||
305- ! innerDeepEqual ( val1 . cause , val2 . cause , mode , memos ) ) ) ) ||
306- ( errors1Enumerable !== ObjectPrototypePropertyIsEnumerable ( val2 , 'errors' ) ||
307- ( ! errors1Enumerable && ! innerDeepEqual ( val1 . errors , val2 . errors , mode , memos ) ) ) ) {
300+ const hasOwnVal2Cause = hasOwn ( val2 , 'cause' ) ;
301+ if ( ( hasOwnVal2Cause !== hasOwn ( val1 , 'cause' ) && ( mode !== kPartial || hasOwnVal2Cause ) ) ) {
308302return false ;
309303}
310304} else if ( isBoxedPrimitive ( val1 ) ) {
@@ -348,10 +342,7 @@ function innerDeepEqual(val1, val2, mode, memos) {
348342}
349343
350344function getEnumerables ( val , keys ) {
351- return ArrayPrototypeFilter (
352- keys ,
353- ( k ) => ObjectPrototypePropertyIsEnumerable ( val , k ) ,
354- ) ;
345+ return ArrayPrototypeFilter ( keys , ( key ) => hasEnumerable ( val , key ) ) ;
355346}
356347
357348function keyCheck ( val1 , val2 , mode , memos , iterationType , keys2 ) {
@@ -371,7 +362,7 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
371362// Cheap key test
372363if ( keys2 . length > 0 ) {
373364for ( const key of keys2 ) {
374- if ( ! ObjectPrototypePropertyIsEnumerable ( val1 , key ) ) {
365+ if ( ! hasEnumerable ( val1 , key ) ) {
375366return false ;
376367}
377368}
@@ -380,11 +371,11 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
380371if ( ! isArrayLikeObject ) {
381372// The pair must have the same number of owned properties.
382373if ( mode === kPartial ) {
383- const symbolKeys = ObjectGetOwnPropertySymbols ( val2 ) ;
374+ const symbolKeys = getOwnSymbols ( val2 ) ;
384375if ( symbolKeys . length !== 0 ) {
385376for ( const key of symbolKeys ) {
386- if ( ObjectPrototypePropertyIsEnumerable ( val2 , key ) ) {
387- if ( ! ObjectPrototypePropertyIsEnumerable ( val1 , key ) ) {
377+ if ( hasEnumerable ( val2 , key ) ) {
378+ if ( ! hasEnumerable ( val1 , key ) ) {
388379return false ;
389380}
390381ArrayPrototypePush ( keys2 , key ) ;
@@ -396,27 +387,27 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
396387}
397388
398389if ( mode === kStrict ) {
399- const symbolKeysA = ObjectGetOwnPropertySymbols ( val1 ) ;
390+ const symbolKeysA = getOwnSymbols ( val1 ) ;
400391if ( symbolKeysA . length !== 0 ) {
401392let count = 0 ;
402393for ( const key of symbolKeysA ) {
403- if ( ObjectPrototypePropertyIsEnumerable ( val1 , key ) ) {
404- if ( ! ObjectPrototypePropertyIsEnumerable ( val2 , key ) ) {
394+ if ( hasEnumerable ( val1 , key ) ) {
395+ if ( ! hasEnumerable ( val2 , key ) ) {
405396return false ;
406397}
407398ArrayPrototypePush ( keys2 , key ) ;
408399count ++ ;
409- } else if ( ObjectPrototypePropertyIsEnumerable ( val2 , key ) ) {
400+ } else if ( hasEnumerable ( val2 , key ) ) {
410401return false ;
411402}
412403}
413- const symbolKeysB = ObjectGetOwnPropertySymbols ( val2 ) ;
404+ const symbolKeysB = getOwnSymbols ( val2 ) ;
414405if ( symbolKeysA . length !== symbolKeysB . length &&
415406getEnumerables ( val2 , symbolKeysB ) . length !== count ) {
416407return false ;
417408}
418409} else {
419- const symbolKeysB = ObjectGetOwnPropertySymbols ( val2 ) ;
410+ const symbolKeysB = getOwnSymbols ( val2 ) ;
420411if ( symbolKeysB . length !== 0 &&
421412getEnumerables ( val2 , symbolKeysB ) . length !== 0 ) {
422413return false ;
@@ -441,7 +432,6 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
441432c : undefined ,
442433d : undefined ,
443434deep : false ,
444- deleteFailures : false ,
445435} ;
446436return objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
447437}
@@ -476,27 +466,21 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
476466
477467const areEq = objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
478468
479- if ( areEq || memos . deleteFailures ) {
480- set . delete ( val1 ) ;
481- set . delete ( val2 ) ;
482- }
469+ set . delete ( val1 ) ;
470+ set . delete ( val2 ) ;
483471
484472return areEq ;
485473}
486474
487475function setHasEqualElement ( set , val1 , mode , memo ) {
488- const { deleteFailures } = memo ;
489- memo . deleteFailures = true ;
490476for ( const val2 of set ) {
491477if ( innerDeepEqual ( val1 , val2 , mode , memo ) ) {
492478// Remove the matching element to make sure we do not check that again.
493479set . delete ( val2 ) ;
494- memo . deleteFailures = deleteFailures ;
495480return true ;
496481}
497482}
498483
499- memo . deleteFailures = deleteFailures ;
500484return false ;
501485}
502486
@@ -557,6 +541,8 @@ function partialObjectSetEquiv(a, b, mode, set, memo) {
557541return false ;
558542}
559543}
544+ /* c8 ignore next */
545+ assert . fail ( 'Unreachable code' ) ;
560546}
561547
562548function setObjectEquiv ( a , b , mode , set , memo ) {
@@ -623,18 +609,14 @@ function mapHasEqualEntry(set, map, key1, item1, mode, memo) {
623609// To be able to handle cases like:
624610// Map([[{}, 'a'], [{}, 'b']]) vs Map([[{}, 'b'], [{}, 'a']])
625611// ... we need to consider *all* matching keys, not just the first we find.
626- const { deleteFailures } = memo ;
627- memo . deleteFailures = true ;
628612for ( const key2 of set ) {
629613if ( innerDeepEqual ( key1 , key2 , mode , memo ) &&
630614innerDeepEqual ( item1 , map . get ( key2 ) , mode , memo ) ) {
631615set . delete ( key2 ) ;
632- memo . deleteFailures = deleteFailures ;
633616return true ;
634617}
635618}
636619
637- memo . deleteFailures = deleteFailures ;
638620return false ;
639621}
640622
@@ -652,6 +634,8 @@ function partialObjectMapEquiv(a, b, mode, set, memo) {
652634return false ;
653635}
654636}
637+ /* c8 ignore next */
638+ assert . fail ( 'Unreachable code' ) ;
655639}
656640
657641function mapObjectEquivalence ( a , b , mode , set , memo ) {
@@ -747,11 +731,11 @@ function partialSparseArrayEquiv(a, b, mode, memos, startA, startB) {
747731function partialArrayEquiv ( a , b , mode , memos ) {
748732let aPos = 0 ;
749733for ( let i = 0 ; i < b . length ; i ++ ) {
750- let isSparse = b [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( b , i ) ;
734+ let isSparse = b [ i ] === undefined && ! hasOwn ( b , i ) ;
751735if ( isSparse ) {
752736return partialSparseArrayEquiv ( a , b , mode , memos , aPos , i ) ;
753737}
754- while ( ! ( isSparse = a [ aPos ] === undefined && ! ObjectPrototypeHasOwnProperty ( a , aPos ) ) &&
738+ while ( ! ( isSparse = a [ aPos ] === undefined && ! hasOwn ( a , aPos ) ) &&
755739! innerDeepEqual ( a [ aPos ] , b [ i ] , mode , memos ) ) {
756740aPos ++ ;
757741if ( aPos > a . length - b . length + i ) {
@@ -776,8 +760,7 @@ function sparseArrayEquiv(a, b, mode, memos, i) {
776760}
777761for ( ; i < keysA . length ; i ++ ) {
778762const key = keysA [ i ] ;
779- if ( ! ObjectPrototypeHasOwnProperty ( b , key ) ||
780- ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
763+ if ( ! hasOwn ( b , key ) || ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
781764return false ;
782765}
783766}
@@ -802,8 +785,8 @@ function objEquiv(a, b, mode, keys2, memos, iterationType) {
802785if ( ! innerDeepEqual ( a [ i ] , b [ i ] , mode , memos ) ) {
803786return false ;
804787}
805- const isSparseA = a [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( a , i ) ;
806- const isSparseB = b [ i ] === undefined && ! ObjectPrototypeHasOwnProperty ( b , i ) ;
788+ const isSparseA = a [ i ] === undefined && ! hasOwn ( a , i ) ;
789+ const isSparseB = b [ i ] === undefined && ! hasOwn ( b , i ) ;
807790if ( isSparseA !== isSparseB ) {
808791return false ;
809792}
0 commit comments