@evolu/common 8.0.0-next.4 → 8.0.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 +279 -173
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +105 -101
- package/dist/src/Assert.d.ts +44 -44
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +44 -32
- package/dist/src/BigInt.d.ts +6 -3
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -2
- package/dist/src/Brand.d.ts +27 -40
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Buffer.d.ts +27 -11
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Cache.d.ts +9 -4
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +8 -3
- package/dist/src/Callbacks.d.ts +30 -19
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Console.d.ts +145 -66
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +91 -43
- package/dist/src/Crypto.d.ts +85 -42
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +44 -20
- package/dist/src/Eq.d.ts +87 -21
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +67 -19
- package/dist/src/Error.d.ts +5 -3
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +16 -0
- package/dist/src/Function.d.ts +119 -58
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +86 -43
- package/dist/src/Http.d.ts +394 -0
- package/dist/src/Http.d.ts.map +1 -0
- package/dist/src/Http.js +102 -0
- package/dist/src/Identicon.d.ts +16 -7
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +14 -5
- package/dist/src/LeakDetector.d.ts +88 -0
- package/dist/src/LeakDetector.d.ts.map +1 -0
- package/dist/src/LeakDetector.js +86 -0
- package/dist/src/LockManager.d.ts +18 -9
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/LockManager.js +7 -8
- package/dist/src/Lookup.d.ts +43 -13
- package/dist/src/Lookup.d.ts.map +1 -1
- package/dist/src/Lookup.js +28 -8
- package/dist/src/Microtask.d.ts +1 -1
- package/dist/src/Microtask.d.ts.map +1 -1
- package/dist/src/Microtask.js +3 -7
- package/dist/src/Number.d.ts +49 -13
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +34 -5
- package/dist/src/Object.d.ts +160 -40
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +92 -46
- package/dist/src/Option.d.ts +10 -7
- package/dist/src/Option.d.ts.map +1 -1
- package/dist/src/Option.js +9 -6
- package/dist/src/Order.d.ts +21 -21
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +18 -21
- package/dist/src/Platform.d.ts +31 -0
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +98 -0
- package/dist/src/Random.d.ts +32 -17
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +12 -8
- package/dist/src/Redacted.d.ts +43 -29
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +14 -3
- package/dist/src/Ref.d.ts +11 -3
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +2 -2
- package/dist/src/RefCount.d.ts +2 -6
- package/dist/src/RefCount.d.ts.map +1 -1
- package/dist/src/RefCount.js +33 -90
- package/dist/src/Relation.d.ts +70 -5
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +77 -2
- package/dist/src/Resource.d.ts +590 -155
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +592 -343
- package/dist/src/Result.d.ts +838 -191
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +163 -102
- package/dist/src/Schedule.d.ts +684 -231
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +766 -295
- package/dist/src/Set.d.ts +89 -40
- package/dist/src/Set.d.ts.map +1 -1
- package/dist/src/Set.js +50 -29
- package/dist/src/Sqlite.d.ts +29 -72
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +41 -46
- package/dist/src/StackTrace.d.ts +40 -0
- package/dist/src/StackTrace.d.ts.map +1 -0
- package/dist/src/StackTrace.js +140 -0
- package/dist/src/Store.d.ts +5 -4
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +5 -4
- package/dist/src/String.d.ts +7 -1
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +20 -7
- package/dist/src/Task.d.ts +3572 -1770
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1879 -1274
- package/dist/src/Test.d.ts +17 -125
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +17 -68
- package/dist/src/Time.d.ts +108 -49
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +172 -73
- package/dist/src/Type.d.ts +3542 -1926
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +3070 -1784
- package/dist/src/Types.d.ts +200 -108
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +39 -8
- package/dist/src/WebSocket.d.ts +48 -23
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +15 -6
- package/dist/src/Worker.d.ts +94 -36
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +58 -24
- package/dist/src/index.d.ts +55 -52
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/intl/cs.d.ts +94 -0
- package/dist/src/intl/cs.d.ts.map +1 -0
- package/dist/src/intl/cs.js +220 -0
- package/dist/src/intl/index.d.ts +7 -0
- package/dist/src/intl/index.d.ts.map +1 -0
- package/dist/src/intl/index.js +6 -0
- package/dist/src/local-first/Db.d.ts +12 -8
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +109 -132
- package/dist/src/local-first/Error.d.ts +4 -4
- package/dist/src/local-first/Evolu.d.ts +338 -92
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +47 -55
- package/dist/src/local-first/LocalAuth.d.ts +4 -4
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/Owner.d.ts +61 -24
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +45 -8
- package/dist/src/local-first/Protocol.d.ts +44 -31
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +36 -13
- package/dist/src/local-first/Query.d.ts +147 -62
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +112 -58
- package/dist/src/local-first/Relay.d.ts +44 -14
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Schema.d.ts +92 -41
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +25 -8
- package/dist/src/local-first/Shared.d.ts +23 -21
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +100 -57
- package/dist/src/local-first/Storage.d.ts +53 -32
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +194 -234
- package/dist/src/local-first/Timestamp.d.ts +21 -21
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +2 -2
- package/dist/src/local-first/index.d.ts +11 -11
- package/package.json +14 -13
- package/src/Array.ts +306 -205
- package/src/Assert.ts +54 -69
- package/src/BigInt.ts +6 -3
- package/src/Brand.ts +27 -40
- package/src/Buffer.ts +28 -12
- package/src/Cache.ts +9 -4
- package/src/Callbacks.ts +30 -19
- package/src/Console.ts +156 -84
- package/src/Crypto.ts +83 -41
- package/src/Eq.ts +95 -22
- package/src/Error.ts +8 -4
- package/src/Function.ts +167 -59
- package/src/Http.ts +549 -0
- package/src/Identicon.ts +16 -7
- package/src/LeakDetector.ts +182 -0
- package/src/LockManager.ts +43 -39
- package/src/Lookup.ts +62 -28
- package/src/Microtask.ts +19 -23
- package/src/Number.ts +64 -12
- package/src/Object.ts +173 -49
- package/src/Option.ts +10 -7
- package/src/Order.ts +23 -21
- package/src/Platform.ts +136 -0
- package/src/Polyfills.ts +6 -12
- package/src/Random.ts +32 -19
- package/src/Redacted.ts +44 -30
- package/src/Ref.ts +14 -6
- package/src/RefCount.ts +38 -80
- package/src/Relation.ts +202 -10
- package/src/Resource.ts +1199 -591
- package/src/Result.ts +930 -271
- package/src/Schedule.ts +859 -343
- package/src/Set.ts +89 -40
- package/src/Sqlite.ts +144 -138
- package/src/StackTrace.ts +230 -0
- package/src/Store.ts +8 -7
- package/src/String.ts +22 -5
- package/src/Task.ts +5101 -2832
- package/src/Test.ts +20 -168
- package/src/Time.ts +293 -90
- package/src/Type.ts +10034 -4117
- package/src/Types.ts +227 -110
- package/src/WebSocket.ts +64 -36
- package/src/Worker.ts +180 -72
- package/src/index.ts +55 -52
- package/src/intl/cs.ts +388 -0
- package/src/intl/index.ts +7 -0
- package/src/local-first/Db.ts +152 -179
- package/src/local-first/Error.ts +4 -4
- package/src/local-first/Evolu.ts +495 -250
- package/src/local-first/LocalAuth.ts +6 -12
- package/src/local-first/Owner.ts +58 -21
- package/src/local-first/Protocol.ts +49 -31
- package/src/local-first/Query.ts +146 -61
- package/src/local-first/Relay.ts +51 -21
- package/src/local-first/Schema.ts +109 -51
- package/src/local-first/Shared.ts +266 -226
- package/src/local-first/Storage.ts +266 -264
- package/src/local-first/Timestamp.ts +25 -18
- package/src/local-first/index.ts +11 -11
- package/dist/src/Skiplist.d.ts +0 -28
- package/dist/src/Skiplist.d.ts.map +0 -1
- package/dist/src/Skiplist.js +0 -64
- package/dist/src/Tracer.d.ts +0 -48
- package/dist/src/Tracer.d.ts.map +0 -1
- package/dist/src/Tracer.js +0 -6
- package/src/Skiplist.ts +0 -108
- package/src/Tracer.ts +0 -54
package/src/Eq.ts
CHANGED
|
@@ -4,30 +4,85 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { Order } from "./Order.
|
|
7
|
+
import type { Order } from "./Order.ts";
|
|
8
8
|
import type {
|
|
9
9
|
JsonArray,
|
|
10
10
|
JsonObject,
|
|
11
11
|
JsonValue,
|
|
12
12
|
JsonValueInput,
|
|
13
|
-
} from "./Type.
|
|
13
|
+
} from "./Type.ts";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Compares two values of the same type `A` for equality.
|
|
17
17
|
*
|
|
18
18
|
* Equality functions start with an 'eq' prefix, e.g., `eqString`.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* An `Eq` must define an equivalence relation over its intended domain:
|
|
21
|
+
*
|
|
22
|
+
* - **Reflexive**: `eq(a, a)` is `true`.
|
|
23
|
+
* - **Symmetric**: `eq(a, b)` equals `eq(b, a)`.
|
|
24
|
+
* - **Transitive**: if `eq(a, b)` and `eq(b, c)` are `true`, then `eq(a, c)` is
|
|
25
|
+
* `true`.
|
|
26
|
+
*
|
|
27
|
+
* Use {@link eqFromOrder} to derive equality from an {@link Order}.
|
|
28
|
+
*
|
|
29
|
+
* ### Example
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { createEqObject, eqNumber } from "@evolu/common";
|
|
33
|
+
*
|
|
34
|
+
* const eqPoint = createEqObject({ x: eqNumber, y: eqNumber });
|
|
35
|
+
*
|
|
36
|
+
* expect(eqPoint({ x: 1, y: 2 }, { x: 1, y: 2 })).toBe(true);
|
|
37
|
+
* expect(eqPoint({ x: 1, y: 2 }, { x: 2, y: 1 })).toBe(false);
|
|
38
|
+
* ```
|
|
21
39
|
*/
|
|
22
40
|
export type Eq<in A> = (x: A, y: A) => boolean;
|
|
23
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Compares two values with strict equality (`===`).
|
|
44
|
+
*
|
|
45
|
+
* Strict equality considers `NaN` unequal to itself. Use {@link eqSameValueZero}
|
|
46
|
+
* when values can contain `NaN` and equality must be reflexive.
|
|
47
|
+
*/
|
|
24
48
|
export const eqStrict = <A>(x: A, y: A): boolean => x === y;
|
|
25
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Compares two values using SameValueZero equality.
|
|
52
|
+
*
|
|
53
|
+
* SameValueZero is the standard equality algorithm used by `Map`, `Set`, and
|
|
54
|
+
* `Array.prototype.includes`. It behaves like strict equality except that `NaN`
|
|
55
|
+
* equals itself. Both algorithms consider `0` and `-0` equal.
|
|
56
|
+
*
|
|
57
|
+
* ### Example
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { eqSameValueZero } from "@evolu/common";
|
|
61
|
+
*
|
|
62
|
+
* expect(eqSameValueZero(NaN, NaN)).toBe(true);
|
|
63
|
+
* expect(eqSameValueZero(0, -0)).toBe(true);
|
|
64
|
+
* expect(eqSameValueZero({}, {})).toBe(false);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export const eqSameValueZero = <A>(x: A, y: A): boolean =>
|
|
68
|
+
x === y || Object.is(x, y);
|
|
69
|
+
|
|
70
|
+
/** An {@link Eq} for strings using strict equality. */
|
|
26
71
|
export const eqString: Eq<string> = eqStrict;
|
|
27
|
-
|
|
72
|
+
|
|
73
|
+
/** An {@link Eq} for numbers using {@link eqSameValueZero}. */
|
|
74
|
+
export const eqNumber: Eq<number> = eqSameValueZero;
|
|
75
|
+
|
|
76
|
+
/** An {@link Eq} for bigints using strict equality. */
|
|
28
77
|
export const eqBigInt: Eq<bigint> = eqStrict;
|
|
78
|
+
|
|
79
|
+
/** An {@link Eq} for booleans using strict equality. */
|
|
29
80
|
export const eqBoolean: Eq<boolean> = eqStrict;
|
|
81
|
+
|
|
82
|
+
/** An {@link Eq} for `undefined`. */
|
|
30
83
|
export const eqUndefined: Eq<undefined> = eqStrict;
|
|
84
|
+
|
|
85
|
+
/** An {@link Eq} for `null`. */
|
|
31
86
|
export const eqNull: Eq<null> = eqStrict;
|
|
32
87
|
|
|
33
88
|
/** Derives an {@link Eq} from an {@link Order}. */
|
|
@@ -43,10 +98,15 @@ export const eqFromOrder =
|
|
|
43
98
|
* ### Example
|
|
44
99
|
*
|
|
45
100
|
* ```ts
|
|
101
|
+
* import { createEqArrayLike, eqNumber } from "@evolu/common";
|
|
102
|
+
*
|
|
46
103
|
* const eqArrayNumber = createEqArrayLike(eqNumber);
|
|
47
|
-
*
|
|
48
|
-
* eqArrayNumber(
|
|
49
|
-
*
|
|
104
|
+
*
|
|
105
|
+
* expect(eqArrayNumber([1, 2, 3], [1, 2, 3])).toBe(true);
|
|
106
|
+
* expect(
|
|
107
|
+
* eqArrayNumber(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3])),
|
|
108
|
+
* ).toBe(true);
|
|
109
|
+
* expect(eqArrayNumber([1, 2, 3], [1, 2, 4])).toBe(false);
|
|
50
110
|
* ```
|
|
51
111
|
*/
|
|
52
112
|
export const createEqArrayLike =
|
|
@@ -70,10 +130,12 @@ export const createEqArrayLike =
|
|
|
70
130
|
* ### Example
|
|
71
131
|
*
|
|
72
132
|
* ```ts
|
|
133
|
+
* import { eqArrayStrict } from "@evolu/common";
|
|
134
|
+
*
|
|
73
135
|
* const a = { x: 1 };
|
|
74
136
|
* const b = { x: 1 };
|
|
75
|
-
* eqArrayStrict([a, a], [a, a])
|
|
76
|
-
* eqArrayStrict([a], [b])
|
|
137
|
+
* expect(eqArrayStrict([a, a], [a, a])).toBe(true);
|
|
138
|
+
* expect(eqArrayStrict([a], [b])).toBe(false);
|
|
77
139
|
* ```
|
|
78
140
|
*/
|
|
79
141
|
export const eqArrayStrict = /*#__PURE__*/ createEqArrayLike(eqStrict);
|
|
@@ -84,9 +146,9 @@ export const eqArrayStrict = /*#__PURE__*/ createEqArrayLike(eqStrict);
|
|
|
84
146
|
* ### Example
|
|
85
147
|
*
|
|
86
148
|
* ```ts
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* eqArrayNumber([1,
|
|
149
|
+
* import { eqArrayNumber } from "@evolu/common";
|
|
150
|
+
*
|
|
151
|
+
* expect(eqArrayNumber([1, NaN], [1, NaN])).toBe(true);
|
|
90
152
|
* ```
|
|
91
153
|
*/
|
|
92
154
|
export const eqArrayNumber = /*#__PURE__*/ createEqArrayLike(eqNumber);
|
|
@@ -98,9 +160,12 @@ export const eqArrayNumber = /*#__PURE__*/ createEqArrayLike(eqNumber);
|
|
|
98
160
|
* ### Example
|
|
99
161
|
*
|
|
100
162
|
* ```ts
|
|
163
|
+
* import { createEqObject, eqNumber } from "@evolu/common";
|
|
164
|
+
*
|
|
101
165
|
* const eqObjectNumber = createEqObject({ a: eqNumber });
|
|
102
|
-
*
|
|
103
|
-
* eqObjectNumber({ a: 1 }, { a:
|
|
166
|
+
*
|
|
167
|
+
* expect(eqObjectNumber({ a: 1 }, { a: 1 })).toBe(true);
|
|
168
|
+
* expect(eqObjectNumber({ a: 1 }, { a: 2 })).toBe(false);
|
|
104
169
|
* ```
|
|
105
170
|
*/
|
|
106
171
|
export const createEqObject =
|
|
@@ -122,7 +187,8 @@ export const createEqObject =
|
|
|
122
187
|
*
|
|
123
188
|
* - Uses an iterative approach with a stack to handle large or deeply nested
|
|
124
189
|
* objects without risking stack overflow.
|
|
125
|
-
* -
|
|
190
|
+
* - Defensively handles circular references in runtime values without looping,
|
|
191
|
+
* although cyclic values are not valid JSON.
|
|
126
192
|
* - Unlike JSON.stringify, this function directly compares values, avoiding
|
|
127
193
|
* serialization overhead and leveraging short-circuit evaluation for faster
|
|
128
194
|
* failure on mismatched structures.
|
|
@@ -130,9 +196,12 @@ export const createEqObject =
|
|
|
130
196
|
* ### Example
|
|
131
197
|
*
|
|
132
198
|
* ```ts
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
199
|
+
* import { eqJsonValue, type JsonValue } from "@evolu/common";
|
|
200
|
+
*
|
|
201
|
+
* const first: JsonValue = { profile: { name: "Ada" } };
|
|
202
|
+
* const second: JsonValue = { profile: { name: "Ada" } };
|
|
203
|
+
*
|
|
204
|
+
* expect(eqJsonValue(first, second)).toBe(true);
|
|
136
205
|
* ```
|
|
137
206
|
*/
|
|
138
207
|
export const eqJsonValue = (a: JsonValue, b: JsonValue): boolean => {
|
|
@@ -212,7 +281,8 @@ export const eqJsonValue = (a: JsonValue, b: JsonValue): boolean => {
|
|
|
212
281
|
*
|
|
213
282
|
* - Uses an iterative approach with a stack to handle large or deeply nested
|
|
214
283
|
* objects without risking stack overflow.
|
|
215
|
-
* -
|
|
284
|
+
* - Defensively handles circular references in runtime values without looping,
|
|
285
|
+
* although cyclic values are not valid JSON.
|
|
216
286
|
* - Unlike JSON.stringify, this function directly compares values, avoiding
|
|
217
287
|
* serialization overhead and leveraging short-circuit evaluation for faster
|
|
218
288
|
* failure on mismatched structures.
|
|
@@ -220,9 +290,12 @@ export const eqJsonValue = (a: JsonValue, b: JsonValue): boolean => {
|
|
|
220
290
|
* ### Example
|
|
221
291
|
*
|
|
222
292
|
* ```ts
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
293
|
+
* import { eqJsonValueInput, type JsonValueInput } from "@evolu/common";
|
|
294
|
+
*
|
|
295
|
+
* const first: JsonValueInput = { profile: { name: "Ada" } };
|
|
296
|
+
* const second: JsonValueInput = { profile: { name: "Ada" } };
|
|
297
|
+
*
|
|
298
|
+
* expect(eqJsonValueInput(first, second)).toBe(true);
|
|
226
299
|
* ```
|
|
227
300
|
*/
|
|
228
301
|
export const eqJsonValueInput = (
|
package/src/Error.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type
|
|
7
|
+
import { type InferType, typed, type TypedType, Unknown } from "./Type.ts";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* A wrapper for unknown errors caught at runtime.
|
|
@@ -18,9 +18,13 @@ import type { Typed } from "./Type.js";
|
|
|
18
18
|
*
|
|
19
19
|
* Use {@link createUnknownError} to create instances.
|
|
20
20
|
*/
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
}
|
|
21
|
+
export const UnknownError: TypedType<
|
|
22
|
+
"UnknownError",
|
|
23
|
+
{ readonly error: typeof Unknown }
|
|
24
|
+
> = /*#__PURE__*/ typed("UnknownError", {
|
|
25
|
+
error: Unknown,
|
|
26
|
+
});
|
|
27
|
+
export interface UnknownError extends InferType<typeof UnknownError> {}
|
|
24
28
|
|
|
25
29
|
/**
|
|
26
30
|
* Creates an {@link UnknownError} from an unknown error.
|
package/src/Function.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { assertNotDisposed } from "./Assert.ts";
|
|
8
|
+
import { isFunction } from "./Object.ts";
|
|
9
|
+
import type { Writable } from "./Types.ts";
|
|
10
|
+
|
|
7
11
|
/**
|
|
8
12
|
* Helper function to ensure exhaustive matching in a switch statement. Throws
|
|
9
13
|
* an error if an unhandled case is encountered.
|
|
@@ -11,32 +15,36 @@
|
|
|
11
15
|
* ### Example
|
|
12
16
|
*
|
|
13
17
|
* ```ts
|
|
18
|
+
* import { exhaustiveCheck } from "@evolu/common";
|
|
19
|
+
*
|
|
14
20
|
* type Color = "red" | "green" | "blue";
|
|
21
|
+
* const handled: Array<string> = [];
|
|
15
22
|
*
|
|
16
23
|
* const handleColor = (color: Color): void => {
|
|
17
24
|
* switch (color) {
|
|
18
25
|
* case "red":
|
|
19
|
-
*
|
|
26
|
+
* handled.push("Handling red");
|
|
20
27
|
* break;
|
|
21
28
|
* case "green":
|
|
22
|
-
*
|
|
29
|
+
* handled.push("Handling green");
|
|
23
30
|
* break;
|
|
24
31
|
* case "blue":
|
|
25
|
-
*
|
|
32
|
+
* handled.push("Handling blue");
|
|
26
33
|
* break;
|
|
27
34
|
* default:
|
|
28
|
-
* exhaustiveCheck(color);
|
|
35
|
+
* exhaustiveCheck(color);
|
|
29
36
|
* }
|
|
30
37
|
* };
|
|
38
|
+
*
|
|
39
|
+
* handleColor("blue");
|
|
40
|
+
* expect(handled).toEqual(["Handling blue"]);
|
|
31
41
|
* ```
|
|
32
42
|
*
|
|
33
43
|
* Use this primarily in side-effect switches (`void` branches). For
|
|
34
44
|
* value-producing switches, TypeScript can enforce exhaustiveness without a
|
|
35
|
-
* `default` branch.
|
|
36
|
-
*
|
|
37
|
-
* ### Example
|
|
45
|
+
* `default` branch in either of the following styles.
|
|
38
46
|
*
|
|
39
|
-
* Return from
|
|
47
|
+
* ### Return from every case
|
|
40
48
|
*
|
|
41
49
|
* ```ts
|
|
42
50
|
* type Color = "red" | "green" | "blue";
|
|
@@ -51,11 +59,11 @@
|
|
|
51
59
|
* return "#0000ff";
|
|
52
60
|
* }
|
|
53
61
|
* };
|
|
54
|
-
* ```
|
|
55
62
|
*
|
|
56
|
-
*
|
|
63
|
+
* expect(colorToHex("green")).toBe("#00ff00");
|
|
64
|
+
* ```
|
|
57
65
|
*
|
|
58
|
-
*
|
|
66
|
+
* ### Assign in every case
|
|
59
67
|
*
|
|
60
68
|
* ```ts
|
|
61
69
|
* type Input =
|
|
@@ -63,7 +71,7 @@
|
|
|
63
71
|
* | { readonly type: "Query" }
|
|
64
72
|
* | { readonly type: "Export" };
|
|
65
73
|
*
|
|
66
|
-
* const
|
|
74
|
+
* const inputToKind = (input: Input): "A" | "B" | "C" => {
|
|
67
75
|
* let result: "A" | "B" | "C";
|
|
68
76
|
*
|
|
69
77
|
* switch (input.type) {
|
|
@@ -78,12 +86,10 @@
|
|
|
78
86
|
* break;
|
|
79
87
|
* }
|
|
80
88
|
*
|
|
81
|
-
*
|
|
89
|
+
* return result;
|
|
82
90
|
* };
|
|
83
91
|
*
|
|
84
|
-
*
|
|
85
|
-
* console.log(kind);
|
|
86
|
-
* };
|
|
92
|
+
* expect(inputToKind({ type: "Query" })).toBe("B");
|
|
87
93
|
* ```
|
|
88
94
|
*/
|
|
89
95
|
export const exhaustiveCheck = (value: never): never => {
|
|
@@ -99,81 +105,181 @@ export const exhaustiveCheck = (value: never): never => {
|
|
|
99
105
|
* ### Example
|
|
100
106
|
*
|
|
101
107
|
* ```ts
|
|
102
|
-
*
|
|
103
|
-
* const same = values.map(identity); // [1, 2, 3]
|
|
108
|
+
* import { identity } from "@evolu/common";
|
|
104
109
|
*
|
|
110
|
+
* const values = [1, 2, 3];
|
|
111
|
+
* const object = { value: 1 };
|
|
105
112
|
* const getTransform = (shouldDouble: boolean) =>
|
|
106
|
-
* shouldDouble ? (
|
|
113
|
+
* shouldDouble ? (value: number) => value * 2 : identity;
|
|
114
|
+
*
|
|
115
|
+
* expect(values.map(identity)).toEqual([1, 2, 3]);
|
|
116
|
+
* expect(identity(object)).toBe(object);
|
|
117
|
+
* expect(getTransform(false)(2)).toBe(2);
|
|
107
118
|
* ```
|
|
108
119
|
*/
|
|
109
120
|
export const identity = <A>(a: A): A => a;
|
|
110
121
|
|
|
111
122
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
123
|
+
* Creates an object that follows JavaScript disposal semantics.
|
|
124
|
+
*
|
|
125
|
+
* The first argument is the object to make disposable. The returned object gets
|
|
126
|
+
* a disposal method and its functions are wrapped with a disposal guard. This
|
|
127
|
+
* is the JavaScript equivalent of .NET `ObjectDisposedException`: once an
|
|
128
|
+
* object has been disposed, calling its methods is a programmer error and
|
|
129
|
+
* should throw immediately instead of continuing with invalid state. Evolu
|
|
130
|
+
* asserts this invariant with the "Cannot use a disposed object." message.
|
|
131
|
+
*
|
|
132
|
+
* The second argument is an optional disposer. When provided, it is
|
|
133
|
+
* [moved](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DisposableStack/move)
|
|
134
|
+
* into the returned object, and the returned object's disposal method disposes
|
|
135
|
+
* it. Omit it when the object has no cleanup resources but still must become
|
|
136
|
+
* unusable after disposal, such as with reference count helpers where disposal
|
|
137
|
+
* enforces correct ownership tracking.
|
|
138
|
+
*
|
|
139
|
+
* ### Example
|
|
140
|
+
*
|
|
141
|
+
* ```ts
|
|
142
|
+
* import { disposable } from "@evolu/common";
|
|
143
|
+
*
|
|
144
|
+
* let cleaned = false;
|
|
145
|
+
* const createResource = () => {
|
|
146
|
+
* using disposer = new DisposableStack();
|
|
147
|
+
* disposer.defer(() => {
|
|
148
|
+
* cleaned = true;
|
|
149
|
+
* });
|
|
150
|
+
* return disposable({ read: () => "ready" }, disposer);
|
|
151
|
+
* };
|
|
152
|
+
*
|
|
153
|
+
* const resource = createResource();
|
|
154
|
+
* expect(resource.read()).toBe("ready");
|
|
155
|
+
* resource[Symbol.dispose]();
|
|
156
|
+
*
|
|
157
|
+
* expect(cleaned).toBe(true);
|
|
158
|
+
* expect(() => resource.read()).toThrow("Cannot use a disposed object.");
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export function disposable<T extends object>(
|
|
162
|
+
value: T extends Disposable ? Omit<T, typeof Symbol.dispose> : T,
|
|
163
|
+
disposer?: DisposableStack,
|
|
164
|
+
): T extends Disposable ? T : T & Disposable;
|
|
165
|
+
export function disposable<T extends object>(
|
|
166
|
+
value: T extends AsyncDisposable ? Omit<T, typeof Symbol.asyncDispose> : T,
|
|
167
|
+
disposer: AsyncDisposableStack,
|
|
168
|
+
): T extends AsyncDisposable ? T : T & AsyncDisposable;
|
|
169
|
+
export function disposable<T extends object>(
|
|
170
|
+
value: T,
|
|
171
|
+
disposer: DisposableStack | AsyncDisposableStack | null = null,
|
|
172
|
+
): T & (Disposable | AsyncDisposable) {
|
|
173
|
+
const mutableValue = value as Writable<Record<string, unknown>>;
|
|
174
|
+
const ownedDisposer = disposer?.move() ?? new DisposableStack();
|
|
175
|
+
|
|
176
|
+
for (const [key, property] of Object.entries(value)) {
|
|
177
|
+
if (!isFunction(property)) continue;
|
|
178
|
+
|
|
179
|
+
mutableValue[key] = (...args: Array<unknown>): unknown => {
|
|
180
|
+
assertNotDisposed(ownedDisposer);
|
|
181
|
+
return (property as (...args: Array<unknown>) => unknown)(...args);
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (ownedDisposer instanceof AsyncDisposableStack) {
|
|
186
|
+
(value as T & AsyncDisposable)[Symbol.asyncDispose] = () =>
|
|
187
|
+
ownedDisposer.disposeAsync();
|
|
188
|
+
} else {
|
|
189
|
+
(value as T & Disposable)[Symbol.dispose] = () => ownedDisposer.dispose();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return value as T & (Disposable | AsyncDisposable);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export const isDisposable = (
|
|
196
|
+
value: unknown,
|
|
197
|
+
): value is Disposable | AsyncDisposable => {
|
|
198
|
+
if (typeof value !== "object" || value === null) return false;
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
isFunction((value as Partial<Disposable>)[Symbol.dispose]) ||
|
|
202
|
+
isFunction((value as Partial<AsyncDisposable>)[Symbol.asyncDispose])
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A function that takes no arguments and returns a value.
|
|
114
208
|
*
|
|
115
209
|
* Useful for:
|
|
116
210
|
*
|
|
117
|
-
* - Providing default callbacks (see {@link
|
|
211
|
+
* - Providing default callbacks (see {@link constVoid}, {@link constTrue}, etc.)
|
|
118
212
|
* - Delaying expensive operations until actually needed
|
|
119
213
|
* - Deferring side effects so the callee controls when they run
|
|
120
214
|
*
|
|
121
215
|
* ### Example
|
|
122
216
|
*
|
|
123
217
|
* ```ts
|
|
124
|
-
*
|
|
125
|
-
* const notify = (onDone: Lazy<void> = lazyVoid) => {
|
|
126
|
-
* onDone();
|
|
127
|
-
* };
|
|
218
|
+
* import { constVoid, type Thunk } from "@evolu/common";
|
|
128
219
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* const data = getData();
|
|
220
|
+
* const notify = (onDone: Thunk<void> = constVoid) => onDone();
|
|
221
|
+
* notify();
|
|
132
222
|
*
|
|
133
|
-
*
|
|
134
|
-
* const
|
|
135
|
-
*
|
|
223
|
+
* let value = 0;
|
|
224
|
+
* const compute: Thunk<number> = () => ++value;
|
|
225
|
+
* const jobs: Array<Thunk<void>> = [];
|
|
226
|
+
* const schedule = (job: Thunk<void>): void => {
|
|
227
|
+
* jobs.push(job);
|
|
136
228
|
* };
|
|
137
|
-
* schedule(() =>
|
|
229
|
+
* schedule(() => {
|
|
230
|
+
* value += 10;
|
|
231
|
+
* });
|
|
232
|
+
*
|
|
233
|
+
* const computed = compute();
|
|
234
|
+
* jobs.shift()?.();
|
|
235
|
+
* expect(computed).toBe(1);
|
|
236
|
+
* expect(value).toBe(11);
|
|
138
237
|
* ```
|
|
139
238
|
*/
|
|
140
|
-
export type
|
|
239
|
+
export type Thunk<T> = () => T;
|
|
141
240
|
|
|
142
241
|
/**
|
|
143
|
-
* Creates a {@link
|
|
242
|
+
* Creates a {@link Thunk} that always returns a precomputed value.
|
|
144
243
|
*
|
|
145
|
-
* Use when the value is expensive to compute and want to compute it once at
|
|
244
|
+
* Use when the value is expensive to compute and you want to compute it once at
|
|
146
245
|
* definition time rather than on every call.
|
|
147
246
|
*
|
|
148
247
|
* ### Example
|
|
149
248
|
*
|
|
150
249
|
* ```ts
|
|
151
|
-
*
|
|
152
|
-
*
|
|
250
|
+
* import { constant } from "@evolu/common";
|
|
251
|
+
*
|
|
252
|
+
* let version = 0;
|
|
253
|
+
* const readConfig = () => ({ version: ++version });
|
|
254
|
+
* const getConstantConfig = constant(readConfig());
|
|
255
|
+
* const getFreshConfig = () => readConfig();
|
|
153
256
|
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
257
|
+
* expect(getConstantConfig()).toBe(getConstantConfig());
|
|
258
|
+
* expect(getConstantConfig().version).toBe(1);
|
|
259
|
+
* expect(getFreshConfig().version).toBe(2);
|
|
260
|
+
* expect(getFreshConfig().version).toBe(3);
|
|
156
261
|
* ```
|
|
157
262
|
*/
|
|
158
|
-
export const
|
|
159
|
-
<T>(value: T):
|
|
263
|
+
export const constant =
|
|
264
|
+
<T>(value: T): Thunk<T> =>
|
|
160
265
|
() =>
|
|
161
266
|
value;
|
|
162
267
|
|
|
163
|
-
/** A {@link
|
|
164
|
-
export const
|
|
268
|
+
/** A {@link Thunk} that returns `true`. */
|
|
269
|
+
export const constTrue: Thunk<true> = /*#__PURE__*/ constant(true);
|
|
165
270
|
|
|
166
|
-
/** A {@link
|
|
167
|
-
export const
|
|
271
|
+
/** A {@link Thunk} that returns `false`. */
|
|
272
|
+
export const constFalse: Thunk<false> = /*#__PURE__*/ constant(false);
|
|
168
273
|
|
|
169
|
-
/** A {@link
|
|
170
|
-
export const
|
|
274
|
+
/** A {@link Thunk} that returns `null`. */
|
|
275
|
+
export const constNull: Thunk<null> = /*#__PURE__*/ constant(null);
|
|
171
276
|
|
|
172
|
-
/** A {@link
|
|
173
|
-
export const
|
|
277
|
+
/** A {@link Thunk} that returns `undefined`. */
|
|
278
|
+
export const constUndefined: Thunk<undefined> =
|
|
279
|
+
/*#__PURE__*/ constant(undefined);
|
|
174
280
|
|
|
175
|
-
/** A {@link
|
|
176
|
-
export const
|
|
281
|
+
/** A {@link Thunk} that returns `undefined` for void callbacks. */
|
|
282
|
+
export const constVoid: Thunk<void> = constUndefined;
|
|
177
283
|
|
|
178
284
|
/**
|
|
179
285
|
* Development placeholder that always throws.
|
|
@@ -185,17 +291,19 @@ export const lazyVoid: Lazy<void> = lazyUndefined;
|
|
|
185
291
|
* ### Example
|
|
186
292
|
*
|
|
187
293
|
* ```ts
|
|
188
|
-
*
|
|
189
|
-
* const fetchUser = (id: UserId): Result<User, FetchError> => todo();
|
|
294
|
+
* import { todo } from "@evolu/common";
|
|
190
295
|
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
296
|
+
* interface Config {
|
|
297
|
+
* readonly theme: string;
|
|
298
|
+
* }
|
|
194
299
|
*
|
|
195
|
-
*
|
|
300
|
+
* const getCount = (): number => todo();
|
|
196
301
|
* const getConfig = () => todo<Config>();
|
|
197
302
|
*
|
|
198
|
-
* expectTypeOf
|
|
303
|
+
* expectTypeOf<
|
|
304
|
+
* [ReturnType<typeof getCount>, ReturnType<typeof getConfig>]
|
|
305
|
+
* >().toEqualTypeOf<[number, Config]>();
|
|
306
|
+
* expect(getCount).toThrow("not yet implemented");
|
|
199
307
|
* ```
|
|
200
308
|
*/
|
|
201
309
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|