1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @format
    
  8.  * @flow
    
  9.  */
    
  10. 
    
  11. 'use strict';
    
  12. 
    
  13. type Options = {+unsafelyIgnoreFunctions?: boolean};
    
  14. 
    
  15. /*
    
  16.  * @returns {bool} true if different, false if equal
    
  17.  */
    
  18. function deepDiffer(
    
  19.   one: any,
    
  20.   two: any,
    
  21.   maxDepthOrOptions: Options | number = -1,
    
  22.   maybeOptions?: Options,
    
  23. ): boolean {
    
  24.   const options =
    
  25.     typeof maxDepthOrOptions === 'number' ? maybeOptions : maxDepthOrOptions;
    
  26.   const maxDepth =
    
  27.     typeof maxDepthOrOptions === 'number' ? maxDepthOrOptions : -1;
    
  28.   if (maxDepth === 0) {
    
  29.     return true;
    
  30.   }
    
  31.   if (one === two) {
    
  32.     // Short circuit on identical object references instead of traversing them.
    
  33.     return false;
    
  34.   }
    
  35.   if (typeof one === 'function' && typeof two === 'function') {
    
  36.     // We consider all functions equal unless explicitly configured otherwise
    
  37.     let unsafelyIgnoreFunctions =
    
  38.       options == null ? null : options.unsafelyIgnoreFunctions;
    
  39.     if (unsafelyIgnoreFunctions == null) {
    
  40.       unsafelyIgnoreFunctions = true;
    
  41.     }
    
  42.     return !unsafelyIgnoreFunctions;
    
  43.   }
    
  44.   if (typeof one !== 'object' || one === null) {
    
  45.     // Primitives can be directly compared
    
  46.     return one !== two;
    
  47.   }
    
  48.   if (typeof two !== 'object' || two === null) {
    
  49.     // We know they are different because the previous case would have triggered
    
  50.     // otherwise.
    
  51.     return true;
    
  52.   }
    
  53.   if (one.constructor !== two.constructor) {
    
  54.     return true;
    
  55.   }
    
  56.   if (Array.isArray(one)) {
    
  57.     // We know two is also an array because the constructors are equal
    
  58.     const len = one.length;
    
  59.     if (two.length !== len) {
    
  60.       return true;
    
  61.     }
    
  62.     for (let ii = 0; ii < len; ii++) {
    
  63.       if (deepDiffer(one[ii], two[ii], maxDepth - 1, options)) {
    
  64.         return true;
    
  65.       }
    
  66.     }
    
  67.   } else {
    
  68.     for (const key in one) {
    
  69.       if (deepDiffer(one[key], two[key], maxDepth - 1, options)) {
    
  70.         return true;
    
  71.       }
    
  72.     }
    
  73.     for (const twoKey in two) {
    
  74.       // The only case we haven't checked yet is keys that are in two but aren't
    
  75.       // in one, which means they are different.
    
  76.       if (one[twoKey] === undefined && two[twoKey] !== undefined) {
    
  77.         return true;
    
  78.       }
    
  79.     }
    
  80.   }
    
  81.   return false;
    
  82. }
    
  83. 
    
  84. module.exports = deepDiffer;