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