@nlozgachev/pipekit 0.1.7 → 0.2.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/README.md +41 -218
- package/esm/src/Core/Arr.js +14 -14
- package/esm/src/Core/Option.js +16 -16
- package/esm/src/Core/Rec.js +1 -1
- package/esm/src/Core/Result.js +14 -14
- package/esm/src/Core/Task.js +73 -5
- package/esm/src/Core/TaskOption.js +3 -3
- package/esm/src/Core/TaskResult.js +62 -5
- package/esm/src/Core/These.js +40 -40
- package/esm/src/Types/Brand.js +3 -3
- package/package.json +2 -1
- package/script/src/Core/Arr.js +14 -14
- package/script/src/Core/Option.js +16 -16
- package/script/src/Core/Rec.js +1 -1
- package/script/src/Core/Result.js +14 -14
- package/script/src/Core/Task.js +73 -5
- package/script/src/Core/TaskOption.js +3 -3
- package/script/src/Core/TaskResult.js +62 -5
- package/script/src/Core/These.js +40 -40
- package/script/src/Types/Brand.js +3 -3
- package/types/src/Core/Arr.d.ts +3 -3
- package/types/src/Core/Arr.d.ts.map +1 -1
- package/types/src/Core/Option.d.ts +9 -9
- package/types/src/Core/Option.d.ts.map +1 -1
- package/types/src/Core/Rec.d.ts.map +1 -1
- package/types/src/Core/Result.d.ts +9 -9
- package/types/src/Core/Result.d.ts.map +1 -1
- package/types/src/Core/Task.d.ts +49 -5
- package/types/src/Core/Task.d.ts.map +1 -1
- package/types/src/Core/TaskOption.d.ts.map +1 -1
- package/types/src/Core/TaskResult.d.ts +40 -1
- package/types/src/Core/TaskResult.d.ts.map +1 -1
- package/types/src/Core/These.d.ts +31 -31
- package/types/src/Core/These.d.ts.map +1 -1
- package/types/src/Types/Brand.d.ts +5 -5
|
@@ -12,11 +12,11 @@ var Option;
|
|
|
12
12
|
* Option.of(42); // Some(42)
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
Option.of = (value) => Option.
|
|
15
|
+
Option.of = (value) => Option.some(value);
|
|
16
16
|
/**
|
|
17
17
|
* Creates a Some containing the given value.
|
|
18
18
|
*/
|
|
19
|
-
Option.
|
|
19
|
+
Option.some = (value) => ({ kind: "Some", value });
|
|
20
20
|
/**
|
|
21
21
|
* Type guard that checks if a Option is Some.
|
|
22
22
|
*/
|
|
@@ -24,7 +24,7 @@ var Option;
|
|
|
24
24
|
/**
|
|
25
25
|
* Creates a None (empty Option).
|
|
26
26
|
*/
|
|
27
|
-
Option.
|
|
27
|
+
Option.none = () => ({ kind: "None" });
|
|
28
28
|
/**
|
|
29
29
|
* Type guard that checks if a Option is None.
|
|
30
30
|
*/
|
|
@@ -39,7 +39,7 @@ var Option;
|
|
|
39
39
|
* Option.fromNullable(42); // Some(42)
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
Option.fromNullable = (value) => value === null || value === undefined ? Option.
|
|
42
|
+
Option.fromNullable = (value) => value === null || value === undefined ? Option.none() : Option.some(value);
|
|
43
43
|
/**
|
|
44
44
|
* Extracts the value from a Option, returning null if None.
|
|
45
45
|
*/
|
|
@@ -52,7 +52,7 @@ var Option;
|
|
|
52
52
|
* Creates a Option from a possibly undefined value.
|
|
53
53
|
* Returns None if undefined, Some otherwise.
|
|
54
54
|
*/
|
|
55
|
-
Option.fromUndefined = (value) => value === undefined ? Option.
|
|
55
|
+
Option.fromUndefined = (value) => value === undefined ? Option.none() : Option.some(value);
|
|
56
56
|
/**
|
|
57
57
|
* Converts an Option to a Result.
|
|
58
58
|
* Some becomes Ok, None becomes Err with the provided error.
|
|
@@ -65,33 +65,33 @@ var Option;
|
|
|
65
65
|
* ); // Ok(42)
|
|
66
66
|
*
|
|
67
67
|
* pipe(
|
|
68
|
-
* Option.
|
|
68
|
+
* Option.none(),
|
|
69
69
|
* Option.toResult(() => "Value was missing")
|
|
70
70
|
* ); // Err("Value was missing")
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
|
-
Option.toResult = (onNone) => (data) => Option.isSome(data) ? Result_js_1.Result.
|
|
73
|
+
Option.toResult = (onNone) => (data) => Option.isSome(data) ? Result_js_1.Result.ok(data.value) : Result_js_1.Result.err(onNone());
|
|
74
74
|
/**
|
|
75
75
|
* Creates an Option from a Result.
|
|
76
76
|
* Ok becomes Some, Err becomes None (the error is discarded).
|
|
77
77
|
*
|
|
78
78
|
* @example
|
|
79
79
|
* ```ts
|
|
80
|
-
* Option.fromResult(Result.
|
|
81
|
-
* Option.fromResult(Result.
|
|
80
|
+
* Option.fromResult(Result.ok(42)); // Some(42)
|
|
81
|
+
* Option.fromResult(Result.err("oops")); // None
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
|
-
Option.fromResult = (data) => Result_js_1.Result.isOk(data) ? Option.
|
|
84
|
+
Option.fromResult = (data) => Result_js_1.Result.isOk(data) ? Option.some(data.value) : Option.none();
|
|
85
85
|
/**
|
|
86
86
|
* Transforms the value inside a Option if it exists.
|
|
87
87
|
*
|
|
88
88
|
* @example
|
|
89
89
|
* ```ts
|
|
90
90
|
* pipe(Option.of(5), Option.map(n => n * 2)); // Some(10)
|
|
91
|
-
* pipe(Option.
|
|
91
|
+
* pipe(Option.none(), Option.map(n => n * 2)); // None
|
|
92
92
|
* ```
|
|
93
93
|
*/
|
|
94
|
-
Option.map = (f) => (data) => Option.isSome(data) ? Option.
|
|
94
|
+
Option.map = (f) => (data) => Option.isSome(data) ? Option.some(f(data.value)) : data;
|
|
95
95
|
/**
|
|
96
96
|
* Chains Option computations. If the first is Some, passes the value to f.
|
|
97
97
|
* If the first is None, propagates None.
|
|
@@ -100,7 +100,7 @@ var Option;
|
|
|
100
100
|
* ```ts
|
|
101
101
|
* const parseNumber = (s: string): Option<number> => {
|
|
102
102
|
* const n = parseInt(s, 10);
|
|
103
|
-
* return isNaN(n) ? Option.
|
|
103
|
+
* return isNaN(n) ? Option.none() : Option.of(n);
|
|
104
104
|
* };
|
|
105
105
|
*
|
|
106
106
|
* pipe(Option.of("42"), Option.chain(parseNumber)); // Some(42)
|
|
@@ -144,7 +144,7 @@ var Option;
|
|
|
144
144
|
* @example
|
|
145
145
|
* ```ts
|
|
146
146
|
* pipe(Option.of(5), Option.getOrElse(0)); // 5
|
|
147
|
-
* pipe(Option.
|
|
147
|
+
* pipe(Option.none(), Option.getOrElse(0)); // 0
|
|
148
148
|
* ```
|
|
149
149
|
*/
|
|
150
150
|
Option.getOrElse = (defaultValue) => (data) => Option.isSome(data) ? data.value : defaultValue;
|
|
@@ -176,7 +176,7 @@ var Option;
|
|
|
176
176
|
* pipe(Option.of(2), Option.filter(n => n > 3)); // None
|
|
177
177
|
* ```
|
|
178
178
|
*/
|
|
179
|
-
Option.filter = (predicate) => (data) => Option.isSome(data) && predicate(data.value) ? data : Option.
|
|
179
|
+
Option.filter = (predicate) => (data) => Option.isSome(data) && predicate(data.value) ? data : Option.none();
|
|
180
180
|
/**
|
|
181
181
|
* Recovers from a None by providing a fallback Option.
|
|
182
182
|
*/
|
|
@@ -194,5 +194,5 @@ var Option;
|
|
|
194
194
|
* ); // Some(8)
|
|
195
195
|
* ```
|
|
196
196
|
*/
|
|
197
|
-
Option.ap = (arg) => (data) => Option.isSome(data) && Option.isSome(arg) ? Option.
|
|
197
|
+
Option.ap = (arg) => (data) => Option.isSome(data) && Option.isSome(arg) ? Option.some(data.value(arg.value)) : Option.none();
|
|
198
198
|
})(Option || (exports.Option = Option = {}));
|
package/script/src/Core/Rec.js
CHANGED
|
@@ -90,7 +90,7 @@ var Rec;
|
|
|
90
90
|
* pipe({ a: 1, b: 2 }, Rec.lookup("c")); // None
|
|
91
91
|
* ```
|
|
92
92
|
*/
|
|
93
|
-
Rec.lookup = (key) => (data) => Object.prototype.hasOwnProperty.call(data, key) ? Option_js_1.Option.
|
|
93
|
+
Rec.lookup = (key) => (data) => Object.prototype.hasOwnProperty.call(data, key) ? Option_js_1.Option.some(data[key]) : Option_js_1.Option.none();
|
|
94
94
|
/**
|
|
95
95
|
* Returns all keys of a record.
|
|
96
96
|
*/
|
|
@@ -11,15 +11,15 @@ var Result;
|
|
|
11
11
|
* Result.of(42); // Ok(42)
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
|
-
Result.of = (value) => Result.
|
|
14
|
+
Result.of = (value) => Result.ok(value);
|
|
15
15
|
/**
|
|
16
16
|
* Creates a failed Result with the given error.
|
|
17
17
|
*/
|
|
18
|
-
Result.
|
|
18
|
+
Result.err = (error) => ({ kind: "Error", error });
|
|
19
19
|
/**
|
|
20
20
|
* Creates a successful Result with the given value.
|
|
21
21
|
*/
|
|
22
|
-
Result.
|
|
22
|
+
Result.ok = (value) => ({ kind: "Ok", value });
|
|
23
23
|
/**
|
|
24
24
|
* Type guard that checks if an Result is Ok.
|
|
25
25
|
*/
|
|
@@ -43,10 +43,10 @@ var Result;
|
|
|
43
43
|
*/
|
|
44
44
|
Result.tryCatch = (f, onError) => {
|
|
45
45
|
try {
|
|
46
|
-
return Result.
|
|
46
|
+
return Result.ok(f());
|
|
47
47
|
}
|
|
48
48
|
catch (e) {
|
|
49
|
-
return Result.
|
|
49
|
+
return Result.err(onError(e));
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
/**
|
|
@@ -55,19 +55,19 @@ var Result;
|
|
|
55
55
|
* @example
|
|
56
56
|
* ```ts
|
|
57
57
|
* pipe(Result.of(5), Result.map(n => n * 2)); // Ok(10)
|
|
58
|
-
* pipe(Result.
|
|
58
|
+
* pipe(Result.err("error"), Result.map(n => n * 2)); // Err("error")
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
|
-
Result.map = (f) => (data) => Result.isOk(data) ? Result.
|
|
61
|
+
Result.map = (f) => (data) => Result.isOk(data) ? Result.ok(f(data.value)) : data;
|
|
62
62
|
/**
|
|
63
63
|
* Transforms the error value inside an Result.
|
|
64
64
|
*
|
|
65
65
|
* @example
|
|
66
66
|
* ```ts
|
|
67
|
-
* pipe(Result.
|
|
67
|
+
* pipe(Result.err("oops"), Result.mapError(e => e.toUpperCase())); // Err("OOPS")
|
|
68
68
|
* ```
|
|
69
69
|
*/
|
|
70
|
-
Result.mapError = (f) => (data) => Result.isErr(data) ? Result.
|
|
70
|
+
Result.mapError = (f) => (data) => Result.isErr(data) ? Result.err(f(data.error)) : data;
|
|
71
71
|
/**
|
|
72
72
|
* Chains Result computations. If the first is Ok, passes the value to f.
|
|
73
73
|
* If the first is Err, propagates the error.
|
|
@@ -75,7 +75,7 @@ var Result;
|
|
|
75
75
|
* @example
|
|
76
76
|
* ```ts
|
|
77
77
|
* const validatePositive = (n: number): Result<string, number> =>
|
|
78
|
-
* n > 0 ? Result.of(n) : Result.
|
|
78
|
+
* n > 0 ? Result.of(n) : Result.err("Must be positive");
|
|
79
79
|
*
|
|
80
80
|
* pipe(Result.of(5), Result.chain(validatePositive)); // Ok(5)
|
|
81
81
|
* pipe(Result.of(-1), Result.chain(validatePositive)); // Err("Must be positive")
|
|
@@ -118,7 +118,7 @@ var Result;
|
|
|
118
118
|
* @example
|
|
119
119
|
* ```ts
|
|
120
120
|
* pipe(Result.of(5), Result.getOrElse(0)); // 5
|
|
121
|
-
* pipe(Result.
|
|
121
|
+
* pipe(Result.err("error"), Result.getOrElse(0)); // 0
|
|
122
122
|
* ```
|
|
123
123
|
*/
|
|
124
124
|
Result.getOrElse = (defaultValue) => (data) => Result.isOk(data) ? data.value : defaultValue;
|
|
@@ -154,8 +154,8 @@ var Result;
|
|
|
154
154
|
*
|
|
155
155
|
* @example
|
|
156
156
|
* ```ts
|
|
157
|
-
* Result.toOption(Result.
|
|
158
|
-
* Result.toOption(Result.
|
|
157
|
+
* Result.toOption(Result.ok(42)); // Some(42)
|
|
158
|
+
* Result.toOption(Result.err("oops")); // None
|
|
159
159
|
* ```
|
|
160
160
|
*/
|
|
161
161
|
Result.toOption = (data) => Result.isOk(data) ? { kind: "Some", value: data.value } : { kind: "None" };
|
|
@@ -172,5 +172,5 @@ var Result;
|
|
|
172
172
|
* ); // Ok(8)
|
|
173
173
|
* ```
|
|
174
174
|
*/
|
|
175
|
-
Result.ap = (arg) => (data) => Result.isOk(data) && Result.isOk(arg) ? Result.
|
|
175
|
+
Result.ap = (arg) => (data) => Result.isOk(data) && Result.isOk(arg) ? Result.ok(data.value(arg.value)) : Result.isErr(data) ? data : arg;
|
|
176
176
|
})(Result || (exports.Result = Result = {}));
|
package/script/src/Core/Task.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Task = void 0;
|
|
4
|
+
const Result_js_1 = require("./Result.js");
|
|
4
5
|
var Task;
|
|
5
6
|
(function (Task) {
|
|
6
7
|
/**
|
|
@@ -13,10 +14,6 @@ var Task;
|
|
|
13
14
|
* ```
|
|
14
15
|
*/
|
|
15
16
|
Task.of = (value) => () => Promise.resolve(value);
|
|
16
|
-
/**
|
|
17
|
-
* Creates a Task that will reject with the given error.
|
|
18
|
-
*/
|
|
19
|
-
Task.fail = (error) => () => Promise.reject(error);
|
|
20
17
|
/**
|
|
21
18
|
* Creates a Task from a function that returns a Promise.
|
|
22
19
|
* Alias for directly creating a Task.
|
|
@@ -40,7 +37,7 @@ var Task;
|
|
|
40
37
|
*/
|
|
41
38
|
Task.map = (f) => (data) => () => data().then(f);
|
|
42
39
|
/**
|
|
43
|
-
* Chains Task computations.
|
|
40
|
+
* Chains Task computations. Passes the resolved value of the first Task to f.
|
|
44
41
|
*
|
|
45
42
|
* @example
|
|
46
43
|
* ```ts
|
|
@@ -98,6 +95,7 @@ var Task;
|
|
|
98
95
|
Task.all = (tasks) => () => Promise.all(tasks.map((t) => t()));
|
|
99
96
|
/**
|
|
100
97
|
* Delays the execution of a Task by the specified milliseconds.
|
|
98
|
+
* Useful for debouncing or rate limiting.
|
|
101
99
|
*
|
|
102
100
|
* @example
|
|
103
101
|
* ```ts
|
|
@@ -108,4 +106,74 @@ var Task;
|
|
|
108
106
|
* ```
|
|
109
107
|
*/
|
|
110
108
|
Task.delay = (ms) => (data) => () => new Promise((resolve, reject) => setTimeout(() => data().then(resolve, reject), ms));
|
|
109
|
+
/**
|
|
110
|
+
* Runs a Task a fixed number of times sequentially, collecting all results into an array.
|
|
111
|
+
* An optional delay (ms) can be inserted between runs.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* pipe(
|
|
116
|
+
* pollSensor,
|
|
117
|
+
* Task.repeat({ times: 5, delay: 1000 })
|
|
118
|
+
* )(); // Task<Reading[]> — 5 readings, one per second
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
Task.repeat = (options) => (task) => () => {
|
|
122
|
+
const { times, delay: ms } = options;
|
|
123
|
+
if (times <= 0)
|
|
124
|
+
return Promise.resolve([]);
|
|
125
|
+
const results = [];
|
|
126
|
+
const wait = () => ms !== undefined && ms > 0 ? new Promise((r) => setTimeout(r, ms)) : Promise.resolve();
|
|
127
|
+
const run = (left) => task().then((a) => {
|
|
128
|
+
results.push(a);
|
|
129
|
+
if (left <= 1)
|
|
130
|
+
return results;
|
|
131
|
+
return wait().then(() => run(left - 1));
|
|
132
|
+
});
|
|
133
|
+
return run(times);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Runs a Task repeatedly until the result satisfies a predicate, returning that result.
|
|
137
|
+
* An optional delay (ms) can be inserted between runs.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* pipe(
|
|
142
|
+
* checkStatus,
|
|
143
|
+
* Task.repeatUntil({ when: (s) => s === "ready", delay: 500 })
|
|
144
|
+
* )(); // polls every 500ms until status is "ready"
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
Task.repeatUntil = (options) => (task) => () => {
|
|
148
|
+
const { when: predicate, delay: ms } = options;
|
|
149
|
+
const wait = () => ms !== undefined && ms > 0 ? new Promise((r) => setTimeout(r, ms)) : Promise.resolve();
|
|
150
|
+
const run = () => task().then((a) => {
|
|
151
|
+
if (predicate(a))
|
|
152
|
+
return a;
|
|
153
|
+
return wait().then(run);
|
|
154
|
+
});
|
|
155
|
+
return run();
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Converts a `Task<A>` into a `Task<Result<E, A>>`, resolving to `Err` if the
|
|
159
|
+
* Task does not complete within the given time.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* pipe(
|
|
164
|
+
* fetchUser,
|
|
165
|
+
* Task.timeout(5000, () => new TimeoutError("fetch user timed out")),
|
|
166
|
+
* TaskResult.chain(processUser)
|
|
167
|
+
* );
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
Task.timeout = (ms, onTimeout) => (task) => () => {
|
|
171
|
+
let timerId;
|
|
172
|
+
return Promise.race([
|
|
173
|
+
task().then((a) => { clearTimeout(timerId); return Result_js_1.Result.ok(a); }),
|
|
174
|
+
new Promise((resolve) => {
|
|
175
|
+
timerId = setTimeout(() => resolve(Result_js_1.Result.err(onTimeout())), ms);
|
|
176
|
+
}),
|
|
177
|
+
]);
|
|
178
|
+
};
|
|
111
179
|
})(Task || (exports.Task = Task = {}));
|
|
@@ -12,7 +12,7 @@ var TaskOption;
|
|
|
12
12
|
/**
|
|
13
13
|
* Creates a TaskOption that resolves to None.
|
|
14
14
|
*/
|
|
15
|
-
TaskOption.none = () => Task_js_1.Task.of(Option_js_1.Option.
|
|
15
|
+
TaskOption.none = () => Task_js_1.Task.of(Option_js_1.Option.none());
|
|
16
16
|
/**
|
|
17
17
|
* Lifts an Option into a TaskOption.
|
|
18
18
|
*/
|
|
@@ -32,7 +32,7 @@ var TaskOption;
|
|
|
32
32
|
* );
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
|
-
TaskOption.tryCatch = (f) => () => f().then(Option_js_1.Option.of).catch(() => Option_js_1.Option.
|
|
35
|
+
TaskOption.tryCatch = (f) => () => f().then(Option_js_1.Option.of).catch(() => Option_js_1.Option.none());
|
|
36
36
|
/**
|
|
37
37
|
* Transforms the value inside a TaskOption.
|
|
38
38
|
*/
|
|
@@ -49,7 +49,7 @@ var TaskOption;
|
|
|
49
49
|
* )();
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
|
-
TaskOption.chain = (f) => (data) => Task_js_1.Task.chain((option) => Option_js_1.Option.isSome(option) ? f(option.value) : Task_js_1.Task.of(Option_js_1.Option.
|
|
52
|
+
TaskOption.chain = (f) => (data) => Task_js_1.Task.chain((option) => Option_js_1.Option.isSome(option) ? f(option.value) : Task_js_1.Task.of(Option_js_1.Option.none()))(data);
|
|
53
53
|
/**
|
|
54
54
|
* Applies a function wrapped in a TaskOption to a value wrapped in a TaskOption.
|
|
55
55
|
* Both Tasks run in parallel.
|
|
@@ -8,11 +8,11 @@ var TaskResult;
|
|
|
8
8
|
/**
|
|
9
9
|
* Wraps a value in a successful TaskResult.
|
|
10
10
|
*/
|
|
11
|
-
TaskResult.of = (value) => Task_js_1.Task.of(Result_js_1.Result.
|
|
11
|
+
TaskResult.of = (value) => Task_js_1.Task.of(Result_js_1.Result.ok(value));
|
|
12
12
|
/**
|
|
13
13
|
* Creates a failed TaskResult with the given error.
|
|
14
14
|
*/
|
|
15
|
-
TaskResult.
|
|
15
|
+
TaskResult.err = (error) => Task_js_1.Task.of(Result_js_1.Result.err(error));
|
|
16
16
|
/**
|
|
17
17
|
* Creates a TaskResult from a function that may throw.
|
|
18
18
|
* Catches any errors and transforms them using the onError function.
|
|
@@ -27,8 +27,8 @@ var TaskResult;
|
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
TaskResult.tryCatch = (f, onError) => () => f()
|
|
30
|
-
.then(Result_js_1.Result.
|
|
31
|
-
.catch((e) => Result_js_1.Result.
|
|
30
|
+
.then(Result_js_1.Result.ok)
|
|
31
|
+
.catch((e) => Result_js_1.Result.err(onError(e)));
|
|
32
32
|
/**
|
|
33
33
|
* Transforms the success value inside a TaskResult.
|
|
34
34
|
*/
|
|
@@ -41,7 +41,7 @@ var TaskResult;
|
|
|
41
41
|
* Chains TaskResult computations. If the first succeeds, passes the value to f.
|
|
42
42
|
* If the first fails, propagates the error.
|
|
43
43
|
*/
|
|
44
|
-
TaskResult.chain = (f) => (data) => Task_js_1.Task.chain((result) => Result_js_1.Result.isOk(result) ? f(result.value) : Task_js_1.Task.of(Result_js_1.Result.
|
|
44
|
+
TaskResult.chain = (f) => (data) => Task_js_1.Task.chain((result) => Result_js_1.Result.isOk(result) ? f(result.value) : Task_js_1.Task.of(Result_js_1.Result.err(result.error)))(data);
|
|
45
45
|
/**
|
|
46
46
|
* Extracts the value from a TaskResult by providing handlers for both cases.
|
|
47
47
|
*/
|
|
@@ -63,4 +63,61 @@ var TaskResult;
|
|
|
63
63
|
* Useful for logging or debugging.
|
|
64
64
|
*/
|
|
65
65
|
TaskResult.tap = (f) => (data) => Task_js_1.Task.map(Result_js_1.Result.tap(f))(data);
|
|
66
|
+
/**
|
|
67
|
+
* Re-runs a TaskResult on `Err` with configurable attempts, backoff, and retry condition.
|
|
68
|
+
*
|
|
69
|
+
* @param options.attempts - Total number of attempts (1 = no retry, 3 = up to 3 tries)
|
|
70
|
+
* @param options.backoff - Fixed delay in ms, or a function `(attempt) => ms` for computed delay
|
|
71
|
+
* @param options.when - Only retry when this returns true; defaults to always retry on Err
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* // Retry up to 3 times with exponential backoff
|
|
76
|
+
* pipe(
|
|
77
|
+
* fetchUser,
|
|
78
|
+
* TaskResult.retry({ attempts: 3, backoff: n => n * 1000 })
|
|
79
|
+
* );
|
|
80
|
+
*
|
|
81
|
+
* // Only retry on network errors, not auth errors
|
|
82
|
+
* pipe(
|
|
83
|
+
* fetchUser,
|
|
84
|
+
* TaskResult.retry({ attempts: 3, when: e => e instanceof NetworkError })
|
|
85
|
+
* );
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
TaskResult.retry = (options) => (data) => () => {
|
|
89
|
+
const { attempts, backoff, when: shouldRetry } = options;
|
|
90
|
+
const getDelay = (n) => backoff === undefined ? 0 : typeof backoff === "function" ? backoff(n) : backoff;
|
|
91
|
+
const run = (left) => data().then((result) => {
|
|
92
|
+
if (Result_js_1.Result.isOk(result))
|
|
93
|
+
return result;
|
|
94
|
+
if (left <= 1)
|
|
95
|
+
return result;
|
|
96
|
+
if (shouldRetry !== undefined && !shouldRetry(result.error))
|
|
97
|
+
return result;
|
|
98
|
+
const ms = getDelay(attempts - left + 1);
|
|
99
|
+
return (ms > 0 ? new Promise((r) => setTimeout(r, ms)) : Promise.resolve()).then(() => run(left - 1));
|
|
100
|
+
});
|
|
101
|
+
return run(attempts);
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Fails a TaskResult with a typed error if it does not resolve within the given time.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* pipe(
|
|
109
|
+
* fetchUser,
|
|
110
|
+
* TaskResult.timeout(5000, () => new TimeoutError("fetch user timed out"))
|
|
111
|
+
* );
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
TaskResult.timeout = (ms, onTimeout) => (data) => () => {
|
|
115
|
+
let timerId;
|
|
116
|
+
return Promise.race([
|
|
117
|
+
data().then((result) => { clearTimeout(timerId); return result; }),
|
|
118
|
+
new Promise((resolve) => {
|
|
119
|
+
timerId = setTimeout(() => resolve(Result_js_1.Result.err(onTimeout())), ms);
|
|
120
|
+
}),
|
|
121
|
+
]);
|
|
122
|
+
};
|
|
66
123
|
})(TaskResult || (exports.TaskResult = TaskResult = {}));
|
package/script/src/Core/These.js
CHANGED
|
@@ -9,28 +9,28 @@ var These;
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
12
|
-
* These.
|
|
12
|
+
* These.err("Something went wrong");
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
These.
|
|
15
|
+
These.err = (error) => Result_js_1.Result.err(error);
|
|
16
16
|
/**
|
|
17
17
|
* Creates a These holding only a success value (no error).
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```ts
|
|
21
|
-
* These.
|
|
21
|
+
* These.ok(42);
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
These.
|
|
24
|
+
These.ok = (value) => Result_js_1.Result.ok(value);
|
|
25
25
|
/**
|
|
26
26
|
* Creates a These holding both an error/warning and a success value.
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* ```ts
|
|
30
|
-
* These.
|
|
30
|
+
* These.both("Deprecated API used", result);
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
|
-
These.
|
|
33
|
+
These.both = (error, value) => ({
|
|
34
34
|
kind: "Both",
|
|
35
35
|
error,
|
|
36
36
|
value,
|
|
@@ -60,33 +60,33 @@ var These;
|
|
|
60
60
|
*
|
|
61
61
|
* @example
|
|
62
62
|
* ```ts
|
|
63
|
-
* pipe(These.
|
|
64
|
-
* pipe(These.
|
|
65
|
-
* pipe(These.
|
|
63
|
+
* pipe(These.ok(5), These.map(n => n * 2)); // Ok(10)
|
|
64
|
+
* pipe(These.both("warn", 5), These.map(n => n * 2)); // Both("warn", 10)
|
|
65
|
+
* pipe(These.err("err"), These.map(n => n * 2)); // Err("err")
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
68
|
These.map = (f) => (data) => {
|
|
69
69
|
if (These.isErr(data))
|
|
70
70
|
return data;
|
|
71
71
|
if (These.isOk(data))
|
|
72
|
-
return These.
|
|
73
|
-
return These.
|
|
72
|
+
return These.ok(f(data.value));
|
|
73
|
+
return These.both(data.error, f(data.value));
|
|
74
74
|
};
|
|
75
75
|
/**
|
|
76
76
|
* Transforms the error/warning value, leaving the success value unchanged.
|
|
77
77
|
*
|
|
78
78
|
* @example
|
|
79
79
|
* ```ts
|
|
80
|
-
* pipe(These.
|
|
81
|
-
* pipe(These.
|
|
80
|
+
* pipe(These.err("err"), These.mapErr(e => e.toUpperCase())); // Err("ERR")
|
|
81
|
+
* pipe(These.both("warn", 5), These.mapErr(e => e.toUpperCase())); // Both("WARN", 5)
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
84
|
These.mapErr = (f) => (data) => {
|
|
85
85
|
if (These.isOk(data))
|
|
86
86
|
return data;
|
|
87
87
|
if (These.isErr(data))
|
|
88
|
-
return These.
|
|
89
|
-
return These.
|
|
88
|
+
return These.err(f(data.error));
|
|
89
|
+
return These.both(f(data.error), data.value);
|
|
90
90
|
};
|
|
91
91
|
/**
|
|
92
92
|
* Transforms both the error and success values independently.
|
|
@@ -94,17 +94,17 @@ var These;
|
|
|
94
94
|
* @example
|
|
95
95
|
* ```ts
|
|
96
96
|
* pipe(
|
|
97
|
-
* These.
|
|
97
|
+
* These.both("warn", 5),
|
|
98
98
|
* These.bimap(e => e.toUpperCase(), n => n * 2)
|
|
99
99
|
* ); // Both("WARN", 10)
|
|
100
100
|
* ```
|
|
101
101
|
*/
|
|
102
102
|
These.bimap = (onErr, onOk) => (data) => {
|
|
103
103
|
if (These.isErr(data))
|
|
104
|
-
return These.
|
|
104
|
+
return These.err(onErr(data.error));
|
|
105
105
|
if (These.isOk(data))
|
|
106
|
-
return These.
|
|
107
|
-
return These.
|
|
106
|
+
return These.ok(onOk(data.value));
|
|
107
|
+
return These.both(onErr(data.error), onOk(data.value));
|
|
108
108
|
};
|
|
109
109
|
/**
|
|
110
110
|
* Chains These computations by passing the success value to f.
|
|
@@ -115,11 +115,11 @@ var These;
|
|
|
115
115
|
*
|
|
116
116
|
* @example
|
|
117
117
|
* ```ts
|
|
118
|
-
* const double = (n: number): These<string, number> => These.
|
|
118
|
+
* const double = (n: number): These<string, number> => These.ok(n * 2);
|
|
119
119
|
*
|
|
120
|
-
* pipe(These.
|
|
121
|
-
* pipe(These.
|
|
122
|
-
* pipe(These.
|
|
120
|
+
* pipe(These.ok(5), These.chain(double)); // Ok(10)
|
|
121
|
+
* pipe(These.both("warn", 5), These.chain(double)); // Both("warn", 10)
|
|
122
|
+
* pipe(These.err("err"), These.chain(double)); // Err("err")
|
|
123
123
|
* ```
|
|
124
124
|
*/
|
|
125
125
|
These.chain = (f) => (data) => {
|
|
@@ -128,7 +128,7 @@ var These;
|
|
|
128
128
|
if (These.isOk(data))
|
|
129
129
|
return f(data.value);
|
|
130
130
|
const result = f(data.value);
|
|
131
|
-
return These.isOk(result) ? These.
|
|
131
|
+
return These.isOk(result) ? These.both(data.error, result.value) : result;
|
|
132
132
|
};
|
|
133
133
|
/**
|
|
134
134
|
* Extracts a value from a These by providing handlers for all three cases.
|
|
@@ -179,9 +179,9 @@ var These;
|
|
|
179
179
|
*
|
|
180
180
|
* @example
|
|
181
181
|
* ```ts
|
|
182
|
-
* pipe(These.
|
|
183
|
-
* pipe(These.
|
|
184
|
-
* pipe(These.
|
|
182
|
+
* pipe(These.ok(5), These.getOrElse(0)); // 5
|
|
183
|
+
* pipe(These.both("warn", 5), These.getOrElse(0)); // 5
|
|
184
|
+
* pipe(These.err("err"), These.getOrElse(0)); // 0
|
|
185
185
|
* ```
|
|
186
186
|
*/
|
|
187
187
|
These.getOrElse = (defaultValue) => (data) => These.hasValue(data) ? data.value : defaultValue;
|
|
@@ -202,17 +202,17 @@ var These;
|
|
|
202
202
|
*
|
|
203
203
|
* @example
|
|
204
204
|
* ```ts
|
|
205
|
-
* These.swap(These.
|
|
206
|
-
* These.swap(These.
|
|
207
|
-
* These.swap(These.
|
|
205
|
+
* These.swap(These.err("err")); // Ok("err")
|
|
206
|
+
* These.swap(These.ok(5)); // Err(5)
|
|
207
|
+
* These.swap(These.both("warn", 5)); // Both(5, "warn")
|
|
208
208
|
* ```
|
|
209
209
|
*/
|
|
210
210
|
These.swap = (data) => {
|
|
211
211
|
if (These.isErr(data))
|
|
212
|
-
return These.
|
|
212
|
+
return These.ok(data.error);
|
|
213
213
|
if (These.isOk(data))
|
|
214
|
-
return These.
|
|
215
|
-
return These.
|
|
214
|
+
return These.err(data.value);
|
|
215
|
+
return These.both(data.value, data.error);
|
|
216
216
|
};
|
|
217
217
|
/**
|
|
218
218
|
* Converts a These to an Option.
|
|
@@ -220,9 +220,9 @@ var These;
|
|
|
220
220
|
*
|
|
221
221
|
* @example
|
|
222
222
|
* ```ts
|
|
223
|
-
* These.toOption(These.
|
|
224
|
-
* These.toOption(These.
|
|
225
|
-
* These.toOption(These.
|
|
223
|
+
* These.toOption(These.ok(42)); // Some(42)
|
|
224
|
+
* These.toOption(These.both("warn", 42)); // Some(42)
|
|
225
|
+
* These.toOption(These.err("err")); // None
|
|
226
226
|
* ```
|
|
227
227
|
*/
|
|
228
228
|
These.toOption = (data) => These.hasValue(data) ? { kind: "Some", value: data.value } : { kind: "None" };
|
|
@@ -232,14 +232,14 @@ var These;
|
|
|
232
232
|
*
|
|
233
233
|
* @example
|
|
234
234
|
* ```ts
|
|
235
|
-
* These.toResult(These.
|
|
236
|
-
* These.toResult(These.
|
|
237
|
-
* These.toResult(These.
|
|
235
|
+
* These.toResult(These.ok(42)); // Ok(42)
|
|
236
|
+
* These.toResult(These.both("warn", 42)); // Ok(42)
|
|
237
|
+
* These.toResult(These.err("err")); // Err("err")
|
|
238
238
|
* ```
|
|
239
239
|
*/
|
|
240
240
|
These.toResult = (data) => {
|
|
241
241
|
if (These.hasValue(data))
|
|
242
|
-
return Result_js_1.Result.
|
|
242
|
+
return Result_js_1.Result.ok(data.value);
|
|
243
243
|
return data;
|
|
244
244
|
};
|
|
245
245
|
})(These || (exports.These = These = {}));
|
|
@@ -4,19 +4,19 @@ exports.Brand = void 0;
|
|
|
4
4
|
var Brand;
|
|
5
5
|
(function (Brand) {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Returns a constructor that wraps a value of type T in brand K.
|
|
8
8
|
* The resulting function performs an unchecked cast — only use when the raw
|
|
9
9
|
* value is known to satisfy the brand's invariants.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```ts
|
|
13
13
|
* type PositiveNumber = Brand<"PositiveNumber", number>;
|
|
14
|
-
* const toPositiveNumber = Brand.
|
|
14
|
+
* const toPositiveNumber = Brand.wrap<"PositiveNumber", number>();
|
|
15
15
|
*
|
|
16
16
|
* const n: PositiveNumber = toPositiveNumber(42);
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
Brand.
|
|
19
|
+
Brand.wrap = () => (value) => value;
|
|
20
20
|
/**
|
|
21
21
|
* Strips the brand and returns the underlying value.
|
|
22
22
|
* Since Brand<K, T> extends T this is rarely needed, but can improve readability.
|