@nlozgachev/pipelined 0.31.0 → 0.33.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.
@@ -1,56 +1,4 @@
1
- import { N as NonEmptyList } from './NonEmptyList-BlGFjor5.js';
2
-
3
- declare const _deferred: unique symbol;
4
- /**
5
- * A nominally typed, one-shot async value that supports `await` but enforces infallibility.
6
- *
7
- * Two design choices work together to make the guarantee structural rather than documentary:
8
- *
9
- * - The phantom `[_deferred]` symbol makes the type **nominal**: only values produced by
10
- * `Deferred.fromPromise` satisfy it. A plain object `{ then: ... }` does not.
11
- * - The single-parameter `.then()` **excludes rejection handlers** by construction. There is
12
- * no second argument to pass, so chaining and `.catch()` are impossible.
13
- *
14
- * This makes `Deferred<A>` the natural return type for `Task<A>`, which is guaranteed to
15
- * never reject.
16
- *
17
- * @example
18
- * ```ts
19
- * const value = await Deferred.fromPromise(Promise.resolve(42));
20
- * // value === 42
21
- * ```
22
- */
23
- type Deferred<A> = {
24
- readonly [_deferred]: A;
25
- readonly then: (onfulfilled: (value: A) => unknown) => void;
26
- };
27
- declare namespace Deferred {
28
- /**
29
- * Wraps a `Promise` into a `Deferred`, structurally excluding rejection handlers,
30
- * `.catch()`, `.finally()`, and chainable `.then()`.
31
- *
32
- * **Precondition**: `p` must never reject. If `p` rejects, the returned `Deferred` will
33
- * never resolve — `await`-ing it will hang indefinitely. Use `TaskResult.tryCatch` to
34
- * handle operations that may fail before converting to a `Deferred`.
35
- *
36
- * @example
37
- * ```ts
38
- * const d = Deferred.fromPromise(Promise.resolve("hello"));
39
- * const value = await d; // "hello"
40
- * ```
41
- */
42
- const fromPromise: <A>(p: Promise<A>) => Deferred<A>;
43
- /**
44
- * Converts a `Deferred` back into a `Promise`.
45
- *
46
- * @example
47
- * ```ts
48
- * const p = Deferred.toPromise(Deferred.fromPromise(Promise.resolve(42)));
49
- * // p is Promise<42>
50
- * ```
51
- */
52
- const toPromise: <A>(d: Deferred<A>) => Promise<A>;
53
- }
1
+ import { NonEmptyList, Duration } from './types.mjs';
54
2
 
