t-tasks 1.2.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/t-tasks.d.ts +1913 -0
- package/dist/t-tasks.esm.js +778 -2
- package/dist/t-tasks.esm.js.map +1 -1
- package/dist/t-tasks.js +814 -2
- package/dist/t-tasks.js.map +1 -1
- package/package.json +12 -7
- package/src/either.ts +135 -45
- package/src/maybe.ts +121 -37
- package/src/task.ts +472 -252
- package/dist/either.d.ts +0 -626
- package/dist/index.d.ts +0 -3
- package/dist/maybe.d.ts +0 -595
- package/dist/t-tasks.modern.mjs +0 -2
- package/dist/t-tasks.modern.mjs.map +0 -1
- package/dist/t-tasks.umd.js +0 -2
- package/dist/t-tasks.umd.js.map +0 -1
- package/dist/task.d.ts +0 -489
package/src/task.ts
CHANGED
|
@@ -26,6 +26,7 @@ export type TaskFunction<A extends unknown[], R> = (...args: A) => Task<R>;
|
|
|
26
26
|
/**
|
|
27
27
|
* Task generator
|
|
28
28
|
*
|
|
29
|
+
* @template T yielded underlying type
|
|
29
30
|
* @template TT yielded task type
|
|
30
31
|
* @template R returned task resolve type
|
|
31
32
|
*
|
|
@@ -44,6 +45,7 @@ export type TaskGenerator<T, TT extends Task<T>, R> = Generator<TT, R, T>;
|
|
|
44
45
|
* Function returning task generator (generator function)
|
|
45
46
|
*
|
|
46
47
|
* @template A argument types
|
|
48
|
+
* @template T yielded underlying type
|
|
47
49
|
* @template TT yielded task type
|
|
48
50
|
* @template R returned task resolve type
|
|
49
51
|
*
|
|
@@ -178,6 +180,13 @@ export interface Task<R> extends TaskBase<R> {
|
|
|
178
180
|
*/
|
|
179
181
|
matchChain<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => Task<R2>; rejected: (error: any) => Task<R3>; canceled: () => Task<R4> }): Task<R2 | R3 | R4>;
|
|
180
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Read the settled result when the task has already finished
|
|
185
|
+
*
|
|
186
|
+
* @returns settled result, or null when the task is still pending
|
|
187
|
+
*/
|
|
188
|
+
resolved: () => Cancelable<R> | null;
|
|
189
|
+
|
|
181
190
|
/**
|
|
182
191
|
* Return underlying promise in order to await result
|
|
183
192
|
*
|
|
@@ -186,16 +195,19 @@ export interface Task<R> extends TaskBase<R> {
|
|
|
186
195
|
resolve: () => TaskInvoke<R>;
|
|
187
196
|
|
|
188
197
|
/**
|
|
189
|
-
* Invoke underlying
|
|
198
|
+
* Invoke underlying cancel method without error
|
|
199
|
+
*
|
|
200
|
+
* @returns 'true' when the task was still pending and cancelation was applied
|
|
190
201
|
*/
|
|
191
|
-
cancel: () =>
|
|
202
|
+
cancel: () => boolean;
|
|
192
203
|
|
|
193
204
|
/**
|
|
194
|
-
* Invoke underlying
|
|
205
|
+
* Invoke underlying cancel method with error
|
|
195
206
|
*
|
|
196
207
|
* @param error error value to be injected from outside
|
|
208
|
+
* @returns 'true' when the task was still pending and the error was applied
|
|
197
209
|
*/
|
|
198
|
-
reject: (error: any) =>
|
|
210
|
+
reject: (error: any) => boolean;
|
|
199
211
|
|
|
200
212
|
/**
|
|
201
213
|
* Wrap task to singleton generator
|
|
@@ -242,7 +254,7 @@ export namespace Task {
|
|
|
242
254
|
* @note low-level primitive for creating custom tasks, not intended for general use
|
|
243
255
|
*/
|
|
244
256
|
export function create<R>(invoke: TaskInvoke<R>, cancel: TaskCancel): Task<R> {
|
|
245
|
-
return new TaskClass<R>(invoke, cancel);
|
|
257
|
+
return new TaskClass<R>({ resolved: false, invoke, cancel });
|
|
246
258
|
}
|
|
247
259
|
|
|
248
260
|
/**
|
|
@@ -252,8 +264,8 @@ export namespace Task {
|
|
|
252
264
|
* @param value value to be returned upon awaiting
|
|
253
265
|
* @returns task resolving to specified value
|
|
254
266
|
*/
|
|
255
|
-
export function resolved<R>(value: R) {
|
|
256
|
-
return
|
|
267
|
+
export function resolved<R>(value: R): Task<R> {
|
|
268
|
+
return new TaskClass<R>({ resolved: true, result: Maybe.just(Either.right(value)) });
|
|
257
269
|
}
|
|
258
270
|
|
|
259
271
|
/**
|
|
@@ -261,20 +273,20 @@ export namespace Task {
|
|
|
261
273
|
*
|
|
262
274
|
* @template R returned task's resolve type
|
|
263
275
|
* @param error error to be returned upon awaiting
|
|
264
|
-
* @returns task
|
|
276
|
+
* @returns task rejected with the specified error
|
|
265
277
|
*/
|
|
266
|
-
export function rejected<R>(error: any) {
|
|
267
|
-
return
|
|
278
|
+
export function rejected<R>(error: any): Task<R> {
|
|
279
|
+
return new TaskClass<R>({ resolved: true, result: Maybe.just(Either.left(error)) });
|
|
268
280
|
}
|
|
269
281
|
|
|
270
282
|
/**
|
|
271
283
|
* Invariant task constructor creating canceled task
|
|
272
284
|
*
|
|
273
285
|
* @template R returned task's resolve type
|
|
274
|
-
* @returns task
|
|
286
|
+
* @returns canceled task
|
|
275
287
|
*/
|
|
276
|
-
export function canceled<R>() {
|
|
277
|
-
return
|
|
288
|
+
export function canceled<R>(): Task<R> {
|
|
289
|
+
return new TaskClass<R>({ resolved: true, result: Maybe.nothing() });
|
|
278
290
|
}
|
|
279
291
|
|
|
280
292
|
/**
|
|
@@ -294,19 +306,16 @@ export namespace Task {
|
|
|
294
306
|
* ```
|
|
295
307
|
*/
|
|
296
308
|
export function fromPromise<R>(promise: PromiseLike<R>): Task<R> {
|
|
297
|
-
const
|
|
309
|
+
const cell = settleCell<Cancelable<R>>();
|
|
298
310
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
311
|
+
const cancel: TaskCancel = (error: Maybe<any>) => cell.resolve(error.map(Either.left));
|
|
312
|
+
|
|
313
|
+
promise
|
|
314
|
+
.then(Either.right, Either.left)
|
|
315
|
+
.then(Maybe.just)
|
|
316
|
+
.then(cell.resolve);
|
|
302
317
|
|
|
303
|
-
|
|
304
|
-
.then(Either.right, Either.left)
|
|
305
|
-
.then(Maybe.just)
|
|
306
|
-
.then(resolve);
|
|
307
|
-
}),
|
|
308
|
-
(error: Maybe<any>) => resolve(error.map(Either.left)),
|
|
309
|
-
);
|
|
318
|
+
return Task.create(cell.promise, cancel);
|
|
310
319
|
}
|
|
311
320
|
|
|
312
321
|
/**
|
|
@@ -333,24 +342,120 @@ export namespace Task {
|
|
|
333
342
|
* ```
|
|
334
343
|
*/
|
|
335
344
|
export function fromFunction<R>(producer: () => R, cancelRef: { cancel: TaskCancel }): Task<R> {
|
|
336
|
-
const
|
|
345
|
+
const cell = settleCell<Cancelable<R>>();
|
|
337
346
|
|
|
338
|
-
const cancel = (error: Maybe<any>) => resolve(error.map(Either.left));
|
|
347
|
+
const cancel: TaskCancel = (error: Maybe<any>) => cell.resolve(error.map(Either.left));
|
|
339
348
|
|
|
340
349
|
cancelRef.cancel = cancel;
|
|
341
350
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
351
|
+
try {
|
|
352
|
+
cell.resolve(Maybe.just(Either.right(producer())));
|
|
353
|
+
} catch (e) {
|
|
354
|
+
cell.resolve(Maybe.just(Either.left(e)));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return Task.create(cell.promise, cancel);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Generic callback task
|
|
362
|
+
*
|
|
363
|
+
* Usefull for creating custom tasks from success and error callbacks and cancelaton function. Synchronous callbacks are not supported, @see fromFunction
|
|
364
|
+
*
|
|
365
|
+
* @template H cancelation handler type
|
|
366
|
+
* @template R returned task resolve type
|
|
367
|
+
* @param create task body with success and error callbacks
|
|
368
|
+
* @param onCancel cancelation function intended for stopping task execution
|
|
369
|
+
* @returns task resolving to success value
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```typescript
|
|
373
|
+
* export function timeout(delay: number) {
|
|
374
|
+
* return fromCallback<NodeJS.Timeout, void>((resolve) => setTimeout(() => resolve(), delay), clearTimeout);
|
|
375
|
+
* }
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
export function fromCallback<H, R>(create: (resolve: (result: R) => void, reject: (error: any) => void, cancel: () => void) => H, onCancel: (handler: H) => void): Task<R> {
|
|
379
|
+
const cell = settleCell<Cancelable<R>>();
|
|
380
|
+
|
|
381
|
+
let handler: { value: H } | null = null;
|
|
382
|
+
|
|
383
|
+
const cancel: TaskCancel = (error: Maybe<any>) => {
|
|
384
|
+
const wasPending = cell.resolve(error.map(Either.left));
|
|
385
|
+
if (wasPending && handler) {
|
|
386
|
+
onCancel(handler.value);
|
|
387
|
+
}
|
|
388
|
+
return wasPending;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
const value = create(
|
|
393
|
+
(r) => cell.resolve(Maybe.just(Either.right(r))),
|
|
394
|
+
(e) => cell.resolve(Maybe.just(Either.left(e))),
|
|
395
|
+
() => cancel(Maybe.nothing()),
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
handler = { value };
|
|
399
|
+
|
|
400
|
+
const result = cell.settled();
|
|
401
|
+
if (result && !result.value.match({ just: (v) => v.isRight(), nothing: () => false })) {
|
|
402
|
+
onCancel(value);
|
|
403
|
+
}
|
|
404
|
+
} catch (e) {
|
|
405
|
+
cell.resolve(Maybe.just(Either.left(e)));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return Task.create(cell.promise, cancel);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Lift an async operation that accepts an AbortSignal into a Task.
|
|
413
|
+
*
|
|
414
|
+
* Creates an internal AbortController and passes its signal to `producer`.
|
|
415
|
+
* If the resulting task is canceled or rejected externally, `controller.abort()`
|
|
416
|
+
* is called automatically.
|
|
417
|
+
*
|
|
418
|
+
* @template R returned task resolve type
|
|
419
|
+
* @param producer factory function receiving an AbortSignal
|
|
420
|
+
* @returns task wrapping the operation
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* ```typescript
|
|
424
|
+
* const fetchUser = (id: string) =>
|
|
425
|
+
* Task.fromAbortSignal((signal) =>
|
|
426
|
+
* fetch(`/api/users/${id}`, { signal }).then((res) => res.json())
|
|
427
|
+
* );
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
export function fromAbortSignal<R>(
|
|
431
|
+
producer: (signal: AbortSignal) => PromiseLike<R>
|
|
432
|
+
): Task<R> {
|
|
433
|
+
const cell = settleCell<Cancelable<R>>();
|
|
434
|
+
const controller = new AbortController();
|
|
435
|
+
|
|
436
|
+
const cancel: TaskCancel = (error: Maybe<any>) => {
|
|
437
|
+
const wasPending = cell.resolve(error.map(Either.left));
|
|
438
|
+
if (wasPending) {
|
|
439
|
+
controller.abort(error.match({ just: (err) => err, nothing: () => undefined }));
|
|
440
|
+
}
|
|
441
|
+
return wasPending;
|
|
442
|
+
};
|
|
345
443
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
444
|
+
try {
|
|
445
|
+
producer(controller.signal).then((value) => {
|
|
446
|
+
cell.resolve(Maybe.just(Either.right(value)));
|
|
447
|
+
}, (error) => {
|
|
448
|
+
if (controller.signal.aborted && (error?.name === 'AbortError' || (typeof DOMException !== 'undefined' && error instanceof DOMException && error.name === 'AbortError'))) {
|
|
449
|
+
cell.resolve(Maybe.nothing());
|
|
450
|
+
} else {
|
|
451
|
+
cell.resolve(Maybe.just(Either.left(error)));
|
|
350
452
|
}
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
|
|
453
|
+
});
|
|
454
|
+
} catch (e) {
|
|
455
|
+
cell.resolve(Maybe.just(Either.left(e)));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return Task.create(cell.promise, cancel);
|
|
354
459
|
}
|
|
355
460
|
|
|
356
461
|
/**
|
|
@@ -367,9 +472,8 @@ export namespace Task {
|
|
|
367
472
|
/**
|
|
368
473
|
* Convinience shortcut for yielding timers
|
|
369
474
|
*
|
|
370
|
-
* @
|
|
371
|
-
* @
|
|
372
|
-
* @returns generator to be be used with yield*
|
|
475
|
+
* @param delay duration in ms after that the generator resolves
|
|
476
|
+
* @returns generator to be used with yield*
|
|
373
477
|
*/
|
|
374
478
|
export function timeoutGenerator(delay: number) {
|
|
375
479
|
return Task.timeout(delay).generator();
|
|
@@ -407,6 +511,7 @@ export namespace Task {
|
|
|
407
511
|
*
|
|
408
512
|
* If error is not caught the task is interrupted and returns 'just left error' immediately. In case of cancelation the task is interrupted and returns 'nothing' immediately
|
|
409
513
|
*
|
|
514
|
+
* @template T yielded underlying type
|
|
410
515
|
* @template TT yielded task type
|
|
411
516
|
* @template R returned task resolve type
|
|
412
517
|
* @param taskGeneratorFunction task generator function
|
|
@@ -431,21 +536,50 @@ export namespace Task {
|
|
|
431
536
|
* ```
|
|
432
537
|
*/
|
|
433
538
|
export function generate<T, TT extends Task<T>, R>(taskGeneratorFunction: TaskGeneratorFunction<[], T, TT, R>): Task<R> {
|
|
434
|
-
const generator = taskGeneratorFunction();
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
539
|
+
const generator: TaskGenerator<T, TT, R> = taskGeneratorFunction();
|
|
540
|
+
const cell = settleCell<Cancelable<R>>();
|
|
541
|
+
|
|
542
|
+
let current: { task: Task<T>; error: Maybe<any> | null } | null = null;
|
|
543
|
+
|
|
544
|
+
const sequentor = (invoke: () => IteratorResult<TT, R>, override?: Cancelable<R>) => {
|
|
545
|
+
try {
|
|
546
|
+
const next = invoke();
|
|
547
|
+
|
|
548
|
+
if (next.done) {
|
|
549
|
+
cell.resolve(override ?? current?.error?.map(Either.left) ?? Maybe.just(Either.right(next.value)));
|
|
550
|
+
current = null;
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
current = {
|
|
555
|
+
task: next.value,
|
|
556
|
+
error: null,
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
next.value._invoke((maybe) => maybe.matchTap({
|
|
560
|
+
just: (either) => either.matchTap({
|
|
561
|
+
right: (value) => sequentor(() => generator.next(value), override),
|
|
562
|
+
left: (error) => sequentor(() => generator.throw(error), override),
|
|
563
|
+
}),
|
|
564
|
+
nothing: () => sequentor(() => generator.return(undefined as R), Maybe.nothing()),
|
|
565
|
+
}))
|
|
566
|
+
} catch (error) {
|
|
567
|
+
cell.resolve(override ?? Maybe.just(Either.left(error)));
|
|
568
|
+
current = null;
|
|
569
|
+
}
|
|
446
570
|
};
|
|
447
571
|
|
|
448
|
-
|
|
572
|
+
sequentor(() => generator.next());
|
|
573
|
+
|
|
574
|
+
return Task.create(cell.promise, (error) => {
|
|
575
|
+
if (cell.settled() || !current) {
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
current.error = error;
|
|
580
|
+
|
|
581
|
+
return current.task._cancel(error);
|
|
582
|
+
});
|
|
449
583
|
}
|
|
450
584
|
|
|
451
585
|
/**
|
|
@@ -453,16 +587,15 @@ export namespace Task {
|
|
|
453
587
|
*
|
|
454
588
|
* Simplifies wrighting functions returning generated tasks
|
|
455
589
|
*
|
|
456
|
-
* @template
|
|
590
|
+
* @template A generator arguments
|
|
591
|
+
* @template T yielded underlying type
|
|
457
592
|
* @template TT yielded task type
|
|
458
593
|
* @template R returned task resolve type
|
|
459
594
|
* @param taskGeneratorFunction function* (...args) task generator function
|
|
460
|
-
* @returns task resolving to generator's return type
|
|
595
|
+
* @returns task function resolving to generator's return type
|
|
461
596
|
*/
|
|
462
597
|
export function generateFunction<A extends any[], T, TT extends Task<T>, R>(taskGeneratorFunction: TaskGeneratorFunction<A, T, TT, R>): TaskFunction<A, R> {
|
|
463
|
-
return (...args: A) => generate(
|
|
464
|
-
return yield* taskGeneratorFunction(...args);
|
|
465
|
-
});
|
|
598
|
+
return (...args: A) => generate(() => taskGeneratorFunction(...args));
|
|
466
599
|
}
|
|
467
600
|
|
|
468
601
|
/**
|
|
@@ -483,51 +616,13 @@ export namespace Task {
|
|
|
483
616
|
* ```
|
|
484
617
|
*/
|
|
485
618
|
export function timeout(delay: number) {
|
|
486
|
-
return fromCallback<NodeJS.Timeout, void>((resolve) => setTimeout(
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Generic callback task
|
|
491
|
-
*
|
|
492
|
-
* Usefull for creating custom tasks from success and error callbacks and cancelaton function. Synchronous callbacks are not supported, @see fromFuction
|
|
493
|
-
*
|
|
494
|
-
* @param create task body with success and error callbacks
|
|
495
|
-
* @param cancel cancelation function intended for stopping task execution
|
|
496
|
-
* @returns task resolving to success value
|
|
497
|
-
*
|
|
498
|
-
* @example
|
|
499
|
-
* ```typescript
|
|
500
|
-
* export function timeout(delay: number) {
|
|
501
|
-
* return fromCallback<NodeJS.Timeout, void>((resolve) => setTimeout(() => resolve(), delay), clearTimeout);
|
|
502
|
-
* }
|
|
503
|
-
* ```
|
|
504
|
-
*/
|
|
505
|
-
export function fromCallback<H, R>(create: (resolve: (result: R) => void, reject: (error: any) => void, cancel: () => void) => H, onCancel: (handler: H) => void): Task<R> {
|
|
506
|
-
let handler: H;
|
|
507
|
-
|
|
508
|
-
const [resolve, setResolve] = resolver<Cancelable<R>>();
|
|
509
|
-
|
|
510
|
-
return Task.create(
|
|
511
|
-
new Promise<Cancelable<R>>((_resolve) => {
|
|
512
|
-
setResolve(_resolve);
|
|
513
|
-
|
|
514
|
-
handler = create(
|
|
515
|
-
(r) => resolve(Maybe.just(Either.right(r))),
|
|
516
|
-
(e) => resolve(Maybe.just(Either.left(e))),
|
|
517
|
-
() => resolve(Maybe.nothing())
|
|
518
|
-
);
|
|
519
|
-
}),
|
|
520
|
-
(error: Maybe<any>) => {
|
|
521
|
-
resolve(error.map(Either.left));
|
|
522
|
-
|
|
523
|
-
onCancel(handler);
|
|
524
|
-
},
|
|
525
|
-
);
|
|
619
|
+
return fromCallback<NodeJS.Timeout, void>((resolve) => setTimeout(resolve, delay), clearTimeout);
|
|
526
620
|
}
|
|
527
621
|
|
|
528
622
|
/**
|
|
529
623
|
* Start multiple tasks one after another
|
|
530
624
|
*
|
|
625
|
+
* @template T underlying task type
|
|
531
626
|
* @param taskFunctions list of task functions (without arguments)
|
|
532
627
|
* @returns composite task invoring every task in order and resolving to the list of results
|
|
533
628
|
*/
|
|
@@ -550,47 +645,38 @@ export namespace Task {
|
|
|
550
645
|
*
|
|
551
646
|
* @template T underlying task type
|
|
552
647
|
* @param tasks iterable of tasks to execute
|
|
553
|
-
* @
|
|
648
|
+
* @returns task resolving to the list of results
|
|
554
649
|
*/
|
|
555
650
|
export function all<T>(tasks: Iterable<Task<T>>) {
|
|
556
|
-
const [resolve, setResolve] = resolver<Cancelable<T[]>>();
|
|
557
|
-
|
|
558
651
|
const taskArray = Array.from(tasks);
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
taskArray.map((task, i) => {
|
|
585
|
-
return task.matchTap({
|
|
586
|
-
resolved: (value) => resolved(value, i),
|
|
587
|
-
rejected: (error) => rejected(Maybe.just(error)),
|
|
588
|
-
canceled: () => rejected(Maybe.nothing()),
|
|
589
|
-
});
|
|
652
|
+
if (taskArray.length === 0) {
|
|
653
|
+
return Task.resolved([]);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return Task.fromCallback<Task<T>[], T[]>((resolve, reject, cancel) => {
|
|
657
|
+
const results: T[] = new Array(taskArray.length);
|
|
658
|
+
let remaining = taskArray.length;
|
|
659
|
+
|
|
660
|
+
taskArray.forEach((task, i) => {
|
|
661
|
+
task.matchTap({
|
|
662
|
+
resolved: (value) => {
|
|
663
|
+
results[i] = value;
|
|
664
|
+
remaining--;
|
|
665
|
+
if (remaining === 0) resolve(results);
|
|
666
|
+
},
|
|
667
|
+
rejected: (error) => {
|
|
668
|
+
reject(error);
|
|
669
|
+
taskArray.forEach((t) => t.cancel());
|
|
670
|
+
},
|
|
671
|
+
canceled: () => {
|
|
672
|
+
cancel();
|
|
673
|
+
taskArray.forEach((t) => t.cancel());
|
|
674
|
+
},
|
|
590
675
|
});
|
|
591
|
-
})
|
|
592
|
-
|
|
593
|
-
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
return taskArray;
|
|
679
|
+
}, (subtasks) => subtasks.forEach((t) => t.cancel()));
|
|
594
680
|
}
|
|
595
681
|
|
|
596
682
|
/**
|
|
@@ -605,47 +691,43 @@ export namespace Task {
|
|
|
605
691
|
*
|
|
606
692
|
* @template T underlying task type
|
|
607
693
|
* @param tasks iterable of tasks to execute
|
|
608
|
-
* @
|
|
694
|
+
* @returns task resolving to the result of first successfull task
|
|
609
695
|
*/
|
|
610
696
|
export function any<T>(tasks: Iterable<Task<T>>) {
|
|
611
|
-
const
|
|
697
|
+
const cell = settleCell<Cancelable<T>>();
|
|
612
698
|
|
|
613
699
|
const taskArray = Array.from(tasks);
|
|
614
700
|
|
|
615
|
-
|
|
701
|
+
if (taskArray.length < 1) {
|
|
702
|
+
return Task.canceled();
|
|
703
|
+
}
|
|
616
704
|
|
|
617
|
-
const
|
|
705
|
+
const cancel = (error: Maybe<any>) => taskArray.map((task) => task._cancel(error)).every((r) => r);
|
|
706
|
+
|
|
707
|
+
const list = taskArray.map<Maybe<any>>(() => Maybe.nothing());
|
|
618
708
|
|
|
619
709
|
const resolved = (value: Maybe<T>) => {
|
|
620
|
-
resolve(value.map(Either.right));
|
|
710
|
+
cell.resolve(value.map(Either.right));
|
|
621
711
|
cancel(Maybe.nothing());
|
|
622
712
|
};
|
|
713
|
+
|
|
623
714
|
const rejected = (error: any, i: number) => {
|
|
624
715
|
list[i] = Maybe.just(error);
|
|
625
716
|
|
|
626
717
|
if (Maybe.everyJust(list)) {
|
|
627
|
-
resolve(Maybe.just(Either.left(list.map(Just.just))));
|
|
718
|
+
cell.resolve(Maybe.just(Either.left(list.map((v) => Just.just(v)))));
|
|
628
719
|
}
|
|
629
720
|
};
|
|
630
721
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
722
|
+
taskArray.map((task, i) => {
|
|
723
|
+
return task.matchTap({
|
|
724
|
+
resolved: (value) => resolved(Maybe.just(value)),
|
|
725
|
+
rejected: (error) => rejected(error, i),
|
|
726
|
+
canceled: () => resolved(Maybe.nothing()),
|
|
727
|
+
});
|
|
728
|
+
});
|
|
638
729
|
|
|
639
|
-
|
|
640
|
-
return task.matchTap({
|
|
641
|
-
resolved: (value) => resolved(Maybe.just(value)),
|
|
642
|
-
rejected: (error) => rejected(error, i),
|
|
643
|
-
canceled: () => resolved(Maybe.nothing()),
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
}),
|
|
647
|
-
cancel,
|
|
648
|
-
);
|
|
730
|
+
return Task.create(cell.promise, cancel);
|
|
649
731
|
}
|
|
650
732
|
|
|
651
733
|
/**
|
|
@@ -654,6 +736,7 @@ export namespace Task {
|
|
|
654
736
|
* If the second task resolves sooner than the first, resulting task is canceled
|
|
655
737
|
* Otherwise the resulting task resolves together with the first one
|
|
656
738
|
*
|
|
739
|
+
* @template T underlying task type
|
|
657
740
|
* @param task task to limit
|
|
658
741
|
* @param limitTask limiting task
|
|
659
742
|
* @returns task limites according to limitTask
|
|
@@ -668,7 +751,9 @@ export namespace Task {
|
|
|
668
751
|
* Given task is re-generated in case of failure (both external and internal)
|
|
669
752
|
* Resulting task is still cancelable by standard means
|
|
670
753
|
*
|
|
754
|
+
* @template T underlying task type
|
|
671
755
|
* @param taskFunction task preoducing function
|
|
756
|
+
* @returns task that retries until the produced task resolves
|
|
672
757
|
*/
|
|
673
758
|
export function repeat<T>(taskFunction: TaskFunction<[], T>) {
|
|
674
759
|
const sequentor = (): Task<T> => taskFunction().chainRejected(sequentor);
|
|
@@ -682,152 +767,281 @@ export namespace Task {
|
|
|
682
767
|
/// --------------------------------------------------------------------------------------
|
|
683
768
|
|
|
684
769
|
type TaskInvoke<R> = Promise<Cancelable<R>>;
|
|
685
|
-
type TaskCancel = (error: Maybe<any>) =>
|
|
770
|
+
type TaskCancel = (error: Maybe<any>) => boolean;
|
|
686
771
|
|
|
687
772
|
/**
|
|
688
773
|
* @hidden
|
|
689
774
|
*/
|
|
690
775
|
interface TaskBase<R> {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
*/
|
|
694
|
-
readonly _invoke: TaskInvoke<R>;
|
|
695
|
-
/**
|
|
696
|
-
* @hidden
|
|
697
|
-
*/
|
|
698
|
-
readonly _cancel: TaskCancel;
|
|
776
|
+
_invoke(op: (result: Cancelable<R>) => void): void;
|
|
777
|
+
_cancel(error: Maybe<any>): boolean;
|
|
699
778
|
}
|
|
700
779
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
780
|
+
/**
|
|
781
|
+
* One-shot settlement cell.
|
|
782
|
+
*
|
|
783
|
+
* The Promise is created internally, so there is no unarmed window: `resolve`
|
|
784
|
+
* before or after construction always owns the result (first writer wins).
|
|
785
|
+
* Later `resolve` calls are ignored. Reentrant `resolve` from the sink is ignored.
|
|
786
|
+
*
|
|
787
|
+
* `settled` is for skipping continuations; it does not cancel children by itself.
|
|
788
|
+
* After creating a child, if `settled` is already true, cancel that child with
|
|
789
|
+
* the stored value. Bind `_cancel` to the child only after that check.
|
|
790
|
+
*/
|
|
791
|
+
type SettleCell<T> = {
|
|
792
|
+
readonly promise: Promise<T>;
|
|
793
|
+
readonly resolve: (value: T) => boolean;
|
|
794
|
+
readonly settled: () => { value: T } | null;
|
|
795
|
+
};
|
|
705
796
|
|
|
706
|
-
|
|
707
|
-
const r = globalResolve;
|
|
797
|
+
const stub = () => void undefined;
|
|
708
798
|
|
|
709
|
-
|
|
799
|
+
const settleCell = <T>(): SettleCell<T> => {
|
|
800
|
+
let sink: (value: T) => void = stub;
|
|
801
|
+
let settled: { value: T } | null = null;
|
|
710
802
|
|
|
711
|
-
|
|
712
|
-
|
|
803
|
+
const promise = new Promise<T>((resolve) => {
|
|
804
|
+
sink = resolve;
|
|
805
|
+
});
|
|
713
806
|
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
807
|
+
const resolve = (next: T) => {
|
|
808
|
+
if (settled) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
717
811
|
|
|
718
|
-
|
|
719
|
-
};
|
|
812
|
+
settled = { value: next };
|
|
720
813
|
|
|
721
|
-
|
|
722
|
-
const globalCancel = { cancel: _task._cancel };
|
|
814
|
+
sink(next);
|
|
723
815
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
// Tecnically it's not possible to throw here anymore as op is lifted into task now, but just in case
|
|
727
|
-
try {
|
|
728
|
-
const { _invoke: invoke2, _cancel: cancel2 } = Task.fromFunction(() => op(result), globalCancel);
|
|
816
|
+
return true;
|
|
817
|
+
};
|
|
729
818
|
|
|
730
|
-
|
|
819
|
+
return {
|
|
820
|
+
promise,
|
|
821
|
+
resolve,
|
|
822
|
+
settled: () => settled,
|
|
823
|
+
};
|
|
824
|
+
};
|
|
731
825
|
|
|
732
|
-
|
|
826
|
+
function chainTaskMaybe<R, R2>(parent: Task<R>, op: (value: Cancelable<R>) => Task<R2>): Task<R2> {
|
|
827
|
+
const cell = settleCell<Cancelable<R2>>();
|
|
828
|
+
|
|
829
|
+
let state:
|
|
830
|
+
| { phase: 'parent' }
|
|
831
|
+
| { phase: 'transform', error: Maybe<any> | null }
|
|
832
|
+
| { phase: 'child', cancel: TaskCancel }
|
|
833
|
+
| { phase: 'closed' } = { phase: 'parent' };
|
|
834
|
+
|
|
835
|
+
parent._invoke((result) => {
|
|
836
|
+
state = { phase: 'transform', error: null }
|
|
837
|
+
|
|
838
|
+
let child: Task<R2> | null = null;
|
|
839
|
+
try {
|
|
840
|
+
child = op(result);
|
|
841
|
+
} catch (e) {
|
|
842
|
+
cell.resolve(Maybe.just(Either.left(e)));
|
|
843
|
+
state = { phase: 'closed' };
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const transformError = state.phase === 'transform' ? state.error : null;
|
|
848
|
+
|
|
849
|
+
state = { phase: 'child', cancel: (error) => child._cancel(error) };
|
|
850
|
+
|
|
851
|
+
if (transformError) {
|
|
852
|
+
cell.resolve(transformError.map(Either.left));
|
|
853
|
+
state = { phase: 'closed' };
|
|
854
|
+
child._cancel(transformError);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return child._invoke((value) => {
|
|
859
|
+
cell.resolve(value);
|
|
860
|
+
state = { phase: 'closed' };
|
|
861
|
+
});
|
|
862
|
+
});
|
|
733
863
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
864
|
+
return Task.create(cell.promise, (error) => {
|
|
865
|
+
if (cell.settled()) {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (state.phase === 'parent') {
|
|
870
|
+
return parent._cancel(error);
|
|
871
|
+
} else if (state.phase === 'transform') {
|
|
872
|
+
state.error = error;
|
|
873
|
+
return true;
|
|
874
|
+
} else if (state.phase === 'child') {
|
|
875
|
+
return state.cancel(error);
|
|
876
|
+
} else {
|
|
877
|
+
return false;
|
|
878
|
+
}
|
|
879
|
+
});
|
|
880
|
+
}
|
|
737
881
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
882
|
+
function mapTaskMaybe<R, R2>(parent: Task<R>, op: (value: Cancelable<R>) => Cancelable<R2>): Task<R2> {
|
|
883
|
+
const cell = settleCell<Cancelable<R2>>();
|
|
884
|
+
|
|
885
|
+
let state:
|
|
886
|
+
| { phase: 'parent' }
|
|
887
|
+
| { phase: 'transform', error: Maybe<any> | null }
|
|
888
|
+
| { phase: 'closed' } = { phase: 'parent' };
|
|
889
|
+
|
|
890
|
+
parent._invoke((result) => {
|
|
891
|
+
state = { phase: 'transform', error: null }
|
|
892
|
+
|
|
893
|
+
let value: Cancelable<R2> | null = null;
|
|
894
|
+
try {
|
|
895
|
+
value = op(result);
|
|
896
|
+
} catch (e) {
|
|
897
|
+
cell.resolve(Maybe.just(Either.left(e)));
|
|
898
|
+
state = { phase: 'closed' };
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
const transformError = state.phase === 'transform' ? state.error : null;
|
|
903
|
+
|
|
904
|
+
if (transformError) {
|
|
905
|
+
cell.resolve(transformError.map(Either.left));
|
|
906
|
+
} else {
|
|
907
|
+
cell.resolve(value);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
state = { phase: 'closed' };
|
|
911
|
+
});
|
|
741
912
|
|
|
742
|
-
|
|
913
|
+
return Task.create(cell.promise, (error) => {
|
|
914
|
+
if (cell.settled()) {
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
if (state.phase === 'parent') {
|
|
919
|
+
return parent._cancel(error);
|
|
920
|
+
} else if (state.phase === 'transform') {
|
|
921
|
+
state.error = error;
|
|
922
|
+
return true;
|
|
923
|
+
} else {
|
|
924
|
+
return false;
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
}
|
|
743
928
|
|
|
744
|
-
|
|
929
|
+
function tapTaskMaybe<R>(parent: Task<R>, op: (value: Cancelable<R>) => void): Task<R> {
|
|
930
|
+
parent._invoke((result) => {
|
|
931
|
+
try {
|
|
932
|
+
op(result);
|
|
933
|
+
} catch (e) {
|
|
934
|
+
reportError(e);
|
|
935
|
+
}
|
|
936
|
+
});
|
|
745
937
|
|
|
746
|
-
|
|
747
|
-
} catch (e) {
|
|
748
|
-
return Maybe.just(Either.left(e));
|
|
749
|
-
}
|
|
750
|
-
}),
|
|
751
|
-
(error: Maybe<any>) => globalCancel.cancel(error),
|
|
752
|
-
);
|
|
938
|
+
return parent;
|
|
753
939
|
}
|
|
754
940
|
|
|
755
|
-
function chainTaskEither<R, R2>(_task:
|
|
941
|
+
function chainTaskEither<R, R2>(_task: Task<R>, op: (value: Rejectable<R>) => Task<R2>): Task<R2> {
|
|
756
942
|
return chainTaskMaybe<R, R2>(_task, (maybe) => maybe.map(op).orMap<Task<R2>>(Task.canceled).just);
|
|
757
943
|
}
|
|
758
944
|
|
|
759
|
-
function
|
|
760
|
-
return chainTaskMaybe<R, R2>(_task, (maybe) => {
|
|
761
|
-
return op(maybe).matchMap<Task<R2>>({
|
|
762
|
-
just: (either) =>
|
|
763
|
-
either.matchMap<Task<R2>>({
|
|
764
|
-
right: Task.resolved,
|
|
765
|
-
left: Task.rejected,
|
|
766
|
-
}).right,
|
|
767
|
-
nothing: Task.canceled,
|
|
768
|
-
}).just;
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
function mapTaskEither<R, R2>(_task: TaskBase<R>, op: (value: Rejectable<R>) => Rejectable<R2>) {
|
|
945
|
+
function mapTaskEither<R, R2>(_task: Task<R>, op: (value: Rejectable<R>) => Rejectable<R2>): Task<R2> {
|
|
773
946
|
return mapTaskMaybe<R, R2>(_task, (maybe) => maybe.map(op));
|
|
774
947
|
}
|
|
775
948
|
|
|
776
|
-
function
|
|
777
|
-
return mapTaskMaybe<R, R>(_task, (value) => {
|
|
778
|
-
op(value);
|
|
779
|
-
|
|
780
|
-
return value;
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
function tapTaskEither<R>(_task: TaskBase<R>, op: (value: Rejectable<R>) => void) {
|
|
949
|
+
function tapTaskEither<R>(_task: Task<R>, op: (value: Rejectable<R>) => void): Task<R> {
|
|
785
950
|
return tapTaskMaybe<R>(_task, (maybe) => maybe.tap(op));
|
|
786
951
|
}
|
|
787
952
|
|
|
953
|
+
type SyncState<R> =
|
|
954
|
+
| { resolved: false; invoke: TaskInvoke<R>; cancel: TaskCancel }
|
|
955
|
+
| { resolved: true; result: Cancelable<R> }
|
|
956
|
+
|
|
788
957
|
class TaskClass<R> implements Task<R> {
|
|
789
|
-
constructor(
|
|
958
|
+
constructor(private _state: SyncState<R>) {
|
|
959
|
+
if (!this._state.resolved) {
|
|
960
|
+
this._state.invoke = this._state.invoke.then((result) => {
|
|
961
|
+
if (!this._state.resolved) {
|
|
962
|
+
this._state = { resolved: true, result }
|
|
963
|
+
}
|
|
964
|
+
return result;
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
}
|
|
790
968
|
|
|
791
|
-
|
|
969
|
+
_invoke(op: (result: Cancelable<R>) => void) {
|
|
970
|
+
if (this._state.resolved) {
|
|
971
|
+
return op(this._state.result);
|
|
972
|
+
} else {
|
|
973
|
+
return this._state.invoke.then(op);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
_cancel(error: Maybe<any>) {
|
|
978
|
+
if (this._state.resolved) {
|
|
979
|
+
return false
|
|
980
|
+
} else {
|
|
981
|
+
return this._state.cancel(error);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
tapCanceled(op: () => void): Task<R> {
|
|
792
986
|
return tapTaskMaybe<R>(this, (maybe) => maybe.orTap(op));
|
|
793
987
|
}
|
|
794
|
-
tapRejected(op: (error: any) => void) {
|
|
988
|
+
tapRejected(op: (error: any) => void): Task<R> {
|
|
795
989
|
return tapTaskEither<R>(this, (either) => either.orTap(op));
|
|
796
990
|
}
|
|
797
|
-
tap(op: (value: R) => void) {
|
|
991
|
+
tap(op: (value: R) => void): Task<R> {
|
|
798
992
|
return tapTaskEither<R>(this, (either) => either.tap(op));
|
|
799
993
|
}
|
|
800
994
|
|
|
801
|
-
mapCanceled<R2>(op: () => R2) {
|
|
995
|
+
mapCanceled<R2>(op: () => R2): Task<R | R2> {
|
|
802
996
|
return mapTaskMaybe<R, R | R2>(this, (maybe) => maybe.orMap(() => Either.right(op())));
|
|
803
997
|
}
|
|
804
|
-
mapRejected<R2>(op: (error: any) => R2) {
|
|
998
|
+
mapRejected<R2>(op: (error: any) => R2): Task<R | R2> {
|
|
805
999
|
return mapTaskEither<R, R | R2>(this, (either) => either.orMap(op));
|
|
806
1000
|
}
|
|
807
|
-
map<R2>(op: (value: R) => R2) {
|
|
1001
|
+
map<R2>(op: (value: R) => R2): Task<R2> {
|
|
808
1002
|
return mapTaskEither<R, R2>(this, (either) => either.map(op));
|
|
809
1003
|
}
|
|
810
1004
|
|
|
811
|
-
chainCanceled<R2>(op: () => Task<R2>) {
|
|
1005
|
+
chainCanceled<R2>(op: () => Task<R2>): Task<R | R2> {
|
|
812
1006
|
const mapEither = (either: Rejectable<R>) => either.map(Task.resolved).orMap<Task<R>>(Task.rejected).right;
|
|
813
1007
|
|
|
814
1008
|
return chainTaskMaybe<R, R | R2>(this, (maybe) => maybe.map(mapEither).orMap(op).just);
|
|
815
1009
|
}
|
|
816
|
-
chainRejected<R2>(op: (error: any) => Task<R2>) {
|
|
1010
|
+
chainRejected<R2>(op: (error: any) => Task<R2>): Task<R | R2> {
|
|
817
1011
|
return chainTaskEither<R, R | R2>(this, (either) => either.map(Task.resolved).orMap(op).right);
|
|
818
1012
|
}
|
|
819
|
-
chain<R2>(op: (value: R) => Task<R2>) {
|
|
1013
|
+
chain<R2>(op: (value: R) => Task<R2>): Task<R2> {
|
|
820
1014
|
return chainTaskEither<R, R2>(this, (either) => either.map(op).orMap<Task<R2>>(Task.rejected).right);
|
|
821
1015
|
}
|
|
822
1016
|
|
|
1017
|
+
resolved() {
|
|
1018
|
+
if (this._state.resolved) {
|
|
1019
|
+
return this._state.result;
|
|
1020
|
+
} else {
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
823
1025
|
resolve() {
|
|
824
|
-
|
|
1026
|
+
if (this._state.resolved) {
|
|
1027
|
+
return Promise.resolve(this._state.result);
|
|
1028
|
+
} else {
|
|
1029
|
+
return this._state.invoke;
|
|
1030
|
+
}
|
|
825
1031
|
}
|
|
826
1032
|
cancel() {
|
|
827
|
-
|
|
1033
|
+
if (this._state.resolved) {
|
|
1034
|
+
return false;
|
|
1035
|
+
} else {
|
|
1036
|
+
return this._state.cancel(Maybe.nothing());
|
|
1037
|
+
}
|
|
828
1038
|
}
|
|
829
1039
|
reject(error: any) {
|
|
830
|
-
|
|
1040
|
+
if (this._state.resolved) {
|
|
1041
|
+
return false;
|
|
1042
|
+
} else {
|
|
1043
|
+
return this._state.cancel(Maybe.just(error));
|
|
1044
|
+
}
|
|
831
1045
|
}
|
|
832
1046
|
|
|
833
1047
|
generator() {
|
|
@@ -836,7 +1050,7 @@ class TaskClass<R> implements Task<R> {
|
|
|
836
1050
|
})(this);
|
|
837
1051
|
}
|
|
838
1052
|
|
|
839
|
-
matchTap(op: { resolved: (value: R) => void; rejected: (error: any) => void; canceled: () => void }) {
|
|
1053
|
+
matchTap(op: { resolved: (value: R) => void; rejected: (error: any) => void; canceled: () => void }): Task<R> {
|
|
840
1054
|
return tapTaskMaybe(this, (maybe) => {
|
|
841
1055
|
return maybe.matchTap({
|
|
842
1056
|
just: (either) => {
|
|
@@ -850,31 +1064,37 @@ class TaskClass<R> implements Task<R> {
|
|
|
850
1064
|
});
|
|
851
1065
|
}
|
|
852
1066
|
|
|
853
|
-
matchMap<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => R2; rejected: (error: any) => R3; canceled: () => R4 }) {
|
|
1067
|
+
matchMap<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => R2; rejected: (error: any) => R3; canceled: () => R4 }): Task<R2 | R3 | R4> {
|
|
854
1068
|
return mapTaskMaybe(this, (maybe) => {
|
|
855
|
-
return maybe.
|
|
1069
|
+
return Maybe.just(maybe.match<Right<R2 | R3 | R4, any>>({
|
|
856
1070
|
just: (either) => {
|
|
857
|
-
return either.
|
|
1071
|
+
return Either.right(either.match({
|
|
858
1072
|
right: op.resolved,
|
|
859
1073
|
left: op.rejected,
|
|
860
|
-
});
|
|
1074
|
+
}));
|
|
861
1075
|
},
|
|
862
1076
|
nothing: () => Either.right(op.canceled()),
|
|
863
|
-
});
|
|
1077
|
+
}));
|
|
864
1078
|
});
|
|
865
1079
|
}
|
|
866
1080
|
|
|
867
|
-
matchChain<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => Task<R2>; rejected: (error: any) => Task<R3>; canceled: () => Task<R4> }) {
|
|
1081
|
+
matchChain<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => Task<R2>; rejected: (error: any) => Task<R3>; canceled: () => Task<R4> }): Task<R2 | R3 | R4> {
|
|
868
1082
|
return chainTaskMaybe(this, (maybe) => {
|
|
869
|
-
return maybe.
|
|
1083
|
+
return maybe.match<Task<R2 | R3 | R4>>({
|
|
870
1084
|
just: (either) => {
|
|
871
|
-
return either.
|
|
1085
|
+
return either.match<Task<R2 | R3>>({
|
|
872
1086
|
right: op.resolved,
|
|
873
1087
|
left: op.rejected,
|
|
874
|
-
})
|
|
1088
|
+
});
|
|
875
1089
|
},
|
|
876
1090
|
nothing: op.canceled,
|
|
877
|
-
})
|
|
1091
|
+
});
|
|
878
1092
|
});
|
|
879
1093
|
}
|
|
880
1094
|
}
|
|
1095
|
+
|
|
1096
|
+
function reportError(error: unknown): void {
|
|
1097
|
+
if (typeof globalThis.reportError === 'function') {
|
|
1098
|
+
globalThis.reportError(error);
|
|
1099
|
+
}
|
|
1100
|
+
}
|