retuple 1.0.0-next.2 → 1.0.0-next.21

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