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