retuple 1.0.0-next.2 → 1.0.0-next.20

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/index.js CHANGED
@@ -9,61 +9,221 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _ResultAsync_inner;
12
+ var _ResultAsync_inner, _a, _ResultRetry_f, _ResultRetry_promise, _ResultRetry_times, _ResultRetry_attempt, _ResultRetry_aborted, _ResultRetry_abort, _ResultRetry_getDelay, _ResultRetry_handler;
13
+ import { ResultLikeSymbol, } from "retuple-symbols";
14
+ /**
15
+ * ## Retuple Unwrap Failed
16
+ *
17
+ * An error which occurs when calling `$unwrap` on `Err`.
18
+ */
13
19
  export class RetupleUnwrapFailed extends Error {
14
20
  constructor(value, msg = "Unwrap failed") {
15
21
  super(msg, value instanceof Error ? { cause: value } : undefined);
16
22
  this.value = value;
17
23
  }
18
24
  }
25
+ /**
26
+ * ## Retuple Unwrap Err Failed
27
+ *
28
+ * An error which occurs when calling `$unwrapErr` on `Ok`.
29
+ */
19
30
  export class RetupleUnwrapErrFailed extends Error {
20
31
  constructor(value, msg = "Unwrap error failed") {
21
32
  super(msg);
22
33
  this.value = value;
23
34
  }
24
35
  }
36
+ /**
37
+ * ## Retuple Expect Failed
38
+ *
39
+ * An error which occurs when calling `$expect` on `Err`, when the value
40
+ * contained in the `Err` is not an instance of `Error`.
41
+ */
25
42
  export class RetupleExpectFailed extends Error {
26
43
  constructor(value) {
27
44
  super("Expect failed");
28
45
  this.value = value;
29
46
  }
30
47
  }