55
3
  type WithKind<K extends string> = {
56
4
  readonly kind: K;
@@ -275,6 +223,44 @@ declare namespace Result {
275
223
  * ```
276
224
  */
277
225
  const fromPredicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Result<E, A>;
226
+ /**
227
+ * Creates a Result from a nullable value.
228
+ * Returns Ok if the value is not null or undefined, error from onNull otherwise.
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * pipe(null, Result.fromNullable(() => "is null")); // Error("is null")
233
+ * pipe(42, Result.fromNullable(() => "is null")); // Ok(42)
234
+ * ```
235
+ */
236
+ const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Result<E, A>;
237
+ /**
238
+ * Creates a Result from a Maybe.
239
+ * Some becomes Ok, None becomes error from onNone.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * pipe(Maybe.none(), Result.fromMaybe(() => "is none")); // Error("is none")
244
+ * pipe(Maybe.some(42), Result.fromMaybe(() => "is none")); // Ok(42)
245
+ * ```
246
+ */
247
+ const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Result<E, A>;
248
+ /**
249
+ * Wraps a throwing function of any arguments, returning a new function
250
+ * that catches errors and returns a Result.
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * const safeParse = Result.fromThrowable(
255
+ * (s: string) => JSON.parse(s),
256
+ * (e) => new Error(`Parse error: ${e}`)
257
+ * );
258
+ *
259
+ * safeParse('{"a":1}'); // Ok({ a: 1 })
260
+ * safeParse('invalid'); // Error(Error)
261
+ * ```
262
+ */
263
+ const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => A, onError: (e: unknown) => E) => (...args: Args) => Result<E, A>;
278
264
  /**
279
265
  * Recovers from an error by providing a fallback Result.
280
266
  * The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
@@ -536,6 +522,223 @@ declare namespace Maybe {
536
522
  const ap: <A>(arg: Maybe<A>) => <B>(data: Maybe<(a: A) => B>) => Maybe<B>;
537
523
  }
538
524
 
525
+ declare const _deferred: unique symbol;
526
+ /**
527
+ * A nominally typed, one-shot async value that supports `await` but enforces infallibility.
528
+ *
529
+ * Two design choices work together to make the guarantee structural rather than documentary:
530
+ *
531
+ * - The phantom `[_deferred]` symbol makes the type **nominal**: only values produced by
532
+ * `Deferred.fromPromise` satisfy it. A plain object `{ then: ... }` does not.
533
+ * - The single-parameter `.then()` **excludes rejection handlers** by construction. There is
534
+ * no second argument to pass, so chaining and `.catch()` are impossible.
535
+ *
536
+ * This makes `Deferred<A>` the natural return type for `Task<A>`, which is guaranteed to
537
+ * never reject.
538
+ *
539
+ * @example
540
+ * ```ts
541
+ * const value = await Deferred.fromPromise(Promise.resolve(42));
542
+ * // value === 42
543
+ * ```
544
+ */
545
+ type Deferred<A> = {
546
+ readonly [_deferred]: A;
547
+ readonly then: (onfulfilled: (value: A) => unknown) => void;
548
+ };
549
+ declare namespace Deferred {
550
+ /**
551
+ * Wraps a `Promise` into a `Deferred`, structurally excluding rejection handlers,
552
+ * `.catch()`, `.finally()`, and chainable `.then()`.
553
+ *
554
+ * **Precondition**: `p` must never reject. If `p` rejects, the returned `Deferred` will
555
+ * never resolve — `await`-ing it will hang indefinitely. Use `TaskResult.tryCatch` to
556
+ * handle operations that may fail before converting to a `Deferred`.
557
+ *
558
+ * @example
559
+ * ```ts
560
+ * const d = Deferred.fromPromise(Promise.resolve("hello"));
561
+ * const value = await d; // "hello"
562
+ * ```
563
+ */
564
+ const fromPromise: <A>(p: Promise<A>) => Deferred<A>;
565
+ /**
566
+ * Converts a `Deferred` back into a `Promise`.
567
+ *
568
+ * @example
569
+ * ```ts
570
+ * const p = Deferred.toPromise(Deferred.fromPromise(Promise.resolve(42)));
571
+ * // p is Promise<42>
572
+ * ```
573
+ */
574
+ const toPromise: <A>(d: Deferred<A>) => Promise<A>;
575
+ }
576
+
577
+ /**
578
+ * A function that checks whether two values of type `A` are equal.
579
+ * Use built-in instances (`Equality.string`, `Equality.number`, etc.) as starting points,
580
+ * then adapt them with `Equality.by` and combine them with `Equality.and`.
581
+ *
582
+ * @example
583
+ * ```ts
584
+ * type User = { id: string; name: string };
585
+ * const byId = pipe(Equality.string, Equality.by((u: User) => u.id));
586
+ *
587
+ * pipe(users, Arr.uniqWith(byId));
588
+ * ```
589
+ */
590
+ type Equality<A> = (a: A, b: A) => boolean;
591
+ declare namespace Equality {
592
+ /**
593
+ * Equality for strings. Case-sensitive.
594
+ *
595
+ * @example
596
+ * ```ts
597
+ * Equality.string("hello", "hello"); // true
598
+ * Equality.string("hello", "Hello"); // false
599
+ * ```
600
+ */
601
+ const string: Equality<string>;
602
+ /**
603
+ * Equality for numbers. Uses strict equality.
604
+ *
605
+ * @example
606
+ * ```ts
607
+ * Equality.number(42, 42); // true
608
+ * ```
609
+ */
610
+ const number: Equality<number>;
611
+ /**
612
+ * Equality for booleans.
613
+ *
614
+ * @example
615
+ * ```ts
616
+ * Equality.boolean(true, true); // true
617
+ * ```
618
+ */
619
+ const boolean: Equality<boolean>;
620
+ /**
621
+ * Equality for `Date` values. Compares by numeric time value.
622
+ *
623
+ * @example
624
+ * ```ts
625
+ * Equality.date(new Date("2024-01-01"), new Date("2024-01-01")); // true
626
+ * ```
627
+ */
628
+ const date: Equality<Date>;
629
+ /**
630
+ * Lifts an element equality into an array equality. Two arrays are equal if they have the
631
+ * same length and every element pair is equal under `eq`.
632
+ *
633
+ * @example
634
+ * ```ts
635
+ * Equality.array(Equality.number)([1, 2, 3], [1, 2, 3]); // true
636
+ * ```
637
+ */
638
+ const array: <A>(eq: Equality<A>) => Equality<readonly A[]>;
639
+ /**
640
+ * Adapts an equality for type `A` into an equality for type `B` by extracting a field.
641
+ * Read as "equality by this field": `pipe(Equality.string, Equality.by(u => u.name))`.
642
+ *
643
+ * @example
644
+ * ```ts
645
+ * type Product = { id: string; price: number };
646
+ * const byId = pipe(Equality.string, Equality.by((p: Product) => p.id));
647
+ * byId({ id: "p1", price: 9 }, { id: "p1", price: 12 }); // true
648
+ * ```
649
+ */
650
+ const by: <A, B>(f: (b: B) => A) => (eq: Equality<A>) => Equality<B>;
651
+ /**
652
+ * Combines two equalities with logical AND. Both must pass for two values to be considered equal.
653
+ * Data-last: the first equality is the data being piped.
654
+ *
655
+ * @example
656
+ * ```ts
657
+ * const exact = pipe(byName, Equality.and(byRole));
658
+ * exact(userA, userB); // true only if name AND role match
659
+ * ```
660
+ */
661
+ const and: <A>(eq2: Equality<A>) => (eq1: Equality<A>) => Equality<A>;
662
+ }
663
+
664
+ /**
665
+ * A function that orders two values of type `A`. Returns a negative number when `a` comes before
666
+ * `b`, a positive number when `a` comes after `b`, and `0` when they are equal.
667
+ *
668
+ * Compatible with `Array.prototype.sort` and `Arr.sortWith`.
669
+ *
670
+ * @example
671
+ * ```ts
672
+ * type Employee = { name: string; salary: number };
673
+ *
674
+ * const byName = pipe(Ordering.string, Ordering.by((e: Employee) => e.name));
675
+ * const bySalary = pipe(Ordering.number, Ordering.by((e: Employee) => e.salary));
676
+ *
677
+ * pipe(employees, Arr.sortWith(pipe(byName, Ordering.thenBy(bySalary))));
678
+ * ```
679
+ */
680
+ type Ordering<A> = (a: A, b: A) => number;
681
+ declare namespace Ordering {
682
+ /**
683
+ * Alphabetical ordering for strings.
684
+ *
685
+ * @example
686
+ * ```ts
687
+ * Ordering.string("apple", "banana"); // negative
688
+ * ```
689
+ */
690
+ const string: Ordering<string>;
691
+ /**
692
+ * Numeric ordering. Equivalent to `(a, b) => a - b`.
693
+ *
694
+ * @example
695
+ * ```ts
696
+ * pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
697
+ * ```
698
+ */
699
+ const number: Ordering<number>;
700
+ /**
701
+ * Ordering for `Date` values by numeric time value.
702
+ *
703
+ * @example
704
+ * ```ts
705
+ * pipe(dates, Arr.sortWith(Ordering.date)); // earliest first
706
+ * ```
707
+ */
708
+ const date: Ordering<Date>;
709
+ /**
710
+ * Flips the direction of an ordering.
711
+ *
712
+ * @example
713
+ * ```ts
714
+ * pipe([3, 1, 2], Arr.sortWith(Ordering.reverse(Ordering.number))); // [3, 2, 1]
715
+ * ```
716
+ */
717
+ const reverse: <A>(ord: Ordering<A>) => Ordering<A>;
718
+ /**
719
+ * Chains two orderings: the second is used only when the first returns `0`.
720
+ * Data-last: the first ordering is the data being piped.
721
+ *
722
+ * @example
723
+ * ```ts
724
+ * const byDeptThenSalary = pipe(byDept, Ordering.thenBy(bySalary));
725
+ * ```
726
+ */
727
+ const thenBy: <A>(ord2: Ordering<A>) => (ord1: Ordering<A>) => Ordering<A>;
728
+ /**
729
+ * Adapts an ordering for type `A` into an ordering for type `B` by extracting a field.
730
+ * Read as "ordering by this field": `pipe(Ordering.number, Ordering.by(p => p.price))`.
731
+ *
732
+ * @example
733
+ * ```ts
734
+ * type Product = { name: string; price: number };
735
+ * const byPrice = pipe(Ordering.number, Ordering.by((p: Product) => p.price));
736
+ * pipe(products, Arr.sortWith(byPrice));
737
+ * ```
738
+ */
739
+ const by: <A, B>(f: (b: B) => A) => (ord: Ordering<A>) => Ordering<B>;
740
+ }
741
+
539
742
  /**
540
743
  * A lazy async computation that always resolves.
541
744
  *
@@ -679,37 +882,37 @@ declare namespace Task {
679
882
  */
680
883
  const all: <T extends readonly Task<unknown>[]>(tasks: T) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
681
884
  /**
682
- * Delays the execution of a Task by the specified milliseconds.
885
+ * Delays the execution of a Task by the specified milliseconds or duration.
683
886
  * Useful for debouncing or rate limiting.
684
887
  *
685
888
  * @example
686
889
  * ```ts
687
890
  * pipe(
688
891
  * Task.resolve(42),
689
- * Task.delay(1000)
892
+ * Task.delay(Duration.seconds(1))
690
893
  * )(); // Resolves after 1 second
691
894
  * ```
692
895
  */
693
- const delay: (ms: number) => <A>(data: Task<A>) => Task<A>;
896
+ const delay: (ms: number | Duration) => <A>(data: Task<A>) => Task<A>;
694
897
  /**
695
898
  * Runs a Task a fixed number of times sequentially, collecting all results into an array.
696
- * An optional delay (ms) can be inserted between runs.
899
+ * An optional delay (ms or Duration) can be inserted between runs.
697
900
  *
698
901
  * @example
699
902
  * ```ts
700
903
  * pipe(
701
904
  * pollSensor,
702
- * Task.repeat({ times: 5, delay: 1000 })
905
+ * Task.repeat({ times: 5, delay: Duration.seconds(1) })
703
906
  * )(); // Task<Reading[]> — 5 readings, one per second
704
907
  * ```
705
908
  */
706
909
  const repeat: (options: {
707
910
  times: number;
708
- delay?: number;
911
+ delay?: number | Duration;
709
912
  }) => <A>(task: Task<A>) => Task<readonly A[]>;
710
913
  /**
711
914
  * Runs a Task repeatedly until the result satisfies a predicate, returning that result.
712
- * An optional delay (ms) can be inserted between runs.
915
+ * An optional delay (ms or Duration) can be inserted between runs.
713
916
  * An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
714
917
  * regardless of whether the predicate was satisfied.
715
918
  *
@@ -717,18 +920,19 @@ declare namespace Task {
717
920
  * ```ts
718
921
  * pipe(
719
922
  * checkStatus,
720
- * Task.repeatUntil({ when: (s) => s === "ready", delay: 500 })
923
+ * Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
721
924
  * )(); // polls every 500ms until status is "ready"
722
925
  * ```
723
926
  */
724
927
  const repeatUntil: <A>(options: {
725
928
  when: (a: A) => boolean;
726
- delay?: number;
929
+ delay?: number | Duration;
727
930
  maxAttempts?: number;
728
931
  }) => (task: Task<A>) => Task<A>;
729
932
  /**
730
933
  * Resolves with the value of the first Task to complete. All Tasks start
731
- * immediately; the rest are abandoned once one resolves.
934
+ * immediately. When one resolves, the other tasks are cancelled (aborted)
935
+ * downstream.
732
936
  *
733
937
  * @example
734
938
  * ```ts
@@ -739,6 +943,17 @@ declare namespace Task {
739
943
  * ```
740
944
  */
741
945
  const race: <A>(tasks: ReadonlyArray<Task<A>>) => Task<A>;
946
+ /**
947
+ * Runs an array of Tasks concurrently and collects their results in an array.
948
+ * Forward-propagates the call site's AbortSignal to all subtasks concurrently.
949
+ *
950
+ * @example
951
+ * ```ts
952
+ * Task.sequence([loadConfig, detectLocale, loadTheme])();
953
+ * // Deferred<[Config, string, Theme]>
954
+ * ```
955
+ */
956
+ const sequence: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
742
957
  /**
743
958
  * Runs an array of Tasks one at a time in order, collecting all results.
744
959
  * Each Task starts only after the previous one resolves.
@@ -766,12 +981,12 @@ declare namespace Task {
766
981
  * ```ts
767
982
  * pipe(
768
983
  * heavyComputation,
769
- * Task.timeout(5000, () => "timed out"),
984
+ * Task.timeout(Duration.seconds(5), () => "timed out"),
770
985
  * TaskResult.chain(processResult)
771
986
  * );
772
987
  * ```
773
988
  */
774
- const timeout: <E>(ms: number, onTimeout: () => E) => <A>(task: Task<A>) => Task<Result<E, A>>;
989
+ const timeout: <E>(ms: number | Duration, onTimeout: () => E) => <A>(task: Task<A>) => Task<Result<E, A>>;
775
990
  /**
776
991
  * Creates a Task paired with an `abort` handle. Calling `abort()` cancels the
777
992
  * current in-flight call immediately. Unlike a one-shot abort, calling `task()`
@@ -812,4 +1027,4 @@ declare namespace Task {
812
1027
  const run: (signal?: AbortSignal) => <A>(task: Task<A>) => Promise<A>;
813
1028
  }
814
1029
 
815
- export { Deferred as D, type Error as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithValue as W, type WithLog as a, type WithKind as b, type WithError as c, type RetryOptions as d, type TimeoutOptions as e, type WithTimeout as f, type WithMinInterval as g, type WithCooldown as h, type WithConcurrency as i, type WithSize as j, type WithMs as k, type WithN as l, type WithErrors as m, type WithFirst as n, type WithSecond as o };
1030
+ export { Deferred as D, Equality as E, Maybe as M, type None as N, type Ok as O, Result as R, type Some as S, Task as T, type WithValue as W, type Error as a, Ordering as b, type WithLog as c, type WithKind as d, type WithError as e, type RetryOptions as f, type TimeoutOptions as g, type WithTimeout as h, type WithMinInterval as i, type WithCooldown as j, type WithConcurrency as k, type WithSize as l, type WithMs as m, type WithN as n, type WithErrors as o, type WithFirst as p, type WithSecond as q };