@@ -24,6 +24,7 @@ const { compare } = process.binding('buffer');
2424const { isSet, isMap, isDate, isRegExp } = process . binding ( 'util' ) ;
2525const { objectToString } = require ( 'internal/util' ) ;
2626const errors = require ( 'internal/errors' ) ;
27+ const { propertyIsEnumerable } = Object . prototype ;
2728
2829// The assert module provides functions that throw
2930// AssertionError's when particular conditions are not met. The
@@ -165,7 +166,7 @@ function isObjectOrArrayTag(tag) {
165166// For strict comparison, objects should have
166167// a) The same built-in type tags
167168// b) The same prototypes.
168- function strictDeepEqual ( actual , expected ) {
169+ function strictDeepEqual ( actual , expected , memos ) {
169170 if ( typeof actual !== 'object' ) {
170171 return typeof actual === 'number' && Number . isNaN ( actual ) &&
171172 Number . isNaN ( expected ) ;
@@ -186,12 +187,12 @@ function strictDeepEqual(actual, expected) {
186187 // Check for sparse arrays and general fast path
187188 if ( actual . length !== expected . length )
188189 return false ;
189- // Skip testing the part below and continue in the callee function .
190- return ;
190+ // Skip testing the part below and continue with the keyCheck .
191+ return keyCheck ( actual , expected , true , memos ) ;
191192 }
192193 if ( actualTag === '[object Object]' ) {
193- // Skip testing the part below and continue in the callee function .
194- return ;
194+ // Skip testing the part below and continue with the keyCheck .
195+ return keyCheck ( actual , expected , true , memos ) ;
195196 }
196197 if ( isDate ( actual ) ) {
197198 if ( actual . getTime ( ) !== expected . getTime ( ) ) {
@@ -215,10 +216,8 @@ function strictDeepEqual(actual, expected) {
215216 }
216217 // Buffer.compare returns true, so actual.length === expected.length
217218 // if they both only contain numeric keys, we don't need to exam further
218- if ( Object . keys ( actual ) . length === actual . length &&
219- Object . keys ( expected ) . length === expected . length ) {
220- return true ;
221- }
219+ return keyCheck ( actual , expected , true , memos , actual . length ,
220+ expected . length ) ;
222221 } else if ( typeof actual . valueOf === 'function' ) {
223222 const actualValue = actual . valueOf ( ) ;
224223 // Note: Boxed string keys are going to be compared again by Object.keys
@@ -232,15 +231,14 @@ function strictDeepEqual(actual, expected) {
232231 lengthActual = actual . length ;
233232 lengthExpected = expected . length ;
234233 }
235- if ( Object . keys ( actual ) . length === lengthActual &&
236- Object . keys ( expected ) . length === lengthExpected ) {
237- return true ;
238- }
234+ return keyCheck ( actual , expected , true , memos , lengthActual ,
235+ lengthExpected ) ;
239236 }
240237 }
238+ return keyCheck ( actual , expected , true , memos ) ;
241239}
242240
243- function looseDeepEqual ( actual , expected ) {
241+ function looseDeepEqual ( actual , expected , memos ) {
244242 if ( actual === null || typeof actual !== 'object' ) {
245243 if ( expected === null || typeof expected !== 'object' ) {
246244 // eslint-disable-next-line eqeqeq
@@ -274,33 +272,62 @@ function looseDeepEqual(actual, expected) {
274272 } else if ( isArguments ( actualTag ) || isArguments ( expectedTag ) ) {
275273 return false ;
276274 }
275+ return keyCheck ( actual , expected , false , memos ) ;
277276}
278277
279- function innerDeepEqual ( actual , expected , strict , memos ) {
280- // All identical values are equivalent, as determined by ===.
281- if ( actual === expected ) {
282- if ( actual !== 0 )
283- return true ;
284- return strict ? Object . is ( actual , expected ) : true ;
285- }
286-
287- // Returns a boolean if (not) equal and undefined in case we have to check
288- // further.
289- const partialCheck = strict ?
290- strictDeepEqual ( actual , expected ) :
291- looseDeepEqual ( actual , expected ) ;
292-
293- if ( partialCheck !== undefined ) {
294- return partialCheck ;
295- }
296-
278+ function keyCheck ( actual , expected , strict , memos , lengthA , lengthB ) {
297279 // For all remaining Object pairs, including Array, objects and Maps,
298280 // equivalence is determined by having:
299281 // a) The same number of owned enumerable properties
300282 // b) The same set of keys/indexes (although not necessarily the same order)
301283 // c) Equivalent values for every corresponding key/index
302284 // d) For Sets and Maps, equal contents
303285 // Note: this accounts for both named and indexed properties on Arrays.
286+ var aKeys = Object . keys ( actual ) ;
287+ var bKeys = Object . keys ( expected ) ;
288+ var i ;
289+
290+ // The pair must have the same number of owned properties.
291+ if ( aKeys . length !== bKeys . length )
292+ return false ;
293+
294+ if ( strict ) {
295+ var symbolKeysA = Object . getOwnPropertySymbols ( actual ) ;
296+ var symbolKeysB = Object . getOwnPropertySymbols ( expected ) ;
297+ if ( symbolKeysA . length !== 0 ) {
298+ symbolKeysA = symbolKeysA . filter ( ( k ) =>
299+ propertyIsEnumerable . call ( actual , k ) ) ;
300+ symbolKeysB = symbolKeysB . filter ( ( k ) =>
301+ propertyIsEnumerable . call ( expected , k ) ) ;
302+ if ( symbolKeysA . length !== symbolKeysB . length )
303+ return false ;
304+ } else if ( symbolKeysB . length !== 0 && symbolKeysB . filter ( ( k ) =>
305+ propertyIsEnumerable . call ( expected , k ) ) . length !== 0 ) {
306+ return false ;
307+ }
308+ if ( lengthA !== undefined ) {
309+ if ( aKeys . length !== lengthA || bKeys . length !== lengthB )
310+ return false ;
311+ if ( symbolKeysA . length === 0 )
312+ return true ;
313+ aKeys = [ ] ;
314+ bKeys = [ ] ;
315+ }
316+ if ( symbolKeysA . length !== 0 ) {
317+ aKeys . push ( ...symbolKeysA ) ;
318+ bKeys . push ( ...symbolKeysB ) ;
319+ }
320+ }
321+
322+ // Cheap key test:
323+ const keys = { } ;
324+ for ( i = 0 ; i < aKeys . length ; i ++ ) {
325+ keys [ aKeys [ i ] ] = true ;
326+ }
327+ for ( i = 0 ; i < aKeys . length ; i ++ ) {
328+ if ( keys [ bKeys [ i ] ] === undefined )
329+ return false ;
330+ }
304331
305332 // Use memos to handle cycles.
306333 if ( memos === undefined ) {
@@ -323,25 +350,6 @@ function innerDeepEqual(actual, expected, strict, memos) {
323350 memos . position ++ ;
324351 }
325352
326- const aKeys = Object . keys ( actual ) ;
327- const bKeys = Object . keys ( expected ) ;
328- var i ;
329-
330- // The pair must have the same number of owned properties
331- // (keys incorporates hasOwnProperty).
332- if ( aKeys . length !== bKeys . length )
333- return false ;
334-
335- // Cheap key test:
336- const keys = { } ;
337- for ( i = 0 ; i < aKeys . length ; i ++ ) {
338- keys [ aKeys [ i ] ] = true ;
339- }
340- for ( i = 0 ; i < aKeys . length ; i ++ ) {
341- if ( keys [ bKeys [ i ] ] === undefined )
342- return false ;
343- }
344-
345353 memos . actual . set ( actual , memos . position ) ;
346354 memos . expected . set ( expected , memos . position ) ;
347355
@@ -353,6 +361,21 @@ function innerDeepEqual(actual, expected, strict, memos) {
353361 return areEq ;
354362}
355363
364+ function innerDeepEqual ( actual , expected , strict , memos ) {
365+ // All identical values are equivalent, as determined by ===.
366+ if ( actual === expected ) {
367+ if ( actual !== 0 )
368+ return true ;
369+ return strict ? Object . is ( actual , expected ) : true ;
370+ }
371+
372+ // Check more closely if actual and expected are equal.
373+ if ( strict === true )
374+ return strictDeepEqual ( actual , expected , memos ) ;
375+
376+ return looseDeepEqual ( actual , expected , memos ) ;
377+ }
378+
356379function setHasEqualElement ( set , val1 , strict , memo ) {
357380 // Go looking.
358381 for ( const val2 of set ) {
0 commit comments