@evolu/common 7.0.0 → 7.2.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/README.md +26 -28
- package/dist/src/Array.d.ts +120 -43
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +71 -51
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Brand.d.ts +1 -1
- package/dist/src/Cache.d.ts +1 -6
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +1 -6
- package/dist/src/Console.d.ts +1 -1
- package/dist/src/Console.js +1 -1
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +5 -1
- package/dist/src/Evolu/Internal.d.ts +2 -2
- package/dist/src/Evolu/Internal.js +2 -2
- package/dist/src/Evolu/Public.d.ts +1 -1
- package/dist/src/Evolu/Public.js +1 -1
- package/dist/src/Order.d.ts +0 -5
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +0 -5
- package/dist/src/Platform.d.ts +0 -5
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +0 -5
- package/dist/src/Random.d.ts +0 -5
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +0 -5
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Result.d.ts +15 -17
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Store.d.ts +0 -5
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +0 -5
- package/dist/src/Task.d.ts +4 -10
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +0 -5
- package/dist/src/Time.d.ts +0 -5
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +0 -5
- package/dist/src/Type.d.ts +3 -3
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1 -1
- package/dist/src/Types.d.ts +37 -0
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/WebSocket.d.ts +0 -5
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +0 -5
- package/dist/src/Worker.d.ts +0 -5
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +0 -5
- package/package.json +1 -1
- package/src/Array.ts +157 -45
- package/src/Assert.ts +0 -14
- package/src/Brand.ts +1 -1
- package/src/Cache.ts +1 -7
- package/src/Console.ts +1 -1
- package/src/Crypto.ts +5 -1
- package/src/Evolu/Internal.ts +2 -2
- package/src/Evolu/Public.ts +1 -1
- package/src/Order.ts +0 -6
- package/src/Platform.ts +0 -6
- package/src/Random.ts +0 -6
- package/src/Ref.ts +0 -5
- package/src/Result.ts +15 -17
- package/src/Store.ts +0 -5
- package/src/Task.ts +4 -11
- package/src/Time.ts +0 -6
- package/src/Type.ts +3 -3
- package/src/Types.ts +42 -0
- package/src/WebSocket.ts +0 -6
- package/src/Worker.ts +0 -6
package/src/Array.ts
CHANGED
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Array types, type guards, operations, transformations, accessors, and (rare)
|
|
3
|
+
* mutations
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* ### Example
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* // Types - compile-time guarantee of at least one element
|
|
9
|
+
* const _valid: NonEmptyReadonlyArray<number> = [1, 2, 3];
|
|
10
|
+
* // ts-expect-error - empty array is not a valid NonEmptyReadonlyArray
|
|
11
|
+
* const _invalid: NonEmptyReadonlyArray<number> = [];
|
|
12
|
+
*
|
|
13
|
+
* // Type guards
|
|
14
|
+
* const arr: ReadonlyArray<number> = [1, 2, 3];
|
|
15
|
+
* if (isNonEmptyReadonlyArray(arr)) {
|
|
16
|
+
* firstInArray(arr);
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* // Operations
|
|
20
|
+
* const appended = appendToArray([1, 2, 3], 4); // [1, 2, 3, 4]
|
|
21
|
+
* const prepended = prependToArray([2, 3], 1); // [1, 2, 3]
|
|
22
|
+
*
|
|
23
|
+
* // Transformations
|
|
24
|
+
* const readonly: ReadonlyArray<number> = [1, 2, 3];
|
|
25
|
+
* const mapped = mapArray(readonly, (x) => x * 2); // [2, 4, 6]
|
|
26
|
+
* const filtered = filterArray(readonly, (x) => x > 1); // [2, 3]
|
|
27
|
+
* const deduped = dedupeArray([1, 2, 1, 3, 2]); // [1, 2, 3]
|
|
28
|
+
* const [evens, odds] = partitionArray(
|
|
29
|
+
* [1, 2, 3, 4, 5],
|
|
30
|
+
* (x) => x % 2 === 0,
|
|
31
|
+
* ); // [[2, 4], [1, 3, 5]]
|
|
32
|
+
*
|
|
33
|
+
* // Accessors
|
|
34
|
+
* const first = firstInArray(["a", "b", "c"]); // "a"
|
|
35
|
+
* const last = lastInArray(["a", "b", "c"]); // "c"
|
|
36
|
+
*
|
|
37
|
+
* // Mutations
|
|
38
|
+
* const mutable: NonEmptyArray<number> = [1, 2, 3];
|
|
39
|
+
* shiftArray(mutable); // 1 (guaranteed to exist)
|
|
40
|
+
* mutable; // [2, 3]
|
|
41
|
+
* ```
|
|
6
42
|
*
|
|
7
43
|
* Functions are intentionally data-first to be prepared for the upcoming
|
|
8
44
|
* JavaScript pipe operator.
|
|
@@ -43,43 +79,11 @@
|
|
|
43
79
|
* **Note**: Feel free to use Array instance methods (mutation) if you think
|
|
44
80
|
* it's better (performance, local scope, etc.).
|
|
45
81
|
*
|
|
46
|
-
* ### Example
|
|
47
|
-
*
|
|
48
|
-
* ```ts
|
|
49
|
-
* // Types - compile-time guarantee of at least one element
|
|
50
|
-
* const _valid: NonEmptyReadonlyArray<number> = [1, 2, 3];
|
|
51
|
-
* // ts-expect-error - empty array is not a valid NonEmptyReadonlyArray
|
|
52
|
-
* const _invalid: NonEmptyReadonlyArray<number> = [];
|
|
53
|
-
*
|
|
54
|
-
* // Guards
|
|
55
|
-
* const arr: ReadonlyArray<number> = [1, 2, 3];
|
|
56
|
-
* if (isNonEmptyReadonlyArray(arr)) {
|
|
57
|
-
* firstInArray(arr);
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* // Operations
|
|
61
|
-
* const appended = appendToArray([1, 2, 3], 4); // [1, 2, 3, 4]
|
|
62
|
-
* const prepended = prependToArray([2, 3], 1); // [1, 2, 3]
|
|
63
|
-
*
|
|
64
|
-
* // Transformations
|
|
65
|
-
* const readonly: ReadonlyArray<number> = [1, 2, 3];
|
|
66
|
-
* const mapped = mapArray(readonly, (x) => x * 2); // [2, 4, 6]
|
|
67
|
-
* const filtered = filterArray(readonly, (x) => x > 1); // [2, 3]
|
|
68
|
-
* const deduped = dedupeArray([1, 2, 1, 3, 2]); // [1, 2, 3]
|
|
69
|
-
*
|
|
70
|
-
* // Accessors
|
|
71
|
-
* const first = firstInArray(["a", "b", "c"]); // "a"
|
|
72
|
-
* const last = lastInArray(["a", "b", "c"]); // "c"
|
|
73
|
-
*
|
|
74
|
-
* // Mutations
|
|
75
|
-
* const mutable: NonEmptyArray<number> = [1, 2, 3];
|
|
76
|
-
* shiftArray(mutable); // 1 (guaranteed to exist)
|
|
77
|
-
* mutable; // [2, 3]
|
|
78
|
-
* ```
|
|
79
|
-
*
|
|
80
82
|
* @module
|
|
81
83
|
*/
|
|
82
84
|
|
|
85
|
+
import { PredicateWithIndex, RefinementWithIndex } from "./Types.js";
|
|
86
|
+
|
|
83
87
|
/**
|
|
84
88
|
* An array with at least one element.
|
|
85
89
|
*
|
|
@@ -175,8 +179,7 @@ export const prependToArray = <T>(
|
|
|
175
179
|
/**
|
|
176
180
|
* Maps an array using a mapper function.
|
|
177
181
|
*
|
|
178
|
-
* Accepts both mutable and readonly arrays.
|
|
179
|
-
* Preserves non-empty type.
|
|
182
|
+
* Accepts both mutable and readonly arrays. Preserves non-empty type.
|
|
180
183
|
*
|
|
181
184
|
* ### Example
|
|
182
185
|
*
|
|
@@ -202,22 +205,49 @@ export function mapArray<T, U>(
|
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
/**
|
|
205
|
-
* Filters an array using a predicate function, returning a new
|
|
208
|
+
* Filters an array using a predicate or refinement function, returning a new
|
|
209
|
+
* readonly array.
|
|
206
210
|
*
|
|
207
|
-
* Accepts both mutable and readonly arrays.
|
|
211
|
+
* Accepts both mutable and readonly arrays. When used with a refinement
|
|
212
|
+
* function (with `value is Type` syntax), TypeScript will narrow the result
|
|
213
|
+
* type to the narrowed type, making it useful for filtering with Evolu Types
|
|
214
|
+
* like `PositiveInt.is`.
|
|
208
215
|
*
|
|
209
|
-
* ###
|
|
216
|
+
* ### Examples
|
|
217
|
+
*
|
|
218
|
+
* #### With predicate
|
|
210
219
|
*
|
|
211
220
|
* ```ts
|
|
212
221
|
* filterArray([1, 2, 3, 4, 5], (x) => x % 2 === 0); // [2, 4]
|
|
213
222
|
* ```
|
|
214
223
|
*
|
|
224
|
+
* #### With refinement
|
|
225
|
+
*
|
|
226
|
+
* ```ts
|
|
227
|
+
* const mixed: ReadonlyArray<NonEmptyString | PositiveInt> = [
|
|
228
|
+
* NonEmptyString.orThrow("hello"),
|
|
229
|
+
* PositiveInt.orThrow(42),
|
|
230
|
+
* ];
|
|
231
|
+
* const positiveInts = filterArray(mixed, PositiveInt.is);
|
|
232
|
+
* // positiveInts: ReadonlyArray<PositiveInt> (narrowed type)
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
215
235
|
* @category Transformations
|
|
216
236
|
*/
|
|
217
|
-
export
|
|
237
|
+
export function filterArray<T, S extends T>(
|
|
238
|
+
array: ReadonlyArray<T>,
|
|
239
|
+
refinement: RefinementWithIndex<T, S>,
|
|
240
|
+
): ReadonlyArray<S>;
|
|
241
|
+
export function filterArray<T>(
|
|
242
|
+
array: ReadonlyArray<T>,
|
|
243
|
+
predicate: PredicateWithIndex<T>,
|
|
244
|
+
): ReadonlyArray<T>;
|
|
245
|
+
export function filterArray<T>(
|
|
218
246
|
array: ReadonlyArray<T>,
|
|
219
|
-
predicate:
|
|
220
|
-
): ReadonlyArray<T>
|
|
247
|
+
predicate: PredicateWithIndex<T>,
|
|
248
|
+
): ReadonlyArray<T> {
|
|
249
|
+
return array.filter(predicate) as ReadonlyArray<T>;
|
|
250
|
+
}
|
|
221
251
|
|
|
222
252
|
/**
|
|
223
253
|
* Returns a new readonly array with duplicate items removed. If `by` is
|
|
@@ -272,6 +302,71 @@ export function dedupeArray<T>(
|
|
|
272
302
|
}) as ReadonlyArray<T>;
|
|
273
303
|
}
|
|
274
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Partitions an array into two arrays based on a predicate or refinement
|
|
307
|
+
* function.
|
|
308
|
+
*
|
|
309
|
+
* Returns a tuple where the first array contains elements that satisfy the
|
|
310
|
+
* predicate, and the second array contains elements that do not. Accepts both
|
|
311
|
+
* mutable and readonly arrays.
|
|
312
|
+
*
|
|
313
|
+
* When used with a refinement function (with `value is Type` syntax),
|
|
314
|
+
* TypeScript will narrow the first array to the narrowed type, making it useful
|
|
315
|
+
* for filtering with Evolu Types like `PositiveInt.is`.
|
|
316
|
+
*
|
|
317
|
+
* ### Examples
|
|
318
|
+
*
|
|
319
|
+
* #### With predicate
|
|
320
|
+
*
|
|
321
|
+
* ```ts
|
|
322
|
+
* const [evens, odds] = partitionArray(
|
|
323
|
+
* [1, 2, 3, 4, 5],
|
|
324
|
+
* (x) => x % 2 === 0,
|
|
325
|
+
* );
|
|
326
|
+
* evens; // [2, 4]
|
|
327
|
+
* odds; // [1, 3, 5]
|
|
328
|
+
* ```
|
|
329
|
+
*
|
|
330
|
+
* #### With refinement
|
|
331
|
+
*
|
|
332
|
+
* ```ts
|
|
333
|
+
* const mixed: ReadonlyArray<NonEmptyString | PositiveInt> = [
|
|
334
|
+
* NonEmptyString.orThrow("hello"),
|
|
335
|
+
* PositiveInt.orThrow(42),
|
|
336
|
+
* ];
|
|
337
|
+
* const [positiveInts, strings] = partitionArray(mixed, PositiveInt.is);
|
|
338
|
+
* // positiveInts: ReadonlyArray<PositiveInt> (narrowed type)
|
|
339
|
+
* // strings: ReadonlyArray<NonEmptyString> (Exclude<T, PositiveInt>)
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* @category Transformations
|
|
343
|
+
*/
|
|
344
|
+
export function partitionArray<T, S extends T>(
|
|
345
|
+
array: ReadonlyArray<T>,
|
|
346
|
+
refinement: RefinementWithIndex<T, S>,
|
|
347
|
+
): readonly [ReadonlyArray<S>, ReadonlyArray<Exclude<T, S>>];
|
|
348
|
+
export function partitionArray<T>(
|
|
349
|
+
array: ReadonlyArray<T>,
|
|
350
|
+
predicate: PredicateWithIndex<T>,
|
|
351
|
+
): readonly [ReadonlyArray<T>, ReadonlyArray<T>];
|
|
352
|
+
export function partitionArray<T>(
|
|
353
|
+
array: ReadonlyArray<T>,
|
|
354
|
+
predicate: PredicateWithIndex<T>,
|
|
355
|
+
): readonly [ReadonlyArray<T>, ReadonlyArray<T>] {
|
|
356
|
+
const trueArray: Array<T> = [];
|
|
357
|
+
const falseArray: Array<T> = [];
|
|
358
|
+
|
|
359
|
+
for (let i = 0; i < array.length; i++) {
|
|
360
|
+
if (predicate(array[i], i)) {
|
|
361
|
+
trueArray.push(array[i]);
|
|
362
|
+
} else {
|
|
363
|
+
falseArray.push(array[i]);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return [trueArray as ReadonlyArray<T>, falseArray as ReadonlyArray<T>];
|
|
368
|
+
}
|
|
369
|
+
|
|
275
370
|
/**
|
|
276
371
|
* Returns the first element of a non-empty array.
|
|
277
372
|
*
|
|
@@ -319,3 +414,20 @@ export const lastInArray = <T>(array: NonEmptyReadonlyArray<T>): T =>
|
|
|
319
414
|
* @category Mutations
|
|
320
415
|
*/
|
|
321
416
|
export const shiftArray = <T>(array: NonEmptyArray<T>): T => array.shift() as T;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Pops an item from a non-empty mutable array, guaranteed to return T.
|
|
420
|
+
*
|
|
421
|
+
* **Mutates** the original array.
|
|
422
|
+
*
|
|
423
|
+
* ### Example
|
|
424
|
+
*
|
|
425
|
+
* ```ts
|
|
426
|
+
* const arr: NonEmptyArray<number> = [1, 2, 3];
|
|
427
|
+
* popArray(arr); // 3
|
|
428
|
+
* arr; // [1, 2]
|
|
429
|
+
* ```
|
|
430
|
+
*
|
|
431
|
+
* @category Mutations
|
|
432
|
+
*/
|
|
433
|
+
export const popArray = <T>(array: NonEmptyArray<T>): T => array.pop() as T;
|
package/src/Assert.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🚨
|
|
3
|
-
*
|
|
4
|
-
* This module provides assertion utilities to prevent invalid states from
|
|
5
|
-
* propagating through the system by halting execution when a condition fails,
|
|
6
|
-
* improving reliability and debuggability.
|
|
7
|
-
*
|
|
8
|
-
* **Warning**: Do not use this instead of {@link Type}. Assertions are intended
|
|
9
|
-
* for conditions that are logically guaranteed but not statically known by
|
|
10
|
-
* TypeScript, or for catching and signaling developer mistakes eagerly (e.g.,
|
|
11
|
-
* invalid configuration).
|
|
12
|
-
*
|
|
13
|
-
* @module
|
|
14
|
-
*/
|
|
15
1
|
import type { Type } from "./Type.js";
|
|
16
2
|
|
|
17
3
|
/**
|
package/src/Brand.ts
CHANGED
package/src/Cache.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🗄️ Generic cache interface and LRU cache implementation.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { PositiveInt } from "./Type.js";
|
|
8
2
|
|
|
9
3
|
/**
|
|
@@ -32,7 +26,7 @@ export interface Cache<K, V> {
|
|
|
32
26
|
}
|
|
33
27
|
|
|
34
28
|
/**
|
|
35
|
-
* Creates
|
|
29
|
+
* Creates an LRU (least recently used) cache with a maximum capacity.
|
|
36
30
|
*
|
|
37
31
|
* When the cache reaches capacity, the least recently used entry is evicted.
|
|
38
32
|
* Both `get` and `set` operations update the access order.
|
package/src/Console.ts
CHANGED
package/src/Crypto.ts
CHANGED
package/src/Evolu/Internal.ts
CHANGED
package/src/Evolu/Public.ts
CHANGED
package/src/Order.ts
CHANGED
package/src/Platform.ts
CHANGED
package/src/Random.ts
CHANGED
package/src/Ref.ts
CHANGED
package/src/Result.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 🛡️ Type-safe errors
|
|
3
|
-
*
|
|
4
2
|
* The problem with throwing an exception in JavaScript is that the caught error
|
|
5
3
|
* is always of an unknown type. The unknown type is a problem because we can't
|
|
6
4
|
* be sure all errors have been handled because the TypeScript compiler can't
|
|
7
5
|
* tell us.
|
|
8
6
|
*
|
|
9
|
-
* Languages like Rust
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* Languages like Rust or Haskell use a type-safe approach to error handling,
|
|
8
|
+
* where errors are explicitly represented as part of the return type, such as
|
|
9
|
+
* Result or Either, allowing the developer to handle errors safely. TypeScript
|
|
10
|
+
* can have this too via the `Result` type.
|
|
13
11
|
*
|
|
14
12
|
* The `Result` type can be either {@link Ok} (success) or {@link Err} (error).
|
|
15
13
|
* Use {@link ok} to create a successful result and {@link err} to create an error
|
|
@@ -63,7 +61,7 @@
|
|
|
63
61
|
* - For safe code, use `ok` and `err`.
|
|
64
62
|
* - For unsafe code, use `trySync` or `tryAsync`.
|
|
65
63
|
*
|
|
66
|
-
*
|
|
64
|
+
* Safe asynchronous code (using Result with a Promise):
|
|
67
65
|
*
|
|
68
66
|
* ```ts
|
|
69
67
|
* const fetchUser = async (
|
|
@@ -84,7 +82,7 @@
|
|
|
84
82
|
* };
|
|
85
83
|
* ```
|
|
86
84
|
*
|
|
87
|
-
* ### Naming
|
|
85
|
+
* ### Naming convention
|
|
88
86
|
*
|
|
89
87
|
* - For values: `const user = getUser()`
|
|
90
88
|
* - For a single void operation: `const result = foo()`
|
|
@@ -117,7 +115,7 @@
|
|
|
117
115
|
*
|
|
118
116
|
* ### Examples
|
|
119
117
|
*
|
|
120
|
-
* #### Sequential
|
|
118
|
+
* #### Sequential operations with short-circuiting
|
|
121
119
|
*
|
|
122
120
|
* When performing a sequence of operations where any failure should stop
|
|
123
121
|
* further processing, use the `Result` type with early returns.
|
|
@@ -181,7 +179,7 @@
|
|
|
181
179
|
* };
|
|
182
180
|
* ```
|
|
183
181
|
*
|
|
184
|
-
* ### Handling
|
|
182
|
+
* ### Handling unexpected errors
|
|
185
183
|
*
|
|
186
184
|
* Even with disciplined use of `trySync` and `tryAsync`, unexpected errors can
|
|
187
185
|
* still occur due to programming mistakes, third-party library bugs, or edge
|
|
@@ -192,7 +190,7 @@
|
|
|
192
190
|
* expected errors handled via the `Result` type. Unexpected errors should fail
|
|
193
191
|
* fast - the operation fails immediately and the error bubbles up.
|
|
194
192
|
*
|
|
195
|
-
* #### In
|
|
193
|
+
* #### In browser environments
|
|
196
194
|
*
|
|
197
195
|
* ```ts
|
|
198
196
|
* // Global error handler for unexpected errors
|
|
@@ -209,7 +207,7 @@
|
|
|
209
207
|
* });
|
|
210
208
|
* ```
|
|
211
209
|
*
|
|
212
|
-
* #### In Node.js
|
|
210
|
+
* #### In Node.js environments
|
|
213
211
|
*
|
|
214
212
|
* ```ts
|
|
215
213
|
* // Handle uncaught exceptions - log and fail fast
|
|
@@ -347,16 +345,16 @@ export interface Ok<T> {
|
|
|
347
345
|
* An error {@link Result}.
|
|
348
346
|
*
|
|
349
347
|
* The `error` property can be any type that describes the error. For normal
|
|
350
|
-
*
|
|
348
|
+
* domain logic, use a plain object. This allows us to structure errors with
|
|
351
349
|
* custom fields (e.g., `{ type: "MyError", code: 123 }`). Messages for users
|
|
352
350
|
* belong to translations, not to error objects.
|
|
353
351
|
*
|
|
354
|
-
* If you need a
|
|
352
|
+
* If you need a stack trace for debugging, use an `Error` instance or a custom
|
|
355
353
|
* error class to include additional metadata.
|
|
356
354
|
*
|
|
357
355
|
* ### Examples
|
|
358
356
|
*
|
|
359
|
-
* ####
|
|
357
|
+
* #### Domain logic error (plain object, recommended)
|
|
360
358
|
*
|
|
361
359
|
* ```ts
|
|
362
360
|
* const failure = err({
|
|
@@ -366,13 +364,13 @@ export interface Ok<T> {
|
|
|
366
364
|
* });
|
|
367
365
|
* ```
|
|
368
366
|
*
|
|
369
|
-
* #### Debugging with
|
|
367
|
+
* #### Debugging with stack trace (error instance)
|
|
370
368
|
*
|
|
371
369
|
* ```ts
|
|
372
370
|
* const failure = err(new Error("Something went wrong"));
|
|
373
371
|
* ```
|
|
374
372
|
*
|
|
375
|
-
* #### Custom
|
|
373
|
+
* #### Custom error class
|
|
376
374
|
*
|
|
377
375
|
* ```ts
|
|
378
376
|
* class MyCustomError extends Error {
|
package/src/Store.ts
CHANGED
package/src/Task.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ⚡ Lazy, cancellable Promise that returns Result instead of throwing
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { isNonEmptyArray, shiftArray } from "./Array.js";
|
|
8
2
|
import { Result, err, ok } from "./Result.js";
|
|
9
3
|
import { Duration, durationToNonNegativeInt } from "./Time.js";
|
|
10
4
|
import { NonNegativeInt, PositiveInt } from "./Type.js";
|
|
11
5
|
|
|
12
6
|
/**
|
|
13
|
-
* `Task` is a
|
|
14
|
-
*
|
|
7
|
+
* `Task` is a function that creates and returns an optionally cancellable
|
|
8
|
+
* Promise using {@link Result}.
|
|
15
9
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* eager execution.
|
|
10
|
+
* The laziness allows safe composition, e.g. retry logic, because it prevents
|
|
11
|
+
* eager execution until the Task is actually invoked.
|
|
19
12
|
*
|
|
20
13
|
* ### Cancellation
|
|
21
14
|
*
|
package/src/Time.ts
CHANGED
package/src/Type.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Runtime types
|
|
3
3
|
*
|
|
4
4
|
* Evolu {@link Type} is like a type guard that returns typed errors (via
|
|
5
5
|
* {@link Result}) instead of throwing. We either get a safely typed value or a
|
|
@@ -213,7 +213,7 @@ import { hasNodeBuffer } from "./Platform.js";
|
|
|
213
213
|
import { err, getOrNull, getOrThrow, ok, Result, trySync } from "./Result.js";
|
|
214
214
|
import { safelyStringifyUnknownValue } from "./String.js";
|
|
215
215
|
import type { TimeDep } from "./Time.js";
|
|
216
|
-
import type { Literal, Simplify, WidenLiteral } from "./Types.js";
|
|
216
|
+
import type { Literal, Refinement, Simplify, WidenLiteral } from "./Types.js";
|
|
217
217
|
import { IntentionalNever } from "./Types.js";
|
|
218
218
|
|
|
219
219
|
export interface Type<
|
|
@@ -353,7 +353,7 @@ export interface Type<
|
|
|
353
353
|
* console.log(filteredStrings); // ["hello", "world"]
|
|
354
354
|
* ```
|
|
355
355
|
*/
|
|
356
|
-
readonly is:
|
|
356
|
+
readonly is: Refinement<unknown, T>;
|
|
357
357
|
|
|
358
358
|
readonly [EvoluTypeSymbol]: true;
|
|
359
359
|
|
package/src/Types.ts
CHANGED
|
@@ -22,6 +22,23 @@ import * as Kysely from "kysely";
|
|
|
22
22
|
*/
|
|
23
23
|
export type Predicate<T> = (value: T) => boolean;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Checks a condition on a value at a given index and returns a boolean.
|
|
27
|
+
*
|
|
28
|
+
* Useful for callbacks that need both the element and its position.
|
|
29
|
+
*
|
|
30
|
+
* ### Example
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* const isEvenIndex: PredicateWithIndex<string> = (value, index) =>
|
|
34
|
+
* index % 2 === 0;
|
|
35
|
+
*
|
|
36
|
+
* const items = ["a", "b", "c", "d"];
|
|
37
|
+
* const evenIndexItems = items.filter(isEvenIndex); // ["a", "c"]
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export type PredicateWithIndex<T> = (value: T, index: number) => boolean;
|
|
41
|
+
|
|
25
42
|
/**
|
|
26
43
|
* A type guard function that refines type `A` to a narrower type `B`.
|
|
27
44
|
*
|
|
@@ -42,6 +59,31 @@ export type Predicate<T> = (value: T) => boolean;
|
|
|
42
59
|
*/
|
|
43
60
|
export type Refinement<in A, out B extends A> = (a: A) => a is B;
|
|
44
61
|
|
|
62
|
+
/**
|
|
63
|
+
* A type guard function that refines type `A` to a narrower type `B` at a given
|
|
64
|
+
* index.
|
|
65
|
+
*
|
|
66
|
+
* Useful for callbacks that need both the element and its position while
|
|
67
|
+
* maintaining type narrowing.
|
|
68
|
+
*
|
|
69
|
+
* ### Example
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* type Item = { type: "number" | "string"; value: unknown };
|
|
73
|
+
*
|
|
74
|
+
* const isNumberItem: RefinementWithIndex<Item, Item & { type: "number" }> =
|
|
75
|
+
* (item, index): item is Item & { type: "number" } =>
|
|
76
|
+
* index > 0 && item.type === "number";
|
|
77
|
+
*
|
|
78
|
+
* const items: ReadonlyArray<Item> = [...];
|
|
79
|
+
* const [numbers, others] = partitionArray(items, isNumberItem);
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export type RefinementWithIndex<in A, out B extends A> = (
|
|
83
|
+
a: A,
|
|
84
|
+
index: number,
|
|
85
|
+
) => a is B;
|
|
86
|
+
|
|
45
87
|
/**
|
|
46
88
|
* Makes properties optional if they accept `null` as a value.
|
|
47
89
|
*
|
package/src/WebSocket.ts
CHANGED