forked from rocicorp/replicache
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson.ts
More file actions
91 lines (80 loc) · 1.99 KB
/
Copy pathjson.ts
File metadata and controls
91 lines (80 loc) · 1.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/** The values that can be represented in JSON */
export type JSONValue =
| null
| string
| boolean
| number
| Array<JSONValue>
| JSONObject;
/**
* A JSON object. We allow undefined values because in TypeScript there is no
* way to express optional missing properties vs properties with the value
* `undefined`.
*/
export type JSONObject = Partial<{[key: string]: JSONValue}>;
/**
* Checks deep equality of two JSON value with (almost) same semantics as
* `JSON.stringify`. The only difference is that with `JSON.stringify` the
* ordering of the properties in an object/map/dictionary matters. In
* [[deepEqual]] the following two values are consider equal, even though the
* strings JSON.stringify would produce is different:
*
* ```js
* assert(deepEqual(t({a: 1, b: 2}, {b: 2, a: 1}))
* ```
*/
export function deepEqual(
a: JSONValue | undefined,
b: JSONValue | undefined,
): boolean {
if (a === b) {
return true;
}
if (typeof a !== typeof b) {
return false;
}
switch (typeof a) {
case 'boolean':
case 'number':
case 'string':
return false;
}
// a cannot be undefined here because either a and b are undefined or their
// types are different.
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion
a = a!;
// 'object'
if (Array.isArray(a)) {
if (!Array.isArray(b)) {
return false;
}
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (!deepEqual(a[i], b[i])) {
return false;
}
}
return true;
}
if (a === null || b === null) {
return false;
}
if (Array.isArray(b)) {
return false;
}
// We know b is an object here but type inference is not smart enough.
b = b as JSONObject;
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) {
return false;
}
for (const key of aKeys) {
if (!deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}