nalloc 0.0.1 → 0.0.3
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 +22 -7
- package/build/option.cjs.map +1 -1
- package/build/option.d.ts +22 -1
- package/build/option.js +17 -8
- package/build/option.js.map +1 -1
- package/build/result.cjs +137 -48
- package/build/result.cjs.map +1 -1
- package/build/result.d.ts +91 -50
- package/build/result.js +112 -35
- 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 +322 -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 +39 -9
- package/src/result.ts +236 -106
- 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,49 +29,53 @@ 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
|
-
*
|
|
36
|
-
* @param
|
|
37
|
+
* Converts a Promise to a Result. Resolves to Ok if successful, Err on rejection.
|
|
38
|
+
* @param promise - The promise to convert
|
|
37
39
|
* @param onError - Optional error transformer
|
|
38
|
-
* @returns Promise
|
|
40
|
+
* @returns Promise resolving to Ok(value) or Err(error)
|
|
39
41
|
* @example
|
|
40
|
-
* await
|
|
42
|
+
* await fromPromise(fetch('/api')) // Ok(Response) or Err(unknown)
|
|
43
|
+
* await fromPromise(fetch('/api'), e => String(e)) // Ok(Response) or Err(string)
|
|
41
44
|
*/
|
|
42
|
-
export async function
|
|
45
|
+
export async function fromPromise<T>(promise: Promise<T>): Promise<Result<T, unknown>>;
|
|
46
|
+
export async function fromPromise<T, E>(promise: Promise<T>, onError: (error: unknown) => E): Promise<Result<T, E>>;
|
|
47
|
+
export async function fromPromise<T, E = unknown>(promise: Promise<T>, onError?: (error: unknown) => E): Promise<Result<T, E>> {
|
|
43
48
|
try {
|
|
44
|
-
return (await
|
|
49
|
+
return (await promise) as Ok<T>;
|
|
45
50
|
} catch (error) {
|
|
46
51
|
return ERR(onError ? onError(error) : (error as E));
|
|
47
52
|
}
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
/**
|
|
51
|
-
*
|
|
52
|
-
* @param fn -
|
|
53
|
-
* @
|
|
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
|
|
56
|
+
* Executes a function that may return sync or async, preserving sync execution when possible.
|
|
57
|
+
* @param fn - Function that may return T or Promise<T>
|
|
58
|
+
* @param onError - Optional error transformer
|
|
59
|
+
* @returns Result<T, E> if sync, Promise<Result<T, E>> if async
|
|
64
60
|
* @example
|
|
65
|
-
*
|
|
66
|
-
*
|
|
61
|
+
* tryCatchMaybePromise(() => 42) // Ok(42) - sync
|
|
62
|
+
* tryCatchMaybePromise(() => Promise.resolve(42)) // Promise<Ok(42)> - async
|
|
63
|
+
* tryCatchMaybePromise(() => { throw 'err' }) // Err('err') - sync
|
|
67
64
|
*/
|
|
68
|
-
export
|
|
65
|
+
export function tryCatchMaybePromise<T>(fn: () => MaybePromise<T>): Result<T, unknown> | Promise<Result<T, unknown>>;
|
|
66
|
+
export function tryCatchMaybePromise<T, E>(fn: () => MaybePromise<T>, onError: (error: unknown) => E): Result<T, E> | Promise<Result<T, E>>;
|
|
67
|
+
export function tryCatchMaybePromise<T, E = unknown>(fn: () => MaybePromise<T>, onError?: (error: unknown) => E): Result<T, E> | Promise<Result<T, E>> {
|
|
69
68
|
try {
|
|
70
|
-
|
|
69
|
+
const result = fn();
|
|
70
|
+
if (isThenable(result)) {
|
|
71
|
+
return Promise.resolve(result).then(
|
|
72
|
+
(value) => value as Ok<T>,
|
|
73
|
+
(error) => ERR(onError ? onError(error) : (error as E)),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return result as Ok<T>;
|
|
71
77
|
} catch (error) {
|
|
72
|
-
return ERR(
|
|
78
|
+
return ERR(onError ? onError(error) : (error as E));
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
|
|
@@ -97,7 +103,7 @@ export function unwrapOrReturn<T, E, const R>(result: Result<T, E>, onErr: (erro
|
|
|
97
103
|
*/
|
|
98
104
|
export function assertOk<T, E>(result: Result<T, E>, message?: string): asserts result is Ok<T> {
|
|
99
105
|
if (isErr(result)) {
|
|
100
|
-
throw new Error(message ?? `Expected Ok result. Received error: ${String(
|
|
106
|
+
throw new Error(message ?? `Expected Ok result. Received error: ${String(result.error)}`);
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
|
|
@@ -122,7 +128,7 @@ export function assertErr<T, E>(result: Result<T, E>, message?: string): asserts
|
|
|
122
128
|
* @returns true if Err with Some error value
|
|
123
129
|
*/
|
|
124
130
|
export function isSomeErr<T, E>(result: Result<T, E>): boolean {
|
|
125
|
-
return isErr(result) && isSome(
|
|
131
|
+
return isErr(result) && isSome(result.error);
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
/**
|
|
@@ -138,8 +144,8 @@ export function map<T, U, E>(result: Err<E>, fn: (value: T) => U): Err<E>;
|
|
|
138
144
|
export function map<T, U>(result: Ok<T>, fn: (value: T) => U): Ok<U>;
|
|
139
145
|
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
|
|
140
146
|
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
|
|
147
|
+
if (isErr(result)) return result;
|
|
148
|
+
return fn(result) as Ok<U>;
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
/**
|
|
@@ -172,8 +178,8 @@ export function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Resu
|
|
|
172
178
|
export function flatMap<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
|
|
173
179
|
export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
174
180
|
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
|
|
181
|
+
if (isErr(result)) return result;
|
|
182
|
+
return fn(result);
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
/**
|
|
@@ -185,7 +191,7 @@ export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<
|
|
|
185
191
|
export function andThen<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
|
|
186
192
|
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
187
193
|
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
|
|
188
|
-
return
|
|
194
|
+
return isErr(result) ? result : fn(result);
|
|
189
195
|
}
|
|
190
196
|
|
|
191
197
|
/**
|
|
@@ -219,7 +225,7 @@ export function tapErr<E>(result: Err<E>, fn: (error: E) => void): Err<E>;
|
|
|
219
225
|
export function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;
|
|
220
226
|
export function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> {
|
|
221
227
|
if (isErr(result)) {
|
|
222
|
-
fn(
|
|
228
|
+
fn(result.error);
|
|
223
229
|
}
|
|
224
230
|
return result;
|
|
225
231
|
}
|
|
@@ -242,19 +248,22 @@ export function bimap<T, U, E, F>(result: Result<T, E>, okFn: (value: T) => U, e
|
|
|
242
248
|
}
|
|
243
249
|
|
|
244
250
|
/**
|
|
245
|
-
* Extracts the Ok value, throws if
|
|
251
|
+
* Extracts the Ok value, throws Err if not Ok.
|
|
252
|
+
* Use with safeTry for Rust-like ? operator ergonomics.
|
|
246
253
|
* @param result - The Result to unwrap
|
|
247
254
|
* @returns The contained Ok value
|
|
248
|
-
* @throws
|
|
255
|
+
* @throws The Err object itself
|
|
249
256
|
* @example
|
|
250
257
|
* unwrap(ok(42)) // 42
|
|
251
|
-
* unwrap(err('failed')) // throws
|
|
258
|
+
* unwrap(err('failed')) // throws Err
|
|
259
|
+
* safeTry(() => {
|
|
260
|
+
* const a = unwrap(getValue());
|
|
261
|
+
* return a + 1;
|
|
262
|
+
* });
|
|
252
263
|
*/
|
|
253
264
|
export function unwrap<T, E>(result: Result<T, E>): T {
|
|
254
|
-
if (isErr(result))
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
return result as T;
|
|
265
|
+
if (isErr(result)) throw result.error;
|
|
266
|
+
return result;
|
|
258
267
|
}
|
|
259
268
|
|
|
260
269
|
/**
|
|
@@ -339,9 +348,9 @@ export function mapOrElse<T, E, U>(result: Result<T, E>, defaultFn: () => U, fn:
|
|
|
339
348
|
*/
|
|
340
349
|
export function expect<T, E>(result: Result<T, E>, message: string): T {
|
|
341
350
|
if (isErr(result)) {
|
|
342
|
-
throw new Error(`${message}: ${String(
|
|
351
|
+
throw new Error(`${message}: ${String(result.error)}`);
|
|
343
352
|
}
|
|
344
|
-
return result
|
|
353
|
+
return result;
|
|
345
354
|
}
|
|
346
355
|
|
|
347
356
|
/**
|
|
@@ -421,7 +430,7 @@ export function toOption<T, E>(result: Result<T, E>): Option<T> {
|
|
|
421
430
|
* toErrorOption(ok(42)) // None
|
|
422
431
|
*/
|
|
423
432
|
export function toErrorOption<T, E>(result: Result<T, E>): Option<E> {
|
|
424
|
-
return isErr(result) ? optionOf(
|
|
433
|
+
return isErr(result) ? optionOf(result.error) : NONE;
|
|
425
434
|
}
|
|
426
435
|
|
|
427
436
|
/**
|
|
@@ -434,9 +443,9 @@ export function toErrorOption<T, E>(result: Result<T, E>): Option<E> {
|
|
|
434
443
|
* zip(ok(1), err('e')) // Err('e')
|
|
435
444
|
*/
|
|
436
445
|
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
|
|
446
|
+
if (isErr(left)) return left;
|
|
447
|
+
if (isErr(right)) return right;
|
|
448
|
+
return [left, right] as Ok<[T, U]>;
|
|
440
449
|
}
|
|
441
450
|
|
|
442
451
|
/**
|
|
@@ -449,9 +458,9 @@ export function zip<T, U, E>(left: Result<T, E>, right: Result<U, E>): Result<[T
|
|
|
449
458
|
* zipWith(ok(2), ok(3), (a, b) => a + b) // Ok(5)
|
|
450
459
|
*/
|
|
451
460
|
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
|
|
461
|
+
if (isErr(left)) return left;
|
|
462
|
+
if (isErr(right)) return right;
|
|
463
|
+
return fn(left, right) as Ok<V>;
|
|
455
464
|
}
|
|
456
465
|
|
|
457
466
|
/**
|
|
@@ -503,6 +512,36 @@ export function partition<T, E>(results: Result<T, E>[]): [T[], E[]] {
|
|
|
503
512
|
return [oks, errs];
|
|
504
513
|
}
|
|
505
514
|
|
|
515
|
+
/**
|
|
516
|
+
* Extracts all Ok values from an iterable of Results.
|
|
517
|
+
* @param results - Iterable of Results
|
|
518
|
+
* @returns Array of Ok values
|
|
519
|
+
* @example
|
|
520
|
+
* filterOk([ok(1), err('a'), ok(2)]) // [1, 2]
|
|
521
|
+
*/
|
|
522
|
+
export function filterOk<T, E>(results: Iterable<Result<T, E>>): T[] {
|
|
523
|
+
const oks: T[] = [];
|
|
524
|
+
for (const result of results) {
|
|
525
|
+
if (isOk(result)) oks.push(result);
|
|
526
|
+
}
|
|
527
|
+
return oks;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Extracts all Err values from an iterable of Results.
|
|
532
|
+
* @param results - Iterable of Results
|
|
533
|
+
* @returns Array of error values
|
|
534
|
+
* @example
|
|
535
|
+
* filterErr([ok(1), err('a'), ok(2)]) // ['a']
|
|
536
|
+
*/
|
|
537
|
+
export function filterErr<T, E>(results: Iterable<Result<T, E>>): E[] {
|
|
538
|
+
const errs: E[] = [];
|
|
539
|
+
for (const result of results) {
|
|
540
|
+
if (isErr(result)) errs.push(result.error);
|
|
541
|
+
}
|
|
542
|
+
return errs;
|
|
543
|
+
}
|
|
544
|
+
|
|
506
545
|
/**
|
|
507
546
|
* Collects an array of Results into a Result of an array. Fails on first Err.
|
|
508
547
|
* @param results - Array of Results
|
|
@@ -515,10 +554,8 @@ export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
|
515
554
|
const values: T[] = [];
|
|
516
555
|
|
|
517
556
|
for (const result of results) {
|
|
518
|
-
if (isErr(result))
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
values.push(result as Ok<T>);
|
|
557
|
+
if (isErr(result)) return result;
|
|
558
|
+
values.push(result);
|
|
522
559
|
}
|
|
523
560
|
|
|
524
561
|
return values as Ok<T[]>;
|
|
@@ -533,7 +570,15 @@ export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
|
533
570
|
* collectAll([ok(1), err('a'), err('b')]) // Err(['a', 'b'])
|
|
534
571
|
*/
|
|
535
572
|
export function collectAll<T, E>(results: Result<T, E>[]): Result<T[], E[]> {
|
|
536
|
-
const
|
|
573
|
+
const oks: T[] = [];
|
|
574
|
+
const errs: E[] = [];
|
|
575
|
+
for (const result of results) {
|
|
576
|
+
if (isOk(result)) {
|
|
577
|
+
oks.push(result);
|
|
578
|
+
} else {
|
|
579
|
+
errs.push(result.error);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
537
582
|
return errs.length > 0 ? ERR(errs) : (oks as Ok<T[]>);
|
|
538
583
|
}
|
|
539
584
|
|
|
@@ -542,8 +587,8 @@ export function collectAll<T, E>(results: Result<T, E>[]): Result<T[], E[]> {
|
|
|
542
587
|
* @param results - Array of Results
|
|
543
588
|
* @returns Ok(values) if all Ok, first Err otherwise
|
|
544
589
|
*/
|
|
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>>;
|
|
590
|
+
export function all<T, E>(results: Result<T, E>[]): Result<readonly Widen<T>[], WidenNever<E>> {
|
|
591
|
+
return collect(results) as Result<readonly Widen<T>[], WidenNever<E>>;
|
|
547
592
|
}
|
|
548
593
|
|
|
549
594
|
/**
|
|
@@ -555,12 +600,11 @@ export function all<T, E>(results: Result<T, E>[]): Result<Widen<T>[], WidenNeve
|
|
|
555
600
|
* any([err('a'), err('b')]) // Err(['a', 'b'])
|
|
556
601
|
*/
|
|
557
602
|
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++) {
|
|
603
|
+
const errors: WidenNever<E>[] = [];
|
|
604
|
+
for (let i = 0; i < results.length; i++) {
|
|
561
605
|
const result = results[i];
|
|
562
606
|
if (isOk(result)) return result as Ok<Widen<T>>;
|
|
563
|
-
errors
|
|
607
|
+
errors.push((result as Err<WidenNever<E>>).error);
|
|
564
608
|
}
|
|
565
609
|
return ERR(errors);
|
|
566
610
|
}
|
|
@@ -576,7 +620,7 @@ export function any<T, E>(results: Result<T, E>[]): Result<Widen<T>, WidenNever<
|
|
|
576
620
|
*/
|
|
577
621
|
export function transpose<T, E>(result: Result<Option<T>, E>): Option<Result<T, E>> {
|
|
578
622
|
if (isErr(result)) {
|
|
579
|
-
return ERR(
|
|
623
|
+
return ERR(result.error) as Option<Result<T, E>>;
|
|
580
624
|
}
|
|
581
625
|
const opt = result as Option<T>;
|
|
582
626
|
return isNone(opt) ? NONE : (opt as unknown as Ok<T> as Option<Result<T, E>>);
|
|
@@ -606,71 +650,157 @@ export function isOkAnd<T, E>(result: Result<T, E>, predicate: (value: T) => boo
|
|
|
606
650
|
* isErrAnd(ok(42), e => true) // false
|
|
607
651
|
*/
|
|
608
652
|
export function isErrAnd<T, E>(result: Result<T, E>, predicate: (error: E) => boolean): boolean {
|
|
609
|
-
return isErr(result) && predicate(
|
|
653
|
+
return isErr(result) && predicate(result.error);
|
|
610
654
|
}
|
|
611
655
|
|
|
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);
|
|
656
|
+
export function settledToResult<T, E>(result: PromiseSettledResult<Result<T, E>>): Result<T, E> {
|
|
657
|
+
if (result.status === 'fulfilled') return result.value;
|
|
658
|
+
return ERR(result.reason);
|
|
628
659
|
}
|
|
629
660
|
|
|
630
661
|
/**
|
|
631
|
-
*
|
|
632
|
-
* @param
|
|
633
|
-
* @
|
|
634
|
-
* @returns Promise of the chained Result
|
|
662
|
+
* Partitions an async iterable of Results.
|
|
663
|
+
* @param results - Iterable of Promise Results
|
|
664
|
+
* @returns Promise of [Ok values, Err values]
|
|
635
665
|
* @example
|
|
636
|
-
* await
|
|
666
|
+
* await partitionAsync([Promise.resolve(ok(1)), Promise.resolve(err('a'))])
|
|
667
|
+
* // [[1], ['a']]
|
|
637
668
|
*/
|
|
638
|
-
export async function
|
|
639
|
-
|
|
640
|
-
return
|
|
669
|
+
export async function partitionAsync<T, E>(promises: Iterable<Promise<Result<T, E>>>): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
670
|
+
const settled = await Promise.allSettled(promises);
|
|
671
|
+
return partition(settled.map(settledToResult)) as [Widen<T>[], WidenNever<E>[]];
|
|
641
672
|
}
|
|
642
673
|
|
|
643
674
|
/**
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
* @param
|
|
647
|
-
* @
|
|
648
|
-
* @
|
|
675
|
+
* Settles an array of MaybePromise values into Results.
|
|
676
|
+
* Returns synchronously if all inputs are sync, avoiding Promise overhead.
|
|
677
|
+
* @param values - Array of values that may or may not be Promises
|
|
678
|
+
* @returns Array of Results (sync) or Promise of Results (if any async)
|
|
679
|
+
* @example
|
|
680
|
+
* settleMaybePromise([1, 2, 3]) // [Ok(1), Ok(2), Ok(3)] - sync
|
|
681
|
+
* settleMaybePromise([1, Promise.resolve(2)]) // Promise<[Ok(1), Ok(2)]>
|
|
682
|
+
* settleMaybePromise([Promise.reject('e')]) // Promise<[Err('e')]>
|
|
649
683
|
*/
|
|
650
|
-
export
|
|
651
|
-
|
|
684
|
+
export function settleMaybePromise<T, E = unknown>(values: MaybePromise<T>[]): Result<T, E>[] | Promise<Result<T, E>[]> {
|
|
685
|
+
const len = values.length;
|
|
686
|
+
const results = new Array<Result<T, E>>(len);
|
|
687
|
+
let pendingIndices: number[] | undefined;
|
|
688
|
+
let pendingPromises: Promise<T>[] | undefined;
|
|
689
|
+
|
|
690
|
+
for (let i = 0; i < len; i++) {
|
|
691
|
+
const v = values[i];
|
|
692
|
+
if (isThenable(v)) {
|
|
693
|
+
(pendingIndices ??= []).push(i);
|
|
694
|
+
(pendingPromises ??= []).push(Promise.resolve(v));
|
|
695
|
+
} else {
|
|
696
|
+
results[i] = v as Ok<T>;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (!pendingPromises) return results;
|
|
701
|
+
|
|
702
|
+
return Promise.allSettled(pendingPromises).then((settled) => {
|
|
703
|
+
for (let i = 0; i < settled.length; i++) {
|
|
704
|
+
const s = settled[i];
|
|
705
|
+
results[pendingIndices![i]] = s.status === 'fulfilled' ? (s.value as Ok<T>) : ERR(s.reason as E);
|
|
706
|
+
}
|
|
707
|
+
return results;
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export async function partitionMaybePromiseAsync<T, E>(
|
|
712
|
+
values: MaybePromise<Result<T, E>>[],
|
|
713
|
+
oks: Widen<T>[],
|
|
714
|
+
errs: WidenNever<E>[],
|
|
715
|
+
startIndex: number = 0,
|
|
716
|
+
): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
717
|
+
const suffixLength = values.length - startIndex;
|
|
718
|
+
const pending = new Array<Promise<Result<T, E>>>(suffixLength);
|
|
719
|
+
|
|
720
|
+
for (let i = 0; i < suffixLength; i++) {
|
|
721
|
+
const value = values[startIndex + i];
|
|
722
|
+
pending[i] = Promise.resolve(value).then(
|
|
723
|
+
(result) => result as Result<T, E>,
|
|
724
|
+
(error) => ERR(error as E),
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const resolved = await Promise.all(pending);
|
|
729
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
730
|
+
const result = resolved[i];
|
|
731
|
+
if (isOk(result)) {
|
|
732
|
+
oks.push(result as Widen<T>);
|
|
733
|
+
} else {
|
|
734
|
+
errs.push((result as Err<WidenNever<E>>).error);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return [oks, errs] as [Widen<T>[], WidenNever<E>[]];
|
|
652
738
|
}
|
|
653
739
|
|
|
654
740
|
/**
|
|
655
|
-
* Partitions
|
|
656
|
-
*
|
|
657
|
-
* @
|
|
741
|
+
* Partitions MaybePromise Results into Ok and Err values.
|
|
742
|
+
* Returns synchronously if all inputs are sync, avoiding Promise overhead.
|
|
743
|
+
* @param values - Array of MaybePromise Results
|
|
744
|
+
* @returns [Ok values, Err values] (sync) or Promise of same (if any async)
|
|
658
745
|
* @example
|
|
659
|
-
*
|
|
660
|
-
* // [[1], ['a']]
|
|
746
|
+
* partitionMaybePromise([ok(1), err('a')]) // [[1], ['a']] - sync
|
|
747
|
+
* partitionMaybePromise([ok(1), Promise.resolve(err('a'))]) // Promise<[[1], ['a']]>
|
|
661
748
|
*/
|
|
662
|
-
export
|
|
749
|
+
export function partitionMaybePromise<T, E>(values: MaybePromise<Result<T, E>>[]): [Widen<T>[], WidenNever<E>[]] | Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
750
|
+
const len = values.length;
|
|
663
751
|
const oks: Widen<T>[] = [];
|
|
664
752
|
const errs: WidenNever<E>[] = [];
|
|
665
753
|
|
|
666
|
-
for (
|
|
667
|
-
const
|
|
668
|
-
if (
|
|
669
|
-
|
|
754
|
+
for (let i = 0; i < len; i++) {
|
|
755
|
+
const value = values[i];
|
|
756
|
+
if (isThenable(value)) {
|
|
757
|
+
return partitionMaybePromiseAsync(values, oks, errs, i);
|
|
758
|
+
}
|
|
759
|
+
if (isOk(value)) {
|
|
760
|
+
oks.push(value as Widen<T>);
|
|
670
761
|
} else {
|
|
671
|
-
errs.push((
|
|
762
|
+
errs.push((value as Err<WidenNever<E>>).error);
|
|
672
763
|
}
|
|
673
764
|
}
|
|
674
765
|
|
|
675
766
|
return [oks, errs];
|
|
676
767
|
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Executes a function, catching thrown Err values.
|
|
771
|
+
* Use with unwrap for Rust-like ? operator ergonomics.
|
|
772
|
+
* @param fn - Function that may throw Err via unwrap
|
|
773
|
+
* @returns Ok(return value) or the caught Err
|
|
774
|
+
* @example
|
|
775
|
+
* const result = safeTry(() => {
|
|
776
|
+
* const a = unwrap(parseNumber('10'));
|
|
777
|
+
* const b = unwrap(parseNumber('5'));
|
|
778
|
+
* return a + b;
|
|
779
|
+
* }); // Ok(15) or Err(...)
|
|
780
|
+
*/
|
|
781
|
+
export function safeTry<T>(fn: () => T): Result<T, unknown> {
|
|
782
|
+
try {
|
|
783
|
+
return fn() as Ok<T>;
|
|
784
|
+
} catch (e) {
|
|
785
|
+
return ERR(e);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Async version of safeTry.
|
|
791
|
+
* @param fn - Async function that may throw Err via unwrap
|
|
792
|
+
* @returns Promise of Ok(return value) or the caught Err
|
|
793
|
+
* @example
|
|
794
|
+
* const result = await safeTryAsync(async () => {
|
|
795
|
+
* const user = unwrap(await fetchUser(id));
|
|
796
|
+
* const posts = unwrap(await fetchPosts(user.id));
|
|
797
|
+
* return { user, posts };
|
|
798
|
+
* });
|
|
799
|
+
*/
|
|
800
|
+
export async function safeTryAsync<T>(fn: () => Promise<T>): Promise<Result<T, unknown>> {
|
|
801
|
+
try {
|
|
802
|
+
return (await fn()) as Ok<T>;
|
|
803
|
+
} catch (e) {
|
|
804
|
+
return ERR(e);
|
|
805
|
+
}
|
|
806
|
+
}
|
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';
|