@nlozgachev/pipelined 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/data.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as NonEmptyArr, N as NonEmpty } from './InternalTypes-LdhLQx3N.js';
2
- import { M as Maybe, R as Result, E as Equality, b as Ordering, T as Task } from './Validation-DZLizBZ0.js';
3
- import { B as Brand } from './Duration-B8joKzro.js';
1
+ import { a as NonEmptyArr, N as NonEmpty } from './InternalTypes-CCXa8Kvr.js';
2
+ import { M as Maybe, R as Result, E as Equality, b as Ordering, T as Task } from './Task-9SJCMtG4.js';
3
+ import { B as Brand } from './Duration-DeyxG6VQ.js';
4
4
  import './types.js';
5
5
 
6
6
  declare namespace ArrTaskResult {
@@ -24,7 +24,7 @@ declare namespace ArrTaskResult {
24
24
  * )(); // Deferred<Err("non-positive")>
25
25
  * ```
26
26
  */
27
- const traverse: <E, A, B>(f: (a: A) => Task<Result<E, B>>) => (data: readonly A[]) => Task<Result<E, readonly B[]>>;
27
+ const traverse: <E, A, B>(f: (a: A) => Task.Result<E, B>) => (data: readonly A[]) => Task.Result<E, readonly B[]>;
28
28
  /**
29
29
  * Collects an array of Task.Results into a Task.Result of array.
30
30
  * Returns the first Err if any element is Err, runs sequentially.
@@ -37,721 +37,106 @@ declare namespace ArrTaskResult {
37
37
  * )(); // Deferred<Ok([1, 2])>
38
38
  * ```
39
39
  */
40
- const sequence: <E, A>(data: readonly Task<Result<E, A>>[]) => Task<Result<E, readonly A[]>>;
40
+ const sequence: <E, A>(data: readonly Task.Result<E, A>[]) => Task.Result<E, readonly A[]>;
41
41
  }
