@nlozgachev/pipelined 0.66.0 → 0.67.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 +18 -5
- package/dist/{Core-D7_9dZpV.mjs → Core-BCN6WRzp.mjs} +761 -419
- package/dist/{Core-6SkC-fh5.cjs → Core-CfAL_21H.cjs} +761 -419
- package/dist/{InternalTypes-DzDey5Do.d.ts → InternalTypes-C0F5jyVQ.d.ts} +1 -1
- package/dist/{InternalTypes-B1Lh9uw_.d.cts → InternalTypes-DxSlzrpu.d.cts} +1 -1
- package/dist/composition.d.cts +2 -2
- package/dist/composition.d.ts +2 -2
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.mjs +1 -1
- package/dist/data.cjs +991 -527
- package/dist/data.d.cts +479 -308
- package/dist/data.d.ts +479 -308
- package/dist/data.mjs +991 -527
- package/dist/{index-Bs8En5LJ.d.cts → index-CTe9CCHY.d.cts} +3 -0
- package/dist/{index-Bs8En5LJ.d.ts → index-CTe9CCHY.d.ts} +3 -0
- package/dist/{index-8A9NqJTq.d.cts → index-CdzHrj62.d.ts} +609 -298
- package/dist/{index-CY4ZLbjM.d.ts → index-NYjtX7XS.d.cts} +609 -298
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/types.cjs +5 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.mjs +5 -1
- package/package.json +20 -19
package/dist/data.mjs
CHANGED
|
@@ -1,42 +1,57 @@
|
|
|
1
|
-
import { S as Deferred, g as Maybe, i as isNonEmptyArr, n as Task, o as Result } from "./Core-
|
|
1
|
+
import { S as Deferred, g as Maybe, i as isNonEmptyArr, n as Task, o as Result, r as Validation } from "./Core-BCN6WRzp.mjs";
|
|
2
2
|
//#region src/Data/Arr.ts
|
|
3
3
|
let ArrMaybe;
|
|
4
4
|
(function(_ArrMaybe) {
|
|
5
|
-
const traverse = _ArrMaybe.traverse = (
|
|
6
|
-
const n =
|
|
5
|
+
const traverse = _ArrMaybe.traverse = (transform) => (items) => {
|
|
6
|
+
const n = items.length;
|
|
7
7
|
const result = new Array(n);
|
|
8
8
|
for (let i = 0; i < n; i++) {
|
|
9
|
-
const mapped =
|
|
9
|
+
const mapped = transform(items[i]);
|
|
10
10
|
if (mapped.kind === "None") return Maybe.make.none();
|
|
11
11
|
result[i] = mapped.value;
|
|
12
12
|
}
|
|
13
13
|
return Maybe.make.some(result);
|
|
14
14
|
};
|
|
15
|
-
_ArrMaybe.sequence = (
|
|
15
|
+
_ArrMaybe.sequence = (items) => traverse((item) => item)(items);
|
|
16
16
|
})(ArrMaybe || (ArrMaybe = {}));
|
|
17
17
|
let ArrResult;
|
|
18
18
|
(function(_ArrResult) {
|
|
19
|
-
const traverse = _ArrResult.traverse = (
|
|
20
|
-
const n =
|
|
19
|
+
const traverse = _ArrResult.traverse = (transform) => (items) => {
|
|
20
|
+
const n = items.length;
|
|
21
21
|
const result = new Array(n);
|
|
22
22
|
for (let i = 0; i < n; i++) {
|
|
23
|
-
const mapped =
|
|
23
|
+
const mapped = transform(items[i]);
|
|
24
24
|
if (mapped.kind === "Err") return mapped;
|
|
25
25
|
result[i] = mapped.value;
|
|
26
26
|
}
|
|
27
27
|
return Result.make.ok(result);
|
|
28
28
|
};
|
|
29
|
-
_ArrResult.sequence = (
|
|
29
|
+
_ArrResult.sequence = (items) => traverse((item) => item)(items);
|
|
30
30
|
})(ArrResult || (ArrResult = {}));
|
|
31
|
+
let ArrValidation;
|
|
32
|
+
(function(_ArrValidation) {
|
|
33
|
+
const traverse = _ArrValidation.traverse = (transform) => (items) => {
|
|
34
|
+
const n = items.length;
|
|
35
|
+
const result = new Array(n);
|
|
36
|
+
const errors = [];
|
|
37
|
+
for (let i = 0; i < n; i++) {
|
|
38
|
+
const mapped = transform(items[i]);
|
|
39
|
+
if (Validation.is.failed(mapped)) errors.push(...mapped.errors);
|
|
40
|
+
else if (errors.length === 0) result[i] = mapped.value;
|
|
41
|
+
}
|
|
42
|
+
return isNonEmptyArr(errors) ? Validation.make.failedAll(errors) : Validation.make.passed(result);
|
|
43
|
+
};
|
|
44
|
+
_ArrValidation.sequence = (items) => traverse((item) => item)(items);
|
|
45
|
+
})(ArrValidation || (ArrValidation = {}));
|
|
31
46
|
let ArrTaskResult;
|
|
32
47
|
(function(_ArrTaskResult) {
|
|
33
|
-
const traverse = _ArrTaskResult.traverse = (
|
|
48
|
+
const traverse = _ArrTaskResult.traverse = (transform, options) => (items) => (signal) => Deferred.from.Promise((async () => {
|
|
34
49
|
const concurrency = options?.concurrency;
|
|
35
|
-
const len =
|
|
50
|
+
const len = items.length;
|
|
36
51
|
if (concurrency === void 0 || concurrency <= 1 || len <= 1) {
|
|
37
52
|
const result = [];
|
|
38
|
-
for (const a of
|
|
39
|
-
const r = await Deferred.to.Promise(
|
|
53
|
+
for (const a of items) {
|
|
54
|
+
const r = await Deferred.to.Promise(transform(a)(signal));
|
|
40
55
|
if (Result.is.err(r)) return r;
|
|
41
56
|
result.push(r.value);
|
|
42
57
|
}
|
|
@@ -49,7 +64,7 @@ let ArrTaskResult;
|
|
|
49
64
|
const worker = async () => {
|
|
50
65
|
while (nextIndex < len && !settled) {
|
|
51
66
|
const currentIndex = nextIndex++;
|
|
52
|
-
const r = await Deferred.to.Promise(
|
|
67
|
+
const r = await Deferred.to.Promise(transform(items[currentIndex])(signal));
|
|
53
68
|
if (settled) return;
|
|
54
69
|
if (Result.is.err(r)) {
|
|
55
70
|
settled = true;
|
|
@@ -67,12 +82,12 @@ let ArrTaskResult;
|
|
|
67
82
|
});
|
|
68
83
|
});
|
|
69
84
|
})());
|
|
70
|
-
_ArrTaskResult.sequence = (
|
|
85
|
+
_ArrTaskResult.sequence = (items) => traverse((item) => item)(items);
|
|
71
86
|
})(ArrTaskResult || (ArrTaskResult = {}));
|
|
72
87
|
let ArrTask;
|
|
73
88
|
(function(_ArrTask) {
|
|
74
|
-
const traverse = _ArrTask.traverse = (
|
|
75
|
-
_ArrTask.sequence = (
|
|
89
|
+
const traverse = _ArrTask.traverse = (transform, options) => (items) => Task.all(items.map(transform), options);
|
|
90
|
+
_ArrTask.sequence = (items) => traverse((item) => item)(items);
|
|
76
91
|
_ArrTask.Result = ArrTaskResult;
|
|
77
92
|
})(ArrTask || (ArrTask = {}));
|
|
78
93
|
/**
|
|
@@ -102,96 +117,118 @@ let ArrTask;
|
|
|
102
117
|
/**
|
|
103
118
|
* Returns the first element of an array, or None if the array is empty.
|
|
104
119
|
*
|
|
120
|
+
* @see {@link last} for accessing the final element.
|
|
121
|
+
* @see {@link tail} for all elements except the first.
|
|
122
|
+
*
|
|
105
123
|
* @example
|
|
106
124
|
* ```ts
|
|
107
125
|
* Arr.head([1, 2, 3]); // Some(1)
|
|
108
126
|
* Arr.head([]); // None
|
|
109
127
|
* ```
|
|
110
128
|
*/
|
|
111
|
-
const head = (
|
|
129
|
+
const head = (items) => items.length > 0 ? Maybe.make.some(items[0]) : Maybe.make.none();
|
|
112
130
|
/**
|
|
113
131
|
* Returns the last element of an array, or None if the array is empty.
|
|
114
132
|
*
|
|
133
|
+
* @see {@link head} for accessing the first element.
|
|
134
|
+
* @see {@link init} for all elements except the last.
|
|
135
|
+
*
|
|
115
136
|
* @example
|
|
116
137
|
* ```ts
|
|
117
138
|
* Arr.last([1, 2, 3]); // Some(3)
|
|
118
139
|
* Arr.last([]); // None
|
|
119
140
|
* ```
|
|
120
141
|
*/
|
|
121
|
-
const last = (
|
|
142
|
+
const last = (items) => items.length > 0 ? Maybe.make.some(items[items.length - 1]) : Maybe.make.none();
|
|
122
143
|
/**
|
|
123
144
|
* Returns all elements except the first, or None if the array is empty.
|
|
124
145
|
*
|
|
146
|
+
* @see {@link head} for accessing the first element.
|
|
147
|
+
*
|
|
125
148
|
* @example
|
|
126
149
|
* ```ts
|
|
127
150
|
* Arr.tail([1, 2, 3]); // Some([2, 3])
|
|
128
151
|
* Arr.tail([]); // None
|
|
129
152
|
* ```
|
|
130
153
|
*/
|
|
131
|
-
const tail = (
|
|
154
|
+
const tail = (items) => items.length > 0 ? Maybe.make.some(items.slice(1)) : Maybe.make.none();
|
|
132
155
|
/**
|
|
133
156
|
* Returns all elements except the last, or None if the array is empty.
|
|
134
157
|
*
|
|
158
|
+
* @see {@link last} for accessing the final element.
|
|
159
|
+
*
|
|
135
160
|
* @example
|
|
136
161
|
* ```ts
|
|
137
162
|
* Arr.init([1, 2, 3]); // Some([1, 2])
|
|
138
163
|
* Arr.init([]); // None
|
|
139
164
|
* ```
|
|
140
165
|
*/
|
|
141
|
-
const init = (
|
|
166
|
+
const init = (items) => items.length > 0 ? Maybe.make.some(items.slice(0, -1)) : Maybe.make.none();
|
|
142
167
|
/**
|
|
143
168
|
* Returns the first element matching the predicate, or None.
|
|
144
169
|
*
|
|
170
|
+
* @see {@link findLast} for finding the last matching element.
|
|
171
|
+
* @see {@link findIndex} for obtaining the index of the first matching element.
|
|
172
|
+
*
|
|
145
173
|
* @example
|
|
146
174
|
* ```ts
|
|
147
175
|
* pipe([1, 2, 3, 4], Arr.findFirst(n => n > 2)); // Some(3)
|
|
148
176
|
* ```
|
|
149
177
|
*/
|
|
150
|
-
const findFirst = (predicate) => (
|
|
151
|
-
const idx =
|
|
152
|
-
return idx !== -1 ? Maybe.make.some(
|
|
178
|
+
const findFirst = (predicate) => (items) => {
|
|
179
|
+
const idx = items.findIndex(predicate);
|
|
180
|
+
return idx !== -1 ? Maybe.make.some(items[idx]) : Maybe.make.none();
|
|
153
181
|
};
|
|
154
182
|
/**
|
|
155
183
|
* Returns the last element matching the predicate, or None.
|
|
156
184
|
*
|
|
185
|
+
* @see {@link findFirst} for finding the first matching element.
|
|
186
|
+
*
|
|
157
187
|
* @example
|
|
158
188
|
* ```ts
|
|
159
189
|
* pipe([1, 2, 3, 4], Arr.findLast(n => n > 2)); // Some(4)
|
|
160
190
|
* ```
|
|
161
191
|
*/
|
|
162
|
-
const findLast = (predicate) => (
|
|
163
|
-
for (let i =
|
|
192
|
+
const findLast = (predicate) => (items) => {
|
|
193
|
+
for (let i = items.length - 1; i >= 0; i--) if (predicate(items[i])) return Maybe.make.some(items[i]);
|
|
164
194
|
return Maybe.make.none();
|
|
165
195
|
};
|
|
166
196
|
/**
|
|
167
197
|
* Returns the index of the first element matching the predicate, or None.
|
|
168
198
|
*
|
|
199
|
+
* @see {@link findFirst} for finding the matching element value.
|
|
200
|
+
*
|
|
169
201
|
* @example
|
|
170
202
|
* ```ts
|
|
171
203
|
* pipe([1, 2, 3, 4], Arr.findIndex(n => n > 2)); // Some(2)
|
|
172
204
|
* ```
|
|
173
205
|
*/
|
|
174
|
-
const findIndex = (predicate) => (
|
|
175
|
-
const idx =
|
|
206
|
+
const findIndex = (predicate) => (items) => {
|
|
207
|
+
const idx = items.findIndex(predicate);
|
|
176
208
|
return idx !== -1 ? Maybe.make.some(idx) : Maybe.make.none();
|
|
177
209
|
};
|
|
178
210
|
/**
|
|
179
211
|
* Transforms each element of an array.
|
|
180
212
|
*
|
|
213
|
+
* @see {@link flatMap} for mapping and flattening arrays.
|
|
214
|
+
* @see {@link mapWithIndex} for mapping with element indices.
|
|
215
|
+
*
|
|
181
216
|
* @example
|
|
182
217
|
* ```ts
|
|
183
218
|
* pipe([1, 2, 3], Arr.map(n => n * 2)); // [2, 4, 6]
|
|
184
219
|
* ```
|
|
185
220
|
*/
|
|
186
|
-
const map$3 = (
|
|
187
|
-
const n =
|
|
221
|
+
const map$3 = (transform) => (items) => {
|
|
222
|
+
const n = items.length;
|
|
188
223
|
const result = new Array(n);
|
|
189
|
-
for (let i = 0; i < n; i++) result[i] =
|
|
224
|
+
for (let i = 0; i < n; i++) result[i] = transform(items[i]);
|
|
190
225
|
return result;
|
|
191
226
|
};
|
|
192
227
|
/**
|
|
193
228
|
* Transforms each element using both its value and its zero-based index.
|
|
194
229
|
*
|
|
230
|
+
* @see {@link map} for mapping without indices.
|
|
231
|
+
*
|
|
195
232
|
* @example
|
|
196
233
|
* ```ts
|
|
197
234
|
* pipe(
|
|
@@ -200,30 +237,34 @@ const map$3 = (f) => (data) => {
|
|
|
200
237
|
* ); // [{ position: 1, value: "a" }, { position: 2, value: "b" }, { position: 3, value: "c" }]
|
|
201
238
|
* ```
|
|
202
239
|
*/
|
|
203
|
-
const mapWithIndex = (
|
|
204
|
-
const n =
|
|
240
|
+
const mapWithIndex = (transform) => (items) => {
|
|
241
|
+
const n = items.length;
|
|
205
242
|
const result = new Array(n);
|
|
206
|
-
for (let i = 0; i < n; i++) result[i] =
|
|
243
|
+
for (let i = 0; i < n; i++) result[i] = transform(i, items[i]);
|
|
207
244
|
return result;
|
|
208
245
|
};
|
|
209
246
|
/**
|
|
210
247
|
* Filters elements that satisfy the predicate.
|
|
211
248
|
*
|
|
249
|
+
* @see {@link filterMap} for filtering and mapping simultaneously.
|
|
250
|
+
*
|
|
212
251
|
* @example
|
|
213
252
|
* ```ts
|
|
214
253
|
* pipe([1, 2, 3, 4], Arr.filter(n => n % 2 === 0)); // [2, 4]
|
|
215
254
|
* ```
|
|
216
255
|
*/
|
|
217
|
-
const filter$3 = (predicate) => (
|
|
218
|
-
const n =
|
|
256
|
+
const filter$3 = (predicate) => (items) => {
|
|
257
|
+
const n = items.length;
|
|
219
258
|
const result = [];
|
|
220
|
-
for (let i = 0; i < n; i++) if (predicate(
|
|
259
|
+
for (let i = 0; i < n; i++) if (predicate(items[i])) result.push(items[i]);
|
|
221
260
|
return result;
|
|
222
261
|
};
|
|
223
262
|
/**
|
|
224
263
|
* Maps each element to a Maybe and collects only the Some values.
|
|
225
264
|
* Combines map and filter in a single pass.
|
|
226
265
|
*
|
|
266
|
+
* @see {@link filter} for filtering with a boolean predicate.
|
|
267
|
+
*
|
|
227
268
|
* @example
|
|
228
269
|
* ```ts
|
|
229
270
|
* const parseNum = (s: string): Maybe<number> => {
|
|
@@ -234,10 +275,10 @@ const filter$3 = (predicate) => (data) => {
|
|
|
234
275
|
* pipe(["1", "abc", "3"], Arr.filterMap(parseNum)); // [1, 3]
|
|
235
276
|
* ```
|
|
236
277
|
*/
|
|
237
|
-
const filterMap$3 = (
|
|
278
|
+
const filterMap$3 = (transform) => (items) => {
|
|
238
279
|
const result = [];
|
|
239
|
-
for (let i = 0; i <
|
|
240
|
-
const mapped =
|
|
280
|
+
for (let i = 0; i < items.length; i++) {
|
|
281
|
+
const mapped = transform(items[i]);
|
|
241
282
|
if (mapped.kind === "Some") result.push(mapped.value);
|
|
242
283
|
}
|
|
243
284
|
return result;
|
|
@@ -247,50 +288,59 @@ const filterMap$3 = (f) => (data) => {
|
|
|
247
288
|
* First group contains elements that satisfy the predicate,
|
|
248
289
|
* second group contains the rest.
|
|
249
290
|
*
|
|
291
|
+
* @see {@link partitionMap} for partitioning with a Result function.
|
|
292
|
+
*
|
|
250
293
|
* @example
|
|
251
294
|
* ```ts
|
|
252
295
|
* pipe([1, 2, 3, 4], Arr.partition(n => n % 2 === 0)); // [[2, 4], [1, 3]]
|
|
253
296
|
* ```
|
|
254
297
|
*/
|
|
255
|
-
const partition = (predicate) => (
|
|
298
|
+
const partition = (predicate) => (items) => {
|
|
256
299
|
const pass = [];
|
|
257
300
|
const fail = [];
|
|
258
|
-
for (const
|
|
301
|
+
for (const item of items) (predicate(item) ? pass : fail).push(item);
|
|
259
302
|
return [pass, fail];
|
|
260
303
|
};
|
|
261
304
|
/**
|
|
262
305
|
* Narrows a list of Maybe values down to a list of their underlying values,
|
|
263
306
|
* discarding all None instances.
|
|
264
307
|
*
|
|
308
|
+
* @see {@link separate} for dividing Results into error and success arrays.
|
|
309
|
+
*
|
|
265
310
|
* @example
|
|
266
311
|
* ```ts
|
|
267
312
|
* Arr.compact([Maybe.make.some(1), Maybe.make.none(), Maybe.make.some(3)]); // [1, 3]
|
|
268
313
|
* ```
|
|
269
314
|
*/
|
|
270
|
-
const compact$2 = (
|
|
315
|
+
const compact$2 = (items) => {
|
|
271
316
|
const result = [];
|
|
272
|
-
for (const item of
|
|
317
|
+
for (const item of items) if (item.kind === "Some") result.push(item.value);
|
|
273
318
|
return result;
|
|
274
319
|
};
|
|
275
320
|
/**
|
|
276
321
|
* Separates an array of Result values into two separate lists of errors and successes.
|
|
277
322
|
* Returns a tuple containing `[errors, successes]`.
|
|
278
323
|
*
|
|
324
|
+
* @see {@link compact} for extracting Some values from Maybe instances.
|
|
325
|
+
*
|
|
279
326
|
* @example
|
|
280
327
|
* ```ts
|
|
281
328
|
* Arr.separate([Result.make.ok(1), Result.make.err("bad"), Result.make.ok(3)]); // [["bad"], [1, 3]]
|
|
282
329
|
* ```
|
|
283
330
|
*/
|
|
284
|
-
const separate = (
|
|
331
|
+
const separate = (items) => {
|
|
285
332
|
const errors = [];
|
|
286
333
|
const successes = [];
|
|
287
|
-
for (const item of
|
|
334
|
+
for (const item of items) if (item.kind === "Ok") successes.push(item.value);
|
|
288
335
|
else errors.push(item.error);
|
|
289
336
|
return [errors, successes];
|
|
290
337
|
};
|
|
291
338
|
/**
|
|
292
339
|
* Maps each element to a Result, and separates the results into a tuple of failures and successes.
|
|
293
340
|
*
|
|
341
|
+
* @see {@link partition} for partitioning with a boolean predicate.
|
|
342
|
+
* @see {@link partitionMaybe} for partitioning with a Maybe function.
|
|
343
|
+
*
|
|
294
344
|
* @example
|
|
295
345
|
* ```ts
|
|
296
346
|
* pipe(
|
|
@@ -299,11 +349,11 @@ const separate = (data) => {
|
|
|
299
349
|
* ); // [["odd: 1", "odd: 3"], [2, 4]]
|
|
300
350
|
* ```
|
|
301
351
|
*/
|
|
302
|
-
const partitionMap = (
|
|
352
|
+
const partitionMap = (transform) => (items) => {
|
|
303
353
|
const errors = [];
|
|
304
354
|
const successes = [];
|
|
305
|
-
for (const item of
|
|
306
|
-
const mapped =
|
|
355
|
+
for (const item of items) {
|
|
356
|
+
const mapped = transform(item);
|
|
307
357
|
if (mapped.kind === "Ok") successes.push(mapped.value);
|
|
308
358
|
else errors.push(mapped.error);
|
|
309
359
|
}
|
|
@@ -312,6 +362,8 @@ const partitionMap = (f) => (data) => {
|
|
|
312
362
|
/**
|
|
313
363
|
* Groups elements by a key function.
|
|
314
364
|
*
|
|
365
|
+
* @see {@link indexBy} for indexing elements into a Map.
|
|
366
|
+
*
|
|
315
367
|
* @example
|
|
316
368
|
* ```ts
|
|
317
369
|
* pipe(
|
|
@@ -320,27 +372,33 @@ const partitionMap = (f) => (data) => {
|
|
|
320
372
|
* ); // { a: ["apple", "avocado"], b: ["banana"] }
|
|
321
373
|
* ```
|
|
322
374
|
*/
|
|
323
|
-
const groupBy$2 = (
|
|
375
|
+
const groupBy$2 = (keySelector) => (items) => {
|
|
324
376
|
const result = {};
|
|
325
|
-
for (const
|
|
326
|
-
const key =
|
|
377
|
+
for (const item of items) {
|
|
378
|
+
const key = keySelector(item);
|
|
327
379
|
if (!result[key]) result[key] = [];
|
|
328
|
-
result[key].push(
|
|
380
|
+
result[key].push(item);
|
|
329
381
|
}
|
|
330
382
|
return result;
|
|
331
383
|
};
|
|
332
384
|
/**
|
|
333
385
|
* Removes duplicate elements using strict equality.
|
|
334
386
|
*
|
|
387
|
+
* @see {@link uniqBy} for deduplicating by a key projection.
|
|
388
|
+
* @see {@link uniqWith} for deduplicating with custom equality.
|
|
389
|
+
*
|
|
335
390
|
* @example
|
|
336
391
|
* ```ts
|
|
337
392
|
* Arr.uniq([1, 2, 2, 3, 1]); // [1, 2, 3]
|
|
338
393
|
* ```
|
|
339
394
|
*/
|
|
340
|
-
const uniq = (
|
|
395
|
+
const uniq = (items) => items.length <= 1 ? items : [...new Set(items)];
|
|
341
396
|
/**
|
|
342
397
|
* Removes duplicate elements by comparing the result of a key function.
|
|
343
398
|
*
|
|
399
|
+
* @see {@link uniq} for reference-equality deduplication.
|
|
400
|
+
* @see {@link uniqWith} for deduplicating with custom equality.
|
|
401
|
+
*
|
|
344
402
|
* @example
|
|
345
403
|
* ```ts
|
|
346
404
|
* pipe(
|
|
@@ -349,14 +407,14 @@ const uniq = (data) => data.length <= 1 ? data : [...new Set(data)];
|
|
|
349
407
|
* ); // [{id: 1, name: "a"}, {id: 2, name: "c"}]
|
|
350
408
|
* ```
|
|
351
409
|
*/
|
|
352
|
-
const uniqBy = (
|
|
410
|
+
const uniqBy = (keySelector) => (items) => {
|
|
353
411
|
const seen = /* @__PURE__ */ new Set();
|
|
354
412
|
const result = [];
|
|
355
|
-
for (const
|
|
356
|
-
const key =
|
|
413
|
+
for (const item of items) {
|
|
414
|
+
const key = keySelector(item);
|
|
357
415
|
if (!seen.has(key)) {
|
|
358
416
|
seen.add(key);
|
|
359
|
-
result.push(
|
|
417
|
+
result.push(item);
|
|
360
418
|
}
|
|
361
419
|
}
|
|
362
420
|
return result;
|
|
@@ -366,6 +424,9 @@ const uniqBy = (f) => (data) => {
|
|
|
366
424
|
* Preserves the order of first occurrences. Complements `uniq` (reference equality)
|
|
367
425
|
* and `uniqBy` (key extraction).
|
|
368
426
|
*
|
|
427
|
+
* @see {@link uniq} for reference-equality deduplication.
|
|
428
|
+
* @see {@link uniqBy} for key-based deduplication.
|
|
429
|
+
*
|
|
369
430
|
* @example
|
|
370
431
|
* ```ts
|
|
371
432
|
* type Point = { x: number; y: number };
|
|
@@ -377,29 +438,33 @@ const uniqBy = (f) => (data) => {
|
|
|
377
438
|
* ); // [{ x: 1, y: 1 }, { x: 2, y: 2 }]
|
|
378
439
|
* ```
|
|
379
440
|
*/
|
|
380
|
-
const uniqWith = (
|
|
441
|
+
const uniqWith = (areEqual) => (items) => {
|
|
381
442
|
const result = [];
|
|
382
|
-
for (const
|
|
443
|
+
for (const item of items) if (!result.some((existing) => areEqual(existing, item))) result.push(item);
|
|
383
444
|
return result;
|
|
384
445
|
};
|
|
385
446
|
/**
|
|
386
447
|
* Sorts an array using a comparison function. Returns a new array.
|
|
387
448
|
* To sort with a typed `Ordering<A>`, prefer `Arr.sortWith`.
|
|
388
449
|
*
|
|
450
|
+
* @see {@link sortWith} for sorting using typed Ordering instances.
|
|
451
|
+
*
|
|
389
452
|
* @example
|
|
390
453
|
* ```ts
|
|
391
454
|
* pipe([3, 1, 2], Arr.sortBy((a, b) => a - b)); // [1, 2, 3]
|
|
392
455
|
* ```
|
|
393
456
|
*/
|
|
394
|
-
const sortBy = (compare) => (
|
|
395
|
-
const arr =
|
|
457
|
+
const sortBy = (compare) => (items) => {
|
|
458
|
+
const arr = items;
|
|
396
459
|
if (typeof arr.toSorted === "function") return arr.toSorted(compare);
|
|
397
|
-
return [...
|
|
460
|
+
return [...items].sort(compare);
|
|
398
461
|
};
|
|
399
462
|
/**
|
|
400
463
|
* Sorts an array using an `Ordering<A>`. Returns a new array without mutating the original.
|
|
401
464
|
* Use this over `sortBy` when you have a typed `Ordering<A>` from the `Ordering` module.
|
|
402
465
|
*
|
|
466
|
+
* @see {@link sortBy} for sorting using a comparator function.
|
|
467
|
+
*
|
|
403
468
|
* @example
|
|
404
469
|
* ```ts
|
|
405
470
|
* pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
|
|
@@ -410,37 +475,41 @@ const sortBy = (compare) => (data) => {
|
|
|
410
475
|
* pipe(products, Arr.sortWith(byPrice));
|
|
411
476
|
* ```
|
|
412
477
|
*/
|
|
413
|
-
const sortWith = (
|
|
414
|
-
const arr =
|
|
415
|
-
if (typeof arr.toSorted === "function") return arr.toSorted(
|
|
416
|
-
return [...
|
|
478
|
+
const sortWith = (ordering) => (items) => {
|
|
479
|
+
const arr = items;
|
|
480
|
+
if (typeof arr.toSorted === "function") return arr.toSorted(ordering);
|
|
481
|
+
return [...items].sort(ordering);
|
|
417
482
|
};
|
|
418
483
|
/**
|
|
419
484
|
* Pairs up elements from two arrays. Stops at the shorter array.
|
|
420
485
|
*
|
|
486
|
+
* @see {@link zipWith} for pairing elements with a custom combining function.
|
|
487
|
+
*
|
|
421
488
|
* @example
|
|
422
489
|
* ```ts
|
|
423
490
|
* pipe([1, 2, 3], Arr.zip(["a", "b"])); // [[1, "a"], [2, "b"]]
|
|
424
491
|
* ```
|
|
425
492
|
*/
|
|
426
|
-
const zip = (other) => (
|
|
427
|
-
const len = Math.min(
|
|
493
|
+
const zip = (other) => (items) => {
|
|
494
|
+
const len = Math.min(items.length, other.length);
|
|
428
495
|
const result = new Array(len);
|
|
429
|
-
for (let i = 0; i < len; i++) result[i] = [
|
|
496
|
+
for (let i = 0; i < len; i++) result[i] = [items[i], other[i]];
|
|
430
497
|
return result;
|
|
431
498
|
};
|
|
432
499
|
/**
|
|
433
500
|
* Combines elements from two arrays using a function. Stops at the shorter array.
|
|
434
501
|
*
|
|
502
|
+
* @see {@link zip} for pairing elements into 2-tuples.
|
|
503
|
+
*
|
|
435
504
|
* @example
|
|
436
505
|
* ```ts
|
|
437
506
|
* pipe([1, 2], Arr.zipWith((a: number, b: string) => `${a}${b}`)(["a", "b"])); // ["1a", "2b"]
|
|
438
507
|
* ```
|
|
439
508
|
*/
|
|
440
|
-
const zipWith = (
|
|
441
|
-
const len = Math.min(
|
|
509
|
+
const zipWith = (combine) => (other) => (items) => {
|
|
510
|
+
const len = Math.min(items.length, other.length);
|
|
442
511
|
const result = new Array(len);
|
|
443
|
-
for (let i = 0; i < len; i++) result[i] =
|
|
512
|
+
for (let i = 0; i < len; i++) result[i] = combine(items[i], other[i]);
|
|
444
513
|
return result;
|
|
445
514
|
};
|
|
446
515
|
/**
|
|
@@ -451,10 +520,10 @@ const zipWith = (f) => (other) => (data) => {
|
|
|
451
520
|
* pipe([1, 2, 3], Arr.intersperse(0)); // [1, 0, 2, 0, 3]
|
|
452
521
|
* ```
|
|
453
522
|
*/
|
|
454
|
-
const intersperse = (
|
|
455
|
-
if (
|
|
456
|
-
const result = [
|
|
457
|
-
for (let i = 1; i <
|
|
523
|
+
const intersperse = (separator) => (items) => {
|
|
524
|
+
if (items.length <= 1) return items;
|
|
525
|
+
const result = [items[0]];
|
|
526
|
+
for (let i = 1; i < items.length; i++) result.push(separator, items[i]);
|
|
458
527
|
return result;
|
|
459
528
|
};
|
|
460
529
|
/**
|
|
@@ -465,37 +534,41 @@ const intersperse = (sep) => (data) => {
|
|
|
465
534
|
* pipe([1, 2], Arr.concat([3, 4])); // [1, 2, 3, 4]
|
|
466
535
|
* ```
|
|
467
536
|
*/
|
|
468
|
-
const concat = (other) => (
|
|
537
|
+
const concat = (other) => (items) => [...items, ...other];
|
|
469
538
|
/**
|
|
470
539
|
* Splits an array into chunks of the given size.
|
|
471
540
|
*
|
|
541
|
+
* @see {@link chunkBy} for grouping consecutive elements sharing a key.
|
|
542
|
+
*
|
|
472
543
|
* @example
|
|
473
544
|
* ```ts
|
|
474
545
|
* pipe([1, 2, 3, 4, 5], Arr.chunksOf(2)); // [[1, 2], [3, 4], [5]]
|
|
475
546
|
* ```
|
|
476
547
|
*/
|
|
477
|
-
const chunksOf = (
|
|
478
|
-
if (
|
|
548
|
+
const chunksOf = (size) => (items) => {
|
|
549
|
+
if (size <= 0) return [];
|
|
479
550
|
const result = [];
|
|
480
|
-
for (let i = 0; i <
|
|
551
|
+
for (let i = 0; i < items.length; i += size) result.push(items.slice(i, i + size));
|
|
481
552
|
return result;
|
|
482
553
|
};
|
|
483
554
|
/**
|
|
484
555
|
* Flattens a nested array by one level.
|
|
485
556
|
*
|
|
557
|
+
* @see {@link flatMap} for mapping elements to arrays before flattening.
|
|
558
|
+
*
|
|
486
559
|
* @example
|
|
487
560
|
* ```ts
|
|
488
561
|
* Arr.flatten([[1, 2], [3], [4, 5]]); // [1, 2, 3, 4, 5]
|
|
489
562
|
* ```
|
|
490
563
|
*/
|
|
491
|
-
const flatten = (
|
|
564
|
+
const flatten = (items) => {
|
|
492
565
|
let totalLen = 0;
|
|
493
|
-
const outerLen =
|
|
494
|
-
for (let i = 0; i < outerLen; i++) totalLen +=
|
|
566
|
+
const outerLen = items.length;
|
|
567
|
+
for (let i = 0; i < outerLen; i++) totalLen += items[i].length;
|
|
495
568
|
const result = new Array(totalLen);
|
|
496
569
|
let idx = 0;
|
|
497
570
|
for (let i = 0; i < outerLen; i++) {
|
|
498
|
-
const chunk =
|
|
571
|
+
const chunk = items[i];
|
|
499
572
|
const innerLen = chunk.length;
|
|
500
573
|
for (let j = 0; j < innerLen; j++) result[idx++] = chunk[j];
|
|
501
574
|
}
|
|
@@ -504,16 +577,19 @@ const flatten = (data) => {
|
|
|
504
577
|
/**
|
|
505
578
|
* Maps each element to an array and flattens the result.
|
|
506
579
|
*
|
|
580
|
+
* @see {@link map} for mapping without flattening.
|
|
581
|
+
* @see {@link flatten} for flattening without mapping.
|
|
582
|
+
*
|
|
507
583
|
* @example
|
|
508
584
|
* ```ts
|
|
509
585
|
* pipe([1, 2, 3], Arr.flatMap(n => [n, n * 10])); // [1, 10, 2, 20, 3, 30]
|
|
510
586
|
* ```
|
|
511
587
|
*/
|
|
512
|
-
const flatMap = (
|
|
513
|
-
const n =
|
|
588
|
+
const flatMap = (transform) => (items) => {
|
|
589
|
+
const n = items.length;
|
|
514
590
|
const result = [];
|
|
515
591
|
for (let i = 0; i < n; i++) {
|
|
516
|
-
const chunk =
|
|
592
|
+
const chunk = transform(items[i]);
|
|
517
593
|
const m = chunk.length;
|
|
518
594
|
for (let j = 0; j < m; j++) result.push(chunk[j]);
|
|
519
595
|
}
|
|
@@ -522,32 +598,38 @@ const flatMap = (f) => (data) => {
|
|
|
522
598
|
/**
|
|
523
599
|
* Reduces an array from the left.
|
|
524
600
|
*
|
|
601
|
+
* @see {@link scan} for preserving intermediate accumulation states.
|
|
602
|
+
*
|
|
525
603
|
* @example
|
|
526
604
|
* ```ts
|
|
527
605
|
* pipe([1, 2, 3], Arr.reduce(0, (acc, n) => acc + n)); // 6
|
|
528
606
|
* ```
|
|
529
607
|
*/
|
|
530
|
-
const reduce$2 = (initial,
|
|
608
|
+
const reduce$2 = (initial, reducer) => (items) => items.reduce(reducer, initial);
|
|
531
609
|
const _traverseTask = Object.assign((f, options) => ArrTask.traverse(f, options), { Result: ArrTaskResult.traverse });
|
|
532
610
|
const _sequenceTask = Object.assign((data) => ArrTask.sequence(data), { Result: ArrTaskResult.sequence });
|
|
533
611
|
/**
|
|
534
612
|
* Prepends a value to the beginning of an array, returning a NonEmptyArr.
|
|
535
613
|
*
|
|
614
|
+
* @see {@link append} for adding an element to the end.
|
|
615
|
+
*
|
|
536
616
|
* @example
|
|
537
617
|
* ```ts
|
|
538
618
|
* pipe([1, 2], Arr.prepend(0)); // [0, 1, 2]
|
|
539
619
|
* ```
|
|
540
620
|
*/
|
|
541
|
-
const prepend = (
|
|
621
|
+
const prepend = (item) => (items) => [item, ...items];
|
|
542
622
|
/**
|
|
543
623
|
* Appends a value to the end of an array, returning a NonEmptyArr.
|
|
544
624
|
*
|
|
625
|
+
* @see {@link prepend} for adding an element to the beginning.
|
|
626
|
+
*
|
|
545
627
|
* @example
|
|
546
628
|
* ```ts
|
|
547
629
|
* pipe([1, 2], Arr.append(3)); // [1, 2, 3]
|
|
548
630
|
* ```
|
|
549
631
|
*/
|
|
550
|
-
const append = (
|
|
632
|
+
const append = (item) => (items) => [...items, item];
|
|
551
633
|
/**
|
|
552
634
|
* Returns the length of an array.
|
|
553
635
|
*
|
|
@@ -556,31 +638,35 @@ const append = (value) => (data) => [...data, value];
|
|
|
556
638
|
* Arr.size([1, 2, 3]); // 3
|
|
557
639
|
* ```
|
|
558
640
|
*/
|
|
559
|
-
const size$3 = (
|
|
641
|
+
const size$3 = (items) => items.length;
|
|
560
642
|
/**
|
|
561
643
|
* Returns true if any element satisfies the predicate.
|
|
562
644
|
*
|
|
645
|
+
* @see {@link every} for checking whether all elements satisfy a predicate.
|
|
646
|
+
*
|
|
563
647
|
* @example
|
|
564
648
|
* ```ts
|
|
565
649
|
* pipe([1, 2, 3], Arr.some(n => n > 2)); // true
|
|
566
650
|
* ```
|
|
567
651
|
*/
|
|
568
|
-
const some = (predicate) => (
|
|
569
|
-
const n =
|
|
570
|
-
for (let i = 0; i < n; i++) if (predicate(
|
|
652
|
+
const some = (predicate) => (items) => {
|
|
653
|
+
const n = items.length;
|
|
654
|
+
for (let i = 0; i < n; i++) if (predicate(items[i])) return true;
|
|
571
655
|
return false;
|
|
572
656
|
};
|
|
573
657
|
/**
|
|
574
658
|
* Returns true if all elements satisfy the predicate.
|
|
575
659
|
*
|
|
660
|
+
* @see {@link some} for checking whether any element satisfies a predicate.
|
|
661
|
+
*
|
|
576
662
|
* @example
|
|
577
663
|
* ```ts
|
|
578
664
|
* pipe([1, 2, 3], Arr.every(n => n > 0)); // true
|
|
579
665
|
* ```
|
|
580
666
|
*/
|
|
581
|
-
const every = (predicate) => (
|
|
582
|
-
const n =
|
|
583
|
-
for (let i = 0; i < n; i++) if (!predicate(
|
|
667
|
+
const every = (predicate) => (items) => {
|
|
668
|
+
const n = items.length;
|
|
669
|
+
for (let i = 0; i < n; i++) if (!predicate(items[i])) return false;
|
|
584
670
|
return true;
|
|
585
671
|
};
|
|
586
672
|
/**
|
|
@@ -591,11 +677,13 @@ const every = (predicate) => (data) => {
|
|
|
591
677
|
* Arr.reverse([1, 2, 3]); // [3, 2, 1]
|
|
592
678
|
* ```
|
|
593
679
|
*/
|
|
594
|
-
const reverse = (
|
|
680
|
+
const reverse = (items) => [...items].toReversed();
|
|
595
681
|
/**
|
|
596
682
|
* Returns a new array with `item` inserted before the element at `index`.
|
|
597
683
|
* Negative indices are clamped to 0; indices beyond the array length append to the end.
|
|
598
684
|
*
|
|
685
|
+
* @see {@link removeAt} for removing an element at an index.
|
|
686
|
+
*
|
|
599
687
|
* @example
|
|
600
688
|
* ```ts
|
|
601
689
|
* pipe([1, 2, 3], Arr.insertAt(1, 99)); // [1, 99, 2, 3]
|
|
@@ -603,11 +691,11 @@ const reverse = (data) => [...data].toReversed();
|
|
|
603
691
|
* pipe([1, 2, 3], Arr.insertAt(3, 99)); // [1, 2, 3, 99]
|
|
604
692
|
* ```
|
|
605
693
|
*/
|
|
606
|
-
const insertAt = (index, item) => (
|
|
607
|
-
const i = Math.max(0, Math.min(index,
|
|
608
|
-
const arr =
|
|
694
|
+
const insertAt = (index, item) => (items) => {
|
|
695
|
+
const i = Math.max(0, Math.min(index, items.length));
|
|
696
|
+
const arr = items;
|
|
609
697
|
if (typeof arr.toSpliced === "function") return arr.toSpliced(i, 0, item);
|
|
610
|
-
const result = [...
|
|
698
|
+
const result = [...items];
|
|
611
699
|
result.splice(i, 0, item);
|
|
612
700
|
return result;
|
|
613
701
|
};
|
|
@@ -615,6 +703,8 @@ const insertAt = (index, item) => (data) => {
|
|
|
615
703
|
* Returns a new array with the element at `index` removed.
|
|
616
704
|
* Returns the original array unchanged if `index` is out of bounds.
|
|
617
705
|
*
|
|
706
|
+
* @see {@link insertAt} for inserting an element at an index.
|
|
707
|
+
*
|
|
618
708
|
* @example
|
|
619
709
|
* ```ts
|
|
620
710
|
* pipe([1, 2, 3], Arr.removeAt(1)); // [1, 3]
|
|
@@ -622,76 +712,90 @@ const insertAt = (index, item) => (data) => {
|
|
|
622
712
|
* pipe([1, 2, 3], Arr.removeAt(5)); // [1, 2, 3]
|
|
623
713
|
* ```
|
|
624
714
|
*/
|
|
625
|
-
const removeAt = (index) => (
|
|
626
|
-
if (index < 0 || index >=
|
|
627
|
-
const arr =
|
|
715
|
+
const removeAt = (index) => (items) => {
|
|
716
|
+
if (index < 0 || index >= items.length) return items;
|
|
717
|
+
const arr = items;
|
|
628
718
|
if (typeof arr.toSpliced === "function") return arr.toSpliced(index, 1);
|
|
629
|
-
const result = [...
|
|
719
|
+
const result = [...items];
|
|
630
720
|
result.splice(index, 1);
|
|
631
721
|
return result;
|
|
632
722
|
};
|
|
633
723
|
/**
|
|
634
724
|
* Takes the first n elements from an array.
|
|
635
725
|
*
|
|
726
|
+
* @see {@link drop} for discarding the first n elements.
|
|
727
|
+
* @see {@link takeWhile} for taking elements based on a predicate.
|
|
728
|
+
*
|
|
636
729
|
* @example
|
|
637
730
|
* ```ts
|
|
638
731
|
* pipe([1, 2, 3, 4], Arr.take(2)); // [1, 2]
|
|
639
732
|
* ```
|
|
640
733
|
*/
|
|
641
|
-
const take = (
|
|
734
|
+
const take = (count) => (items) => count <= 0 ? [] : items.slice(0, count);
|
|
642
735
|
/**
|
|
643
736
|
* Drops the first n elements from an array.
|
|
644
737
|
*
|
|
738
|
+
* @see {@link take} for keeping the first n elements.
|
|
739
|
+
* @see {@link dropWhile} for discarding elements based on a predicate.
|
|
740
|
+
*
|
|
645
741
|
* @example
|
|
646
742
|
* ```ts
|
|
647
743
|
* pipe([1, 2, 3, 4], Arr.drop(2)); // [3, 4]
|
|
648
744
|
* ```
|
|
649
745
|
*/
|
|
650
|
-
const drop = (
|
|
746
|
+
const drop = (count) => (items) => items.slice(count);
|
|
651
747
|
/**
|
|
652
748
|
* Takes elements from the start while the predicate holds.
|
|
653
749
|
*
|
|
750
|
+
* @see {@link dropWhile} for discarding elements while a predicate holds.
|
|
751
|
+
* @see {@link take} for taking a fixed count of elements.
|
|
752
|
+
*
|
|
654
753
|
* @example
|
|
655
754
|
* ```ts
|
|
656
755
|
* pipe([1, 2, 3, 1], Arr.takeWhile(n => n < 3)); // [1, 2]
|
|
657
756
|
* ```
|
|
658
757
|
*/
|
|
659
|
-
const takeWhile = (predicate) => (
|
|
758
|
+
const takeWhile = (predicate) => (items) => {
|
|
660
759
|
const result = [];
|
|
661
|
-
for (const
|
|
662
|
-
if (!predicate(
|
|
663
|
-
result.push(
|
|
760
|
+
for (const item of items) {
|
|
761
|
+
if (!predicate(item)) break;
|
|
762
|
+
result.push(item);
|
|
664
763
|
}
|
|
665
764
|
return result;
|
|
666
765
|
};
|
|
667
766
|
/**
|
|
668
767
|
* Drops elements from the start while the predicate holds.
|
|
669
768
|
*
|
|
769
|
+
* @see {@link takeWhile} for keeping elements while a predicate holds.
|
|
770
|
+
* @see {@link drop} for discarding a fixed count of elements.
|
|
771
|
+
*
|
|
670
772
|
* @example
|
|
671
773
|
* ```ts
|
|
672
774
|
* pipe([1, 2, 3, 1], Arr.dropWhile(n => n < 3)); // [3, 1]
|
|
673
775
|
* ```
|
|
674
776
|
*/
|
|
675
|
-
const dropWhile = (predicate) => (
|
|
777
|
+
const dropWhile = (predicate) => (items) => {
|
|
676
778
|
let i = 0;
|
|
677
|
-
while (i <
|
|
678
|
-
return
|
|
779
|
+
while (i < items.length && predicate(items[i])) i++;
|
|
780
|
+
return items.slice(i);
|
|
679
781
|
};
|
|
680
782
|
/**
|
|
681
783
|
* Like `reduce`, but returns every intermediate accumulator as an array.
|
|
682
784
|
* The initial value is not included — the output has the same length as the input.
|
|
683
785
|
*
|
|
786
|
+
* @see {@link reduce} for computing only the final accumulator value.
|
|
787
|
+
*
|
|
684
788
|
* @example
|
|
685
789
|
* ```ts
|
|
686
790
|
* pipe([1, 2, 3], Arr.scan(0, (acc, n) => acc + n)); // [1, 3, 6]
|
|
687
791
|
* ```
|
|
688
792
|
*/
|
|
689
|
-
const scan = (initial,
|
|
690
|
-
const n =
|
|
793
|
+
const scan = (initial, reducer) => (items) => {
|
|
794
|
+
const n = items.length;
|
|
691
795
|
const result = new Array(n);
|
|
692
796
|
let acc = initial;
|
|
693
797
|
for (let i = 0; i < n; i++) {
|
|
694
|
-
acc =
|
|
798
|
+
acc = reducer(acc, items[i]);
|
|
695
799
|
result[i] = acc;
|
|
696
800
|
}
|
|
697
801
|
return result;
|
|
@@ -707,28 +811,31 @@ const scan = (initial, f) => (data) => {
|
|
|
707
811
|
* pipe([1, 2, 3], Arr.splitAt(10)); // [[1, 2, 3], []]
|
|
708
812
|
* ```
|
|
709
813
|
*/
|
|
710
|
-
const splitAt = (index) => (
|
|
814
|
+
const splitAt = (index) => (items) => {
|
|
711
815
|
const i = Math.max(0, index);
|
|
712
|
-
return [
|
|
816
|
+
return [items.slice(0, i), items.slice(i)];
|
|
713
817
|
};
|
|
714
818
|
/**
|
|
715
819
|
* Partitions an array by applying a function returning `Maybe<B>`.
|
|
716
820
|
* Elements returning `None` are gathered into `failures` (original `A` values);
|
|
717
821
|
* elements returning `Some(b)` are gathered into `successes` (`B` values).
|
|
718
822
|
*
|
|
823
|
+
* @see {@link partitionMap} for partitioning with a Result mapper.
|
|
824
|
+
* @see {@link partition} for partitioning with a boolean predicate.
|
|
825
|
+
*
|
|
719
826
|
* @example
|
|
720
827
|
* ```ts
|
|
721
828
|
* const parseNumber = (s: string) => isNaN(Number(s)) ? Maybe.make.none() : Maybe.make.some(Number(s));
|
|
722
829
|
* pipe(["1", "abc", "3"], Arr.partitionMaybe(parseNumber)); // [["abc"], [1, 3]]
|
|
723
830
|
* ```
|
|
724
831
|
*/
|
|
725
|
-
const partitionMaybe = (
|
|
832
|
+
const partitionMaybe = (transform) => (items) => {
|
|
726
833
|
const failures = [];
|
|
727
834
|
const successes = [];
|
|
728
|
-
for (let i = 0; i <
|
|
729
|
-
const res =
|
|
835
|
+
for (let i = 0; i < items.length; i++) {
|
|
836
|
+
const res = transform(items[i]);
|
|
730
837
|
if (res.kind === "Some") successes.push(res.value);
|
|
731
|
-
else failures.push(
|
|
838
|
+
else failures.push(items[i]);
|
|
732
839
|
}
|
|
733
840
|
return [failures, successes];
|
|
734
841
|
};
|
|
@@ -743,13 +850,15 @@ const partitionMaybe = (f) => (data) => {
|
|
|
743
850
|
* pipe([10, 20, 30], Arr.at(5)); // None
|
|
744
851
|
* ```
|
|
745
852
|
*/
|
|
746
|
-
const at = (index) => (
|
|
747
|
-
const targetIndex = index < 0 ?
|
|
748
|
-
if (targetIndex < 0 || targetIndex >=
|
|
749
|
-
return Maybe.make.some(
|
|
853
|
+
const at = (index) => (items) => {
|
|
854
|
+
const targetIndex = index < 0 ? items.length + index : index;
|
|
855
|
+
if (targetIndex < 0 || targetIndex >= items.length) return Maybe.make.none();
|
|
856
|
+
return Maybe.make.some(items[targetIndex]);
|
|
750
857
|
};
|
|
751
858
|
/**
|
|
752
|
-
* Finds the first element in an array for which `
|
|
859
|
+
* Finds the first element in an array for which `transform` returns `Some(b)`.
|
|
860
|
+
*
|
|
861
|
+
* @see {@link findFirst} for finding elements with a boolean predicate.
|
|
753
862
|
*
|
|
754
863
|
* @example
|
|
755
864
|
* ```ts
|
|
@@ -759,9 +868,9 @@ const at = (index) => (data) => {
|
|
|
759
868
|
* ); // Some(1)
|
|
760
869
|
* ```
|
|
761
870
|
*/
|
|
762
|
-
const findMap = (
|
|
763
|
-
for (let i = 0; i <
|
|
764
|
-
const res =
|
|
871
|
+
const findMap = (transform) => (items) => {
|
|
872
|
+
for (let i = 0; i < items.length; i++) {
|
|
873
|
+
const res = transform(items[i]);
|
|
765
874
|
if (res.kind === "Some") return res;
|
|
766
875
|
}
|
|
767
876
|
return Maybe.make.none();
|
|
@@ -769,6 +878,8 @@ const findMap = (f) => (data) => {
|
|
|
769
878
|
/**
|
|
770
879
|
* Indexes elements of an array into a `ReadonlyMap<K, A>` using a key extraction function.
|
|
771
880
|
*
|
|
881
|
+
* @see {@link groupBy} for grouping multiple items per key into arrays.
|
|
882
|
+
*
|
|
772
883
|
* @example
|
|
773
884
|
* ```ts
|
|
774
885
|
* pipe(
|
|
@@ -777,9 +888,9 @@ const findMap = (f) => (data) => {
|
|
|
777
888
|
* ); // ReadonlyMap { 1 => { id: 1, name: "Alice" }, 2 => { id: 2, name: "Bob" } }
|
|
778
889
|
* ```
|
|
779
890
|
*/
|
|
780
|
-
const indexBy = (
|
|
891
|
+
const indexBy = (keySelector) => (items) => {
|
|
781
892
|
const resultMap = new globalThis.Map();
|
|
782
|
-
for (let i = 0; i <
|
|
893
|
+
for (let i = 0; i < items.length; i++) resultMap.set(keySelector(items[i]), items[i]);
|
|
783
894
|
return resultMap;
|
|
784
895
|
};
|
|
785
896
|
/**
|
|
@@ -791,16 +902,18 @@ const indexBy = (keyFn) => (data) => {
|
|
|
791
902
|
* // ReadonlyMap { "a" => 3, "b" => 2, "c" => 1 }
|
|
792
903
|
* ```
|
|
793
904
|
*/
|
|
794
|
-
const frequencies = (
|
|
905
|
+
const frequencies = (items) => {
|
|
795
906
|
const resultMap = new globalThis.Map();
|
|
796
|
-
for (let i = 0; i <
|
|
797
|
-
const item =
|
|
907
|
+
for (let i = 0; i < items.length; i++) {
|
|
908
|
+
const item = items[i];
|
|
798
909
|
resultMap.set(item, (resultMap.get(item) ?? 0) + 1);
|
|
799
910
|
}
|
|
800
911
|
return resultMap;
|
|
801
912
|
};
|
|
802
913
|
/**
|
|
803
|
-
* Groups consecutive elements that share the same key returned by `
|
|
914
|
+
* Groups consecutive elements that share the same key returned by `keySelector`.
|
|
915
|
+
*
|
|
916
|
+
* @see {@link chunksOf} for fixed-size chunking.
|
|
804
917
|
*
|
|
805
918
|
* @example
|
|
806
919
|
* ```ts
|
|
@@ -810,14 +923,14 @@ const frequencies = (data) => {
|
|
|
810
923
|
* ); // [[1, 1], [2], [3, 3], [1]]
|
|
811
924
|
* ```
|
|
812
925
|
*/
|
|
813
|
-
const chunkBy = (
|
|
814
|
-
if (
|
|
926
|
+
const chunkBy = (keySelector) => (items) => {
|
|
927
|
+
if (items.length === 0) return [];
|
|
815
928
|
const result = [];
|
|
816
|
-
let currentChunk = [
|
|
817
|
-
let currentKey =
|
|
818
|
-
for (let i = 1; i <
|
|
819
|
-
const item =
|
|
820
|
-
const key =
|
|
929
|
+
let currentChunk = [items[0]];
|
|
930
|
+
let currentKey = keySelector(items[0]);
|
|
931
|
+
for (let i = 1; i < items.length; i++) {
|
|
932
|
+
const item = items[i];
|
|
933
|
+
const key = keySelector(item);
|
|
821
934
|
if (Object.is(key, currentKey)) currentChunk.push(item);
|
|
822
935
|
else {
|
|
823
936
|
result.push(currentChunk);
|
|
@@ -832,20 +945,22 @@ const chunkBy = (keyFn) => (data) => {
|
|
|
832
945
|
* Removes consecutive duplicate elements.
|
|
833
946
|
* An optional `Equality<A>` can be provided (defaults to `Object.is`).
|
|
834
947
|
*
|
|
948
|
+
* @see {@link uniq} for deduplicating across the entire array.
|
|
949
|
+
*
|
|
835
950
|
* @example
|
|
836
951
|
* ```ts
|
|
837
952
|
* Arr.dedupeAdjacent()([1, 1, 2, 2, 1, 3]); // [1, 2, 1, 3]
|
|
838
953
|
* ```
|
|
839
954
|
*/
|
|
840
|
-
const dedupeAdjacent = (
|
|
841
|
-
if (
|
|
842
|
-
const result = [
|
|
843
|
-
for (let i = 1; i <
|
|
955
|
+
const dedupeAdjacent = (areEqual = (first, second) => Object.is(first, second)) => (items) => {
|
|
956
|
+
if (items.length === 0) return [];
|
|
957
|
+
const result = [items[0]];
|
|
958
|
+
for (let i = 1; i < items.length; i++) if (!areEqual(items[i], result[result.length - 1])) result.push(items[i]);
|
|
844
959
|
return result;
|
|
845
960
|
};
|
|
846
961
|
/**
|
|
847
962
|
* Produces a sliding window of `size` elements over an array, advancing by `step` (default `1`).
|
|
848
|
-
* Returns an empty array if `size <= 0` or `size >
|
|
963
|
+
* Returns an empty array if `size <= 0` or `size > items.length`.
|
|
849
964
|
*
|
|
850
965
|
* @example
|
|
851
966
|
* ```ts
|
|
@@ -853,15 +968,15 @@ const dedupeAdjacent = (eq = (a, b) => Object.is(a, b)) => (data) => {
|
|
|
853
968
|
* pipe([1, 2, 3, 4], Arr.windowed(2, { step: 2 })); // [[1, 2], [3, 4]]
|
|
854
969
|
* ```
|
|
855
970
|
*/
|
|
856
|
-
const windowed = (windowSize, options) => (
|
|
971
|
+
const windowed = (windowSize, options) => (items) => {
|
|
857
972
|
const step = options?.step ?? 1;
|
|
858
|
-
if (windowSize <= 0 || step <= 0 ||
|
|
973
|
+
if (windowSize <= 0 || step <= 0 || items.length < windowSize) return [];
|
|
859
974
|
const result = [];
|
|
860
|
-
for (let i = 0; i <=
|
|
975
|
+
for (let i = 0; i <= items.length - windowSize; i += step) result.push(items.slice(i, i + windowSize));
|
|
861
976
|
return result;
|
|
862
977
|
};
|
|
863
978
|
/**
|
|
864
|
-
* Generates an array from an initial seed state until `
|
|
979
|
+
* Generates an array from an initial seed state until `step` returns `None`.
|
|
865
980
|
*
|
|
866
981
|
* @example
|
|
867
982
|
* ```ts
|
|
@@ -869,11 +984,11 @@ const windowed = (windowSize, options) => (data) => {
|
|
|
869
984
|
* // [1, 2, 3]
|
|
870
985
|
* ```
|
|
871
986
|
*/
|
|
872
|
-
const unfold = (initial,
|
|
987
|
+
const unfold = (initial, step) => {
|
|
873
988
|
const result = [];
|
|
874
989
|
let currentState = initial;
|
|
875
990
|
while (true) {
|
|
876
|
-
const next =
|
|
991
|
+
const next = step(currentState);
|
|
877
992
|
if (next.kind === "None") break;
|
|
878
993
|
const [item, nextState] = next.value;
|
|
879
994
|
result.push(item);
|
|
@@ -914,6 +1029,7 @@ const Arr = {
|
|
|
914
1029
|
prepend,
|
|
915
1030
|
append,
|
|
916
1031
|
size: size$3,
|
|
1032
|
+
length: size$3,
|
|
917
1033
|
some,
|
|
918
1034
|
every,
|
|
919
1035
|
reverse,
|
|
@@ -934,33 +1050,44 @@ const Arr = {
|
|
|
934
1050
|
dedupeAdjacent,
|
|
935
1051
|
windowed,
|
|
936
1052
|
unfold,
|
|
937
|
-
from: { Array: (data) => data.length > 0 ? Maybe.make.some(data) : Maybe.make.none() },
|
|
938
1053
|
is: {
|
|
939
|
-
|
|
940
|
-
|
|
1054
|
+
/**
|
|
1055
|
+
* Returns `true` when the array is empty.
|
|
1056
|
+
*
|
|
1057
|
+
* @see {@link nonEmpty} for checking if an array contains elements.
|
|
1058
|
+
*/
|
|
1059
|
+
empty: (items) => items.length === 0,
|
|
1060
|
+
/**
|
|
1061
|
+
* Returns `true` when the array contains at least one element.
|
|
1062
|
+
*
|
|
1063
|
+
* @see {@link empty} for checking if an array is empty.
|
|
1064
|
+
*/
|
|
1065
|
+
nonEmpty: (items) => isNonEmptyArr(items)
|
|
941
1066
|
},
|
|
942
1067
|
traverse: {
|
|
943
1068
|
Maybe: ArrMaybe.traverse,
|
|
944
1069
|
Result: ArrResult.traverse,
|
|
945
|
-
Task: _traverseTask
|
|
1070
|
+
Task: _traverseTask,
|
|
1071
|
+
Validation: ArrValidation.traverse
|
|
946
1072
|
},
|
|
947
1073
|
sequence: {
|
|
948
1074
|
Maybe: ArrMaybe.sequence,
|
|
949
1075
|
Result: ArrResult.sequence,
|
|
950
|
-
Task: _sequenceTask
|
|
1076
|
+
Task: _sequenceTask,
|
|
1077
|
+
Validation: ArrValidation.sequence
|
|
951
1078
|
},
|
|
952
1079
|
NonEmpty: {
|
|
953
|
-
singleton: (
|
|
954
|
-
from: {
|
|
955
|
-
head: (
|
|
956
|
-
last: (
|
|
957
|
-
tail: (
|
|
958
|
-
reduce: (
|
|
959
|
-
map: (
|
|
960
|
-
mapWithIndex: (
|
|
961
|
-
intersperse: (
|
|
962
|
-
concat: (other) => (
|
|
963
|
-
reverse: (
|
|
1080
|
+
singleton: (item) => [item],
|
|
1081
|
+
from: { array: (items) => isNonEmptyArr(items) ? Maybe.make.some(items) : Maybe.make.none() },
|
|
1082
|
+
head: (items) => items[0],
|
|
1083
|
+
last: (items) => items[items.length - 1],
|
|
1084
|
+
tail: (items) => items.slice(1),
|
|
1085
|
+
reduce: (reducer) => (items) => items.reduce(reducer),
|
|
1086
|
+
map: (transform) => (items) => map$3(transform)(items),
|
|
1087
|
+
mapWithIndex: (transform) => (items) => mapWithIndex(transform)(items),
|
|
1088
|
+
intersperse: (separator) => (items) => intersperse(separator)(items),
|
|
1089
|
+
concat: (other) => (items) => concat(other)(items),
|
|
1090
|
+
reverse: (items) => reverse(items)
|
|
964
1091
|
}
|
|
965
1092
|
};
|
|
966
1093
|
//#endregion
|
|
@@ -991,30 +1118,36 @@ const BigNum = {
|
|
|
991
1118
|
* BigNum.is.zero(5n); // false
|
|
992
1119
|
* ```
|
|
993
1120
|
*/
|
|
994
|
-
zero: (
|
|
1121
|
+
zero: (value) => value === 0n,
|
|
995
1122
|
/**
|
|
996
1123
|
* Returns `true` when the bigint is an even integer.
|
|
997
1124
|
*
|
|
1125
|
+
* @see {@link BigNum.is.odd} to check if a bigint is odd.
|
|
1126
|
+
*
|
|
998
1127
|
* @example
|
|
999
1128
|
* ```ts
|
|
1000
1129
|
* BigNum.is.even(4n); // true
|
|
1001
1130
|
* BigNum.is.even(3n); // false
|
|
1002
1131
|
* ```
|
|
1003
1132
|
*/
|
|
1004
|
-
even: (
|
|
1133
|
+
even: (value) => value % 2n === 0n,
|
|
1005
1134
|
/**
|
|
1006
1135
|
* Returns `true` when the bigint is an odd integer.
|
|
1007
1136
|
*
|
|
1137
|
+
* @see {@link BigNum.is.even} to check if a bigint is even.
|
|
1138
|
+
*
|
|
1008
1139
|
* @example
|
|
1009
1140
|
* ```ts
|
|
1010
1141
|
* BigNum.is.odd(3n); // true
|
|
1011
1142
|
* BigNum.is.odd(4n); // false
|
|
1012
1143
|
* ```
|
|
1013
1144
|
*/
|
|
1014
|
-
odd: (
|
|
1145
|
+
odd: (value) => value % 2n !== 0n,
|
|
1015
1146
|
/**
|
|
1016
1147
|
* Returns `true` when the bigint is strictly greater than zero (`0n`).
|
|
1017
1148
|
*
|
|
1149
|
+
* @see {@link BigNum.is.negative} to check if a bigint is less than zero.
|
|
1150
|
+
*
|
|
1018
1151
|
* @example
|
|
1019
1152
|
* ```ts
|
|
1020
1153
|
* BigNum.is.positive(5n); // true
|
|
@@ -1022,10 +1155,12 @@ const BigNum = {
|
|
|
1022
1155
|
* BigNum.is.positive(-5n); // false
|
|
1023
1156
|
* ```
|
|
1024
1157
|
*/
|
|
1025
|
-
positive: (
|
|
1158
|
+
positive: (value) => value > 0n,
|
|
1026
1159
|
/**
|
|
1027
1160
|
* Returns `true` when the bigint is strictly less than zero (`0n`).
|
|
1028
1161
|
*
|
|
1162
|
+
* @see {@link BigNum.is.positive} to check if a bigint is greater than zero.
|
|
1163
|
+
*
|
|
1029
1164
|
* @example
|
|
1030
1165
|
* ```ts
|
|
1031
1166
|
* BigNum.is.negative(-5n); // true
|
|
@@ -1033,7 +1168,7 @@ const BigNum = {
|
|
|
1033
1168
|
* BigNum.is.negative(5n); // false
|
|
1034
1169
|
* ```
|
|
1035
1170
|
*/
|
|
1036
|
-
negative: (
|
|
1171
|
+
negative: (value) => value < 0n
|
|
1037
1172
|
},
|
|
1038
1173
|
from: {
|
|
1039
1174
|
/**
|
|
@@ -1045,10 +1180,10 @@ const BigNum = {
|
|
|
1045
1180
|
* BigNum.from.string("abc"); // None
|
|
1046
1181
|
* ```
|
|
1047
1182
|
*/
|
|
1048
|
-
string: (
|
|
1183
|
+
string: (text) => {
|
|
1049
1184
|
try {
|
|
1050
|
-
if (
|
|
1051
|
-
return Maybe.make.some(BigInt(
|
|
1185
|
+
if (text.trim() === "") return Maybe.make.none();
|
|
1186
|
+
return Maybe.make.some(BigInt(text));
|
|
1052
1187
|
} catch {
|
|
1053
1188
|
return Maybe.make.none();
|
|
1054
1189
|
}
|
|
@@ -1062,9 +1197,9 @@ const BigNum = {
|
|
|
1062
1197
|
* BigNum.from.number(3.14); // None
|
|
1063
1198
|
* ```
|
|
1064
1199
|
*/
|
|
1065
|
-
number: (
|
|
1066
|
-
if (!Number.isInteger(
|
|
1067
|
-
return Maybe.make.some(BigInt(
|
|
1200
|
+
number: (value) => {
|
|
1201
|
+
if (!Number.isInteger(value) || value < Number.MIN_SAFE_INTEGER || value > Number.MAX_SAFE_INTEGER) return Maybe.make.none();
|
|
1202
|
+
return Maybe.make.some(BigInt(value));
|
|
1068
1203
|
}
|
|
1069
1204
|
},
|
|
1070
1205
|
to: {
|
|
@@ -1077,75 +1212,100 @@ const BigNum = {
|
|
|
1077
1212
|
* BigNum.to.number(9007199254740993n); // None
|
|
1078
1213
|
* ```
|
|
1079
1214
|
*/
|
|
1080
|
-
number: (
|
|
1081
|
-
if (
|
|
1082
|
-
return Maybe.make.some(Number(
|
|
1215
|
+
number: (value) => {
|
|
1216
|
+
if (value < BigInt(Number.MIN_SAFE_INTEGER) || value > BigInt(Number.MAX_SAFE_INTEGER)) return Maybe.make.none();
|
|
1217
|
+
return Maybe.make.some(Number(value));
|
|
1083
1218
|
} },
|
|
1084
1219
|
/**
|
|
1085
|
-
* Adds `
|
|
1220
|
+
* Adds `amount` to `value`. Data-last curried signature: `add(amount)(value)` = `value + amount`.
|
|
1221
|
+
*
|
|
1222
|
+
* @see {@link BigNum.subtract} to subtract an amount from a bigint.
|
|
1086
1223
|
*
|
|
1087
1224
|
* @example
|
|
1088
1225
|
* ```ts
|
|
1089
1226
|
* pipe(10n, BigNum.add(5n)); // 15n
|
|
1090
1227
|
* ```
|
|
1091
1228
|
*/
|
|
1092
|
-
add: (
|
|
1229
|
+
add: (amount) => (value) => value + amount,
|
|
1093
1230
|
/**
|
|
1094
|
-
* Subtracts `
|
|
1231
|
+
* Subtracts `amount` from `from`. Data-last curried signature: `subtract(amount)(from)` = `from - amount`.
|
|
1232
|
+
*
|
|
1233
|
+
* @see {@link BigNum.add} to add an amount to a bigint.
|
|
1095
1234
|
*
|
|
1096
1235
|
* @example
|
|
1097
1236
|
* ```ts
|
|
1098
|
-
* pipe(10n, BigNum.
|
|
1237
|
+
* pipe(10n, BigNum.subtract(3n)); // 7n
|
|
1099
1238
|
* ```
|
|
1100
1239
|
*/
|
|
1101
|
-
|
|
1240
|
+
subtract: (amount) => (from) => from - amount,
|
|
1102
1241
|
/**
|
|
1103
|
-
* Multiplies `
|
|
1242
|
+
* Multiplies `value` by `factor`. Data-last curried signature: `multiply(factor)(value)` = `value * factor`.
|
|
1243
|
+
*
|
|
1244
|
+
* @see {@link BigNum.divide} to divide a bigint by a divisor.
|
|
1104
1245
|
*
|
|
1105
1246
|
* @example
|
|
1106
1247
|
* ```ts
|
|
1107
|
-
* pipe(6n, BigNum.
|
|
1248
|
+
* pipe(6n, BigNum.multiply(7n)); // 42n
|
|
1108
1249
|
* ```
|
|
1109
1250
|
*/
|
|
1110
|
-
|
|
1251
|
+
multiply: (factor) => (value) => value * factor,
|
|
1111
1252
|
/**
|
|
1112
|
-
* Divides `
|
|
1253
|
+
* Divides `dividend` by `divisor`. Returns `None` if `divisor` is `0n`.
|
|
1254
|
+
*
|
|
1255
|
+
* @see {@link BigNum.multiply} to multiply a bigint by a factor.
|
|
1256
|
+
* @see {@link BigNum.remainder} to compute the division remainder.
|
|
1113
1257
|
*
|
|
1114
1258
|
* @example
|
|
1115
1259
|
* ```ts
|
|
1116
|
-
* pipe(20n, BigNum.
|
|
1117
|
-
* pipe(5n, BigNum.
|
|
1260
|
+
* pipe(20n, BigNum.divide(4n)); // Some(5n)
|
|
1261
|
+
* pipe(5n, BigNum.divide(0n)); // None
|
|
1118
1262
|
* ```
|
|
1119
1263
|
*/
|
|
1120
|
-
|
|
1264
|
+
divide: (divisor) => (dividend) => divisor === 0n ? Maybe.make.none() : Maybe.make.some(dividend / divisor),
|
|
1121
1265
|
/**
|
|
1122
|
-
* Computes remainder of `
|
|
1266
|
+
* Computes remainder of `dividend / divisor`. Returns `None` if `divisor` is `0n`.
|
|
1267
|
+
*
|
|
1268
|
+
* @see {@link BigNum.divide} for full division.
|
|
1123
1269
|
*
|
|
1124
1270
|
* @example
|
|
1125
1271
|
* ```ts
|
|
1126
|
-
* pipe(10n, BigNum.
|
|
1127
|
-
* pipe(5n, BigNum.
|
|
1272
|
+
* pipe(10n, BigNum.remainder(3n)); // Some(1n)
|
|
1273
|
+
* pipe(5n, BigNum.remainder(0n)); // None
|
|
1128
1274
|
* ```
|
|
1129
1275
|
*/
|
|
1130
|
-
|
|
1276
|
+
remainder: (divisor) => (dividend) => divisor === 0n ? Maybe.make.none() : Maybe.make.some(dividend % divisor),
|
|
1131
1277
|
/**
|
|
1132
|
-
* Clamps `
|
|
1278
|
+
* Clamps `value` between `min` and `max` (inclusive).
|
|
1133
1279
|
*
|
|
1134
1280
|
* @example
|
|
1135
1281
|
* ```ts
|
|
1136
1282
|
* pipe(150n, BigNum.clamp(0n, 100n)); // 100n
|
|
1137
1283
|
* ```
|
|
1138
1284
|
*/
|
|
1139
|
-
clamp: (min, max) => (
|
|
1285
|
+
clamp: (min, max) => (value) => value < min ? min : value > max ? max : value,
|
|
1286
|
+
/**
|
|
1287
|
+
* Returns `true` when the bigint is between `min` and `max` (both inclusive).
|
|
1288
|
+
*
|
|
1289
|
+
* @see {@link BigNum.inRange} for half-open range checking [start, end).
|
|
1290
|
+
*
|
|
1291
|
+
* @example
|
|
1292
|
+
* ```ts
|
|
1293
|
+
* pipe(5n, BigNum.between(1n, 10n)); // true
|
|
1294
|
+
* pipe(0n, BigNum.between(1n, 10n)); // false
|
|
1295
|
+
* ```
|
|
1296
|
+
*/
|
|
1297
|
+
between: (min, max) => (value) => value >= min && value <= max,
|
|
1140
1298
|
/**
|
|
1141
|
-
* Returns `true` if `
|
|
1299
|
+
* Returns `true` if `value` is in the range `[start, end)` (inclusive start, exclusive end).
|
|
1300
|
+
*
|
|
1301
|
+
* @see {@link BigNum.between} for fully closed range checking [min, max].
|
|
1142
1302
|
*
|
|
1143
1303
|
* @example
|
|
1144
1304
|
* ```ts
|
|
1145
1305
|
* pipe(5n, BigNum.inRange(1n, 10n)); // true
|
|
1146
1306
|
* ```
|
|
1147
1307
|
*/
|
|
1148
|
-
inRange: (start, end) => (
|
|
1308
|
+
inRange: (start, end) => (value) => value >= start && value < end,
|
|
1149
1309
|
/**
|
|
1150
1310
|
* Returns absolute value of a `bigint`.
|
|
1151
1311
|
*
|
|
@@ -1154,65 +1314,69 @@ number: (b) => {
|
|
|
1154
1314
|
* BigNum.abs(-42n); // 42n
|
|
1155
1315
|
* ```
|
|
1156
1316
|
*/
|
|
1157
|
-
abs: (
|
|
1317
|
+
abs: (value) => value < 0n ? -value : value,
|
|
1158
1318
|
/**
|
|
1159
|
-
* Returns the minimum of `
|
|
1319
|
+
* Returns the minimum of `value` and `other`.
|
|
1320
|
+
*
|
|
1321
|
+
* @see {@link BigNum.max} to determine the maximum value.
|
|
1160
1322
|
*
|
|
1161
1323
|
* @example
|
|
1162
1324
|
* ```ts
|
|
1163
1325
|
* pipe(10n, BigNum.min(5n)); // 5n
|
|
1164
1326
|
* ```
|
|
1165
1327
|
*/
|
|
1166
|
-
min: (
|
|
1328
|
+
min: (other) => (value) => value < other ? value : other,
|
|
1167
1329
|
/**
|
|
1168
|
-
* Returns the maximum of `
|
|
1330
|
+
* Returns the maximum of `value` and `other`.
|
|
1331
|
+
*
|
|
1332
|
+
* @see {@link BigNum.min} to determine the minimum value.
|
|
1169
1333
|
*
|
|
1170
1334
|
* @example
|
|
1171
1335
|
* ```ts
|
|
1172
1336
|
* pipe(10n, BigNum.max(5n)); // 10n
|
|
1173
1337
|
* ```
|
|
1174
1338
|
*/
|
|
1175
|
-
max: (
|
|
1339
|
+
max: (other) => (value) => value > other ? value : other
|
|
1176
1340
|
};
|
|
1177
1341
|
//#endregion
|
|
1178
1342
|
//#region src/Data/Bool.ts
|
|
1179
|
-
const isBoolean = (
|
|
1180
|
-
const isTrue = (
|
|
1181
|
-
const isFalse = (
|
|
1182
|
-
const isTruthy = (
|
|
1183
|
-
const isFalsy = (
|
|
1184
|
-
const not = (
|
|
1185
|
-
const and = (that) => (
|
|
1186
|
-
const or = (that) => (
|
|
1187
|
-
const xor = (that) => (
|
|
1188
|
-
const andLazy = (that) => (
|
|
1189
|
-
const orLazy = (that) => (
|
|
1190
|
-
const all = (
|
|
1191
|
-
for (let i = 0; i <
|
|
1343
|
+
const isBoolean = (value) => typeof value === "boolean";
|
|
1344
|
+
const isTrue = (value) => value === true;
|
|
1345
|
+
const isFalse = (value) => value === false;
|
|
1346
|
+
const isTruthy = (value) => Boolean(value);
|
|
1347
|
+
const isFalsy = (value) => !value;
|
|
1348
|
+
const not = (condition) => !condition;
|
|
1349
|
+
const and = (that) => (condition) => condition && that;
|
|
1350
|
+
const or = (that) => (condition) => condition || that;
|
|
1351
|
+
const xor = (that) => (condition) => condition !== that;
|
|
1352
|
+
const andLazy = (that) => (condition) => condition && that();
|
|
1353
|
+
const orLazy = (that) => (condition) => condition || that();
|
|
1354
|
+
const all = (conditions) => {
|
|
1355
|
+
for (let i = 0; i < conditions.length; i++) if (!conditions[i]) return false;
|
|
1192
1356
|
return true;
|
|
1193
1357
|
};
|
|
1194
|
-
const any = (
|
|
1195
|
-
for (let i = 0; i <
|
|
1358
|
+
const any = (conditions) => {
|
|
1359
|
+
for (let i = 0; i < conditions.length; i++) if (conditions[i]) return true;
|
|
1196
1360
|
return false;
|
|
1197
1361
|
};
|
|
1198
|
-
const fold = (onFalse, onTrue) => (
|
|
1199
|
-
const match = (cases) => (
|
|
1200
|
-
const fromString = (
|
|
1201
|
-
const trimmed =
|
|
1362
|
+
const fold = (onFalse, onTrue) => (condition) => condition ? onTrue() : onFalse();
|
|
1363
|
+
const match = (cases) => (condition) => condition ? cases.true() : cases.false();
|
|
1364
|
+
const fromString = (text) => {
|
|
1365
|
+
const trimmed = text.trim().toLowerCase();
|
|
1202
1366
|
if (trimmed === "true") return Maybe.make.some(true);
|
|
1203
1367
|
if (trimmed === "false") return Maybe.make.some(false);
|
|
1204
1368
|
return Maybe.make.none();
|
|
1205
1369
|
};
|
|
1206
|
-
const fromNumber = (
|
|
1207
|
-
if (
|
|
1208
|
-
if (
|
|
1370
|
+
const fromNumber = (value) => {
|
|
1371
|
+
if (value === 1) return Maybe.make.some(true);
|
|
1372
|
+
if (value === 0) return Maybe.make.some(false);
|
|
1209
1373
|
return Maybe.make.none();
|
|
1210
1374
|
};
|
|
1211
1375
|
const fromTruthy = (value) => Boolean(value);
|
|
1212
|
-
const toMaybe = (onTrue) => (
|
|
1213
|
-
const toResult = (onErr, onOk) => (
|
|
1214
|
-
const toNumber = (
|
|
1215
|
-
const toString = (
|
|
1376
|
+
const toMaybe = (onTrue) => (condition) => condition ? Maybe.make.some(onTrue()) : Maybe.make.none();
|
|
1377
|
+
const toResult = (onErr, onOk) => (condition) => condition ? Result.make.ok(onOk()) : Result.make.err(onErr());
|
|
1378
|
+
const toNumber = (condition) => condition ? 1 : 0;
|
|
1379
|
+
const toString = (condition) => condition ? "true" : "false";
|
|
1216
1380
|
const Bool = {
|
|
1217
1381
|
is: {
|
|
1218
1382
|
/**
|
|
@@ -1230,6 +1394,8 @@ const Bool = {
|
|
|
1230
1394
|
/**
|
|
1231
1395
|
* Narrowing guard — checks if a value is strictly `true`.
|
|
1232
1396
|
*
|
|
1397
|
+
* @see {@link Bool.is.false} to check if a value is strictly false.
|
|
1398
|
+
*
|
|
1233
1399
|
* @example
|
|
1234
1400
|
* ```ts
|
|
1235
1401
|
* Bool.is.true(true); // true
|
|
@@ -1240,6 +1406,8 @@ const Bool = {
|
|
|
1240
1406
|
/**
|
|
1241
1407
|
* Narrowing guard — checks if a value is strictly `false`.
|
|
1242
1408
|
*
|
|
1409
|
+
* @see {@link Bool.is.true} to check if a value is strictly true.
|
|
1410
|
+
*
|
|
1243
1411
|
* @example
|
|
1244
1412
|
* ```ts
|
|
1245
1413
|
* Bool.is.false(false); // true
|
|
@@ -1250,6 +1418,8 @@ const Bool = {
|
|
|
1250
1418
|
/**
|
|
1251
1419
|
* Type guard — checks if a value is truthy (not `false`, `0`, `0n`, `""`, `null`, `undefined`, or `NaN`).
|
|
1252
1420
|
*
|
|
1421
|
+
* @see {@link Bool.is.falsy} to check if a value is falsy.
|
|
1422
|
+
*
|
|
1253
1423
|
* @example
|
|
1254
1424
|
* ```ts
|
|
1255
1425
|
* Bool.is.truthy("hello"); // true
|
|
@@ -1262,6 +1432,8 @@ const Bool = {
|
|
|
1262
1432
|
/**
|
|
1263
1433
|
* Type guard — checks if a value is falsy (`false`, `0`, `0n`, `""`, `null`, `undefined`, or `NaN`).
|
|
1264
1434
|
*
|
|
1435
|
+
* @see {@link Bool.is.truthy} to check if a value is truthy.
|
|
1436
|
+
*
|
|
1265
1437
|
* @example
|
|
1266
1438
|
* ```ts
|
|
1267
1439
|
* Bool.is.falsy(""); // true
|
|
@@ -1282,9 +1454,12 @@ const Bool = {
|
|
|
1282
1454
|
*/
|
|
1283
1455
|
not,
|
|
1284
1456
|
/**
|
|
1285
|
-
* Logical AND combinator. Returns `true` only if both `
|
|
1457
|
+
* Logical AND combinator. Returns `true` only if both `condition` and `that` are `true`.
|
|
1286
1458
|
*
|
|
1287
|
-
* Data-last: `pipe(
|
|
1459
|
+
* Data-last: `pipe(condition, Bool.and(that))`.
|
|
1460
|
+
*
|
|
1461
|
+
* @see {@link Bool.or} for logical OR combinator.
|
|
1462
|
+
* @see {@link Bool.andLazy} for short-circuiting lazy evaluation.
|
|
1288
1463
|
*
|
|
1289
1464
|
* @example
|
|
1290
1465
|
* ```ts
|
|
@@ -1294,9 +1469,12 @@ const Bool = {
|
|
|
1294
1469
|
*/
|
|
1295
1470
|
and,
|
|
1296
1471
|
/**
|
|
1297
|
-
* Logical OR combinator. Returns `true` if either `
|
|
1472
|
+
* Logical OR combinator. Returns `true` if either `condition` or `that` is `true`.
|
|
1473
|
+
*
|
|
1474
|
+
* Data-last: `pipe(condition, Bool.or(that))`.
|
|
1298
1475
|
*
|
|
1299
|
-
*
|
|
1476
|
+
* @see {@link Bool.and} for logical AND combinator.
|
|
1477
|
+
* @see {@link Bool.orLazy} for short-circuiting lazy evaluation.
|
|
1300
1478
|
*
|
|
1301
1479
|
* @example
|
|
1302
1480
|
* ```ts
|
|
@@ -1306,9 +1484,9 @@ const Bool = {
|
|
|
1306
1484
|
*/
|
|
1307
1485
|
or,
|
|
1308
1486
|
/**
|
|
1309
|
-
* Logical XOR (exclusive OR) combinator. Returns `true` if exactly one of `
|
|
1487
|
+
* Logical XOR (exclusive OR) combinator. Returns `true` if exactly one of `condition` and `that` is `true`.
|
|
1310
1488
|
*
|
|
1311
|
-
* Data-last: `pipe(
|
|
1489
|
+
* Data-last: `pipe(condition, Bool.xor(that))`.
|
|
1312
1490
|
*
|
|
1313
1491
|
* @example
|
|
1314
1492
|
* ```ts
|
|
@@ -1319,9 +1497,12 @@ const Bool = {
|
|
|
1319
1497
|
xor,
|
|
1320
1498
|
/**
|
|
1321
1499
|
* Lazy logical AND combinator.
|
|
1322
|
-
* If `
|
|
1500
|
+
* If `condition` is `false`, the `that` computation is never evaluated.
|
|
1323
1501
|
*
|
|
1324
|
-
* Data-last: `pipe(
|
|
1502
|
+
* Data-last: `pipe(condition, Bool.andLazy(that))`.
|
|
1503
|
+
*
|
|
1504
|
+
* @see {@link Bool.orLazy} for lazy logical OR combinator.
|
|
1505
|
+
* @see {@link Bool.and} for strict logical AND evaluation.
|
|
1325
1506
|
*
|
|
1326
1507
|
* @example
|
|
1327
1508
|
* ```ts
|
|
@@ -1334,9 +1515,12 @@ const Bool = {
|
|
|
1334
1515
|
andLazy,
|
|
1335
1516
|
/**
|
|
1336
1517
|
* Lazy logical OR combinator.
|
|
1337
|
-
* If `
|
|
1518
|
+
* If `condition` is `true`, the `that` computation is never evaluated.
|
|
1519
|
+
*
|
|
1520
|
+
* Data-last: `pipe(condition, Bool.orLazy(that))`.
|
|
1338
1521
|
*
|
|
1339
|
-
*
|
|
1522
|
+
* @see {@link Bool.andLazy} for lazy logical AND combinator.
|
|
1523
|
+
* @see {@link Bool.or} for strict logical OR evaluation.
|
|
1340
1524
|
*
|
|
1341
1525
|
* @example
|
|
1342
1526
|
* ```ts
|
|
@@ -1352,6 +1536,8 @@ const Bool = {
|
|
|
1352
1536
|
* Returns `true` if every boolean is `true`, or for an empty array (vacuous truth).
|
|
1353
1537
|
* Short-circuits on the first `false`.
|
|
1354
1538
|
*
|
|
1539
|
+
* @see {@link Bool.any} to check if at least one boolean is true.
|
|
1540
|
+
*
|
|
1355
1541
|
* @example
|
|
1356
1542
|
* ```ts
|
|
1357
1543
|
* Bool.all([true, true, true]); // true
|
|
@@ -1365,6 +1551,8 @@ const Bool = {
|
|
|
1365
1551
|
* Returns `true` if at least one boolean is `true`. Returns `false` for an empty array.
|
|
1366
1552
|
* Short-circuits on the first `true`.
|
|
1367
1553
|
*
|
|
1554
|
+
* @see {@link Bool.all} to check if all booleans are true.
|
|
1555
|
+
*
|
|
1368
1556
|
* @example
|
|
1369
1557
|
* ```ts
|
|
1370
1558
|
* Bool.any([false, true, false]); // true
|
|
@@ -1379,6 +1567,8 @@ const Bool = {
|
|
|
1379
1567
|
* Positional ordering: `onFalse` first, `onTrue` second.
|
|
1380
1568
|
* Aligned with `Result.fold(onErr, onOk)` and `Maybe.fold(onNone, onSome)`.
|
|
1381
1569
|
*
|
|
1570
|
+
* @see {@link Bool.match} for named-case pattern matching with an object literal.
|
|
1571
|
+
*
|
|
1382
1572
|
* @example
|
|
1383
1573
|
* ```ts
|
|
1384
1574
|
* pipe(
|
|
@@ -1394,6 +1584,8 @@ const Bool = {
|
|
|
1394
1584
|
/**
|
|
1395
1585
|
* Pattern matching on boolean using named cases `{ true, false }`.
|
|
1396
1586
|
*
|
|
1587
|
+
* @see {@link Bool.fold} for positional argument pattern matching.
|
|
1588
|
+
*
|
|
1397
1589
|
* @example
|
|
1398
1590
|
* ```ts
|
|
1399
1591
|
* pipe(
|
|
@@ -1498,119 +1690,221 @@ const Bool = {
|
|
|
1498
1690
|
//#endregion
|
|
1499
1691
|
//#region src/Data/Dict.ts
|
|
1500
1692
|
const DictIs = {
|
|
1501
|
-
|
|
1502
|
-
|
|
1693
|
+
/**
|
|
1694
|
+
* Returns `true` when the dictionary contains zero entries.
|
|
1695
|
+
*
|
|
1696
|
+
* @see {@link nonEmpty} for checking if a dictionary contains entries.
|
|
1697
|
+
*/
|
|
1698
|
+
empty: (dict) => dict.size === 0,
|
|
1699
|
+
/**
|
|
1700
|
+
* Returns `true` when the dictionary contains at least one entry.
|
|
1701
|
+
*
|
|
1702
|
+
* @see {@link empty} for checking if a dictionary is empty.
|
|
1703
|
+
*/
|
|
1704
|
+
nonEmpty: (dict) => dict.size > 0
|
|
1503
1705
|
};
|
|
1504
1706
|
const empty$1 = () => new globalThis.Map();
|
|
1505
1707
|
const singleton$1 = (key, value) => new globalThis.Map([[key, value]]);
|
|
1506
1708
|
const DictFrom = {
|
|
1507
1709
|
entries: (entries) => new globalThis.Map(entries),
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
nullable: (data) => data === null || data === void 0 ? Maybe.make.none() : Maybe.make.some(data)
|
|
1710
|
+
record: (record) => new globalThis.Map(Object.entries(record)),
|
|
1711
|
+
nullable: (dict) => dict === null || dict === void 0 ? Maybe.make.none() : Maybe.make.some(dict)
|
|
1511
1712
|
};
|
|
1512
|
-
const DictTo = {
|
|
1713
|
+
const DictTo = { record: (dict) => {
|
|
1513
1714
|
const result = {};
|
|
1514
|
-
for (const [k, v] of
|
|
1715
|
+
for (const [k, v] of dict) result[k] = v;
|
|
1515
1716
|
return result;
|
|
1516
1717
|
} };
|
|
1517
|
-
const groupBy$1 = (
|
|
1718
|
+
const groupBy$1 = (keySelector) => (items) => {
|
|
1518
1719
|
const result = new globalThis.Map();
|
|
1519
|
-
for (const
|
|
1520
|
-
const k =
|
|
1720
|
+
for (const item of items) {
|
|
1721
|
+
const k = keySelector(item);
|
|
1521
1722
|
const existing = result.get(k);
|
|
1522
|
-
if (existing !== void 0) existing.push(
|
|
1523
|
-
else result.set(k, [
|
|
1723
|
+
if (existing !== void 0) existing.push(item);
|
|
1724
|
+
else result.set(k, [item]);
|
|
1524
1725
|
}
|
|
1525
1726
|
return result;
|
|
1526
1727
|
};
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1728
|
+
/**
|
|
1729
|
+
* Returns `true` when the dictionary contains the specified key.
|
|
1730
|
+
*
|
|
1731
|
+
* @see {@link lookup} for retrieving the value associated with a key.
|
|
1732
|
+
*/
|
|
1733
|
+
const has$1 = (key) => (dict) => dict.has(key);
|
|
1734
|
+
/**
|
|
1735
|
+
* Retrieves the value associated with a key wrapped in a `Maybe`.
|
|
1736
|
+
*
|
|
1737
|
+
* @see {@link has} for checking key existence without retrieving the value.
|
|
1738
|
+
*/
|
|
1739
|
+
const lookup$1 = (key) => (dict) => {
|
|
1740
|
+
const val = dict.get(key);
|
|
1741
|
+
return val !== void 0 || dict.has(key) ? Maybe.make.some(val) : Maybe.make.none();
|
|
1742
|
+
};
|
|
1743
|
+
const size$2 = (dict) => dict.size;
|
|
1744
|
+
/**
|
|
1745
|
+
* Returns all keys of a dictionary.
|
|
1746
|
+
*
|
|
1747
|
+
* @see {@link values} for extracting dictionary values.
|
|
1748
|
+
* @see {@link entries} for extracting key-value pairs.
|
|
1749
|
+
*/
|
|
1750
|
+
const keys$1 = (dict) => Array.from(dict.keys());
|
|
1751
|
+
/**
|
|
1752
|
+
* Returns all values of a dictionary.
|
|
1753
|
+
*
|
|
1754
|
+
* @see {@link keys} for extracting dictionary keys.
|
|
1755
|
+
* @see {@link entries} for extracting key-value pairs.
|
|
1756
|
+
*/
|
|
1757
|
+
const values$1 = (dict) => Array.from(dict.values());
|
|
1758
|
+
/**
|
|
1759
|
+
* Returns all key-value pairs of a dictionary.
|
|
1760
|
+
*
|
|
1761
|
+
* @see {@link keys} for extracting dictionary keys.
|
|
1762
|
+
* @see {@link values} for extracting dictionary values.
|
|
1763
|
+
*/
|
|
1764
|
+
const entries$1 = (dict) => Array.from(dict.entries());
|
|
1765
|
+
/**
|
|
1766
|
+
* Returns a new dictionary with the key set to value.
|
|
1767
|
+
*
|
|
1768
|
+
* @see {@link remove} for deleting a key from a dictionary.
|
|
1769
|
+
* @see {@link upsert} for conditional insertion/update.
|
|
1770
|
+
*/
|
|
1771
|
+
const insert = (key, value) => (dict) => {
|
|
1772
|
+
const res = new globalThis.Map(dict);
|
|
1538
1773
|
res.set(key, value);
|
|
1539
1774
|
return res;
|
|
1540
1775
|
};
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1776
|
+
/**
|
|
1777
|
+
* Returns a new dictionary with the specified key removed.
|
|
1778
|
+
*
|
|
1779
|
+
* @see {@link insert} for adding or replacing a key in a dictionary.
|
|
1780
|
+
*/
|
|
1781
|
+
const remove$1 = (key) => (dict) => {
|
|
1782
|
+
if (!dict.has(key)) return dict;
|
|
1783
|
+
const res = new globalThis.Map(dict);
|
|
1544
1784
|
res.delete(key);
|
|
1545
1785
|
return res;
|
|
1546
1786
|
};
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1787
|
+
/**
|
|
1788
|
+
* Inserts or updates a key using a callback that receives the existing value if present.
|
|
1789
|
+
*
|
|
1790
|
+
* @see {@link insert} for unconditional key setting.
|
|
1791
|
+
*/
|
|
1792
|
+
const upsert = (key, update) => (dict) => {
|
|
1793
|
+
const res = new globalThis.Map(dict);
|
|
1794
|
+
const existing = dict.has(key) ? Maybe.make.some(dict.get(key)) : Maybe.make.none();
|
|
1795
|
+
res.set(key, update(existing));
|
|
1551
1796
|
return res;
|
|
1552
1797
|
};
|
|
1553
|
-
|
|
1798
|
+
/**
|
|
1799
|
+
* Transforms each value in the dictionary.
|
|
1800
|
+
*
|
|
1801
|
+
* @see {@link mapWithKey} for transforming values with key access.
|
|
1802
|
+
*/
|
|
1803
|
+
const map$2 = (transform) => (dict) => {
|
|
1554
1804
|
const res = new globalThis.Map();
|
|
1555
|
-
for (const [k, v] of
|
|
1805
|
+
for (const [k, v] of dict) res.set(k, transform(v));
|
|
1556
1806
|
return res;
|
|
1557
1807
|
};
|
|
1558
|
-
|
|
1808
|
+
/**
|
|
1809
|
+
* Transforms each value in the dictionary, also receiving the key.
|
|
1810
|
+
*
|
|
1811
|
+
* @see {@link map} for transforming values without key access.
|
|
1812
|
+
*/
|
|
1813
|
+
const mapWithKey$1 = (transform) => (dict) => {
|
|
1559
1814
|
const res = new globalThis.Map();
|
|
1560
|
-
for (const [k, v] of
|
|
1815
|
+
for (const [k, v] of dict) res.set(k, transform(k, v));
|
|
1561
1816
|
return res;
|
|
1562
1817
|
};
|
|
1563
|
-
|
|
1818
|
+
/**
|
|
1819
|
+
* Filters dictionary entries by a predicate on values.
|
|
1820
|
+
*
|
|
1821
|
+
* @see {@link filterWithKey} for filtering with key access.
|
|
1822
|
+
*/
|
|
1823
|
+
const filter$2 = (predicate) => (dict) => {
|
|
1564
1824
|
const res = new globalThis.Map();
|
|
1565
|
-
for (const [k, v] of
|
|
1825
|
+
for (const [k, v] of dict) if (predicate(v)) res.set(k, v);
|
|
1566
1826
|
return res;
|
|
1567
1827
|
};
|
|
1568
|
-
|
|
1828
|
+
/**
|
|
1829
|
+
* Filters dictionary entries by a predicate that also receives the key.
|
|
1830
|
+
*
|
|
1831
|
+
* @see {@link filter} for filtering values without key access.
|
|
1832
|
+
*/
|
|
1833
|
+
const filterWithKey$1 = (predicate) => (dict) => {
|
|
1569
1834
|
const res = new globalThis.Map();
|
|
1570
|
-
for (const [k, v] of
|
|
1835
|
+
for (const [k, v] of dict) if (predicate(k, v)) res.set(k, v);
|
|
1571
1836
|
return res;
|
|
1572
1837
|
};
|
|
1573
|
-
|
|
1838
|
+
/**
|
|
1839
|
+
* Removes all `None` values from a dictionary, unwrapping `Some` values.
|
|
1840
|
+
*/
|
|
1841
|
+
const compact$1 = (dict) => {
|
|
1574
1842
|
const res = new globalThis.Map();
|
|
1575
|
-
for (const [k, v] of
|
|
1843
|
+
for (const [k, v] of dict) if (v.kind === "Some") res.set(k, v.value);
|
|
1576
1844
|
return res;
|
|
1577
1845
|
};
|
|
1578
|
-
|
|
1846
|
+
/**
|
|
1847
|
+
* Transforms values with a function returning `Maybe`, keeping only `Some` values.
|
|
1848
|
+
*
|
|
1849
|
+
* @see {@link filter} for filtering without transformation.
|
|
1850
|
+
*/
|
|
1851
|
+
const filterMap$2 = (transform) => (dict) => {
|
|
1579
1852
|
const res = new globalThis.Map();
|
|
1580
|
-
for (const [k, v] of
|
|
1581
|
-
const mb =
|
|
1853
|
+
for (const [k, v] of dict) {
|
|
1854
|
+
const mb = transform(v);
|
|
1582
1855
|
if (mb.kind === "Some") res.set(k, mb.value);
|
|
1583
1856
|
}
|
|
1584
1857
|
return res;
|
|
1585
1858
|
};
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1859
|
+
/**
|
|
1860
|
+
* Combines two dictionaries, preferring entries from `other` on key collisions.
|
|
1861
|
+
*
|
|
1862
|
+
* @see {@link intersection} for keeping only common keys.
|
|
1863
|
+
* @see {@link difference} for removing keys present in the other dictionary.
|
|
1864
|
+
*/
|
|
1865
|
+
const union$1 = (other) => (dict) => {
|
|
1866
|
+
if (dict.size === 0) return other;
|
|
1867
|
+
if (other.size === 0) return dict;
|
|
1868
|
+
const res = new globalThis.Map(dict);
|
|
1590
1869
|
for (const [k, v] of other) res.set(k, v);
|
|
1591
1870
|
return res;
|
|
1592
1871
|
};
|
|
1593
|
-
|
|
1872
|
+
/**
|
|
1873
|
+
* Returns a new dictionary containing only keys present in both dictionaries.
|
|
1874
|
+
*
|
|
1875
|
+
* @see {@link union} for combining all keys from both dictionaries.
|
|
1876
|
+
* @see {@link difference} for subtracting keys.
|
|
1877
|
+
*/
|
|
1878
|
+
const intersection$1 = (other) => (dict) => {
|
|
1594
1879
|
const res = new globalThis.Map();
|
|
1595
|
-
for (const [k, v] of
|
|
1880
|
+
for (const [k, v] of dict) if (other.has(k)) res.set(k, v);
|
|
1596
1881
|
return res;
|
|
1597
1882
|
};
|
|
1598
|
-
|
|
1599
|
-
|
|
1883
|
+
/**
|
|
1884
|
+
* Returns a new dictionary containing keys from `dict` that are not in `other`.
|
|
1885
|
+
*
|
|
1886
|
+
* @see {@link union} for combining all keys.
|
|
1887
|
+
* @see {@link intersection} for keeping only common keys.
|
|
1888
|
+
*/
|
|
1889
|
+
const difference$1 = (other) => (dict) => {
|
|
1890
|
+
if (other.size === 0) return dict;
|
|
1600
1891
|
const res = new globalThis.Map();
|
|
1601
|
-
for (const [k, v] of
|
|
1892
|
+
for (const [k, v] of dict) if (!other.has(k)) res.set(k, v);
|
|
1602
1893
|
return res;
|
|
1603
1894
|
};
|
|
1604
|
-
const reduce$1 = (
|
|
1605
|
-
let acc =
|
|
1606
|
-
for (const [, v] of
|
|
1895
|
+
const reduce$1 = (initial, reducer) => (dict) => {
|
|
1896
|
+
let acc = initial;
|
|
1897
|
+
for (const [, v] of dict) acc = reducer(acc, v);
|
|
1607
1898
|
return acc;
|
|
1608
1899
|
};
|
|
1609
|
-
const reduceWithKey = (
|
|
1610
|
-
let acc =
|
|
1611
|
-
for (const [k, v] of
|
|
1900
|
+
const reduceWithKey = (initial, reducer) => (dict) => {
|
|
1901
|
+
let acc = initial;
|
|
1902
|
+
for (const [k, v] of dict) acc = reducer(acc, v, k);
|
|
1612
1903
|
return acc;
|
|
1613
1904
|
};
|
|
1905
|
+
/**
|
|
1906
|
+
* Merges two dictionaries using a combination function on collisions.
|
|
1907
|
+
*/
|
|
1614
1908
|
function mergeWith$1(combine) {
|
|
1615
1909
|
return ((arg1, arg2) => {
|
|
1616
1910
|
if (arg2 !== void 0) {
|
|
@@ -1628,27 +1922,27 @@ function mergeWith$1(combine) {
|
|
|
1628
1922
|
};
|
|
1629
1923
|
});
|
|
1630
1924
|
}
|
|
1631
|
-
const mapEntries$1 = (
|
|
1925
|
+
const mapEntries$1 = (transform) => (dict) => {
|
|
1632
1926
|
const res = new globalThis.Map();
|
|
1633
|
-
for (const [k, v] of
|
|
1634
|
-
const [nk, nv] =
|
|
1927
|
+
for (const [k, v] of dict) {
|
|
1928
|
+
const [nk, nv] = transform(k, v);
|
|
1635
1929
|
res.set(nk, nv);
|
|
1636
1930
|
}
|
|
1637
1931
|
return res;
|
|
1638
1932
|
};
|
|
1639
|
-
const mapKeys$1 = (
|
|
1933
|
+
const mapKeys$1 = (transform) => (dict) => {
|
|
1640
1934
|
const res = new globalThis.Map();
|
|
1641
|
-
for (const [k, v] of
|
|
1935
|
+
for (const [k, v] of dict) res.set(transform(k), v);
|
|
1642
1936
|
return res;
|
|
1643
1937
|
};
|
|
1644
1938
|
const _nonEmptySingleton = (key, value) => new globalThis.Map([[key, value]]);
|
|
1645
|
-
const _nonEmptyFromMap = (
|
|
1646
|
-
const _nonEmptyKeys = (
|
|
1647
|
-
const _nonEmptyValues = (
|
|
1648
|
-
const _nonEmptyEntries = (
|
|
1649
|
-
const _nonEmptyReduce = (
|
|
1650
|
-
const _nonEmptyMap = (
|
|
1651
|
-
const _nonEmptyMapWithKey = (
|
|
1939
|
+
const _nonEmptyFromMap = (dict) => dict.size > 0 ? Maybe.make.some(dict) : Maybe.make.none();
|
|
1940
|
+
const _nonEmptyKeys = (dict) => keys$1(dict);
|
|
1941
|
+
const _nonEmptyValues = (dict) => values$1(dict);
|
|
1942
|
+
const _nonEmptyEntries = (dict) => entries$1(dict);
|
|
1943
|
+
const _nonEmptyReduce = (reducer) => (dict) => _nonEmptyValues(dict).reduce(reducer);
|
|
1944
|
+
const _nonEmptyMap = (transform) => (dict) => map$2(transform)(dict);
|
|
1945
|
+
const _nonEmptyMapWithKey = (transform) => (dict) => mapWithKey$1(transform)(dict);
|
|
1652
1946
|
const Dict = {
|
|
1653
1947
|
is: DictIs,
|
|
1654
1948
|
empty: empty$1,
|
|
@@ -1681,7 +1975,7 @@ const Dict = {
|
|
|
1681
1975
|
mapKeys: mapKeys$1,
|
|
1682
1976
|
NonEmpty: {
|
|
1683
1977
|
singleton: _nonEmptySingleton,
|
|
1684
|
-
from: {
|
|
1978
|
+
from: { map: _nonEmptyFromMap },
|
|
1685
1979
|
keys: _nonEmptyKeys,
|
|
1686
1980
|
values: _nonEmptyValues,
|
|
1687
1981
|
entries: _nonEmptyEntries,
|
|
@@ -1734,9 +2028,9 @@ const Json = {
|
|
|
1734
2028
|
};
|
|
1735
2029
|
//#endregion
|
|
1736
2030
|
//#region src/Data/Num.ts
|
|
1737
|
-
const sumFn = (
|
|
2031
|
+
const sumFn = (numbers) => {
|
|
1738
2032
|
let result = 0;
|
|
1739
|
-
for (let i = 0; i <
|
|
2033
|
+
for (let i = 0; i < numbers.length; i++) result += numbers[i];
|
|
1740
2034
|
return result;
|
|
1741
2035
|
};
|
|
1742
2036
|
const Num = {
|
|
@@ -1750,27 +2044,31 @@ const Num = {
|
|
|
1750
2044
|
* Num.is.zero(5); // false
|
|
1751
2045
|
* ```
|
|
1752
2046
|
*/
|
|
1753
|
-
zero: (
|
|
2047
|
+
zero: (value) => value === 0,
|
|
1754
2048
|
/**
|
|
1755
2049
|
* Returns `true` when the number is a whole integer.
|
|
1756
2050
|
*
|
|
2051
|
+
* @see {@link Num.is.float} to check for fractional numbers.
|
|
2052
|
+
*
|
|
1757
2053
|
* @example
|
|
1758
2054
|
* ```ts
|
|
1759
2055
|
* Num.is.integer(5); // true
|
|
1760
2056
|
* Num.is.integer(3.14); // false
|
|
1761
2057
|
* ```
|
|
1762
2058
|
*/
|
|
1763
|
-
integer: (
|
|
2059
|
+
integer: (value) => Number.isInteger(value),
|
|
1764
2060
|
/**
|
|
1765
2061
|
* Returns `true` when the number is a finite float (fractional number).
|
|
1766
2062
|
*
|
|
2063
|
+
* @see {@link Num.is.integer} to check for whole numbers.
|
|
2064
|
+
*
|
|
1767
2065
|
* @example
|
|
1768
2066
|
* ```ts
|
|
1769
2067
|
* Num.is.float(3.14); // true
|
|
1770
2068
|
* Num.is.float(5); // false
|
|
1771
2069
|
* ```
|
|
1772
2070
|
*/
|
|
1773
|
-
float: (
|
|
2071
|
+
float: (value) => Number.isFinite(value) && !Number.isInteger(value),
|
|
1774
2072
|
/**
|
|
1775
2073
|
* Returns `true` when the number is finite (not `Infinity`, `-Infinity`, or `NaN`).
|
|
1776
2074
|
*
|
|
@@ -1780,7 +2078,7 @@ const Num = {
|
|
|
1780
2078
|
* Num.is.finite(Infinity); // false
|
|
1781
2079
|
* ```
|
|
1782
2080
|
*/
|
|
1783
|
-
finite: (
|
|
2081
|
+
finite: (value) => Number.isFinite(value),
|
|
1784
2082
|
/**
|
|
1785
2083
|
* Returns `true` when the value is `NaN`.
|
|
1786
2084
|
*
|
|
@@ -1790,10 +2088,12 @@ const Num = {
|
|
|
1790
2088
|
* Num.is.nan(42); // false
|
|
1791
2089
|
* ```
|
|
1792
2090
|
*/
|
|
1793
|
-
nan: (
|
|
2091
|
+
nan: (value) => Number.isNaN(value),
|
|
1794
2092
|
/**
|
|
1795
2093
|
* Returns `true` when the number is an even integer.
|
|
1796
2094
|
*
|
|
2095
|
+
* @see {@link Num.is.odd} to check if a number is odd.
|
|
2096
|
+
*
|
|
1797
2097
|
* @example
|
|
1798
2098
|
* ```ts
|
|
1799
2099
|
* Num.is.even(4); // true
|
|
@@ -1801,10 +2101,12 @@ const Num = {
|
|
|
1801
2101
|
* Num.is.even(2.5); // false
|
|
1802
2102
|
* ```
|
|
1803
2103
|
*/
|
|
1804
|
-
even: (
|
|
2104
|
+
even: (value) => Number.isInteger(value) && value % 2 === 0,
|
|
1805
2105
|
/**
|
|
1806
2106
|
* Returns `true` when the number is an odd integer.
|
|
1807
2107
|
*
|
|
2108
|
+
* @see {@link Num.is.even} to check if a number is even.
|
|
2109
|
+
*
|
|
1808
2110
|
* @example
|
|
1809
2111
|
* ```ts
|
|
1810
2112
|
* Num.is.odd(3); // true
|
|
@@ -1812,10 +2114,12 @@ const Num = {
|
|
|
1812
2114
|
* Num.is.odd(2.5); // false
|
|
1813
2115
|
* ```
|
|
1814
2116
|
*/
|
|
1815
|
-
odd: (
|
|
2117
|
+
odd: (value) => Number.isInteger(value) && value % 2 !== 0,
|
|
1816
2118
|
/**
|
|
1817
2119
|
* Returns `true` when the number is strictly greater than zero.
|
|
1818
2120
|
*
|
|
2121
|
+
* @see {@link Num.is.negative} to check if a number is less than zero.
|
|
2122
|
+
*
|
|
1819
2123
|
* @example
|
|
1820
2124
|
* ```ts
|
|
1821
2125
|
* Num.is.positive(5); // true
|
|
@@ -1823,10 +2127,12 @@ const Num = {
|
|
|
1823
2127
|
* Num.is.positive(-5); // false
|
|
1824
2128
|
* ```
|
|
1825
2129
|
*/
|
|
1826
|
-
positive: (
|
|
2130
|
+
positive: (value) => value > 0,
|
|
1827
2131
|
/**
|
|
1828
2132
|
* Returns `true` when the number is strictly less than zero.
|
|
1829
2133
|
*
|
|
2134
|
+
* @see {@link Num.is.positive} to check if a number is greater than zero.
|
|
2135
|
+
*
|
|
1830
2136
|
* @example
|
|
1831
2137
|
* ```ts
|
|
1832
2138
|
* Num.is.negative(-5); // true
|
|
@@ -1834,7 +2140,7 @@ const Num = {
|
|
|
1834
2140
|
* Num.is.negative(5); // false
|
|
1835
2141
|
* ```
|
|
1836
2142
|
*/
|
|
1837
|
-
negative: (
|
|
2143
|
+
negative: (value) => value < 0
|
|
1838
2144
|
},
|
|
1839
2145
|
/**
|
|
1840
2146
|
* Generates an array of numbers from `from` to `to` (both inclusive),
|
|
@@ -1868,10 +2174,12 @@ const Num = {
|
|
|
1868
2174
|
* pipe(42, Num.clamp(0, 100)); // 42
|
|
1869
2175
|
* ```
|
|
1870
2176
|
*/
|
|
1871
|
-
clamp: (min, max) => (
|
|
2177
|
+
clamp: (min, max) => (value) => Math.min(Math.max(value, min), max),
|
|
1872
2178
|
/**
|
|
1873
2179
|
* Returns `true` when the number is between `min` and `max` (both inclusive).
|
|
1874
2180
|
*
|
|
2181
|
+
* @see {@link Num.inRange} for half-open range checking [start, end).
|
|
2182
|
+
*
|
|
1875
2183
|
* @example
|
|
1876
2184
|
* ```ts
|
|
1877
2185
|
* pipe(5, Num.between(1, 10)); // true
|
|
@@ -1879,10 +2187,12 @@ const Num = {
|
|
|
1879
2187
|
* pipe(10, Num.between(1, 10)); // true
|
|
1880
2188
|
* ```
|
|
1881
2189
|
*/
|
|
1882
|
-
between: (min, max) => (
|
|
2190
|
+
between: (min, max) => (value) => value >= min && value <= max,
|
|
1883
2191
|
/**
|
|
1884
2192
|
* Returns `true` when the number is in the range `[start, end)` (inclusive of `start`, exclusive of `end`).
|
|
1885
2193
|
*
|
|
2194
|
+
* @see {@link Num.between} for fully closed range checking [min, max].
|
|
2195
|
+
*
|
|
1886
2196
|
* @example
|
|
1887
2197
|
* ```ts
|
|
1888
2198
|
* pipe(5, Num.inRange(1, 10)); // true
|
|
@@ -1890,7 +2200,7 @@ const Num = {
|
|
|
1890
2200
|
* pipe(10, Num.inRange(1, 10)); // false
|
|
1891
2201
|
* ```
|
|
1892
2202
|
*/
|
|
1893
|
-
inRange: (start, end) => (
|
|
2203
|
+
inRange: (start, end) => (value) => value >= start && value < end,
|
|
1894
2204
|
/**
|
|
1895
2205
|
* Parses a string as a number. Returns `None` when the result is `NaN`.
|
|
1896
2206
|
*
|
|
@@ -1902,13 +2212,15 @@ const Num = {
|
|
|
1902
2212
|
* Num.parse(""); // None
|
|
1903
2213
|
* ```
|
|
1904
2214
|
*/
|
|
1905
|
-
parse: (
|
|
1906
|
-
if (
|
|
1907
|
-
const n = Number(
|
|
2215
|
+
parse: (text) => {
|
|
2216
|
+
if (text.trim() === "") return Maybe.make.none();
|
|
2217
|
+
const n = Number(text);
|
|
1908
2218
|
return isNaN(n) ? Maybe.make.none() : Maybe.make.some(n);
|
|
1909
2219
|
},
|
|
1910
2220
|
/**
|
|
1911
|
-
* Adds `
|
|
2221
|
+
* Adds `amount` to a number. Data-last: use in `pipe` or `Arr.map`.
|
|
2222
|
+
*
|
|
2223
|
+
* @see {@link Num.subtract} to subtract an amount from a number.
|
|
1912
2224
|
*
|
|
1913
2225
|
* @example
|
|
1914
2226
|
* ```ts
|
|
@@ -1916,9 +2228,11 @@ const Num = {
|
|
|
1916
2228
|
* pipe([1, 2, 3], Arr.map(Num.add(10))); // [11, 12, 13]
|
|
1917
2229
|
* ```
|
|
1918
2230
|
*/
|
|
1919
|
-
add: (
|
|
2231
|
+
add: (amount) => (value) => value + amount,
|
|
1920
2232
|
/**
|
|
1921
|
-
* Subtracts `
|
|
2233
|
+
* Subtracts `amount` from a number. Data-last: `subtract(amount)(from)` = `from - amount`.
|
|
2234
|
+
*
|
|
2235
|
+
* @see {@link Num.add} to add an amount to a number.
|
|
1922
2236
|
*
|
|
1923
2237
|
* @example
|
|
1924
2238
|
* ```ts
|
|
@@ -1926,9 +2240,11 @@ const Num = {
|
|
|
1926
2240
|
* pipe([5, 10, 15], Arr.map(Num.subtract(2))); // [3, 8, 13]
|
|
1927
2241
|
* ```
|
|
1928
2242
|
*/
|
|
1929
|
-
subtract: (
|
|
2243
|
+
subtract: (amount) => (from) => from - amount,
|
|
1930
2244
|
/**
|
|
1931
|
-
* Multiplies a number by `
|
|
2245
|
+
* Multiplies a number by `factor`. Data-last: use in `pipe` or `Arr.map`.
|
|
2246
|
+
*
|
|
2247
|
+
* @see {@link Num.divide} to divide a number by a divisor.
|
|
1932
2248
|
*
|
|
1933
2249
|
* @example
|
|
1934
2250
|
* ```ts
|
|
@@ -1936,9 +2252,12 @@ const Num = {
|
|
|
1936
2252
|
* pipe([1, 2, 3], Arr.map(Num.multiply(100))); // [100, 200, 300]
|
|
1937
2253
|
* ```
|
|
1938
2254
|
*/
|
|
1939
|
-
multiply: (
|
|
2255
|
+
multiply: (factor) => (value) => value * factor,
|
|
1940
2256
|
/**
|
|
1941
|
-
* Divides a number by `
|
|
2257
|
+
* Divides a number by `divisor`. Returns `None` when `divisor` is zero. Data-last: `divide(divisor)(dividend)` = `dividend / divisor`.
|
|
2258
|
+
*
|
|
2259
|
+
* @see {@link Num.multiply} to multiply a number by a factor.
|
|
2260
|
+
* @see {@link Num.remainder} to compute the division remainder.
|
|
1942
2261
|
*
|
|
1943
2262
|
* @example
|
|
1944
2263
|
* ```ts
|
|
@@ -1947,7 +2266,7 @@ const Num = {
|
|
|
1947
2266
|
* pipe([10, 20, 30], Arr.filterMap(Num.divide(10))); // [1, 2, 3]
|
|
1948
2267
|
* ```
|
|
1949
2268
|
*/
|
|
1950
|
-
divide: (
|
|
2269
|
+
divide: (divisor) => (dividend) => divisor === 0 ? Maybe.make.none() : Maybe.make.some(dividend / divisor),
|
|
1951
2270
|
/**
|
|
1952
2271
|
* Returns the absolute value of a number.
|
|
1953
2272
|
*
|
|
@@ -1957,7 +2276,7 @@ const Num = {
|
|
|
1957
2276
|
* pipe(5, Num.abs); // 5
|
|
1958
2277
|
* ```
|
|
1959
2278
|
*/
|
|
1960
|
-
abs: (
|
|
2279
|
+
abs: (value) => Math.abs(value),
|
|
1961
2280
|
/**
|
|
1962
2281
|
* Negates a number (arithmetic negation).
|
|
1963
2282
|
*
|
|
@@ -1967,40 +2286,51 @@ const Num = {
|
|
|
1967
2286
|
* pipe(-5, Num.negate); // 5
|
|
1968
2287
|
* ```
|
|
1969
2288
|
*/
|
|
1970
|
-
negate: (
|
|
2289
|
+
negate: (value) => -value,
|
|
1971
2290
|
/**
|
|
1972
2291
|
* Rounds a number to the nearest integer.
|
|
1973
2292
|
*
|
|
2293
|
+
* @see {@link Num.floor} to round down.
|
|
2294
|
+
* @see {@link Num.ceil} to round up.
|
|
2295
|
+
*
|
|
1974
2296
|
* @example
|
|
1975
2297
|
* ```ts
|
|
1976
2298
|
* pipe(3.5, Num.round); // 4
|
|
1977
2299
|
* pipe(3.4, Num.round); // 3
|
|
1978
2300
|
* ```
|
|
1979
2301
|
*/
|
|
1980
|
-
round: (
|
|
2302
|
+
round: (value) => Math.round(value),
|
|
1981
2303
|
/**
|
|
1982
2304
|
* Rounds a number down to the nearest integer.
|
|
1983
2305
|
*
|
|
2306
|
+
* @see {@link Num.round} to round to nearest integer.
|
|
2307
|
+
* @see {@link Num.ceil} to round up.
|
|
2308
|
+
*
|
|
1984
2309
|
* @example
|
|
1985
2310
|
* ```ts
|
|
1986
2311
|
* pipe(3.9, Num.floor); // 3
|
|
1987
2312
|
* pipe(-3.2, Num.floor); // -4
|
|
1988
2313
|
* ```
|
|
1989
2314
|
*/
|
|
1990
|
-
floor: (
|
|
2315
|
+
floor: (value) => Math.floor(value),
|
|
1991
2316
|
/**
|
|
1992
2317
|
* Rounds a number up to the nearest integer.
|
|
1993
2318
|
*
|
|
2319
|
+
* @see {@link Num.round} to round to nearest integer.
|
|
2320
|
+
* @see {@link Num.floor} to round down.
|
|
2321
|
+
*
|
|
1994
2322
|
* @example
|
|
1995
2323
|
* ```ts
|
|
1996
2324
|
* pipe(3.1, Num.ceil); // 4
|
|
1997
2325
|
* pipe(-3.9, Num.ceil); // -3
|
|
1998
2326
|
* ```
|
|
1999
2327
|
*/
|
|
2000
|
-
ceil: (
|
|
2328
|
+
ceil: (value) => Math.ceil(value),
|
|
2001
2329
|
/**
|
|
2002
2330
|
* Returns the remainder of dividing a number by `divisor`. Returns `None` when `divisor` is zero.
|
|
2003
|
-
* Data-last: `remainder(divisor)(
|
|
2331
|
+
* Data-last: `remainder(divisor)(dividend)` = `dividend % divisor`.
|
|
2332
|
+
*
|
|
2333
|
+
* @see {@link Num.divide} for full division.
|
|
2004
2334
|
*
|
|
2005
2335
|
* @example
|
|
2006
2336
|
* ```ts
|
|
@@ -2009,7 +2339,7 @@ const Num = {
|
|
|
2009
2339
|
* pipe([10, 11, 12], Arr.filterMap(Num.remainder(3))); // [1, 2, 0]
|
|
2010
2340
|
* ```
|
|
2011
2341
|
*/
|
|
2012
|
-
remainder: (divisor) => (
|
|
2342
|
+
remainder: (divisor) => (dividend) => divisor === 0 ? Maybe.make.none() : Maybe.make.some(dividend % divisor),
|
|
2013
2343
|
/**
|
|
2014
2344
|
* Computes the sum of a list of numbers. Returns `0` if the list is empty.
|
|
2015
2345
|
*
|
|
@@ -2029,39 +2359,43 @@ const Num = {
|
|
|
2029
2359
|
* Num.mean([]); // None
|
|
2030
2360
|
* ```
|
|
2031
2361
|
*/
|
|
2032
|
-
mean: (
|
|
2362
|
+
mean: (numbers) => numbers.length === 0 ? Maybe.make.none() : Maybe.make.some(sumFn(numbers) / numbers.length),
|
|
2033
2363
|
/**
|
|
2034
2364
|
* Computes the minimum of a list of numbers. Returns `None` if the list is empty.
|
|
2035
2365
|
*
|
|
2366
|
+
* @see {@link Num.max} to compute the maximum value.
|
|
2367
|
+
*
|
|
2036
2368
|
* @example
|
|
2037
2369
|
* ```ts
|
|
2038
2370
|
* Num.min([5, 1, 3]); // Some(1)
|
|
2039
2371
|
* Num.min([]); // None
|
|
2040
2372
|
* ```
|
|
2041
2373
|
*/
|
|
2042
|
-
min: (
|
|
2043
|
-
if (
|
|
2044
|
-
let [result] =
|
|
2045
|
-
for (let i = 1; i <
|
|
2374
|
+
min: (numbers) => {
|
|
2375
|
+
if (numbers.length === 0) return Maybe.make.none();
|
|
2376
|
+
let [result] = numbers;
|
|
2377
|
+
for (let i = 1; i < numbers.length; i++) if (numbers[i] < result) result = numbers[i];
|
|
2046
2378
|
return Maybe.make.some(result);
|
|
2047
2379
|
},
|
|
2048
2380
|
/**
|
|
2049
2381
|
* Computes the maximum of a list of numbers. Returns `None` if the list is empty.
|
|
2050
2382
|
*
|
|
2383
|
+
* @see {@link Num.min} to compute the minimum value.
|
|
2384
|
+
*
|
|
2051
2385
|
* @example
|
|
2052
2386
|
* ```ts
|
|
2053
2387
|
* Num.max([1, 5, 3]); // Some(5)
|
|
2054
2388
|
* Num.max([]); // None
|
|
2055
2389
|
* ```
|
|
2056
2390
|
*/
|
|
2057
|
-
max: (
|
|
2058
|
-
if (
|
|
2059
|
-
let [result] =
|
|
2060
|
-
for (let i = 1; i <
|
|
2391
|
+
max: (numbers) => {
|
|
2392
|
+
if (numbers.length === 0) return Maybe.make.none();
|
|
2393
|
+
let [result] = numbers;
|
|
2394
|
+
for (let i = 1; i < numbers.length; i++) if (numbers[i] > result) result = numbers[i];
|
|
2061
2395
|
return Maybe.make.some(result);
|
|
2062
2396
|
},
|
|
2063
2397
|
/**
|
|
2064
|
-
* Formats a number using `Intl.NumberFormat`. Returns `None` when `
|
|
2398
|
+
* Formats a number using `Intl.NumberFormat`. Returns `None` when `value` is `NaN` or non-finite.
|
|
2065
2399
|
* Data-last curried signature.
|
|
2066
2400
|
*
|
|
2067
2401
|
* @example
|
|
@@ -2071,11 +2405,11 @@ const Num = {
|
|
|
2071
2405
|
* pipe(NaN, formatCurrency); // None
|
|
2072
2406
|
* ```
|
|
2073
2407
|
*/
|
|
2074
|
-
format: (options, locales) => (
|
|
2408
|
+
format: (options, locales) => (value) => !Number.isFinite(value) ? Maybe.make.none() : Maybe.make.some(new Intl.NumberFormat(locales, options).format(value))
|
|
2075
2409
|
};
|
|
2076
2410
|
//#endregion
|
|
2077
2411
|
//#region src/Data/Rec.ts
|
|
2078
|
-
const _isNonEmpty = (
|
|
2412
|
+
const _isNonEmpty = (record) => Object.keys(record).length > 0;
|
|
2079
2413
|
const _setKey = (record, key, value) => {
|
|
2080
2414
|
if (key === "__proto__") Object.defineProperty(record, key, {
|
|
2081
2415
|
value,
|
|
@@ -2087,8 +2421,8 @@ const _setKey = (record, key, value) => {
|
|
|
2087
2421
|
};
|
|
2088
2422
|
let RecMaybe;
|
|
2089
2423
|
(function(_RecMaybe) {
|
|
2090
|
-
const traverse = _RecMaybe.traverse = (
|
|
2091
|
-
const recordKeys = Object.keys(
|
|
2424
|
+
const traverse = _RecMaybe.traverse = (transform) => (record) => {
|
|
2425
|
+
const recordKeys = Object.keys(record);
|
|
2092
2426
|
if (recordKeys.length === 0) return {
|
|
2093
2427
|
kind: "Some",
|
|
2094
2428
|
value: {}
|
|
@@ -2096,7 +2430,7 @@ let RecMaybe;
|
|
|
2096
2430
|
const result = {};
|
|
2097
2431
|
for (let i = 0; i < recordKeys.length; i++) {
|
|
2098
2432
|
const key = recordKeys[i];
|
|
2099
|
-
const maybeVal =
|
|
2433
|
+
const maybeVal = transform(record[key]);
|
|
2100
2434
|
if (maybeVal.kind === "None") return maybeVal;
|
|
2101
2435
|
_setKey(result, key, maybeVal.value);
|
|
2102
2436
|
}
|
|
@@ -2105,16 +2439,16 @@ let RecMaybe;
|
|
|
2105
2439
|
value: result
|
|
2106
2440
|
};
|
|
2107
2441
|
};
|
|
2108
|
-
_RecMaybe.sequence = (
|
|
2442
|
+
_RecMaybe.sequence = (record) => traverse((value) => value)(record);
|
|
2109
2443
|
})(RecMaybe || (RecMaybe = {}));
|
|
2110
2444
|
let RecResult;
|
|
2111
2445
|
(function(_RecResult) {
|
|
2112
|
-
const traverse = _RecResult.traverse = (
|
|
2113
|
-
const recordKeys = Object.keys(
|
|
2446
|
+
const traverse = _RecResult.traverse = (transform) => (record) => {
|
|
2447
|
+
const recordKeys = Object.keys(record);
|
|
2114
2448
|
const result = {};
|
|
2115
2449
|
for (let i = 0; i < recordKeys.length; i++) {
|
|
2116
2450
|
const key = recordKeys[i];
|
|
2117
|
-
const res =
|
|
2451
|
+
const res = transform(record[key]);
|
|
2118
2452
|
if (res.kind === "Err") return res;
|
|
2119
2453
|
_setKey(result, key, res.value);
|
|
2120
2454
|
}
|
|
@@ -2123,7 +2457,7 @@ let RecResult;
|
|
|
2123
2457
|
value: result
|
|
2124
2458
|
};
|
|
2125
2459
|
};
|
|
2126
|
-
_RecResult.sequence = (
|
|
2460
|
+
_RecResult.sequence = (record) => traverse((value) => value)(record);
|
|
2127
2461
|
})(RecResult || (RecResult = {}));
|
|
2128
2462
|
/**
|
|
2129
2463
|
* Functional record/object utilities that compose well with pipe.
|
|
@@ -2145,16 +2479,20 @@ const RecIs = {
|
|
|
2145
2479
|
/**
|
|
2146
2480
|
* Returns true if the record has no keys.
|
|
2147
2481
|
*
|
|
2482
|
+
* @see {@link nonEmpty} for checking if a record has keys.
|
|
2483
|
+
*
|
|
2148
2484
|
* @example
|
|
2149
2485
|
* ```ts
|
|
2150
2486
|
* Rec.is.empty({}); // true
|
|
2151
2487
|
* Rec.is.empty({ a: 1 }); // false
|
|
2152
2488
|
* ```
|
|
2153
2489
|
*/
|
|
2154
|
-
empty: (
|
|
2490
|
+
empty: (record) => Object.keys(record).length === 0,
|
|
2155
2491
|
/**
|
|
2156
2492
|
* Type guard to check if a record is non-empty.
|
|
2157
2493
|
*
|
|
2494
|
+
* @see {@link empty} for checking if a record has no keys.
|
|
2495
|
+
*
|
|
2158
2496
|
* @example
|
|
2159
2497
|
* ```ts
|
|
2160
2498
|
* Rec.is.nonEmpty({ a: 1 }); // true
|
|
@@ -2166,30 +2504,36 @@ const RecIs = {
|
|
|
2166
2504
|
/**
|
|
2167
2505
|
* Transforms each value in a record.
|
|
2168
2506
|
*
|
|
2507
|
+
* @see {@link mapWithKey} for transforming values with key access.
|
|
2508
|
+
* @see {@link mapKeys} for transforming keys while preserving values.
|
|
2509
|
+
* @see {@link mapEntries} for transforming keys and values simultaneously.
|
|
2510
|
+
*
|
|
2169
2511
|
* @example
|
|
2170
2512
|
* ```ts
|
|
2171
2513
|
* pipe({ a: 1, b: 2 }, Rec.map(n => n * 2)); // { a: 2, b: 4 }
|
|
2172
2514
|
* ```
|
|
2173
2515
|
*/
|
|
2174
|
-
const map$1 = (
|
|
2175
|
-
const recordKeys = Object.keys(
|
|
2176
|
-
const recordValues = Object.values(
|
|
2177
|
-
const result = Object.create(Object.getPrototypeOf(
|
|
2516
|
+
const map$1 = (transform) => (record) => {
|
|
2517
|
+
const recordKeys = Object.keys(record);
|
|
2518
|
+
const recordValues = Object.values(record);
|
|
2519
|
+
const result = Object.create(Object.getPrototypeOf(record));
|
|
2178
2520
|
for (let i = 0; i < recordKeys.length; i++) {
|
|
2179
2521
|
const key = recordKeys[i];
|
|
2180
2522
|
if (key === "__proto__") Object.defineProperty(result, "__proto__", {
|
|
2181
|
-
value:
|
|
2523
|
+
value: transform(recordValues[i]),
|
|
2182
2524
|
writable: true,
|
|
2183
2525
|
enumerable: true,
|
|
2184
2526
|
configurable: true
|
|
2185
2527
|
});
|
|
2186
|
-
else result[key] =
|
|
2528
|
+
else result[key] = transform(recordValues[i]);
|
|
2187
2529
|
}
|
|
2188
2530
|
return result;
|
|
2189
2531
|
};
|
|
2190
2532
|
/**
|
|
2191
2533
|
* Maps each value in a record with a function returning a `Maybe`, keeping only `Some` values.
|
|
2192
2534
|
*
|
|
2535
|
+
* @see {@link filter} for filtering with a boolean predicate.
|
|
2536
|
+
*
|
|
2193
2537
|
* @example
|
|
2194
2538
|
* ```ts
|
|
2195
2539
|
* pipe(
|
|
@@ -2198,12 +2542,12 @@ const map$1 = (f) => (data) => {
|
|
|
2198
2542
|
* ); // { b: 20 }
|
|
2199
2543
|
* ```
|
|
2200
2544
|
*/
|
|
2201
|
-
const filterMap$1 = (
|
|
2202
|
-
const recordKeys = Object.keys(
|
|
2203
|
-
const recordValues = Object.values(
|
|
2204
|
-
const result = Object.create(Object.getPrototypeOf(
|
|
2545
|
+
const filterMap$1 = (transform) => (record) => {
|
|
2546
|
+
const recordKeys = Object.keys(record);
|
|
2547
|
+
const recordValues = Object.values(record);
|
|
2548
|
+
const result = Object.create(Object.getPrototypeOf(record));
|
|
2205
2549
|
for (let i = 0; i < recordKeys.length; i++) {
|
|
2206
|
-
const maybeVal =
|
|
2550
|
+
const maybeVal = transform(recordValues[i]);
|
|
2207
2551
|
if (maybeVal.kind === "Some") _setKey(result, recordKeys[i], maybeVal.value);
|
|
2208
2552
|
}
|
|
2209
2553
|
return result;
|
|
@@ -2211,49 +2555,56 @@ const filterMap$1 = (f) => (data) => {
|
|
|
2211
2555
|
/**
|
|
2212
2556
|
* Transforms each value in a record, also receiving the key.
|
|
2213
2557
|
*
|
|
2558
|
+
* @see {@link map} for transforming values without key access.
|
|
2559
|
+
*
|
|
2214
2560
|
* @example
|
|
2215
2561
|
* ```ts
|
|
2216
2562
|
* pipe({ a: 1, b: 2 }, Rec.mapWithKey((k, v) => `${k}:${v}`));
|
|
2217
2563
|
* // { a: "a:1", b: "b:2" }
|
|
2218
2564
|
* ```
|
|
2219
2565
|
*/
|
|
2220
|
-
const mapWithKey = (
|
|
2221
|
-
const recordKeys = Object.keys(
|
|
2222
|
-
const recordValues = Object.values(
|
|
2223
|
-
const result = Object.create(Object.getPrototypeOf(
|
|
2566
|
+
const mapWithKey = (transform) => (record) => {
|
|
2567
|
+
const recordKeys = Object.keys(record);
|
|
2568
|
+
const recordValues = Object.values(record);
|
|
2569
|
+
const result = Object.create(Object.getPrototypeOf(record));
|
|
2224
2570
|
for (let i = 0; i < recordKeys.length; i++) {
|
|
2225
2571
|
const key = recordKeys[i];
|
|
2226
|
-
_setKey(result, key,
|
|
2572
|
+
_setKey(result, key, transform(key, recordValues[i]));
|
|
2227
2573
|
}
|
|
2228
2574
|
return result;
|
|
2229
2575
|
};
|
|
2230
2576
|
/**
|
|
2231
2577
|
* Filters values in a record by a predicate.
|
|
2232
2578
|
*
|
|
2579
|
+
* @see {@link filterWithKey} for filtering values with key access.
|
|
2580
|
+
* @see {@link filterMap} for filtering and mapping in a single pass.
|
|
2581
|
+
*
|
|
2233
2582
|
* @example
|
|
2234
2583
|
* ```ts
|
|
2235
2584
|
* pipe({ a: 1, b: 2, c: 3 }, Rec.filter(n => n > 1)); // { b: 2, c: 3 }
|
|
2236
2585
|
* ```
|
|
2237
2586
|
*/
|
|
2238
|
-
const filter$1 = (predicate) => (
|
|
2239
|
-
const recordKeys = Object.keys(
|
|
2240
|
-
const recordValues = Object.values(
|
|
2241
|
-
const result = Object.create(Object.getPrototypeOf(
|
|
2587
|
+
const filter$1 = (predicate) => (record) => {
|
|
2588
|
+
const recordKeys = Object.keys(record);
|
|
2589
|
+
const recordValues = Object.values(record);
|
|
2590
|
+
const result = Object.create(Object.getPrototypeOf(record));
|
|
2242
2591
|
for (let i = 0; i < recordKeys.length; i++) if (predicate(recordValues[i])) _setKey(result, recordKeys[i], recordValues[i]);
|
|
2243
2592
|
return result;
|
|
2244
2593
|
};
|
|
2245
2594
|
/**
|
|
2246
2595
|
* Filters values in a record by a predicate that also receives the key.
|
|
2247
2596
|
*
|
|
2597
|
+
* @see {@link filter} for filtering values without key access.
|
|
2598
|
+
*
|
|
2248
2599
|
* @example
|
|
2249
2600
|
* ```ts
|
|
2250
2601
|
* pipe({ a: 1, b: 2, c: 3 }, Rec.filterWithKey((k, v) => k !== "a" && v > 0));
|
|
2251
2602
|
* // { b: 2 }
|
|
2252
2603
|
* ```
|
|
2253
2604
|
*/
|
|
2254
|
-
const filterWithKey = (predicate) => (
|
|
2605
|
+
const filterWithKey = (predicate) => (record) => {
|
|
2255
2606
|
const result = {};
|
|
2256
|
-
for (const [k, v] of Object.entries(
|
|
2607
|
+
for (const [k, v] of Object.entries(record)) if (predicate(k, v)) _setKey(result, k, v);
|
|
2257
2608
|
return result;
|
|
2258
2609
|
};
|
|
2259
2610
|
/**
|
|
@@ -2265,37 +2616,46 @@ const filterWithKey = (predicate) => (data) => {
|
|
|
2265
2616
|
* pipe({ a: 1, b: 2 }, Rec.lookup("c")); // None
|
|
2266
2617
|
* ```
|
|
2267
2618
|
*/
|
|
2268
|
-
const lookup = (key) => (
|
|
2619
|
+
const lookup = (key) => (record) => Object.hasOwn(record, key) ? {
|
|
2269
2620
|
kind: "Some",
|
|
2270
|
-
value:
|
|
2621
|
+
value: record[key]
|
|
2271
2622
|
} : { kind: "None" };
|
|
2272
2623
|
/**
|
|
2273
2624
|
* Returns all keys of a record.
|
|
2274
2625
|
*
|
|
2626
|
+
* @see {@link values} for extracting record values.
|
|
2627
|
+
* @see {@link entries} for extracting key-value pairs.
|
|
2628
|
+
*
|
|
2275
2629
|
* @example
|
|
2276
2630
|
* ```ts
|
|
2277
2631
|
* Rec.keys({ a: 1, b: 2 }); // ["a", "b"]
|
|
2278
2632
|
* ```
|
|
2279
2633
|
*/
|
|
2280
|
-
const keys = (
|
|
2634
|
+
const keys = (record) => Object.keys(record);
|
|
2281
2635
|
/**
|
|
2282
2636
|
* Returns all values of a record.
|
|
2283
2637
|
*
|
|
2638
|
+
* @see {@link keys} for extracting record keys.
|
|
2639
|
+
* @see {@link entries} for extracting key-value pairs.
|
|
2640
|
+
*
|
|
2284
2641
|
* @example
|
|
2285
2642
|
* ```ts
|
|
2286
2643
|
* Rec.values({ a: 1, b: 2 }); // [1, 2]
|
|
2287
2644
|
* ```
|
|
2288
2645
|
*/
|
|
2289
|
-
const values = (
|
|
2646
|
+
const values = (record) => Object.values(record);
|
|
2290
2647
|
/**
|
|
2291
2648
|
* Returns all key-value pairs of a record.
|
|
2292
2649
|
*
|
|
2650
|
+
* @see {@link keys} for extracting record keys.
|
|
2651
|
+
* @see {@link values} for extracting record values.
|
|
2652
|
+
*
|
|
2293
2653
|
* @example
|
|
2294
2654
|
* ```ts
|
|
2295
2655
|
* Rec.entries({ a: 1, b: 2 }); // [["a", 1], ["b", 2]]
|
|
2296
2656
|
* ```
|
|
2297
2657
|
*/
|
|
2298
|
-
const entries = (
|
|
2658
|
+
const entries = (record) => Object.entries(record);
|
|
2299
2659
|
const RecFrom = {
|
|
2300
2660
|
/**
|
|
2301
2661
|
* Creates a record from key-value pairs.
|
|
@@ -2305,9 +2665,9 @@ const RecFrom = {
|
|
|
2305
2665
|
* Rec.from.entries([["a", 1], ["b", 2]]); // { a: 1, b: 2 }
|
|
2306
2666
|
* ```
|
|
2307
2667
|
*/
|
|
2308
|
-
entries: (
|
|
2668
|
+
entries: (pairs) => Object.fromEntries(pairs) };
|
|
2309
2669
|
/**
|
|
2310
|
-
* Groups elements of an array into a record keyed by the result of `
|
|
2670
|
+
* Groups elements of an array into a record keyed by the result of `keySelector`. Each key maps to
|
|
2311
2671
|
* the array of elements that produced it, in insertion order.
|
|
2312
2672
|
*
|
|
2313
2673
|
* Unlike `Dict.groupBy`, keys are always strings. Use `Dict.groupBy` when you need non-string
|
|
@@ -2321,10 +2681,10 @@ entries: (data) => Object.fromEntries(data) };
|
|
|
2321
2681
|
* ); // { a: ["apple", "avocado"], b: ["banana", "blueberry"] }
|
|
2322
2682
|
* ```
|
|
2323
2683
|
*/
|
|
2324
|
-
const groupBy = (
|
|
2684
|
+
const groupBy = (keySelector) => (items) => {
|
|
2325
2685
|
const result = {};
|
|
2326
2686
|
for (const item of items) {
|
|
2327
|
-
const key =
|
|
2687
|
+
const key = keySelector(item);
|
|
2328
2688
|
if (Object.hasOwn(result, key)) result[key].push(item);
|
|
2329
2689
|
else _setKey(result, key, [item]);
|
|
2330
2690
|
}
|
|
@@ -2333,40 +2693,46 @@ const groupBy = (keyFn) => (items) => {
|
|
|
2333
2693
|
/**
|
|
2334
2694
|
* Picks specific keys from a record.
|
|
2335
2695
|
*
|
|
2696
|
+
* @see {@link omit} for removing specific keys from a record.
|
|
2697
|
+
*
|
|
2336
2698
|
* @example
|
|
2337
2699
|
* ```ts
|
|
2338
2700
|
* pipe({ a: 1, b: 2, c: 3 }, Rec.pick("a", "c")); // { a: 1, c: 3 }
|
|
2339
2701
|
* ```
|
|
2340
2702
|
*/
|
|
2341
|
-
const pick = (...pickedKeys) => (
|
|
2703
|
+
const pick = (...pickedKeys) => (record) => {
|
|
2342
2704
|
const result = {};
|
|
2343
|
-
for (const key of pickedKeys) if (Object.hasOwn(
|
|
2705
|
+
for (const key of pickedKeys) if (Object.hasOwn(record, key)) _setKey(result, key, record[key]);
|
|
2344
2706
|
return result;
|
|
2345
2707
|
};
|
|
2346
2708
|
/**
|
|
2347
2709
|
* Omits specific keys from a record.
|
|
2348
2710
|
*
|
|
2711
|
+
* @see {@link pick} for retaining only specific keys from a record.
|
|
2712
|
+
*
|
|
2349
2713
|
* @example
|
|
2350
2714
|
* ```ts
|
|
2351
2715
|
* pipe({ a: 1, b: 2, c: 3 }, Rec.omit("b")); // { a: 1, c: 3 }
|
|
2352
2716
|
* ```
|
|
2353
2717
|
*/
|
|
2354
|
-
const omit = (...omittedKeys) => (
|
|
2718
|
+
const omit = (...omittedKeys) => (record) => {
|
|
2355
2719
|
const omitSet = new Set(omittedKeys);
|
|
2356
2720
|
const result = {};
|
|
2357
|
-
for (const key of Object.keys(
|
|
2721
|
+
for (const key of Object.keys(record)) if (!omitSet.has(key)) _setKey(result, key, record[key]);
|
|
2358
2722
|
return result;
|
|
2359
2723
|
};
|
|
2360
2724
|
/**
|
|
2361
2725
|
* Merges two records. Values from the second record take precedence.
|
|
2362
2726
|
*
|
|
2727
|
+
* @see {@link mergeWith} for merging records with custom collision resolution.
|
|
2728
|
+
*
|
|
2363
2729
|
* @example
|
|
2364
2730
|
* ```ts
|
|
2365
2731
|
* pipe({ a: 1, b: 2 }, Rec.merge({ b: 3, c: 4 })); // { a: 1, b: 3, c: 4 }
|
|
2366
2732
|
* ```
|
|
2367
2733
|
*/
|
|
2368
|
-
const merge = (other) => (
|
|
2369
|
-
...
|
|
2734
|
+
const merge = (other) => (record) => ({
|
|
2735
|
+
...record,
|
|
2370
2736
|
...other
|
|
2371
2737
|
});
|
|
2372
2738
|
function mergeWith(combine) {
|
|
@@ -2396,24 +2762,27 @@ function mergeWith(combine) {
|
|
|
2396
2762
|
* Rec.size({ a: 1, b: 2 }); // 2
|
|
2397
2763
|
* ```
|
|
2398
2764
|
*/
|
|
2399
|
-
const size$1 = (
|
|
2765
|
+
const size$1 = (record) => Object.keys(record).length;
|
|
2400
2766
|
/**
|
|
2401
2767
|
* Transforms each key while preserving values.
|
|
2402
2768
|
* If two keys map to the same new key, the last one wins.
|
|
2403
2769
|
*
|
|
2770
|
+
* @see {@link map} for transforming values.
|
|
2771
|
+
* @see {@link mapEntries} for transforming keys and values simultaneously.
|
|
2772
|
+
*
|
|
2404
2773
|
* @example
|
|
2405
2774
|
* ```ts
|
|
2406
2775
|
* pipe({ firstName: "Alice", lastName: "Smith" }, Rec.mapKeys(k => k.toUpperCase()));
|
|
2407
2776
|
* // { FIRSTNAME: "Alice", LASTNAME: "Smith" }
|
|
2408
2777
|
* ```
|
|
2409
2778
|
*/
|
|
2410
|
-
const mapKeys = (
|
|
2411
|
-
const recKeys = Object.keys(
|
|
2412
|
-
if (recKeys.length === 0) return
|
|
2779
|
+
const mapKeys = (transform) => (record) => {
|
|
2780
|
+
const recKeys = Object.keys(record);
|
|
2781
|
+
if (recKeys.length === 0) return record;
|
|
2413
2782
|
const result = {};
|
|
2414
2783
|
for (let i = 0; i < recKeys.length; i++) {
|
|
2415
2784
|
const k = recKeys[i];
|
|
2416
|
-
_setKey(result,
|
|
2785
|
+
_setKey(result, transform(k), record[k]);
|
|
2417
2786
|
}
|
|
2418
2787
|
return result;
|
|
2419
2788
|
};
|
|
@@ -2427,13 +2796,13 @@ const mapKeys = (f) => (data) => {
|
|
|
2427
2796
|
* // { a: 1, c: 3 }
|
|
2428
2797
|
* ```
|
|
2429
2798
|
*/
|
|
2430
|
-
const compact = (
|
|
2431
|
-
const recKeys = Object.keys(
|
|
2799
|
+
const compact = (record) => {
|
|
2800
|
+
const recKeys = Object.keys(record);
|
|
2432
2801
|
if (recKeys.length === 0) return {};
|
|
2433
2802
|
const result = {};
|
|
2434
2803
|
for (let i = 0; i < recKeys.length; i++) {
|
|
2435
2804
|
const k = recKeys[i];
|
|
2436
|
-
const v =
|
|
2805
|
+
const v = record[k];
|
|
2437
2806
|
if (v.kind === "Some") _setKey(result, k, v.value);
|
|
2438
2807
|
}
|
|
2439
2808
|
return result;
|
|
@@ -2441,6 +2810,9 @@ const compact = (data) => {
|
|
|
2441
2810
|
/**
|
|
2442
2811
|
* Transforms key and value pairs simultaneously.
|
|
2443
2812
|
*
|
|
2813
|
+
* @see {@link map} for transforming values.
|
|
2814
|
+
* @see {@link mapKeys} for transforming keys.
|
|
2815
|
+
*
|
|
2444
2816
|
* @example
|
|
2445
2817
|
* ```ts
|
|
2446
2818
|
* pipe(
|
|
@@ -2449,13 +2821,13 @@ const compact = (data) => {
|
|
|
2449
2821
|
* ); // { A: 10, B: 20 }
|
|
2450
2822
|
* ```
|
|
2451
2823
|
*/
|
|
2452
|
-
const mapEntries = (
|
|
2453
|
-
const recKeys = Object.keys(
|
|
2824
|
+
const mapEntries = (transform) => (record) => {
|
|
2825
|
+
const recKeys = Object.keys(record);
|
|
2454
2826
|
if (recKeys.length === 0) return {};
|
|
2455
2827
|
const result = {};
|
|
2456
2828
|
for (let i = 0; i < recKeys.length; i++) {
|
|
2457
2829
|
const k = recKeys[i];
|
|
2458
|
-
const [newKey, newVal] =
|
|
2830
|
+
const [newKey, newVal] = transform(k, record[k]);
|
|
2459
2831
|
_setKey(result, newKey, newVal);
|
|
2460
2832
|
}
|
|
2461
2833
|
return result;
|
|
@@ -2471,12 +2843,12 @@ const mapEntries = (f) => (data) => {
|
|
|
2471
2843
|
* ); // { user: { profile: { age: 31 } } }
|
|
2472
2844
|
* ```
|
|
2473
2845
|
*/
|
|
2474
|
-
const updateIn = (path,
|
|
2846
|
+
const updateIn = (path, transform) => (record) => {
|
|
2475
2847
|
const updateNode = (obj, pathKeys) => {
|
|
2476
2848
|
const [head, ...tail] = pathKeys;
|
|
2477
2849
|
if (tail.length === 0) return {
|
|
2478
2850
|
...obj,
|
|
2479
|
-
[head]:
|
|
2851
|
+
[head]: transform(obj?.[head])
|
|
2480
2852
|
};
|
|
2481
2853
|
const child = obj && typeof obj === "object" && head in obj ? obj[head] : {};
|
|
2482
2854
|
return {
|
|
@@ -2484,12 +2856,12 @@ const updateIn = (path, f) => (data) => {
|
|
|
2484
2856
|
[head]: updateNode(child, tail)
|
|
2485
2857
|
};
|
|
2486
2858
|
};
|
|
2487
|
-
return updateNode(
|
|
2859
|
+
return updateNode(record, path);
|
|
2488
2860
|
};
|
|
2489
2861
|
const Rec = {
|
|
2490
2862
|
is: RecIs,
|
|
2491
2863
|
from: RecFrom,
|
|
2492
|
-
to: { Dict: (
|
|
2864
|
+
to: { Dict: (record) => new globalThis.Map(Object.entries(record)) },
|
|
2493
2865
|
map: map$1,
|
|
2494
2866
|
filterMap: filterMap$1,
|
|
2495
2867
|
mapWithKey,
|
|
@@ -2519,13 +2891,13 @@ const Rec = {
|
|
|
2519
2891
|
},
|
|
2520
2892
|
NonEmpty: {
|
|
2521
2893
|
singleton: (key, value) => ({ [key]: value }),
|
|
2522
|
-
from: {
|
|
2523
|
-
keys: (
|
|
2524
|
-
values: (
|
|
2525
|
-
entries: (
|
|
2526
|
-
reduce: (
|
|
2527
|
-
map: (
|
|
2528
|
-
mapWithKey: (
|
|
2894
|
+
from: { record: (record) => _isNonEmpty(record) ? Maybe.make.some(record) : Maybe.make.none() },
|
|
2895
|
+
keys: (record) => keys(record),
|
|
2896
|
+
values: (record) => values(record),
|
|
2897
|
+
entries: (record) => entries(record),
|
|
2898
|
+
reduce: (reducer) => (record) => values(record).reduce(reducer),
|
|
2899
|
+
map: (transform) => (record) => map$1(transform)(record),
|
|
2900
|
+
mapWithKey: (transform) => (record) => mapWithKey(transform)(record)
|
|
2529
2901
|
}
|
|
2530
2902
|
};
|
|
2531
2903
|
//#endregion
|
|
@@ -2536,18 +2908,21 @@ const StrNonEmptyConst = { from: {
|
|
|
2536
2908
|
*
|
|
2537
2909
|
* @example
|
|
2538
2910
|
* ```ts
|
|
2539
|
-
* Str.NonEmpty.from.
|
|
2540
|
-
* Str.NonEmpty.from.
|
|
2911
|
+
* Str.NonEmpty.from.string("hello"); // Some("hello")
|
|
2912
|
+
* Str.NonEmpty.from.string(""); // None
|
|
2541
2913
|
* ```
|
|
2542
2914
|
*/
|
|
2543
|
-
|
|
2544
|
-
const isEmpty$1 = (
|
|
2545
|
-
const isNonEmpty$1 = (
|
|
2915
|
+
string: (text) => text.length > 0 ? Maybe.make.some(text) : Maybe.make.none() } };
|
|
2916
|
+
const isEmpty$1 = (text) => text.length === 0;
|
|
2917
|
+
const isNonEmpty$1 = (text) => text.length > 0;
|
|
2918
|
+
const isBlank = (text) => text.trim().length === 0;
|
|
2546
2919
|
const Str = {
|
|
2547
2920
|
is: {
|
|
2548
2921
|
/**
|
|
2549
2922
|
* Returns `true` when the string is empty.
|
|
2550
2923
|
*
|
|
2924
|
+
* @see {@link nonEmpty} for checking if a string contains at least one character.
|
|
2925
|
+
*
|
|
2551
2926
|
* @example
|
|
2552
2927
|
* ```ts
|
|
2553
2928
|
* pipe("", Str.is.empty); // true
|
|
@@ -2557,8 +2932,22 @@ const Str = {
|
|
|
2557
2932
|
empty: isEmpty$1,
|
|
2558
2933
|
/**
|
|
2559
2934
|
* Type guard to check if a string is non-empty.
|
|
2935
|
+
*
|
|
2936
|
+
* @see {@link empty} for checking if a string has zero length.
|
|
2937
|
+
*/
|
|
2938
|
+
nonEmpty: isNonEmpty$1,
|
|
2939
|
+
/**
|
|
2940
|
+
* Returns `true` when the string is empty or contains only whitespace.
|
|
2941
|
+
*
|
|
2942
|
+
* @see {@link empty} for checking zero length without trimming whitespace.
|
|
2943
|
+
*
|
|
2944
|
+
* @example
|
|
2945
|
+
* ```ts
|
|
2946
|
+
* pipe(" ", Str.is.blank); // true
|
|
2947
|
+
* pipe("hi", Str.is.blank); // false
|
|
2948
|
+
* ```
|
|
2560
2949
|
*/
|
|
2561
|
-
|
|
2950
|
+
blank: isBlank
|
|
2562
2951
|
},
|
|
2563
2952
|
/**
|
|
2564
2953
|
* Splits a string by a separator. Data-last: use in `pipe`.
|
|
@@ -2568,7 +2957,7 @@ const Str = {
|
|
|
2568
2957
|
* pipe("a,b,c", Str.split(",")); // ["a", "b", "c"]
|
|
2569
2958
|
* ```
|
|
2570
2959
|
*/
|
|
2571
|
-
split: (separator) => (
|
|
2960
|
+
split: (separator) => (text) => text.split(separator),
|
|
2572
2961
|
/**
|
|
2573
2962
|
* Removes leading and trailing whitespace from a string.
|
|
2574
2963
|
*
|
|
@@ -2577,7 +2966,7 @@ const Str = {
|
|
|
2577
2966
|
* pipe(" hello ", Str.trim); // "hello"
|
|
2578
2967
|
* ```
|
|
2579
2968
|
*/
|
|
2580
|
-
trim: (
|
|
2969
|
+
trim: (text) => text.trim(),
|
|
2581
2970
|
/**
|
|
2582
2971
|
* Returns `true` when the string contains the given substring.
|
|
2583
2972
|
*
|
|
@@ -2587,74 +2976,88 @@ const Str = {
|
|
|
2587
2976
|
* pipe("hello world", Str.includes("xyz")); // false
|
|
2588
2977
|
* ```
|
|
2589
2978
|
*/
|
|
2590
|
-
includes: (substring) => (
|
|
2979
|
+
includes: (substring) => (text) => text.includes(substring),
|
|
2591
2980
|
/**
|
|
2592
2981
|
* Replaces the first occurrence of a pattern in a string. Data-last: use in `pipe`.
|
|
2593
2982
|
*
|
|
2983
|
+
* @see {@link replaceAll} for substituting every occurrence instead of only the first.
|
|
2984
|
+
*
|
|
2594
2985
|
* @example
|
|
2595
2986
|
* ```ts
|
|
2596
2987
|
* pipe("foo foo foo", Str.replace("foo", "bar")); // "bar foo foo"
|
|
2597
2988
|
* pipe("Hello World", Str.replace(/world/i, "Earth")); // "Hello Earth"
|
|
2598
2989
|
* ```
|
|
2599
2990
|
*/
|
|
2600
|
-
replace: (pattern, replacement) => (
|
|
2991
|
+
replace: (pattern, replacement) => (text) => text.replace(pattern, replacement),
|
|
2601
2992
|
/**
|
|
2602
2993
|
* Replaces all occurrences of a pattern in a string. Data-last: use in `pipe`.
|
|
2603
2994
|
*
|
|
2995
|
+
* @see {@link replace} for substituting only the first occurrence.
|
|
2996
|
+
*
|
|
2604
2997
|
* @example
|
|
2605
2998
|
* ```ts
|
|
2606
2999
|
* pipe("foo foo foo", Str.replaceAll("foo", "bar")); // "bar bar bar"
|
|
2607
3000
|
* pipe("aAbBaA", Str.replaceAll(/a/gi, "x")); // "xxBBxx"
|
|
2608
3001
|
* ```
|
|
2609
3002
|
*/
|
|
2610
|
-
replaceAll: (pattern, replacement) => (
|
|
3003
|
+
replaceAll: (pattern, replacement) => (text) => text.replaceAll(pattern, replacement),
|
|
2611
3004
|
/**
|
|
2612
3005
|
* Returns `true` when the string starts with the given prefix.
|
|
2613
3006
|
*
|
|
3007
|
+
* @see {@link endsWith} for checking suffix matches.
|
|
3008
|
+
*
|
|
2614
3009
|
* @example
|
|
2615
3010
|
* ```ts
|
|
2616
3011
|
* pipe("hello world", Str.startsWith("hello")); // true
|
|
2617
3012
|
* pipe("hello world", Str.startsWith("world")); // false
|
|
2618
3013
|
* ```
|
|
2619
3014
|
*/
|
|
2620
|
-
startsWith: (prefix) => (
|
|
3015
|
+
startsWith: (prefix) => (text) => text.startsWith(prefix),
|
|
2621
3016
|
/**
|
|
2622
3017
|
* Returns `true` when the string ends with the given suffix.
|
|
2623
3018
|
*
|
|
3019
|
+
* @see {@link startsWith} for checking prefix matches.
|
|
3020
|
+
*
|
|
2624
3021
|
* @example
|
|
2625
3022
|
* ```ts
|
|
2626
3023
|
* pipe("hello world", Str.endsWith("world")); // true
|
|
2627
3024
|
* pipe("hello world", Str.endsWith("hello")); // false
|
|
2628
3025
|
* ```
|
|
2629
3026
|
*/
|
|
2630
|
-
endsWith: (suffix) => (
|
|
3027
|
+
endsWith: (suffix) => (text) => text.endsWith(suffix),
|
|
2631
3028
|
/**
|
|
2632
3029
|
* Converts a string to uppercase.
|
|
2633
3030
|
*
|
|
3031
|
+
* @see {@link toLowerCase} for lowercasing characters.
|
|
3032
|
+
*
|
|
2634
3033
|
* @example
|
|
2635
3034
|
* ```ts
|
|
2636
3035
|
* pipe("hello", Str.toUpperCase); // "HELLO"
|
|
2637
3036
|
* ```
|
|
2638
3037
|
*/
|
|
2639
|
-
toUpperCase: (
|
|
3038
|
+
toUpperCase: (text) => text.toUpperCase(),
|
|
2640
3039
|
/**
|
|
2641
3040
|
* Converts a string to lowercase.
|
|
2642
3041
|
*
|
|
3042
|
+
* @see {@link toUpperCase} for uppercasing characters.
|
|
3043
|
+
*
|
|
2643
3044
|
* @example
|
|
2644
3045
|
* ```ts
|
|
2645
3046
|
* pipe("HELLO", Str.toLowerCase); // "hello"
|
|
2646
3047
|
* ```
|
|
2647
3048
|
*/
|
|
2648
|
-
toLowerCase: (
|
|
3049
|
+
toLowerCase: (text) => text.toLowerCase(),
|
|
2649
3050
|
/**
|
|
2650
3051
|
* Converts the first character of a string to uppercase.
|
|
2651
3052
|
*
|
|
3053
|
+
* @see {@link uncapitalize} for converting the first character to lowercase.
|
|
3054
|
+
*
|
|
2652
3055
|
* @example
|
|
2653
3056
|
* ```ts
|
|
2654
3057
|
* pipe("hello", Str.capitalize); // "Hello"
|
|
2655
3058
|
* ```
|
|
2656
3059
|
*/
|
|
2657
|
-
capitalize: (
|
|
3060
|
+
capitalize: (text) => text.length === 0 ? "" : text.charAt(0).toUpperCase() + text.slice(1),
|
|
2658
3061
|
/**
|
|
2659
3062
|
* Splits a string into lines, normalising `\r\n` and `\r` line endings.
|
|
2660
3063
|
*
|
|
@@ -2664,7 +3067,7 @@ const Str = {
|
|
|
2664
3067
|
* Str.lines("a\r\nb"); // ["a", "b"]
|
|
2665
3068
|
* ```
|
|
2666
3069
|
*/
|
|
2667
|
-
lines: (
|
|
3070
|
+
lines: (text) => text.split(/\r?\n|\r/),
|
|
2668
3071
|
/**
|
|
2669
3072
|
* Splits a string into words on any whitespace boundary, filtering out empty strings.
|
|
2670
3073
|
*
|
|
@@ -2673,17 +3076,7 @@ const Str = {
|
|
|
2673
3076
|
* Str.words(" hello world "); // ["hello", "world"]
|
|
2674
3077
|
* ```
|
|
2675
3078
|
*/
|
|
2676
|
-
words: (
|
|
2677
|
-
/**
|
|
2678
|
-
* Returns `true` when the string is empty or contains only whitespace.
|
|
2679
|
-
*
|
|
2680
|
-
* @example
|
|
2681
|
-
* ```ts
|
|
2682
|
-
* pipe(" ", Str.isBlank); // true
|
|
2683
|
-
* pipe("hi", Str.isBlank); // false
|
|
2684
|
-
* ```
|
|
2685
|
-
*/
|
|
2686
|
-
isBlank: (s) => s.trim().length === 0,
|
|
3079
|
+
words: (text) => text.trim().split(/\s+/).filter(Boolean),
|
|
2687
3080
|
/**
|
|
2688
3081
|
* Returns the length of the string.
|
|
2689
3082
|
*
|
|
@@ -2693,7 +3086,7 @@ const Str = {
|
|
|
2693
3086
|
* pipe("", Str.length); // 0
|
|
2694
3087
|
* ```
|
|
2695
3088
|
*/
|
|
2696
|
-
length: (
|
|
3089
|
+
length: (text) => text.length,
|
|
2697
3090
|
/**
|
|
2698
3091
|
* Extracts a substring between two indices. Data-last: use in `pipe`.
|
|
2699
3092
|
*
|
|
@@ -2703,27 +3096,31 @@ const Str = {
|
|
|
2703
3096
|
* pipe("hello", Str.slice(2)); // "llo"
|
|
2704
3097
|
* ```
|
|
2705
3098
|
*/
|
|
2706
|
-
slice: (start, end) => (
|
|
3099
|
+
slice: (start, end) => (text) => text.slice(start, end),
|
|
2707
3100
|
/**
|
|
2708
3101
|
* Pads the start of a string to a specified length. Data-last: use in `pipe`.
|
|
2709
3102
|
*
|
|
3103
|
+
* @see {@link padEnd} for padding the right side of a string.
|
|
3104
|
+
*
|
|
2710
3105
|
* @example
|
|
2711
3106
|
* ```ts
|
|
2712
3107
|
* pipe("5", Str.padStart(3, "0")); // "005"
|
|
2713
3108
|
* pipe("hi", Str.padStart(5)); // " hi"
|
|
2714
3109
|
* ```
|
|
2715
3110
|
*/
|
|
2716
|
-
padStart: (maxLength, fillString) => (
|
|
3111
|
+
padStart: (maxLength, fillString) => (text) => text.padStart(maxLength, fillString),
|
|
2717
3112
|
/**
|
|
2718
3113
|
* Pads the end of a string to a specified length. Data-last: use in `pipe`.
|
|
2719
3114
|
*
|
|
3115
|
+
* @see {@link padStart} for padding the left side of a string.
|
|
3116
|
+
*
|
|
2720
3117
|
* @example
|
|
2721
3118
|
* ```ts
|
|
2722
3119
|
* pipe("hi", Str.padEnd(5, ".")); // "hi..."
|
|
2723
3120
|
* pipe("hi", Str.padEnd(5)); // "hi "
|
|
2724
3121
|
* ```
|
|
2725
3122
|
*/
|
|
2726
|
-
padEnd: (maxLength, fillString) => (
|
|
3123
|
+
padEnd: (maxLength, fillString) => (text) => text.padEnd(maxLength, fillString),
|
|
2727
3124
|
/**
|
|
2728
3125
|
* Safe number parsers that return `Maybe` instead of `NaN`.
|
|
2729
3126
|
*/
|
|
@@ -2731,6 +3128,8 @@ const Str = {
|
|
|
2731
3128
|
/**
|
|
2732
3129
|
* Parses a string as an integer (base 10). Returns `None` if the result is `NaN`.
|
|
2733
3130
|
*
|
|
3131
|
+
* @see {@link float} for parsing floating-point numbers.
|
|
3132
|
+
*
|
|
2734
3133
|
* @example
|
|
2735
3134
|
* ```ts
|
|
2736
3135
|
* Str.parse.int("42"); // Some(42)
|
|
@@ -2738,14 +3137,16 @@ const Str = {
|
|
|
2738
3137
|
* Str.parse.int("abc"); // None
|
|
2739
3138
|
* ```
|
|
2740
3139
|
*/
|
|
2741
|
-
int: (
|
|
2742
|
-
if (
|
|
2743
|
-
const n = Number.parseInt(
|
|
3140
|
+
int: (text) => {
|
|
3141
|
+
if (text.length === 0) return Maybe.make.none();
|
|
3142
|
+
const n = Number.parseInt(text, 10);
|
|
2744
3143
|
return Number.isNaN(n) ? Maybe.make.none() : Maybe.make.some(n);
|
|
2745
3144
|
},
|
|
2746
3145
|
/**
|
|
2747
3146
|
* Parses a string as a floating-point number. Returns `None` if the result is `NaN`.
|
|
2748
3147
|
*
|
|
3148
|
+
* @see {@link int} for parsing base-10 integers.
|
|
3149
|
+
*
|
|
2749
3150
|
* @example
|
|
2750
3151
|
* ```ts
|
|
2751
3152
|
* Str.parse.float("3.14"); // Some(3.14)
|
|
@@ -2753,9 +3154,9 @@ const Str = {
|
|
|
2753
3154
|
* Str.parse.float("abc"); // None
|
|
2754
3155
|
* ```
|
|
2755
3156
|
*/
|
|
2756
|
-
float: (
|
|
2757
|
-
if (
|
|
2758
|
-
const n = Number.parseFloat(
|
|
3157
|
+
float: (text) => {
|
|
3158
|
+
if (text.length === 0) return Maybe.make.none();
|
|
3159
|
+
const n = Number.parseFloat(text);
|
|
2759
3160
|
return Number.isNaN(n) ? Maybe.make.none() : Maybe.make.some(n);
|
|
2760
3161
|
}
|
|
2761
3162
|
},
|
|
@@ -2763,41 +3164,47 @@ const Str = {
|
|
|
2763
3164
|
* Matches a string against a regular expression.
|
|
2764
3165
|
* Pure and safe: resets `pattern.lastIndex = 0` to prevent bugs with stateful `/g` and `/y` regexes.
|
|
2765
3166
|
*
|
|
3167
|
+
* @see {@link test} for boolean validation without extracting capture groups.
|
|
3168
|
+
*
|
|
2766
3169
|
* @example
|
|
2767
3170
|
* ```ts
|
|
2768
3171
|
* pipe("hello 42", Str.match(/\d+/)); // Some(["42"])
|
|
2769
3172
|
* pipe("hello", Str.match(/\d+/)); // None
|
|
2770
3173
|
* ```
|
|
2771
3174
|
*/
|
|
2772
|
-
match: (pattern) => (
|
|
3175
|
+
match: (pattern) => (text) => {
|
|
2773
3176
|
pattern.lastIndex = 0;
|
|
2774
|
-
const result =
|
|
3177
|
+
const result = text.match(pattern);
|
|
2775
3178
|
return result !== null ? Maybe.make.some(result) : Maybe.make.none();
|
|
2776
3179
|
},
|
|
2777
3180
|
/**
|
|
2778
3181
|
* Tests whether a string matches a regular expression.
|
|
2779
3182
|
* Pure and safe: resets `pattern.lastIndex = 0` to prevent bugs with stateful `/g` and `/y` regexes.
|
|
2780
3183
|
*
|
|
3184
|
+
* @see {@link match} for extracting capture groups into a Maybe.
|
|
3185
|
+
*
|
|
2781
3186
|
* @example
|
|
2782
3187
|
* ```ts
|
|
2783
3188
|
* pipe("user@example.com", Str.test(/^[^@]+@[^@]+$/)); // true
|
|
2784
3189
|
* pipe("invalid-email", Str.test(/^[^@]+@[^@]+$/)); // false
|
|
2785
3190
|
* ```
|
|
2786
3191
|
*/
|
|
2787
|
-
test: (pattern) => (
|
|
3192
|
+
test: (pattern) => (text) => {
|
|
2788
3193
|
pattern.lastIndex = 0;
|
|
2789
|
-
return pattern.test(
|
|
3194
|
+
return pattern.test(text);
|
|
2790
3195
|
},
|
|
2791
3196
|
/**
|
|
2792
3197
|
* Converts the first character of a string to lower case.
|
|
2793
3198
|
*
|
|
3199
|
+
* @see {@link capitalize} for converting the first character to uppercase.
|
|
3200
|
+
*
|
|
2794
3201
|
* @example
|
|
2795
3202
|
* ```ts
|
|
2796
|
-
*
|
|
2797
|
-
* Str.uncapitalize
|
|
3203
|
+
* pipe("Hello", Str.uncapitalize); // "hello"
|
|
3204
|
+
* pipe("", Str.uncapitalize); // ""
|
|
2798
3205
|
* ```
|
|
2799
3206
|
*/
|
|
2800
|
-
uncapitalize: (
|
|
3207
|
+
uncapitalize: (text) => text.length === 0 ? "" : text.charAt(0).toLowerCase() + text.slice(1),
|
|
2801
3208
|
/**
|
|
2802
3209
|
* Truncates a string to a maximum length, appending an optional suffix (default `"..."`).
|
|
2803
3210
|
* Data-last curried signature.
|
|
@@ -2809,100 +3216,158 @@ const Str = {
|
|
|
2809
3216
|
* pipe("Hello, world!", Str.truncate({ length: 8, suffix: "…" })); // "Hello, w…"
|
|
2810
3217
|
* ```
|
|
2811
3218
|
*/
|
|
2812
|
-
truncate: (options) => (
|
|
3219
|
+
truncate: (options) => (text) => {
|
|
2813
3220
|
const { length: targetLength, suffix = "..." } = options;
|
|
2814
|
-
if (
|
|
3221
|
+
if (text.length <= targetLength) return text;
|
|
2815
3222
|
if (targetLength <= suffix.length) return suffix.slice(0, targetLength);
|
|
2816
|
-
return
|
|
3223
|
+
return text.slice(0, targetLength - suffix.length) + suffix;
|
|
2817
3224
|
},
|
|
2818
3225
|
NonEmpty: StrNonEmptyConst
|
|
2819
3226
|
};
|
|
2820
3227
|
//#endregion
|
|
2821
3228
|
//#region src/Data/Uniq.ts
|
|
2822
|
-
const isEmpty = (
|
|
2823
|
-
const isNonEmpty = (
|
|
3229
|
+
const isEmpty = (set) => set.size === 0;
|
|
3230
|
+
const isNonEmpty = (set) => set.size > 0;
|
|
2824
3231
|
const empty = () => new globalThis.Set();
|
|
2825
3232
|
const singleton = (item) => new globalThis.Set([item]);
|
|
2826
|
-
const fromArray = (
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
3233
|
+
const fromArray = (items) => new globalThis.Set(items);
|
|
3234
|
+
/**
|
|
3235
|
+
* Returns `true` when the set contains the given element.
|
|
3236
|
+
*
|
|
3237
|
+
* @see {@link add} for inserting an element into a set.
|
|
3238
|
+
* @see {@link remove} for deleting an element from a set.
|
|
3239
|
+
*/
|
|
3240
|
+
const has = (item) => (set) => set.has(item);
|
|
3241
|
+
const size = (set) => set.size;
|
|
3242
|
+
/**
|
|
3243
|
+
* Returns a new set with the element added.
|
|
3244
|
+
*
|
|
3245
|
+
* @see {@link remove} for deleting an element from a set.
|
|
3246
|
+
* @see {@link toggle} for toggling presence of an element.
|
|
3247
|
+
*/
|
|
3248
|
+
const add = (item) => (set) => {
|
|
3249
|
+
if (set.has(item)) return set;
|
|
3250
|
+
const result = new globalThis.Set(set);
|
|
2832
3251
|
result.add(item);
|
|
2833
3252
|
return result;
|
|
2834
3253
|
};
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
3254
|
+
/**
|
|
3255
|
+
* Returns a new set with the element removed.
|
|
3256
|
+
*
|
|
3257
|
+
* @see {@link add} for adding an element to a set.
|
|
3258
|
+
*/
|
|
3259
|
+
const remove = (item) => (set) => {
|
|
3260
|
+
if (!set.has(item)) return set;
|
|
3261
|
+
const result = new globalThis.Set(set);
|
|
2838
3262
|
result.delete(item);
|
|
2839
3263
|
return result;
|
|
2840
3264
|
};
|
|
2841
|
-
|
|
2842
|
-
|
|
3265
|
+
/**
|
|
3266
|
+
* Toggles presence of an element in a set.
|
|
3267
|
+
*
|
|
3268
|
+
* @see {@link add} for unconditionally adding an element.
|
|
3269
|
+
* @see {@link remove} for unconditionally removing an element.
|
|
3270
|
+
*/
|
|
3271
|
+
const toggle = (item) => (set) => {
|
|
3272
|
+
const result = new globalThis.Set(set);
|
|
2843
3273
|
if (result.has(item)) result.delete(item);
|
|
2844
3274
|
else result.add(item);
|
|
2845
3275
|
return result;
|
|
2846
3276
|
};
|
|
2847
|
-
|
|
3277
|
+
/**
|
|
3278
|
+
* Transforms each element of a set into a new set.
|
|
3279
|
+
*
|
|
3280
|
+
* @see {@link filterMap} for mapping and filtering in a single step.
|
|
3281
|
+
*/
|
|
3282
|
+
const map = (transform) => (set) => {
|
|
2848
3283
|
const result = new globalThis.Set();
|
|
2849
|
-
for (const item of
|
|
3284
|
+
for (const item of set) result.add(transform(item));
|
|
2850
3285
|
return result;
|
|
2851
3286
|
};
|
|
2852
|
-
|
|
3287
|
+
/**
|
|
3288
|
+
* Filters elements of a set by a predicate.
|
|
3289
|
+
*
|
|
3290
|
+
* @see {@link filterMap} for filtering and mapping simultaneously.
|
|
3291
|
+
*/
|
|
3292
|
+
const filter = (predicate) => (set) => {
|
|
2853
3293
|
const result = new globalThis.Set();
|
|
2854
|
-
for (const item of
|
|
3294
|
+
for (const item of set) if (predicate(item)) result.add(item);
|
|
2855
3295
|
return result;
|
|
2856
3296
|
};
|
|
2857
|
-
|
|
3297
|
+
/**
|
|
3298
|
+
* Transforms elements with a function returning `Maybe`, keeping only `Some` values.
|
|
3299
|
+
*
|
|
3300
|
+
* @see {@link filter} for filtering with a boolean predicate.
|
|
3301
|
+
* @see {@link map} for transforming without filtering.
|
|
3302
|
+
*/
|
|
3303
|
+
const filterMap = (transform) => (set) => {
|
|
2858
3304
|
const result = new globalThis.Set();
|
|
2859
|
-
for (const item of
|
|
2860
|
-
const mb =
|
|
3305
|
+
for (const item of set) {
|
|
3306
|
+
const mb = transform(item);
|
|
2861
3307
|
if (mb.kind === "Some") result.add(mb.value);
|
|
2862
3308
|
}
|
|
2863
3309
|
return result;
|
|
2864
3310
|
};
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
3311
|
+
/**
|
|
3312
|
+
* Computes the union of two sets.
|
|
3313
|
+
*
|
|
3314
|
+
* @see {@link intersection} for keeping only elements present in both sets.
|
|
3315
|
+
* @see {@link difference} for subtracting elements.
|
|
3316
|
+
*/
|
|
3317
|
+
const union = (other) => (set) => {
|
|
3318
|
+
const s = set;
|
|
3319
|
+
if (typeof s.union === "function") return s.union(other);
|
|
3320
|
+
const result = new globalThis.Set(set);
|
|
2869
3321
|
for (const item of other) result.add(item);
|
|
2870
3322
|
return result;
|
|
2871
3323
|
};
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
3324
|
+
/**
|
|
3325
|
+
* Computes the intersection of two sets.
|
|
3326
|
+
*
|
|
3327
|
+
* @see {@link union} for combining elements from both sets.
|
|
3328
|
+
* @see {@link difference} for subtracting elements.
|
|
3329
|
+
*/
|
|
3330
|
+
const intersection = (other) => (set) => {
|
|
3331
|
+
const s = set;
|
|
3332
|
+
if (typeof s.intersection === "function") return s.intersection(other);
|
|
2875
3333
|
const result = new globalThis.Set();
|
|
2876
|
-
for (const item of
|
|
3334
|
+
for (const item of set) if (other.has(item)) result.add(item);
|
|
2877
3335
|
return result;
|
|
2878
3336
|
};
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
3337
|
+
/**
|
|
3338
|
+
* Computes the set difference (`set \ other`).
|
|
3339
|
+
*
|
|
3340
|
+
* @see {@link union} for combining all elements.
|
|
3341
|
+
* @see {@link intersection} for keeping only common elements.
|
|
3342
|
+
*/
|
|
3343
|
+
const difference = (other) => (set) => {
|
|
3344
|
+
const s = set;
|
|
3345
|
+
if (typeof s.difference === "function") return s.difference(other);
|
|
2882
3346
|
const result = new globalThis.Set();
|
|
2883
|
-
for (const item of
|
|
3347
|
+
for (const item of set) if (!other.has(item)) result.add(item);
|
|
2884
3348
|
return result;
|
|
2885
3349
|
};
|
|
2886
|
-
const isSubsetOf = (other) => (
|
|
2887
|
-
const
|
|
2888
|
-
if (typeof
|
|
2889
|
-
for (const item of
|
|
3350
|
+
const isSubsetOf = (other) => (set) => {
|
|
3351
|
+
const s = set;
|
|
3352
|
+
if (typeof s.isSubsetOf === "function") return s.isSubsetOf(other);
|
|
3353
|
+
for (const item of set) if (!other.has(item)) return false;
|
|
2890
3354
|
return true;
|
|
2891
3355
|
};
|
|
2892
|
-
const reduce = (
|
|
2893
|
-
let acc =
|
|
2894
|
-
for (const item of
|
|
3356
|
+
const reduce = (initial, reducer) => (set) => {
|
|
3357
|
+
let acc = initial;
|
|
3358
|
+
for (const item of set) acc = reducer(acc, item);
|
|
2895
3359
|
return acc;
|
|
2896
3360
|
};
|
|
2897
|
-
const toArray = (
|
|
3361
|
+
const toArray = (set) => [...set];
|
|
2898
3362
|
const Uniq = {
|
|
2899
3363
|
is: {
|
|
2900
3364
|
empty: isEmpty,
|
|
2901
|
-
nonEmpty: isNonEmpty
|
|
3365
|
+
nonEmpty: isNonEmpty,
|
|
3366
|
+
subsetOf: isSubsetOf
|
|
2902
3367
|
},
|
|
2903
3368
|
empty,
|
|
2904
3369
|
singleton,
|
|
2905
|
-
from: {
|
|
3370
|
+
from: { array: fromArray },
|
|
2906
3371
|
has,
|
|
2907
3372
|
size,
|
|
2908
3373
|
add,
|
|
@@ -2915,15 +3380,14 @@ const Uniq = {
|
|
|
2915
3380
|
union,
|
|
2916
3381
|
intersection,
|
|
2917
3382
|
difference,
|
|
2918
|
-
isSubsetOf,
|
|
2919
3383
|
reduce,
|
|
2920
|
-
to: {
|
|
3384
|
+
to: { array: toArray },
|
|
2921
3385
|
NonEmpty: {
|
|
2922
3386
|
singleton: (item) => new globalThis.Set([item]),
|
|
2923
|
-
from: {
|
|
2924
|
-
reduce: (
|
|
2925
|
-
map: (
|
|
2926
|
-
to: {
|
|
3387
|
+
from: { set: (set) => set.size > 0 ? Maybe.make.some(set) : Maybe.make.none() },
|
|
3388
|
+
reduce: (reducer) => (set) => toArray(set).reduce(reducer),
|
|
3389
|
+
map: (transform) => (set) => map(transform)(set),
|
|
3390
|
+
to: { array: (set) => toArray(set) }
|
|
2927
3391
|
}
|
|
2928
3392
|
};
|
|
2929
3393
|
//#endregion
|