retuple 1.0.0-next.3 → 1.0.0-next.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/index.cjs +931 -133
- package/dist/index.d.cts +1428 -287
- package/dist/index.d.ts +1428 -287
- package/dist/index.js +925 -125
- package/package.json +13 -10
package/dist/index.js
CHANGED
|
@@ -9,7 +9,9 @@ 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
|
+
const RetupleStackSymbol = Symbol("RetupleStackSymbol");
|
|
13
15
|
/**
|
|
14
16
|
* ## Retuple Unwrap Failed
|
|
15
17
|
*
|
|
@@ -35,7 +37,7 @@ export class RetupleUnwrapErrFailed extends Error {
|
|
|
35
37
|
/**
|
|
36
38
|
* ## Retuple Expect Failed
|
|
37
39
|
*
|
|
38
|
-
* An error which occurs when calling `$expect` on `Err`,
|
|
40
|
+
* An error which occurs when calling `$expect` on `Err`, when the value
|
|
39
41
|
* contained in the `Err` is not an instance of `Error`.
|
|
40
42
|
*/
|
|
41
43
|
export class RetupleExpectFailed extends Error {
|
|
@@ -44,6 +46,43 @@ export class RetupleExpectFailed extends Error {
|
|
|
44
46
|
this.value = value;
|
|
45
47
|
}
|
|
46
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* ## Retuple Assert Failed
|
|
51
|
+
*
|
|
52
|
+
* This error is used as the error type of a `Result` when using $assert,
|
|
53
|
+
* when no map error function is provided.
|
|
54
|
+
*/
|
|
55
|
+
export class RetupleAssertFailed extends Error {
|
|
56
|
+
constructor(value) {
|
|
57
|
+
super("Assert failed");
|
|
58
|
+
this.value = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* ## Retuple Filter Failed
|
|
63
|
+
*
|
|
64
|
+
* This error is used as the error type of a `Result` when using $filter,
|
|
65
|
+
* when no map error function is provided.
|
|
66
|
+
*/
|
|
67
|
+
export class RetupleFilterFailed extends Error {
|
|
68
|
+
constructor(value) {
|
|
69
|
+
super("Filter failed");
|
|
70
|
+
this.value = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* ## Retuple Index Failed
|
|
75
|
+
*
|
|
76
|
+
* This error is used as the error type of a `Result` when using $atIndex or
|
|
77
|
+
* $firstIndex, when no map error function is provided.
|
|
78
|
+
*/
|
|
79
|
+
export class RetupleIndexFailed extends Error {
|
|
80
|
+
constructor(index, value) {
|
|
81
|
+
super("Index failed");
|
|
82
|
+
this.index = index;
|
|
83
|
+
this.value = value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
47
86
|
/**
|
|
48
87
|
* ## Retuple Thrown Value Error
|
|
49
88
|
*
|
|
@@ -51,22 +90,24 @@ export class RetupleExpectFailed extends Error {
|
|
|
51
90
|
* thrown error or rejected value is not an instance of `Error`, and when no
|
|
52
91
|
* map error function is provided.
|
|
53
92
|
*/
|
|
54
|
-
export class
|
|
93
|
+
export class RetupleCaughtValueError extends Error {
|
|
55
94
|
constructor(value) {
|
|
56
95
|
super("Caught value was not an instance of Error");
|
|
57
96
|
this.value = value;
|
|
58
97
|
}
|
|
59
98
|
}
|
|
60
99
|
/**
|
|
61
|
-
* ## Retuple Invalid
|
|
100
|
+
* ## Retuple Invalid Union Error
|
|
62
101
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
102
|
+
* This error is thrown when attempting to construct a `Result` from a
|
|
103
|
+
* discriminated union, when the 'success' property is not boolean. In this
|
|
104
|
+
* case, it is impossible to determine whether the result should be `Ok` or
|
|
105
|
+
* `Err`.
|
|
66
106
|
*/
|
|
67
|
-
export class
|
|
107
|
+
export class RetupleInvalidUnionError extends Error {
|
|
68
108
|
constructor(value) {
|
|
69
|
-
super("Constructing a Result from
|
|
109
|
+
super("Constructing a Result from discriminated union failed, the success " +
|
|
110
|
+
"property must be boolean");
|
|
70
111
|
this.value = value;
|
|
71
112
|
}
|
|
72
113
|
}
|
|
@@ -76,22 +117,28 @@ export class RetupleInvalidResultError extends Error {
|
|
|
76
117
|
* @TODO
|
|
77
118
|
*/
|
|
78
119
|
export function Result(resultLike) {
|
|
79
|
-
|
|
80
|
-
if (err === null || err === undefined) {
|
|
81
|
-
return new ResultOk(ok);
|
|
82
|
-
}
|
|
83
|
-
if (ok === null || ok === undefined) {
|
|
84
|
-
return new ResultErr(err);
|
|
85
|
-
}
|
|
86
|
-
throw new RetupleInvalidResultError(resultLike);
|
|
120
|
+
return asResult(resultLike);
|
|
87
121
|
}
|
|
88
122
|
Result.Ok = Ok;
|
|
89
123
|
Result.Err = Err;
|
|
90
|
-
Result
|
|
91
|
-
Result
|
|
92
|
-
Result
|
|
93
|
-
Result
|
|
94
|
-
Result
|
|
124
|
+
Result.$from = $from;
|
|
125
|
+
Result.$resolve = $resolve;
|
|
126
|
+
Result.$nonNullable = $nonNullable;
|
|
127
|
+
Result.$truthy = $truthy;
|
|
128
|
+
Result.$fromUnion = $fromUnion;
|
|
129
|
+
Result.$safe = $safe;
|
|
130
|
+
Result.$safeAsync = $safeAsync;
|
|
131
|
+
Result.$safePromise = $safePromise;
|
|
132
|
+
Result.$retry = $retry;
|
|
133
|
+
Result.$safeRetry = $safeRetry;
|
|
134
|
+
Result.$all = $all;
|
|
135
|
+
Result.$allPromised = $allPromised;
|
|
136
|
+
Result.$any = $any;
|
|
137
|
+
Result.$anyPromised = $anyPromised;
|
|
138
|
+
Result.$collect = $collect;
|
|
139
|
+
Result.$collectPromised = $collectPromised;
|
|
140
|
+
Result.$pipe = $pipe;
|
|
141
|
+
Result.$pipeAsync = $pipeAsync;
|
|
95
142
|
Object.freeze(Result);
|
|
96
143
|
export function Ok(val) {
|
|
97
144
|
return new ResultOk(val);
|
|
@@ -99,43 +146,401 @@ export function Ok(val) {
|
|
|
99
146
|
export function Err(err) {
|
|
100
147
|
return new ResultErr(err);
|
|
101
148
|
}
|
|
102
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Construct a {@link Result} from a {@link ResultLike}.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
*
|
|
154
|
+
* ```ts
|
|
155
|
+
* const value: Result<T, E> | ResultLike<T, E> = someResultFn();
|
|
156
|
+
* const result: Result<T, E> = Result.$from(result);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
function $from(result) {
|
|
160
|
+
if (result instanceof ResultOk || result instanceof ResultErr) {
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
return asResult(result);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Construct a {@link ResultAsync} from a {@link ResultLikeAwaitable}.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
*
|
|
170
|
+
* ```ts
|
|
171
|
+
* const value:
|
|
172
|
+
* | Result<T, E>
|
|
173
|
+
* | ResultLike<T, E>
|
|
174
|
+
* | ResultAsync<T, E>
|
|
175
|
+
* | Promise<Result<T, E>>
|
|
176
|
+
* | Promise<ResultLike<T, E>>
|
|
177
|
+
* | PromiseLike<Result<T, E>>
|
|
178
|
+
* | PromiseLike<ResultLike<T, E>> = someResultFn();
|
|
179
|
+
*
|
|
180
|
+
* const result: ResultAsync<T, E> = Result.$resolve(result);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
function $resolve(result) {
|
|
184
|
+
switch (true) {
|
|
185
|
+
case result instanceof ResultAsync:
|
|
186
|
+
return result;
|
|
187
|
+
case result instanceof ResultOk:
|
|
188
|
+
case result instanceof ResultErr:
|
|
189
|
+
return new ResultAsync(Promise.resolve(result));
|
|
190
|
+
default:
|
|
191
|
+
return new ResultAsync(Promise.resolve(result).then((asResult)));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function $nonNullable(value, error = mapTrue) {
|
|
103
195
|
if (value !== null && value !== undefined) {
|
|
104
|
-
return
|
|
196
|
+
return Ok(value);
|
|
105
197
|
}
|
|
106
|
-
return
|
|
198
|
+
return Err(error());
|
|
107
199
|
}
|
|
108
|
-
|
|
200
|
+
function $truthy(value, error = mapTrue) {
|
|
109
201
|
if (value) {
|
|
110
|
-
return
|
|
202
|
+
return Ok(value);
|
|
111
203
|
}
|
|
112
|
-
return
|
|
204
|
+
return Err(error());
|
|
113
205
|
}
|
|
114
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Construct a {@link Result} from a common discriminated union shape. If the
|
|
208
|
+
* union is 'success' then the result is `Ok`
|
|
209
|
+
*
|
|
210
|
+
* Otherwise, the result is `Err` containing:
|
|
211
|
+
*
|
|
212
|
+
* - the returned value from the error function when provided;
|
|
213
|
+
* - or `true` otherwise.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
*
|
|
217
|
+
* ```ts
|
|
218
|
+
* const result: Result<string, Error> = Result.$truthy(
|
|
219
|
+
* username.trim(),
|
|
220
|
+
* () => new Error("Username is empty"),
|
|
221
|
+
* );
|
|
222
|
+
* ```
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
*
|
|
226
|
+
* ```ts
|
|
227
|
+
* const [err, value] = Result.$truthy("test");
|
|
228
|
+
*
|
|
229
|
+
* assert.equal(err, undefined);
|
|
230
|
+
* assert.equal(value, "test");
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
*
|
|
235
|
+
* ```ts
|
|
236
|
+
* const [err, value] = Result.$truthy("");
|
|
237
|
+
*
|
|
238
|
+
* assert.equal(err, true);
|
|
239
|
+
* assert.equal(value, undefined);
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
*
|
|
244
|
+
* ```ts
|
|
245
|
+
* const [err, value] = Result.$truthy(0, () => "error");
|
|
246
|
+
*
|
|
247
|
+
* assert.equal(err, "error");
|
|
248
|
+
* assert.equal(value, undefined);
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
function $fromUnion(union) {
|
|
252
|
+
if (union.success === true) {
|
|
253
|
+
return Ok(union.data);
|
|
254
|
+
}
|
|
255
|
+
if (union.success === false) {
|
|
256
|
+
return Err(union.error);
|
|
257
|
+
}
|
|
258
|
+
throw new RetupleInvalidUnionError(union);
|
|
259
|
+
}
|
|
260
|
+
function $safe(f, mapError = ensureError) {
|
|
115
261
|
try {
|
|
116
|
-
return
|
|
262
|
+
return Ok(f());
|
|
117
263
|
}
|
|
118
264
|
catch (err) {
|
|
119
|
-
return
|
|
265
|
+
return Err(mapError(err));
|
|
120
266
|
}
|
|
121
267
|
}
|
|
122
|
-
|
|
268
|
+
function $safeAsync(f, mapError = ensureError) {
|
|
123
269
|
return new ResultAsync((async () => {
|
|
124
270
|
try {
|
|
125
|
-
return
|
|
271
|
+
return Ok(await f());
|
|
126
272
|
}
|
|
127
273
|
catch (err) {
|
|
128
|
-
return
|
|
274
|
+
return Err(await mapError(err));
|
|
129
275
|
}
|
|
130
276
|
})());
|
|
131
277
|
}
|
|
132
|
-
|
|
278
|
+
function $safePromise(promise, mapError = ensureError) {
|
|
133
279
|
return new ResultAsync(promise.then((Ok), async (err) => Err(await mapError(err))));
|
|
134
280
|
}
|
|
135
281
|
/**
|
|
136
|
-
*
|
|
282
|
+
* Construct a {@link ResultRetry} from a function which returns a
|
|
283
|
+
* {@link Result}. The function will be retried based on provided retry
|
|
284
|
+
* settings and eventually return a `Result`. No attempt is made to catch
|
|
285
|
+
* thrown errors or promise rejections.
|
|
137
286
|
*
|
|
138
|
-
* @
|
|
287
|
+
* To retry a potentially unsafe function, use {@link Result.$safeRetry}.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
*
|
|
291
|
+
* ```ts
|
|
292
|
+
* // Retry someResultFn up to 3 times until Ok is returned,
|
|
293
|
+
* // with a 1 second delay between each invocation:
|
|
294
|
+
* const result = await Result.$retry(someResultFn).$times(3).$delay(1000);
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
function $retry(f) {
|
|
298
|
+
return new ResultRetry(f);
|
|
299
|
+
}
|
|
300
|
+
function $safeRetry(f, mapError = ensureError) {
|
|
301
|
+
return new ResultRetry(async () => {
|
|
302
|
+
try {
|
|
303
|
+
return Ok(await f());
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
return Err(mapError(err));
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Construct a {@link Result} from an array of results. If all are Ok,
|
|
312
|
+
* then the result is `Ok` containing a tuple of values. Otherwise,
|
|
313
|
+
* the result is `Err` containing the first error encountered.
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
*
|
|
317
|
+
* ```ts
|
|
318
|
+
* const result: Result<[string, number], Error | string> = Result.$all([
|
|
319
|
+
* Result.$truthy(stringValue, () => new Error("Invalid string")),
|
|
320
|
+
* Result.$truthy(numberValue, () => "Invalid number"),
|
|
321
|
+
* ]);
|
|
322
|
+
* ```
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
*
|
|
326
|
+
* ```ts
|
|
327
|
+
* const tuple: [1, 2, 3] = Result.$all([
|
|
328
|
+
* Ok(1),
|
|
329
|
+
* Ok(2),
|
|
330
|
+
* Ok(3),
|
|
331
|
+
* ]).$unwrap();
|
|
332
|
+
* ```
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
*
|
|
336
|
+
* ```ts
|
|
337
|
+
* const error: "error" = Result.$all([
|
|
338
|
+
* Ok(1),
|
|
339
|
+
* Err("error"),
|
|
340
|
+
* Ok(3),
|
|
341
|
+
* ]).$unwrapErr();
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
function $all(results) {
|
|
345
|
+
const oks = [];
|
|
346
|
+
for (const result of results) {
|
|
347
|
+
const { ok, value } = result[ResultLikeSymbol]();
|
|
348
|
+
if (ok) {
|
|
349
|
+
oks.push(value);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
return Err(value);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return Ok(oks);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* The same as {@link Result.$all|$all} except it accepts result-like
|
|
359
|
+
* promises and returns {@link ResultAsync}.
|
|
360
|
+
*/
|
|
361
|
+
function $allPromised(results) {
|
|
362
|
+
return new ResultAsync(new Promise((resolve, reject) => {
|
|
363
|
+
void Promise.all(results.map((result) => Promise.resolve(result).then((result) => {
|
|
364
|
+
const { ok, value } = result[ResultLikeSymbol]();
|
|
365
|
+
return ok ? value : Promise.reject(value);
|
|
366
|
+
}, (err) => {
|
|
367
|
+
reject(err);
|
|
368
|
+
// Because reject has been called, we can safely return an
|
|
369
|
+
// empty rejection to ensure we don't end up with undefined
|
|
370
|
+
// in the Ok path. The subsequent call to resolve will not
|
|
371
|
+
// change the state of the Promise.
|
|
372
|
+
return Promise.reject();
|
|
373
|
+
}))).then((values) => resolve(Ok(values)), (err) => resolve(Err(err)));
|
|
374
|
+
}));
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Construct a {@link Result} from an array of results. If any are Ok,
|
|
378
|
+
* then the result is `Ok` containing the first value encountered.
|
|
379
|
+
* Otherwise, the result is `Err` containing a tuple of errors.
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
*
|
|
383
|
+
* ```ts
|
|
384
|
+
* const result: Result<string | number, [Error, string]> = Result.$any([
|
|
385
|
+
* Result.$truthy(stringValue, () => new Error("Invalid string")),
|
|
386
|
+
* Result.$truthy(numberValue, () => "Invalid number"),
|
|
387
|
+
* ]);
|
|
388
|
+
* ```
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
*
|
|
392
|
+
* ```ts
|
|
393
|
+
* const tuple: 2 = Result.$any([
|
|
394
|
+
* Err("error1"),
|
|
395
|
+
* Ok(2),
|
|
396
|
+
* Err("error3"),
|
|
397
|
+
* ]).$unwrap();
|
|
398
|
+
* ```
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
*
|
|
402
|
+
* ```ts
|
|
403
|
+
* const error: ["error1", "error2", "error3"] = Result.$any([
|
|
404
|
+
* Err("error1"),
|
|
405
|
+
* Err("error2"),
|
|
406
|
+
* Err("error3"),
|
|
407
|
+
* ]).$unwrapErr();
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
function $any(results) {
|
|
411
|
+
const errs = [];
|
|
412
|
+
for (const result of results) {
|
|
413
|
+
const { ok, value } = result[ResultLikeSymbol]();
|
|
414
|
+
if (ok) {
|
|
415
|
+
return Ok(value);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
errs.push(value);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return Err(errs);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* The same as {@link Result.$any|$any} except it accepts result-like
|
|
425
|
+
* promises and returns {@link ResultAsync}.
|
|
426
|
+
*/
|
|
427
|
+
function $anyPromised(results) {
|
|
428
|
+
return new ResultAsync(new Promise((resolve, reject) => {
|
|
429
|
+
let rejected = false;
|
|
430
|
+
void Promise.any(results.map((result) => Promise.resolve(result).then((result) => {
|
|
431
|
+
const { ok, value } = result[ResultLikeSymbol]();
|
|
432
|
+
return ok ? value : Promise.reject(value);
|
|
433
|
+
}, (err) => {
|
|
434
|
+
rejected = true;
|
|
435
|
+
return Promise.reject(err);
|
|
436
|
+
}))).then((value) => resolve(Ok(value)), (err) => err instanceof AggregateError && rejected === false
|
|
437
|
+
? resolve(Err(err.errors))
|
|
438
|
+
: reject(err));
|
|
439
|
+
}));
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Construct a {@link Result} from an object of results. If all are Ok,
|
|
443
|
+
* then the result is `Ok` containing an object of the values. Otherwise,
|
|
444
|
+
* the result is `Err` containing the first error encountered.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
*
|
|
448
|
+
* ```ts
|
|
449
|
+
* const result: Result<
|
|
450
|
+
* { test1: string, test2: number},
|
|
451
|
+
* string | Error,
|
|
452
|
+
* > = Result.$collect({
|
|
453
|
+
* test1: Result.$truthy(stringValue, () => new Error("Invalid string")),
|
|
454
|
+
* test2: Result.$truthy(numberValue, () => "Invalid number"),
|
|
455
|
+
* ]);
|
|
456
|
+
* ```
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
*
|
|
460
|
+
* ```ts
|
|
461
|
+
* const object: { a: 1, b: 2 } = Result.$collect({
|
|
462
|
+
* a: Ok(1),
|
|
463
|
+
* b: Ok(2),
|
|
464
|
+
* }).$unwrap();
|
|
465
|
+
* ```
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
*
|
|
469
|
+
* ```ts
|
|
470
|
+
* const error: "error" = Result.$collect({
|
|
471
|
+
* a: Ok(1),
|
|
472
|
+
* b: Err("error"),
|
|
473
|
+
* }).$unwrapErr();
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
function $collect(results) {
|
|
477
|
+
const oks = {};
|
|
478
|
+
for (const [key, result] of Object.entries(results)) {
|
|
479
|
+
const { ok, value } = result[ResultLikeSymbol]();
|
|
480
|
+
if (ok) {
|
|
481
|
+
oks[key] = value;
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
return Err(value);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return Ok(oks);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* The same as {@link Result.$collect|$collect} except it accepts result-like
|
|
491
|
+
* promises and returns {@link ResultAsync}.
|
|
492
|
+
*/
|
|
493
|
+
function $collectPromised(results) {
|
|
494
|
+
return new ResultAsync(new Promise((resolve, reject) => {
|
|
495
|
+
void Promise.all(Object.entries(results).map(([key, result]) => Promise.resolve(result).then((result) => {
|
|
496
|
+
const { ok, value } = result[ResultLikeSymbol]();
|
|
497
|
+
return ok ? [key, value] : Promise.reject(value);
|
|
498
|
+
}, (err) => {
|
|
499
|
+
reject(err);
|
|
500
|
+
// Because reject has been called, we can safely return an
|
|
501
|
+
// empty rejection to ensure we don't end up with undefined
|
|
502
|
+
// in the Ok path. The subsequent call to resolve will not
|
|
503
|
+
// change the state of the Promise.
|
|
504
|
+
return Promise.reject();
|
|
505
|
+
}))).then((values) => resolve(Ok(Object.fromEntries(values))), (err) => resolve(Err(err)));
|
|
506
|
+
}));
|
|
507
|
+
}
|
|
508
|
+
function $pipe(f0, ...fnx) {
|
|
509
|
+
const first = asResult(f0());
|
|
510
|
+
if (first instanceof ResultErr) {
|
|
511
|
+
return first;
|
|
512
|
+
}
|
|
513
|
+
let current = first[1];
|
|
514
|
+
for (const fn of fnx) {
|
|
515
|
+
const result = asResult(fn(current));
|
|
516
|
+
if (result instanceof ResultErr) {
|
|
517
|
+
return result;
|
|
518
|
+
}
|
|
519
|
+
current = result[1];
|
|
520
|
+
}
|
|
521
|
+
return Ok(current);
|
|
522
|
+
}
|
|
523
|
+
function $pipeAsync(f0, ...fnx) {
|
|
524
|
+
return new ResultAsync((async () => {
|
|
525
|
+
const first = asResult(await f0());
|
|
526
|
+
if (first instanceof ResultErr) {
|
|
527
|
+
return first;
|
|
528
|
+
}
|
|
529
|
+
let current = first[1];
|
|
530
|
+
for (const fn of fnx) {
|
|
531
|
+
const result = asResult(await fn(current));
|
|
532
|
+
if (result instanceof ResultErr) {
|
|
533
|
+
return result;
|
|
534
|
+
}
|
|
535
|
+
current = result[1];
|
|
536
|
+
}
|
|
537
|
+
return Ok(current);
|
|
538
|
+
})());
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* ## ResultOk
|
|
542
|
+
*
|
|
543
|
+
* This is the `Ok` variant of a `Result`, used internally and not exported.
|
|
139
544
|
*/
|
|
140
545
|
class ResultOk extends Array {
|
|
141
546
|
constructor(value) {
|
|
@@ -143,13 +548,10 @@ class ResultOk extends Array {
|
|
|
143
548
|
this[0] = undefined;
|
|
144
549
|
this[1] = value;
|
|
145
550
|
}
|
|
146
|
-
|
|
147
|
-
return this[1];
|
|
148
|
-
}
|
|
149
|
-
$toNativeTuple() {
|
|
150
|
-
return [undefined, this[1]];
|
|
551
|
+
[ResultLikeSymbol]() {
|
|
552
|
+
return { ok: true, value: this[1] };
|
|
151
553
|
}
|
|
152
|
-
|
|
554
|
+
toJSON() {
|
|
153
555
|
return this[1];
|
|
154
556
|
}
|
|
155
557
|
$isOk() {
|
|
@@ -180,50 +582,120 @@ class ResultOk extends Array {
|
|
|
180
582
|
return this[1];
|
|
181
583
|
}
|
|
182
584
|
$map(f) {
|
|
183
|
-
return
|
|
585
|
+
return Ok(f(this[1]));
|
|
184
586
|
}
|
|
185
587
|
$mapErr() {
|
|
186
588
|
return this;
|
|
187
589
|
}
|
|
188
590
|
$mapOr(_def, f) {
|
|
189
|
-
return
|
|
591
|
+
return Ok(f(this[1]));
|
|
190
592
|
}
|
|
191
593
|
$mapOrElse(_def, f) {
|
|
192
|
-
return
|
|
193
|
-
}
|
|
194
|
-
$
|
|
195
|
-
return
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
594
|
+
return Ok(f(this[1]));
|
|
595
|
+
}
|
|
596
|
+
$assert(mapError) {
|
|
597
|
+
return this[1]
|
|
598
|
+
? this
|
|
599
|
+
: Err(mapError
|
|
600
|
+
? mapError(this[1])
|
|
601
|
+
: new RetupleAssertFailed(this[1]));
|
|
602
|
+
}
|
|
603
|
+
$filter(filter, mapError) {
|
|
604
|
+
return filter(this[1])
|
|
605
|
+
? this
|
|
606
|
+
: Err(mapError ? mapError(this[1]) : new RetupleFilterFailed(this[1]));
|
|
607
|
+
}
|
|
608
|
+
$atIndex(index, mapError) {
|
|
609
|
+
const element = this[1][index];
|
|
610
|
+
return element
|
|
611
|
+
? Ok(element)
|
|
612
|
+
: Err(mapError
|
|
613
|
+
? mapError(this[1])
|
|
614
|
+
: new RetupleIndexFailed(index, this[1]));
|
|
615
|
+
}
|
|
616
|
+
$firstIndex(mapError) {
|
|
617
|
+
const first = this[1][0];
|
|
618
|
+
return first
|
|
619
|
+
? Ok(first)
|
|
620
|
+
: Err(mapError
|
|
621
|
+
? mapError(this[1])
|
|
622
|
+
: new RetupleIndexFailed(0, this[1]));
|
|
199
623
|
}
|
|
200
624
|
$or() {
|
|
201
625
|
return this;
|
|
202
626
|
}
|
|
627
|
+
$orAsync() {
|
|
628
|
+
return this.$async();
|
|
629
|
+
}
|
|
203
630
|
$orElse() {
|
|
204
631
|
return this;
|
|
205
632
|
}
|
|
633
|
+
$orElseAsync() {
|
|
634
|
+
return this.$async();
|
|
635
|
+
}
|
|
206
636
|
$orSafe() {
|
|
207
637
|
return this;
|
|
208
638
|
}
|
|
639
|
+
$orSafeAsync() {
|
|
640
|
+
return this.$async();
|
|
641
|
+
}
|
|
642
|
+
$orSafePromise() {
|
|
643
|
+
return this.$async();
|
|
644
|
+
}
|
|
209
645
|
$and(and) {
|
|
210
|
-
return and;
|
|
646
|
+
return asResult(and);
|
|
647
|
+
}
|
|
648
|
+
$andAsync(and) {
|
|
649
|
+
return this.$async().$and(and);
|
|
211
650
|
}
|
|
212
651
|
$andThen(f) {
|
|
213
|
-
return f(this[1]);
|
|
652
|
+
return asResult(f(this[1]));
|
|
653
|
+
}
|
|
654
|
+
$andStack(f) {
|
|
655
|
+
const res = asResult(f(this[1]));
|
|
656
|
+
if (res instanceof ResultErr) {
|
|
657
|
+
return res;
|
|
658
|
+
}
|
|
659
|
+
if (this[1] instanceof RetupleStack) {
|
|
660
|
+
return Ok(new RetupleStack(...this[1], res[1]));
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
return Ok(new RetupleStack(this[1], res[1]));
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
$andThenAsync(f) {
|
|
667
|
+
return this.$async().$andThen(f);
|
|
668
|
+
}
|
|
669
|
+
$andStackAsync(f) {
|
|
670
|
+
return this.$async().$andStack(f);
|
|
214
671
|
}
|
|
215
672
|
$andThrough(f) {
|
|
216
|
-
const res = f(this[1]);
|
|
673
|
+
const res = asResult(f(this[1]));
|
|
217
674
|
return res instanceof ResultErr ? res : this;
|
|
218
675
|
}
|
|
676
|
+
$andThroughAsync(f) {
|
|
677
|
+
return this.$async().$andThrough(f);
|
|
678
|
+
}
|
|
219
679
|
$andSafe(f, mapError = ensureError) {
|
|
220
680
|
try {
|
|
221
|
-
return
|
|
681
|
+
return Ok(f(this[1]));
|
|
222
682
|
}
|
|
223
683
|
catch (err) {
|
|
224
|
-
return
|
|
684
|
+
return Err(mapError(err));
|
|
225
685
|
}
|
|
226
686
|
}
|
|
687
|
+
$andSafeAsync(f, mapError = ensureError) {
|
|
688
|
+
return this.$async().$andSafe(f, mapError);
|
|
689
|
+
}
|
|
690
|
+
$andSafePromise(promise, mapError = ensureError) {
|
|
691
|
+
return this.$async().$andSafePromise(promise, mapError);
|
|
692
|
+
}
|
|
693
|
+
$andPipe(f0, ...fx) {
|
|
694
|
+
return Result.$pipe(() => f0(this[1]), ...fx);
|
|
695
|
+
}
|
|
696
|
+
$andPipeAsync(f0, ...fx) {
|
|
697
|
+
return Result.$pipeAsync(() => f0(this[1]), ...fx);
|
|
698
|
+
}
|
|
227
699
|
$peek(f) {
|
|
228
700
|
f(this);
|
|
229
701
|
return this;
|
|
@@ -244,11 +716,14 @@ class ResultOk extends Array {
|
|
|
244
716
|
$promise() {
|
|
245
717
|
return Promise.resolve(this);
|
|
246
718
|
}
|
|
719
|
+
*$iter() {
|
|
720
|
+
yield* this[1];
|
|
721
|
+
}
|
|
247
722
|
}
|
|
248
723
|
/**
|
|
249
|
-
* ##
|
|
724
|
+
* ## ResultErr
|
|
250
725
|
*
|
|
251
|
-
*
|
|
726
|
+
* This is the `Err` variant of a `Result`, used internally and not exported.
|
|
252
727
|
*/
|
|
253
728
|
class ResultErr extends Array {
|
|
254
729
|
constructor(err) {
|
|
@@ -256,15 +731,12 @@ class ResultErr extends Array {
|
|
|
256
731
|
this[0] = err;
|
|
257
732
|
this[1] = undefined;
|
|
258
733
|
}
|
|
734
|
+
[ResultLikeSymbol]() {
|
|
735
|
+
return { ok: false, value: this[0] };
|
|
736
|
+
}
|
|
259
737
|
toJSON() {
|
|
260
738
|
return null;
|
|
261
739
|
}
|
|
262
|
-
$toNativeTuple() {
|
|
263
|
-
return [this[0], undefined];
|
|
264
|
-
}
|
|
265
|
-
$value() {
|
|
266
|
-
return this[0];
|
|
267
|
-
}
|
|
268
740
|
$isOk() {
|
|
269
741
|
return false;
|
|
270
742
|
}
|
|
@@ -299,46 +771,91 @@ class ResultErr extends Array {
|
|
|
299
771
|
return this;
|
|
300
772
|
}
|
|
301
773
|
$mapErr(f) {
|
|
302
|
-
return
|
|
774
|
+
return Err(f(this[0]));
|
|
303
775
|
}
|
|
304
776
|
$mapOr(def) {
|
|
305
|
-
return
|
|
777
|
+
return Ok(def);
|
|
306
778
|
}
|
|
307
779
|
$mapOrElse(def) {
|
|
308
|
-
return
|
|
780
|
+
return Ok(def(this[0]));
|
|
309
781
|
}
|
|
310
|
-
$
|
|
782
|
+
$assert() {
|
|
311
783
|
return this;
|
|
312
784
|
}
|
|
313
|
-
$
|
|
785
|
+
$filter() {
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
$atIndex() {
|
|
789
|
+
return this;
|
|
790
|
+
}
|
|
791
|
+
$firstIndex() {
|
|
314
792
|
return this;
|
|
315
793
|
}
|
|
316
794
|
$or(or) {
|
|
317
|
-
return or;
|
|
795
|
+
return asResult(or);
|
|
796
|
+
}
|
|
797
|
+
$orAsync(or) {
|
|
798
|
+
return this.$async().$or(or);
|
|
318
799
|
}
|
|
319
800
|
$orElse(f) {
|
|
320
|
-
return f(this[0]);
|
|
801
|
+
return asResult(f(this[0]));
|
|
802
|
+
}
|
|
803
|
+
$orElseAsync(f) {
|
|
804
|
+
return this.$async().$orElse(f);
|
|
321
805
|
}
|
|
322
806
|
$orSafe(f, mapError = ensureError) {
|
|
323
807
|
try {
|
|
324
|
-
return
|
|
808
|
+
return Ok(f(this[0]));
|
|
325
809
|
}
|
|
326
810
|
catch (err) {
|
|
327
|
-
return
|
|
811
|
+
return Err(mapError(err));
|
|
328
812
|
}
|
|
329
813
|
}
|
|
814
|
+
$orSafeAsync(f, mapError = ensureError) {
|
|
815
|
+
return this.$async().$orSafe(f, mapError);
|
|
816
|
+
}
|
|
817
|
+
$orSafePromise(promise, mapError = ensureError) {
|
|
818
|
+
return this.$async().$orSafePromise(promise, mapError);
|
|
819
|
+
}
|
|
330
820
|
$and() {
|
|
331
821
|
return this;
|
|
332
822
|
}
|
|
823
|
+
$andAsync() {
|
|
824
|
+
return this.$async();
|
|
825
|
+
}
|
|
333
826
|
$andThen() {
|
|
334
827
|
return this;
|
|
335
828
|
}
|
|
829
|
+
$andStack() {
|
|
830
|
+
return this;
|
|
831
|
+
}
|
|
832
|
+
$andThenAsync() {
|
|
833
|
+
return this.$async();
|
|
834
|
+
}
|
|
835
|
+
$andStackAsync() {
|
|
836
|
+
return this.$async();
|
|
837
|
+
}
|
|
336
838
|
$andThrough() {
|
|
337
839
|
return this;
|
|
338
840
|
}
|
|
841
|
+
$andThroughAsync() {
|
|
842
|
+
return this.$async();
|
|
843
|
+
}
|
|
339
844
|
$andSafe() {
|
|
340
845
|
return this;
|
|
341
846
|
}
|
|
847
|
+
$andSafeAsync() {
|
|
848
|
+
return this.$async();
|
|
849
|
+
}
|
|
850
|
+
$andSafePromise() {
|
|
851
|
+
return this.$async();
|
|
852
|
+
}
|
|
853
|
+
$andPipe() {
|
|
854
|
+
return this;
|
|
855
|
+
}
|
|
856
|
+
$andPipeAsync() {
|
|
857
|
+
return this.$async();
|
|
858
|
+
}
|
|
342
859
|
$peek(f) {
|
|
343
860
|
f(this);
|
|
344
861
|
return this;
|
|
@@ -359,6 +876,9 @@ class ResultErr extends Array {
|
|
|
359
876
|
$promise() {
|
|
360
877
|
return Promise.resolve(this);
|
|
361
878
|
}
|
|
879
|
+
*$iter() {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
362
882
|
}
|
|
363
883
|
/**
|
|
364
884
|
* ## ResultAsync
|
|
@@ -374,44 +894,79 @@ class ResultAsync {
|
|
|
374
894
|
return __classPrivateFieldGet(this, _ResultAsync_inner, "f").then(onfulfilled, onrejected);
|
|
375
895
|
}
|
|
376
896
|
/**
|
|
377
|
-
* @
|
|
378
|
-
*/
|
|
379
|
-
async $value() {
|
|
380
|
-
return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$value();
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* @TODO
|
|
897
|
+
* The same as {@link Retuple.$expect|$expect}, except it returns a `Promise`.
|
|
384
898
|
*/
|
|
385
899
|
async $expect() {
|
|
386
900
|
return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$expect();
|
|
387
901
|
}
|
|
388
902
|
/**
|
|
389
|
-
* @
|
|
903
|
+
* The same as {@link Retuple.$unwrap|$unwrap}, except it returns a `Promise`.
|
|
390
904
|
*/
|
|
391
905
|
async $unwrap(msg) {
|
|
392
906
|
return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$unwrap(msg);
|
|
393
907
|
}
|
|
394
908
|
/**
|
|
395
|
-
*
|
|
909
|
+
* Resolves this `ResultAsync` using the provided resolver. The resolver
|
|
910
|
+
* receives a promise which resolves when the result is `Ok` and rejects if
|
|
911
|
+
* the result is `Err`.
|
|
912
|
+
*
|
|
913
|
+
* This method should only be called when the `E` type extends `Error`. This
|
|
914
|
+
* is enforced with a type constraint. If the error value is not an instance
|
|
915
|
+
* of Error, the promise rejects with `RetupleExpectFailed`.
|
|
916
|
+
*
|
|
917
|
+
* @example
|
|
918
|
+
*
|
|
919
|
+
* ```ts
|
|
920
|
+
* async function resolver(promise: Promise<URL>): string {
|
|
921
|
+
* try {
|
|
922
|
+
* const url = await promise;
|
|
923
|
+
*
|
|
924
|
+
* return url.toString();
|
|
925
|
+
* } catch (cause) {
|
|
926
|
+
* throw new Error("Not a valid URL", { cause });
|
|
927
|
+
* }
|
|
928
|
+
* }
|
|
929
|
+
*
|
|
930
|
+
* const urlString = await Result.$safeAsync(() => getDataAsync())
|
|
931
|
+
* .$andSafe((data) => new URL(data.url))
|
|
932
|
+
* .$resolve(resolver);
|
|
933
|
+
* ```
|
|
934
|
+
*/
|
|
935
|
+
async $resolve(resolver) {
|
|
936
|
+
return __classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (result) => {
|
|
937
|
+
if (result instanceof ResultOk) {
|
|
938
|
+
return await resolver(Promise.resolve(result[1]));
|
|
939
|
+
}
|
|
940
|
+
return await resolver(Promise.reject(result[0] instanceof Error
|
|
941
|
+
? result[0]
|
|
942
|
+
: new RetupleExpectFailed(result[0])));
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* The same as {@link Retuple.$unwrapErr|$unwrapErr}, except it returns
|
|
947
|
+
* a `Promise`.
|
|
396
948
|
*/
|
|
397
949
|
async $unwrapErr(msg) {
|
|
398
950
|
return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$unwrapErr(msg);
|
|
399
951
|
}
|
|
400
952
|
/**
|
|
401
|
-
* @
|
|
953
|
+
* The same as {@link Retuple.$unwrapOr|$unwrapOr}, except it returns
|
|
954
|
+
* a `Promise`.
|
|
402
955
|
*/
|
|
403
956
|
async $unwrapOr(def) {
|
|
404
957
|
return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$unwrapOr(def);
|
|
405
958
|
}
|
|
406
959
|
/**
|
|
407
|
-
* @
|
|
960
|
+
* The same as {@link Retuple.$unwrapOrElse|$unwrapOrElse}, except it returns
|
|
961
|
+
* a `Promise`.
|
|
408
962
|
*/
|
|
409
963
|
async $unwrapOrElse(f) {
|
|
410
964
|
const res = await __classPrivateFieldGet(this, _ResultAsync_inner, "f");
|
|
411
965
|
return res instanceof ResultOk ? res[1] : f();
|
|
412
966
|
}
|
|
413
967
|
/**
|
|
414
|
-
* @
|
|
968
|
+
* The same as {@link Retuple.$map|$map}, except it returns
|
|
969
|
+
* {@link ResultAsync}.
|
|
415
970
|
*/
|
|
416
971
|
$map(f) {
|
|
417
972
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -421,7 +976,8 @@ class ResultAsync {
|
|
|
421
976
|
}));
|
|
422
977
|
}
|
|
423
978
|
/**
|
|
424
|
-
* @
|
|
979
|
+
* The same as {@link Retuple.$mapErr|$mapErr}, except it returns
|
|
980
|
+
* {@link ResultAsync}.
|
|
425
981
|
*/
|
|
426
982
|
$mapErr(f) {
|
|
427
983
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -431,7 +987,8 @@ class ResultAsync {
|
|
|
431
987
|
}));
|
|
432
988
|
}
|
|
433
989
|
/**
|
|
434
|
-
* @
|
|
990
|
+
* The same as {@link Retuple.$mapOr|$mapOr}, except it returns
|
|
991
|
+
* {@link ResultAsync}.
|
|
435
992
|
*/
|
|
436
993
|
$mapOr(def, f) {
|
|
437
994
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -441,7 +998,8 @@ class ResultAsync {
|
|
|
441
998
|
}));
|
|
442
999
|
}
|
|
443
1000
|
/**
|
|
444
|
-
* @
|
|
1001
|
+
* The same as {@link Retuple.$mapOrElse|$mapOrElse}, except it returns
|
|
1002
|
+
* {@link ResultAsync}.
|
|
445
1003
|
*/
|
|
446
1004
|
$mapOrElse(def, f) {
|
|
447
1005
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -450,36 +1008,68 @@ class ResultAsync {
|
|
|
450
1008
|
: new ResultOk(def(res[0]));
|
|
451
1009
|
}));
|
|
452
1010
|
}
|
|
453
|
-
$
|
|
1011
|
+
$assert(mapError) {
|
|
454
1012
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
455
|
-
if (res instanceof ResultErr
|
|
1013
|
+
if (res instanceof ResultErr) {
|
|
456
1014
|
return res;
|
|
457
1015
|
}
|
|
458
|
-
return
|
|
1016
|
+
return res[1]
|
|
1017
|
+
? res
|
|
1018
|
+
: Err(mapError
|
|
1019
|
+
? mapError(res[1])
|
|
1020
|
+
: new RetupleAssertFailed(res[1]));
|
|
459
1021
|
}));
|
|
460
1022
|
}
|
|
461
|
-
$
|
|
1023
|
+
$filter(check, mapError) {
|
|
462
1024
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
463
|
-
if (res instanceof ResultErr
|
|
1025
|
+
if (res instanceof ResultErr) {
|
|
464
1026
|
return res;
|
|
465
1027
|
}
|
|
466
|
-
return
|
|
1028
|
+
return check(res[1])
|
|
1029
|
+
? res
|
|
1030
|
+
: Err(mapError
|
|
1031
|
+
? mapError(res[1])
|
|
1032
|
+
: new RetupleFilterFailed(res[1]));
|
|
1033
|
+
}));
|
|
1034
|
+
}
|
|
1035
|
+
$atIndex(index, mapError) {
|
|
1036
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then((res) => {
|
|
1037
|
+
if (res instanceof ResultErr) {
|
|
1038
|
+
return res;
|
|
1039
|
+
}
|
|
1040
|
+
const element = res[1][index];
|
|
1041
|
+
return element
|
|
1042
|
+
? Ok(element)
|
|
1043
|
+
: Err(mapError
|
|
1044
|
+
? mapError(res[1])
|
|
1045
|
+
: new RetupleIndexFailed(index, res[1]));
|
|
1046
|
+
}));
|
|
1047
|
+
}
|
|
1048
|
+
$firstIndex(mapError) {
|
|
1049
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then((res) => {
|
|
1050
|
+
if (res instanceof ResultErr) {
|
|
1051
|
+
return res;
|
|
1052
|
+
}
|
|
1053
|
+
const first = res[1][0];
|
|
1054
|
+
return first
|
|
1055
|
+
? Ok(first)
|
|
1056
|
+
: Err(mapError
|
|
1057
|
+
? mapError(res[1])
|
|
1058
|
+
: new RetupleIndexFailed(0, res[1]));
|
|
467
1059
|
}));
|
|
468
1060
|
}
|
|
469
|
-
/**
|
|
470
|
-
* @TODO
|
|
471
|
-
*/
|
|
472
1061
|
$or(or) {
|
|
473
1062
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
474
|
-
return res instanceof ResultErr
|
|
1063
|
+
return res instanceof ResultErr
|
|
1064
|
+
? asResult(await or)
|
|
1065
|
+
: res;
|
|
475
1066
|
}));
|
|
476
1067
|
}
|
|
477
|
-
/**
|
|
478
|
-
* @TODO
|
|
479
|
-
*/
|
|
480
1068
|
$orElse(f) {
|
|
481
1069
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
482
|
-
return res instanceof ResultErr
|
|
1070
|
+
return res instanceof ResultErr
|
|
1071
|
+
? asResult(await f(res[0]))
|
|
1072
|
+
: res;
|
|
483
1073
|
}));
|
|
484
1074
|
}
|
|
485
1075
|
$orSafe(f, mapError = ensureError) {
|
|
@@ -495,29 +1085,52 @@ class ResultAsync {
|
|
|
495
1085
|
}
|
|
496
1086
|
}));
|
|
497
1087
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
1088
|
+
$orSafePromise(promise, mapError = ensureError) {
|
|
1089
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
1090
|
+
if (res instanceof ResultOk) {
|
|
1091
|
+
return res;
|
|
1092
|
+
}
|
|
1093
|
+
try {
|
|
1094
|
+
return new ResultOk(await promise);
|
|
1095
|
+
}
|
|
1096
|
+
catch (err) {
|
|
1097
|
+
return new ResultErr(mapError(err));
|
|
1098
|
+
}
|
|
1099
|
+
}));
|
|
1100
|
+
}
|
|
501
1101
|
$and(and) {
|
|
502
1102
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
503
|
-
return res instanceof ResultOk
|
|
1103
|
+
return res instanceof ResultOk
|
|
1104
|
+
? asResult(await and)
|
|
1105
|
+
: res;
|
|
504
1106
|
}));
|
|
505
1107
|
}
|
|
506
|
-
/**
|
|
507
|
-
* @TODO
|
|
508
|
-
*/
|
|
509
1108
|
$andThen(f) {
|
|
510
1109
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
511
|
-
return res instanceof ResultOk
|
|
1110
|
+
return res instanceof ResultOk
|
|
1111
|
+
? asResult(await f(res[1]))
|
|
1112
|
+
: res;
|
|
1113
|
+
}));
|
|
1114
|
+
}
|
|
1115
|
+
$andStack(f) {
|
|
1116
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
1117
|
+
if (res instanceof ResultErr) {
|
|
1118
|
+
return res;
|
|
1119
|
+
}
|
|
1120
|
+
const resThen = asResult(await f(res[1]));
|
|
1121
|
+
if (resThen instanceof ResultErr) {
|
|
1122
|
+
return resThen;
|
|
1123
|
+
}
|
|
1124
|
+
if (res[1] instanceof RetupleStack) {
|
|
1125
|
+
return Ok(new RetupleStack(...res[1], resThen[1]));
|
|
1126
|
+
}
|
|
1127
|
+
return Ok(new RetupleStack(res[1], resThen[1]));
|
|
512
1128
|
}));
|
|
513
1129
|
}
|
|
514
|
-
/**
|
|
515
|
-
* @TODO
|
|
516
|
-
*/
|
|
517
1130
|
$andThrough(f) {
|
|
518
1131
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
519
1132
|
if (res instanceof ResultOk) {
|
|
520
|
-
const through = await f(res[1]);
|
|
1133
|
+
const through = asResult(await f(res[1]));
|
|
521
1134
|
if (through instanceof ResultErr) {
|
|
522
1135
|
return through;
|
|
523
1136
|
}
|
|
@@ -531,15 +1144,47 @@ class ResultAsync {
|
|
|
531
1144
|
return res;
|
|
532
1145
|
}
|
|
533
1146
|
try {
|
|
534
|
-
return
|
|
1147
|
+
return Ok(await f(res[1]));
|
|
535
1148
|
}
|
|
536
1149
|
catch (err) {
|
|
537
|
-
return
|
|
1150
|
+
return Err(mapError(err));
|
|
1151
|
+
}
|
|
1152
|
+
}));
|
|
1153
|
+
}
|
|
1154
|
+
$andSafePromise(promise, mapError = ensureError) {
|
|
1155
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
1156
|
+
if (res instanceof ResultErr) {
|
|
1157
|
+
return res;
|
|
1158
|
+
}
|
|
1159
|
+
try {
|
|
1160
|
+
return Ok(await promise);
|
|
1161
|
+
}
|
|
1162
|
+
catch (err) {
|
|
1163
|
+
return Err(mapError(err));
|
|
1164
|
+
}
|
|
1165
|
+
}));
|
|
1166
|
+
}
|
|
1167
|
+
$andPipe(...fx) {
|
|
1168
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
1169
|
+
if (res instanceof ResultErr) {
|
|
1170
|
+
return res;
|
|
538
1171
|
}
|
|
1172
|
+
let current = res[1];
|
|
1173
|
+
for (const f of fx) {
|
|
1174
|
+
const result = asResult(await f(current));
|
|
1175
|
+
if (result instanceof ResultErr) {
|
|
1176
|
+
return result;
|
|
1177
|
+
}
|
|
1178
|
+
current = result[1];
|
|
1179
|
+
}
|
|
1180
|
+
return Ok(current);
|
|
539
1181
|
}));
|
|
540
1182
|
}
|
|
541
1183
|
/**
|
|
542
|
-
* @
|
|
1184
|
+
* The same as {@link Retuple.$peek|$peek}, except it:
|
|
1185
|
+
*
|
|
1186
|
+
* - awaits the peek function;
|
|
1187
|
+
* - returns {@link ResultAsync}.
|
|
543
1188
|
*/
|
|
544
1189
|
$peek(f) {
|
|
545
1190
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -548,7 +1193,10 @@ class ResultAsync {
|
|
|
548
1193
|
}));
|
|
549
1194
|
}
|
|
550
1195
|
/**
|
|
551
|
-
* @
|
|
1196
|
+
* The same as {@link Retuple.$tap|$tap}, except it:
|
|
1197
|
+
*
|
|
1198
|
+
* - awaits the tap function;
|
|
1199
|
+
* - returns {@link ResultAsync}.
|
|
552
1200
|
*/
|
|
553
1201
|
$tap(f) {
|
|
554
1202
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -559,7 +1207,10 @@ class ResultAsync {
|
|
|
559
1207
|
}));
|
|
560
1208
|
}
|
|
561
1209
|
/**
|
|
562
|
-
* @
|
|
1210
|
+
* The same as {@link Retuple.$tapErr|$tapErr}, except it:
|
|
1211
|
+
*
|
|
1212
|
+
* - awaits the tap error function;
|
|
1213
|
+
* - returns {@link ResultAsync}.
|
|
563
1214
|
*/
|
|
564
1215
|
$tapErr(f) {
|
|
565
1216
|
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then(async (res) => {
|
|
@@ -570,22 +1221,171 @@ class ResultAsync {
|
|
|
570
1221
|
}));
|
|
571
1222
|
}
|
|
572
1223
|
/**
|
|
573
|
-
* @
|
|
1224
|
+
* The same as {@link Retuple.$flatten|$flatten} except it returns
|
|
1225
|
+
* {@link ResultAsync}.
|
|
1226
|
+
*/
|
|
1227
|
+
$flatten() {
|
|
1228
|
+
return new ResultAsync(__classPrivateFieldGet(this, _ResultAsync_inner, "f").then((res) => res.$flatten()));
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* The same as {@link Retuple.$promise|$promise}.
|
|
574
1232
|
*/
|
|
575
1233
|
$promise() {
|
|
576
1234
|
return Promise.resolve(this);
|
|
577
1235
|
}
|
|
1236
|
+
/**
|
|
1237
|
+
* The same as {@link Retuple.$iter|$iter}, except it returns a `Promise`.
|
|
1238
|
+
*/
|
|
1239
|
+
async $iter() {
|
|
1240
|
+
return (await __classPrivateFieldGet(this, _ResultAsync_inner, "f")).$iter();
|
|
1241
|
+
}
|
|
578
1242
|
}
|
|
579
1243
|
_ResultAsync_inner = new WeakMap();
|
|
1244
|
+
/**
|
|
1245
|
+
* ## ResultRetry
|
|
1246
|
+
*/
|
|
1247
|
+
class ResultRetry extends ResultAsync {
|
|
1248
|
+
static zero() {
|
|
1249
|
+
return 0;
|
|
1250
|
+
}
|
|
1251
|
+
static delay(ms) {
|
|
1252
|
+
return new Promise((resolve) => setTimeout(resolve, Math.min(ms, _a.MAX_TIMEOUT)));
|
|
1253
|
+
}
|
|
1254
|
+
static integer(value) {
|
|
1255
|
+
if (typeof value === "number" && Number.isInteger(value)) {
|
|
1256
|
+
return Math.max(0, value);
|
|
1257
|
+
}
|
|
1258
|
+
return 0;
|
|
1259
|
+
}
|
|
1260
|
+
constructor(f) {
|
|
1261
|
+
super(Promise.resolve().then(() => __classPrivateFieldGet(this, _ResultRetry_promise, "f")));
|
|
1262
|
+
_ResultRetry_f.set(this, void 0);
|
|
1263
|
+
_ResultRetry_promise.set(this, void 0);
|
|
1264
|
+
_ResultRetry_times.set(this, 1);
|
|
1265
|
+
_ResultRetry_attempt.set(this, 0);
|
|
1266
|
+
_ResultRetry_aborted.set(this, false);
|
|
1267
|
+
_ResultRetry_abort.set(this, () => (__classPrivateFieldSet(this, _ResultRetry_aborted, true, "f")));
|
|
1268
|
+
_ResultRetry_getDelay.set(this, _a.zero);
|
|
1269
|
+
_ResultRetry_handler.set(this, void 0);
|
|
1270
|
+
__classPrivateFieldSet(this, _ResultRetry_f, f, "f");
|
|
1271
|
+
__classPrivateFieldSet(this, _ResultRetry_promise, this.drain(), "f");
|
|
1272
|
+
}
|
|
1273
|
+
then(onfulfilled, onrejected) {
|
|
1274
|
+
return super.then(onfulfilled, onrejected);
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Sets the maximum number of times the retry function can be executed,
|
|
1278
|
+
* mutating this `ResultRetry` instance.
|
|
1279
|
+
*
|
|
1280
|
+
* **The default value is 1 - meaning that unless set, no retries will be
|
|
1281
|
+
* attempted.**
|
|
1282
|
+
*
|
|
1283
|
+
* The retry function can be called up to the maximum number of times until
|
|
1284
|
+
* it returns `Ok`. If it never returns `Ok`, the most recent `Err` is
|
|
1285
|
+
* returned.
|
|
1286
|
+
*
|
|
1287
|
+
* This function accepts a positive integer between 1 and 100:
|
|
1288
|
+
*
|
|
1289
|
+
* - Integers outside of this range are clamped to the nearest valid value;
|
|
1290
|
+
* - Any other value (NaN, Infinity, fractions, strings) are treated as 1.
|
|
1291
|
+
*
|
|
1292
|
+
* @example
|
|
1293
|
+
*
|
|
1294
|
+
* ```ts
|
|
1295
|
+
* // Retry someResultFn up to 3 times until Ok is returned:
|
|
1296
|
+
* const result = await Result.$retry(someResultFn).$times(3);
|
|
1297
|
+
* ```
|
|
1298
|
+
*/
|
|
1299
|
+
$times(times) {
|
|
1300
|
+
__classPrivateFieldSet(this, _ResultRetry_times, Math.min(Math.max(1, _a.integer(times)), _a.MAX_RETRY), "f");
|
|
1301
|
+
return this;
|
|
1302
|
+
}
|
|
1303
|
+
$delay(fnOrMs) {
|
|
1304
|
+
if (typeof fnOrMs === "function") {
|
|
1305
|
+
__classPrivateFieldSet(this, _ResultRetry_getDelay, fnOrMs, "f");
|
|
1306
|
+
return this;
|
|
1307
|
+
}
|
|
1308
|
+
const delay = _a.integer(fnOrMs);
|
|
1309
|
+
if (delay > 0) {
|
|
1310
|
+
__classPrivateFieldSet(this, _ResultRetry_getDelay, () => delay, "f");
|
|
1311
|
+
}
|
|
1312
|
+
return this;
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Sets a handler to be called when an attempt returns `Err`, mutating this
|
|
1316
|
+
* `ResultRetry` instance. The handler can be used to capture information
|
|
1317
|
+
* about each failure, and to abort early and prevent further retries.
|
|
1318
|
+
*
|
|
1319
|
+
* The handler function is called with `ResultRetryHandleState`, containing:
|
|
1320
|
+
*
|
|
1321
|
+
* - **error** - The error value from the last failed attempt;
|
|
1322
|
+
* - **attempt** - The attempt number;
|
|
1323
|
+
* - **abort** - A function which when called, prevents further retries.
|
|
1324
|
+
*
|
|
1325
|
+
* @example
|
|
1326
|
+
*
|
|
1327
|
+
* ```ts
|
|
1328
|
+
* // Retry someResultFn up to 3 times until Ok is returned, logging each
|
|
1329
|
+
* // attempt and aborting early if the error code is "UNAUTHORIZED".
|
|
1330
|
+
* const result = await Result.$retry(someResultFn)
|
|
1331
|
+
* .$times(3)
|
|
1332
|
+
* .$handle(({ error, attempt, abort }) => {
|
|
1333
|
+
* console.info(`Attempt ${attempt} failed: ${error}`);
|
|
1334
|
+
* if (error === "UNAUTHORIZED") {
|
|
1335
|
+
* abort();
|
|
1336
|
+
* }
|
|
1337
|
+
* });
|
|
1338
|
+
* ```
|
|
1339
|
+
*/
|
|
1340
|
+
$handle(f) {
|
|
1341
|
+
__classPrivateFieldSet(this, _ResultRetry_handler, f, "f");
|
|
1342
|
+
return this;
|
|
1343
|
+
}
|
|
1344
|
+
async drain() {
|
|
1345
|
+
var _b;
|
|
1346
|
+
while (__classPrivateFieldGet(this, _ResultRetry_attempt, "f") < __classPrivateFieldGet(this, _ResultRetry_times, "f")) {
|
|
1347
|
+
const result = asResult(await __classPrivateFieldGet(this, _ResultRetry_f, "f").call(this));
|
|
1348
|
+
__classPrivateFieldSet(this, _ResultRetry_attempt, (_b = __classPrivateFieldGet(this, _ResultRetry_attempt, "f"), _b++, _b), "f");
|
|
1349
|
+
if (result.$isOk()) {
|
|
1350
|
+
return result;
|
|
1351
|
+
}
|
|
1352
|
+
if (__classPrivateFieldGet(this, _ResultRetry_handler, "f")) {
|
|
1353
|
+
await __classPrivateFieldGet(this, _ResultRetry_handler, "f").call(this, {
|
|
1354
|
+
error: result[0],
|
|
1355
|
+
attempt: __classPrivateFieldGet(this, _ResultRetry_attempt, "f"),
|
|
1356
|
+
abort: __classPrivateFieldGet(this, _ResultRetry_abort, "f"),
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
if (__classPrivateFieldGet(this, _ResultRetry_aborted, "f") || __classPrivateFieldGet(this, _ResultRetry_attempt, "f") >= __classPrivateFieldGet(this, _ResultRetry_times, "f")) {
|
|
1360
|
+
return result;
|
|
1361
|
+
}
|
|
1362
|
+
const delay = _a.integer(__classPrivateFieldGet(this, _ResultRetry_getDelay, "f").call(this, __classPrivateFieldGet(this, _ResultRetry_attempt, "f")));
|
|
1363
|
+
if (delay > 0) {
|
|
1364
|
+
await _a.delay(delay);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
/* v8 ignore next */
|
|
1368
|
+
throw new Error("Retuple: Unreachable code executed");
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
_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();
|
|
1372
|
+
ResultRetry.MAX_TIMEOUT = 3600000;
|
|
1373
|
+
ResultRetry.MAX_RETRY = 100;
|
|
1374
|
+
class RetupleStack extends Array {
|
|
1375
|
+
}
|
|
1376
|
+
function asResult(resultLike) {
|
|
1377
|
+
if (resultLike instanceof ResultOk || resultLike instanceof ResultErr) {
|
|
1378
|
+
return resultLike;
|
|
1379
|
+
}
|
|
1380
|
+
const result = resultLike[ResultLikeSymbol]();
|
|
1381
|
+
return result.ok ? new ResultOk(result.value) : new ResultErr(result.value);
|
|
1382
|
+
}
|
|
580
1383
|
function ensureError(err) {
|
|
581
1384
|
if (err instanceof Error) {
|
|
582
1385
|
return err;
|
|
583
1386
|
}
|
|
584
|
-
return new
|
|
1387
|
+
return new RetupleCaughtValueError(err);
|
|
585
1388
|
}
|
|
586
1389
|
function mapTrue() {
|
|
587
1390
|
return true;
|
|
588
1391
|
}
|
|
589
|
-
function isTruthy(val) {
|
|
590
|
-
return !!val;
|
|
591
|
-
}
|