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