31
- export class RetupleThrownValueError extends Error {
48
+ /**
49
+ * ## Retuple Thrown Value Error
50
+ *
51
+ * An error constructed when a safe function call throws or rejects, when the
52
+ * thrown error or rejected value is not an instance of `Error`, and when no
53
+ * map error function is provided.
54
+ */
55
+ export class RetupleCaughtValueError extends Error {
32
56
  constructor(value) {
33
57
  super("Caught value was not an instance of Error");
34
58
  this.value = value;
35
59
  }
36
60
  }
61
+ /**
62
+ * ## Retuple Invalid Union Error
63
+ *
64
+ * This error is thrown when attempting to construct a `Result` from a
65
+ * discriminated union, when the 'success' property is not boolean. In this
66
+ * case, it is impossible to determine whether the result should be `Ok` or
67
+ * `Err`.
68
+ */
69
+ export class RetupleInvalidUnionError extends Error {
70
+ constructor(value) {
71
+ super("Constructing a Result from discriminated union failed, the success " +
72
+ "property must be boolean");
73
+ this.value = value;
74
+ }
75
+ }
76
+ /**
77
+ * ## Retuple Array Method Unavailable Error
78
+ *
79
+ * This error is thrown when calling a built-in array method from a `Result`.
80
+ */
81
+ export class RetupleArrayMethodUnavailableError extends Error {
82
+ constructor(value, method) {
83
+ super(`Built in array method '${method}' should not be called directly from ` +
84
+ "a Result, convert the Result to a tuple first");
85
+ this.value = value;
86
+ }
87
+ }
37
88
  /**
38
89
  * ## Result
39
90
  *
40
91
  * @TODO
41
92
  */
42
- export const Result = {
43
- Ok,
44
- Err,
45
- from,
46
- safe,
47
- safeAsync,
48
- safePromise,
49
- };
50
- export default Result;
93
+ export function Result(resultLike) {
94
+ return asResult(resultLike);
95
+ }
96
+ Result.Ok = Ok;
97
+ Result.Err = Err;
98
+ Result.$from = $from;
99
+ Result.$resolve = $resolve;
100
+ Result.$nonNullable = $nonNullable;
101
+ Result.$truthy = $truthy;
102
+ Result.$fromUnion = $fromUnion;
103
+ Result.$safe = $safe;
104
+ Result.$safeAsync = $safeAsync;
105
+ Result.$safePromise = $safePromise;
106
+ Result.$retry = $retry;
107
+ Result.$safeRetry = $safeRetry;
108
+ Object.freeze(Result);
51
109
  export function Ok(val) {
52
110
  return new ResultOk(val);
53
111
  }
54
112
  export function Err(err) {
55
113
  return new ResultErr(err);
56
114
  }
57
- export function from(value, error) {
115
+ /**
116
+ * Construct a {@link Result} from a {@link ResultLike}.
117
+ *
118
+ * @example
119
+ *
120
+ * ```ts
121
+ * const value: Result<T, E> | ResultLike<T, E> = someResultFn();
122
+ * const result: Result<T, E> = Result.$from(result);
123
+ * ```
124
+ */
125
+ function $from(result) {
126
+ if (result instanceof ResultOk || result instanceof ResultErr) {
127
+ return result;
128
+ }
129
+ return asResult(result);
130
+ }
131
+ /**
132
+ * Construct a {@link ResultAsync} from a {@link ResultLikeAwaitable}.
133
+ *
134
+ * @example
135
+ *
136
+ * ```ts
137
+ * const value:
138
+ * | Result<T, E>
139
+ * | ResultLike<T, E>
140
+ * | ResultAsync<T, E>
141
+ * | Promise<Result<T, E>>
142
+ * | Promise<ResultLike<T, E>>
143
+ * | PromiseLike<Result<T, E>>
144
+ * | PromiseLike<ResultLike<T, E>> = someResultFn();
145
+ *
146
+ * const result: ResultAsync<T, E> = Result.$resolve(result);
147
+ * ```
148
+ */
149
+ function $resolve(result) {
150
+ switch (true) {
151
+ case result instanceof ResultAsync:
152
+ return result;
153
+ case result instanceof ResultOk:
154
+ case result instanceof ResultErr:
155
+ return new ResultAsync(Promise.resolve(result));
156
+ default:
157
+ return new ResultAsync(Promise.resolve(result).then((asResult)));
158
+ }
159
+ }
160
+ function $nonNullable(value, error = mapTrue) {
161
+ if (value !== null && value !== undefined) {
162
+ return Ok(value);
163
+ }
164
+ return Err(error());
165
+ }
166
+ function $truthy(value, error = mapTrue) {
58
167
  if (value) {
59
- return new ResultOk(value);
168
+ return Ok(value);
60
169
  }
61
- if (error) {
62
- return new ResultErr(error());
170
+ return Err(error());
171
+ }
172
+ /**
173
+ * Construct a {@link Result} from a common discriminated union shape. If the
174
+ * union is 'success' then the result is `Ok`
175
+ *
176
+ * Otherwise, the result is `Err` containing:
177
+ *
178
+ * - the returned value from the error function when provided;
179
+ * - or `true` otherwise.
180
+ *
181
+ * @example
182
+ *
183
+ * ```ts
184
+ * const result: Result<string, Error> = Result.$truthy(
185
+ * username.trim(),
186
+ * () => new Error("Username is empty"),
187
+ * );
188
+ * ```
189
+ *
190
+ * @example
191
+ *
192
+ * ```ts
193
+ * const [err, value] = Result.$truthy("test");
194
+ *
195
+ * assert.equal(err, undefined);
196
+ * assert.equal(value, "test");
197
+ * ```
198
+ *
199
+ * @example
200
+ *
201
+ * ```ts
202
+ * const [err, value] = Result.$truthy("");
203
+ *
204
+ * assert.equal(err, true);
205
+ * assert.equal(value, undefined);
206
+ * ```
207
+ *
208
+ * @example
209
+ *
210
+ * ```ts
211
+ * const [err, value] = Result.$truthy(0, () => "error");
212
+ *
213
+ * assert.equal(err, "error");
214
+ * assert.equal(value, undefined);
215
+ * ```
216
+ */
217
+ function $fromUnion(union) {
218
+ if (union.success === true) {
219
+ return Ok(union.data);
220
+ }
221
+ if (union.success === false) {
222
+ return Err(union.error);
63
223
  }
64
- return new ResultErr(true);
224
+ throw new RetupleInvalidUnionError(union);
65
225
  }
66
- export function safe(f, mapError = ensureError) {
226
+ function $safe(f, mapError = ensureError) {
67
227
  try {
68
228
  return Ok(f());
69
229
  }
@@ -71,7 +231,7 @@ export function safe(f, mapError = ensureError) {
71
231
  return Err(mapError(err));
72
232
  }
73
233
  }
74
- export function safeAsync(f, mapError = ensureError) {
234
+ function $safeAsync(f, mapError = ensureError) {
75
235
  return new ResultAsync((async () => {
76
236
  try {
77
237
  return Ok(await f());
@@ -81,13 +241,42 @@ export function safeAsync(f, mapError = ensureError) {
81
241
  }
82
242
  })());
83
243
  }
84
- export function safePromise(promise, mapError = ensureError) {
244
+ function $safePromise(promise, mapError = ensureError) {
85
245
  return new ResultAsync(promise.then((Ok), async (err) => Err(await mapError(err))));
86
246
  }
87
247
  /**
88
- * ## Ok
248
+ * Construct a {@link ResultRetry} from a function which returns a
249
+ * {@link Result}. The function will be retried based on provided retry
250
+ * settings and eventually return a `Result`. No attempt is made to catch
251
+ * thrown errors or promise rejections.
89
252
  *
90
- * @TODO
253
+ * To retry a potentially unsafe function, use {@link Result.$safeRetry}.
254
+ *
255
+ * @example
256
+ *
257
+ * ```ts
258
+ * // Retry someResultFn up to 3 times until Ok is returned,
259
+ * // with a 1 second delay between each invocation:
260
+ * const result = await Result.$retry(someResultFn).$times(3).$delay(1000);
261
+ * ```
262
+ */
263
+ function $retry(f) {
264
+ return new ResultRetry(f);
265
+ }
266
+ function $safeRetry(f, mapError = ensureError) {
267
+ return new ResultRetry(async () => {
268
+ try {
269
+ return Ok(await f());
270
+ }
271
+ catch (err) {
272
+ return Err(mapError(err));
273
+ }
274
+ });
275
+ }
276
+ /**
277
+ * ## ResultOk
278
+ *
279
+ * This is the `Ok` variant of a `Result`, used internally and not exported.
91
280
  */
92
281
  class ResultOk extends Array {
93
282
  constructor(value) {
@@ -95,14 +284,17 @@ class ResultOk extends Array {
95
284
  this[0] = undefined;
96
285
  this[1] = value;
97
286
  }
98
- $value() {
287
+ [ResultLikeSymbol]() {
288
+ return { ok: true, value: this[1] };
289
+ }
290
+ toJSON() {
99
291
  return this[1];
100
292
  }
101
293
  $isOk() {
102
294
  return true;
103
295
  }
104
296
  $isOkAnd(f) {
105
- return f(this[1]);
297
+ return !!f(this[1]);
106
298
  }
107
299
  $isErr() {
108
300
  return false;
@@ -126,44 +318,77 @@ class ResultOk extends Array {
126
318
  return this[1];
127
319
  }
128
320
  $map(f) {
129
- return new ResultOk(f(this[1]));
321
+ return Ok(f(this[1]));
130
322
  }
131
323
  $mapErr() {
132
324
  return this;
133
325
  }
134
326
  $mapOr(_def, f) {
135
- return new ResultOk(f(this[1]));
327
+ return Ok(f(this[1]));
136
328
  }
137
329
  $mapOrElse(_def, f) {
138
- return new ResultOk(f(this[1]));
330
+ return Ok(f(this[1]));
331
+ }
332
+ $andAssertOr(def, condition = isTruthy) {
333
+ return condition(this[1]) ? this : asResult(def);
334
+ }
335
+ $andAssertOrElse(def, condition = isTruthy) {
336
+ return condition(this[1]) ? this : asResult(def(this[1]));
139
337
  }
140
338
  $or() {
141
339
  return this;
142
340
  }
341
+ $orAsync() {
342
+ return this.$async();
343
+ }
143
344
  $orElse() {
144
345
  return this;
145
346
  }
347
+ $orElseAsync() {
348
+ return this.$async();
349
+ }
146
350
  $orSafe() {
147
351
  return this;
148
352
  }
353
+ $orSafeAsync() {
354
+ return this.$async();
355
+ }
356
+ $orSafePromise() {
357
+ return this.$async();
358
+ }
149
359
  $and(and) {
150
- return and;
360
+ return asResult(and);
361
+ }
362
+ $andAsync(and) {
363
+ return this.$async().$and(and);
151
364
  }
152
365
  $andThen(f) {
153
- return f(this[1]);
366
+ return asResult(f(this[1]));
367
+ }
368
+ $andThenAsync(f) {
369
+ return this.$async().$andThen(f);
154
370
  }
155
371
  $andThrough(f) {
156
- const res = f(this[1]);
372
+ const res = asResult(f(this[1]));
157
373
  return res instanceof ResultErr ? res : this;
158
374
  }
375
+ $andThroughAsync(f) {
376
+ return this.$async().$andThrough(f);
377
+ }
159
378
  $andSafe(f, mapError = ensureError) {
160
379
  try {
161
- return new ResultOk(f(this[1]));
380
+ return Ok(f(this[1]));
162
381
  }
163
382
  catch (err) {
164
- return new ResultErr(mapError(err));
383
+ return Err(mapError(err));
165
384
  }
166
385
  }
386
+ $andSafeAsync(f, mapError = ensureError) {
387
+ return this.$async().$andSafe(f, mapError);
388
+ }
389
+ $andSafePromise(promise, mapError = ensureError) {
390
+ return this.$async().$andSafePromise(promise, mapError);
391
+ }
167
392
  $peek(f) {
168
393
  f(this);
169
394
  return this;
@@ -184,11 +409,14 @@ class ResultOk extends Array {
184
409
  $promise() {
185
410
  return Promise.resolve(this);
186
411
  }
412
+ *$iter() {
413
+ yield* this[1];
414
+ }
187
415
  }
188
416
  /**
189
- * ## Err
417
+ * ## ResultErr
190
418
  *
191
- * @TODO
419
+ * This is the `Err` variant of a `Result`, used internally and not exported.
192
420
  */
193
421
  class ResultErr extends Array {
194
422
  constructor(err) {
@@ -196,8 +424,11 @@ class ResultErr extends Array {
196
424
  this[0] = err;
197
425
  this[1] = undefined;
198
426
  }
199
- $value() {
200
- return this[0];
427
+ [ResultLikeSymbol]() {
428
+ return { ok: false, value: this[0] };
429
+ }
430
+ toJSON() {
431
+ return null;
201
432
  }
202
433
  $isOk() {
203
434
  return false;
@@ -209,7 +440,7 @@ class ResultErr extends Array {
209
440
  return true;
210
441
  }
211
442
  $isErrAnd(f) {
212
- return f(this[0]);
443
+ return !!f(this[0]);
213
444
  }
214
445
  $expect() {
215
446
  if (this[0] instanceof Error) {
@@ -233,40 +464,73 @@ class ResultErr extends Array {
233
464
  return this;
234
465
  }
235
466
  $mapErr(f) {
236
- return new ResultErr(f(this[0]));
467
+ return Err(f(this[0]));
237
468
  }
238
469
  $mapOr(def) {
239
- return new ResultOk(def);
470
+ return Ok(def);
240
471
  }
241
472
  $mapOrElse(def) {
242
- return new ResultOk(def(this[0]));
473
+ return Ok(def(this[0]));
474
+ }
475
+ $andAssertOr() {
476
+ return this;
477
+ }
478
+ $andAssertOrElse() {
479
+ return this;
243
480
  }
244
481
  $or(or) {
245
- return or;
482
+ return asResult(or);
483
+ }
484
+ $orAsync(or) {
485
+ return this.$async().$or(or);
246
486
  }
247
487
  $orElse(f) {
248
- return f(this[0]);
488
+ return asResult(f(this[0]));
489
+ }
490
+ $orElseAsync(f) {
491
+ return this.$async().$orElse(f);
249
492
  }
250
493
  $orSafe(f, mapError = ensureError) {
251
494
  try {
252
- return new ResultOk(f(this[0]));
495
+ return Ok(f(this[0]));
253
496
  }
254
497
  catch (err) {
255
- return new ResultErr(mapError(err));
498
+ return Err(mapError(err));
256
499
  }
257
500
  }
501
+ $orSafeAsync(f, mapError = ensureError) {
502
+ return this.$async().$orSafe(f, mapError);
503
+ }
504
+ $orSafePromise(promise, mapError = ensureError) {
505
+ return this.$async().$orSafePromise(promise, mapError);
506
+ }
258
507
  $and() {
259
508
  return this;
260
509
  }
510
+ $andAsync() {
511
+ return this.$async();
512
+ }
261
513
  $andThen() {
262
514
  return this;
263
515
  }
516
+ $andThenAsync() {
517
+ return this.$async();
518
+ }
264
519
  $andThrough() {
265
520
  return this;
266
521
  }
522
+ $andThroughAsync() {
523
+ return this.$async();
524
+ }
267
525
  $andSafe() {
268
526
  return this;
269
527
  }
528
+ $andSafeAsync() {
529
+ return this.$async();
530
+ }
531
+ $andSafePromise() {
532
+ return this.$async();
533
+ }
270
534
  $peek(f) {
271
535
  f(this);
272
536
  return this;
@@ -287,6 +551,9 @@ class ResultErr extends Array {
287
551
  $promise() {
288
552
  return Promise.resolve(this);
289
553
  }
554
+ *$iter() {
555
+ return;
556
+ }
290
557
  }
291
558
  /**
292
559
  * ## ResultAsync
@@ -302,44 +569,42 @@ class ResultAsync {
302
569
  return __classPrivateFieldGet(this, _ResultAsync_inner, "f").then(onfulfilled, onrejected);
303
570
  }
304
571
  /**
305
- * @TODO
306
- */
307
- async $value() {
308
- return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$value();
309
- }
310
- /**
311
- * @TODO
572
+ * The same as {@link Retuple.$expect|$expect}, except it returns a `Promise`.
312
573
  */
313
574
  async $expect() {
314
575
  return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$expect();
315
576
  }
316
577
  /**
317
- * @TODO
578
+ * The same as {@link Retuple.$unwrap|$unwrap}, except it returns a `Promise`.
318
579
  */
319
580
  async $unwrap(msg) {
320
581
  return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$unwrap(msg);
321
582
  }
322
583
  /**
323
- * @TODO
584
+ * The same as {@link Retuple.$unwrapErr|$unwrapErr}, except it returns
585
+ * a `Promise`.
324
586
  */
325
587
  async $unwrapErr(msg) {
326
588
  return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$unwrapErr(msg);
327
589
  }
328
590
  /**
329
- * @TODO
591
+ * The same as {@link Retuple.$unwrapOr|$unwrapOr}, except it returns
592
+ * a `Promise`.
330
593
  */
331
594
  async $unwrapOr(def) {
332
595
  return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$unwrapOr(def);
333
596
  }
334
597
  /**
335
- * @TODO
598
+ * The same as {@link Retuple.$unwrapOrElse|$unwrapOrElse}, except it returns
599
+ * a `Promise`.
336
600
  */
337
601
  async $unwrapOrElse(f) {
338
602
  const res = await __classPrivateFieldGet(this, _ResultAsync_inner, "f");
339
603
  return res instanceof ResultOk ? res[1] : f();
340
604
  }
341
605
  /**
342
- * @TODO
606
+ * The same as {@link Retuple.$map|$map}, except it returns
607
+ * {@link ResultAsync}.
343
608
  */
344
609
  $map(f) {
345
610
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -349,7 +614,8 @@ class ResultAsync {
349
614
  }));
350
615
  }
351
616
  /**
352
- * @TODO
617
+ * The same as {@link Retuple.$mapErr|$mapErr}, except it returns
618
+ * {@link ResultAsync}.
353
619
  */
354
620
  $mapErr(f) {
355
621
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -359,7 +625,8 @@ class ResultAsync {
359
625
  }));
360
626
  }
361
627
  /**
362
- * @TODO
628
+ * The same as {@link Retuple.$mapOr|$mapOr}, except it returns
629
+ * {@link ResultAsync}.
363
630
  */
364
631
  $mapOr(def, f) {
365
632
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -369,7 +636,8 @@ class ResultAsync {
369
636
  }));
370
637
  }
371
638
  /**
372
- * @TODO
639
+ * The same as {@link Retuple.$mapOrElse|$mapOrElse}, except it returns
640
+ * {@link ResultAsync}.
373
641
  */
374
642
  $mapOrElse(def, f) {
375
643
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -378,25 +646,36 @@ class ResultAsync {
378
646
  : new ResultOk(def(res[0]));
379
647
  }));
380
648
  }
381
- /**
382
- * @TODO
383
- */
649
+ $andAssertOr(def, condition = isTruthy) {
650
+ return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
651
+ if (res instanceof ResultErr || condition(res[1])) {
652
+ return res;
653
+ }
654
+ return asResult(await def);
655
+ }));
656
+ }
657
+ $andAssertOrElse(def, condition = isTruthy) {
658
+ return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
659
+ if (res instanceof ResultErr || condition(res[1])) {
660
+ return res;
661
+ }
662
+ return asResult(await def(res[1]));
663
+ }));
664
+ }
384
665
  $or(or) {
385
666
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
386
- return res instanceof ResultErr ? await or : res;
667
+ return res instanceof ResultErr
668
+ ? asResult(await or)
669
+ : res;
387
670
  }));
388
671
  }
389
- /**
390
- * @TODO
391
- */
392
672
  $orElse(f) {
393
673
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
394
- return res instanceof ResultErr ? await f(res[0]) : res;
674
+ return res instanceof ResultErr
675
+ ? asResult(await f(res[0]))
676
+ : res;
395
677
  }));
