0.2.0 #5

Merged
Thilawyn merged 59 commits from next into master 2026-05-30 06:10:54 +02:00
3 changed files with 55 additions and 18 deletions
Showing only changes of commit 6e67d8ab7c - Show all commits
-14
View File
@@ -95,20 +95,6 @@ const lens = Effect.all([
Note: while Lens supports asynchronous effects for the proxy logic, we would recommend keeping them synchronous to preserve atomicity. Note: while Lens supports asynchronous effects for the proxy logic, we would recommend keeping them synchronous to preserve atomicity.
If a `Lens` depends on a service in its environment, you can provide that service directly to the lens:
```typescript
class Offset extends Context.Tag("Offset")<Offset, { readonly value: number }>() {}
const root = Lens.fromSubscriptionRef(ref)
const offsetLens = Lens.mapEffect(
root,
n => Effect.map(Offset, ({ value }) => n + value),
(_n, next) => Effect.map(Offset, ({ value }) => next - value),
)
const runnableLens = Lens.provide(offsetLens, Offset, { value: 5 })
```
### Focusing ### Focusing
+2 -3
View File
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { Chunk, Context, Effect, Option, SubscriptionRef } from "effect" import { Chunk, Context, Effect, Layer, Option, SubscriptionRef } from "effect"
import * as Lens from "./Lens.js" import * as Lens from "./Lens.js"
@@ -67,8 +67,7 @@ describe("Lens", () => {
n => Effect.map(Offset, ({ value }) => n + value), n => Effect.map(Offset, ({ value }) => n + value),
(_n, next) => Effect.map(Offset, ({ value }) => next - value), (_n, next) => Effect.map(Offset, ({ value }) => next - value),
), ),
Offset, Layer.succeed(Offset, { value: 5 }),
{ value: 5 },
) )
return Effect.flatMap( return Effect.flatMap(
+53 -1
View File
@@ -1,4 +1,4 @@
import { Array, Chunk, type Context, Effect, Function, identity, Option, Pipeable, Predicate, Readable, Stream, type SubscriptionRef, type SynchronizedRef } from "effect" import { Array, Chunk, Effect, Function, identity, type Layer, Option, Pipeable, Predicate, Readable, Stream, type Context, type SubscriptionRef, type SynchronizedRef } from "effect"
import type { NoSuchElementException } from "effect/Cause" import type { NoSuchElementException } from "effect/Cause"
import * as Subscribable from "./Subscribable.js" import * as Subscribable from "./Subscribable.js"
@@ -273,6 +273,58 @@ export const mapStream: {
* Provides a single service to a `Lens`, removing it from both the read and write environments. * Provides a single service to a `Lens`, removing it from both the read and write environments.
*/ */
export const provide: { export const provide: {
<const Layers extends readonly [Layer.Layer.Any, ...Array<Layer.Layer.Any>]>(
layers: Layers,
): <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Lens<
A,
ER | { [k in keyof Layers]: Layer.Layer.Error<Layers[k]> }[number],
EW | { [k in keyof Layers]: Layer.Layer.Error<Layers[k]> }[number],
{ [k in keyof Layers]: Layer.Layer.Context<Layers[k]> }[number] | Exclude<RR, { [k in keyof Layers]: Layer.Layer.Success<Layers[k]> }[number]>,
{ [k in keyof Layers]: Layer.Layer.Context<Layers[k]> }[number] | Exclude<RW, { [k in keyof Layers]: Layer.Layer.Success<Layers[k]> }[number]>
>
<ROut, E2, RIn>(
layer: Layer.Layer<ROut, E2, RIn>,
): <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Lens<A, ER | E2, EW | E2, RIn | Exclude<RR, ROut>, RIn | Exclude<RW, ROut>>
<R2>(
context: Context.Context<R2>,
): <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Lens<A, ER, EW, Exclude<RR, R2>, Exclude<RW, R2>>
<A, ER, EW, RR, RW, const Layers extends readonly [Layer.Layer.Any, ...Array<Layer.Layer.Any>]>(
self: Lens<A, ER, EW, RR, RW>,
layers: Layers,
): Lens<
A,
ER | { [k in keyof Layers]: Layer.Layer.Error<Layers[k]> }[number],
EW | { [k in keyof Layers]: Layer.Layer.Error<Layers[k]> }[number],
{ [k in keyof Layers]: Layer.Layer.Context<Layers[k]> }[number] | Exclude<RR, { [k in keyof Layers]: Layer.Layer.Success<Layers[k]> }[number]>,
{ [k in keyof Layers]: Layer.Layer.Context<Layers[k]> }[number] | Exclude<RW, { [k in keyof Layers]: Layer.Layer.Success<Layers[k]> }[number]>
>
<A, ER, EW, RR, RW, ROut, E2, RIn>(
self: Lens<A, ER, EW, RR, RW>,
layer: Layer.Layer<ROut, E2, RIn>,
): Lens<A, ER | E2, EW | E2, RIn | Exclude<RR, ROut>, RIn | Exclude<RW, ROut>>
<A, ER, EW, RR, RW, R2>(
self: Lens<A, ER, EW, RR, RW>,
context: Context.Context<R2>,
): Lens<A, ER, EW, Exclude<RR, R2>, Exclude<RW, R2>>
} = Function.dual(2, <A, ER, EW, RR, RW>(
self: Lens<A, ER, EW, RR, RW>,
provider: unknown,
): Lens<A, any, any, any, any> => make({
get get() { return Effect.provide(self.get, provider as any) },
get changes() {
return Stream.unwrapScoped(
Effect.map(
Effect.provide(Effect.context<RR>(), provider as any),
(context) => Stream.provideContext(self.changes as Stream.Stream<A, ER, RR>, context),
),
)
},
modify: <B, E1 = never, R1 = never>(
f: (a: A) => Effect.Effect<readonly [B, A], E1, R1>
) => Effect.provide(self.modify(f), provider as any),
}))
export const provideService: {
<A, ER, EW, RR, RW, I, S>( <A, ER, EW, RR, RW, I, S>(
self: Lens<A, ER, EW, RR, RW>, self: Lens<A, ER, EW, RR, RW>,
tag: Context.Tag<I, S>, tag: Context.Tag<I, S>,