nalloc 0.0.1 → 0.0.2
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 +124 -38
- package/build/index.cjs +12 -68
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +1 -4
- package/build/index.js +1 -3
- package/build/index.js.map +1 -1
- package/build/iter.cjs +105 -0
- package/build/iter.cjs.map +1 -0
- package/build/iter.d.ts +61 -0
- package/build/iter.js +78 -0
- package/build/iter.js.map +1 -0
- package/build/option.cjs +19 -5
- package/build/option.cjs.map +1 -1
- package/build/option.d.ts +22 -1
- package/build/option.js +14 -6
- package/build/option.js.map +1 -1
- package/build/result.cjs +125 -54
- package/build/result.cjs.map +1 -1
- package/build/result.d.ts +83 -53
- package/build/result.js +100 -38
- package/build/result.js.map +1 -1
- package/build/safe.cjs +34 -15
- package/build/safe.cjs.map +1 -1
- package/build/safe.d.ts +4 -27
- package/build/safe.js +3 -14
- package/build/safe.js.map +1 -1
- package/build/types.cjs +38 -7
- package/build/types.cjs.map +1 -1
- package/build/types.d.ts +26 -4
- package/build/types.js +23 -7
- package/build/types.js.map +1 -1
- package/build/unsafe.cjs +14 -61
- package/build/unsafe.cjs.map +1 -1
- package/build/unsafe.d.ts +2 -27
- package/build/unsafe.js +2 -9
- package/build/unsafe.js.map +1 -1
- package/package.json +13 -16
- package/src/__tests__/index.ts +42 -0
- package/src/__tests__/iter.ts +218 -0
- package/src/__tests__/option.ts +48 -19
- package/src/__tests__/result.ts +286 -91
- package/src/__tests__/result.types.ts +3 -22
- package/src/__tests__/safe.ts +9 -15
- package/src/__tests__/unsafe.ts +11 -12
- package/src/index.ts +1 -18
- package/src/iter.ts +129 -0
- package/src/option.ts +36 -7
- package/src/result.ts +216 -113
- package/src/safe.ts +5 -42
- package/src/types.ts +52 -14
- package/src/unsafe.ts +2 -47
- package/build/devtools.cjs +0 -79
- package/build/devtools.cjs.map +0 -1
- package/build/devtools.d.ts +0 -82
- package/build/devtools.js +0 -43
- package/build/devtools.js.map +0 -1
- package/build/testing.cjs +0 -111
- package/build/testing.cjs.map +0 -1
- package/build/testing.d.ts +0 -85
- package/build/testing.js +0 -81
- package/build/testing.js.map +0 -1
- package/src/__tests__/tooling.ts +0 -86
- package/src/devtools.ts +0 -97
- package/src/testing.ts +0 -159
package/src/result.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { err as ERR, isOk, isErr, isSome, isNone, NONE, optionOf } from './types.js';
|
|
2
|
-
import type { Ok, Err, Result, Option, Widen, WidenNever } from './types.js';
|
|
1
|
+
import { err as ERR, isOk, isErr, isSome, isNone, NONE, optionOf, isThenable } from './types.js';
|
|
2
|
+
import type { Ok, Err, Result, Option, Widen, WidenNever, MaybePromise } from './types.js';
|
|
3
3
|
|
|
4
4
|
export type { Ok, Err, Result };
|
|
5
5
|
export { isOk, isErr };
|
|
@@ -14,6 +14,8 @@ export { isOk, isErr };
|
|
|
14
14
|
* tryCatch(() => JSON.parse('invalid')) // Err(SyntaxError)
|
|
15
15
|
* tryCatch(() => { throw 'oops' }, e => e) // Err('oops')
|
|
16
16
|
*/
|
|
17
|
+
export function tryCatch<T>(fn: () => T): Result<T, unknown>;
|
|
18
|
+
export function tryCatch<T, E>(fn: () => T, onError: (error: unknown) => E): Result<T, E>;
|
|
17
19
|
export function tryCatch<T, E = unknown>(fn: () => T, onError?: (error: unknown) => E): Result<T, E> {
|
|
18
20
|
try {
|
|
19
21
|
return fn() as Ok<T>;
|
|
@@ -27,52 +29,37 @@ export function tryCatch<T, E = unknown>(fn: () => T, onError?: (error: unknown)
|
|
|
27
29
|
* @param fn - Function to execute
|
|
28
30
|
* @returns Ok(result) if successful, Err(error) if thrown
|
|
29
31
|
*/
|
|
30
|
-
export function of<T
|
|
32
|
+
export function of<T>(fn: () => T): Result<T, unknown> {
|
|
31
33
|
return tryCatch(fn);
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
|
-
* Executes
|
|
36
|
-
* @param fn -
|
|
37
|
+
* Executes a function that may return sync or async, preserving sync execution when possible.
|
|
38
|
+
* @param fn - Function that may return T or Promise<T>
|
|
37
39
|
* @param onError - Optional error transformer
|
|
38
|
-
* @returns
|
|
40
|
+
* @returns Result<T, E> if sync, Promise<Result<T, E>> if async
|
|
39
41
|
* @example
|
|
40
|
-
*
|
|
42
|
+
* tryCatchMaybePromise(() => 42) // Ok(42) - sync
|
|
43
|
+
* tryCatchMaybePromise(() => Promise.resolve(42)) // Promise<Ok(42)> - async
|
|
44
|
+
* tryCatchMaybePromise(() => { throw 'err' }) // Err('err') - sync
|
|
41
45
|
*/
|
|
42
|
-
export
|
|
46
|
+
export function tryCatchMaybePromise<T>(fn: () => MaybePromise<T>): Result<T, unknown> | Promise<Result<T, unknown>>;
|
|
47
|
+
export function tryCatchMaybePromise<T, E>(fn: () => MaybePromise<T>, onError: (error: unknown) => E): Result<T, E> | Promise<Result<T, E>>;
|
|
48
|
+
export function tryCatchMaybePromise<T, E = unknown>(fn: () => MaybePromise<T>, onError?: (error: unknown) => E): Result<T, E> | Promise<Result<T, E>> {
|
|
43
49
|
try {
|
|
44
|
-
|
|
50
|
+
const result = fn();
|
|
51
|
+
if (isThenable(result)) {
|
|
52
|
+
return Promise.resolve(result).then(
|
|
53
|
+
(value) => value as Ok<T>,
|
|
54
|
+
(error) => ERR(onError ? onError(error) : (error as E)),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return result as Ok<T>;
|
|
45
58
|
} catch (error) {
|
|
46
59
|
return ERR(onError ? onError(error) : (error as E));
|
|
47
60
|
}
|
|
48
61
|
}
|
|
49
62
|
|
|
50
|
-
/**
|
|
51
|
-
* Alias for tryAsync. Executes an async function and captures the result or error.
|
|
52
|
-
* @param fn - Async function to execute
|
|
53
|
-
* @returns Promise of Ok(result) if successful, Err(error) if rejected
|
|
54
|
-
*/
|
|
55
|
-
export function ofAsync<T, E = unknown>(fn: () => Promise<T>): Promise<Result<T, E>> {
|
|
56
|
-
return tryAsync(fn);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Converts a Promise to a Result.
|
|
61
|
-
* @param promise - The promise to convert
|
|
62
|
-
* @param onRejected - Optional rejection handler
|
|
63
|
-
* @returns Promise of Ok(value) if resolved, Err(error) if rejected
|
|
64
|
-
* @example
|
|
65
|
-
* await fromPromise(Promise.resolve(42)) // Ok(42)
|
|
66
|
-
* await fromPromise(Promise.reject('error')) // Err('error')
|
|
67
|
-
*/
|
|
68
|
-
export async function fromPromise<T, E = unknown>(promise: Promise<T>, onRejected?: (reason: unknown) => E): Promise<Result<T, E>> {
|
|
69
|
-
try {
|
|
70
|
-
return (await promise) as Ok<T>;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
return ERR(onRejected ? onRejected(error) : (error as E));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
63
|
/**
|
|
77
64
|
* Unwraps an Ok value or returns a computed value for Err.
|
|
78
65
|
* @param result - The Result to unwrap
|
|
@@ -97,7 +84,7 @@ export function unwrapOrReturn<T, E, const R>(result: Result<T, E>, onErr: (erro
|
|
|
97
84
|
*/
|
|
98
85
|
export function assertOk<T, E>(result: Result<T, E>, message?: string): asserts result is Ok<T> {
|
|
99
86
|
if (isErr(result)) {
|
|
100
|
-
throw new Error(message ?? `Expected Ok result. Received error: ${String(
|
|
87
|
+
throw new Error(message ?? `Expected Ok result. Received error: ${String(result.error)}`);
|
|
101
88
|
}
|
|
102
89
|
}
|
|
103
90
|
|
|
@@ -122,7 +109,7 @@ export function assertErr<T, E>(result: Result<T, E>, message?: string): asserts
|
|
|
122
109
|
* @returns true if Err with Some error value
|
|
123
110
|
*/
|
|
124
111
|
export function isSomeErr<T, E>(result: Result<T, E>): boolean {
|
|
125
|
-
return isErr(result) && isSome(
|
|
112
|
+
return isErr(result) && isSome(result.error);
|
|
126
113
|
}
|
|
127
114
|
|
|
128
115
|
/**
|
|
@@ -138,8 +125,8 @@ export function map<T, U, E>(result: Err<E>, fn: (value: T) => U): Err<E>;
|
|
|
138
125
|
export function map<T, U>(result: Ok<T>, fn: (value: T) => U): Ok<U>;
|
|
139
126
|
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
|
|
140
127
|
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {
|
|
141
|
-
if (isErr(result)) return result
|
|
142
|
-
return fn(result
|
|
128
|
+
if (isErr(result)) return result;
|
|
129
|
+
return fn(result) as Ok<U>;
|
|
143
130
|
}
|
|
144
131
|
|
|
145
132
|
/**
|
|
@@ -172,8 +159,8 @@ export function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Resu
|
|
|
172
159
|
export function flatMap<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
|
|
173
160
|
export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
174
161
|
export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
|
|
175
|
-
if (isErr(result)) return result
|
|
176
|
-
return fn(result
|
|
162
|
+
if (isErr(result)) return result;
|
|
163
|
+
return fn(result);
|
|
177
164
|
}
|
|
178
165
|
|
|
179
166
|
/**
|
|
@@ -185,7 +172,7 @@ export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<
|
|
|
185
172
|
export function andThen<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
|
|
186
173
|
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
187
174
|
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
|
|
188
|
-
return
|
|
175
|
+
return isErr(result) ? result : fn(result);
|
|
189
176
|
}
|
|
190
177
|
|
|
191
178
|
/**
|
|
@@ -219,7 +206,7 @@ export function tapErr<E>(result: Err<E>, fn: (error: E) => void): Err<E>;
|
|
|
219
206
|
export function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;
|
|
220
207
|
export function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> {
|
|
221
208
|
if (isErr(result)) {
|
|
222
|
-
fn(
|
|
209
|
+
fn(result.error);
|
|
223
210
|
}
|
|
224
211
|
return result;
|
|
225
212
|
}
|
|
@@ -242,19 +229,22 @@ export function bimap<T, U, E, F>(result: Result<T, E>, okFn: (value: T) => U, e
|
|
|
242
229
|
}
|
|
243
230
|
|
|
244
231
|
/**
|
|
245
|
-
* Extracts the Ok value, throws if
|
|
232
|
+
* Extracts the Ok value, throws Err if not Ok.
|
|
233
|
+
* Use with safeTry for Rust-like ? operator ergonomics.
|
|
246
234
|
* @param result - The Result to unwrap
|
|
247
235
|
* @returns The contained Ok value
|
|
248
|
-
* @throws
|
|
236
|
+
* @throws The Err object itself
|
|
249
237
|
* @example
|
|
250
238
|
* unwrap(ok(42)) // 42
|
|
251
|
-
* unwrap(err('failed')) // throws
|
|
239
|
+
* unwrap(err('failed')) // throws Err
|
|
240
|
+
* safeTry(() => {
|
|
241
|
+
* const a = unwrap(getValue());
|
|
242
|
+
* return a + 1;
|
|
243
|
+
* });
|
|
252
244
|
*/
|
|
253
245
|
export function unwrap<T, E>(result: Result<T, E>): T {
|
|
254
|
-
if (isErr(result))
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
return result as T;
|
|
246
|
+
if (isErr(result)) throw result.error;
|
|
247
|
+
return result;
|
|
258
248
|
}
|
|
259
249
|
|
|
260
250
|
/**
|
|
@@ -339,9 +329,9 @@ export function mapOrElse<T, E, U>(result: Result<T, E>, defaultFn: () => U, fn:
|
|
|
339
329
|
*/
|
|
340
330
|
export function expect<T, E>(result: Result<T, E>, message: string): T {
|
|
341
331
|
if (isErr(result)) {
|
|
342
|
-
throw new Error(`${message}: ${String(
|
|
332
|
+
throw new Error(`${message}: ${String(result.error)}`);
|
|
343
333
|
}
|
|
344
|
-
return result
|
|
334
|
+
return result;
|
|
345
335
|
}
|
|
346
336
|
|
|
347
337
|
/**
|
|
@@ -421,7 +411,7 @@ export function toOption<T, E>(result: Result<T, E>): Option<T> {
|
|
|
421
411
|
* toErrorOption(ok(42)) // None
|
|
422
412
|
*/
|
|
423
413
|
export function toErrorOption<T, E>(result: Result<T, E>): Option<E> {
|
|
424
|
-
return isErr(result) ? optionOf(
|
|
414
|
+
return isErr(result) ? optionOf(result.error) : NONE;
|
|
425
415
|
}
|
|
426
416
|
|
|
427
417
|
/**
|
|
@@ -434,9 +424,9 @@ export function toErrorOption<T, E>(result: Result<T, E>): Option<E> {
|
|
|
434
424
|
* zip(ok(1), err('e')) // Err('e')
|
|
435
425
|
*/
|
|
436
426
|
export function zip<T, U, E>(left: Result<T, E>, right: Result<U, E>): Result<[T, U], E> {
|
|
437
|
-
if (isErr(left)) return left
|
|
438
|
-
if (isErr(right)) return right
|
|
439
|
-
return [left
|
|
427
|
+
if (isErr(left)) return left;
|
|
428
|
+
if (isErr(right)) return right;
|
|
429
|
+
return [left, right] as Ok<[T, U]>;
|
|
440
430
|
}
|
|
441
431
|
|
|
442
432
|
/**
|
|
@@ -449,9 +439,9 @@ export function zip<T, U, E>(left: Result<T, E>, right: Result<U, E>): Result<[T
|
|
|
449
439
|
* zipWith(ok(2), ok(3), (a, b) => a + b) // Ok(5)
|
|
450
440
|
*/
|
|
451
441
|
export function zipWith<T, U, V, E>(left: Result<T, E>, right: Result<U, E>, fn: (left: T, right: U) => V): Result<V, E> {
|
|
452
|
-
if (isErr(left)) return left
|
|
453
|
-
if (isErr(right)) return right
|
|
454
|
-
return fn(left
|
|
442
|
+
if (isErr(left)) return left;
|
|
443
|
+
if (isErr(right)) return right;
|
|
444
|
+
return fn(left, right) as Ok<V>;
|
|
455
445
|
}
|
|
456
446
|
|
|
457
447
|
/**
|
|
@@ -503,6 +493,36 @@ export function partition<T, E>(results: Result<T, E>[]): [T[], E[]] {
|
|
|
503
493
|
return [oks, errs];
|
|
504
494
|
}
|
|
505
495
|
|
|
496
|
+
/**
|
|
497
|
+
* Extracts all Ok values from an iterable of Results.
|
|
498
|
+
* @param results - Iterable of Results
|
|
499
|
+
* @returns Array of Ok values
|
|
500
|
+
* @example
|
|
501
|
+
* filterOk([ok(1), err('a'), ok(2)]) // [1, 2]
|
|
502
|
+
*/
|
|
503
|
+
export function filterOk<T, E>(results: Iterable<Result<T, E>>): T[] {
|
|
504
|
+
const oks: T[] = [];
|
|
505
|
+
for (const result of results) {
|
|
506
|
+
if (isOk(result)) oks.push(result);
|
|
507
|
+
}
|
|
508
|
+
return oks;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Extracts all Err values from an iterable of Results.
|
|
513
|
+
* @param results - Iterable of Results
|
|
514
|
+
* @returns Array of error values
|
|
515
|
+
* @example
|
|
516
|
+
* filterErr([ok(1), err('a'), ok(2)]) // ['a']
|
|
517
|
+
*/
|
|
518
|
+
export function filterErr<T, E>(results: Iterable<Result<T, E>>): E[] {
|
|
519
|
+
const errs: E[] = [];
|
|
520
|
+
for (const result of results) {
|
|
521
|
+
if (isErr(result)) errs.push(result.error);
|
|
522
|
+
}
|
|
523
|
+
return errs;
|
|
524
|
+
}
|
|
525
|
+
|
|
506
526
|
/**
|
|
507
527
|
* Collects an array of Results into a Result of an array. Fails on first Err.
|
|
508
528
|
* @param results - Array of Results
|
|
@@ -515,10 +535,8 @@ export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
|
515
535
|
const values: T[] = [];
|
|
516
536
|
|
|
517
537
|
for (const result of results) {
|
|
518
|
-
if (isErr(result))
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
values.push(result as Ok<T>);
|
|
538
|
+
if (isErr(result)) return result;
|
|
539
|
+
values.push(result);
|
|
522
540
|
}
|
|
523
541
|
|
|
524
542
|
return values as Ok<T[]>;
|
|
@@ -542,8 +560,8 @@ export function collectAll<T, E>(results: Result<T, E>[]): Result<T[], E[]> {
|
|
|
542
560
|
* @param results - Array of Results
|
|
543
561
|
* @returns Ok(values) if all Ok, first Err otherwise
|
|
544
562
|
*/
|
|
545
|
-
export function all<T, E>(results: Result<T, E>[]): Result<Widen<T>[], WidenNever<E>> {
|
|
546
|
-
return collect(results) as Result<Widen<T>[], WidenNever<E>>;
|
|
563
|
+
export function all<T, E>(results: Result<T, E>[]): Result<readonly Widen<T>[], WidenNever<E>> {
|
|
564
|
+
return collect(results) as Result<readonly Widen<T>[], WidenNever<E>>;
|
|
547
565
|
}
|
|
548
566
|
|
|
549
567
|
/**
|
|
@@ -555,12 +573,11 @@ export function all<T, E>(results: Result<T, E>[]): Result<Widen<T>[], WidenNeve
|
|
|
555
573
|
* any([err('a'), err('b')]) // Err(['a', 'b'])
|
|
556
574
|
*/
|
|
557
575
|
export function any<T, E>(results: Result<T, E>[]): Result<Widen<T>, WidenNever<E>[]> {
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
for (let i = 0; i < len; i++) {
|
|
576
|
+
const errors: WidenNever<E>[] = [];
|
|
577
|
+
for (let i = 0; i < results.length; i++) {
|
|
561
578
|
const result = results[i];
|
|
562
579
|
if (isOk(result)) return result as Ok<Widen<T>>;
|
|
563
|
-
errors
|
|
580
|
+
errors.push((result as Err<WidenNever<E>>).error);
|
|
564
581
|
}
|
|
565
582
|
return ERR(errors);
|
|
566
583
|
}
|
|
@@ -576,7 +593,7 @@ export function any<T, E>(results: Result<T, E>[]): Result<Widen<T>, WidenNever<
|
|
|
576
593
|
*/
|
|
577
594
|
export function transpose<T, E>(result: Result<Option<T>, E>): Option<Result<T, E>> {
|
|
578
595
|
if (isErr(result)) {
|
|
579
|
-
return ERR(
|
|
596
|
+
return ERR(result.error) as Option<Result<T, E>>;
|
|
580
597
|
}
|
|
581
598
|
const opt = result as Option<T>;
|
|
582
599
|
return isNone(opt) ? NONE : (opt as unknown as Ok<T> as Option<Result<T, E>>);
|
|
@@ -606,71 +623,157 @@ export function isOkAnd<T, E>(result: Result<T, E>, predicate: (value: T) => boo
|
|
|
606
623
|
* isErrAnd(ok(42), e => true) // false
|
|
607
624
|
*/
|
|
608
625
|
export function isErrAnd<T, E>(result: Result<T, E>, predicate: (error: E) => boolean): boolean {
|
|
609
|
-
return isErr(result) && predicate(
|
|
626
|
+
return isErr(result) && predicate(result.error);
|
|
610
627
|
}
|
|
611
628
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
* @param fn - Async transform function
|
|
616
|
-
* @param onRejected - Optional rejection handler
|
|
617
|
-
* @returns Promise of mapped Result
|
|
618
|
-
* @example
|
|
619
|
-
* await mapAsync(ok(2), async x => x * 2) // Ok(4)
|
|
620
|
-
*/
|
|
621
|
-
export async function mapAsync<T, U, E = unknown>(
|
|
622
|
-
result: Result<T, E>,
|
|
623
|
-
fn: (value: T) => Promise<U>,
|
|
624
|
-
onRejected?: (error: unknown) => E,
|
|
625
|
-
): Promise<Result<U, E>> {
|
|
626
|
-
if (isErr(result)) return result as Err<E>;
|
|
627
|
-
return fromPromise(fn(result as Ok<T>), onRejected);
|
|
629
|
+
export function settledToResult<T, E>(result: PromiseSettledResult<Result<T, E>>): Result<T, E> {
|
|
630
|
+
if (result.status === 'fulfilled') return result.value;
|
|
631
|
+
return ERR(result.reason);
|
|
628
632
|
}
|
|
629
633
|
|
|
630
634
|
/**
|
|
631
|
-
*
|
|
632
|
-
* @param
|
|
633
|
-
* @
|
|
634
|
-
* @returns Promise of the chained Result
|
|
635
|
+
* Partitions an async iterable of Results.
|
|
636
|
+
* @param results - Iterable of Promise Results
|
|
637
|
+
* @returns Promise of [Ok values, Err values]
|
|
635
638
|
* @example
|
|
636
|
-
* await
|
|
639
|
+
* await partitionAsync([Promise.resolve(ok(1)), Promise.resolve(err('a'))])
|
|
640
|
+
* // [[1], ['a']]
|
|
637
641
|
*/
|
|
638
|
-
export async function
|
|
639
|
-
|
|
640
|
-
return
|
|
642
|
+
export async function partitionAsync<T, E>(promises: Iterable<Promise<Result<T, E>>>): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
643
|
+
const settled = await Promise.allSettled(promises);
|
|
644
|
+
return partition(settled.map(settledToResult)) as [Widen<T>[], WidenNever<E>[]];
|
|
641
645
|
}
|
|
642
646
|
|
|
643
647
|
/**
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* @param
|
|
647
|
-
* @
|
|
648
|
-
* @
|
|
648
|
+
* Settles an array of MaybePromise values into Results.
|
|
649
|
+
* Returns synchronously if all inputs are sync, avoiding Promise overhead.
|
|
650
|
+
* @param values - Array of values that may or may not be Promises
|
|
651
|
+
* @returns Array of Results (sync) or Promise of Results (if any async)
|
|
652
|
+
* @example
|
|
653
|
+
* settleMaybePromise([1, 2, 3]) // [Ok(1), Ok(2), Ok(3)] - sync
|
|
654
|
+
* settleMaybePromise([1, Promise.resolve(2)]) // Promise<[Ok(1), Ok(2)]>
|
|
655
|
+
* settleMaybePromise([Promise.reject('e')]) // Promise<[Err('e')]>
|
|
649
656
|
*/
|
|
650
|
-
export
|
|
651
|
-
|
|
657
|
+
export function settleMaybePromise<T, E = unknown>(values: MaybePromise<T>[]): Result<T, E>[] | Promise<Result<T, E>[]> {
|
|
658
|
+
const len = values.length;
|
|
659
|
+
const results = new Array<Result<T, E>>(len);
|
|
660
|
+
let pendingIndices: number[] | undefined;
|
|
661
|
+
let pendingPromises: Promise<T>[] | undefined;
|
|
662
|
+
|
|
663
|
+
for (let i = 0; i < len; i++) {
|
|
664
|
+
const v = values[i];
|
|
665
|
+
if (isThenable(v)) {
|
|
666
|
+
(pendingIndices ??= []).push(i);
|
|
667
|
+
(pendingPromises ??= []).push(Promise.resolve(v));
|
|
668
|
+
} else {
|
|
669
|
+
results[i] = v as Ok<T>;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (!pendingPromises) return results;
|
|
674
|
+
|
|
675
|
+
return Promise.allSettled(pendingPromises).then((settled) => {
|
|
676
|
+
for (let i = 0; i < settled.length; i++) {
|
|
677
|
+
const s = settled[i];
|
|
678
|
+
results[pendingIndices![i]] = s.status === 'fulfilled' ? (s.value as Ok<T>) : ERR(s.reason as E);
|
|
679
|
+
}
|
|
680
|
+
return results;
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export async function partitionMaybePromiseAsync<T, E>(
|
|
685
|
+
values: MaybePromise<Result<T, E>>[],
|
|
686
|
+
oks: Widen<T>[],
|
|
687
|
+
errs: WidenNever<E>[],
|
|
688
|
+
startIndex: number = 0,
|
|
689
|
+
): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
690
|
+
const suffixLength = values.length - startIndex;
|
|
691
|
+
const pending = new Array<Promise<Result<T, E>>>(suffixLength);
|
|
692
|
+
|
|
693
|
+
for (let i = 0; i < suffixLength; i++) {
|
|
694
|
+
const value = values[startIndex + i];
|
|
695
|
+
pending[i] = Promise.resolve(value).then(
|
|
696
|
+
(result) => result as Result<T, E>,
|
|
697
|
+
(error) => ERR(error as E),
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const resolved = await Promise.all(pending);
|
|
702
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
703
|
+
const result = resolved[i];
|
|
704
|
+
if (isOk(result)) {
|
|
705
|
+
oks.push(result as Widen<T>);
|
|
706
|
+
} else {
|
|
707
|
+
errs.push((result as Err<WidenNever<E>>).error);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return [oks, errs] as [Widen<T>[], WidenNever<E>[]];
|
|
652
711
|
}
|
|
653
712
|
|
|
654
713
|
/**
|
|
655
|
-
* Partitions
|
|
656
|
-
*
|
|
657
|
-
* @
|
|
714
|
+
* Partitions MaybePromise Results into Ok and Err values.
|
|
715
|
+
* Returns synchronously if all inputs are sync, avoiding Promise overhead.
|
|
716
|
+
* @param values - Array of MaybePromise Results
|
|
717
|
+
* @returns [Ok values, Err values] (sync) or Promise of same (if any async)
|
|
658
718
|
* @example
|
|
659
|
-
*
|
|
660
|
-
* // [[1], ['a']]
|
|
719
|
+
* partitionMaybePromise([ok(1), err('a')]) // [[1], ['a']] - sync
|
|
720
|
+
* partitionMaybePromise([ok(1), Promise.resolve(err('a'))]) // Promise<[[1], ['a']]>
|
|
661
721
|
*/
|
|
662
|
-
export
|
|
722
|
+
export function partitionMaybePromise<T, E>(values: MaybePromise<Result<T, E>>[]): [Widen<T>[], WidenNever<E>[]] | Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
723
|
+
const len = values.length;
|
|
663
724
|
const oks: Widen<T>[] = [];
|
|
664
725
|
const errs: WidenNever<E>[] = [];
|
|
665
726
|
|
|
666
|
-
for (
|
|
667
|
-
const
|
|
668
|
-
if (
|
|
669
|
-
|
|
727
|
+
for (let i = 0; i < len; i++) {
|
|
728
|
+
const value = values[i];
|
|
729
|
+
if (isThenable(value)) {
|
|
730
|
+
return partitionMaybePromiseAsync(values, oks, errs, i);
|
|
731
|
+
}
|
|
732
|
+
if (isOk(value)) {
|
|
733
|
+
oks.push(value as Widen<T>);
|
|
670
734
|
} else {
|
|
671
|
-
errs.push((
|
|
735
|
+
errs.push((value as Err<WidenNever<E>>).error);
|
|
672
736
|
}
|
|
673
737
|
}
|
|
674
738
|
|
|
675
739
|
return [oks, errs];
|
|
676
740
|
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Executes a function, catching thrown Err values.
|
|
744
|
+
* Use with unwrap for Rust-like ? operator ergonomics.
|
|
745
|
+
* @param fn - Function that may throw Err via unwrap
|
|
746
|
+
* @returns Ok(return value) or the caught Err
|
|
747
|
+
* @example
|
|
748
|
+
* const result = safeTry(() => {
|
|
749
|
+
* const a = unwrap(parseNumber('10'));
|
|
750
|
+
* const b = unwrap(parseNumber('5'));
|
|
751
|
+
* return a + b;
|
|
752
|
+
* }); // Ok(15) or Err(...)
|
|
753
|
+
*/
|
|
754
|
+
export function safeTry<T>(fn: () => T): Result<T, unknown> {
|
|
755
|
+
try {
|
|
756
|
+
return fn() as Ok<T>;
|
|
757
|
+
} catch (e) {
|
|
758
|
+
return ERR(e);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Async version of safeTry.
|
|
764
|
+
* @param fn - Async function that may throw Err via unwrap
|
|
765
|
+
* @returns Promise of Ok(return value) or the caught Err
|
|
766
|
+
* @example
|
|
767
|
+
* const result = await safeTryAsync(async () => {
|
|
768
|
+
* const user = unwrap(await fetchUser(id));
|
|
769
|
+
* const posts = unwrap(await fetchPosts(user.id));
|
|
770
|
+
* return { user, posts };
|
|
771
|
+
* });
|
|
772
|
+
*/
|
|
773
|
+
export async function safeTryAsync<T>(fn: () => Promise<T>): Promise<Result<T, unknown>> {
|
|
774
|
+
try {
|
|
775
|
+
return (await fn()) as Ok<T>;
|
|
776
|
+
} catch (e) {
|
|
777
|
+
return ERR(e);
|
|
778
|
+
}
|
|
779
|
+
}
|
package/src/safe.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { some, none, ok, err, isOk, isErr, isSome, isNone, isThenable, isSync } from './types.js';
|
|
2
|
+
export type {
|
|
3
3
|
Some,
|
|
4
4
|
None,
|
|
5
5
|
Ok,
|
|
@@ -13,46 +13,9 @@ import type {
|
|
|
13
13
|
ResultErrorType,
|
|
14
14
|
IsResult,
|
|
15
15
|
InferErr,
|
|
16
|
-
|
|
16
|
+
MaybePromise,
|
|
17
17
|
} from './types.js';
|
|
18
|
-
|
|
19
|
-
export type { Some, None, Ok, Err, OptionType, OptionValue, IsOption, InferSome, ResultType, ResultValue, ResultErrorType, IsResult, InferErr };
|
|
20
|
-
|
|
21
|
-
export { none, err };
|
|
18
|
+
export { safeTry, safeTryAsync, unwrap } from './result.js';
|
|
22
19
|
export * as Option from './option.js';
|
|
23
20
|
export * as Result from './result.js';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Creates a Some value with runtime validation.
|
|
27
|
-
* Throws if the value is null or undefined.
|
|
28
|
-
* @param value - The value to wrap (must be non-nullable)
|
|
29
|
-
* @returns The value typed as Some
|
|
30
|
-
* @throws {TypeError} If value is null or undefined
|
|
31
|
-
* @example
|
|
32
|
-
* some(42) // Some(42)
|
|
33
|
-
* some(null) // throws TypeError
|
|
34
|
-
* some(undefined) // throws TypeError
|
|
35
|
-
*/
|
|
36
|
-
export function some<T>(value: T): Some<ValueType<T>> {
|
|
37
|
-
if (value === null || value === undefined) {
|
|
38
|
-
throw new TypeError('some() requires a non-nullable value');
|
|
39
|
-
}
|
|
40
|
-
return someUnsafe(value as ValueType<T>);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Creates an Ok value with runtime validation.
|
|
45
|
-
* Throws if the value is an Err (prevents accidental double-wrapping).
|
|
46
|
-
* @param value - The success value
|
|
47
|
-
* @returns The value typed as Ok
|
|
48
|
-
* @throws {TypeError} If value is an Err
|
|
49
|
-
* @example
|
|
50
|
-
* ok(42) // Ok(42)
|
|
51
|
-
* ok(err('fail')) // throws TypeError
|
|
52
|
-
*/
|
|
53
|
-
export function ok<T>(value: T): Ok<T> {
|
|
54
|
-
if (isErr(value)) {
|
|
55
|
-
throw new TypeError('ok() cannot wrap an Err value');
|
|
56
|
-
}
|
|
57
|
-
return okUnsafe(value);
|
|
58
|
-
}
|
|
21
|
+
export * as Iter from './iter.js';
|