396
678
  }
397
- /**
398
- * @TODO
399
- */
400
679
  $orSafe(f, mapError = ensureError) {
401
680
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
402
681
  if (res instanceof ResultOk) {
@@ -410,29 +689,37 @@ class ResultAsync {
410
689
  }
411
690
  }));
412
691
  }
413
- /**
414
- * @TODO
415
- */
692
+ $orSafePromise(promise, mapError = ensureError) {
693
+ return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
694
+ if (res instanceof ResultOk) {
695
+ return res;
696
+ }
697
+ try {
698
+ return new ResultOk(await promise);
699
+ }
700
+ catch (err) {
701
+ return new ResultErr(mapError(err));
702
+ }
703
+ }));
704
+ }
416
705
  $and(and) {
417
706
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
418
- return res instanceof ResultOk ? await and : res;
707
+ return res instanceof ResultOk
708
+ ? asResult(await and)
709
+ : res;
419
710
  }));
420
711
  }
421
- /**
422
- * @TODO
423
- */
424
712
  $andThen(f) {
425
713
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
426
- return res instanceof ResultOk ? await f(res[1]) : res;
714
+ return res instanceof ResultOk
715
+ ? asResult(await f(res[1]))
716
+ : res;
427
717
  }));
428
718
  }
429
- /**
430
- * @TODO
431
- */
432
719
  $andThrough(f) {
433
720
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
434
721
  if (res instanceof ResultOk) {
435
- const through = await f(res[1]);
722
+ const through = asResult(await f(res[1]));
436
723
  if (through instanceof ResultErr) {
437
724
  return through;
438
725
  }
@@ -440,24 +727,37 @@ class ResultAsync {
440
727
  return res;
441
728
  }));
