@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
|
@@ -163,3 +163,259 @@ export const catchTag: {
|
|
|
163
163
|
),
|
|
164
164
|
),
|
|
165
165
|
);
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Recovers from a typed failure when a predicate holds, by switching to a fallback Fx.
|
|
169
|
+
* Only applies to `Cause.Fail`; defects and interrupts are not caught.
|
|
170
|
+
*
|
|
171
|
+
* Mirrors `Effect.catchIf`.
|
|
172
|
+
*
|
|
173
|
+
* @since 1.0.0
|
|
174
|
+
* @category combinators
|
|
175
|
+
*/
|
|
176
|
+
export const catchIf: {
|
|
177
|
+
<E, A2, E2, R2>(
|
|
178
|
+
predicate: (e: E) => boolean,
|
|
179
|
+
f: (e: E) => Fx<A2, E2, R2>,
|
|
180
|
+
): <A, R>(self: Fx<A, E, R>) => Fx<A | A2, E | E2, R | R2>;
|
|
181
|
+
|
|
182
|
+
<A, E, R, A2, E2, R2>(
|
|
183
|
+
self: Fx<A, E, R>,
|
|
184
|
+
predicate: (e: E) => boolean,
|
|
185
|
+
f: (e: E) => Fx<A2, E2, R2>,
|
|
186
|
+
): Fx<A | A2, E | E2, R | R2>;
|
|
187
|
+
} = dual(
|
|
188
|
+
3,
|
|
189
|
+
<A, E, R, A2, E2, R2>(
|
|
190
|
+
self: Fx<A, E, R>,
|
|
191
|
+
predicate: (e: E) => boolean,
|
|
192
|
+
f: (e: E) => Fx<A2, E2, R2>,
|
|
193
|
+
): Fx<A | A2, E | E2, R | R2> =>
|
|
194
|
+
make<A | A2, E | E2, R | R2>((sink) =>
|
|
195
|
+
self.run(
|
|
196
|
+
makeSink((cause) => {
|
|
197
|
+
const result = Cause.findFail(cause);
|
|
198
|
+
if (Result.isFailure(result)) {
|
|
199
|
+
return sink.onFailure(result.failure);
|
|
200
|
+
}
|
|
201
|
+
const error = result.success.error;
|
|
202
|
+
if (predicate(error)) {
|
|
203
|
+
return f(error).run(sink);
|
|
204
|
+
}
|
|
205
|
+
return sink.onFailure(cause);
|
|
206
|
+
}, sink.onSuccess),
|
|
207
|
+
),
|
|
208
|
+
),
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Recovers from a failure cause when a predicate on the cause holds,
|
|
213
|
+
* by switching to a fallback Fx.
|
|
214
|
+
*
|
|
215
|
+
* Mirrors `Effect.catchCauseIf`.
|
|
216
|
+
*
|
|
217
|
+
* @since 1.0.0
|
|
218
|
+
* @category combinators
|
|
219
|
+
*/
|
|
220
|
+
export const catchCauseIf: {
|
|
221
|
+
<E, A2, E2, R2>(
|
|
222
|
+
predicate: (cause: Cause.Cause<E>) => boolean,
|
|
223
|
+
f: (cause: Cause.Cause<E>) => Fx<A2, E2, R2>,
|
|
224
|
+
): <A, R>(self: Fx<A, E, R>) => Fx<A | A2, E | E2, R | R2>;
|
|
225
|
+
|
|
226
|
+
<A, E, R, A2, E2, R2>(
|
|
227
|
+
self: Fx<A, E, R>,
|
|
228
|
+
predicate: (cause: Cause.Cause<E>) => boolean,
|
|
229
|
+
f: (cause: Cause.Cause<E>) => Fx<A2, E2, R2>,
|
|
230
|
+
): Fx<A | A2, E | E2, R | R2>;
|
|
231
|
+
} = dual(
|
|
232
|
+
3,
|
|
233
|
+
<A, E, R, A2, E2, R2>(
|
|
234
|
+
self: Fx<A, E, R>,
|
|
235
|
+
predicate: (cause: Cause.Cause<E>) => boolean,
|
|
236
|
+
f: (cause: Cause.Cause<E>) => Fx<A2, E2, R2>,
|
|
237
|
+
): Fx<A | A2, E | E2, R | R2> =>
|
|
238
|
+
make<A | A2, E | E2, R | R2>((sink) =>
|
|
239
|
+
self.run(
|
|
240
|
+
makeSink(
|
|
241
|
+
(cause) => (predicate(cause) ? f(cause).run(sink) : sink.onFailure(cause)),
|
|
242
|
+
sink.onSuccess,
|
|
243
|
+
),
|
|
244
|
+
),
|
|
245
|
+
),
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
type TaggedCase<E> = {
|
|
249
|
+
[K in Extract<E, { _tag: string }>["_tag"]]+?: (
|
|
250
|
+
error: Extract<E, { _tag: K }>,
|
|
251
|
+
) => Fx<unknown, unknown, unknown>;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Recovers from typed failures by matching on the `_tag` field with multiple handlers at once.
|
|
256
|
+
*
|
|
257
|
+
* Mirrors `Effect.catchTags`.
|
|
258
|
+
*
|
|
259
|
+
* @since 1.0.0
|
|
260
|
+
* @category combinators
|
|
261
|
+
*/
|
|
262
|
+
export const catchTags: {
|
|
263
|
+
<E, Cases extends TaggedCase<E>>(
|
|
264
|
+
cases: Cases,
|
|
265
|
+
): <A, R>(
|
|
266
|
+
self: Fx<A, E, R>,
|
|
267
|
+
) => Fx<
|
|
268
|
+
| A
|
|
269
|
+
| {
|
|
270
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<infer A2, unknown, unknown>
|
|
271
|
+
? A2
|
|
272
|
+
: never;
|
|
273
|
+
}[keyof Cases],
|
|
274
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
275
|
+
| {
|
|
276
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, infer E2, unknown>
|
|
277
|
+
? E2
|
|
278
|
+
: never;
|
|
279
|
+
}[keyof Cases],
|
|
280
|
+
| R
|
|
281
|
+
| {
|
|
282
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, unknown, infer R2>
|
|
283
|
+
? R2
|
|
284
|
+
: never;
|
|
285
|
+
}[keyof Cases]
|
|
286
|
+
>;
|
|
287
|
+
|
|
288
|
+
<A, E, R, Cases extends TaggedCase<E>>(
|
|
289
|
+
self: Fx<A, E, R>,
|
|
290
|
+
cases: Cases,
|
|
291
|
+
): Fx<
|
|
292
|
+
| A
|
|
293
|
+
| {
|
|
294
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<infer A2, unknown, unknown>
|
|
295
|
+
? A2
|
|
296
|
+
: never;
|
|
297
|
+
}[keyof Cases],
|
|
298
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
299
|
+
| {
|
|
300
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, infer E2, unknown>
|
|
301
|
+
? E2
|
|
302
|
+
: never;
|
|
303
|
+
}[keyof Cases],
|
|
304
|
+
| R
|
|
305
|
+
| {
|
|
306
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, unknown, infer R2>
|
|
307
|
+
? R2
|
|
308
|
+
: never;
|
|
309
|
+
}[keyof Cases]
|
|
310
|
+
>;
|
|
311
|
+
} = dual(
|
|
312
|
+
2,
|
|
313
|
+
<A, E, R, Cases extends TaggedCase<E>>(
|
|
314
|
+
self: Fx<A, E, R>,
|
|
315
|
+
cases: Cases,
|
|
316
|
+
): Fx<
|
|
317
|
+
| A
|
|
318
|
+
| {
|
|
319
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<infer A2, unknown, unknown>
|
|
320
|
+
? A2
|
|
321
|
+
: never;
|
|
322
|
+
}[keyof Cases],
|
|
323
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
324
|
+
| {
|
|
325
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, infer E2, unknown>
|
|
326
|
+
? E2
|
|
327
|
+
: never;
|
|
328
|
+
}[keyof Cases],
|
|
329
|
+
| R
|
|
330
|
+
| {
|
|
331
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, unknown, infer R2>
|
|
332
|
+
? R2
|
|
333
|
+
: never;
|
|
334
|
+
}[keyof Cases]
|
|
335
|
+
> =>
|
|
336
|
+
make<
|
|
337
|
+
| A
|
|
338
|
+
| {
|
|
339
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<infer A2, unknown, unknown>
|
|
340
|
+
? A2
|
|
341
|
+
: never;
|
|
342
|
+
}[keyof Cases],
|
|
343
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
344
|
+
| {
|
|
345
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, infer E2, unknown>
|
|
346
|
+
? E2
|
|
347
|
+
: never;
|
|
348
|
+
}[keyof Cases],
|
|
349
|
+
| R
|
|
350
|
+
| {
|
|
351
|
+
[K in keyof Cases]: Cases[K] extends (e: unknown) => Fx<unknown, unknown, infer R2>
|
|
352
|
+
? R2
|
|
353
|
+
: never;
|
|
354
|
+
}[keyof Cases]
|
|
355
|
+
>((sink) =>
|
|
356
|
+
self.run(
|
|
357
|
+
makeSink(
|
|
358
|
+
(cause) => {
|
|
359
|
+
const result = Cause.findFail(cause);
|
|
360
|
+
if (Result.isFailure(result)) {
|
|
361
|
+
return sink.onFailure(result.failure);
|
|
362
|
+
}
|
|
363
|
+
const error = result.success.error as E;
|
|
364
|
+
if (!hasTag(error)) {
|
|
365
|
+
return sink.onFailure(
|
|
366
|
+
cause as Cause.Cause<
|
|
367
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
368
|
+
| {
|
|
369
|
+
[K in keyof Cases]: Cases[K] extends (
|
|
370
|
+
e: unknown,
|
|
371
|
+
) => Fx<unknown, infer E2, unknown>
|
|
372
|
+
? E2
|
|
373
|
+
: never;
|
|
374
|
+
}[keyof Cases]
|
|
375
|
+
>,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
const tag = (error as { _tag: string })._tag;
|
|
379
|
+
const handler = (cases as Record<
|
|
380
|
+
string,
|
|
381
|
+
(e: unknown) => Fx<unknown, unknown, unknown>
|
|
382
|
+
>)[tag];
|
|
383
|
+
if (handler !== undefined) {
|
|
384
|
+
return handler(error).run(
|
|
385
|
+
sink as import("../../Sink/Sink.js").Sink<
|
|
386
|
+
unknown,
|
|
387
|
+
unknown,
|
|
388
|
+
import("../../Sink/Sink.js").Context<typeof sink>
|
|
389
|
+
>,
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
return sink.onFailure(
|
|
393
|
+
cause as Cause.Cause<
|
|
394
|
+
| Exclude<E, { _tag: keyof Cases }>
|
|
395
|
+
| {
|
|
396
|
+
[K in keyof Cases]: Cases[K] extends (
|
|
397
|
+
e: unknown,
|
|
398
|
+
) => Fx<unknown, infer E2, unknown>
|
|
399
|
+
? E2
|
|
400
|
+
: never;
|
|
401
|
+
}[keyof Cases]
|
|
402
|
+
>,
|
|
403
|
+
);
|
|
404
|
+
},
|
|
405
|
+
sink.onSuccess,
|
|
406
|
+
),
|
|
407
|
+
) as import("effect/Effect").Effect<
|
|
408
|
+
unknown,
|
|
409
|
+
never,
|
|
410
|
+
| R
|
|
411
|
+
| {
|
|
412
|
+
[K in keyof Cases]: Cases[K] extends (
|
|
413
|
+
e: unknown,
|
|
414
|
+
) => Fx<unknown, unknown, infer R2>
|
|
415
|
+
? R2
|
|
416
|
+
: never;
|
|
417
|
+
}[keyof Cases]
|
|
418
|
+
| import("../../Sink/Sink.js").Context<typeof sink>
|
|
419
|
+
>,
|
|
420
|
+
),
|
|
421
|
+
);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
import * as sinkCore from "../../Sink/combinators.js";
|
|
5
|
+
import { make as makeSink } from "../../Sink/Sink.js";
|
|
6
|
+
import { make } from "../constructors/make.js";
|
|
7
|
+
import type { Fx } from "../Fx.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Drops consecutive elements that are considered equal by an effectful predicate.
|
|
11
|
+
* When the effect returns `true`, the element is skipped; when `false`, it is emitted.
|
|
12
|
+
*
|
|
13
|
+
* This is the effectful variant of `skipRepeatsWith`: instead of a pure
|
|
14
|
+
* `Equivalence<A>`, you supply `(prev, next) => Effect<boolean>` where `true`
|
|
15
|
+
* means "equal" (skip) and `false` means "changed" (emit).
|
|
16
|
+
*
|
|
17
|
+
* @param f - Effectful function: `(prev, next) => Effect<boolean>`. Return `true` to skip (treat as duplicate), `false` to emit.
|
|
18
|
+
* @returns An `Fx` with consecutive "equal" elements removed.
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @category combinators
|
|
21
|
+
*/
|
|
22
|
+
export const changesWithEffect: {
|
|
23
|
+
<A, E2, R2>(
|
|
24
|
+
f: (prev: A, next: A) => Effect.Effect<boolean, E2, R2>,
|
|
25
|
+
): <E, R>(fx: Fx<A, E | E2, R>) => Fx<A, E | E2, R | R2>;
|
|
26
|
+
|
|
27
|
+
<A, E, R, E2, R2>(
|
|
28
|
+
fx: Fx<A, E | E2, R>,
|
|
29
|
+
f: (prev: A, next: A) => Effect.Effect<boolean, E2, R2>,
|
|
30
|
+
): Fx<A, E | E2, R | R2>;
|
|
31
|
+
} = dual(
|
|
32
|
+
2,
|
|
33
|
+
<A, E, R, E2, R2>(
|
|
34
|
+
fx: Fx<A, E | E2, R>,
|
|
35
|
+
f: (prev: A, next: A) => Effect.Effect<boolean, E2, R2>,
|
|
36
|
+
): Fx<A, E | E2, R | R2> =>
|
|
37
|
+
make<A, E | E2, R | R2>((sink) =>
|
|
38
|
+
sinkCore.withStateSemaphore(sink, Option.none<A>() as Option.Option<A>, (s) =>
|
|
39
|
+
fx.run(
|
|
40
|
+
makeSink(s.onFailure, (a2) =>
|
|
41
|
+
Effect.matchCauseEffect(
|
|
42
|
+
Effect.flatMap(s.get, (state) =>
|
|
43
|
+
Option.match(state, {
|
|
44
|
+
onNone: () =>
|
|
45
|
+
Effect.flatMap(s.onSuccess(a2), () =>
|
|
46
|
+
s.updateEffect(() => Effect.succeed(Option.some(a2))),
|
|
47
|
+
),
|
|
48
|
+
onSome: (prev) =>
|
|
49
|
+
Effect.matchCauseEffect(f(prev, a2), {
|
|
50
|
+
onFailure: (cause) => s.onFailure(cause),
|
|
51
|
+
onSuccess: (equal) =>
|
|
52
|
+
equal
|
|
53
|
+
? s.updateEffect(() => Effect.succeed(Option.some(prev)))
|
|
54
|
+
: Effect.flatMap(s.onSuccess(a2), () =>
|
|
55
|
+
s.updateEffect(() => Effect.succeed(Option.some(a2))),
|
|
56
|
+
),
|
|
57
|
+
}),
|
|
58
|
+
}),
|
|
59
|
+
),
|
|
60
|
+
{ onFailure: (cause) => s.onFailure(cause), onSuccess: () => Effect.void },
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
);
|
|
@@ -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 { skipWhile, skipWhileEffect } from "./skipWhile.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Drops elements from an Fx until a predicate returns true.
|
|
8
|
+
* Emits from the first element for which the predicate returns true (including that element) and all following elements.
|
|
9
|
+
*
|
|
10
|
+
* @param predicate - The predicate function.
|
|
11
|
+
* @returns An `Fx` that emits once the predicate first matches.
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
* @category combinators
|
|
14
|
+
*/
|
|
15
|
+
export const dropUntil: {
|
|
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
|
+
skipWhile(fx, (a) => !predicate(a)),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Drops elements from an Fx until an effectful predicate returns true.
|
|
26
|
+
* Emits from the first element for which the predicate effect succeeds with true (including that element) and all following elements.
|
|
27
|
+
*
|
|
28
|
+
* @param predicate - Effectful predicate function.
|
|
29
|
+
* @returns An `Fx` that emits once the predicate first matches.
|
|
30
|
+
* @since 1.0.0
|
|
31
|
+
* @category combinators
|
|
32
|
+
*/
|
|
33
|
+
export const dropUntilEffect: {
|
|
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> => skipWhileEffect(fx, (a) => Effect.map(predicate(a), (b) => !b)),
|
|
47
|
+
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import * as FiberSet from "effect/FiberSet";
|
|
3
|
+
import * as Semaphore from "effect/Semaphore";
|
|
3
4
|
import { dual } from "effect/Function";
|
|
4
5
|
import type * as Scope from "effect/Scope";
|
|
5
6
|
import { make as makeSink } from "../../Sink/Sink.js";
|
|
@@ -26,10 +27,12 @@ export const flatMapConcurrently: FlatMapLike<[concurrency: number]> = dual(
|
|
|
26
27
|
): Fx<B, E | E2, R | R2 | Scope.Scope> =>
|
|
27
28
|
make<B, E | E2, R | R2 | Scope.Scope>(
|
|
28
29
|
Effect.fn(function* (sink) {
|
|
29
|
-
const semaphore = yield*
|
|
30
|
+
const semaphore = yield* Semaphore.make(concurrency);
|
|
30
31
|
const lock = semaphore.withPermits(1);
|
|
31
32
|
const set = yield* FiberSet.make<void, never>();
|
|
32
|
-
yield* self.run(
|
|
33
|
+
yield* self.run(
|
|
34
|
+
makeSink(sink.onFailure, (a) => FiberSet.run(set, lock(Effect.asVoid(f(a).run(sink))))),
|
|
35
|
+
);
|
|
33
36
|
yield* FiberSet.awaitEmpty(set);
|
|
34
37
|
}, extendScope),
|
|
35
38
|
),
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export * from "./catch.js";
|
|
2
|
+
export * from "./changesWithEffect.js";
|
|
2
3
|
export * from "./causes.js";
|
|
3
4
|
export * from "./compact.js";
|
|
4
5
|
export * from "./continueWith.js";
|
|
6
|
+
export * from "./dropUntil.js";
|
|
7
|
+
export * from "./additive.js";
|
|
5
8
|
export * from "./ensuring.js";
|
|
6
9
|
export * from "./exhaustLatestMap.js";
|
|
7
10
|
export * from "./exhaustLatestMapEffect.js";
|
|
@@ -29,23 +32,30 @@ export * from "./loopCause.js";
|
|
|
29
32
|
export * from "./loopCauseEffect.js";
|
|
30
33
|
export * from "./loopEffect.js";
|
|
31
34
|
export * from "./map.js";
|
|
35
|
+
export * from "./mapBoth.js";
|
|
32
36
|
export * from "./mapEffect.js";
|
|
37
|
+
export * from "./mapError.js";
|
|
33
38
|
export * from "./mergeAll.js";
|
|
34
39
|
export * from "./mergeOrdered.js";
|
|
35
40
|
export * from "./onError.js";
|
|
36
41
|
export * from "./onExit.js";
|
|
37
42
|
export * from "./onInterrupt.js";
|
|
38
43
|
export * from "./provide.js";
|
|
44
|
+
export * from "./result.js";
|
|
45
|
+
export * from "./scan.js";
|
|
39
46
|
export * from "./skip.js";
|
|
40
47
|
export * from "./skipRepeats.js";
|
|
48
|
+
export * from "./skipWhile.js";
|
|
41
49
|
export * from "./skipRepeatsWith.js";
|
|
42
50
|
export * from "./slice.js";
|
|
43
51
|
export * from "./switchMap.js";
|
|
44
52
|
export * from "./switchMapEffect.js";
|
|
45
53
|
export * from "./take.js";
|
|
46
54
|
export * from "./takeUntil.js";
|
|
55
|
+
export * from "./takeWhile.js";
|
|
47
56
|
export * from "./tapEffect.js";
|
|
48
57
|
export * from "./tuple.js";
|
|
49
58
|
export * from "./unwrap.js";
|
|
50
59
|
export * from "./unwrapScoped.js";
|
|
51
60
|
export * from "./when.js";
|
|
61
|
+
export * from "./zip.js";
|
|
@@ -37,7 +37,7 @@ export interface KeyedOptions<A, B, C, E2, R2> {
|
|
|
37
37
|
/**
|
|
38
38
|
* Optional debounce duration for emission.
|
|
39
39
|
*/
|
|
40
|
-
readonly debounce?: Duration.
|
|
40
|
+
readonly debounce?: Duration.Input;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -323,7 +323,7 @@ function withDebounceFork<A, E, R>(
|
|
|
323
323
|
fork: <R>(effect: Effect.Effect<A, never, R>) => Effect.Effect<void, never, R>,
|
|
324
324
|
scope: Scope.Scope,
|
|
325
325
|
) => Effect.Effect<A, E, R>,
|
|
326
|
-
duration: Duration.
|
|
326
|
+
duration: Duration.Input,
|
|
327
327
|
): Effect.Effect<unknown, E, R | Scope.Scope> {
|
|
328
328
|
return withScopedFork(
|
|
329
329
|
(fork, scope) =>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import { make as makeSink } from "../../Sink/Sink.js";
|
|
4
|
+
import { make } from "../constructors/make.js";
|
|
5
|
+
import type { Fx } from "../Fx.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Transforms both the success and error channels of an Fx using the provided options.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors `Effect.mapBoth`: `onSuccess` maps emitted values, `onFailure` maps the
|
|
11
|
+
* typed failure (via `Cause.map`); defects and interrupts are preserved.
|
|
12
|
+
*
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
* @category combinators
|
|
15
|
+
*/
|
|
16
|
+
export const mapBoth: {
|
|
17
|
+
<E, E2, A, A2>(options: {
|
|
18
|
+
readonly onFailure: (e: E) => E2;
|
|
19
|
+
readonly onSuccess: (a: A) => A2;
|
|
20
|
+
}): <R>(self: Fx<A, E, R>) => Fx<A2, E2, R>;
|
|
21
|
+
|
|
22
|
+
<A, E, R, E2, A2>(
|
|
23
|
+
self: Fx<A, E, R>,
|
|
24
|
+
options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 },
|
|
25
|
+
): Fx<A2, E2, R>;
|
|
26
|
+
} = dual(
|
|
27
|
+
2,
|
|
28
|
+
<A, E, R, E2, A2>(
|
|
29
|
+
self: Fx<A, E, R>,
|
|
30
|
+
options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 },
|
|
31
|
+
): Fx<A2, E2, R> =>
|
|
32
|
+
make<A2, E2, R>((sink) =>
|
|
33
|
+
self.run(
|
|
34
|
+
makeSink(
|
|
35
|
+
(cause) => sink.onFailure(Cause.map(cause, options.onFailure)),
|
|
36
|
+
(a) => sink.onSuccess(options.onSuccess(a)),
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
2
|
+
import { dual } from "effect/Function";
|
|
3
|
+
import { make as makeSink } from "../../Sink/Sink.js";
|
|
4
|
+
import { make } from "../constructors/make.js";
|
|
5
|
+
import type { Fx } from "../Fx.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Transforms the error channel of an Fx using the provided function.
|
|
9
|
+
*
|
|
10
|
+
* Failures (Cause) are mapped via `Cause.map`, so only the typed failure (`Fail`)
|
|
11
|
+
* is transformed; defects and interrupts are preserved unchanged.
|
|
12
|
+
*
|
|
13
|
+
* Mirrors `Effect.mapError`.
|
|
14
|
+
*
|
|
15
|
+
* @since 1.0.0
|
|
16
|
+
* @category combinators
|
|
17
|
+
*/
|
|
18
|
+
export const mapError: {
|
|
19
|
+
<E, E2>(f: (e: E) => E2): <A, R>(self: Fx<A, E, R>) => Fx<A, E2, R>;
|
|
20
|
+
|
|
21
|
+
<A, E, R, E2>(self: Fx<A, E, R>, f: (e: E) => E2): Fx<A, E2, R>;
|
|
22
|
+
} = dual(
|
|
23
|
+
2,
|
|
24
|
+
<A, E, R, E2>(self: Fx<A, E, R>, f: (e: E) => E2): Fx<A, E2, R> =>
|
|
25
|
+
make<A, E2, R>((sink) =>
|
|
26
|
+
self.run(makeSink((cause) => sink.onFailure(Cause.map(cause, f)), sink.onSuccess)),
|
|
27
|
+
),
|
|
28
|
+
);
|
|
@@ -3,7 +3,7 @@ import * as Exit from "effect/Exit";
|
|
|
3
3
|
import { dual } from "effect/Function";
|
|
4
4
|
import * as Layer from "effect/Layer";
|
|
5
5
|
import * as Scope from "effect/Scope";
|
|
6
|
-
import
|
|
6
|
+
import * as ServiceMap from "effect/ServiceMap";
|
|
7
7
|
import { make } from "../constructors/make.js";
|
|
8
8
|
import type { Fx } from "../Fx.js";
|
|
9
9
|
|
|
@@ -60,3 +60,65 @@ export const provideServices: {
|
|
|
60
60
|
<A, E, R, R2>(fx: Fx<A, E, R>, services: ServiceMap.ServiceMap<R2>): Fx<A, E, Exclude<R, R2>> =>
|
|
61
61
|
provide(fx, Layer.succeedServices(services)),
|
|
62
62
|
);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Provides a single service to an Fx.
|
|
66
|
+
*
|
|
67
|
+
* Equivalent to `provideServices(fx, ServiceMap.make(tag, service))`. The service
|
|
68
|
+
* is available for the entire Fx stream, scoped to the stream lifetime.
|
|
69
|
+
*
|
|
70
|
+
* @param tag - The service tag (identifier).
|
|
71
|
+
* @param service - The service implementation.
|
|
72
|
+
* @returns An `Fx` with the required service provided.
|
|
73
|
+
* @since 1.0.0
|
|
74
|
+
* @category combinators
|
|
75
|
+
*/
|
|
76
|
+
export const provideService: {
|
|
77
|
+
<Id, S>(
|
|
78
|
+
tag: ServiceMap.Service<Id, S>,
|
|
79
|
+
service: S,
|
|
80
|
+
): <A, E, R>(fx: Fx<A, E, R>) => Fx<A, E, Exclude<R, Id>>;
|
|
81
|
+
<A, E, R, Id, S>(
|
|
82
|
+
fx: Fx<A, E, R>,
|
|
83
|
+
tag: ServiceMap.Service<Id, S>,
|
|
84
|
+
service: S,
|
|
85
|
+
): Fx<A, E, Exclude<R, Id>>;
|
|
86
|
+
} = dual(
|
|
87
|
+
3,
|
|
88
|
+
<A, E, R, Id, S>(
|
|
89
|
+
fx: Fx<A, E, R>,
|
|
90
|
+
tag: ServiceMap.Service<Id, S>,
|
|
91
|
+
service: S,
|
|
92
|
+
): Fx<A, E, Exclude<R, Id>> => provideServices(fx, ServiceMap.make(tag, service)),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Provides a single service to an Fx by running an effect that produces the service.
|
|
97
|
+
*
|
|
98
|
+
* The effect is run when the Fx is run; the resulting service is provided to the
|
|
99
|
+
* entire stream. Equivalent to `provide(fx, Layer.effect(tag, serviceEffect))`.
|
|
100
|
+
*
|
|
101
|
+
* @param tag - The service tag (identifier).
|
|
102
|
+
* @param serviceEffect - Effect that produces the service (may have its own requirements).
|
|
103
|
+
* @returns An `Fx` with the required service provided.
|
|
104
|
+
* @since 1.0.0
|
|
105
|
+
* @category combinators
|
|
106
|
+
*/
|
|
107
|
+
export const provideServiceEffect: {
|
|
108
|
+
<Id, S, E2, R2>(
|
|
109
|
+
tag: ServiceMap.Service<Id, S>,
|
|
110
|
+
serviceEffect: Effect.Effect<S, E2, R2>,
|
|
111
|
+
): <A, E, R>(fx: Fx<A, E, R>) => Fx<A, E | E2, Exclude<R, Id> | R2>;
|
|
112
|
+
<A, E, R, Id, S, E2, R2>(
|
|
113
|
+
fx: Fx<A, E, R>,
|
|
114
|
+
tag: ServiceMap.Service<Id, S>,
|
|
115
|
+
serviceEffect: Effect.Effect<S, E2, R2>,
|
|
116
|
+
): Fx<A, E | E2, Exclude<R, Id> | R2>;
|
|
117
|
+
} = dual(
|
|
118
|
+
3,
|
|
119
|
+
<A, E, R, Id, S, E2, R2>(
|
|
120
|
+
fx: Fx<A, E, R>,
|
|
121
|
+
tag: ServiceMap.Service<Id, S>,
|
|
122
|
+
serviceEffect: Effect.Effect<S, E2, R2>,
|
|
123
|
+
): Fx<A, E | E2, Exclude<R, Id> | R2> => provide(fx, Layer.effect(tag, serviceEffect)),
|
|
124
|
+
);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import type { Sink } from "../../Sink/Sink.js";
|
|
4
|
+
import { make } from "../constructors/make.js";
|
|
5
|
+
import type { Fx } from "../Fx.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Materializes success and failure of an Fx as `Result` values.
|
|
9
|
+
*
|
|
10
|
+
* - **Success**: each emitted value is wrapped as `Result.succeed(value)`.
|
|
11
|
+
* - **Failure**: any failure (including typed error, defect, and interrupt) is
|
|
12
|
+
* materialized as `Result.fail(cause)`. The output error type is `Cause<E>`,
|
|
13
|
+
* so defects and interrupts are explicitly represented in the `Result` and
|
|
14
|
+
* the resulting Fx has error type `never`.
|
|
15
|
+
*
|
|
16
|
+
* The resulting Fx never fails at the stream level; all outcomes are emitted as
|
|
17
|
+
* `Result<A, Cause<E>>`. Consumers can use `Result.match` or `Result.isSuccess` /
|
|
18
|
+
* `Result.isFailure` to handle success vs failure (including defect/interrupt).
|
|
19
|
+
*
|
|
20
|
+
* @param fx - The `Fx` stream.
|
|
21
|
+
* @returns An `Fx` emitting `Result<A, Cause<E>>`.
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
* @category combinators
|
|
24
|
+
*/
|
|
25
|
+
export const result = <A, E, R>(fx: Fx<A, E, R>): Fx<Result.Result<A, Cause.Cause<E>>, never, R> =>
|
|
26
|
+
make<Result.Result<A, Cause.Cause<E>>, never, R>((sink) => fx.run(new ResultSink(sink)));
|
|
27
|
+
|
|
28
|
+
class ResultSink<A, E, R> implements Sink<A, E, R> {
|
|
29
|
+
readonly sink: Sink<Result.Result<A, Cause.Cause<E>>, never, R>;
|
|
30
|
+
readonly onSuccess: (value: A) => import("effect/Effect").Effect<unknown, never, R>;
|
|
31
|
+
readonly onFailure: (cause: Cause.Cause<E>) => import("effect/Effect").Effect<unknown, never, R>;
|
|
32
|
+
|
|
33
|
+
constructor(sink: Sink<Result.Result<A, Cause.Cause<E>>, never, R>) {
|
|
34
|
+
this.sink = sink;
|
|
35
|
+
const s = sink;
|
|
36
|
+
this.onSuccess = (value) => s.onSuccess(Result.succeed(value));
|
|
37
|
+
this.onFailure = (cause) => s.onSuccess(Result.fail(cause));
|
|
38
|
+
}
|
|
39
|
+
}
|