@typed/fx 2.0.0-beta.0 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -1
- package/dist/Fx/combinators/additive.d.ts +94 -0
- package/dist/Fx/combinators/additive.d.ts.map +1 -0
- package/dist/Fx/combinators/additive.js +92 -0
- package/dist/Fx/combinators/catch.d.ts +61 -0
- package/dist/Fx/combinators/catch.d.ts.map +1 -1
- package/dist/Fx/combinators/catch.js +54 -0
- package/dist/Fx/combinators/changesWithEffect.d.ts +20 -0
- package/dist/Fx/combinators/changesWithEffect.d.ts.map +1 -0
- package/dist/Fx/combinators/changesWithEffect.js +28 -0
- package/dist/Fx/combinators/dropUntil.d.ts +29 -0
- package/dist/Fx/combinators/dropUntil.d.ts.map +1 -0
- package/dist/Fx/combinators/dropUntil.js +23 -0
- package/dist/Fx/combinators/flatMapConcurrently.d.ts.map +1 -1
- package/dist/Fx/combinators/flatMapConcurrently.js +3 -2
- package/dist/Fx/combinators/index.d.ts +10 -0
- package/dist/Fx/combinators/index.d.ts.map +1 -1
- package/dist/Fx/combinators/index.js +10 -0
- package/dist/Fx/combinators/keyed.d.ts +1 -1
- package/dist/Fx/combinators/keyed.d.ts.map +1 -1
- package/dist/Fx/combinators/mapBoth.d.ts +21 -0
- package/dist/Fx/combinators/mapBoth.d.ts.map +1 -0
- package/dist/Fx/combinators/mapBoth.js +14 -0
- package/dist/Fx/combinators/mapError.d.ts +17 -0
- package/dist/Fx/combinators/mapError.d.ts.map +1 -0
- package/dist/Fx/combinators/mapError.js +16 -0
- package/dist/Fx/combinators/provide.d.ts +34 -1
- package/dist/Fx/combinators/provide.d.ts.map +1 -1
- package/dist/Fx/combinators/provide.js +27 -0
- package/dist/Fx/combinators/result.d.ts +23 -0
- package/dist/Fx/combinators/result.d.ts.map +1 -0
- package/dist/Fx/combinators/result.js +32 -0
- package/dist/Fx/combinators/scan.d.ts +33 -0
- package/dist/Fx/combinators/scan.d.ts.map +1 -0
- package/dist/Fx/combinators/scan.js +38 -0
- package/dist/Fx/combinators/skip.d.ts +13 -0
- package/dist/Fx/combinators/skip.d.ts.map +1 -1
- package/dist/Fx/combinators/skip.js +11 -0
- package/dist/Fx/combinators/skipWhile.d.ts +49 -0
- package/dist/Fx/combinators/skipWhile.d.ts.map +1 -0
- package/dist/Fx/combinators/skipWhile.js +66 -0
- package/dist/Fx/combinators/slice.d.ts +13 -0
- package/dist/Fx/combinators/slice.d.ts.map +1 -1
- package/dist/Fx/combinators/slice.js +11 -0
- package/dist/Fx/combinators/take.d.ts +13 -0
- package/dist/Fx/combinators/take.d.ts.map +1 -1
- package/dist/Fx/combinators/take.js +11 -0
- package/dist/Fx/combinators/takeUntil.d.ts +14 -0
- package/dist/Fx/combinators/takeUntil.d.ts.map +1 -1
- package/dist/Fx/combinators/takeUntil.js +14 -0
- package/dist/Fx/combinators/takeWhile.d.ts +29 -0
- package/dist/Fx/combinators/takeWhile.d.ts.map +1 -0
- package/dist/Fx/combinators/takeWhile.js +23 -0
- package/dist/Fx/combinators/zip.d.ts +75 -0
- package/dist/Fx/combinators/zip.d.ts.map +1 -0
- package/dist/Fx/combinators/zip.js +100 -0
- package/dist/Fx/constructors/at.d.ts +2 -2
- package/dist/Fx/constructors/at.d.ts.map +1 -1
- package/dist/Fx/constructors/periodic.d.ts +1 -1
- package/dist/Fx/constructors/periodic.d.ts.map +1 -1
- package/dist/Push/Push.d.ts +64 -1
- package/dist/Push/Push.d.ts.map +1 -1
- package/dist/Push/Push.js +57 -0
- package/dist/RefSubject/RefArray.d.ts.map +1 -1
- package/dist/RefSubject/RefArray.js +2 -1
- package/dist/RefSubject/RefChunk.d.ts.map +1 -1
- package/dist/RefSubject/RefChunk.js +2 -1
- package/dist/RefSubject/RefDateTime.d.ts +4 -4
- package/dist/RefSubject/RefDateTime.d.ts.map +1 -1
- package/dist/RefSubject/RefHashMap.d.ts.map +1 -1
- package/dist/RefSubject/RefHashMap.js +5 -1
- package/dist/RefSubject/RefIterable.d.ts +1 -1
- package/dist/RefSubject/RefIterable.d.ts.map +1 -1
- package/dist/RefSubject/RefIterable.js +6 -1
- package/dist/RefSubject/RefRecord.d.ts.map +1 -1
- package/dist/RefSubject/RefRecord.js +3 -2
- package/dist/RefSubject/RefSubject.d.ts +48 -1
- package/dist/RefSubject/RefSubject.d.ts.map +1 -1
- package/dist/RefSubject/RefSubject.js +80 -1
- package/dist/RefSubject/RefTrie.d.ts +7 -7
- package/dist/RefSubject/RefTrie.d.ts.map +1 -1
- package/dist/RefSubject/RefTrie.js +8 -3
- package/dist/Sink/combinators.d.ts +57 -0
- package/dist/Sink/combinators.d.ts.map +1 -1
- package/dist/Sink/combinators.js +104 -1
- package/dist/Versioned/Versioned.d.ts +30 -0
- package/dist/Versioned/Versioned.d.ts.map +1 -1
- package/dist/Versioned/Versioned.js +18 -0
- package/package.json +10 -6
- package/src/Fx/combinators/additive.ts +142 -0
- package/src/Fx/combinators/catch.ts +256 -0
- package/src/Fx/combinators/changesWithEffect.ts +66 -0
- package/src/Fx/combinators/dropUntil.ts +47 -0
- package/src/Fx/combinators/flatMapConcurrently.ts +5 -2
- package/src/Fx/combinators/index.ts +10 -0
- package/src/Fx/combinators/keyed.ts +2 -2
- package/src/Fx/combinators/mapBoth.ts +40 -0
- package/src/Fx/combinators/mapError.ts +28 -0
- package/src/Fx/combinators/provide.ts +63 -1
- package/src/Fx/combinators/result.ts +39 -0
- package/src/Fx/combinators/scan.ts +82 -0
- package/src/Fx/combinators/skip.ts +21 -0
- package/src/Fx/combinators/skipWhile.ts +100 -0
- package/src/Fx/combinators/slice.ts +23 -0
- package/src/Fx/combinators/take.ts +21 -0
- package/src/Fx/combinators/takeUntil.ts +38 -0
- package/src/Fx/combinators/takeWhile.ts +47 -0
- package/src/Fx/combinators/zip.ts +175 -0
- package/src/Fx/constructors/at.ts +3 -3
- package/src/Fx/constructors/periodic.ts +1 -1
- package/src/Fx.additive-combinators.test.ts +126 -0
- package/src/Fx.catch-additive.test.ts +206 -0
- package/src/Fx.catch.test.ts +1 -2
- package/src/Fx.dropUntil.test.ts +61 -0
- package/src/Fx.lifecycle.test.ts +1 -2
- package/src/Fx.mapError-mapBoth.test.ts +101 -0
- package/src/Fx.provide-combinators.test.ts +94 -0
- package/src/Fx.result-changesWithEffect.test.ts +112 -0
- package/src/Fx.scan.test.ts +73 -0
- package/src/Fx.takeWhile-skipWhile.test.ts +84 -0
- package/src/Fx.zip-merge-additive.test.ts +171 -0
- package/src/Fx.zip.test.ts +133 -0
- package/src/Push/Push.ts +170 -1
- package/src/Push.additive.test.ts +256 -0
- package/src/RefSubject/RefArray.ts +4 -1
- package/src/RefSubject/RefChunk.ts +2 -1
- package/src/RefSubject/RefDateTime.ts +6 -6
- package/src/RefSubject/RefHashMap.ts +10 -1
- package/src/RefSubject/RefIterable.ts +11 -2
- package/src/RefSubject/RefRecord.ts +9 -2
- package/src/RefSubject/RefSubject.ts +108 -9
- package/src/RefSubject/RefTrie.ts +19 -10
- package/src/RefSubject.additive-parity.test.ts +101 -0
- package/src/Sink/combinators.ts +123 -1
- package/src/Sink.combinators.test.ts +88 -0
- package/src/Sink.reduce-collect-head-last.test.ts +107 -0
- package/src/Versioned/Versioned.ts +76 -0
- package/src/Versioned.filterMap.test.ts +91 -0
- package/tsconfig.json +0 -6
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { dual, pipe } from "effect/Function";
|
|
3
|
+
import { loop as sinkLoop, loopEffect as sinkLoopEffect } from "../../Sink/combinators.js";
|
|
4
|
+
import { make } from "../constructors/make.js";
|
|
5
|
+
import type { Fx } from "../Fx.js";
|
|
6
|
+
import { Sink } from "../../Sink.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Scans the stream with a pure function, emitting the accumulated state after each element.
|
|
10
|
+
* Emits the initial value first, then for each input `a` emits `f(state, a)` and updates state.
|
|
11
|
+
*
|
|
12
|
+
* Semantics align with Effect Stream's `scan`: output is `initial`, `f(initial, a1)`, `f(..., a2)`, ...
|
|
13
|
+
*
|
|
14
|
+
* @param initial - Initial state (first value emitted).
|
|
15
|
+
* @param f - Reducer `(state, value) => nextState`.
|
|
16
|
+
* @returns An `Fx` that emits the accumulated state at each step.
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
* @category combinators
|
|
19
|
+
*/
|
|
20
|
+
export const scan: {
|
|
21
|
+
<S, A>(initial: S, f: (s: S, a: A) => S): <E, R>(fx: Fx<A, E, R>) => Fx<S, E, R>;
|
|
22
|
+
<A, E, R, S>(fx: Fx<A, E, R>, initial: S, f: (s: S, a: A) => S): Fx<S, E, R>;
|
|
23
|
+
} = dual(
|
|
24
|
+
3,
|
|
25
|
+
<A, E, R, S>(fx: Fx<A, E, R>, initial: S, f: (s: S, a: A) => S): Fx<S, E, R> =>
|
|
26
|
+
make<S, E, R>((sink) =>
|
|
27
|
+
Effect.gen(function* () {
|
|
28
|
+
yield* sink.onSuccess(initial);
|
|
29
|
+
yield* fx.run(
|
|
30
|
+
sinkLoop(sink, initial, (s, a) => {
|
|
31
|
+
const next = f(s, a);
|
|
32
|
+
return [next, next] as const;
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
}),
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Scans the stream with an effectful function, emitting the accumulated state after each element.
|
|
41
|
+
* Emits the initial value first, then for each input `a` runs `f(state, a)` and emits the resulting state.
|
|
42
|
+
*
|
|
43
|
+
* @param initial - Initial state (first value emitted).
|
|
44
|
+
* @param f - Effectful reducer `(state, value) => Effect<nextState>`.
|
|
45
|
+
* @returns An `Fx` that emits the accumulated state at each step.
|
|
46
|
+
* @since 1.0.0
|
|
47
|
+
* @category combinators
|
|
48
|
+
*/
|
|
49
|
+
export const scanEffect: {
|
|
50
|
+
<S, A, E2, R2>(
|
|
51
|
+
initial: S,
|
|
52
|
+
f: (s: S, a: A) => Effect.Effect<S, E2, R2>,
|
|
53
|
+
): <E, R>(fx: Fx<A, E, R>) => Fx<S, E | E2, R | R2>;
|
|
54
|
+
<A, E, R, S, E2, R2>(
|
|
55
|
+
fx: Fx<A, E, R>,
|
|
56
|
+
initial: S,
|
|
57
|
+
f: (s: S, a: A) => Effect.Effect<S, E2, R2>,
|
|
58
|
+
): Fx<S, E | E2, R | R2>;
|
|
59
|
+
} = dual(
|
|
60
|
+
3,
|
|
61
|
+
<A, E, R, S, E2, R2>(
|
|
62
|
+
fx: Fx<A, E, R>,
|
|
63
|
+
initial: S,
|
|
64
|
+
f: (s: S, a: A) => Effect.Effect<S, E2, R2>,
|
|
65
|
+
): Fx<S, E | E2, R | R2> =>
|
|
66
|
+
make<S, E | E2, R | R2>(<RSink>(sink: Sink<S, E | E2, RSink>) =>
|
|
67
|
+
Effect.gen(function* () {
|
|
68
|
+
const services = yield* Effect.services<R | R2 | RSink>();
|
|
69
|
+
yield* sink.onSuccess(initial);
|
|
70
|
+
yield* fx.run(
|
|
71
|
+
sinkLoopEffect(sink, initial, (s, a) =>
|
|
72
|
+
pipe(
|
|
73
|
+
f(s, a),
|
|
74
|
+
Effect.catchCause((cause) => sink.onFailure(cause).pipe(Effect.as(s))),
|
|
75
|
+
Effect.map((next) => [next, next] as const),
|
|
76
|
+
Effect.provideServices(services),
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
}),
|
|
81
|
+
),
|
|
82
|
+
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
1
2
|
import { dual } from "effect/Function";
|
|
2
3
|
import type { Fx } from "../Fx.js";
|
|
3
4
|
import { slice } from "./slice.js";
|
|
5
|
+
import { unwrap } from "./unwrap.js";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Skips the first `n` elements of an Fx.
|
|
@@ -18,3 +20,22 @@ export const skip: {
|
|
|
18
20
|
2,
|
|
19
21
|
<A, E, R>(fx: Fx<A, E, R>, n: number): Fx<A, E, R> => slice(fx, { skip: n, take: Infinity }),
|
|
20
22
|
);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Skips the first `n` elements where `n` is produced by an Effect.
|
|
26
|
+
*
|
|
27
|
+
* @param count - Effect that produces the number of elements to skip.
|
|
28
|
+
* @returns An `Fx` that emits values after the first `n` elements.
|
|
29
|
+
* @since 1.0.0
|
|
30
|
+
* @category combinators
|
|
31
|
+
*/
|
|
32
|
+
export const skipEffect: {
|
|
33
|
+
<E2, R2>(
|
|
34
|
+
count: Effect.Effect<number, E2, R2>,
|
|
35
|
+
): <A, E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, R | R2>;
|
|
36
|
+
<A, E, R, E2, R2>(fx: Fx<A, E, R>, count: Effect.Effect<number, E2, R2>): Fx<A, E | E2, R | R2>;
|
|
37
|
+
} = dual(
|
|
38
|
+
2,
|
|
39
|
+
<A, E, R, E2, R2>(fx: Fx<A, E, R>, count: Effect.Effect<number, E2, R2>): Fx<A, E | E2, R | R2> =>
|
|
40
|
+
unwrap(Effect.map(count, (n) => skip(fx, n))),
|
|
41
|
+
);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import * as Ref from "effect/Ref";
|
|
4
|
+
import { make as makeFx } from "../constructors/make.js";
|
|
5
|
+
import type { Fx } from "../Fx.js";
|
|
6
|
+
import { make as makeSink } from "../../Sink/Sink.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Skips elements from an Fx while a predicate returns true.
|
|
10
|
+
* Emits from the first element for which the predicate returns false (including that element) and all following elements.
|
|
11
|
+
*
|
|
12
|
+
* @param predicate - The predicate function.
|
|
13
|
+
* @returns An `Fx` that emits once the predicate first fails.
|
|
14
|
+
* @since 1.0.0
|
|
15
|
+
* @category combinators
|
|
16
|
+
*/
|
|
17
|
+
export const skipWhile: {
|
|
18
|
+
<A>(predicate: (a: A) => boolean): <E, R>(fx: Fx<A, E, R>) => Fx<A, E, R>;
|
|
19
|
+
<A, E, R>(fx: Fx<A, E, R>, predicate: (a: A) => boolean): Fx<A, E, R>;
|
|
20
|
+
} = dual(
|
|
21
|
+
2,
|
|
22
|
+
<A, E, R>(fx: Fx<A, E, R>, predicate: (a: A) => boolean): Fx<A, E, R> =>
|
|
23
|
+
makeFx<A, E, R>((sink) =>
|
|
24
|
+
Effect.gen(function* () {
|
|
25
|
+
const skippingRef = yield* Ref.make(true);
|
|
26
|
+
const skipSink = makeSink(sink.onFailure, (a: A) =>
|
|
27
|
+
Effect.gen(function* () {
|
|
28
|
+
const skipping = yield* Ref.get(skippingRef);
|
|
29
|
+
if (skipping) {
|
|
30
|
+
if (predicate(a)) return;
|
|
31
|
+
yield* Ref.set(skippingRef, false);
|
|
32
|
+
}
|
|
33
|
+
return yield* sink.onSuccess(a);
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
return yield* fx.run(skipSink);
|
|
37
|
+
}),
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Skips elements from an Fx while an effectful predicate returns true.
|
|
43
|
+
* Emits from the first element for which the predicate effect succeeds with false (including that element) and all following elements.
|
|
44
|
+
*
|
|
45
|
+
* @param predicate - Effectful predicate function.
|
|
46
|
+
* @returns An `Fx` that emits once the predicate first fails.
|
|
47
|
+
* @since 1.0.0
|
|
48
|
+
* @category combinators
|
|
49
|
+
*/
|
|
50
|
+
export const skipWhileEffect: {
|
|
51
|
+
<A, E2, R2>(
|
|
52
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
53
|
+
): <E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, R | R2>;
|
|
54
|
+
<A, E, R, E2, R2>(
|
|
55
|
+
fx: Fx<A, E, R>,
|
|
56
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
57
|
+
): Fx<A, E | E2, R | R2>;
|
|
58
|
+
} = dual(
|
|
59
|
+
2,
|
|
60
|
+
<A, E, R, E2, R2>(
|
|
61
|
+
fx: Fx<A, E, R>,
|
|
62
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
63
|
+
): Fx<A, E | E2, R | R2> =>
|
|
64
|
+
makeFx<A, E | E2, R | R2>((sink) =>
|
|
65
|
+
Effect.gen(function* () {
|
|
66
|
+
const skippingRef = yield* Ref.make(true);
|
|
67
|
+
const skipSink = makeSink(sink.onFailure, (a: A) =>
|
|
68
|
+
Effect.matchCauseEffect(predicate(a), {
|
|
69
|
+
onFailure: sink.onFailure,
|
|
70
|
+
onSuccess: (ok) =>
|
|
71
|
+
Effect.gen(function* () {
|
|
72
|
+
const skipping = yield* Ref.get(skippingRef);
|
|
73
|
+
if (skipping) {
|
|
74
|
+
if (ok) return;
|
|
75
|
+
yield* Ref.set(skippingRef, false);
|
|
76
|
+
}
|
|
77
|
+
return yield* sink.onSuccess(a);
|
|
78
|
+
}),
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
return yield* fx.run(skipSink);
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Alias of `skipWhile` for Effect parity (`dropWhile` naming).
|
|
88
|
+
*
|
|
89
|
+
* @since 1.0.0
|
|
90
|
+
* @category combinators
|
|
91
|
+
*/
|
|
92
|
+
export const dropWhile = skipWhile;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Alias of `skipWhileEffect` for Effect parity (`dropWhileEffect` naming).
|
|
96
|
+
*
|
|
97
|
+
* @since 1.0.0
|
|
98
|
+
* @category combinators
|
|
99
|
+
*/
|
|
100
|
+
export const dropWhileEffect = skipWhileEffect;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
1
2
|
import { dual } from "effect/Function";
|
|
2
3
|
import * as sinkCore from "../../Sink/combinators.js";
|
|
3
4
|
import { make } from "../constructors/make.js";
|
|
4
5
|
import type { Fx } from "../Fx.js";
|
|
6
|
+
import { unwrap } from "./unwrap.js";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Defines the bounds for slicing an Fx stream.
|
|
@@ -30,3 +32,24 @@ export const slice: {
|
|
|
30
32
|
<A, E, R>(fx: Fx<A, E, R>, bounds: Bounds): Fx<A, E, R> =>
|
|
31
33
|
make<A, E, R>((sink) => sinkCore.slice(sink, bounds, (sink) => fx.run(sink))),
|
|
32
34
|
);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Slices an Fx with bounds produced by an Effect.
|
|
38
|
+
*
|
|
39
|
+
* @param bounds - Effect that produces slice bounds.
|
|
40
|
+
* @returns An `Fx` representing the slice.
|
|
41
|
+
* @since 1.0.0
|
|
42
|
+
* @category combinators
|
|
43
|
+
*/
|
|
44
|
+
export const sliceEffect: {
|
|
45
|
+
<E2, R2>(
|
|
46
|
+
bounds: Effect.Effect<Bounds, E2, R2>,
|
|
47
|
+
): <A, E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, R | R2>;
|
|
48
|
+
<A, E, R, E2, R2>(fx: Fx<A, E, R>, bounds: Effect.Effect<Bounds, E2, R2>): Fx<A, E | E2, R | R2>;
|
|
49
|
+
} = dual(
|
|
50
|
+
2,
|
|
51
|
+
<A, E, R, E2, R2>(
|
|
52
|
+
fx: Fx<A, E, R>,
|
|
53
|
+
bounds: Effect.Effect<Bounds, E2, R2>,
|
|
54
|
+
): Fx<A, E | E2, R | R2> => unwrap(Effect.map(bounds, (b) => slice(fx, b))),
|
|
55
|
+
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
1
2
|
import { dual } from "effect/Function";
|
|
2
3
|
import type { Fx } from "../Fx.js";
|
|
3
4
|
import { slice } from "./slice.js";
|
|
5
|
+
import { unwrap } from "./unwrap.js";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Takes the first `n` elements from an Fx and then completes.
|
|
@@ -15,3 +17,22 @@ export const take: {
|
|
|
15
17
|
|
|
16
18
|
<A, E, R>(fx: Fx<A, E, R>, n: number): Fx<A, E, R>;
|
|
17
19
|
} = dual(2, <A, E, R>(fx: Fx<A, E, R>, n: number): Fx<A, E, R> => slice(fx, { skip: 0, take: n }));
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Takes the first `n` elements where `n` is produced by an Effect.
|
|
23
|
+
*
|
|
24
|
+
* @param count - Effect that produces the number of elements to take.
|
|
25
|
+
* @returns An `Fx` that emits at most `n` elements.
|
|
26
|
+
* @since 1.0.0
|
|
27
|
+
* @category combinators
|
|
28
|
+
*/
|
|
29
|
+
export const takeEffect: {
|
|
30
|
+
<E2, R2>(
|
|
31
|
+
count: Effect.Effect<number, E2, R2>,
|
|
32
|
+
): <A, E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, R | R2>;
|
|
33
|
+
<A, E, R, E2, R2>(fx: Fx<A, E, R>, count: Effect.Effect<number, E2, R2>): Fx<A, E | E2, R | R2>;
|
|
34
|
+
} = dual(
|
|
35
|
+
2,
|
|
36
|
+
<A, E, R, E2, R2>(fx: Fx<A, E, R>, count: Effect.Effect<number, E2, R2>): Fx<A, E | E2, R | R2> =>
|
|
37
|
+
unwrap(Effect.map(count, (n) => take(fx, n))),
|
|
38
|
+
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
1
2
|
import { dual } from "effect/Function";
|
|
2
3
|
import * as combinators from "../../Sink/combinators.js";
|
|
3
4
|
import { make as makeSink } from "../../Sink/Sink.js";
|
|
@@ -31,6 +32,43 @@ export const takeUntil: {
|
|
|
31
32
|
);
|
|
32
33
|
});
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Takes elements from an Fx until an effectful predicate returns true.
|
|
37
|
+
* The element that satisfies the predicate is not included in the output.
|
|
38
|
+
*
|
|
39
|
+
* @param predicate - Effectful predicate function.
|
|
40
|
+
* @returns An `Fx` that completes when the predicate matches.
|
|
41
|
+
* @since 1.0.0
|
|
42
|
+
* @category combinators
|
|
43
|
+
*/
|
|
44
|
+
export const takeUntilEffect: {
|
|
45
|
+
<A, E2, R2>(
|
|
46
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
47
|
+
): <E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, R | R2>;
|
|
48
|
+
<A, E, R, E2, R2>(
|
|
49
|
+
fx: Fx<A, E, R>,
|
|
50
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
51
|
+
): Fx<A, E | E2, R | R2>;
|
|
52
|
+
} = dual(
|
|
53
|
+
2,
|
|
54
|
+
<A, E, R, E2, R2>(
|
|
55
|
+
fx: Fx<A, E, R>,
|
|
56
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
57
|
+
): Fx<A, E | E2, R | R2> =>
|
|
58
|
+
makeFx<A, E | E2, R | R2>((sink) =>
|
|
59
|
+
combinators.withEarlyExit(sink, (sink) =>
|
|
60
|
+
fx.run(
|
|
61
|
+
makeSink(sink.onFailure, (a) =>
|
|
62
|
+
Effect.matchCauseEffect(predicate(a), {
|
|
63
|
+
onFailure: sink.onFailure,
|
|
64
|
+
onSuccess: (matches) => (matches ? sink.earlyExit : sink.onSuccess(a)),
|
|
65
|
+
}),
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
|
|
34
72
|
/**
|
|
35
73
|
* Drops elements from an Fx after a predicate returns true.
|
|
36
74
|
* The element that satisfies the predicate is included in the output.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import type { Fx } from "../Fx.js";
|
|
4
|
+
import { takeUntil, takeUntilEffect } from "./takeUntil.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Takes elements from an Fx while a predicate returns true.
|
|
8
|
+
* Stops at the first element for which the predicate returns false; that element is not included.
|
|
9
|
+
*
|
|
10
|
+
* @param predicate - The predicate function.
|
|
11
|
+
* @returns An `Fx` that emits while the predicate holds.
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
* @category combinators
|
|
14
|
+
*/
|
|
15
|
+
export const takeWhile: {
|
|
16
|
+
<A>(predicate: (a: A) => boolean): <E, R>(fx: Fx<A, E, R>) => Fx<A, E, R>;
|
|
17
|
+
<A, E, R>(fx: Fx<A, E, R>, predicate: (a: A) => boolean): Fx<A, E, R>;
|
|
18
|
+
} = dual(
|
|
19
|
+
2,
|
|
20
|
+
<A, E, R>(fx: Fx<A, E, R>, predicate: (a: A) => boolean): Fx<A, E, R> =>
|
|
21
|
+
takeUntil(fx, (a) => !predicate(a)),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Takes elements from an Fx while an effectful predicate returns true.
|
|
26
|
+
* Stops at the first element for which the predicate effect succeeds with false; that element is not included.
|
|
27
|
+
*
|
|
28
|
+
* @param predicate - Effectful predicate function.
|
|
29
|
+
* @returns An `Fx` that emits while the predicate holds.
|
|
30
|
+
* @since 1.0.0
|
|
31
|
+
* @category combinators
|
|
32
|
+
*/
|
|
33
|
+
export const takeWhileEffect: {
|
|
34
|
+
<A, E2, R2>(
|
|
35
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
36
|
+
): <E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, R | R2>;
|
|
37
|
+
<A, E, R, E2, R2>(
|
|
38
|
+
fx: Fx<A, E, R>,
|
|
39
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
40
|
+
): Fx<A, E | E2, R | R2>;
|
|
41
|
+
} = dual(
|
|
42
|
+
2,
|
|
43
|
+
<A, E, R, E2, R2>(
|
|
44
|
+
fx: Fx<A, E, R>,
|
|
45
|
+
predicate: (a: A) => Effect.Effect<boolean, E2, R2>,
|
|
46
|
+
): Fx<A, E | E2, R | R2> => takeUntilEffect(fx, (a) => Effect.map(predicate(a), (b) => !b)),
|
|
47
|
+
);
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Exit from "effect/Exit";
|
|
3
|
+
import * as Fiber from "effect/Fiber";
|
|
4
|
+
import { dual } from "effect/Function";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
import * as Queue from "effect/Queue";
|
|
7
|
+
import { make as makeSink } from "../../Sink/Sink.js";
|
|
8
|
+
import { make } from "../constructors/make.js";
|
|
9
|
+
import type { Fx } from "../Fx.js";
|
|
10
|
+
import { map } from "./map.js";
|
|
11
|
+
import { tuple } from "./tuple.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Zips two Fx streams in strict lockstep: emits a pair `[a, b]` only when both
|
|
15
|
+
* streams have produced their next value. Emits the i-th pair when both have
|
|
16
|
+
* produced at least i values.
|
|
17
|
+
*
|
|
18
|
+
* **Completion:** The zipped stream completes when the **first** of the two
|
|
19
|
+
* streams completes (no further pairs are emitted). The other stream is
|
|
20
|
+
* interrupted.
|
|
21
|
+
*
|
|
22
|
+
* **Errors:** The first failure from either stream fails the zipped stream.
|
|
23
|
+
*
|
|
24
|
+
* @param that - The second Fx stream.
|
|
25
|
+
* @returns An Fx that emits pairs `[A, B]`.
|
|
26
|
+
* @since 1.0.0
|
|
27
|
+
* @category combinators
|
|
28
|
+
*/
|
|
29
|
+
export const zip: {
|
|
30
|
+
<A2, E2, R2>(
|
|
31
|
+
that: Fx<A2, E2, R2>,
|
|
32
|
+
): <A, E, R>(self: Fx<A, E, R>) => Fx<readonly [A, A2], E | E2, R | R2>;
|
|
33
|
+
<A, E, R, A2, E2, R2>(
|
|
34
|
+
self: Fx<A, E, R>,
|
|
35
|
+
that: Fx<A2, E2, R2>,
|
|
36
|
+
): Fx<readonly [A, A2], E | E2, R | R2>;
|
|
37
|
+
} = dual(
|
|
38
|
+
2,
|
|
39
|
+
<A, E, R, A2, E2, R2>(
|
|
40
|
+
self: Fx<A, E, R>,
|
|
41
|
+
that: Fx<A2, E2, R2>,
|
|
42
|
+
): Fx<readonly [A, A2], E | E2, R | R2> =>
|
|
43
|
+
make<readonly [A, A2], E | E2, R | R2>((sink) =>
|
|
44
|
+
Effect.gen(function* () {
|
|
45
|
+
const leftQueue = yield* Queue.unbounded<Option.Option<A>>();
|
|
46
|
+
const rightQueue = yield* Queue.unbounded<Option.Option<A2>>();
|
|
47
|
+
|
|
48
|
+
const leftSink = makeSink(sink.onFailure, (a: A) => Queue.offer(leftQueue, Option.some(a)));
|
|
49
|
+
const rightSink = makeSink(sink.onFailure, (b: A2) =>
|
|
50
|
+
Queue.offer(rightQueue, Option.some(b)),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const runLeft = self
|
|
54
|
+
.run(leftSink)
|
|
55
|
+
.pipe(Effect.ensuring(Queue.offer(leftQueue, Option.none())));
|
|
56
|
+
const runRight = that
|
|
57
|
+
.run(rightSink)
|
|
58
|
+
.pipe(Effect.ensuring(Queue.offer(rightQueue, Option.none())));
|
|
59
|
+
|
|
60
|
+
const consumer = Effect.gen(function* () {
|
|
61
|
+
while (true) {
|
|
62
|
+
const exitA = yield* Effect.exit(Queue.take(leftQueue));
|
|
63
|
+
if (Exit.isFailure(exitA)) return;
|
|
64
|
+
if (Option.isNone(exitA.value)) return;
|
|
65
|
+
const exitB = yield* Effect.exit(Queue.take(rightQueue));
|
|
66
|
+
if (Exit.isFailure(exitB)) return;
|
|
67
|
+
if (Option.isNone(exitB.value)) return;
|
|
68
|
+
yield* sink.onSuccess([exitA.value.value, exitB.value.value] as const);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const leftFiber = yield* Effect.forkChild(runLeft);
|
|
73
|
+
const rightFiber = yield* Effect.forkChild(runRight);
|
|
74
|
+
yield* consumer.pipe(
|
|
75
|
+
Effect.ensuring(Fiber.interrupt(leftFiber)),
|
|
76
|
+
Effect.ensuring(Fiber.interrupt(rightFiber)),
|
|
77
|
+
);
|
|
78
|
+
}),
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Zips two Fx streams in strict lockstep and combines each pair with a function.
|
|
84
|
+
* Emits `f(a, b)` when both streams have produced their next value.
|
|
85
|
+
*
|
|
86
|
+
* **Completion:** Completes when the **first** of the two streams completes.
|
|
87
|
+
* **Errors:** The first failure from either stream fails the result.
|
|
88
|
+
*
|
|
89
|
+
* @param that - The second Fx stream.
|
|
90
|
+
* @param f - Function to combine the pair `(a, b)` into a single value.
|
|
91
|
+
* @returns An Fx that emits combined values.
|
|
92
|
+
* @since 1.0.0
|
|
93
|
+
* @category combinators
|
|
94
|
+
*/
|
|
95
|
+
export const zipWith: {
|
|
96
|
+
<A, A2, E2, R2, B>(
|
|
97
|
+
that: Fx<A2, E2, R2>,
|
|
98
|
+
f: (a: A, b: A2) => B,
|
|
99
|
+
): <E, R>(self: Fx<A, E, R>) => Fx<B, E | E2, R | R2>;
|
|
100
|
+
<A, E, R, A2, E2, R2, B>(
|
|
101
|
+
self: Fx<A, E, R>,
|
|
102
|
+
that: Fx<A2, E2, R2>,
|
|
103
|
+
f: (a: A, b: A2) => B,
|
|
104
|
+
): Fx<B, E | E2, R | R2>;
|
|
105
|
+
} = dual(
|
|
106
|
+
3,
|
|
107
|
+
<A, E, R, A2, E2, R2, B>(
|
|
108
|
+
self: Fx<A, E, R>,
|
|
109
|
+
that: Fx<A2, E2, R2>,
|
|
110
|
+
f: (a: A, b: A2) => B,
|
|
111
|
+
): Fx<B, E | E2, R | R2> => map(zip(self, that), (pair) => f(pair[0], pair[1])),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Zips two Fx streams by latest values: waits for both to emit at least once,
|
|
116
|
+
* then emits `[left, right]` whenever **either** stream emits (using the latest
|
|
117
|
+
* value from the other). No strict pairing; output count is the sum of
|
|
118
|
+
* emissions from both after the first pair.
|
|
119
|
+
*
|
|
120
|
+
* **Completion:** Completes when **both** streams have completed.
|
|
121
|
+
* **Errors:** The first failure from either stream fails the result.
|
|
122
|
+
*
|
|
123
|
+
* @param that - The second Fx stream.
|
|
124
|
+
* @returns An Fx that emits `[AL, AR]` on every update from either stream.
|
|
125
|
+
* @since 1.0.0
|
|
126
|
+
* @category combinators
|
|
127
|
+
*/
|
|
128
|
+
export const zipLatest: {
|
|
129
|
+
<AR, ER, RR>(
|
|
130
|
+
that: Fx<AR, ER, RR>,
|
|
131
|
+
): <AL, EL, RL>(self: Fx<AL, EL, RL>) => Fx<readonly [AL, AR], EL | ER, RL | RR>;
|
|
132
|
+
<AL, EL, RL, AR, ER, RR>(
|
|
133
|
+
self: Fx<AL, EL, RL>,
|
|
134
|
+
that: Fx<AR, ER, RR>,
|
|
135
|
+
): Fx<readonly [AL, AR], EL | ER, RL | RR>;
|
|
136
|
+
} = dual(
|
|
137
|
+
2,
|
|
138
|
+
<AL, EL, RL, AR, ER, RR>(
|
|
139
|
+
self: Fx<AL, EL, RL>,
|
|
140
|
+
that: Fx<AR, ER, RR>,
|
|
141
|
+
): Fx<readonly [AL, AR], EL | ER, RL | RR> => tuple(self, that),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Zips two Fx streams by latest values and combines each pair with a function.
|
|
146
|
+
* Waits for both to emit at least once, then emits `f(left, right)` whenever
|
|
147
|
+
* either stream emits.
|
|
148
|
+
*
|
|
149
|
+
* **Completion:** Completes when **both** streams have completed.
|
|
150
|
+
* **Errors:** The first failure from either stream fails the result.
|
|
151
|
+
*
|
|
152
|
+
* @param that - The second Fx stream.
|
|
153
|
+
* @param f - Function to combine the latest `(left, right)` into a single value.
|
|
154
|
+
* @returns An Fx that emits combined values.
|
|
155
|
+
* @since 1.0.0
|
|
156
|
+
* @category combinators
|
|
157
|
+
*/
|
|
158
|
+
export const zipLatestWith: {
|
|
159
|
+
<AL, AR, ER, RR, B>(
|
|
160
|
+
that: Fx<AR, ER, RR>,
|
|
161
|
+
f: (left: AL, right: AR) => B,
|
|
162
|
+
): <EL, RL>(self: Fx<AL, EL, RL>) => Fx<B, EL | ER, RL | RR>;
|
|
163
|
+
<AL, EL, RL, AR, ER, RR, B>(
|
|
164
|
+
self: Fx<AL, EL, RL>,
|
|
165
|
+
that: Fx<AR, ER, RR>,
|
|
166
|
+
f: (left: AL, right: AR) => B,
|
|
167
|
+
): Fx<B, EL | ER, RL | RR>;
|
|
168
|
+
} = dual(
|
|
169
|
+
3,
|
|
170
|
+
<AL, EL, RL, AR, ER, RR, B>(
|
|
171
|
+
self: Fx<AL, EL, RL>,
|
|
172
|
+
that: Fx<AR, ER, RR>,
|
|
173
|
+
f: (left: AL, right: AR) => B,
|
|
174
|
+
): Fx<B, EL | ER, RL | RR> => map(zipLatest(self, that), (pair) => f(pair[0], pair[1])),
|
|
175
|
+
);
|
|
@@ -14,10 +14,10 @@ import { make } from "./make.js";
|
|
|
14
14
|
* @category constructors
|
|
15
15
|
*/
|
|
16
16
|
export const at: {
|
|
17
|
-
(delay: Duration.
|
|
18
|
-
<A>(value: A, delay: Duration.
|
|
17
|
+
(delay: Duration.Input): <A>(value: A) => Fx<A>;
|
|
18
|
+
<A>(value: A, delay: Duration.Input): Fx<A>;
|
|
19
19
|
} = dual(
|
|
20
20
|
2,
|
|
21
|
-
<A>(value: A, delay: Duration.
|
|
21
|
+
<A>(value: A, delay: Duration.Input): Fx<A> =>
|
|
22
22
|
make<A, never, never>((sink) => flatMap(sleep(delay), () => sink.onSuccess(value))),
|
|
23
23
|
);
|
|
@@ -11,5 +11,5 @@ import { fromSchedule } from "./fromSchedule.js";
|
|
|
11
11
|
* @since 1.0.0
|
|
12
12
|
* @category constructors
|
|
13
13
|
*/
|
|
14
|
-
export const periodic = (period: Duration.
|
|
14
|
+
export const periodic = (period: Duration.Input): Fx<void> =>
|
|
15
15
|
/*#__PURE__*/ fromSchedule(spaced(period));
|