442
729
  }
443
- /**
444
- * @TODO
445
- */
446
730
  $andSafe(f, mapError = ensureError) {
447
731
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
448
732
  if (res instanceof ResultErr) {
449
733
  return res;
450
734
  }
451
735
  try {
452
- return new ResultOk(await f(res[1]));
736
+ return Ok(await f(res[1]));
453
737
  }
454
738
  catch (err) {
455
- return new ResultErr(mapError(err));
739
+ return Err(mapError(err));
740
+ }
741
+ }));
742
+ }
743
+ $andSafePromise(promise, mapError = ensureError) {
744
+ return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
745
+ if (res instanceof ResultErr) {
746
+ return res;
747
+ }
748
+ try {
749
+ return Ok(await promise);
750
+ }
751
+ catch (err) {
752
+ return Err(mapError(err));
456
753
  }
457
754
  }));
458
755
  }
459
756
  /**
460
- * @TODO
757
+ * The same as {@link Retuple.$peek|$peek}, except it:
758
+ *
759
+ * - awaits the peek function;
760
+ * - returns {@link ResultAsync}.
461
761
  */
462
762
  $peek(f) {
463
763
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -466,7 +766,10 @@ class ResultAsync {
466
766
  }));
467
767
  }
468
768
  /**
469
- * @TODO
769
+ * The same as {@link Retuple.$tap|$tap}, except it:
770
+ *
771
+ * - awaits the tap function;
772
+ * - returns {@link ResultAsync}.
470
773
  */
