@evolu/common 8.7.0 → 8.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Array.d.ts +21 -21
- package/dist/src/Array.js +5 -5
- package/dist/src/Assert.d.ts +478 -141
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +644 -99
- package/dist/src/{Buffer.d.ts → Binary.d.ts} +85 -12
- package/dist/src/Binary.d.ts.map +1 -0
- package/dist/src/{Buffer.js → Binary.js} +206 -24
- package/dist/src/Console.d.ts +2 -10
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +6 -12
- package/dist/src/Crypto.d.ts +5 -5
- package/dist/src/Crypto.js +1 -1
- package/dist/src/Eq.d.ts +35 -40
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +51 -87
- package/dist/src/Function.d.ts +9 -14
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +7 -9
- package/dist/src/Http.d.ts +6 -7
- package/dist/src/Http.d.ts.map +1 -1
- package/dist/src/LeakDetector.d.ts.map +1 -1
- package/dist/src/LeakDetector.js +1 -0
- package/dist/src/LockManager.d.ts +1 -1
- package/dist/src/LockManager.js +1 -1
- package/dist/src/Lookup.d.ts +3 -2
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +4 -3
- package/dist/src/Number.d.ts +1 -1
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +1 -1
- package/dist/src/Object.d.ts +4 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +5 -4
- package/dist/src/Option.d.ts +1 -2
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +1 -2
- package/dist/src/Platform.js +2 -0
- package/dist/src/Polyfills.js +4 -1
- package/dist/src/Random.d.ts +1 -1
- package/dist/src/Result.d.ts +49 -54
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +17 -22
- package/dist/src/Set.d.ts +6 -6
- package/dist/src/Set.js +2 -2
- package/dist/src/Sqlite.js +1 -1
- package/dist/src/String.js +3 -2
- package/dist/src/Task.d.ts +32 -32
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +20 -22
- package/dist/src/Test.d.ts +31 -3
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +46 -3
- package/dist/src/Time.d.ts +3 -11
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +10 -18
- package/dist/src/Type.d.ts +87 -85
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +70 -63
- package/dist/src/Types.d.ts +12 -12
- package/dist/src/Types.js +1 -1
- package/dist/src/WebSocket.d.ts +4 -7
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/Worker.d.ts +1 -1
- package/dist/src/Worker.js +7 -7
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +1 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +1 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +1 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +1 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +1 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +1 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +1 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +1 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +1 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +1 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +1 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +1 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +1 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +1 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +1 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +1 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +1 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +1 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +1 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +1 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +1 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +1 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +1 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +1 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +1 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +1 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +1 -1
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +1 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +1 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +1 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +1 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +1 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +1 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +1 -1
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +1 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +1 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +1 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +1 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +1 -1
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +1 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +1 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +1 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +1 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +1 -1
- package/dist/src/local-first/Evolu.d.ts +12 -12
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +2 -2
- package/dist/src/local-first/Protocol.d.ts +14 -76
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +29 -206
- package/dist/src/local-first/Query.d.ts +11 -11
- package/dist/src/local-first/Query.js +6 -6
- package/dist/src/local-first/Relay.d.ts +2 -2
- package/dist/src/local-first/Schema.d.ts +3 -5
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +2 -4
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +5 -5
- package/dist/src/local-first/Storage.js +4 -4
- package/dist/src/local-first/Timestamp.d.ts +9 -0
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +13 -10
- package/package.json +7 -4
- package/src/Array.test.ts +809 -0
- package/src/Array.ts +21 -21
- package/src/Assert.test.ts +1181 -0
- package/src/Assert.ts +971 -227
- package/src/BigInt.test.ts +28 -0
- package/src/Binary.test.ts +1128 -0
- package/src/{Buffer.ts → Binary.ts} +273 -46
- package/src/Brand.test.ts +90 -0
- package/src/Cache.test.ts +183 -0
- package/src/Callbacks.test.ts +66 -0
- package/src/Console.test.ts +809 -0
- package/src/Console.ts +9 -17
- package/src/Crypto.test.ts +138 -0
- package/src/Crypto.ts +5 -5
- package/src/Eq.test.ts +333 -0
- package/src/Eq.ts +110 -176
- package/src/Error.test.ts +118 -0
- package/src/Function.test.ts +204 -0
- package/src/Function.ts +10 -15
- package/src/Http.test.ts +816 -0
- package/src/Http.ts +6 -7
- package/src/LeakDetector.test.ts +210 -0
- package/src/LeakDetector.ts +1 -0
- package/src/LockManager.ts +2 -2
- package/src/Lookup.test.ts +418 -0
- package/src/Lookup.ts +4 -3
- package/src/Microtask.test.ts +140 -0
- package/src/Number.test.ts +218 -0
- package/src/Number.ts +2 -2
- package/src/Object.test.ts +293 -0
- package/src/Object.ts +5 -4
- package/src/Option.test.ts +104 -0
- package/src/Option.ts +1 -2
- package/src/Order.test.ts +56 -0
- package/src/Platform.ts +2 -0
- package/src/Polyfills.ts +3 -4
- package/src/Random.test.ts +89 -0
- package/src/Random.ts +1 -1
- package/src/Ref.test.ts +139 -0
- package/src/RefCount.test.ts +184 -0
- package/src/Relation.test.ts +505 -0
- package/src/Resource.test.ts +4623 -0
- package/src/Result.test.ts +1829 -0
- package/src/Result.ts +49 -54
- package/src/Schedule.test.ts +1554 -0
- package/src/Set.test.ts +279 -0
- package/src/Set.ts +6 -6
- package/src/Sqlite.ts +1 -1
- package/src/Store.test.ts +288 -0
- package/src/String.test.ts +54 -0
- package/src/String.ts +3 -3
- package/src/Task.test.ts +10820 -0
- package/src/Task.ts +38 -43
- package/src/Test.test.ts +88 -0
- package/src/Test.ts +49 -3
- package/src/Time.test.ts +926 -0
- package/src/Time.ts +13 -21
- package/src/Type.base64.test.ts +88 -0
- package/src/Type.test.ts +20465 -0
- package/src/Type.ts +114 -111
- package/src/Types.test.ts +324 -0
- package/src/Types.ts +13 -13
- package/src/WebSocket.ts +4 -7
- package/src/Worker.test.ts +755 -0
- package/src/Worker.ts +13 -18
- package/src/index.ts +1 -1
- package/src/intl/_en.ts +1 -1
- package/src/intl/ar.ts +1 -1
- package/src/intl/bn.ts +1 -1
- package/src/intl/ca.ts +1 -1
- package/src/intl/cs.ts +1 -1
- package/src/intl/da.ts +1 -1
- package/src/intl/de.ts +1 -1
- package/src/intl/el.ts +1 -1
- package/src/intl/es.ts +1 -1
- package/src/intl/fa.ts +1 -1
- package/src/intl/fi.ts +1 -1
- package/src/intl/fil.ts +1 -1
- package/src/intl/fr.ts +1 -1
- package/src/intl/he.ts +1 -1
- package/src/intl/hi.ts +1 -1
- package/src/intl/hr.ts +1 -1
- package/src/intl/hu.ts +1 -1
- package/src/intl/id.ts +1 -1
- package/src/intl/intl.test.ts +3106 -0
- package/src/intl/it.ts +1 -1
- package/src/intl/ja.ts +1 -1
- package/src/intl/ko.ts +1 -1
- package/src/intl/ml.ts +1 -1
- package/src/intl/mr.ts +1 -1
- package/src/intl/ms.ts +1 -1
- package/src/intl/nb.ts +1 -1
- package/src/intl/nl.ts +1 -1
- package/src/intl/pa.ts +1 -1
- package/src/intl/pl.ts +1 -1
- package/src/intl/pt-BR.ts +1 -1
- package/src/intl/pt.ts +1 -1
- package/src/intl/ro.ts +1 -1
- package/src/intl/sk.ts +1 -1
- package/src/intl/sl.ts +1 -1
- package/src/intl/sv.ts +1 -1
- package/src/intl/sw.ts +1 -1
- package/src/intl/ta.ts +1 -1
- package/src/intl/te.ts +1 -1
- package/src/intl/th.ts +1 -1
- package/src/intl/tr.ts +1 -1
- package/src/intl/uk.ts +1 -1
- package/src/intl/ur.ts +1 -1
- package/src/intl/vi.ts +1 -1
- package/src/intl/zh-CN.ts +1 -1
- package/src/intl/zh-TW.ts +1 -1
- package/src/local-first/Evolu.test.ts +1921 -0
- package/src/local-first/Evolu.ts +18 -14
- package/src/local-first/Owner.test.ts +83 -0
- package/src/local-first/Protocol.test.ts +1037 -0
- package/src/local-first/Protocol.ts +58 -261
- package/src/local-first/Query.test.ts +349 -0
- package/src/local-first/Query.ts +11 -11
- package/src/local-first/Relay.ts +2 -2
- package/src/local-first/Schema.ts +3 -5
- package/src/local-first/Shared.test.ts +1828 -0
- package/src/local-first/Shared.ts +9 -8
- package/src/local-first/Storage.ts +4 -4
- package/src/local-first/Timestamp.test.ts +374 -0
- package/src/local-first/Timestamp.ts +22 -10
- package/dist/src/Buffer.d.ts.map +0 -1
package/src/Eq.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import type { Order } from "./Order.ts";
|
|
8
8
|
import { getObjectKind } from "./Object.ts";
|
|
9
|
-
import type { Data, IsData
|
|
9
|
+
import type { Data, IsData } from "./Type.ts";
|
|
10
10
|
import type { CompileTimeError } from "./Types.ts";
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -21,6 +21,13 @@ import type { CompileTimeError } from "./Types.ts";
|
|
|
21
21
|
* - **Transitive**: if `eq(a, b)` and `eq(b, c)` are `true`, then `eq(a, c)` is
|
|
22
22
|
* `true`.
|
|
23
23
|
*
|
|
24
|
+
* Evolu does not provide `eqStrict`: JavaScript strict equality (`===`) is not
|
|
25
|
+
* reflexive because `NaN === NaN` is `false`, so it cannot define an
|
|
26
|
+
* `Eq<number>`. Use `===` directly when that behavior is required. See [MDN's
|
|
27
|
+
* equality comparisons and sameness
|
|
28
|
+
* guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Equality_comparisons_and_sameness)
|
|
29
|
+
* for how JavaScript's equality algorithms differ.
|
|
30
|
+
*
|
|
24
31
|
* Use {@link eqFromOrder} to derive equality from an {@link Order}.
|
|
25
32
|
*
|
|
26
33
|
* ### Example
|
|
@@ -50,13 +57,13 @@ export type Eq<in A> = (x: A, y: A) => boolean;
|
|
|
50
57
|
* ### Example
|
|
51
58
|
*
|
|
52
59
|
* ```ts
|
|
53
|
-
* import { assertFalse, assertTrue,
|
|
60
|
+
* import { assertFalse, assertTrue, eqSameValue } from "@evolu/common";
|
|
54
61
|
*
|
|
55
|
-
* assertTrue(
|
|
56
|
-
* assertFalse(
|
|
62
|
+
* assertTrue(eqSameValue(NaN, NaN));
|
|
63
|
+
* assertFalse(eqSameValue(0, -0));
|
|
57
64
|
* ```
|
|
58
65
|
*/
|
|
59
|
-
export const
|
|
66
|
+
export const eqSameValue = <A>(x: A, y: A): boolean => Object.is(x, y);
|
|
60
67
|
|
|
61
68
|
/**
|
|
62
69
|
* Compares two values using SameValueZero equality.
|
|
@@ -78,23 +85,23 @@ export const eqStrict = <A>(x: A, y: A): boolean => Object.is(x, y);
|
|
|
78
85
|
export const eqSameValueZero = <A>(x: A, y: A): boolean =>
|
|
79
86
|
x === y || Object.is(x, y);
|
|
80
87
|
|
|
81
|
-
/** An {@link Eq} for strings using {@link
|
|
82
|
-
export const eqString: Eq<string> =
|
|
88
|
+
/** An {@link Eq} for strings using {@link eqSameValue}. */
|
|
89
|
+
export const eqString: Eq<string> = eqSameValue;
|
|
83
90
|
|
|
84
|
-
/** An {@link Eq} for numbers using {@link
|
|
85
|
-
export const eqNumber: Eq<number> =
|
|
91
|
+
/** An {@link Eq} for numbers using {@link eqSameValue}. */
|
|
92
|
+
export const eqNumber: Eq<number> = eqSameValue;
|
|
86
93
|
|
|
87
|
-
/** An {@link Eq} for bigints using {@link
|
|
88
|
-
export const eqBigInt: Eq<bigint> =
|
|
94
|
+
/** An {@link Eq} for bigints using {@link eqSameValue}. */
|
|
95
|
+
export const eqBigInt: Eq<bigint> = eqSameValue;
|
|
89
96
|
|
|
90
|
-
/** An {@link Eq} for booleans using {@link
|
|
91
|
-
export const eqBoolean: Eq<boolean> =
|
|
97
|
+
/** An {@link Eq} for booleans using {@link eqSameValue}. */
|
|
98
|
+
export const eqBoolean: Eq<boolean> = eqSameValue;
|
|
92
99
|
|
|
93
100
|
/** An {@link Eq} for `undefined`. */
|
|
94
|
-
export const eqUndefined: Eq<undefined> =
|
|
101
|
+
export const eqUndefined: Eq<undefined> = eqSameValue;
|
|
95
102
|
|
|
96
103
|
/** An {@link Eq} for `null`. */
|
|
97
|
-
export const eqNull: Eq<null> =
|
|
104
|
+
export const eqNull: Eq<null> = eqSameValue;
|
|
98
105
|
|
|
99
106
|
/** Derives an {@link Eq} from an {@link Order}. */
|
|
100
107
|
export const eqFromOrder =
|
|
@@ -139,7 +146,8 @@ export const createEqArrayLike =
|
|
|
139
146
|
};
|
|
140
147
|
|
|
141
148
|
/**
|
|
142
|
-
* Compares two array-like structures element by element using
|
|
149
|
+
* Compares two array-like structures element by element using
|
|
150
|
+
* {@link eqSameValue}.
|
|
143
151
|
*
|
|
144
152
|
* Useful for structural sharing checks where objects are compared by reference
|
|
145
153
|
* identity. `NaN` elements are equal, while `0` and `-0` elements differ.
|
|
@@ -147,15 +155,19 @@ export const createEqArrayLike =
|
|
|
147
155
|
* ### Example
|
|
148
156
|
*
|
|
149
157
|
* ```ts
|
|
150
|
-
* import {
|
|
158
|
+
* import {
|
|
159
|
+
* assertFalse,
|
|
160
|
+
* assertTrue,
|
|
161
|
+
* eqArraySameValue,
|
|
162
|
+
* } from "@evolu/common";
|
|
151
163
|
*
|
|
152
164
|
* const a = { x: 1 };
|
|
153
165
|
* const b = { x: 1 };
|
|
154
|
-
* assertTrue(
|
|
155
|
-
* assertFalse(
|
|
166
|
+
* assertTrue(eqArraySameValue([a, a], [a, a]));
|
|
167
|
+
* assertFalse(eqArraySameValue([a], [b]));
|
|
156
168
|
* ```
|
|
157
169
|
*/
|
|
158
|
-
export const
|
|
170
|
+
export const eqArraySameValue = /*#__PURE__*/ createEqArrayLike(eqSameValue);
|
|
159
171
|
|
|
160
172
|
/**
|
|
161
173
|
* Compares two array-like structures of numbers for equality.
|
|
@@ -221,17 +233,17 @@ export const createEqObject =
|
|
|
221
233
|
};
|
|
222
234
|
|
|
223
235
|
/**
|
|
224
|
-
*
|
|
236
|
+
* Deeply compares two {@link Data} values using platform-independent structural
|
|
237
|
+
* equality.
|
|
225
238
|
*
|
|
226
|
-
* Primitive values use
|
|
227
|
-
*
|
|
228
|
-
* and Maps
|
|
229
|
-
*
|
|
230
|
-
*
|
|
239
|
+
* Primitive values use `Object.is`. Arrays are ordered; plain Objects compare
|
|
240
|
+
* their own string-keyed properties regardless of property order or prototype;
|
|
241
|
+
* Sets and Maps ignore insertion order; Dates compare their time values; and
|
|
242
|
+
* Uint8Arrays compare their bytes. Cyclic and shared data graphs are
|
|
243
|
+
* supported.
|
|
231
244
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
* use the {@link Data} Type at an unknown boundary.
|
|
245
|
+
* Arguments are restricted to Data at compile time. Use the {@link Data} Type at
|
|
246
|
+
* an unknown boundary.
|
|
235
247
|
*
|
|
236
248
|
* ### Example
|
|
237
249
|
*
|
|
@@ -258,115 +270,14 @@ export function eqData<Actual, Expected>(
|
|
|
258
270
|
...dataError: EqDataError<Actual | Expected>
|
|
259
271
|
): boolean;
|
|
260
272
|
export function eqData(actual: Data, expected: Data): boolean {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
rightsByLeft: new Map(),
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Compares two {@link JsonValue} values using {@link eqData}.
|
|
269
|
-
*
|
|
270
|
-
* ### Example
|
|
271
|
-
*
|
|
272
|
-
* ```ts
|
|
273
|
-
* import { assertTrue, eqJsonValue, type JsonValue } from "@evolu/common";
|
|
274
|
-
*
|
|
275
|
-
* const first: JsonValue = { profile: { name: "Ada" } };
|
|
276
|
-
* const second: JsonValue = { profile: { name: "Ada" } };
|
|
277
|
-
*
|
|
278
|
-
* assertTrue(eqJsonValue(first, second));
|
|
279
|
-
* ```
|
|
280
|
-
*/
|
|
281
|
-
export const eqJsonValue: Eq<JsonValue> = eqData;
|
|
282
|
-
|
|
283
|
-
/** Compares two {@link JsonValueInput} values using {@link eqData}. */
|
|
284
|
-
export const eqJsonValueInput: Eq<JsonValueInput> = eqData;
|
|
285
|
-
|
|
286
|
-
type EqDataError<Value> =
|
|
287
|
-
IsData<Value> extends true
|
|
288
|
-
? []
|
|
289
|
-
: [
|
|
290
|
-
error: CompileTimeError<
|
|
291
|
-
"eqData",
|
|
292
|
-
"Actual and expected values must consist only of Data."
|
|
293
|
-
>,
|
|
294
|
-
];
|
|
295
|
-
|
|
296
|
-
interface EqDataContext {
|
|
297
|
-
readonly pairs: Array<readonly [object, object]>;
|
|
298
|
-
readonly rightsByLeft: Map<object, Set<object>>;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
interface EqDataCompareFrame {
|
|
302
|
-
readonly kind: "Compare";
|
|
303
|
-
readonly actual: Data;
|
|
304
|
-
readonly expected: Data;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
interface EqDataSetFrame {
|
|
308
|
-
readonly kind: "Set";
|
|
309
|
-
readonly actual: ReadonlyArray<Data>;
|
|
310
|
-
readonly actualIndex: number;
|
|
311
|
-
readonly unmatched: Array<Data>;
|
|
312
|
-
readonly candidateIndex: number;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
interface EqDataMapFrame {
|
|
316
|
-
readonly kind: "Map";
|
|
317
|
-
readonly actual: ReadonlyArray<readonly [Data, Data]>;
|
|
318
|
-
readonly actualIndex: number;
|
|
319
|
-
readonly unmatched: Array<readonly [Data, Data]>;
|
|
320
|
-
readonly candidateIndex: number;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
interface EqDataCommitSetFrame {
|
|
324
|
-
readonly kind: "CommitSet";
|
|
325
|
-
readonly match: EqDataSetFrame;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
interface EqDataCommitMapFrame {
|
|
329
|
-
readonly kind: "CommitMap";
|
|
330
|
-
readonly match: EqDataMapFrame;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
interface EqDataFailFrame {
|
|
334
|
-
readonly kind: "Fail";
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
type EqDataFrame =
|
|
338
|
-
| EqDataCompareFrame
|
|
339
|
-
| EqDataSetFrame
|
|
340
|
-
| EqDataMapFrame
|
|
341
|
-
| EqDataCommitSetFrame
|
|
342
|
-
| EqDataCommitMapFrame
|
|
343
|
-
| EqDataFailFrame;
|
|
344
|
-
|
|
345
|
-
type EqDataCollectionFrame = EqDataSetFrame | EqDataMapFrame;
|
|
346
|
-
|
|
347
|
-
interface EqDataCandidateAttempt {
|
|
348
|
-
readonly contextCheckpoint: number;
|
|
349
|
-
readonly frameCheckpoint: number;
|
|
350
|
-
readonly retry: EqDataCollectionFrame;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const eqDataInternal = (
|
|
354
|
-
actual: Data,
|
|
355
|
-
expected: Data,
|
|
356
|
-
context: EqDataContext,
|
|
357
|
-
): boolean => {
|
|
273
|
+
const pairs: Array<readonly [object, object]> = [];
|
|
274
|
+
const rightsByLeft = new Map<object, Set<object>>();
|
|
358
275
|
const frames: Array<EqDataFrame> = [{ kind: "Compare", actual, expected }];
|
|
359
|
-
const attempts: Array<
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
rollbackEqDataContext(context, attempt.contextCheckpoint);
|
|
366
|
-
frames.length = attempt.frameCheckpoint;
|
|
367
|
-
frames.push(attempt.retry);
|
|
368
|
-
return true;
|
|
369
|
-
};
|
|
276
|
+
const attempts: Array<{
|
|
277
|
+
readonly pairsCheckpoint: number;
|
|
278
|
+
readonly frameCheckpoint: number;
|
|
279
|
+
readonly retry: EqDataCollectionFrame;
|
|
280
|
+
}> = [];
|
|
370
281
|
|
|
371
282
|
while (frames.length > 0) {
|
|
372
283
|
const frame = frames.pop()!;
|
|
@@ -375,7 +286,7 @@ const eqDataInternal = (
|
|
|
375
286
|
const x = frame.actual;
|
|
376
287
|
const y = frame.expected;
|
|
377
288
|
|
|
378
|
-
if (
|
|
289
|
+
if (eqSameValue(x, y)) continue;
|
|
379
290
|
if (typeof x !== typeof y) {
|
|
380
291
|
frames.push({ kind: "Fail" });
|
|
381
292
|
continue;
|
|
@@ -390,14 +301,14 @@ const eqDataInternal = (
|
|
|
390
301
|
continue;
|
|
391
302
|
}
|
|
392
303
|
|
|
393
|
-
const rights =
|
|
304
|
+
const rights = rightsByLeft.get(x);
|
|
394
305
|
if (rights?.has(y)) continue;
|
|
395
306
|
if (rights === undefined) {
|
|
396
|
-
|
|
307
|
+
rightsByLeft.set(x, new Set([y]));
|
|
397
308
|
} else {
|
|
398
309
|
rights.add(y);
|
|
399
310
|
}
|
|
400
|
-
|
|
311
|
+
pairs.push([x, y]);
|
|
401
312
|
|
|
402
313
|
const xKind = getObjectKind(x);
|
|
403
314
|
const yKind = getObjectKind(y);
|
|
@@ -546,13 +457,12 @@ const eqDataInternal = (
|
|
|
546
457
|
continue;
|
|
547
458
|
}
|
|
548
459
|
|
|
549
|
-
|
|
550
|
-
|
|
460
|
+
attempts.push({
|
|
461
|
+
pairsCheckpoint: pairs.length,
|
|
551
462
|
frameCheckpoint: frames.length,
|
|
552
463
|
retry: { ...frame, candidateIndex: frame.candidateIndex + 1 },
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
frames.push({ kind: "CommitSet", match: frame });
|
|
464
|
+
});
|
|
465
|
+
frames.push({ kind: "Commit", match: frame });
|
|
556
466
|
frames.push({
|
|
557
467
|
kind: "Compare",
|
|
558
468
|
actual: frame.actual[frame.actualIndex],
|
|
@@ -571,13 +481,12 @@ const eqDataInternal = (
|
|
|
571
481
|
const [actualKey, actualValue] = frame.actual[frame.actualIndex];
|
|
572
482
|
const [expectedKey, expectedValue] =
|
|
573
483
|
frame.unmatched[frame.candidateIndex];
|
|
574
|
-
|
|
575
|
-
|
|
484
|
+
attempts.push({
|
|
485
|
+
pairsCheckpoint: pairs.length,
|
|
576
486
|
frameCheckpoint: frames.length,
|
|
577
487
|
retry: { ...frame, candidateIndex: frame.candidateIndex + 1 },
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
frames.push({ kind: "CommitMap", match: frame });
|
|
488
|
+
});
|
|
489
|
+
frames.push({ kind: "Commit", match: frame });
|
|
581
490
|
frames.push({
|
|
582
491
|
kind: "Compare",
|
|
583
492
|
actual: actualValue,
|
|
@@ -591,7 +500,7 @@ const eqDataInternal = (
|
|
|
591
500
|
continue;
|
|
592
501
|
}
|
|
593
502
|
|
|
594
|
-
if (frame.kind === "
|
|
503
|
+
if (frame.kind === "Commit") {
|
|
595
504
|
attempts.pop();
|
|
596
505
|
frame.match.unmatched.splice(frame.match.candidateIndex, 1);
|
|
597
506
|
frames.push({
|
|
@@ -602,31 +511,56 @@ const eqDataInternal = (
|
|
|
602
511
|
continue;
|
|
603
512
|
}
|
|
604
513
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
frame.match.unmatched.splice(frame.match.candidateIndex, 1);
|
|
608
|
-
frames.push({
|
|
609
|
-
...frame.match,
|
|
610
|
-
actualIndex: frame.match.actualIndex + 1,
|
|
611
|
-
candidateIndex: 0,
|
|
612
|
-
});
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
514
|
+
const attempt = attempts.pop();
|
|
515
|
+
if (attempt === undefined) return false;
|
|
615
516
|
|
|
616
|
-
|
|
517
|
+
while (pairs.length > attempt.pairsCheckpoint) {
|
|
518
|
+
const [left, right] = pairs.pop()!;
|
|
519
|
+
const rights = rightsByLeft.get(left)!;
|
|
520
|
+
rights.delete(right);
|
|
521
|
+
if (rights.size === 0) rightsByLeft.delete(left);
|
|
522
|
+
}
|
|
523
|
+
frames.length = attempt.frameCheckpoint;
|
|
524
|
+
frames.push(attempt.retry);
|
|
617
525
|
}
|
|
618
526
|
|
|
619
527
|
return true;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
type EqDataError<Value> =
|
|
531
|
+
IsData<Value> extends true
|
|
532
|
+
? []
|
|
533
|
+
: [
|
|
534
|
+
error: CompileTimeError<
|
|
535
|
+
"eqData",
|
|
536
|
+
"Actual and expected values must consist only of Data."
|
|
537
|
+
>,
|
|
538
|
+
];
|
|
539
|
+
|
|
540
|
+
interface EqDataSetFrame {
|
|
541
|
+
readonly kind: "Set";
|
|
542
|
+
readonly actual: ReadonlyArray<Data>;
|
|
543
|
+
readonly actualIndex: number;
|
|
544
|
+
readonly unmatched: Array<Data>;
|
|
545
|
+
readonly candidateIndex: number;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
interface EqDataMapFrame {
|
|
549
|
+
readonly kind: "Map";
|
|
550
|
+
readonly actual: ReadonlyArray<readonly [Data, Data]>;
|
|
551
|
+
readonly actualIndex: number;
|
|
552
|
+
readonly unmatched: Array<readonly [Data, Data]>;
|
|
553
|
+
readonly candidateIndex: number;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
type EqDataCollectionFrame = EqDataSetFrame | EqDataMapFrame;
|
|
557
|
+
|
|
558
|
+
type EqDataFrame =
|
|
559
|
+
| {
|
|
560
|
+
readonly kind: "Compare";
|
|
561
|
+
readonly actual: Data;
|
|
562
|
+
readonly expected: Data;
|
|
563
|
+
}
|
|
564
|
+
| EqDataCollectionFrame
|
|
565
|
+
| { readonly kind: "Commit"; readonly match: EqDataCollectionFrame }
|
|
566
|
+
| { readonly kind: "Fail" };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import { assertEqual, assertFalse, assertSame, assertTrue } from "./Assert.ts";
|
|
3
|
+
|
|
4
|
+
import { UnknownError, createUnknownError } from "./Error.ts";
|
|
5
|
+
import { assertType, Object, String } from "./Type.ts";
|
|
6
|
+
|
|
7
|
+
describe("createUnknownError", () => {
|
|
8
|
+
it("UnknownError validates unknown error values", () => {
|
|
9
|
+
const result = createUnknownError("boom");
|
|
10
|
+
|
|
11
|
+
assertTrue(UnknownError.is(result));
|
|
12
|
+
assertFalse(UnknownError.is({ type: "OtherError", error: "boom" }));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("handles plain error", () => {
|
|
16
|
+
const error = new Error("Test error");
|
|
17
|
+
const result = createUnknownError(error);
|
|
18
|
+
|
|
19
|
+
assertEqual(result.type, "UnknownError");
|
|
20
|
+
|
|
21
|
+
assertType(Object, result.error);
|
|
22
|
+
const details = result.error;
|
|
23
|
+
assertEqual(details.message, "Test error");
|
|
24
|
+
assertType(String, details.stack);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("handles error with cause", () => {
|
|
28
|
+
const innerError = new Error("Inner error");
|
|
29
|
+
const error = new Error("Outer error", { cause: innerError });
|
|
30
|
+
const result = createUnknownError(error);
|
|
31
|
+
|
|
32
|
+
assertEqual(result.type, "UnknownError");
|
|
33
|
+
assertType(Object, result.error);
|
|
34
|
+
const details = result.error;
|
|
35
|
+
assertEqual(details.message, "Outer error");
|
|
36
|
+
assertType(String, details.stack);
|
|
37
|
+
assertType(Object, details.cause);
|
|
38
|
+
const cause = details.cause;
|
|
39
|
+
assertEqual(cause.message, "Inner error");
|
|
40
|
+
assertType(String, cause.stack);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("handles inherited stack getter", () => {
|
|
44
|
+
const prototype: object = globalThis.Object.create(Error.prototype, {
|
|
45
|
+
stack: { get: () => "Inherited stack" },
|
|
46
|
+
});
|
|
47
|
+
const error = globalThis.Object.create(prototype) as Error;
|
|
48
|
+
globalThis.Object.defineProperty(error, "message", {
|
|
49
|
+
value: "Test error",
|
|
50
|
+
});
|
|
51
|
+
const result = createUnknownError(error);
|
|
52
|
+
|
|
53
|
+
assertType(Object, result.error);
|
|
54
|
+
const details = result.error;
|
|
55
|
+
assertEqual(details.message, "Test error");
|
|
56
|
+
assertEqual(details.stack, "Inherited stack");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("excludes non-clonable error properties", () => {
|
|
60
|
+
const error = globalThis.Object.assign(new Error("Test error"), {
|
|
61
|
+
nonClonable: () => undefined,
|
|
62
|
+
});
|
|
63
|
+
const result = createUnknownError(error);
|
|
64
|
+
|
|
65
|
+
assertEqual(result.type, "UnknownError");
|
|
66
|
+
assertType(Object, result.error);
|
|
67
|
+
assertFalse("nonClonable" in result.error);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("handles structured cloneable objects", () => {
|
|
71
|
+
const error = { key: "value" };
|
|
72
|
+
const result = createUnknownError(error);
|
|
73
|
+
|
|
74
|
+
assertEqual(result.type, "UnknownError");
|
|
75
|
+
assertEqual(result.error, { key: "value" });
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("handles non-cloneable objects", () => {
|
|
79
|
+
const error = {
|
|
80
|
+
toString: () => {
|
|
81
|
+
throw new Error("Cannot stringify");
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
const result = createUnknownError(error);
|
|
85
|
+
|
|
86
|
+
assertEqual(result.type, "UnknownError");
|
|
87
|
+
assertEqual(result.error, "[Unserializable Object]");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("handles primitive values", () => {
|
|
91
|
+
const error = "A simple string";
|
|
92
|
+
const result = createUnknownError(error);
|
|
93
|
+
|
|
94
|
+
assertEqual(result.type, "UnknownError");
|
|
95
|
+
assertEqual(result.error, "A simple string");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("handles null values", () => {
|
|
99
|
+
const result = createUnknownError(null);
|
|
100
|
+
|
|
101
|
+
assertEqual(result.type, "UnknownError");
|
|
102
|
+
assertSame(result.error, null);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("handles circular references", () => {
|
|
106
|
+
interface Circular {
|
|
107
|
+
self?: Circular;
|
|
108
|
+
}
|
|
109
|
+
const error: Circular = {};
|
|
110
|
+
// Create a circular reference
|
|
111
|
+
error.self = error;
|
|
112
|
+
const result = createUnknownError(error);
|
|
113
|
+
|
|
114
|
+
assertEqual(result.type, "UnknownError");
|
|
115
|
+
const actual = result.error as Circular;
|
|
116
|
+
assertSame(actual.self, actual);
|
|
117
|
+
});
|
|
118
|
+
});
|