42
- declare namespace ArrNonEmpty {
43
- /**
44
- * Creates a single-element list.
45
- *
46
- * @example
47
- * ```ts
48
- * Arr.NonEmpty.singleton(42); // [42]
49
- * ```
50
- */
51
- const singleton: <A>(value: A) => NonEmptyArr<A>;
52
- namespace from {
53
- /**
54
- * Returns Some if the array is non-empty, None otherwise.
55
- *
56
- * @example
57
- * ```ts
58
- * Arr.NonEmpty.from.Array([1, 2]); // Some([1, 2])
59
- * Arr.NonEmpty.from.Array([]); // None
60
- * ```
61
- */
62
- const Array: <A>(data: readonly A[]) => Maybe<NonEmptyArr<A>>;
63
- }
64
- /**
65
- * Returns the first element of a NonEmptyArr.
66
- *
67
- * @example
68
- * ```ts
69
- * Arr.NonEmpty.head([1, 2, 3]); // 1
70
- * ```
71
- */
72
- const head: <A>(data: NonEmptyArr<A>) => A;
73
- /**
74
- * Returns the last element of a NonEmptyArr.
75
- *
76
- * @example
77
- * ```ts
78
- * Arr.NonEmpty.last([1, 2, 3]); // 3
79
- * ```
80
- */
81
- const last: <A>(data: NonEmptyArr<A>) => A;
82
- /**
83
- * Returns all elements except the first.
84
- *
85
- * @example
86
- * ```ts
87
- * Arr.NonEmpty.tail([1, 2, 3]); // [2, 3]
88
- * ```
89
- */
90
- const tail: <A>(data: NonEmptyArr<A>) => readonly A[];
91
- /**
92
- * Reduces a NonEmptyArr from the left without an initial value.
93
- *
94
- * @example
95
- * ```ts
96
- * pipe([1, 2, 3, 4] as Arr.NonEmpty<number>, Arr.NonEmpty.reduce((a: number, b: number) => a + b)); // 10
97
- * ```
98
- */
99
- const reduce: <A>(f: (acc: A, a: A) => A) => (data: NonEmptyArr<A>) => A;
100
- /**
101
- * Transforms each element of a NonEmptyArr.
102
- *
103
- * @example
104
- * ```ts
105
- * pipe(Arr.NonEmpty.singleton(1), Arr.NonEmpty.map(n => n * 2)); // [2]
106
- * ```
107
- */
108
- const map: <A, B>(f: (a: A) => B) => (data: NonEmptyArr<A>) => NonEmptyArr<B>;
109
- /**
110
- * Transforms each element of a NonEmptyArr, also receiving the index.
111
- *
112
- * @example
113
- * ```ts
114
- * pipe(Arr.NonEmpty.singleton("a"), Arr.NonEmpty.mapWithIndex((i, s) => `${i}:${s}`)); // ["0:a"]
115
- * ```
116
- */
117
- const mapWithIndex: <A, B>(f: (i: number, a: A) => B) => (data: NonEmptyArr<A>) => NonEmptyArr<B>;
118
- /**
119
- * Inserts a separator between every element of a NonEmptyArr.
120
- *
121
- * @example
122
- * ```ts
123
- * pipe([1, 2] as Arr.NonEmpty<number>, Arr.NonEmpty.intersperse(0)); // [1, 0, 2]
124
- * ```
125
- */
126
- const intersperse: <A>(sep: A) => (data: NonEmptyArr<A>) => NonEmptyArr<A>;
127
- /**
128
- * Concatenates a NonEmptyArr with a standard array.
129
- *
130
- * @example
131
- * ```ts
132
- * pipe(Arr.NonEmpty.singleton(1), Arr.NonEmpty.concat([2, 3])); // [1, 2, 3]
133
- * ```
134
- */
135
- const concat: <A>(other: readonly A[]) => (data: NonEmptyArr<A>) => NonEmptyArr<A>;
136
- /**
137
- * Reverses a NonEmptyArr.
138
- *
139
- * @example
140
- * ```ts
141
- * pipe(Arr.NonEmpty.singleton(1), Arr.NonEmpty.reverse); // [1]
142
- * ```
143
- */
144
- const reverse: <A>(data: NonEmptyArr<A>) => NonEmptyArr<A>;
145
- }
146
- /**
147
- * Functional array utilities that compose well with pipe.
148
- * All functions are data-last and curried where applicable.
149
- * Safe access functions return Maybe instead of throwing or returning undefined.
150
- *
151
- * @example
152
- * ```ts
153
- * pipe(
154
- * [1, 2, 3, 4, 5],
155
- * Arr.filter(n => n > 2),
156
- * Arr.map(n => n * 10),
157
- * Arr.head
158
- * ); // Some(30)
159
- * ```
160
- */
161
- declare namespace Arr {
162
- /**
163
- * A type alias representing an array that is guaranteed to contain at least one element.
164
- * Under the hood, this is a read-only tuple structure: `readonly [A, ...A[]]`.
165
- *
166
- * @example
167
- * ```ts
168
- * const list: Arr.NonEmpty<number> = [1, 2, 3];
169
- * ```
170
- */
171
- export type NonEmpty<A> = NonEmptyArr<A>;
172
- /**
173
- * Returns the first element of an array, or None if the array is empty.
174
- *
175
- * @example
176
- * ```ts
177
- * Arr.head([1, 2, 3]); // Some(1)
178
- * Arr.head([]); // None
179
- * ```
180
- */
181
- export const head: <A>(data: readonly A[]) => Maybe<A>;
182
- /**
183
- * Returns the last element of an array, or None if the array is empty.
184
- *
185
- * @example
186
- * ```ts
187
- * Arr.last([1, 2, 3]); // Some(3)
188
- * Arr.last([]); // None
189
- * ```
190
- */
191
- export const last: <A>(data: readonly A[]) => Maybe<A>;
192
- /**
193
- * Returns all elements except the first, or None if the array is empty.
194
- *
195
- * @example
196
- * ```ts
197
- * Arr.tail([1, 2, 3]); // Some([2, 3])
198
- * Arr.tail([]); // None
199
- * ```
200
- */
201
- export const tail: <A>(data: readonly A[]) => Maybe<readonly A[]>;
202
- /**
203
- * Returns all elements except the last, or None if the array is empty.
204
- *
205
- * @example
206
- * ```ts
207
- * Arr.init([1, 2, 3]); // Some([1, 2])
208
- * Arr.init([]); // None
209
- * ```
210
- */
211
- export const init: <A>(data: readonly A[]) => Maybe<readonly A[]>;
212
- /**
213
- * Returns the first element matching the predicate, or None.
214
- *
215
- * @example
216
- * ```ts
217
- * pipe([1, 2, 3, 4], Arr.findFirst(n => n > 2)); // Some(3)
218
- * ```
219
- */
220
- export const findFirst: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => Maybe<A>;
221
- /**
222
- * Returns the last element matching the predicate, or None.
223
- *
224
- * @example
225
- * ```ts
226
- * pipe([1, 2, 3, 4], Arr.findLast(n => n > 2)); // Some(4)
227
- * ```
228
- */
229
- export const findLast: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => Maybe<A>;
230
- /**
231
- * Returns the index of the first element matching the predicate, or None.
232
- *
233
- * @example
234
- * ```ts
235
- * pipe([1, 2, 3, 4], Arr.findIndex(n => n > 2)); // Some(2)
236
- * ```
237
- */
238
- export const findIndex: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => Maybe<number>;
239
- /**
240
- * Transforms each element of an array.
241
- *
242
- * @example
243
- * ```ts
244
- * pipe([1, 2, 3], Arr.map(n => n * 2)); // [2, 4, 6]
245
- * ```
246
- */
247
- export const map: <A, B>(f: (a: A) => B) => (data: readonly A[]) => readonly B[];
248
- /**
249
- * Transforms each element using both its value and its zero-based index.
250
- *
251
- * @example
252
- * ```ts
253
- * pipe(
254
- * ["a", "b", "c"],
255
- * Arr.mapWithIndex((i, s) => ({ position: i + 1, value: s }))
256
- * ); // [{ position: 1, value: "a" }, { position: 2, value: "b" }, { position: 3, value: "c" }]
257
- * ```
258
- */
259
- export const mapWithIndex: <A, B>(f: (i: number, a: A) => B) => (data: readonly A[]) => readonly B[];
260
- /**
261
- * Filters elements that satisfy the predicate.
262
- *
263
- * @example
264
- * ```ts
265
- * pipe([1, 2, 3, 4], Arr.filter(n => n % 2 === 0)); // [2, 4]
266
- * ```
267
- */
268
- export const filter: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly A[];
269
- /**
270
- * Maps each element to a Maybe and collects only the Some values.
271
- * Combines map and filter in a single pass.
272
- *
273
- * @example
274
- * ```ts
275
- * const parseNum = (s: string): Maybe<number> => {
276
- * const n = Number(s);
277
- * return isNaN(n) ? Maybe.make.none() : Maybe.make.some(n);
278
- * };
279
- *
280
- * pipe(["1", "abc", "3"], Arr.filterMap(parseNum)); // [1, 3]
281
- * ```
282
- */
283
- export const filterMap: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => readonly B[];
284
- /**
285
- * Splits an array into two groups based on a predicate.
286
- * First group contains elements that satisfy the predicate,
287
- * second group contains the rest.
288
- *
289
- * @example
290
- * ```ts
291
- * pipe([1, 2, 3, 4], Arr.partition(n => n % 2 === 0)); // [[2, 4], [1, 3]]
292
- * ```
293
- */
294
- export const partition: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly [readonly A[], readonly A[]];
295
- /**
296
- * Narrows a list of Maybe values down to a list of their underlying values,
297
- * discarding all None instances.
298
- *
299
- * @example
300
- * ```ts
301
- * Arr.compact([Maybe.make.some(1), Maybe.make.none(), Maybe.make.some(3)]); // [1, 3]
302
- * ```
303
- */
304
- export const compact: <A>(data: readonly Maybe<A>[]) => readonly A[];
305
- /**
306
- * Separates an array of Result values into two separate lists of errors and successes.
307
- * Returns a tuple containing `[errors, successes]`.
308
- *
309
- * @example
310
- * ```ts
311
- * Arr.separate([Result.make.ok(1), Result.make.err("bad"), Result.make.ok(3)]); // [["bad"], [1, 3]]
312
- * ```
313
- */
314
- export const separate: <E, A>(data: readonly Result<E, A>[]) => readonly [readonly E[], readonly A[]];
315
- /**
316
- * Maps each element to a Result, and separates the results into a tuple of failures and successes.
317
- *
318
- * @example
319
- * ```ts
320
- * pipe(
321
- * [1, 2, 3, 4],
322
- * Arr.partitionMap(n => n % 2 === 0 ? Result.make.ok(n) : Result.make.err(`odd: ${n}`))
323
- * ); // [["odd: 1", "odd: 3"], [2, 4]]
324
- * ```
325
- */
326
- export const partitionMap: <A, E, B>(f: (a: A) => Result<E, B>) => (data: readonly A[]) => readonly [readonly E[], readonly B[]];
327
- /**
328
- * Groups elements by a key function.
329
- *
330
- * @example
331
- * ```ts
332
- * pipe(
333
- * ["apple", "avocado", "banana"],
334
- * Arr.groupBy(s => s[0])
335
- * ); // { a: ["apple", "avocado"], b: ["banana"] }
336
- * ```
337
- */
338
- export const groupBy: <A>(f: (a: A) => string) => (data: readonly A[]) => Record<string, NonEmptyArr<A>>;
339
- /**
340
- * Removes duplicate elements using strict equality.
341
- *
342
- * @example
343
- * ```ts
344
- * Arr.uniq([1, 2, 2, 3, 1]); // [1, 2, 3]
345
- * ```
346
- */
347
- export const uniq: <A>(data: readonly A[]) => readonly A[];
348
- /**
349
- * Removes duplicate elements by comparing the result of a key function.
350
- *
351
- * @example
352
- * ```ts
353
- * pipe(
354
- * [{id: 1, name: "a"}, {id: 1, name: "b"}, {id: 2, name: "c"}],
355
- * Arr.uniqBy(x => x.id)
356
- * ); // [{id: 1, name: "a"}, {id: 2, name: "c"}]
357
- * ```
358
- */
359
- export const uniqBy: <A, B>(f: (a: A) => B) => (data: readonly A[]) => readonly A[];
360
- /**
361
- * Removes duplicate elements using a custom equality check.
362
- * Preserves the order of first occurrences. Complements `uniq` (reference equality)
363
- * and `uniqBy` (key extraction).
364
- *
365
- * @example
366
- * ```ts
367
- * type Point = { x: number; y: number };
368
- * const eqPoint: Equality<Point> = (a, b) => a.x === b.x && a.y === b.y;
369
- *
370
- * pipe(
371
- * [{ x: 1, y: 1 }, { x: 2, y: 2 }, { x: 1, y: 1 }],
372
- * Arr.uniqWith(eqPoint),
373
- * ); // [{ x: 1, y: 1 }, { x: 2, y: 2 }]
374
- * ```
375
- */
376
- export const uniqWith: <A>(eq: Equality<A>) => (data: readonly A[]) => readonly A[];
377
- /**
378
- * Sorts an array using a comparison function. Returns a new array.
379
- * To sort with a typed `Ordering<A>`, prefer `Arr.sortWith`.
380
- *
381
- * @example
382
- * ```ts
383
- * pipe([3, 1, 2], Arr.sortBy((a, b) => a - b)); // [1, 2, 3]
384
- * ```
385
- */
386
- export const sortBy: <A>(compare: (a: A, b: A) => number) => (data: readonly A[]) => readonly A[];
387
- /**
388
- * Sorts an array using an `Ordering<A>`. Returns a new array without mutating the original.
389
- * Use this over `sortBy` when you have a typed `Ordering<A>` from the `Ordering` module.
390
- *
391
- * @example
392
- * ```ts
393
- * pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
394
- *
395
- * type Product = { price: number };
396
- * const products: Product[] = [{ price: 20 }, { price: 10 }];
397
- * const byPrice = pipe(Ordering.number, Ordering.by((p: Product) => p.price));
398
- * pipe(products, Arr.sortWith(byPrice));
399
- * ```
400
- */
401
- export const sortWith: <A>(ord: Ordering<A>) => (data: readonly A[]) => readonly A[];
402
- /**
403
- * Pairs up elements from two arrays. Stops at the shorter array.
404
- *
405
- * @example
406
- * ```ts
407
- * pipe([1, 2, 3], Arr.zip(["a", "b"])); // [[1, "a"], [2, "b"]]
408
- * ```
409
- */
410
- export const zip: <B>(other: readonly B[]) => <A>(data: readonly A[]) => readonly (readonly [A, B])[];
411
- /**
412
- * Combines elements from two arrays using a function. Stops at the shorter array.
413
- *
414
- * @example
415
- * ```ts
416
- * pipe([1, 2], Arr.zipWith((a: number, b: string) => `${a}${b}`)(["a", "b"])); // ["1a", "2b"]
417
- * ```
418
- */
419
- export const zipWith: <A, B, C>(f: (a: A, b: B) => C) => (other: readonly B[]) => (data: readonly A[]) => readonly C[];
420
- /**
421
- * Inserts a separator between every element.
422
- *
423
- * @example
424
- * ```ts
425
- * pipe([1, 2, 3], Arr.intersperse(0)); // [1, 0, 2, 0, 3]
426
- * ```
427
- */
428
- export const intersperse: <A>(sep: A) => (data: readonly A[]) => readonly A[];
429
- /**
430
- * Concatenates a standard array with another array.
431
- *
432
- * @example
433
- * ```ts
434
- * pipe([1, 2], Arr.concat([3, 4])); // [1, 2, 3, 4]
435
- * ```
436
- */
437
- export const concat: <A>(other: readonly A[]) => (data: readonly A[]) => readonly A[];
438
- /**
439
- * Splits an array into chunks of the given size.
440
- *
441
- * @example
442
- * ```ts
443
- * pipe([1, 2, 3, 4, 5], Arr.chunksOf(2)); // [[1, 2], [3, 4], [5]]
444
- * ```
445
- */
446
- export const chunksOf: (n: number) => <A>(data: readonly A[]) => readonly (readonly A[])[];
447
- /**
448
- * Flattens a nested array by one level.
449
- *
450
- * @example
451
- * ```ts
452
- * Arr.flatten([[1, 2], [3], [4, 5]]); // [1, 2, 3, 4, 5]
453
- * ```
454
- */
455
- export const flatten: <A>(data: readonly (readonly A[])[]) => readonly A[];
456
- /**
457
- * Maps each element to an array and flattens the result.
458
- *
459
- * @example
460
- * ```ts
461
- * pipe([1, 2, 3], Arr.flatMap(n => [n, n * 10])); // [1, 10, 2, 20, 3, 30]
462
- * ```
463
- */
464
- export const flatMap: <A, B>(f: (a: A) => readonly B[]) => (data: readonly A[]) => readonly B[];
465
- /**
466
- * Reduces an array from the left.
467
- *
468
- * @example
469
- * ```ts
470
- * pipe([1, 2, 3], Arr.reduce(0, (acc, n) => acc + n)); // 6
471
- * ```
472
- */
473
- export const reduce: <A, B>(initial: B, f: (acc: B, a: A) => B) => (data: readonly A[]) => B;
474
- interface TaskTraverse {
475
- <A, B>(f: (a: A) => Task<B>): (data: readonly A[]) => Task<readonly B[]>;
476
- Result: typeof ArrTaskResult.traverse;
477
- }
478
- interface TaskSequence {
479
- <A>(data: readonly Task<A>[]): Task<readonly A[]>;
480
- Result: typeof ArrTaskResult.sequence;
481
- }
482
- export namespace traverse {
483
- const Maybe: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => Maybe<readonly B[]>;
484
- const Result: <E, A, B>(f: (a: A) => Result<E, B>) => (data: readonly A[]) => Result<E, readonly B[]>;
485
- const Task: TaskTraverse;
486
- }
487
- export namespace sequence {
488
- const Maybe: <A>(data: readonly Maybe<A>[]) => Maybe<readonly A[]>;
489
- const Result: <E, A>(data: readonly Result<E, A>[]) => Result<E, readonly A[]>;
490
- const Task: TaskSequence;
491
- }
492
- export namespace is {
493
- /**
494
- * Returns true if the array is empty.
495
- *
496
- * @example
497
- * ```ts
498
- * Arr.is.empty([]); // true
499
- * Arr.is.empty([1]); // false
500
- * ```
501
- */
502
- const empty: <A>(data: readonly A[]) => data is readonly [];
503
- /**
504
- * Returns true if the array is non-empty (type guard).
505
- *
506
- * @example
507
- * ```ts
508
- * Arr.is.nonEmpty([1, 2]); // true
509
- * Arr.is.nonEmpty([]); // false
510
- * ```
511
- */
512
- const nonEmpty: <A>(data: readonly A[]) => data is NonEmpty<A>;
513
- }
514
- /**
515
- * Prepends a value to the beginning of an array, returning a NonEmptyArr.
516
- *
517
- * @example
518
- * ```ts
519
- * pipe([1, 2], Arr.prepend(0)); // [0, 1, 2]
520
- * ```
521
- */
522
- export const prepend: <A>(value: A) => (data: readonly A[]) => NonEmpty<A>;
523
- /**
524
- * Appends a value to the end of an array, returning a NonEmptyArr.
525
- *
526
- * @example
527
- * ```ts
528
- * pipe([1, 2], Arr.append(3)); // [1, 2, 3]
529
- * ```
530
- */
531
- export const append: <A>(value: A) => (data: readonly A[]) => NonEmpty<A>;
532
- /**
533
- * Returns the length of an array.
534
- *
535
- * @example
536
- * ```ts
537
- * Arr.size([1, 2, 3]); // 3
538
- * ```
539
- */
540
- export const size: <A>(data: readonly A[]) => number;
541
- /**
542
- * Returns true if any element satisfies the predicate.
543
- *
544
- * @example
545
- * ```ts
546
- * pipe([1, 2, 3], Arr.some(n => n > 2)); // true
547
- * ```
548
- */
549
- export const some: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => boolean;
550
- /**
551
- * Returns true if all elements satisfy the predicate.
552
- *
553
- * @example
554
- * ```ts
555
- * pipe([1, 2, 3], Arr.every(n => n > 0)); // true
556
- * ```
557
- */
558
- export const every: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => boolean;
559
- /**
560
- * Reverses an array. Returns a new array.
561
- *
562
- * @example
563
- * ```ts
564
- * Arr.reverse([1, 2, 3]); // [3, 2, 1]
565
- * ```
566
- */
567
- export const reverse: <A>(data: readonly A[]) => readonly A[];
568
- /**
569
- * Returns a new array with `item` inserted before the element at `index`.
570
- * Negative indices are clamped to 0; indices beyond the array length append to the end.
571
- *
572
- * @example
573
- * ```ts
574
- * pipe([1, 2, 3], Arr.insertAt(1, 99)); // [1, 99, 2, 3]
575
- * pipe([1, 2, 3], Arr.insertAt(0, 99)); // [99, 1, 2, 3]
576
- * pipe([1, 2, 3], Arr.insertAt(3, 99)); // [1, 2, 3, 99]
577
- * ```
578
- */
579
- export const insertAt: <A>(index: number, item: A) => (data: readonly A[]) => readonly A[];
580
- /**
581
- * Returns a new array with the element at `index` removed.
582
- * Returns the original array unchanged if `index` is out of bounds.
583
- *
584
- * @example
585
- * ```ts
586
- * pipe([1, 2, 3], Arr.removeAt(1)); // [1, 3]
587
- * pipe([1, 2, 3], Arr.removeAt(0)); // [2, 3]
588
- * pipe([1, 2, 3], Arr.removeAt(5)); // [1, 2, 3]
589
- * ```
590
- */
591
- export const removeAt: (index: number) => <A>(data: readonly A[]) => readonly A[];
592
- /**
593
- * Takes the first n elements from an array.
594
- *
595
- * @example
596
- * ```ts
597
- * pipe([1, 2, 3, 4], Arr.take(2)); // [1, 2]
598
- * ```
599
- */
600
- export const take: (n: number) => <A>(data: readonly A[]) => readonly A[];
601
- /**
602
- * Drops the first n elements from an array.
603
- *
604
- * @example
605
- * ```ts
606
- * pipe([1, 2, 3, 4], Arr.drop(2)); // [3, 4]
607
- * ```
608
- */
609
- export const drop: (n: number) => <A>(data: readonly A[]) => readonly A[];
610
- /**
611
- * Takes elements from the start while the predicate holds.
612
- *
613
- * @example
614
- * ```ts
615
- * pipe([1, 2, 3, 1], Arr.takeWhile(n => n < 3)); // [1, 2]
616
- * ```
617
- */
618
- export const takeWhile: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly A[];
619
- /**
620
- * Drops elements from the start while the predicate holds.
621
- *
622
- * @example
623
- * ```ts
624
- * pipe([1, 2, 3, 1], Arr.dropWhile(n => n < 3)); // [3, 1]
625
- * ```
626
- */
627
- export const dropWhile: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly A[];
628
- /**
629
- * Like `reduce`, but returns every intermediate accumulator as an array.
630
- * The initial value is not included — the output has the same length as the input.
631
- *
632
- * @example
633
- * ```ts
634
- * pipe([1, 2, 3], Arr.scan(0, (acc, n) => acc + n)); // [1, 3, 6]
635
- * ```
636
- */
637
- export const scan: <A, B>(initial: B, f: (acc: B, a: A) => B) => (data: readonly A[]) => readonly B[];
638
- /**
639
- * Splits an array at an index into a `[before, after]` tuple.
640
- * Negative indices clamp to 0; indices beyond the array length clamp to the end.
641
- *
642
- * @example
643
- * ```ts
644
- * pipe([1, 2, 3, 4], Arr.splitAt(2)); // [[1, 2], [3, 4]]
645
- * pipe([1, 2, 3], Arr.splitAt(0)); // [[], [1, 2, 3]]
646
- * pipe([1, 2, 3], Arr.splitAt(10)); // [[1, 2, 3], []]
647
- * ```
648
- */
649
- export const splitAt: (index: number) => <A>(data: readonly A[]) => readonly [readonly A[], readonly A[]];
650
- /**
651
- * Partitions an array by applying a function returning `Maybe<B>`.
652
- * Elements returning `None` are gathered into `failures` (original `A` values);
653
- * elements returning `Some(b)` are gathered into `successes` (`B` values).
654
- *
655
- * @example
656
- * ```ts
657
- * const parseNumber = (s: string) => isNaN(Number(s)) ? Maybe.make.none() : Maybe.make.some(Number(s));
658
- * pipe(["1", "abc", "3"], Arr.partitionMaybe(parseNumber)); // [["abc"], [1, 3]]
659
- * ```
660
- */
661
- export const partitionMaybe: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => readonly [failures: readonly A[], successes: readonly B[]];
662
- /**
663
- * Safely looks up an element by index. Supports negative indices counting back from the end.
664
- * Returns `None` if the index is out of bounds.
665
- *
666
- * @example
667
- * ```ts
668
- * pipe([10, 20, 30], Arr.at(1)); // Some(20)
669
- * pipe([10, 20, 30], Arr.at(-1)); // Some(30)
670
- * pipe([10, 20, 30], Arr.at(5)); // None
671
- * ```
672
- */
673
- export const at: (index: number) => <A>(data: readonly A[]) => Maybe<A>;
674
- /**
675
- * Finds the first element in an array for which `f` returns `Some(b)`.
676
- *
677
- * @example
678
- * ```ts
679
- * pipe(
680
- * ["1", "a", "2"],
681
- * Arr.findMap((s) => isNaN(Number(s)) ? Maybe.make.none() : Maybe.make.some(Number(s)))
682
- * ); // Some(1)
683
- * ```
684
- */
685
- export const findMap: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => Maybe<B>;
686
- /**
687
- * Indexes elements of an array into a `ReadonlyMap<K, A>` using a key extraction function.
688
- *
689
- * @example
690
- * ```ts
691
- * pipe(
692
- * [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }],
693
- * Arr.indexBy((u) => u.id)
694
- * ); // ReadonlyMap { 1 => { id: 1, name: "Alice" }, 2 => { id: 2, name: "Bob" } }
695
- * ```
696
- */
697
- export const indexBy: <A, K>(keyFn: (a: A) => K) => (data: readonly A[]) => ReadonlyMap<K, A>;
698
- /**
699
- * Counts occurrences of each element in an array, returning a `ReadonlyMap<A, number>`.
700
- *
701
- * @example
702
- * ```ts
703
- * Arr.frequencies(["a", "b", "a", "c", "b", "a"]);
704
- * // ReadonlyMap { "a" => 3, "b" => 2, "c" => 1 }
705
- * ```
706
- */
707
- export const frequencies: <A>(data: readonly A[]) => ReadonlyMap<A, number>;
708
- /**
709
- * Groups consecutive elements that share the same key returned by `keyFn`.
710
- *
711
- * @example
712
- * ```ts
713
- * pipe(
714
- * [1, 1, 2, 3, 3, 1],
715
- * Arr.chunkBy((n) => n)
716
- * ); // [[1, 1], [2], [3, 3], [1]]
717
- * ```
718
- */
719
- export const chunkBy: <A, K>(keyFn: (a: A) => K) => (data: readonly A[]) => readonly (readonly A[])[];
720
- /**
721
- * Removes consecutive duplicate elements.
722
- * An optional `Equality<A>` can be provided (defaults to `Object.is`).
723
- *
724
- * @example
725
- * ```ts
726
- * Arr.dedupeAdjacent()([1, 1, 2, 2, 1, 3]); // [1, 2, 1, 3]
727
- * ```
728
- */
729
- export const dedupeAdjacent: <A>(eq?: Equality<A>) => (data: readonly A[]) => readonly A[];
730
- /**
731
- * Produces a sliding window of `size` elements over an array, advancing by `step` (default `1`).
732
- * Returns an empty array if `size <= 0` or `size > data.length`.
733
- *
734
- * @example
735
- * ```ts
736
- * pipe([1, 2, 3, 4], Arr.windowed(2)); // [[1, 2], [2, 3], [3, 4]]
737
- * pipe([1, 2, 3, 4], Arr.windowed(2, { step: 2 })); // [[1, 2], [3, 4]]
738
- * ```
739
- */
740
- export const windowed: (size: number, options?: {
42
+ interface TaskTraverse {
43
+ <A, B>(f: (a: A) => Task<B>): (data: readonly A[]) => Task<readonly B[]>;
44
+ Result: typeof ArrTaskResult.traverse;
45
+ }
46
+ interface TaskSequence {
47
+ <A>(data: readonly Task<A>[]): Task<readonly A[]>;
48
+ Result: typeof ArrTaskResult.sequence;
49
+ }
50
+ declare const Arr: {
51
+ head: <A>(data: readonly A[]) => Maybe<A>;
52
+ last: <A>(data: readonly A[]) => Maybe<A>;
53
+ tail: <A>(data: readonly A[]) => Maybe<readonly A[]>;
54
+ init: <A>(data: readonly A[]) => Maybe<readonly A[]>;
55
+ findFirst: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => Maybe<A>;
56
+ findLast: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => Maybe<A>;
57
+ findIndex: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => Maybe<number>;
58
+ map: <A, B>(f: (a: A) => B) => (data: readonly A[]) => readonly B[];
59
+ mapWithIndex: <A, B>(f: (i: number, a: A) => B) => (data: readonly A[]) => readonly B[];
60
+ filter: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly A[];
61
+ filterMap: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => readonly B[];
62
+ partition: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly [readonly A[], readonly A[]];
63
+ compact: <A>(data: readonly Maybe<A>[]) => readonly A[];
64
+ separate: <E, A>(data: readonly Result<E, A>[]) => readonly [readonly E[], readonly A[]];
65
+ partitionMap: <A, E, B>(f: (a: A) => Result<E, B>) => (data: readonly A[]) => readonly [readonly E[], readonly B[]];
66
+ groupBy: <A>(f: (a: A) => string) => (data: readonly A[]) => Record<string, NonEmptyArr<A>>;
67
+ uniq: <A>(data: readonly A[]) => readonly A[];
68
+ uniqBy: <A, B>(f: (a: A) => B) => (data: readonly A[]) => readonly A[];
69
+ uniqWith: <A>(eq: Equality<A>) => (data: readonly A[]) => readonly A[];
70
+ sortBy: <A>(compare: (a: A, b: A) => number) => (data: readonly A[]) => readonly A[];
71
+ sortWith: <A>(ord: Ordering<A>) => (data: readonly A[]) => readonly A[];
72
+ zip: <B>(other: readonly B[]) => <A>(data: readonly A[]) => readonly (readonly [A, B])[];
73
+ zipWith: <A, B, C>(f: (a: A, b: B) => C) => (other: readonly B[]) => (data: readonly A[]) => readonly C[];
74
+ intersperse: <A>(sep: A) => (data: readonly A[]) => readonly A[];
75
+ concat: <A>(other: readonly A[]) => (data: readonly A[]) => readonly A[];
76
+ chunksOf: (n: number) => <A>(data: readonly A[]) => readonly (readonly A[])[];
77
+ flatten: <A>(data: readonly (readonly A[])[]) => readonly A[];
78
+ flatMap: <A, B>(f: (a: A) => readonly B[]) => (data: readonly A[]) => readonly B[];
79
+ reduce: <A, B>(initial: B, f: (acc: B, a: A) => B) => (data: readonly A[]) => B;
80
+ prepend: <A>(value: A) => (data: readonly A[]) => NonEmptyArr<A>;
81
+ append: <A>(value: A) => (data: readonly A[]) => NonEmptyArr<A>;
82
+ size: <A>(data: readonly A[]) => number;
83
+ some: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => boolean;
84
+ every: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => boolean;
85
+ reverse: <A>(data: readonly A[]) => readonly A[];
86
+ insertAt: <A>(index: number, item: A) => (data: readonly A[]) => readonly A[];
87
+ removeAt: (index: number) => <A>(data: readonly A[]) => readonly A[];
88
+ take: (n: number) => <A>(data: readonly A[]) => readonly A[];
89
+ drop: (n: number) => <A>(data: readonly A[]) => readonly A[];
90
+ takeWhile: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly A[];
91
+ dropWhile: <A>(predicate: (a: A) => boolean) => (data: readonly A[]) => readonly A[];
92
+ scan: <A, B>(initial: B, f: (acc: B, a: A) => B) => (data: readonly A[]) => readonly B[];
93
+ splitAt: (index: number) => <A>(data: readonly A[]) => readonly [readonly A[], readonly A[]];
94
+ partitionMaybe: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => readonly [failures: readonly A[], successes: readonly B[]];
95
+ at: (index: number) => <A>(data: readonly A[]) => Maybe<A>;
96
+ findMap: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => Maybe<B>;
97
+ indexBy: <A, K>(keyFn: (a: A) => K) => (data: readonly A[]) => ReadonlyMap<K, A>;
98
+ frequencies: <A>(data: readonly A[]) => ReadonlyMap<A, number>;
99
+ chunkBy: <A, K>(keyFn: (a: A) => K) => (data: readonly A[]) => readonly (readonly A[])[];
100
+ dedupeAdjacent: <A>(eq?: Equality<A>) => (data: readonly A[]) => readonly A[];
101
+ windowed: (windowSize: number, options?: {
741
102
  step?: number;
742
103
  }) => <A>(data: readonly A[]) => readonly (readonly A[])[];
743
- /**
744
- * Generates an array from an initial seed state until `f` returns `None`.
745
- *
746
- * @example
747
- * ```ts
748
- * Arr.unfold(1, (n) => n > 3 ? Maybe.make.none() : Maybe.make.some([n, n + 1]));
749
- * // [1, 2, 3]
750
- * ```
751
- */
752
- export const unfold: <A, S>(initial: S, f: (state: S) => Maybe<readonly [A, S]>) => readonly A[];
753
- export const NonEmpty: typeof ArrNonEmpty;
754
- export { };
104
+ unfold: <A, S>(initial: S, f: (state: S) => Maybe<readonly [A, S]>) => readonly A[];
105
+ from: {
106
+ Array: <A>(data: readonly A[]) => Maybe<NonEmptyArr<A>>;
107
+ };
108
+ is: {
109
+ empty: <A>(data: readonly A[]) => data is readonly [];
110
+ nonEmpty: <A>(data: readonly A[]) => data is NonEmptyArr<A>;
111
+ };
112
+ traverse: {
113
+ Maybe: <A, B>(f: (a: A) => Maybe<B>) => (data: readonly A[]) => Maybe<readonly B[]>;
114
+ Result: <E, A, B>(f: (a: A) => Result<E, B>) => (data: readonly A[]) => Result<E, readonly B[]>;
115
+ Task: TaskTraverse;
116
+ };
117
+ sequence: {
118
+ Maybe: <A>(data: readonly Maybe<A>[]) => Maybe<readonly A[]>;
119
+ Result: <E, A>(data: readonly Result<E, A>[]) => Result<E, readonly A[]>;
120
+ Task: TaskSequence;
121
+ };
122
+ NonEmpty: {
123
+ singleton: <A>(value: A) => NonEmptyArr<A>;
124
+ from: {
125
+ Array: <A>(data: readonly A[]) => Maybe<NonEmptyArr<A>>;
126
+ };
127
+ head: <A>(data: NonEmptyArr<A>) => A;
128
+ last: <A>(data: NonEmptyArr<A>) => A;
129
+ tail: <A>(data: NonEmptyArr<A>) => readonly A[];
130
+ reduce: <A>(f: (acc: A, a: A) => A) => (data: NonEmptyArr<A>) => A;
131
+ map: <A, B>(f: (a: A) => B) => (data: NonEmptyArr<A>) => NonEmptyArr<B>;
132
+ mapWithIndex: <A, B>(f: (i: number, a: A) => B) => (data: NonEmptyArr<A>) => NonEmptyArr<B>;
133
+ intersperse: <A>(sep: A) => (data: NonEmptyArr<A>) => NonEmptyArr<A>;
134
+ concat: <A>(other: readonly A[]) => (data: NonEmptyArr<A>) => NonEmptyArr<A>;
135
+ reverse: <A>(data: NonEmptyArr<A>) => NonEmptyArr<A>;
136
+ };
137
+ };
138
+ declare namespace Arr {
139
+ type NonEmpty<A> = NonEmptyArr<A>;
755
140
  }
756
141
 
757
142
  /**
@@ -769,8 +154,62 @@ declare namespace Arr {
769
154
  * ); // Some(150n)
770
155
  * ```
771
156
  */
772
- declare namespace BigNum {
773
- namespace from {
157
+ declare const BigNum: {
158
+ is: {
159
+ /**
160
+ * Returns `true` when the bigint is equal to zero (`0n`).
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * BigNum.is.zero(0n); // true
165
+ * BigNum.is.zero(5n); // false
166
+ * ```
167
+ */
168
+ zero: (b: bigint) => boolean;
169
+ /**
170
+ * Returns `true` when the bigint is an even integer.
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * BigNum.is.even(4n); // true
175
+ * BigNum.is.even(3n); // false
176
+ * ```
177
+ */
178
+ even: (b: bigint) => boolean;
179
+ /**
180
+ * Returns `true` when the bigint is an odd integer.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * BigNum.is.odd(3n); // true
185
+ * BigNum.is.odd(4n); // false
186
+ * ```
187
+ */
188
+ odd: (b: bigint) => boolean;
189
+ /**
190
+ * Returns `true` when the bigint is strictly greater than zero (`0n`).
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * BigNum.is.positive(5n); // true
195
+ * BigNum.is.positive(0n); // false
196
+ * BigNum.is.positive(-5n); // false
197
+ * ```
198
+ */
199
+ positive: (b: bigint) => boolean;
200
+ /**
201
+ * Returns `true` when the bigint is strictly less than zero (`0n`).
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * BigNum.is.negative(-5n); // true
206
+ * BigNum.is.negative(0n); // false
207
+ * BigNum.is.negative(5n); // false
208
+ * ```
209
+ */
210
+ negative: (b: bigint) => boolean;
211
+ };
212
+ from: {
774
213
  /**
775
214
  * Safely parses a string into a `bigint`. Returns `None` if parsing fails.
776
215
  *
@@ -780,7 +219,7 @@ declare namespace BigNum {
780
219
  * BigNum.from.string("abc"); // None
781
220
  * ```
782
221
  */
783
- const string: (s: string) => Maybe<bigint>;
222
+ string: (s: string) => Maybe<bigint>;
784
223
  /**
785
224
  * Safely converts a number into a `bigint`. Returns `None` for floats, `NaN`, or non-safe integers.
786
225
  *
@@ -790,9 +229,9 @@ declare namespace BigNum {
790
229
  * BigNum.from.number(3.14); // None
791
230
  * ```
792
231
  */
793
- const number: (n: number) => Maybe<bigint>;
794
- }
795
- namespace to {
232
+ number: (n: number) => Maybe<bigint>;
233
+ };
234
+ to: {
796
235
  /**
797
236
  * Safely converts a `bigint` to a `number`. Returns `None` if the value is outside JavaScript's safe integer range.
798
237
  *
@@ -802,8 +241,8 @@ declare namespace BigNum {
802
241
  * BigNum.to.number(9007199254740993n); // None
803
242
  * ```
804
243
  */
805
- const number: (b: bigint) => Maybe<number>;
806
- }
244
+ number: (b: bigint) => Maybe<number>;
245
+ };
807
246
  /**
808
247
  * Adds `b` to `a`. Data-last curried signature: `add(b)(a)` = `a + b`.
809
248
  *
@@ -812,7 +251,7 @@ declare namespace BigNum {
812
251
  * pipe(10n, BigNum.add(5n)); // 15n
813
252
  * ```
814
253
  */
815
- const add: (b: bigint) => (a: bigint) => bigint;
254
+ add: (b: bigint) => (a: bigint) => bigint;
816
255
  /**
817
256
  * Subtracts `b` from `a`. Data-last curried signature: `sub(b)(a)` = `a - b`.
818
257
  *
@@ -821,7 +260,7 @@ declare namespace BigNum {
821
260
  * pipe(10n, BigNum.sub(3n)); // 7n
822
261
  * ```
823
262
  */
824
- const sub: (b: bigint) => (a: bigint) => bigint;
263
+ sub: (b: bigint) => (a: bigint) => bigint;
825
264
  /**
826
265
  * Multiplies `a` by `b`. Data-last curried signature: `mul(b)(a)` = `a * b`.
827
266
  *
@@ -830,7 +269,7 @@ declare namespace BigNum {
830
269
  * pipe(6n, BigNum.mul(7n)); // 42n
831
270
  * ```
832
271
  */
833
- const mul: (b: bigint) => (a: bigint) => bigint;
272
+ mul: (b: bigint) => (a: bigint) => bigint;
834
273
  /**
835
274
  * Divides `a` by `b`. Returns `None` if `b` is `0n`.
836
275
  *
@@ -840,7 +279,7 @@ declare namespace BigNum {
840
279
  * pipe(5n, BigNum.div(0n)); // None
841
280
  * ```
842
281
  */
843
- const div: (b: bigint) => (a: bigint) => Maybe<bigint>;
282
+ div: (b: bigint) => (a: bigint) => Maybe<bigint>;
844
283
  /**
845
284
  * Computes remainder of `a / b`. Returns `None` if `b` is `0n`.
846
285
  *
@@ -850,7 +289,7 @@ declare namespace BigNum {
850
289
  * pipe(5n, BigNum.mod(0n)); // None
851
290
  * ```
852
291
  */
853
- const mod: (b: bigint) => (a: bigint) => Maybe<bigint>;
292
+ mod: (b: bigint) => (a: bigint) => Maybe<bigint>;
854
293
  /**
855
294
  * Clamps `a` between `min` and `max` (inclusive).
856
295
  *
@@ -859,7 +298,7 @@ declare namespace BigNum {
859
298
  * pipe(150n, BigNum.clamp(0n, 100n)); // 100n
860
299
  * ```
861
300
  */
862
- const clamp: (min: bigint, max: bigint) => (a: bigint) => bigint;
301
+ clamp: (min: bigint, max: bigint) => (a: bigint) => bigint;
863
302
  /**
864
303
  * Returns `true` if `a` is in the range `[start, end)` (inclusive start, exclusive end).
865
304
  *
@@ -868,7 +307,7 @@ declare namespace BigNum {
868
307
  * pipe(5n, BigNum.inRange(1n, 10n)); // true
869
308
  * ```
870
309
  */
871
- const inRange: (start: bigint, end: bigint) => (a: bigint) => boolean;
310
+ inRange: (start: bigint, end: bigint) => (a: bigint) => boolean;
872
311
  /**
873
312
  * Returns absolute value of a `bigint`.
874
313
  *
@@ -877,7 +316,7 @@ declare namespace BigNum {
877
316
  * BigNum.abs(-42n); // 42n
878
317
  * ```
879
318
  */
880
- const abs: (a: bigint) => bigint;
319
+ abs: (a: bigint) => bigint;
881
320
  /**
882
321
  * Returns the minimum of `a` and `b`.
883
322
  *
@@ -886,7 +325,7 @@ declare namespace BigNum {
886
325
  * pipe(10n, BigNum.min(5n)); // 5n
887
326
  * ```
888
327
  */
889
- const min: (b: bigint) => (a: bigint) => bigint;
328
+ min: (b: bigint) => (a: bigint) => bigint;
890
329
  /**
891
330
  * Returns the maximum of `a` and `b`.
892
331
  *
@@ -895,472 +334,362 @@ declare namespace BigNum {
895
334
  * pipe(10n, BigNum.max(5n)); // 10n
896
335
  * ```
897
336
  */
898
- const max: (b: bigint) => (a: bigint) => bigint;
899
- }
337
+ max: (b: bigint) => (a: bigint) => bigint;
338
+ };
900
339
 
901
- /**
902
- * A branded type representing a key-value dictionary with at least one entry.
903
- */
904
- type NonEmptyMap<K, V> = Brand<NonEmpty<"Dict">, ReadonlyMap<K, V>>;
905
- /**
906
- * Functional utilities for key-value dictionaries (`ReadonlyMap<K, V>`). All functions are pure
907
- * and data-last — they compose naturally with `pipe`.
908
- *
909
- * Unlike plain objects (`Rec`), dictionaries support any key type, preserve insertion order, and
910
- * make membership checks explicit via `lookup` returning `Maybe`.
911
- *
912
- * @example
913
- * ```ts
914
- * import { Dict } from "@nlozgachev/pipelined/data";
915
- * import { pipe } from "@nlozgachev/pipelined/composition";
916
- *
917
- * const scores = pipe(
918
- * Dict.from.entries([["alice", 10], ["bob", 8], ["carol", 10]] as const),
919
- * Dict.filter(n => n >= 10),
920
- * Dict.map(n => `${n} points`),
921
- * );
922
- * // ReadonlyMap { "alice" => "10 points", "carol" => "10 points" }
923
- * ```
924
- */
925
- declare namespace DictNonEmpty {
926
- /**
927
- * Creates a NonEmptyMap containing a single key-value entry.
928
- *
929
- * @example
930
- * ```ts
931
- * Dict.NonEmpty.singleton("name", "Alice"); // ReadonlyMap { "name" => "Alice" }
932
- * ```
933
- */
934
- const singleton: <K, V>(key: K, value: V) => NonEmptyMap<K, V>;
935
- namespace from {
340
+ type BoolMatchCases<A, B> = {
341
+ readonly true: () => A;
342
+ readonly false: () => B;
343
+ };
344
+ declare const Bool: {
345
+ is: {
936
346
  /**
937
- * Returns Some containing NonEmptyMap if the map is not empty, None otherwise.
347
+ * Type guard — checks if a value is a primitive boolean.
938
348
  *
939
349
  * @example
940
350
  * ```ts
941
- * Dict.NonEmpty.from.Map(Dict.from.entries([["a", 1]])); // Some(ReadonlyMap { "a" => 1 })
942
- * Dict.NonEmpty.from.Map(Dict.empty()); // None
351
+ * Bool.is.boolean(true); // true
352
+ * Bool.is.boolean(false); // true
353
+ * Bool.is.boolean("true"); // false
354
+ * Bool.is.boolean(null); // false
943
355
  * ```
944
356
  */
945
- const Map: <K, V>(m: ReadonlyMap<K, V>) => Maybe<NonEmptyMap<K, V>>;
946
- }
947
- /**
948
- * Returns a non-empty array of keys, in insertion order.
949
- *
950
- * @example
951
- * ```ts
952
- * Dict.NonEmpty.keys(Dict.NonEmpty.singleton("a", 1)); // ["a"]
953
- * ```
954
- */
955
- const keys: <K, V>(m: NonEmptyMap<K, V>) => NonEmptyArr<K>;
956
- /**
957
- * Returns a non-empty array of values, in insertion order.
958
- *
959
- * @example
960
- * ```ts
961
- * Dict.NonEmpty.values(Dict.NonEmpty.singleton("a", 1)); // [1]
962
- * ```
963
- */
964
- const values: <K, V>(m: NonEmptyMap<K, V>) => NonEmptyArr<V>;
965
- /**
966
- * Returns a non-empty array of entry tuples, in insertion order.
967
- *
968
- * @example
969
- * ```ts
970
- * Dict.NonEmpty.entries(Dict.NonEmpty.singleton("a", 1)); // [["a", 1]]
971
- * ```
972
- */
973
- const entries: <K, V>(m: NonEmptyMap<K, V>) => NonEmptyArr<readonly [K, V]>;
974
- /**
975
- * Reduces a NonEmptyMap's values from the left without an initial seed value.
976
- *
977
- * @example
978
- * ```ts
979
- * pipe(Dict.NonEmpty.singleton("a", 1), Dict.NonEmpty.reduce((a, b) => a + b)); // 1
980
- * ```
981
- */
982
- const reduce: <V>(f: (acc: V, value: V) => V) => <K>(m: NonEmptyMap<K, V>) => V;
983
- /**
984
- * Transforms each value in the non-empty dictionary.
985
- *
986
- * @example
987
- * ```ts
988
- * pipe(Dict.NonEmpty.singleton("a", 1), Dict.NonEmpty.map(n => n * 2));
989
- * // ReadonlyMap { "a" => 2 }
990
- * ```
991
- */
992
- const map: <A, B>(f: (a: A) => B) => <K>(m: NonEmptyMap<K, A>) => NonEmptyMap<K, B>;
993
- /**
994
- * Transforms each value in the non-empty dictionary, also receiving the key.
995
- *
996
- * @example
997
- * ```ts
998
- * pipe(Dict.NonEmpty.singleton("a", 1), Dict.NonEmpty.mapWithKey((k, v) => `${k}:${v}`));
999
- * // ReadonlyMap { "a" => "a:1" }
1000
- * ```
1001
- */
1002
- const mapWithKey: <K, A, B>(f: (key: K, a: A) => B) => (m: NonEmptyMap<K, A>) => NonEmptyMap<K, B>;
1003
- }
1004
- declare namespace Dict {
1005
- /**
1006
- * A branded type representing a key-value dictionary with at least one entry.
1007
- */
1008
- type NonEmpty<K, V> = NonEmptyMap<K, V>;
1009
- namespace is {
357
+ boolean: (u: unknown) => u is boolean;
1010
358
  /**
1011
- * Returns `true` if the dictionary has no entries.
359
+ * Narrowing guard — checks if a value is strictly `true`.
1012
360
  *
1013
361
  * @example
1014
362
  * ```ts
1015
- * Dict.is.empty(Dict.empty()); // true
363
+ * Bool.is.true(true); // true
364
+ * Bool.is.true(false); // false
1016
365
  * ```
1017
366
  */
1018
- const empty: <K, V>(m: ReadonlyMap<K, V>) => boolean;
367
+ true: (u: unknown) => u is true;
1019
368
  /**
1020
- * Type guard to check if a dictionary is non-empty.
369
+ * Narrowing guard — checks if a value is strictly `false`.
1021
370
  *
1022
371
  * @example
1023
372
  * ```ts
1024
- * Dict.is.nonEmpty(Dict.from.entries([["a", 1]])); // true
1025
- * Dict.is.nonEmpty(Dict.empty()); // false
373
+ * Bool.is.false(false); // true
374
+ * Bool.is.false(true); // false
1026
375
  * ```
1027
376
  */
1028
- const nonEmpty: <K, V>(m: ReadonlyMap<K, V>) => m is NonEmpty<K, V>;
1029
- }
1030
- /**
1031
- * Creates an empty dictionary.
1032
- *
1033
- * @example
1034
- * ```ts
1035
- * Dict.empty<string, number>(); // ReadonlyMap {}
1036
- * ```
1037
- */
1038
- const empty: <K, V>() => ReadonlyMap<K, V>;
1039
- /**
1040
- * Creates a dictionary with a single entry.
1041
- *
1042
- * @example
1043
- * ```ts
1044
- * Dict.singleton("name", "Alice"); // ReadonlyMap { "name" => "Alice" }
1045
- * ```
1046
- */
1047
- const singleton: <K, V>(key: K, value: V) => ReadonlyMap<K, V>;
1048
- namespace from {
377
+ false: (u: unknown) => u is false;
1049
378
  /**
1050
- * Creates a dictionary from an array of key-value pairs.
379
+ * Type guard — checks if a value is truthy (not `false`, `0`, `0n`, `""`, `null`, `undefined`, or `NaN`).
1051
380
  *
1052
381
  * @example
1053
382
  * ```ts
1054
- * Dict.from.entries([["a", 1], ["b", 2]]); // ReadonlyMap { "a" => 1, "b" => 2 }
383
+ * Bool.is.truthy("hello"); // true
384
+ * Bool.is.truthy(42); // true
385
+ * Bool.is.truthy(0); // false
386
+ * Bool.is.truthy(null); // false
1055
387
  * ```
1056
388
  */
1057
- const entries: <K, V>(entries: readonly (readonly [K, V])[]) => ReadonlyMap<K, V>;
389
+ truthy: <T>(u: T) => u is Exclude<T, false | 0 | 0n | "" | null | undefined>;
1058
390
  /**
1059
- * Creates a dictionary from a plain object. Keys are always strings.
391
+ * Type guard — checks if a value is falsy (`false`, `0`, `0n`, `""`, `null`, `undefined`, or `NaN`).
1060
392
  *
1061
393
  * @example
1062
394
  * ```ts
1063
- * Dict.from.Record({ a: 1, b: 2 }); // ReadonlyMap { "a" => 1, "b" => 2 }
395
+ * Bool.is.falsy(""); // true
396
+ * Bool.is.falsy(null); // true
397
+ * Bool.is.falsy("content"); // false
1064
398
  * ```
1065
399
  */
1066
- const Record: <V>(rec: Readonly<Record<string, V>>) => ReadonlyMap<string, V>;
1067
- }
1068
- /**
1069
- * Groups elements of an array into a dictionary keyed by the result of `keyFn`. Each key maps
1070
- * to the array of elements that produced it, in insertion order. Uses the native `Map.groupBy`
1071
- * when available, falling back to a manual loop in older environments.
1072
- *
1073
- * @example
1074
- * ```ts
1075
- * pipe(
1076
- * [{ name: "alice", role: "admin" }, { name: "bob", role: "viewer" }, { name: "carol", role: "admin" }],
1077
- * Dict.groupBy(user => user.role),
1078
- * );
1079
- * // ReadonlyMap { "admin" => [alice, carol], "viewer" => [bob] }
1080
- * ```
1081
- */
1082
- const groupBy: <K, A>(keyFn: (a: A) => K) => (items: readonly A[]) => ReadonlyMap<K, readonly A[]>;
1083
- /**
1084
- * Returns `true` if the dictionary contains the given key.
1085
- *
1086
- * @example
1087
- * ```ts
1088
- * pipe(Dict.from.entries([["a", 1]]), Dict.has("a")); // true
1089
- * pipe(Dict.from.entries([["a", 1]]), Dict.has("b")); // false
1090
- * ```
1091
- */
1092
- const has: <K>(key: K) => <V>(m: ReadonlyMap<K, V>) => boolean;
1093
- /**
1094
- * Looks up a value by key, returning `Some(value)` if found and `None` if not.
1095
- *
1096
- * @example
1097
- * ```ts
1098
- * pipe(Dict.from.entries([["a", 1]]), Dict.lookup("a")); // Some(1)
1099
- * pipe(Dict.from.entries([["a", 1]]), Dict.lookup("b")); // None
1100
- * ```
1101
- */
1102
- const lookup: <K>(key: K) => <V>(m: ReadonlyMap<K, V>) => Maybe<V>;
1103
- /**
1104
- * Returns the number of entries in the dictionary.
1105
- *
1106
- * @example
1107
- * ```ts
1108
- * Dict.size(Dict.from.entries([["a", 1], ["b", 2]])); // 2
1109
- * ```
1110
- */
1111
- const size: <K, V>(m: ReadonlyMap<K, V>) => number;
400
+ falsy: (u: unknown) => u is false | 0 | 0n | "" | null | undefined;
401
+ };
1112
402
  /**
1113
- * Returns all keys as a readonly array, in insertion order.
403
+ * Unary boolean negation: inverts the given boolean value.
1114
404
  *
1115
405
  * @example
1116
406
  * ```ts
1117
- * Dict.keys(Dict.from.entries([["a", 1], ["b", 2]])); // ["a", "b"]
407
+ * Bool.not(true); // false
408
+ * Bool.not(false); // true
1118
409
  * ```
1119
410
  */
1120
- const keys: <K, V>(m: ReadonlyMap<K, V>) => readonly K[];
411
+ not: (b: boolean) => boolean;
1121
412
  /**
1122
- * Returns all values as a readonly array, in insertion order.
413
+ * Logical AND combinator. Returns `true` only if both `self` and `that` are `true`.
1123
414
  *
1124
- * @example
1125
- * ```ts
1126
- * Dict.values(Dict.from.entries([["a", 1], ["b", 2]])); // [1, 2]
1127
- * ```
1128
- */
1129
- const values: <K, V>(m: ReadonlyMap<K, V>) => readonly V[];
1130
- /**
1131
- * Returns all key-value pairs as a readonly array of tuples, in insertion order.
415
+ * Data-last: `pipe(self, Bool.and(that))`.
1132
416
  *
1133
417
  * @example
1134
418
  * ```ts
1135
- * Dict.entries(Dict.from.entries([["a", 1], ["b", 2]])); // [["a", 1], ["b", 2]]
419
+ * pipe(true, Bool.and(true)); // true
420
+ * pipe(true, Bool.and(false)); // false
1136
421
  * ```
1137
422
  */
1138
- const entries: <K, V>(m: ReadonlyMap<K, V>) => readonly (readonly [K, V])[];
423
+ and: (that: boolean) => (self: boolean) => boolean;
1139
424
  /**
1140
- * Returns a new dictionary with the given key set to the given value.
1141
- * If the key already exists, its value is replaced.
425
+ * Logical OR combinator. Returns `true` if either `self` or `that` is `true`.
1142
426
  *
1143
- * @example
1144
- * ```ts
1145
- * pipe(Dict.from.entries([["a", 1]]), Dict.insert("b", 2));
1146
- * // ReadonlyMap { "a" => 1, "b" => 2 }
1147
- * ```
1148
- */
1149
- const insert: <K, V>(key: K, value: V) => (m: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
1150
- /**
1151
- * Returns a new dictionary with the given key removed.
1152
- * If the key does not exist, the dictionary is returned unchanged.
427
+ * Data-last: `pipe(self, Bool.or(that))`.
1153
428
  *
1154
429
  * @example
1155
430
  * ```ts
1156
- * pipe(Dict.from.entries([["a", 1], ["b", 2]]), Dict.remove("a"));
1157
- * // ReadonlyMap { "b" => 2 }
431
+ * pipe(false, Bool.or(true)); // true
432
+ * pipe(false, Bool.or(false)); // false
1158
433
  * ```
1159
434
  */
1160
- const remove: <K, V>(key: K) => (m: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
435
+ or: (that: boolean) => (self: boolean) => boolean;
1161
436
  /**
1162
- * Returns a new dictionary with the value at `key` set by `f`. If the key does not exist,
1163
- * `f` receives `None`. If the key exists, `f` receives `Some(currentValue)`.
437
+ * Logical XOR (exclusive OR) combinator. Returns `true` if exactly one of `self` and `that` is `true`.
1164
438
  *
1165
- * Useful for incrementing counters, initialising defaults, or conditional updates.
439
+ * Data-last: `pipe(self, Bool.xor(that))`.
1166
440
  *
1167
441
  * @example
1168
442
  * ```ts
1169
- * const increment = (opt: Maybe<number>) => pipe(opt, Maybe.getOrElse(() => 0)) + 1;
1170
- * pipe(Dict.from.entries([["views", 5]]), Dict.upsert("views", increment)); // { views: 6 }
1171
- * pipe(Dict.from.entries([["views", 5]]), Dict.upsert("likes", increment)); // { views: 5, likes: 1 }
443
+ * pipe(true, Bool.xor(false)); // true
444
+ * pipe(true, Bool.xor(true)); // false
1172
445
  * ```
1173
446
  */
1174
- const upsert: <K, V>(key: K, f: (existing: Maybe<V>) => V) => (m: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
447
+ xor: (that: boolean) => (self: boolean) => boolean;
1175
448
  /**
1176
- * Transforms each value in the dictionary.
449
+ * Lazy logical AND combinator.
450
+ * If `self` is `false`, the `that` computation is never evaluated.
1177
451
  *
1178
- * @example
1179
- * ```ts
1180
- * pipe(Dict.from.entries([["a", 1], ["b", 2]]), Dict.map(n => n * 2));
1181
- * // ReadonlyMap { "a" => 2, "b" => 4 }
1182
- * ```
1183
- */
1184
- const map: <A, B>(f: (a: A) => B) => <K>(m: ReadonlyMap<K, A>) => ReadonlyMap<K, B>;
1185
- /**
1186
- * Transforms each value in the dictionary, also receiving the key.
452
+ * Data-last: `pipe(self, Bool.andLazy(that))`.
1187
453
  *
1188
454
  * @example
1189
455
  * ```ts
1190
- * pipe(Dict.from.entries([["a", 1], ["b", 2]]), Dict.mapWithKey((k, v) => `${k}:${v}`));
1191
- * // ReadonlyMap { "a" => "a:1", "b" => "b:2" }
456
+ * pipe(
457
+ * isCached,
458
+ * Bool.andLazy(() => checkPermissions())
459
+ * );
1192
460
  * ```
1193
461
  */
1194
- const mapWithKey: <K, A, B>(f: (key: K, a: A) => B) => (m: ReadonlyMap<K, A>) => ReadonlyMap<K, B>;
462
+ andLazy: (that: () => boolean) => (self: boolean) => boolean;
1195
463
  /**
1196
- * Returns a new dictionary containing only the entries for which the predicate returns `true`.
464
+ * Lazy logical OR combinator.
465
+ * If `self` is `true`, the `that` computation is never evaluated.
1197
466
  *
1198
- * @example
1199
- * ```ts
1200
- * pipe(Dict.from.entries([["a", 1], ["b", 3], ["c", 0]]), Dict.filter(n => n > 0));
1201
- * // ReadonlyMap { "a" => 1, "b" => 3 }
1202
- * ```
1203
- */
1204
- const filter: <A>(predicate: (a: A) => boolean) => <K>(m: ReadonlyMap<K, A>) => ReadonlyMap<K, A>;
1205
- /**
1206
- * Returns a new dictionary containing only the entries for which the predicate returns `true`.
1207
- * The predicate also receives the key.
467
+ * Data-last: `pipe(self, Bool.orLazy(that))`.
1208
468
  *
1209
469
  * @example
1210
470
  * ```ts
1211
- * pipe(Dict.from.entries([["a", 1], ["b", 2]]), Dict.filterWithKey((k, v) => k !== "a" && v > 0));
1212
- * // ReadonlyMap { "b" => 2 }
471
+ * pipe(
472
+ * isAdmin,
473
+ * Bool.orLazy(() => hasAccess(userId))
474
+ * );
1213
475
  * ```
1214
476
  */
1215
- const filterWithKey: <K, A>(predicate: (key: K, a: A) => boolean) => (m: ReadonlyMap<K, A>) => ReadonlyMap<K, A>;
477
+ orLazy: (that: () => boolean) => (self: boolean) => boolean;
1216
478
  /**
1217
- * Removes all `None` values from a `ReadonlyMap<K, Maybe<A>>`, returning a plain
1218
- * `ReadonlyMap<K, A>`. Useful when building dictionaries from fallible lookups.
479
+ * N-ary AND aggregation across an array of booleans.
480
+ * Returns `true` if every boolean is `true`, or for an empty array (vacuous truth).
481
+ * Short-circuits on the first `false`.
1219
482
  *
1220
483
  * @example
1221
484
  * ```ts
1222
- * Dict.compact(Dict.from.entries<string, Maybe<number>>([
1223
- * ["a", Maybe.make.some(1)],
1224
- * ["b", Maybe.make.none()],
1225
- * ["c", Maybe.make.some(3)],
1226
- * ]));
1227
- * // ReadonlyMap { "a" => 1, "c" => 3 }
485
+ * Bool.all([true, true, true]); // true
486
+ * Bool.all([true, false, true]); // false
487
+ * Bool.all([]); // true
1228
488
  * ```
1229
489
  */
1230
- const compact: <K, A>(m: ReadonlyMap<K, Maybe<A>>) => ReadonlyMap<K, A>;
490
+ all: (booleans: readonly boolean[]) => boolean;
1231
491
  /**
1232
- * Applies `f` to each value. Entries where `f` returns `None` are removed; entries where
1233
- * `f` returns `Some` are kept with the unwrapped value. Combines map and filter in one pass.
492
+ * N-ary OR aggregation across an array of booleans.
493
+ * Returns `true` if at least one boolean is `true`. Returns `false` for an empty array.
494
+ * Short-circuits on the first `true`.
1234
495
  *
1235
496
  * @example
1236
497
  * ```ts
1237
- * const parse = (s: string): Maybe<number> => {
1238
- * const n = Number(s);
1239
- * return isNaN(n) ? Maybe.make.none() : Maybe.make.some(n);
1240
- * };
1241
- * Dict.filterMap(parse)(Dict.from.Record({ a: "1", b: "two", c: "3" }));
1242
- * // ReadonlyMap { "a" => 1, "c" => 3 }
498
+ * Bool.any([false, true, false]); // true
499
+ * Bool.any([false, false]); // false
500
+ * Bool.any([]); // false
1243
501
  * ```
1244
502
  */
1245
- const filterMap: <A, B>(f: (a: A) => Maybe<B>) => <K>(m: ReadonlyMap<K, A>) => ReadonlyMap<K, B>;
503
+ any: (booleans: readonly boolean[]) => boolean;
1246
504
  /**
1247
- * Merges two dictionaries. When both contain the same key, the value from `other` takes
1248
- * precedence.
505
+ * Catamorphism for boolean: evaluates `onFalse()` when `false` and `onTrue()` when `true`.
1249
506
  *
1250
- * @example
1251
- * ```ts
1252
- * pipe(
1253
- * Dict.from.entries([["a", 1], ["b", 2]]),
1254
- * Dict.union(Dict.from.entries([["b", 3], ["c", 4]])),
1255
- * );
1256
- * // ReadonlyMap { "a" => 1, "b" => 3, "c" => 4 }
1257
- * ```
1258
- */
1259
- const union: <K, V>(other: ReadonlyMap<K, V>) => (m: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
1260
- /**
1261
- * Returns a new dictionary containing only the entries whose keys appear in both dictionaries.
1262
- * Values are taken from the left (base) dictionary.
507
+ * Positional ordering: `onFalse` first, `onTrue` second.
508
+ * Aligned with `Result.fold(onErr, onOk)` and `Maybe.fold(onNone, onSome)`.
1263
509
  *
1264
510
  * @example
1265
511
  * ```ts
1266
512
  * pipe(
1267
- * Dict.from.entries([["a", 1], ["b", 2], ["c", 3]]),
1268
- * Dict.intersection(Dict.from.entries([["b", 99], ["c", 0]])),
513
+ * isDarkMode,
514
+ * Bool.fold(
515
+ * () => "light-theme",
516
+ * () => "dark-theme"
517
+ * )
1269
518
  * );
1270
- * // ReadonlyMap { "b" => 2, "c" => 3 }
1271
519
  * ```
1272
520
  */
1273
- const intersection: <K, V>(other: ReadonlyMap<K, unknown>) => (m: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
521
+ fold: <A, B>(onFalse: () => A, onTrue: () => B) => (b: boolean) => A | B;
1274
522
  /**
1275
- * Returns a new dictionary containing only the entries whose keys do not appear in `other`.
523
+ * Pattern matching on boolean using named cases `{ true, false }`.
1276
524
  *
1277
525
  * @example
1278
526
  * ```ts
1279
527
  * pipe(
1280
- * Dict.from.entries([["a", 1], ["b", 2], ["c", 3]]),
1281
- * Dict.difference(Dict.from.entries([["b", 0]])),
528
+ * isEnabled,
529
+ * Bool.match({
530
+ * true: () => "Feature Active",
531
+ * false: () => "Feature Disabled",
532
+ * })
1282
533
  * );
1283
- * // ReadonlyMap { "a" => 1, "c" => 3 }
1284
- * ```
1285
- */
1286
- const difference: <K, V>(other: ReadonlyMap<K, unknown>) => (m: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
1287
- /**
1288
- * Folds the dictionary into a single value by applying `f` to each value in insertion order.
1289
- * When you also need the key, use `reduceWithKey`.
1290
- *
1291
- * @example
1292
- * ```ts
1293
- * Dict.reduce(0, (acc, value: number) => acc + value)(
1294
- * Dict.from.entries([["a", 1], ["b", 2], ["c", 3]])
1295
- * ); // 6
1296
- * ```
1297
- */
1298
- const reduce: <A, B>(init: B, f: (acc: B, value: A) => B) => <K>(m: ReadonlyMap<K, A>) => B;
1299
- /**
1300
- * Folds the dictionary into a single value by applying `f` to each key-value pair in insertion
1301
- * order.
1302
- *
1303
- * @example
1304
- * ```ts
1305
- * Dict.reduceWithKey("", (acc, value, key) => acc + key + ":" + value + " ")(
1306
- * Dict.from.entries([["a", 1], ["b", 2]])
1307
- * ); // "a:1 b:2 "
1308
534
  * ```
1309
535
  */
1310
- const reduceWithKey: <K, A, B>(init: B, f: (acc: B, value: A, key: K) => B) => (m: ReadonlyMap<K, A>) => B;
1311
- /**
1312
- * Merges two maps using a custom combination function on key collisions.
1313
- * Supports both uncurried `Dict.mergeWith(combine)(first, second)` and curried `pipe(first, Dict.mergeWith(combine)(second))`.
1314
- *
1315
- * @example
1316
- * ```ts
1317
- * const combineStats = Dict.mergeWith((a: number, b: number) => a + b);
1318
- * const map1 = Dict.from.entries([["a", 1], ["b", 2]]);
1319
- * const map2 = Dict.from.entries([["b", 3], ["c", 4]]);
1320
- * combineStats(map1, map2);
1321
- * pipe(map1, combineStats(map2));
1322
- * ```
1323
- */
1324
- function mergeWith<K, V>(combine: (a: V, b: V) => V): {
1325
- (second: ReadonlyMap<K, V>): (first: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
1326
- (first: ReadonlyMap<K, V>, second: ReadonlyMap<K, V>): ReadonlyMap<K, V>;
536
+ match: <A, B>(cases: BoolMatchCases<A, B>) => (b: boolean) => A | B;
537
+ from: {
538
+ /**
539
+ * Parses a string into a `Maybe<boolean>`.
540
+ * Returns `Some(true)` for `"true"`, `Some(false)` for `"false"` (case-insensitive & trimmed),
541
+ * and `None` for any other string.
542
+ *
543
+ * @example
544
+ * ```ts
545
+ * Bool.from.string("true"); // Some(true)
546
+ * Bool.from.string("FALSE"); // Some(false)
547
+ * Bool.from.string("yes"); // None
548
+ * ```
549
+ */
550
+ string: (s: string) => Maybe<boolean>;
551
+ /**
552
+ * Converts a number into a `Maybe<boolean>`.
553
+ * Returns `Some(true)` for `1`, `Some(false)` for `0`, and `None` for any other number.
554
+ *
555
+ * @example
556
+ * ```ts
557
+ * Bool.from.number(1); // Some(true)
558
+ * Bool.from.number(0); // Some(false)
559
+ * Bool.from.number(42); // None
560
+ * ```
561
+ */
562
+ number: (n: number) => Maybe<boolean>;
563
+ /**
564
+ * Coerces any unknown value into a boolean via standard JS `Boolean(value)`.
565
+ *
566
+ * @example
567
+ * ```ts
568
+ * Bool.from.truthy("hello"); // true
569
+ * Bool.from.truthy(0); // false
570
+ * ```
571
+ */
572
+ truthy: (value: unknown) => boolean;
1327
573
  };
1328
- namespace to {
574
+ to: {
1329
575
  /**
1330
- * Converts a `ReadonlyMap<string, V>` to a plain object. Only meaningful when keys are strings.
576
+ * Lifts a boolean condition into a `Maybe`.
577
+ * Returns `Some(onTrue())` when `true`, and `None` when `false`.
1331
578
  *
1332
579
  * @example
1333
580
  * ```ts
1334
- * Dict.to.Record(Dict.from.entries([["a", 1], ["b", 2]])); // { a: 1, b: 2 }
581
+ * pipe(
582
+ * user.isVerified,
583
+ * Bool.to.Maybe(() => user.profile)
584
+ * ); // Some(profile) or None
1335
585
  * ```
1336
586
  */
1337
- const Record: <V>(m: ReadonlyMap<string, V>) => Readonly<Record<string, V>>;
1338
- }
1339
- /**
1340
- * Transforms key and value pairs simultaneously into a new ReadonlyMap.
1341
- *
1342
- * @example
1343
- * ```ts
1344
- * pipe(
1345
- * Dict.from.entries([["a", 1], ["b", 2]]),
1346
- * Dict.mapEntries((k, v) => [k.toUpperCase(), v * 10])
1347
- * ); // Map { "A" => 10, "B" => 20 }
1348
- * ```
1349
- */
1350
- const mapEntries: <K1, V1, K2, V2>(f: (key: K1, value: V1) => readonly [K2, V2]) => (data: ReadonlyMap<K1, V1>) => ReadonlyMap<K2, V2>;
1351
- /**
1352
- * Transforms keys of a ReadonlyMap while preserving values.
1353
- *
1354
- * @example
1355
- * ```ts
1356
- * pipe(
1357
- * Dict.from.entries([["a", 1], ["b", 2]]),
1358
- * Dict.mapKeys((k) => k.toUpperCase())
1359
- * ); // Map { "A" => 1, "B" => 2 }
1360
- * ```
587
+ Maybe: <A>(onTrue: () => A) => (b: boolean) => Maybe<A>;
588
+ /**
589
+ * Lifts a boolean condition into a `Result`.
590
+ * Returns `Ok(onOk())` when `true`, and `Err(onErr())` when `false`.
591
+ *
592
+ * @example
593
+ * ```ts
594
+ * pipe(
595
+ * hasPermission,
596
+ * Bool.to.Result(
597
+ * () => "Permission denied",
598
+ * () => sessionData
599
+ * )
600
+ * ); // Ok(sessionData) or Err("Permission denied")
601
+ * ```
602
+ */
603
+ Result: <E, A>(onErr: () => E, onOk: () => A) => (b: boolean) => Result<E, A>;
604
+ /**
605
+ * Converts a boolean to numeric `1` or `0`.
606
+ *
607
+ * @example
608
+ * ```ts
609
+ * Bool.to.number(true); // 1
610
+ * Bool.to.number(false); // 0
611
+ * ```
612
+ */
613
+ number: (b: boolean) => 1 | 0;
614
+ /**
615
+ * Converts a boolean to literal string `"true"` or `"false"`.
616
+ *
617
+ * @example
618
+ * ```ts
619
+ * Bool.to.string(true); // "true"
620
+ * Bool.to.string(false); // "false"
621
+ * ```
622
+ */
623
+ string: (b: boolean) => "true" | "false";
624
+ };
625
+ };
626
+
627
+ /**
628
+ * A branded type representing a key-value dictionary with at least one entry.
629
+ */
630
+ type NonEmptyMap<K, V> = Brand<NonEmpty<"Dict">, ReadonlyMap<K, V>>;
631
+ declare function mergeWith$1<V>(combine: (a: V, b: V) => V): {
632
+ <K>(first: ReadonlyMap<K, V>, second: ReadonlyMap<K, V>): ReadonlyMap<K, V>;
633
+ <K>(second: ReadonlyMap<K, V>): (first: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
634
+ };
635
+ declare const Dict: {
636
+ is: {
637
+ empty: <K, V>(m: ReadonlyMap<K, V>) => boolean;
638
+ nonEmpty: <K, V>(m: ReadonlyMap<K, V>) => m is NonEmptyMap<K, V>;
639
+ };
640
+ empty: <K, V>() => ReadonlyMap<K, V>;
641
+ singleton: <K, V>(key: K, value: V) => ReadonlyMap<K, V>;
642
+ from: {
643
+ entries: <K, V>(entries: readonly (readonly [K, V])[]) => ReadonlyMap<K, V>;
644
+ Record: <K extends string, V>(record: Readonly<Record<K, V>>) => ReadonlyMap<K, V>;
645
+ Array: <K, V>(data: readonly (readonly [K, V])[]) => ReadonlyMap<K, V>;
646
+ nullable: <K, V>(data: ReadonlyMap<K, V> | null | undefined) => Maybe<ReadonlyMap<K, V>>;
647
+ };
648
+ to: {
649
+ Record: <K extends string, V>(map: ReadonlyMap<K, V>) => Readonly<Record<K, V>>;
650
+ };
651
+ groupBy: <A, K>(f: (a: A) => K) => (as: readonly A[]) => ReadonlyMap<K, NonEmptyArr<A>>;
652
+ has: <K, V>(key: K) => (data: ReadonlyMap<K, V>) => boolean;
653
+ lookup: <K, V>(key: K) => (data: ReadonlyMap<K, V>) => Maybe<V>;
654
+ size: <K, V>(data: ReadonlyMap<K, V>) => number;
655
+ keys: <K, V>(data: ReadonlyMap<K, V>) => readonly K[];
656
+ values: <K, V>(data: ReadonlyMap<K, V>) => readonly V[];
657
+ entries: <K, V>(data: ReadonlyMap<K, V>) => readonly (readonly [K, V])[];
658
+ insert: <K, V>(key: K, value: V) => (data: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
659
+ remove: <K, V>(key: K) => (data: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
660
+ upsert: <K, V>(key: K, f: (existing: Maybe<V>) => V) => (data: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
661
+ map: <A, B>(f: (a: A) => B) => <K>(data: ReadonlyMap<K, A>) => ReadonlyMap<K, B>;
662
+ mapWithKey: <K, A, B>(f: (key: K, value: A) => B) => (data: ReadonlyMap<K, A>) => ReadonlyMap<K, B>;
663
+ filter: <A>(predicate: (a: A) => boolean) => <K>(data: ReadonlyMap<K, A>) => ReadonlyMap<K, A>;
664
+ filterWithKey: <K, A>(predicate: (key: K, value: A) => boolean) => (data: ReadonlyMap<K, A>) => ReadonlyMap<K, A>;
665
+ compact: <K, A>(data: ReadonlyMap<K, Maybe<A>>) => ReadonlyMap<K, A>;
666
+ filterMap: <A, B>(f: (a: A) => Maybe<B>) => <K>(data: ReadonlyMap<K, A>) => ReadonlyMap<K, B>;
667
+ union: <K, V>(other: ReadonlyMap<K, V>) => (data: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
668
+ intersection: <K, V>(other: ReadonlyMap<K, V>) => (data: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
669
+ difference: <K, V>(other: ReadonlyMap<K, V>) => (data: ReadonlyMap<K, V>) => ReadonlyMap<K, V>;
670
+ reduce: <B, V>(init: B, f: (acc: B, value: V) => B) => <K>(data: ReadonlyMap<K, V>) => B;
671
+ reduceWithKey: <B, K, V>(init: B, f: (acc: B, value: V, key: K) => B) => (data: ReadonlyMap<K, V>) => B;
672
+ mergeWith: typeof mergeWith$1;
673
+ mapEntries: <K1, V1, K2, V2>(f: (key: K1, value: V1) => readonly [K2, V2]) => (data: ReadonlyMap<K1, V1>) => ReadonlyMap<K2, V2>;
674
+ mapKeys: <K1, K2, V>(f: (key: K1) => K2) => (data: ReadonlyMap<K1, V>) => ReadonlyMap<K2, V>;
675
+ NonEmpty: {
676
+ singleton: <K, V>(key: K, value: V) => NonEmptyMap<K, V>;
677
+ from: {
678
+ Map: <K, V>(m: ReadonlyMap<K, V>) => Maybe<NonEmptyMap<K, V>>;
679
+ };
680
+ keys: <K, V>(m: NonEmptyMap<K, V>) => NonEmptyArr<K>;
681
+ values: <K, V>(m: NonEmptyMap<K, V>) => NonEmptyArr<V>;
682
+ entries: <K, V>(m: NonEmptyMap<K, V>) => NonEmptyArr<readonly [K, V]>;
683
+ reduce: <V>(f: (acc: V, value: V) => V) => <K>(m: NonEmptyMap<K, V>) => V;
684
+ map: <A, B>(f: (a: A) => B) => <K>(m: NonEmptyMap<K, A>) => NonEmptyMap<K, B>;
685
+ mapWithKey: <K, A, B>(f: (key: K, a: A) => B) => (m: NonEmptyMap<K, A>) => NonEmptyMap<K, B>;
686
+ };
687
+ };
688
+ declare namespace Dict {
689
+ /**
690
+ * A branded type representing a key-value dictionary with at least one entry.
1361
691
  */
1362
- const mapKeys: <K1, K2, V>(f: (key: K1) => K2) => (data: ReadonlyMap<K1, V>) => ReadonlyMap<K2, V>;
1363
- const NonEmpty: typeof DictNonEmpty;
692
+ type NonEmpty<K, V> = NonEmptyMap<K, V>;
1364
693
  }
1365
694
 
1366
695
  /**
@@ -1378,7 +707,7 @@ declare namespace Dict {
1378
707
  * ); // Ok("Alice")
1379
708
  * ```
1380
709
  */
1381
- declare namespace Json {
710
+ declare const Json: {
1382
711
  /**
1383
712
  * Safely parses a JSON string into `unknown`.
1384
713
  * Converts thrown exceptions into a `Result<SyntaxError, unknown>`.
@@ -1389,7 +718,7 @@ declare namespace Json {
1389
718
  * Json.parse('{invalid}'); // Err(SyntaxError)
1390
719
  * ```
1391
720
  */
1392
- const parse: (text: string) => Result<SyntaxError, unknown>;
721
+ parse: (text: string) => Result<SyntaxError, unknown>;
1393
722
  /**
1394
723
  * Safely stringifies a value into a JSON string.
1395
724
  * Converts thrown exceptions (e.g. circular references) into a `Result<TypeError, string>`.
@@ -1399,27 +728,11 @@ declare namespace Json {
1399
728
  * Json.stringify({ a: 1 }); // Ok('{"a":1}')
1400
729
  * ```
1401
730
  */
1402
- const stringify: (value: unknown, replacer?: (this: any, key: string, value: any) => any, space?: string | number) => Result<TypeError, string>;
1403
- }
731
+ stringify: (value: unknown, replacer?: (this: any, key: string, value: any) => any, space?: string | number) => Result<TypeError, string>;
732
+ };
1404
733
 
1405
- /**
1406
- * Number utilities for common operations. All transformation functions are data-last
1407
- * and curried so they compose naturally with `pipe` and `Arr.map`.
1408
- *
1409
- * @example
1410
- * ```ts
1411
- * import { Num } from "@nlozgachev/pipelined/data";
1412
- * import { pipe } from "@nlozgachev/pipelined/composition";
1413
- *
1414
- * pipe(
1415
- * Num.range(1, 6),
1416
- * Arr.map(Num.multiply(2)),
1417
- * Arr.filter(Num.between(4, 8))
1418
- * ); // [4, 6, 8]
1419
- * ```
1420
- */
1421
- declare namespace Num {
1422
- namespace is {
734
+ declare const Num: {
735
+ is: {
1423
736
  /**
1424
737
  * Returns `true` when the number is equal to zero.
1425
738
  *
@@ -1429,7 +742,7 @@ declare namespace Num {
1429
742
  * Num.is.zero(5); // false
1430
743
  * ```
1431
744
  */
1432
- const zero: (n: number) => boolean;
745
+ zero: (n: number) => boolean;
1433
746
  /**
1434
747
  * Returns `true` when the number is a whole integer.
1435
748
  *
@@ -1439,7 +752,7 @@ declare namespace Num {
1439
752
  * Num.is.integer(3.14); // false
1440
753
  * ```
1441
754
  */
1442
- const integer: (n: number) => boolean;
755
+ integer: (n: number) => boolean;
1443
756
  /**
1444
757
  * Returns `true` when the number is a finite float (fractional number).
1445
758
  *
@@ -1449,7 +762,7 @@ declare namespace Num {
1449
762
  * Num.is.float(5); // false
1450
763
  * ```
1451
764
  */
1452
- const float: (n: number) => boolean;
765
+ float: (n: number) => boolean;
1453
766
  /**
1454
767
  * Returns `true` when the number is finite (not `Infinity`, `-Infinity`, or `NaN`).
1455
768
  *
@@ -1459,7 +772,7 @@ declare namespace Num {
1459
772
  * Num.is.finite(Infinity); // false
1460
773
  * ```
1461
774
  */
1462
- const finite: (n: number) => boolean;
775
+ finite: (n: number) => boolean;
1463
776
  /**
1464
777
  * Returns `true` when the value is `NaN`.
1465
778
  *
@@ -1469,7 +782,7 @@ declare namespace Num {
1469
782
  * Num.is.nan(42); // false
1470
783
  * ```
1471
784
  */
1472
- const nan: (n: number) => boolean;
785
+ nan: (n: number) => boolean;
1473
786
  /**
1474
787
  * Returns `true` when the number is an even integer.
1475
788
  *
@@ -1480,7 +793,7 @@ declare namespace Num {
1480
793
  * Num.is.even(2.5); // false
1481
794
  * ```
1482
795
  */
1483
- const even: (n: number) => boolean;
796
+ even: (n: number) => boolean;
1484
797
  /**
1485
798
  * Returns `true` when the number is an odd integer.
1486
799
  *
@@ -1491,7 +804,7 @@ declare namespace Num {
1491
804
  * Num.is.odd(2.5); // false
1492
805
  * ```
1493
806
  */
1494
- const odd: (n: number) => boolean;
807
+ odd: (n: number) => boolean;
1495
808
  /**
1496
809
  * Returns `true` when the number is strictly greater than zero.
1497
810
  *
@@ -1502,7 +815,7 @@ declare namespace Num {
1502
815
  * Num.is.positive(-5); // false
1503
816
  * ```
1504
817
  */
1505
- const positive: (n: number) => boolean;
818
+ positive: (n: number) => boolean;
1506
819
  /**
1507
820
  * Returns `true` when the number is strictly less than zero.
1508
821
  *
@@ -1513,8 +826,8 @@ declare namespace Num {
1513
826
  * Num.is.negative(5); // false
1514
827
  * ```
1515
828
  */
1516
- const negative: (n: number) => boolean;
1517
- }
829
+ negative: (n: number) => boolean;
830
+ };
1518
831
  /**
1519
832
  * Generates an array of numbers from `from` to `to` (both inclusive),
1520
833
  * stepping by `step` (default `1`). If `step` is negative or zero, or `from > to`,
@@ -1530,7 +843,7 @@ declare namespace Num {
1530
843
  * Num.range(3, 3); // [3]
1531
844
  * ```
1532
845
  */
1533
- const range: (from: number, to: number, step?: number) => readonly number[];
846
+ range: (from: number, to: number, step?: number) => readonly number[];
1534
847
  /**
1535
848
  * Clamps a number between `min` and `max` (both inclusive).
1536
849
  *
@@ -1541,7 +854,7 @@ declare namespace Num {
1541
854
  * pipe(42, Num.clamp(0, 100)); // 42
1542
855
  * ```
1543
856
  */
1544
- const clamp: (min: number, max: number) => (n: number) => number;
857
+ clamp: (min: number, max: number) => (n: number) => number;
1545
858
  /**
1546
859
  * Returns `true` when the number is between `min` and `max` (both inclusive).
1547
860
  *
@@ -1552,7 +865,7 @@ declare namespace Num {
1552
865
  * pipe(10, Num.between(1, 10)); // true
1553
866
  * ```
1554
867
  */
1555
- const between: (min: number, max: number) => (n: number) => boolean;
868
+ between: (min: number, max: number) => (n: number) => boolean;
1556
869
  /**
1557
870
  * Returns `true` when the number is in the range `[start, end)` (inclusive of `start`, exclusive of `end`).
1558
871
  *
@@ -1563,7 +876,7 @@ declare namespace Num {
1563
876
  * pipe(10, Num.inRange(1, 10)); // false
1564
877
  * ```
1565
878
  */
1566
- const inRange: (start: number, end: number) => (n: number) => boolean;
879
+ inRange: (start: number, end: number) => (n: number) => boolean;
1567
880
  /**
1568
881
  * Parses a string as a number. Returns `None` when the result is `NaN`.
1569
882
  *
@@ -1575,7 +888,7 @@ declare namespace Num {
1575
888
  * Num.parse(""); // None
1576
889
  * ```
1577
890
  */
1578
- const parse: (s: string) => Maybe<number>;
891
+ parse: (s: string) => Maybe<number>;
1579
892
  /**
1580
893
  * Adds `b` to a number. Data-last: use in `pipe` or `Arr.map`.
1581
894
  *
@@ -1585,7 +898,7 @@ declare namespace Num {
1585
898
  * pipe([1, 2, 3], Arr.map(Num.add(10))); // [11, 12, 13]
1586
899
  * ```
1587
900
  */
1588
- const add: (b: number) => (a: number) => number;
901
+ add: (b: number) => (a: number) => number;
1589
902
  /**
1590
903
  * Subtracts `b` from a number. Data-last: `subtract(b)(a)` = `a - b`.
1591
904
  *
@@ -1595,523 +908,250 @@ declare namespace Num {
1595
908
  * pipe([5, 10, 15], Arr.map(Num.subtract(2))); // [3, 8, 13]
1596
909
  * ```
1597
910
  */
1598
- const subtract: (b: number) => (a: number) => number;
911
+ subtract: (b: number) => (a: number) => number;
1599
912
  /**
1600
913
  * Multiplies a number by `b`. Data-last: use in `pipe` or `Arr.map`.
1601
914
  *
1602
915
  * @example
1603
916
  * ```ts
1604
- * pipe(6, Num.multiply(7)); // 42
1605
- * pipe([1, 2, 3], Arr.map(Num.multiply(100))); // [100, 200, 300]
1606
- * ```
1607
- */
1608
- const multiply: (b: number) => (a: number) => number;
1609
- /**
1610
- * Divides a number by `b`. Returns `None` when `b` is zero. Data-last: `divide(b)(a)` = `a / b`.
1611
- *
1612
- * @example
1613
- * ```ts
1614
- * pipe(20, Num.divide(4)); // Some(5)
1615
- * pipe(5, Num.divide(0)); // None
1616
- * pipe([10, 20, 30], Arr.filterMap(Num.divide(10))); // [1, 2, 3]
1617
- * ```
1618
- */
1619
- const divide: (b: number) => (a: number) => Maybe<number>;
1620
- /**
1621
- * Returns the absolute value of a number.
1622
- *
1623
- * @example
1624
- * ```ts
1625
- * pipe(-5, Num.abs); // 5
1626
- * pipe(5, Num.abs); // 5
1627
- * ```
1628
- */
1629
- const abs: (n: number) => number;
1630
- /**
1631
- * Negates a number (arithmetic negation).
1632
- *
1633
- * @example
1634
- * ```ts
1635
- * pipe(5, Num.negate); // -5
1636
- * pipe(-5, Num.negate); // 5
1637
- * ```
1638
- */
1639
- const negate: (n: number) => number;
1640
- /**
1641
- * Rounds a number to the nearest integer.
1642
- *
1643
- * @example
1644
- * ```ts
1645
- * pipe(3.5, Num.round); // 4
1646
- * pipe(3.4, Num.round); // 3
1647
- * ```
1648
- */
1649
- const round: (n: number) => number;
1650
- /**
1651
- * Rounds a number down to the nearest integer.
1652
- *
1653
- * @example
1654
- * ```ts
1655
- * pipe(3.9, Num.floor); // 3
1656
- * pipe(-3.2, Num.floor); // -4
1657
- * ```
1658
- */
1659
- const floor: (n: number) => number;
1660
- /**
1661
- * Rounds a number up to the nearest integer.
1662
- *
1663
- * @example
1664
- * ```ts
1665
- * pipe(3.1, Num.ceil); // 4
1666
- * pipe(-3.9, Num.ceil); // -3
1667
- * ```
1668
- */
1669
- const ceil: (n: number) => number;
1670
- /**
1671
- * Returns the remainder of dividing a number by `divisor`. Returns `None` when `divisor` is zero.
1672
- * Data-last: `remainder(divisor)(a)` = `a % divisor`.
1673
- *
1674
- * @example
1675
- * ```ts
1676
- * pipe(10, Num.remainder(3)); // Some(1)
1677
- * pipe(5, Num.remainder(0)); // None
1678
- * pipe([10, 11, 12], Arr.filterMap(Num.remainder(3))); // [1, 2, 0]
1679
- * ```
1680
- */
1681
- const remainder: (divisor: number) => (n: number) => Maybe<number>;
1682
- /**
1683
- * Computes the sum of a list of numbers. Returns `0` if the list is empty.
1684
- *
1685
- * @example
1686
- * ```ts
1687
- * Num.sum([1, 2, 3]); // 6
1688
- * Num.sum([]); // 0
1689
- * ```
1690
- */
1691
- const sum: (ns: readonly number[]) => number;
1692
- /**
1693
- * Computes the mean of a list of numbers. Returns `None` if the list is empty.
1694
- *
1695
- * @example
1696
- * ```ts
1697
- * Num.mean([1, 2, 3]); // Some(2)
1698
- * Num.mean([]); // None
1699
- * ```
1700
- */
1701
- const mean: (ns: readonly number[]) => Maybe<number>;
1702
- /**
1703
- * Computes the minimum of a list of numbers. Returns `None` if the list is empty.
1704
- *
1705
- * @example
1706
- * ```ts
1707
- * Num.min([5, 1, 3]); // Some(1)
1708
- * Num.min([]); // None
1709
- * ```
1710
- */
1711
- const min: (ns: readonly number[]) => Maybe<number>;
1712
- /**
1713
- * Computes the maximum of a list of numbers. Returns `None` if the list is empty.
1714
- *
1715
- * @example
1716
- * ```ts
1717
- * Num.max([1, 5, 3]); // Some(5)
1718
- * Num.max([]); // None
1719
- * ```
1720
- */
1721
- const max: (ns: readonly number[]) => Maybe<number>;
1722
- /**
1723
- * Formats a number using `Intl.NumberFormat`. Returns `None` when `n` is `NaN` or non-finite.
1724
- * Data-last curried signature.
1725
- *
1726
- * @example
1727
- * ```ts
1728
- * const formatCurrency = Num.format({ style: "currency", currency: "USD" }, "en-US");
1729
- * pipe(1234.5, formatCurrency); // Some("$1,234.50")
1730
- * pipe(NaN, formatCurrency); // None
1731
- * ```
1732
- */
1733
- const format: (options?: Intl.NumberFormatOptions, locales?: string | string[]) => (n: number) => Maybe<string>;
1734
- }
1735
-
1736
- /**
1737
- * A branded type representing a record with at least one key-value pair.
1738
- */
1739
- type NonEmptyRecord<A, K extends string = string> = Brand<NonEmpty<"Rec">, Readonly<Record<K, A>>>;
1740
- declare namespace RecNonEmpty {
1741
- /**
1742
- * Creates a NonEmpty record from a single key-value pair.
1743
- *
1744
- * @example
1745
- * ```ts
1746
- * Rec.NonEmpty.singleton("a", 1); // { a: 1 }
1747
- * ```
1748
- */
1749
- const singleton: <K extends string, A>(key: K, value: A) => NonEmptyRecord<A, K>;
1750
- namespace from {
1751
- /**
1752
- * Creates a NonEmpty record from a standard record if it is not empty.
1753
- *
1754
- * @example
1755
- * ```ts
1756
- * Rec.NonEmpty.from.Record({ a: 1 }); // Some({ a: 1 })
1757
- * Rec.NonEmpty.from.Record({}); // None
1758
- * ```
1759
- */
1760
- const Record: <K extends string, A>(data: Readonly<Record<K, A>>) => Maybe<NonEmptyRecord<A, K>>;
1761
- }
1762
- /**
1763
- * Returns a non-empty array of keys for a NonEmpty record.
1764
- *
1765
- * @example
1766
- * ```ts
1767
- * Rec.NonEmpty.keys(Rec.NonEmpty.singleton("a", 1)); // ["a"]
1768
- * ```
1769
- */
1770
- const keys: <K extends string, A>(data: NonEmptyRecord<A, K>) => NonEmptyArr<K>;
1771
- /**
1772
- * Returns a non-empty array of values for a NonEmpty record.
1773
- *
1774
- * @example
1775
- * ```ts
1776
- * Rec.NonEmpty.values(Rec.NonEmpty.singleton("a", 1)); // [1]
1777
- * ```
1778
- */
1779
- const values: <K extends string, A>(data: NonEmptyRecord<A, K>) => NonEmptyArr<A>;
1780
- /**
1781
- * Returns a non-empty array of entry tuples for a NonEmpty record.
1782
- *
1783
- * @example
1784
- * ```ts
1785
- * Rec.NonEmpty.entries(Rec.NonEmpty.singleton("a", 1)); // [["a", 1]]
1786
- * ```
1787
- */
1788
- const entries: <K extends string, A>(data: NonEmptyRecord<A, K>) => NonEmptyArr<readonly [K, A]>;
1789
- /**
1790
- * Reduces a NonEmpty record's values from the left without an initial value.
1791
- *
1792
- * @example
1793
- * ```ts
1794
- * pipe(Rec.NonEmpty.singleton("a", 1), Rec.NonEmpty.reduce((a, b) => a + b)); // 1
1795
- * ```
1796
- */
1797
- const reduce: <A>(f: (acc: A, a: A) => A) => <K extends string>(data: NonEmptyRecord<A, K>) => A;
1798
- /**
1799
- * Transforms each value of a NonEmpty record.
1800
- *
1801
- * @example
1802
- * ```ts
1803
- * pipe(Rec.NonEmpty.singleton("a", 1), Rec.NonEmpty.map(n => n * 2)); // { a: 2 }
1804
- * ```
1805
- */
1806
- const map: <A, B>(f: (a: A) => B) => <K extends string>(data: NonEmptyRecord<A, K>) => NonEmptyRecord<B, K>;
1807
- /**
1808
- * Transforms each value of a NonEmpty record, also receiving the key.
1809
- *
1810
- * @example
1811
- * ```ts
1812
- * pipe(Rec.NonEmpty.singleton("a", 1), Rec.NonEmpty.mapWithKey((k, v) => `${k}:${v}`)); // { a: "a:1" }
1813
- * ```
1814
- */
1815
- const mapWithKey: <A, B>(f: (key: string, a: A) => B) => <K extends string>(data: NonEmptyRecord<A, K>) => NonEmptyRecord<B, K>;
1816
- }
1817
- /**
1818
- * Functional record/object utilities that compose well with pipe.
1819
- * All functions are data-last and curried where applicable.
1820
- *
1821
- * @example
1822
- * ```ts
1823
- * pipe(
1824
- * { a: 1, b: 2, c: 3 },
1825
- * Rec.filter(n => n > 1),
1826
- * Rec.map(n => n * 10)
1827
- * ); // { b: 20, c: 30 }
1828
- * ```
1829
- */
1830
- declare namespace Rec {
1831
- /**
1832
- * A branded type representing a record with at least one key-value pair.
1833
- */
1834
- type NonEmpty<A, K extends string = string> = NonEmptyRecord<A, K>;
1835
- namespace is {
1836
- /**
1837
- * Returns true if the record has no keys.
1838
- *
1839
- * @example
1840
- * ```ts
1841
- * Rec.is.empty({}); // true
1842
- * Rec.is.empty({ a: 1 }); // false
1843
- * ```
1844
- */
1845
- const empty: <A>(data: Readonly<Record<string, A>>) => boolean;
1846
- /**
1847
- * Type guard to check if a record is non-empty.
1848
- *
1849
- * @example
1850
- * ```ts
1851
- * Rec.is.nonEmpty({ a: 1 }); // true
1852
- * Rec.is.nonEmpty({}); // false
1853
- * ```
1854
- */
1855
- const nonEmpty: <A, K extends string>(data: Readonly<Record<K, A>>) => data is NonEmptyRecord<A, K>;
1856
- }
1857
- /**
1858
- * Transforms each value in a record.
1859
- *
1860
- * @example
1861
- * ```ts
1862
- * pipe({ a: 1, b: 2 }, Rec.map(n => n * 2)); // { a: 2, b: 4 }
1863
- * ```
1864
- */
1865
- const map: <A, B>(f: (a: A) => B) => <K extends string>(data: Readonly<Record<K, A>>) => Readonly<Record<K, B>>;
1866
- /**
1867
- * Maps each value in a record with a function returning a `Maybe`, keeping only `Some` values.
1868
- *
1869
- * @example
1870
- * ```ts
1871
- * pipe(
1872
- * { a: 1, b: 2, c: 3 },
1873
- * Rec.filterMap((n) => (n % 2 === 0 ? Maybe.make.some(n * 10) : Maybe.make.none()))
1874
- * ); // { b: 20 }
1875
- * ```
1876
- */
1877
- const filterMap: <A, B>(f: (a: A) => Maybe<B>) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, B>>;
1878
- /**
1879
- * Transforms each value in a record, also receiving the key.
1880
- *
1881
- * @example
1882
- * ```ts
1883
- * pipe({ a: 1, b: 2 }, Rec.mapWithKey((k, v) => `${k}:${v}`));
1884
- * // { a: "a:1", b: "b:2" }
1885
- * ```
1886
- */
1887
- const mapWithKey: <A, B>(f: (key: string, a: A) => B) => <K extends string>(data: Readonly<Record<K, A>>) => Readonly<Record<K, B>>;
1888
- /**
1889
- * Filters values in a record by a predicate.
1890
- *
1891
- * @example
1892
- * ```ts
1893
- * pipe({ a: 1, b: 2, c: 3 }, Rec.filter(n => n > 1)); // { b: 2, c: 3 }
1894
- * ```
1895
- */
1896
- const filter: <A>(predicate: (a: A) => boolean) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1897
- /**
1898
- * Filters values in a record by a predicate that also receives the key.
1899
- *
1900
- * @example
1901
- * ```ts
1902
- * pipe({ a: 1, b: 2, c: 3 }, Rec.filterWithKey((k, v) => k !== "a" && v > 0));
1903
- * // { b: 2 }
1904
- * ```
1905
- */
1906
- const filterWithKey: <A>(predicate: (key: string, a: A) => boolean) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1907
- /**
1908
- * Looks up a value by key, returning Maybe.
1909
- *
1910
- * @example
1911
- * ```ts
1912
- * pipe({ a: 1, b: 2 }, Rec.lookup("a")); // Some(1)
1913
- * pipe({ a: 1, b: 2 }, Rec.lookup("c")); // None
1914
- * ```
1915
- */
1916
- const lookup: <K extends string>(key: K) => <V>(data: Record<string, V>) => Maybe<V>;
1917
- /**
1918
- * Returns all keys of a record.
1919
- *
1920
- * @example
1921
- * ```ts
1922
- * Rec.keys({ a: 1, b: 2 }); // ["a", "b"]
917
+ * pipe(6, Num.multiply(7)); // 42
918
+ * pipe([1, 2, 3], Arr.map(Num.multiply(100))); // [100, 200, 300]
1923
919
  * ```
1924
920
  */
1925
- const keys: <T extends Record<string, unknown>>(data: T) => readonly (keyof T & string)[];
921
+ multiply: (b: number) => (a: number) => number;
1926
922
  /**
1927
- * Returns all values of a record.
923
+ * Divides a number by `b`. Returns `None` when `b` is zero. Data-last: `divide(b)(a)` = `a / b`.
1928
924
  *
1929
925
  * @example
1930
926
  * ```ts
1931
- * Rec.values({ a: 1, b: 2 }); // [1, 2]
927
+ * pipe(20, Num.divide(4)); // Some(5)
928
+ * pipe(5, Num.divide(0)); // None
929
+ * pipe([10, 20, 30], Arr.filterMap(Num.divide(10))); // [1, 2, 3]
1932
930
  * ```
1933
931
  */
1934
- const values: <T extends Record<string, unknown>>(data: T) => readonly T[keyof T & string][];
932
+ divide: (b: number) => (a: number) => Maybe<number>;
1935
933
  /**
1936
- * Returns all key-value pairs of a record.
934
+ * Returns the absolute value of a number.
1937
935
  *
1938
936
  * @example
1939
937
  * ```ts
1940
- * Rec.entries({ a: 1, b: 2 }); // [["a", 1], ["b", 2]]
938
+ * pipe(-5, Num.abs); // 5
939
+ * pipe(5, Num.abs); // 5
1941
940
  * ```
1942
941
  */
1943
- const entries: <T extends Record<string, unknown>>(data: T) => readonly (readonly [keyof T, T[keyof T]])[];
1944
- namespace from {
1945
- /**
1946
- * Creates a record from key-value pairs.
1947
- *
1948
- * @example
1949
- * ```ts
1950
- * Rec.from.entries([["a", 1], ["b", 2]]); // { a: 1, b: 2 }
1951
- * ```
1952
- */
1953
- const entries: <A>(data: readonly (readonly [string, A])[]) => Readonly<Record<string, A>>;
1954
- }
942
+ abs: (n: number) => number;
1955
943
  /**
1956
- * Groups elements of an array into a record keyed by the result of `keyFn`. Each key maps to
1957
- * the array of elements that produced it, in insertion order.
1958
- *
1959
- * Unlike `Dict.groupBy`, keys are always strings. Use `Dict.groupBy` when you need non-string
1960
- * keys or want to avoid the plain-object prototype chain.
944
+ * Negates a number (arithmetic negation).
1961
945
  *
1962
946
  * @example
1963
947
  * ```ts
1964
- * pipe(
1965
- * ["apple", "avocado", "banana", "blueberry"],
1966
- * Rec.groupBy(s => s[0]),
1967
- * ); // { a: ["apple", "avocado"], b: ["banana", "blueberry"] }
948
+ * pipe(5, Num.negate); // -5
949
+ * pipe(-5, Num.negate); // 5
1968
950
  * ```
1969
951
  */
1970
- const groupBy: <A>(keyFn: (a: A) => string) => (items: readonly A[]) => Readonly<Record<string, readonly A[]>>;
952
+ negate: (n: number) => number;
1971
953
  /**
1972
- * Picks specific keys from a record.
954
+ * Rounds a number to the nearest integer.
1973
955
  *
1974
956
  * @example
1975
957
  * ```ts
1976
- * pipe({ a: 1, b: 2, c: 3 }, Rec.pick("a", "c")); // { a: 1, c: 3 }
958
+ * pipe(3.5, Num.round); // 4
959
+ * pipe(3.4, Num.round); // 3
1977
960
  * ```
1978
961
  */
1979
- const pick: <K extends string>(...pickedKeys: K[]) => <A extends Record<K, unknown>>(data: A) => Pick<A, K>;
962
+ round: (n: number) => number;
1980
963
  /**
1981
- * Omits specific keys from a record.
964
+ * Rounds a number down to the nearest integer.
1982
965
  *
1983
966
  * @example
1984
967
  * ```ts
1985
- * pipe({ a: 1, b: 2, c: 3 }, Rec.omit("b")); // { a: 1, c: 3 }
968
+ * pipe(3.9, Num.floor); // 3
969
+ * pipe(-3.2, Num.floor); // -4
1986
970
  * ```
1987
971
  */
1988
- const omit: <K extends string>(...omittedKeys: K[]) => <A extends Record<K, unknown>>(data: A) => Omit<A, K>;
972
+ floor: (n: number) => number;
1989
973
  /**
1990
- * Merges two records. Values from the second record take precedence.
974
+ * Rounds a number up to the nearest integer.
1991
975
  *
1992
976
  * @example
1993
977
  * ```ts
1994
- * pipe({ a: 1, b: 2 }, Rec.merge({ b: 3, c: 4 })); // { a: 1, b: 3, c: 4 }
978
+ * pipe(3.1, Num.ceil); // 4
979
+ * pipe(-3.9, Num.ceil); // -3
1995
980
  * ```
1996
981
  */
1997
- const merge: <A>(other: Readonly<Record<string, A>>) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
982
+ ceil: (n: number) => number;
1998
983
  /**
1999
- * Merges two records using a custom combination function on key collisions.
2000
- * Supports both uncurried `Rec.mergeWith(combine)(first, second)` and curried `pipe(first, Rec.mergeWith(combine)(second))`.
984
+ * Returns the remainder of dividing a number by `divisor`. Returns `None` when `divisor` is zero.
985
+ * Data-last: `remainder(divisor)(a)` = `a % divisor`.
2001
986
  *
2002
987
  * @example
2003
988
  * ```ts
2004
- * const combineStats = Rec.mergeWith((a: number, b: number) => a + b);
2005
- * combineStats({ a: 1, b: 2 }, { b: 3, c: 4 }); // { a: 1, b: 5, c: 4 }
2006
- * pipe({ a: 1, b: 2 }, combineStats({ b: 3, c: 4 })); // { a: 1, b: 5, c: 4 }
989
+ * pipe(10, Num.remainder(3)); // Some(1)
990
+ * pipe(5, Num.remainder(0)); // None
991
+ * pipe([10, 11, 12], Arr.filterMap(Num.remainder(3))); // [1, 2, 0]
2007
992
  * ```
2008
993
  */
2009
- function mergeWith<A>(combine: (a: A, b: A) => A): {
2010
- (second: Readonly<Record<string, A>>): (first: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
2011
- (first: Readonly<Record<string, A>>, second: Readonly<Record<string, A>>): Readonly<Record<string, A>>;
2012
- };
994
+ remainder: (divisor: number) => (n: number) => Maybe<number>;
2013
995
  /**
2014
- * Returns the number of keys in a record.
996
+ * Computes the sum of a list of numbers. Returns `0` if the list is empty.
2015
997
  *
2016
998
  * @example
2017
999
  * ```ts
2018
- * Rec.size({ a: 1, b: 2 }); // 2
1000
+ * Num.sum([1, 2, 3]); // 6
1001
+ * Num.sum([]); // 0
2019
1002
  * ```
2020
1003
  */
2021
- const size: <A>(data: Readonly<Record<string, A>>) => number;
1004
+ sum: (ns: readonly number[]) => number;
2022
1005
  /**
2023
- * Transforms each key while preserving values.
2024
- * If two keys map to the same new key, the last one wins.
1006
+ * Computes the mean of a list of numbers. Returns `None` if the list is empty.
2025
1007
  *
2026
1008
  * @example
2027
1009
  * ```ts
2028
- * pipe({ firstName: "Alice", lastName: "Smith" }, Rec.mapKeys(k => k.toUpperCase()));
2029
- * // { FIRSTNAME: "Alice", LASTNAME: "Smith" }
1010
+ * Num.mean([1, 2, 3]); // Some(2)
1011
+ * Num.mean([]); // None
2030
1012
  * ```
2031
1013
  */
2032
- const mapKeys: (f: (key: string) => string) => <A>(data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1014
+ mean: (ns: readonly number[]) => Maybe<number>;
2033
1015
  /**
2034
- * Removes all `None` values from a `Record<string, Maybe<A>>`, returning a plain `Record<string, A>`.
2035
- * Useful when building records from fallible lookups.
1016
+ * Computes the minimum of a list of numbers. Returns `None` if the list is empty.
2036
1017
  *
2037
1018
  * @example
2038
1019
  * ```ts
2039
- * Rec.compact({ a: Maybe.make.some(1), b: Maybe.make.none(), c: Maybe.make.some(3) });
2040
- * // { a: 1, c: 3 }
1020
+ * Num.min([5, 1, 3]); // Some(1)
1021
+ * Num.min([]); // None
2041
1022
  * ```
2042
1023
  */
2043
- const compact: <A>(data: Readonly<Record<string, Maybe<A>>>) => Readonly<Record<string, A>>;
1024
+ min: (ns: readonly number[]) => Maybe<number>;
2044
1025
  /**
2045
- * Transforms key and value pairs simultaneously.
1026
+ * Computes the maximum of a list of numbers. Returns `None` if the list is empty.
2046
1027
  *
2047
1028
  * @example
2048
1029
  * ```ts
2049
- * pipe(
2050
- * { a: 1, b: 2 },
2051
- * Rec.mapEntries((k, v) => [k.toUpperCase(), v * 10])
2052
- * ); // { A: 10, B: 20 }
1030
+ * Num.max([1, 5, 3]); // Some(5)
1031
+ * Num.max([]); // None
2053
1032
  * ```
2054
1033
  */
2055
- const mapEntries: <A, K2 extends string, B>(f: (key: string, value: A) => readonly [K2, B]) => (data: Readonly<Record<string, A>>) => Readonly<Record<K2, B>>;
1034
+ max: (ns: readonly number[]) => Maybe<number>;
2056
1035
  /**
2057
- * Immutably updates a value at a deep nested path inside a record.
1036
+ * Formats a number using `Intl.NumberFormat`. Returns `None` when `n` is `NaN` or non-finite.
1037
+ * Data-last curried signature.
2058
1038
  *
2059
1039
  * @example
2060
1040
  * ```ts
2061
- * pipe(
2062
- * { user: { profile: { age: 30 } } },
2063
- * Rec.updateIn(["user", "profile", "age"], (n: number) => n + 1)
2064
- * ); // { user: { profile: { age: 31 } } }
2065
- * ```
2066
- */
2067
- const updateIn: <T>(path: readonly [string, ...string[]], f: (val: T) => T) => (data: Readonly<Record<string, unknown>>) => Readonly<Record<string, unknown>>;
2068
- namespace traverse {
2069
- const Maybe: <A, B>(f: (a: A) => Maybe<B>) => (data: Readonly<Record<string, A>>) => Maybe<Readonly<Record<string, B>>>;
2070
- const Result: <E, A, B>(f: (a: A) => Result<E, B>) => (data: Readonly<Record<string, A>>) => Result<E, Readonly<Record<string, B>>>;
2071
- }
2072
- namespace sequence {
2073
- const Maybe: <A>(data: Readonly<Record<string, Maybe<A>>>) => Maybe<Readonly<Record<string, A>>>;
2074
- const Result: <E, A>(data: Readonly<Record<string, Result<E, A>>>) => Result<E, Readonly<Record<string, A>>>;
2075
- }
2076
- const NonEmpty: typeof RecNonEmpty;
2077
- }
1041
+ * const formatCurrency = Num.format({ style: "currency", currency: "USD" }, "en-US");
1042
+ * pipe(1234.5, formatCurrency); // Some("$1,234.50")
1043
+ * pipe(NaN, formatCurrency); // None
1044
+ * ```
1045
+ */
1046
+ format: (options?: Intl.NumberFormatOptions, locales?: string | string[]) => (n: number) => Maybe<string>;
1047
+ };
2078
1048
 
2079
1049
  /**
2080
- * A branded type representing a string with at least one character.
1050
+ * A branded type representing a record with at least one key-value pair.
2081
1051
  */
2082
- type NonEmptyString = Brand<NonEmpty<"Str">, string>;
1052
+ type NonEmptyRecord<A, K extends string = string> = Brand<NonEmpty<"Rec">, Readonly<Record<K, A>>>;
2083
1053
  /**
2084
- * String utilities. All transformation functions are data-last and curried so they
2085
- * compose naturally with `pipe`. Safe parsers return `Maybe` instead of `NaN`.
1054
+ * Merges two records using a custom combination function on key collisions.
1055
+ * Supports both uncurried `Rec.mergeWith(combine)(first, second)` and curried `pipe(first, Rec.mergeWith(combine)(second))`.
2086
1056
  *
2087
1057
  * @example
2088
1058
  * ```ts
2089
- * import { Str } from "@nlozgachev/pipelined/data";
2090
- * import { pipe } from "@nlozgachev/pipelined/composition";
2091
- *
2092
- * pipe(" Hello, World! ", Str.trim, Str.toLowerCase); // "hello, world!"
1059
+ * const combineStats = Rec.mergeWith((a: number, b: number) => a + b);
1060
+ * combineStats({ a: 1, b: 2 }, { b: 3, c: 4 }); // { a: 1, b: 5, c: 4 }
1061
+ * pipe({ a: 1, b: 2 }, combineStats({ b: 3, c: 4 })); // { a: 1, b: 5, c: 4 }
2093
1062
  * ```
2094
1063
  */
2095
- declare namespace StrNonEmpty {
2096
- namespace from {
1064
+ declare function mergeWith<A>(combine: (a: A, b: A) => A): {
1065
+ (second: Readonly<Record<string, A>>): (first: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1066
+ (first: Readonly<Record<string, A>>, second: Readonly<Record<string, A>>): Readonly<Record<string, A>>;
1067
+ };
1068
+ declare const Rec: {
1069
+ is: {
1070
+ /**
1071
+ * Returns true if the record has no keys.
1072
+ *
1073
+ * @example
1074
+ * ```ts
1075
+ * Rec.is.empty({}); // true
1076
+ * Rec.is.empty({ a: 1 }); // false
1077
+ * ```
1078
+ */
1079
+ empty: <A>(data: Readonly<Record<string, A>>) => boolean;
1080
+ /**
1081
+ * Type guard to check if a record is non-empty.
1082
+ *
1083
+ * @example
1084
+ * ```ts
1085
+ * Rec.is.nonEmpty({ a: 1 }); // true
1086
+ * Rec.is.nonEmpty({}); // false
1087
+ * ```
1088
+ */
1089
+ nonEmpty: <A, K extends string>(data: Readonly<Record<K, A>>) => data is NonEmptyRecord<A, K>;
1090
+ };
1091
+ from: {
2097
1092
  /**
2098
- * Returns Some containing NonEmptyString if the string is not empty, None otherwise.
1093
+ * Creates a record from key-value pairs.
2099
1094
  *
2100
1095
  * @example
2101
1096
  * ```ts
2102
- * Str.NonEmpty.from.String("hello"); // Some("hello")
2103
- * Str.NonEmpty.from.String(""); // None
1097
+ * Rec.from.entries([["a", 1], ["b", 2]]); // { a: 1, b: 2 }
2104
1098
  * ```
2105
1099
  */
2106
- const String: (s: string) => Maybe<NonEmptyString>;
2107
- }
1100
+ entries: <A>(data: readonly (readonly [string, A])[]) => Readonly<Record<string, A>>;
1101
+ };
1102
+ to: {
1103
+ Dict: <A, K extends string = string>(data: Readonly<Record<K, A>>) => ReadonlyMap<K, A>;
1104
+ };
1105
+ map: <A, B>(f: (a: A) => B) => <K extends string>(data: Readonly<Record<K, A>>) => Readonly<Record<K, B>>;
1106
+ filterMap: <A, B>(f: (a: A) => Maybe<B>) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, B>>;
1107
+ mapWithKey: <A, B>(f: (key: string, a: A) => B) => <K extends string>(data: Readonly<Record<K, A>>) => Readonly<Record<K, B>>;
1108
+ filter: <A>(predicate: (a: A) => boolean) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1109
+ filterWithKey: <A>(predicate: (key: string, a: A) => boolean) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1110
+ lookup: <K extends string>(key: K) => <V>(data: Record<string, V>) => Maybe<V>;
1111
+ keys: <T extends Record<string, unknown>>(data: T) => readonly (keyof T & string)[];
1112
+ values: <T extends Record<string, unknown>>(data: T) => readonly T[keyof T & string][];
1113
+ entries: <T extends Record<string, unknown>>(data: T) => readonly (readonly [keyof T, T[keyof T]])[];
1114
+ groupBy: <A>(keyFn: (a: A) => string) => (items: readonly A[]) => Readonly<Record<string, readonly A[]>>;
1115
+ pick: <K extends string>(...pickedKeys: K[]) => <A extends Record<K, unknown>>(data: A) => Pick<A, K>;
1116
+ omit: <K extends string>(...omittedKeys: K[]) => <A extends Record<K, unknown>>(data: A) => Omit<A, K>;
1117
+ merge: <A>(other: Readonly<Record<string, A>>) => (data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1118
+ mergeWith: typeof mergeWith;
1119
+ size: <A>(data: Readonly<Record<string, A>>) => number;
1120
+ mapKeys: (f: (key: string) => string) => <A>(data: Readonly<Record<string, A>>) => Readonly<Record<string, A>>;
1121
+ compact: <A>(data: Readonly<Record<string, Maybe<A>>>) => Readonly<Record<string, A>>;
1122
+ mapEntries: <A, K2 extends string, B>(f: (key: string, value: A) => readonly [K2, B]) => (data: Readonly<Record<string, A>>) => Readonly<Record<K2, B>>;
1123
+ updateIn: <T>(path: readonly [string, ...string[]], f: (val: T) => T) => (data: Readonly<Record<string, unknown>>) => Readonly<Record<string, unknown>>;
1124
+ traverse: {
1125
+ Maybe: <A, B>(f: (a: A) => Maybe<B>) => (data: Readonly<Record<string, A>>) => Maybe<Readonly<Record<string, B>>>;
1126
+ Result: <E, A, B>(f: (a: A) => Result<E, B>) => (data: Readonly<Record<string, A>>) => Result<E, Readonly<Record<string, B>>>;
1127
+ };
1128
+ sequence: {
1129
+ Maybe: <A>(data: Readonly<Record<string, Maybe<A>>>) => Maybe<Readonly<Record<string, A>>>;
1130
+ Result: <E, A>(data: Readonly<Record<string, Result<E, A>>>) => Result<E, Readonly<Record<string, A>>>;
1131
+ };
1132
+ NonEmpty: {
1133
+ singleton: <K extends string, A>(key: K, value: A) => NonEmptyRecord<A, K>;
1134
+ from: {
1135
+ Record: <K extends string, A>(data: Readonly<Record<K, A>>) => Maybe<NonEmptyRecord<A, K>>;
1136
+ };
1137
+ keys: <K extends string, A>(data: NonEmptyRecord<A, K>) => NonEmptyArr<K>;
1138
+ values: <K extends string, A>(data: NonEmptyRecord<A, K>) => NonEmptyArr<A>;
1139
+ entries: <K extends string, A>(data: NonEmptyRecord<A, K>) => NonEmptyArr<readonly [K, A]>;
1140
+ reduce: <A>(f: (acc: A, a: A) => A) => <K extends string>(data: NonEmptyRecord<A, K>) => A;
1141
+ map: <A, B>(f: (a: A) => B) => <K extends string>(data: NonEmptyRecord<A, K>) => NonEmptyRecord<B, K>;
1142
+ mapWithKey: <A, B>(f: (key: string, a: A) => B) => <K extends string>(data: NonEmptyRecord<A, K>) => NonEmptyRecord<B, K>;
1143
+ };
1144
+ };
1145
+ declare namespace Rec {
1146
+ type NonEmpty<A, K extends string = string> = NonEmptyRecord<A, K>;
2108
1147
  }
2109
- declare namespace Str {
2110
- /**
2111
- * A branded type representing a string with at least one character.
2112
- */
2113
- type NonEmpty = NonEmptyString;
2114
- namespace is {
1148
+
1149
+ /**
1150
+ * A branded type representing a string with at least one character.
1151
+ */
1152
+ type NonEmptyString = Brand<NonEmpty<"Str">, string>;
1153
+ declare const Str: {
1154
+ is: {
2115
1155
  /**
2116
1156
  * Returns `true` when the string is empty.
2117
1157
  *
@@ -2121,12 +1161,12 @@ declare namespace Str {
2121
1161
  * pipe("hi", Str.is.empty); // false
2122
1162
  * ```
2123
1163
  */
2124
- const empty: (s: string) => boolean;
1164
+ empty: (s: string) => boolean;
2125
1165
  /**
2126
1166
  * Type guard to check if a string is non-empty.
2127
1167
  */
2128
- const nonEmpty: (s: string) => s is NonEmpty;
2129
- }
1168
+ nonEmpty: (s: string) => s is NonEmptyString;
1169
+ };
2130
1170
  /**
2131
1171
  * Splits a string by a separator. Data-last: use in `pipe`.
2132
1172
  *
@@ -2135,7 +1175,7 @@ declare namespace Str {
2135
1175
  * pipe("a,b,c", Str.split(",")); // ["a", "b", "c"]
2136
1176
  * ```
2137
1177
  */
2138
- const split: (separator: string | RegExp) => (s: string) => readonly string[];
1178
+ split: (separator: string | RegExp) => (s: string) => readonly string[];
2139
1179
  /**
2140
1180
  * Removes leading and trailing whitespace from a string.
2141
1181
  *
@@ -2144,7 +1184,7 @@ declare namespace Str {
2144
1184
  * pipe(" hello ", Str.trim); // "hello"
2145
1185
  * ```
2146
1186
  */
2147
- const trim: (s: string) => string;
1187
+ trim: (s: string) => string;
2148
1188
  /**
2149
1189
  * Returns `true` when the string contains the given substring.
2150
1190
  *
@@ -2154,7 +1194,7 @@ declare namespace Str {
2154
1194
  * pipe("hello world", Str.includes("xyz")); // false
2155
1195
  * ```
2156
1196
  */
2157
- const includes: (substring: string) => (s: string) => boolean;
1197
+ includes: (substring: string) => (s: string) => boolean;
2158
1198
  /**
2159
1199
  * Replaces the first occurrence of a pattern in a string. Data-last: use in `pipe`.
2160
1200
  *
@@ -2164,7 +1204,7 @@ declare namespace Str {
2164
1204
  * pipe("Hello World", Str.replace(/world/i, "Earth")); // "Hello Earth"
2165
1205
  * ```
2166
1206
  */
2167
- const replace: (pattern: string | RegExp, replacement: string) => (s: string) => string;
1207
+ replace: (pattern: string | RegExp, replacement: string) => (s: string) => string;
2168
1208
  /**
2169
1209
  * Replaces all occurrences of a pattern in a string. Data-last: use in `pipe`.
2170
1210
  *
@@ -2174,7 +1214,7 @@ declare namespace Str {
2174
1214
  * pipe("aAbBaA", Str.replaceAll(/a/gi, "x")); // "xxBBxx"
2175
1215
  * ```
2176
1216
  */
2177
- const replaceAll: (pattern: string | RegExp, replacement: string) => (s: string) => string;
1217
+ replaceAll: (pattern: string | RegExp, replacement: string) => (s: string) => string;
2178
1218
  /**
2179
1219
  * Returns `true` when the string starts with the given prefix.
2180
1220
  *
@@ -2184,7 +1224,7 @@ declare namespace Str {
2184
1224
  * pipe("hello world", Str.startsWith("world")); // false
2185
1225
  * ```
2186
1226
  */
2187
- const startsWith: (prefix: string) => (s: string) => boolean;
1227
+ startsWith: (prefix: string) => (s: string) => boolean;
2188
1228
  /**
2189
1229
  * Returns `true` when the string ends with the given suffix.
2190
1230
  *
@@ -2194,7 +1234,7 @@ declare namespace Str {
2194
1234
  * pipe("hello world", Str.endsWith("hello")); // false
2195
1235
  * ```
2196
1236
  */
2197
- const endsWith: (suffix: string) => (s: string) => boolean;
1237
+ endsWith: (suffix: string) => (s: string) => boolean;
2198
1238
  /**
2199
1239
  * Converts a string to uppercase.
2200
1240
  *
@@ -2203,7 +1243,7 @@ declare namespace Str {
2203
1243
  * pipe("hello", Str.toUpperCase); // "HELLO"
2204
1244
  * ```
2205
1245
  */
2206
- const toUpperCase: (s: string) => string;
1246
+ toUpperCase: (s: string) => string;
2207
1247
  /**
2208
1248
  * Converts a string to lowercase.
2209
1249
  *
@@ -2212,7 +1252,7 @@ declare namespace Str {
2212
1252
  * pipe("HELLO", Str.toLowerCase); // "hello"
2213
1253
  * ```
2214
1254
  */
2215
- const toLowerCase: (s: string) => string;
1255
+ toLowerCase: (s: string) => string;
2216
1256
  /**
2217
1257
  * Converts the first character of a string to uppercase.
2218
1258
  *
@@ -2221,7 +1261,7 @@ declare namespace Str {
2221
1261
  * pipe("hello", Str.capitalize); // "Hello"
2222
1262
  * ```
2223
1263
  */
2224
- const capitalize: (s: string) => string;
1264
+ capitalize: (s: string) => string;
2225
1265
  /**
2226
1266
  * Splits a string into lines, normalising `\r\n` and `\r` line endings.
2227
1267
  *
@@ -2231,7 +1271,7 @@ declare namespace Str {
2231
1271
  * Str.lines("a\r\nb"); // ["a", "b"]
2232
1272
  * ```
2233
1273
  */
2234
- const lines: (s: string) => readonly string[];
1274
+ lines: (s: string) => readonly string[];
2235
1275
  /**
2236
1276
  * Splits a string into words on any whitespace boundary, filtering out empty strings.
2237
1277
  *
@@ -2240,7 +1280,7 @@ declare namespace Str {
2240
1280
  * Str.words(" hello world "); // ["hello", "world"]
2241
1281
  * ```
2242
1282
  */
2243
- const words: (s: string) => readonly string[];
1283
+ words: (s: string) => readonly string[];
2244
1284
  /**
2245
1285
  * Returns `true` when the string is empty or contains only whitespace.
2246
1286
  *
@@ -2250,7 +1290,7 @@ declare namespace Str {
2250
1290
  * pipe("hi", Str.isBlank); // false
2251
1291
  * ```
2252
1292
  */
2253
- const isBlank: (s: string) => boolean;
1293
+ isBlank: (s: string) => boolean;
2254
1294
  /**
2255
1295
  * Returns the length of the string.
2256
1296
  *
@@ -2260,7 +1300,7 @@ declare namespace Str {
2260
1300
  * pipe("", Str.length); // 0
2261
1301
  * ```
2262
1302
  */
2263
- const length: (s: string) => number;
1303
+ length: (s: string) => number;
2264
1304
  /**
2265
1305
  * Extracts a substring between two indices. Data-last: use in `pipe`.
2266
1306
  *
@@ -2270,7 +1310,7 @@ declare namespace Str {
2270
1310
  * pipe("hello", Str.slice(2)); // "llo"
2271
1311
  * ```
2272
1312
  */
2273
- const slice: (start: number, end?: number) => (s: string) => string;
1313
+ slice: (start: number, end?: number) => (s: string) => string;
2274
1314
  /**
2275
1315
  * Pads the start of a string to a specified length. Data-last: use in `pipe`.
2276
1316
  *
@@ -2280,7 +1320,7 @@ declare namespace Str {
2280
1320
  * pipe("hi", Str.padStart(5)); // " hi"
2281
1321
  * ```
2282
1322
  */
2283
- const padStart: (maxLength: number, fillString?: string) => (s: string) => string;
1323
+ padStart: (maxLength: number, fillString?: string) => (s: string) => string;
2284
1324
  /**
2285
1325
  * Pads the end of a string to a specified length. Data-last: use in `pipe`.
2286
1326
  *
@@ -2290,11 +1330,11 @@ declare namespace Str {
2290
1330
  * pipe("hi", Str.padEnd(5)); // "hi "
2291
1331
  * ```
2292
1332
  */
2293
- const padEnd: (maxLength: number, fillString?: string) => (s: string) => string;
1333
+ padEnd: (maxLength: number, fillString?: string) => (s: string) => string;
2294
1334
  /**
2295
1335
  * Safe number parsers that return `Maybe` instead of `NaN`.
2296
1336
  */
2297
- const parse: {
1337
+ parse: {
2298
1338
  /**
2299
1339
  * Parses a string as an integer (base 10). Returns `None` if the result is `NaN`.
2300
1340
  *
@@ -2327,7 +1367,7 @@ declare namespace Str {
2327
1367
  * Str.parseJson('invalid'); // Err(SyntaxError)
2328
1368
  * ```
2329
1369
  */
2330
- const parseJson: (s: string) => Result<SyntaxError, unknown>;
1370
+ parseJson: (s: string) => Result<SyntaxError, unknown>;
2331
1371
  /**
2332
1372
  * Converts the first character of a string to lower case.
2333
1373
  *
@@ -2337,7 +1377,7 @@ declare namespace Str {
2337
1377
  * Str.uncapitalize(""); // ""
2338
1378
  * ```
2339
1379
  */
2340
- const uncapitalize: (s: string) => string;
1380
+ uncapitalize: (s: string) => string;
2341
1381
  /**
2342
1382
  * Truncates a string to a maximum length, appending an optional suffix (default `"..."`).
2343
1383
  * Data-last curried signature.
@@ -2349,267 +1389,80 @@ declare namespace Str {
2349
1389
  * pipe("Hello, world!", Str.truncate({ length: 8, suffix: "…" })); // "Hello, w…"
2350
1390
  * ```
2351
1391
  */
2352
- const truncate: (options: {
1392
+ truncate: (options: {
2353
1393
  length: number;
2354
1394
  suffix?: string;
2355
1395
  }) => (s: string) => string;
2356
- const NonEmpty: typeof StrNonEmpty;
1396
+ NonEmpty: {
1397
+ from: {
1398
+ /**
1399
+ * Returns Some containing NonEmptyString if the string is not empty, None otherwise.
1400
+ *
1401
+ * @example
1402
+ * ```ts
1403
+ * Str.NonEmpty.from.String("hello"); // Some("hello")
1404
+ * Str.NonEmpty.from.String(""); // None
1405
+ * ```
1406
+ */
1407
+ String: (s: string) => Maybe<NonEmptyString>;
1408
+ };
1409
+ };
1410
+ };
1411
+ declare namespace Str {
1412
+ /**
1413
+ * A branded type representing a string with at least one character.
1414
+ */
1415
+ type NonEmpty = NonEmptyString;
2357
1416
  }
2358
1417
 
2359
1418
  /**
2360
1419
  * A branded type representing a unique collection with at least one element.
2361
1420
  */
2362
1421
  type NonEmptySet<A> = Brand<NonEmpty<"Uniq">, ReadonlySet<A>>;
2363
- /**
2364
- * Functional utilities for unique-value collections (`ReadonlySet<A>`). All functions are pure
2365
- * and data-last — they compose naturally with `pipe`.
2366
- *
2367
- * Every "mutating" operation returns a new set; the original is never changed.
2368
- *
2369
- * @example
2370
- * ```ts
2371
- * import { Uniq } from "@nlozgachev/pipelined/data";
2372
- * import { pipe } from "@nlozgachev/pipelined/composition";
2373
- *
2374
- * const active = pipe(
2375
- * Uniq.from.Array(["alice", "bob", "alice", "carol"]),
2376
- * Uniq.remove("bob"),
2377
- * Uniq.map(name => name.toUpperCase()),
2378
- * );
2379
- * // ReadonlySet { "ALICE", "CAROL" }
2380
- * ```
2381
- */
2382
- declare namespace UniqNonEmpty {
2383
- /**
2384
- * Creates a single-element unique collection.
2385
- *
2386
- * @example
2387
- * ```ts
2388
- * Uniq.NonEmpty.singleton(42); // ReadonlySet { 42 }
2389
- * ```
2390
- */
2391
- const singleton: <A>(item: A) => NonEmptySet<A>;
2392
- namespace from {
2393
- /**
2394
- * Returns Some containing NonEmptySet if the set is not empty, None otherwise.
2395
- *
2396
- * @example
2397
- * ```ts
2398
- * Uniq.NonEmpty.from.Set(Uniq.from.Array([1, 2])); // Some(ReadonlySet { 1, 2 })
2399
- * Uniq.NonEmpty.from.Set(Uniq.empty()); // None
2400
- * ```
2401
- */
2402
- const Set: <A>(s: ReadonlySet<A>) => Maybe<NonEmptySet<A>>;
2403
- }
2404
- /**
2405
- * Folds the collection into a single value without an initial seed value.
2406
- *
2407
- * @example
2408
- * ```ts
2409
- * pipe(Uniq.NonEmpty.singleton(42), Uniq.NonEmpty.reduce((a, b) => a + b)); // 42
2410
- * ```
2411
- */
2412
- const reduce: <A>(f: (acc: A, a: A) => A) => (s: NonEmptySet<A>) => A;
2413
- /**
2414
- * Transforms each item in the non-empty unique collection.
2415
- *
2416
- * @example
2417
- * ```ts
2418
- * pipe(Uniq.NonEmpty.singleton(1), Uniq.NonEmpty.map(n => n * 2)); // ReadonlySet { 2 }
2419
- * ```
2420
- */
2421
- const map: <A, B>(f: (a: A) => B) => (s: NonEmptySet<A>) => NonEmptySet<B>;
2422
- namespace to {
2423
- /**
2424
- * Converts the collection to a non-empty readonly array in insertion order.
2425
- *
2426
- * @example
2427
- * ```ts
2428
- * Uniq.NonEmpty.to.Array(Uniq.NonEmpty.singleton(42)); // [42]
2429
- * ```
2430
- */
2431
- const Array: <A>(s: NonEmptySet<A>) => NonEmptyArr<A>;
2432
- }
2433
- }
1422
+ declare const Uniq: {
1423
+ is: {
1424
+ empty: <A>(s: ReadonlySet<A>) => boolean;
1425
+ nonEmpty: <A>(s: ReadonlySet<A>) => s is NonEmptySet<A>;
1426
+ };
1427
+ empty: <A>() => ReadonlySet<A>;
1428
+ singleton: <A>(item: A) => ReadonlySet<A>;
1429
+ from: {
1430
+ Array: <A>(arr: readonly A[]) => ReadonlySet<A>;
1431
+ };
1432
+ has: <A>(item: A) => (s: ReadonlySet<A>) => boolean;
1433
+ size: <A>(s: ReadonlySet<A>) => number;
1434
+ add: <A>(item: A) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1435
+ insert: <A>(item: A) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1436
+ remove: <A>(item: A) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1437
+ toggle: <A>(item: A) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1438
+ map: <A, B>(f: (a: A) => B) => (s: ReadonlySet<A>) => ReadonlySet<B>;
1439
+ filter: <A>(predicate: (a: A) => boolean) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1440
+ filterMap: <A, B>(f: (a: A) => Maybe<B>) => (s: ReadonlySet<A>) => ReadonlySet<B>;
1441
+ union: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1442
+ intersection: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1443
+ difference: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => ReadonlySet<A>;
1444
+ isSubsetOf: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => boolean;
1445
+ reduce: <A, B>(init: B, f: (acc: B, a: A) => B) => (s: ReadonlySet<A>) => B;
1446
+ to: {
1447
+ Array: <A>(s: ReadonlySet<A>) => readonly A[];
1448
+ };
1449
+ NonEmpty: {
1450
+ singleton: <A>(item: A) => NonEmptySet<A>;
1451
+ from: {
1452
+ Set: <A>(s: ReadonlySet<A>) => Maybe<NonEmptySet<A>>;
1453
+ };
1454
+ reduce: <A>(f: (acc: A, a: A) => A) => (s: NonEmptySet<A>) => A;
1455
+ map: <A, B>(f: (a: A) => B) => (s: NonEmptySet<A>) => NonEmptySet<B>;
1456
+ to: {
1457
+ Array: <A>(s: NonEmptySet<A>) => NonEmptyArr<A>;
1458
+ };
1459
+ };
1460
+ };
2434
1461
  declare namespace Uniq {
2435
1462
  /**
2436
1463
  * A branded type representing a unique collection with at least one element.
2437
1464
  */
2438
1465
  type NonEmpty<A> = NonEmptySet<A>;
2439
- namespace is {
2440
- /**
2441
- * Returns `true` if the collection has no items.
2442
- *
2443
- * @example
2444
- * ```ts
2445
- * Uniq.is.empty(Uniq.empty()); // true
2446
- * ```
2447
- */
2448
- const empty: <A>(s: ReadonlySet<A>) => boolean;
2449
- /**
2450
- * Type guard to check if a unique collection is non-empty.
2451
- *
2452
- * @example
2453
- * ```ts
2454
- * Uniq.is.nonEmpty(Uniq.from.Array([1, 2])); // true
2455
- * Uniq.is.nonEmpty(Uniq.empty()); // false
2456
- * ```
2457
- */
2458
- const nonEmpty: <A>(s: ReadonlySet<A>) => s is NonEmpty<A>;
2459
- }
2460
- /**
2461
- * Creates an empty unique collection.
2462
- *
2463
- * @example
2464
- * ```ts
2465
- * Uniq.empty<number>(); // ReadonlySet {}
2466
- * ```
2467
- */
2468
- const empty: <A>() => ReadonlySet<A>;
2469
- /**
2470
- * Creates a unique collection containing a single item.
2471
- *
2472
- * @example
2473
- * ```ts
2474
- * Uniq.singleton(42); // ReadonlySet { 42 }
2475
- * ```
2476
- */
2477
- const singleton: <A>(item: A) => ReadonlySet<A>;
2478
- namespace from {
2479
- /**
2480
- * Creates a unique collection from an array, automatically discarding duplicates.
2481
- *
2482
- * @example
2483
- * ```ts
2484
- * Uniq.from.Array([1, 2, 2, 3, 3, 3]); // ReadonlySet { 1, 2, 3 }
2485
- * Uniq.from.Array([]); // ReadonlySet {}
2486
- * ```
2487
- */
2488
- const Array: <A>(arr: readonly A[]) => ReadonlySet<A>;
2489
- }
2490
- /**
2491
- * Returns `true` if the collection contains the given item.
2492
- *
2493
- * @example
2494
- * ```ts
2495
- * pipe(Uniq.from.Array([1, 2, 3]), Uniq.has(2)); // true
2496
- * pipe(Uniq.from.Array([1, 2, 3]), Uniq.has(4)); // false
2497
- * ```
2498
- */
2499
- const has: <A>(item: A) => (s: ReadonlySet<A>) => boolean;
2500
- /**
2501
- * Returns the number of items in the collection.
2502
- *
2503
- * @example
2504
- * ```ts
2505
- * Uniq.size(Uniq.from.Array([1, 2, 3])); // 3
2506
- * ```
2507
- */
2508
- const size: <A>(s: ReadonlySet<A>) => number;
2509
- /**
2510
- * Returns `true` if every item in `set` also exists in `other`.
2511
- *
2512
- * @example
2513
- * ```ts
2514
- * pipe(Uniq.from.Array([1, 2]), Uniq.isSubsetOf(Uniq.from.Array([1, 2, 3]))); // true
2515
- * pipe(Uniq.from.Array([1, 4]), Uniq.isSubsetOf(Uniq.from.Array([1, 2, 3]))); // false
2516
- * pipe(Uniq.empty<number>(), Uniq.isSubsetOf(Uniq.from.Array([1, 2, 3]))); // true
2517
- * ```
2518
- */
2519
- const isSubsetOf: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => boolean;
2520
- /**
2521
- * Returns a new collection with the item added. If the item is already present, returns the
2522
- * original collection unchanged.
2523
- *
2524
- * @example
2525
- * ```ts
2526
- * pipe(Uniq.from.Array([1, 2]), Uniq.insert(3)); // ReadonlySet { 1, 2, 3 }
2527
- * pipe(Uniq.from.Array([1, 2]), Uniq.insert(2)); // ReadonlySet { 1, 2 } — unchanged
2528
- * ```
2529
- */
2530
- const insert: <A>(item: A) => (s: ReadonlySet<A>) => ReadonlySet<A>;
2531
- /**
2532
- * Returns a new collection with the item removed. If the item is not present, returns the
2533
- * original collection unchanged.
2534
- *
2535
- * @example
2536
- * ```ts
2537
- * pipe(Uniq.from.Array([1, 2, 3]), Uniq.remove(2)); // ReadonlySet { 1, 3 }
2538
- * pipe(Uniq.from.Array([1, 2, 3]), Uniq.remove(4)); // ReadonlySet { 1, 2, 3 } — unchanged
2539
- * ```
2540
- */
2541
- const remove: <A>(item: A) => (s: ReadonlySet<A>) => ReadonlySet<A>;
2542
- /**
2543
- * Applies `f` to each item, returning a new collection of the results. Duplicate results are
2544
- * automatically merged.
2545
- *
2546
- * @example
2547
- * ```ts
2548
- * pipe(Uniq.from.Array([1, 2, 3, 4]), Uniq.map(n => n % 3)); // ReadonlySet { 1, 2, 0 }
2549
- * ```
2550
- */
2551
- const map: <A, B>(f: (a: A) => B) => (s: ReadonlySet<A>) => ReadonlySet<B>;
2552
- /**
2553
- * Returns a new collection containing only the items for which the predicate returns `true`.
2554
- *
2555
- * @example
2556
- * ```ts
2557
- * pipe(Uniq.from.Array([1, 2, 3, 4, 5]), Uniq.filter(n => n % 2 === 0));
2558
- * // ReadonlySet { 2, 4 }
2559
- * ```
2560
- */
2561
- const filter: <A>(predicate: (a: A) => boolean) => (s: ReadonlySet<A>) => ReadonlySet<A>;
2562
- /**
2563
- * Returns a new collection containing all items from both collections.
2564
- *
2565
- * @example
2566
- * ```ts
2567
- * pipe(Uniq.from.Array([1, 2, 3]), Uniq.union(Uniq.from.Array([2, 3, 4])));
2568
- * // ReadonlySet { 1, 2, 3, 4 }
2569
- * ```
2570
- */
2571
- const union: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => ReadonlySet<A>;
2572
- /**
2573
- * Returns a new collection containing only the items that appear in both collections.
2574
- *
2575
- * @example
2576
- * ```ts
2577
- * pipe(Uniq.from.Array([1, 2, 3]), Uniq.intersection(Uniq.from.Array([2, 3, 4])));
2578
- * // ReadonlySet { 2, 3 }
2579
- * ```
2580
- */
2581
- const intersection: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => ReadonlySet<A>;
2582
- /**
2583
- * Returns a new collection containing only the items from `set` that do not appear in `other`.
2584
- *
2585
- * @example
2586
- * ```ts
2587
- * pipe(Uniq.from.Array([1, 2, 3, 4]), Uniq.difference(Uniq.from.Array([2, 4])));
2588
- * // ReadonlySet { 1, 3 }
2589
- * ```
2590
- */
2591
- const difference: <A>(other: ReadonlySet<A>) => (s: ReadonlySet<A>) => ReadonlySet<A>;
2592
- /**
2593
- * Folds the collection into a single value by applying `f` to each item in insertion order.
2594
- *
2595
- * @example
2596
- * ```ts
2597
- * Uniq.reduce(0, (acc, n: number) => acc + n)(Uniq.from.Array([1, 2, 3])); // 6
2598
- * ```
2599
- */
2600
- const reduce: <A, B>(init: B, f: (acc: B, a: A) => B) => (s: ReadonlySet<A>) => B;
2601
- namespace to {
2602
- /**
2603
- * Converts the collection to a readonly array in insertion order.
2604
- *
2605
- * @example
2606
- * ```ts
2607
- * Uniq.to.Array(Uniq.from.Array([3, 1, 2])); // [3, 1, 2]
2608
- * ```
2609
- */
2610
- const Array: <A>(s: ReadonlySet<A>) => readonly A[];
2611
- }
2612
- const NonEmpty: typeof UniqNonEmpty;
2613
1466
  }
2614
1467
 
2615
- export { Arr, BigNum, Dict, Json, type NonEmptyMap, type NonEmptyRecord, type NonEmptySet, type NonEmptyString, Num, Rec, Str, Uniq };
1468
+ export { Arr, BigNum, Bool, type BoolMatchCases, Dict, Json, type NonEmptyMap, type NonEmptyRecord, type NonEmptySet, type NonEmptyString, Num, Rec, Str, Uniq };