471
774
  $tap(f) {
472
775
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -477,7 +780,10 @@ class ResultAsync {
477
780
  }));
478
781
  }
479
782
  /**
480
- * @TODO
783
+ * The same as {@link Retuple.$tapErr|$tapErr}, except it:
784
+ *
785
+ * - awaits the tap error function;
786
+ * - returns {@link ResultAsync}.
481
787
  */
482
788
  $tapErr(f) {
483
789
  return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
@@ -488,31 +794,165 @@ class ResultAsync {
488
794
  }));
489
795
  }
490
796
  /**
491
- * @TODO
797
+ * The same as {@link Retuple.$promise|$promise}.
492
798
  */
493
799
  $promise() {
494
800
  return Promise.resolve(this);
495
801
  }
802
+ /**
803
+ * The same as {@link Retuple.$iter|$iter}, except it returns a `Promise`.
804
+ */
805
+ async $iter() {
806
+ return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$iter();
807
+ }
496
808
  }
497
809
  _ResultAsync_inner = new WeakMap();
810
+ /**
811
+ * ## ResultRetry
812
+ */
813
+ class ResultRetry extends ResultAsync {
814
+ static zero() {
815
+ return 0;
816
+ }
817
+ static delay(ms) {
818
+ return new Promise((resolve) => setTimeout(resolve, Math.min(ms, _a.MAX_TIMEOUT)));
819
+ }
820
+ static integer(value) {
821
+ if (typeof value === "number" && Number.isInteger(value)) {
822
+ return Math.max(0, value);
823
+ }
824
+ return 0;
825
+ }
826
+ constructor(f) {
827
+ super(Promise.resolve().then(() => __classPrivateFieldGet(this, _ResultRetry_promise, "f")));
828
+ _ResultRetry_f.set(this, void 0);
829
+ _ResultRetry_promise.set(this, void 0);
830
+ _ResultRetry_times.set(this, 1);
831
+ _ResultRetry_attempt.set(this, 0);
832
+ _ResultRetry_aborted.set(this, false);
833
+ _ResultRetry_abort.set(this, () => (__classPrivateFieldSet(this, _ResultRetry_aborted, true, "f")));
834
+ _ResultRetry_getDelay.set(this, _a.zero);
835
+ _ResultRetry_handler.set(this, void 0);
836
+ __classPrivateFieldSet(this, _ResultRetry_f, f, "f");
837
+ __classPrivateFieldSet(this, _ResultRetry_promise, this.drain(), "f");
838
+ }
839
+ then(onfulfilled, onrejected) {
840
+ return super.then(onfulfilled, onrejected);
841
+ }
842
+ /**
843
+ * Sets the maximum number of times the retry function can be executed,
844
+ * mutating this `ResultRetry` instance.
845
+ *
846
+ * **The default value is 1 - meaning that unless set, no retries will be
847
+ * attempted.**
848
+ *
849
+ * The retry function can be called up to the maximum number of times until
850
+ * it returns `Ok`. If it never returns `Ok`, the most recent `Err` is
851
+ * returned.
852
+ *
853
+ * This function accepts a positive integer between 1 and 100:
854
+ *
855
+ * - Integers outside of this range are clamped to the nearest valid value;
856
+ * - Any other value (NaN, Infinity, fractions, strings) are treated as 1.
857
+ *
858
+ * @example
859
+ *
860
+ * ```ts
861
+ * // Retry someResultFn up to 3 times until Ok is returned:
862
+ * const result = await Result.$retry(someResultFn).$times(3);
863
+ * ```
864
+ */
865
+ $times(times) {
866
+ __classPrivateFieldSet(this, _ResultRetry_times, Math.min(Math.max(1, _a.integer(times)), _a.MAX_RETRY), "f");
867
+ return this;
868
+ }
869
+ $delay(fnOrMs) {
870
+ if (typeof fnOrMs === "function") {
871
+ __classPrivateFieldSet(this, _ResultRetry_getDelay, fnOrMs, "f");
872
+ return this;
873
+ }
874
+ const delay = _a.integer(fnOrMs);
875
+ if (delay > 0) {
876
+ __classPrivateFieldSet(this, _ResultRetry_getDelay, () => delay, "f");
877
+ }
878
+ return this;
879
+ }
880
+ /**
881
+ * Sets a handler to be called when an attempt returns `Err`, mutating this
882
+ * `ResultRetry` instance. The handler can be used to capture information
883
+ * about each failure, and to abort early and prevent further retries.
884
+ *
885
+ * The handler function is called with `ResultRetryHandleState`, containing:
886
+ *
887
+ * - **error** - The error value from the last failed attempt;
888
+ * - **attempt** - The attempt number;
889
+ * - **abort** - A function which when called, prevents further retries.
890
+ *
891
+ * @example
892
+ *
893
+ * ```ts
894
+ * // Retry someResultFn up to 3 times until Ok is returned, logging each
895
+ * // attempt and aborting early if the error code is "UNAUTHORIZED".
896
+ * const result = await Result.$retry(someResultFn)
897
+ * .$times(3)
898
+ * .$handle(({ error, attempt, abort }) => {
899
+ * console.info(`Attempt ${attempt} failed: ${error}`);
900
+ * if (error === "UNAUTHORIZED") {
901
+ * abort();
902
+ * }
903
+ * });
904
+ * ```
905
+ */
906
+ $handle(f) {
907
+ __classPrivateFieldSet(this, _ResultRetry_handler, f, "f");
908
+ return this;
909
+ }
910
+ async drain() {
911
+ var _b;
912
+ while (__classPrivateFieldGet(this, _ResultRetry_attempt, "f") < __classPrivateFieldGet(this, _ResultRetry_times, "f")) {
913
+ const result = asResult(await __classPrivateFieldGet(this, _ResultRetry_f, "f").call(this));
914
+ __classPrivateFieldSet(this, _ResultRetry_attempt, (_b = __classPrivateFieldGet(this, _ResultRetry_attempt, "f"), _b++, _b), "f");
915
+ if (result.$isOk()) {
916
+ return result;
917
+ }
918
+ if (__classPrivateFieldGet(this, _ResultRetry_handler, "f")) {
919
+ await __classPrivateFieldGet(this, _ResultRetry_handler, "f").call(this, {
920
+ error: result[0],
921
+ attempt: __classPrivateFieldGet(this, _ResultRetry_attempt, "f"),
922
+ abort: __classPrivateFieldGet(this, _ResultRetry_abort, "f"),
923
+ });
924
+ }
925
+ if (__classPrivateFieldGet(this, _ResultRetry_aborted, "f") || __classPrivateFieldGet(this, _ResultRetry_attempt, "f") >= __classPrivateFieldGet(this, _ResultRetry_times, "f")) {
926
+ return result;
927
+ }
928
+ const delay = _a.integer(__classPrivateFieldGet(this, _ResultRetry_getDelay, "f").call(this, __classPrivateFieldGet(this, _ResultRetry_attempt, "f")));
929
+ if (delay > 0) {
930
+ await _a.delay(delay);
931
+ }
932
+ }
933
+ /* v8 ignore next */
934
+ throw new Error("Retuple: Unreachable code executed");
935
+ }
936
+ }
937
+ _a = ResultRetry, _ResultRetry_f = new WeakMap(), _ResultRetry_promise = new WeakMap(), _ResultRetry_times = new WeakMap(), _ResultRetry_attempt = new WeakMap(), _ResultRetry_aborted = new WeakMap(), _ResultRetry_abort = new WeakMap(), _ResultRetry_getDelay = new WeakMap(), _ResultRetry_handler = new WeakMap();
938
+ ResultRetry.MAX_TIMEOUT = 3600000;
939
+ ResultRetry.MAX_RETRY = 100;
940
+ function asResult(resultLike) {
941
+ if (resultLike instanceof ResultOk || resultLike instanceof ResultErr) {
942
+ return resultLike;
943
+ }
944
+ const result = resultLike[ResultLikeSymbol]();
945
+ return result.ok ? new ResultOk(result.value) : new ResultErr(result.value);
946
+ }
498
947
  function ensureError(err) {
499
948
  if (err instanceof Error) {
500
949
  return err;
501
950
  }
502
- return new RetupleThrownValueError(err);
951
+ return new RetupleCaughtValueError(err);
952
+ }
953
+ function mapTrue() {
954
+ return true;
955
+ }
956
+ function isTruthy(val) {
957
+ return !!val;
503
958
  }
504
- Object.freeze(Result);
505
- Object.freeze(ResultOk);
506
- Object.freeze(ResultErr);
507
- Object.freeze(ResultAsync);
508
- Object.freeze(RetupleUnwrapFailed);
509
- Object.freeze(RetupleUnwrapErrFailed);
510
- Object.freeze(RetupleExpectFailed);
511
- Object.freeze(RetupleThrownValueError);
512
- Object.freeze(ResultOk.prototype);
513
- Object.freeze(ResultErr.prototype);
514
- Object.freeze(ResultAsync.prototype);
515
- Object.freeze(RetupleUnwrapFailed.prototype);
516
- Object.freeze(RetupleUnwrapErrFailed.prototype);
517
- Object.freeze(RetupleExpectFailed.prototype);
518
- Object.freeze(RetupleThrownValueError.prototype);