t-tasks 2.0.0 → 2.1.1
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 +144 -21
- package/dist/t-tasks.esm.js +72 -37
- package/dist/t-tasks.esm.js.map +1 -1
- package/dist/t-tasks.js +72 -37
- package/dist/t-tasks.js.map +1 -1
- package/package.json +1 -1
- package/src/either.ts +62 -5
- package/src/maybe.ts +54 -3
- package/src/task.ts +142 -76
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,11 @@ 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
|
+
*/
|
|
181
188
|
resolved: () => Cancelable<R> | null;
|
|
182
189
|
|
|
183
190
|
/**
|
|
@@ -188,14 +195,17 @@ export interface Task<R> extends TaskBase<R> {
|
|
|
188
195
|
resolve: () => TaskInvoke<R>;
|
|
189
196
|
|
|
190
197
|
/**
|
|
191
|
-
* Invoke underlying
|
|
198
|
+
* Invoke underlying cancel method without error
|
|
199
|
+
*
|
|
200
|
+
* @returns 'true' when the task was still pending and cancelation was applied
|
|
192
201
|
*/
|
|
193
202
|
cancel: () => boolean;
|
|
194
203
|
|
|
195
204
|
/**
|
|
196
|
-
* Invoke underlying
|
|
205
|
+
* Invoke underlying cancel method with error
|
|
197
206
|
*
|
|
198
207
|
* @param error error value to be injected from outside
|
|
208
|
+
* @returns 'true' when the task was still pending and the error was applied
|
|
199
209
|
*/
|
|
200
210
|
reject: (error: any) => boolean;
|
|
201
211
|
|
|
@@ -263,7 +273,7 @@ export namespace Task {
|
|
|
263
273
|
*
|
|
264
274
|
* @template R returned task's resolve type
|
|
265
275
|
* @param error error to be returned upon awaiting
|
|
266
|
-
* @returns task
|
|
276
|
+
* @returns task rejected with the specified error
|
|
267
277
|
*/
|
|
268
278
|
export function rejected<R>(error: any): Task<R> {
|
|
269
279
|
return new TaskClass<R>({ resolved: true, result: Maybe.just(Either.left(error)) });
|
|
@@ -273,7 +283,7 @@ export namespace Task {
|
|
|
273
283
|
* Invariant task constructor creating canceled task
|
|
274
284
|
*
|
|
275
285
|
* @template R returned task's resolve type
|
|
276
|
-
* @returns task
|
|
286
|
+
* @returns canceled task
|
|
277
287
|
*/
|
|
278
288
|
export function canceled<R>(): Task<R> {
|
|
279
289
|
return new TaskClass<R>({ resolved: true, result: Maybe.nothing() });
|
|
@@ -350,10 +360,12 @@ export namespace Task {
|
|
|
350
360
|
/**
|
|
351
361
|
* Generic callback task
|
|
352
362
|
*
|
|
353
|
-
* Usefull for creating custom tasks from success and error callbacks and cancelaton function. Synchronous callbacks are not supported, @see
|
|
363
|
+
* Usefull for creating custom tasks from success and error callbacks and cancelaton function. Synchronous callbacks are not supported, @see fromFunction
|
|
354
364
|
*
|
|
365
|
+
* @template H cancelation handler type
|
|
366
|
+
* @template R returned task resolve type
|
|
355
367
|
* @param create task body with success and error callbacks
|
|
356
|
-
* @param
|
|
368
|
+
* @param onCancel cancelation function intended for stopping task execution
|
|
357
369
|
* @returns task resolving to success value
|
|
358
370
|
*
|
|
359
371
|
* @example
|
|
@@ -460,9 +472,8 @@ export namespace Task {
|
|
|
460
472
|
/**
|
|
461
473
|
* Convinience shortcut for yielding timers
|
|
462
474
|
*
|
|
463
|
-
* @
|
|
464
|
-
* @
|
|
465
|
-
* @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*
|
|
466
477
|
*/
|
|
467
478
|
export function timeoutGenerator(delay: number) {
|
|
468
479
|
return Task.timeout(delay).generator();
|
|
@@ -500,6 +511,7 @@ export namespace Task {
|
|
|
500
511
|
*
|
|
501
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
|
|
502
513
|
*
|
|
514
|
+
* @template T yielded underlying type
|
|
503
515
|
* @template TT yielded task type
|
|
504
516
|
* @template R returned task resolve type
|
|
505
517
|
* @param taskGeneratorFunction task generator function
|
|
@@ -575,11 +587,12 @@ export namespace Task {
|
|
|
575
587
|
*
|
|
576
588
|
* Simplifies wrighting functions returning generated tasks
|
|
577
589
|
*
|
|
578
|
-
* @template
|
|
590
|
+
* @template A generator arguments
|
|
591
|
+
* @template T yielded underlying type
|
|
579
592
|
* @template TT yielded task type
|
|
580
593
|
* @template R returned task resolve type
|
|
581
594
|
* @param taskGeneratorFunction function* (...args) task generator function
|
|
582
|
-
* @returns task resolving to generator's return type
|
|
595
|
+
* @returns task function resolving to generator's return type
|
|
583
596
|
*/
|
|
584
597
|
export function generateFunction<A extends any[], T, TT extends Task<T>, R>(taskGeneratorFunction: TaskGeneratorFunction<A, T, TT, R>): TaskFunction<A, R> {
|
|
585
598
|
return (...args: A) => generate(() => taskGeneratorFunction(...args));
|
|
@@ -609,6 +622,7 @@ export namespace Task {
|
|
|
609
622
|
/**
|
|
610
623
|
* Start multiple tasks one after another
|
|
611
624
|
*
|
|
625
|
+
* @template T underlying task type
|
|
612
626
|
* @param taskFunctions list of task functions (without arguments)
|
|
613
627
|
* @returns composite task invoring every task in order and resolving to the list of results
|
|
614
628
|
*/
|
|
@@ -631,9 +645,9 @@ export namespace Task {
|
|
|
631
645
|
*
|
|
632
646
|
* @template T underlying task type
|
|
633
647
|
* @param tasks iterable of tasks to execute
|
|
634
|
-
* @
|
|
648
|
+
* @returns task resolving to the list of results
|
|
635
649
|
*/
|
|
636
|
-
export function all<T>(tasks: Iterable<Task<T>>) {
|
|
650
|
+
export function all<T>(tasks: Iterable<Task<T>>): Task<T[]> {
|
|
637
651
|
const taskArray = Array.from(tasks);
|
|
638
652
|
if (taskArray.length === 0) {
|
|
639
653
|
return Task.resolved([]);
|
|
@@ -677,43 +691,48 @@ export namespace Task {
|
|
|
677
691
|
*
|
|
678
692
|
* @template T underlying task type
|
|
679
693
|
* @param tasks iterable of tasks to execute
|
|
680
|
-
* @
|
|
694
|
+
* @returns task resolving to the result of first successfull task
|
|
681
695
|
*/
|
|
682
|
-
export function any<T>(tasks: Iterable<Task<T>>) {
|
|
683
|
-
const cell = settleCell<Cancelable<T>>();
|
|
684
|
-
|
|
696
|
+
export function any<T>(tasks: Iterable<Task<T>>): Task<T> {
|
|
685
697
|
const taskArray = Array.from(tasks);
|
|
686
698
|
|
|
687
|
-
if (taskArray.length
|
|
688
|
-
return Task.
|
|
699
|
+
if (taskArray.length === 0) {
|
|
700
|
+
return Task.rejected([]);
|
|
689
701
|
}
|
|
690
702
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const resolved = (value: Maybe<T>) => {
|
|
696
|
-
cell.resolve(value.map(Either.right));
|
|
697
|
-
cancel(Maybe.nothing());
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
const rejected = (error: any, i: number) => {
|
|
701
|
-
list[i] = Maybe.just(error);
|
|
703
|
+
return Task.fromCallback<Task<T>[], T>((resolve, reject, cancel) => {
|
|
704
|
+
const errors: Maybe<any>[] = taskArray.map(() => Maybe.nothing());
|
|
705
|
+
let remaining = taskArray.length;
|
|
702
706
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
+
const checkAllFailed = () => {
|
|
708
|
+
remaining--;
|
|
709
|
+
if (remaining === 0) {
|
|
710
|
+
const rawErrors = errors.map((e) =>
|
|
711
|
+
e.match({ just: (err) => err, nothing: () => undefined })
|
|
712
|
+
);
|
|
713
|
+
reject(rawErrors);
|
|
714
|
+
}
|
|
715
|
+
};
|
|
707
716
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
717
|
+
taskArray.forEach((task, i) => {
|
|
718
|
+
task.matchTap({
|
|
719
|
+
resolved: (value) => {
|
|
720
|
+
resolve(value);
|
|
721
|
+
taskArray.forEach((t) => t.cancel());
|
|
722
|
+
},
|
|
723
|
+
rejected: (error) => {
|
|
724
|
+
errors[i] = Maybe.just(error);
|
|
725
|
+
checkAllFailed();
|
|
726
|
+
},
|
|
727
|
+
canceled: () => {
|
|
728
|
+
cancel();
|
|
729
|
+
taskArray.forEach((t) => t.cancel());
|
|
730
|
+
},
|
|
731
|
+
});
|
|
713
732
|
});
|
|
714
|
-
});
|
|
715
733
|
|
|
716
|
-
|
|
734
|
+
return taskArray;
|
|
735
|
+
}, (subtasks) => subtasks.forEach((t) => t.cancel()));
|
|
717
736
|
}
|
|
718
737
|
|
|
719
738
|
/**
|
|
@@ -722,12 +741,13 @@ export namespace Task {
|
|
|
722
741
|
* If the second task resolves sooner than the first, resulting task is canceled
|
|
723
742
|
* Otherwise the resulting task resolves together with the first one
|
|
724
743
|
*
|
|
744
|
+
* @template T underlying task type
|
|
725
745
|
* @param task task to limit
|
|
726
746
|
* @param limitTask limiting task
|
|
727
747
|
* @returns task limites according to limitTask
|
|
728
748
|
*/
|
|
729
749
|
export function limit<T>(task: Task<T>, limitTask: Task<void>) {
|
|
730
|
-
return Task.any<T>([task, limitTask.chain<T>(Task.canceled)])
|
|
750
|
+
return Task.any<T>([task, limitTask.chain<T>(Task.canceled)]);
|
|
731
751
|
}
|
|
732
752
|
|
|
733
753
|
/**
|
|
@@ -736,7 +756,9 @@ export namespace Task {
|
|
|
736
756
|
* Given task is re-generated in case of failure (both external and internal)
|
|
737
757
|
* Resulting task is still cancelable by standard means
|
|
738
758
|
*
|
|
759
|
+
* @template T underlying task type
|
|
739
760
|
* @param taskFunction task preoducing function
|
|
761
|
+
* @returns task that retries until the produced task resolves
|
|
740
762
|
*/
|
|
741
763
|
export function repeat<T>(taskFunction: TaskFunction<[], T>) {
|
|
742
764
|
const sequentor = (): Task<T> => taskFunction().chainRejected(sequentor);
|
|
@@ -806,7 +828,7 @@ const settleCell = <T>(): SettleCell<T> => {
|
|
|
806
828
|
};
|
|
807
829
|
};
|
|
808
830
|
|
|
809
|
-
function chainTaskMaybe<R, R2>(parent:
|
|
831
|
+
function chainTaskMaybe<R, R2>(parent: Task<R>, op: (value: Cancelable<R>) => Task<R2>): Task<R2> {
|
|
810
832
|
const cell = settleCell<Cancelable<R2>>();
|
|
811
833
|
|
|
812
834
|
let state:
|
|
@@ -862,36 +884,74 @@ function chainTaskMaybe<R, R2>(parent: TaskBase<R>, op: (value: Cancelable<R>) =
|
|
|
862
884
|
});
|
|
863
885
|
}
|
|
864
886
|
|
|
865
|
-
function
|
|
866
|
-
|
|
867
|
-
}
|
|
887
|
+
function mapTaskMaybe<R, R2>(parent: Task<R>, op: (value: Cancelable<R>) => Cancelable<R2>): Task<R2> {
|
|
888
|
+
const cell = settleCell<Cancelable<R2>>();
|
|
868
889
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
890
|
+
let state:
|
|
891
|
+
| { phase: 'parent' }
|
|
892
|
+
| { phase: 'transform', error: Maybe<any> | null }
|
|
893
|
+
| { phase: 'closed' } = { phase: 'parent' };
|
|
894
|
+
|
|
895
|
+
parent._invoke((result) => {
|
|
896
|
+
state = { phase: 'transform', error: null }
|
|
897
|
+
|
|
898
|
+
let value: Cancelable<R2> | null = null;
|
|
899
|
+
try {
|
|
900
|
+
value = op(result);
|
|
901
|
+
} catch (e) {
|
|
902
|
+
cell.resolve(Maybe.just(Either.left(e)));
|
|
903
|
+
state = { phase: 'closed' };
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
const transformError = state.phase === 'transform' ? state.error : null;
|
|
908
|
+
|
|
909
|
+
if (transformError) {
|
|
910
|
+
cell.resolve(transformError.map(Either.left));
|
|
911
|
+
} else {
|
|
912
|
+
cell.resolve(value);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
state = { phase: 'closed' };
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
return Task.create(cell.promise, (error) => {
|
|
919
|
+
if (cell.settled()) {
|
|
920
|
+
return false;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
if (state.phase === 'parent') {
|
|
924
|
+
return parent._cancel(error);
|
|
925
|
+
} else if (state.phase === 'transform') {
|
|
926
|
+
state.error = error;
|
|
927
|
+
return true;
|
|
928
|
+
} else {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
879
931
|
});
|
|
880
932
|
}
|
|
881
933
|
|
|
882
|
-
function
|
|
883
|
-
|
|
934
|
+
function tapTaskMaybe<R>(parent: Task<R>, op: (value: Cancelable<R>) => void): Task<R> {
|
|
935
|
+
parent._invoke((result) => {
|
|
936
|
+
try {
|
|
937
|
+
op(result);
|
|
938
|
+
} catch (e) {
|
|
939
|
+
reportError(e);
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
return parent;
|
|
884
944
|
}
|
|
885
945
|
|
|
886
|
-
function
|
|
887
|
-
return
|
|
888
|
-
|
|
946
|
+
function chainTaskEither<R, R2>(_task: Task<R>, op: (value: Rejectable<R>) => Task<R2>): Task<R2> {
|
|
947
|
+
return chainTaskMaybe<R, R2>(_task, (maybe) => maybe.map(op).orMap<Task<R2>>(Task.canceled).just);
|
|
948
|
+
}
|
|
889
949
|
|
|
890
|
-
|
|
891
|
-
|
|
950
|
+
function mapTaskEither<R, R2>(_task: Task<R>, op: (value: Rejectable<R>) => Rejectable<R2>): Task<R2> {
|
|
951
|
+
return mapTaskMaybe<R, R2>(_task, (maybe) => maybe.map(op));
|
|
892
952
|
}
|
|
893
953
|
|
|
894
|
-
function tapTaskEither<R>(_task:
|
|
954
|
+
function tapTaskEither<R>(_task: Task<R>, op: (value: Rejectable<R>) => void): Task<R> {
|
|
895
955
|
return tapTaskMaybe<R>(_task, (maybe) => maybe.tap(op));
|
|
896
956
|
}
|
|
897
957
|
|
|
@@ -927,35 +987,35 @@ class TaskClass<R> implements Task<R> {
|
|
|
927
987
|
}
|
|
928
988
|
}
|
|
929
989
|
|
|
930
|
-
tapCanceled(op: () => void) {
|
|
990
|
+
tapCanceled(op: () => void): Task<R> {
|
|
931
991
|
return tapTaskMaybe<R>(this, (maybe) => maybe.orTap(op));
|
|
932
992
|
}
|
|
933
|
-
tapRejected(op: (error: any) => void) {
|
|
993
|
+
tapRejected(op: (error: any) => void): Task<R> {
|
|
934
994
|
return tapTaskEither<R>(this, (either) => either.orTap(op));
|
|
935
995
|
}
|
|
936
|
-
tap(op: (value: R) => void) {
|
|
996
|
+
tap(op: (value: R) => void): Task<R> {
|
|
937
997
|
return tapTaskEither<R>(this, (either) => either.tap(op));
|
|
938
998
|
}
|
|
939
999
|
|
|
940
|
-
mapCanceled<R2>(op: () => R2) {
|
|
1000
|
+
mapCanceled<R2>(op: () => R2): Task<R | R2> {
|
|
941
1001
|
return mapTaskMaybe<R, R | R2>(this, (maybe) => maybe.orMap(() => Either.right(op())));
|
|
942
1002
|
}
|
|
943
|
-
mapRejected<R2>(op: (error: any) => R2) {
|
|
1003
|
+
mapRejected<R2>(op: (error: any) => R2): Task<R | R2> {
|
|
944
1004
|
return mapTaskEither<R, R | R2>(this, (either) => either.orMap(op));
|
|
945
1005
|
}
|
|
946
|
-
map<R2>(op: (value: R) => R2) {
|
|
1006
|
+
map<R2>(op: (value: R) => R2): Task<R2> {
|
|
947
1007
|
return mapTaskEither<R, R2>(this, (either) => either.map(op));
|
|
948
1008
|
}
|
|
949
1009
|
|
|
950
|
-
chainCanceled<R2>(op: () => Task<R2>) {
|
|
1010
|
+
chainCanceled<R2>(op: () => Task<R2>): Task<R | R2> {
|
|
951
1011
|
const mapEither = (either: Rejectable<R>) => either.map(Task.resolved).orMap<Task<R>>(Task.rejected).right;
|
|
952
1012
|
|
|
953
1013
|
return chainTaskMaybe<R, R | R2>(this, (maybe) => maybe.map(mapEither).orMap(op).just);
|
|
954
1014
|
}
|
|
955
|
-
chainRejected<R2>(op: (error: any) => Task<R2>) {
|
|
1015
|
+
chainRejected<R2>(op: (error: any) => Task<R2>): Task<R | R2> {
|
|
956
1016
|
return chainTaskEither<R, R | R2>(this, (either) => either.map(Task.resolved).orMap(op).right);
|
|
957
1017
|
}
|
|
958
|
-
chain<R2>(op: (value: R) => Task<R2>) {
|
|
1018
|
+
chain<R2>(op: (value: R) => Task<R2>): Task<R2> {
|
|
959
1019
|
return chainTaskEither<R, R2>(this, (either) => either.map(op).orMap<Task<R2>>(Task.rejected).right);
|
|
960
1020
|
}
|
|
961
1021
|
|
|
@@ -995,7 +1055,7 @@ class TaskClass<R> implements Task<R> {
|
|
|
995
1055
|
})(this);
|
|
996
1056
|
}
|
|
997
1057
|
|
|
998
|
-
matchTap(op: { resolved: (value: R) => void; rejected: (error: any) => void; canceled: () => void }) {
|
|
1058
|
+
matchTap(op: { resolved: (value: R) => void; rejected: (error: any) => void; canceled: () => void }): Task<R> {
|
|
999
1059
|
return tapTaskMaybe(this, (maybe) => {
|
|
1000
1060
|
return maybe.matchTap({
|
|
1001
1061
|
just: (either) => {
|
|
@@ -1009,7 +1069,7 @@ class TaskClass<R> implements Task<R> {
|
|
|
1009
1069
|
});
|
|
1010
1070
|
}
|
|
1011
1071
|
|
|
1012
|
-
matchMap<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => R2; rejected: (error: any) => R3; canceled: () => R4 }) {
|
|
1072
|
+
matchMap<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => R2; rejected: (error: any) => R3; canceled: () => R4 }): Task<R2 | R3 | R4> {
|
|
1013
1073
|
return mapTaskMaybe(this, (maybe) => {
|
|
1014
1074
|
return Maybe.just(maybe.match<Right<R2 | R3 | R4, any>>({
|
|
1015
1075
|
just: (either) => {
|
|
@@ -1023,7 +1083,7 @@ class TaskClass<R> implements Task<R> {
|
|
|
1023
1083
|
});
|
|
1024
1084
|
}
|
|
1025
1085
|
|
|
1026
|
-
matchChain<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => Task<R2>; rejected: (error: any) => Task<R3>; canceled: () => Task<R4> }) {
|
|
1086
|
+
matchChain<R2, R3 = R2, R4 = R3>(op: { resolved: (value: R) => Task<R2>; rejected: (error: any) => Task<R3>; canceled: () => Task<R4> }): Task<R2 | R3 | R4> {
|
|
1027
1087
|
return chainTaskMaybe(this, (maybe) => {
|
|
1028
1088
|
return maybe.match<Task<R2 | R3 | R4>>({
|
|
1029
1089
|
just: (either) => {
|
|
@@ -1037,3 +1097,9 @@ class TaskClass<R> implements Task<R> {
|
|
|
1037
1097
|
});
|
|
1038
1098
|
}
|
|
1039
1099
|
}
|
|
1100
|
+
|
|
1101
|
+
function reportError(error: unknown): void {
|
|
1102
|
+
if (typeof globalThis.reportError === 'function') {
|
|
1103
|
+
globalThis.reportError(error);
|
|
1104
|
+
}
|
|
1105
|
+
}
|