Fix utils
Lint / lint (push) Successful in 44s

This commit is contained in:
Julien Valverdé
2026-06-20 15:30:05 +02:00
parent c43e9f135f
commit 2634ce2a99
2 changed files with 94 additions and 12 deletions
+82
View File
@@ -407,6 +407,88 @@ describe("Lens", () => {
expect(result[2]).toEqual(Option.none()) expect(result[2]).toEqual(Option.none())
}) })
test("modify and modifyEffect atomically update and return a result", async () => {
const result = await Effect.runPromise(Effect.gen(function*() {
const parent = yield* SubscriptionRef.make(1)
const lens = Lens.fromSubscriptionRef(parent)
const previous = yield* Lens.modify(lens, n => [`value:${ n }`, n + 1] as const)
const doubled = yield* lens.pipe(Lens.modifyEffect(n => Effect.succeed([n * 2, n + 2] as const)))
const current = yield* parent.get
return [previous, doubled, current] as const
}))
expect(result).toEqual(["value:1", 4, 4])
})
test("conditional synchronous operations preserve values on None", async () => {
const result = await Effect.runPromise(Effect.gen(function*() {
const parent = yield* SubscriptionRef.make(1)
const lens = Lens.fromSubscriptionRef(parent)
const fallback = yield* Lens.modifySome(lens, "fallback", () => Option.none())
const modified = yield* lens.pipe(Lens.modifySome("fallback", n => {
n satisfies number
return Option.some([`value:${ n }`, n + 1] as const)
}))
const previous = yield* lens.pipe(Lens.getAndUpdateSome(n => {
n satisfies number
return Option.some(n + 1)
}))
yield* Lens.updateSome(lens, () => Option.none())
yield* lens.pipe(Lens.updateSome(n => {
n satisfies number
return Option.some(n + 1)
}))
const current = yield* Lens.updateSomeAndGet(lens, () => Option.none())
const updated = yield* lens.pipe(Lens.updateSomeAndGet(n => {
n satisfies number
return Option.some(n + 1)
}))
return [fallback, modified, previous, current, updated, yield* parent.get] as const
}))
expect(result).toEqual(["fallback", "value:1", 2, 4, 5, 5])
})
test("conditional effectful operations preserve values on None", async () => {
const result = await Effect.runPromise(Effect.gen(function*() {
const parent = yield* SubscriptionRef.make(10)
const lens = Lens.fromSubscriptionRef(parent)
const modifyNone: Effect.Effect<string> = Lens.modifySomeEffect(lens, "fallback", () => Option.none())
const fallback = yield* modifyNone
const modify: Effect.Effect<string> = lens.pipe(Lens.modifySomeEffect(
"fallback",
n => {
n satisfies number
return Option.some(Effect.succeed([`value:${ n }`, n + 1] as const))
},
))
const modified = yield* modify
const getAndUpdate: Effect.Effect<number> = lens.pipe(Lens.getAndUpdateSomeEffect(n => {
n satisfies number
return Option.some(Effect.succeed(n + 1))
}))
const getAndUpdateNone: Effect.Effect<number> = lens.pipe(Lens.getAndUpdateSomeEffect(() => Option.none()))
const updateNone: Effect.Effect<void> = lens.pipe(Lens.updateSomeEffect(() => Option.none()))
const update: Effect.Effect<void> = lens.pipe(Lens.updateSomeEffect(n => {
n satisfies number
return Option.some(Effect.succeed(n + 1))
}))
const previous = yield* getAndUpdate
const unchanged = yield* getAndUpdateNone
yield* updateNone
yield* update
const updateAndGetNone: Effect.Effect<number> = lens.pipe(Lens.updateSomeAndGetEffect(() => Option.none()))
const current = yield* updateAndGetNone
const updated = yield* lens.pipe(Lens.updateSomeAndGetEffect(n => {
n satisfies number
return Option.some(Effect.succeed(n + 1))
}))
return [fallback, modified, previous, unchanged, current, updated, yield* parent.get] as const
}))
expect(result).toEqual(["fallback", "value:10", 11, 12, 13, 14, 14])
})
// test("changes stream emits updates when lens mutates state", async () => { // test("changes stream emits updates when lens mutates state", async () => {
// const events = await Effect.runPromise( // const events = await Effect.runPromise(
// Effect.flatMap( // Effect.flatMap(
+12 -12
View File
@@ -911,7 +911,7 @@ export const modifyEffect: {
* Conditionally modifies the value of a `Lens`, returning `fallback` when the function returns `None`. * Conditionally modifies the value of a `Lens`, returning `fallback` when the function returns `None`.
*/ */
export const modifySome: { export const modifySome: {
<B, A>(fallback: B, pf: (a: A) => Option.Option<readonly [B, A]>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<B, ER | EW, RR | RW> <B, A>(fallback: B, pf: (a: NoInfer<A>) => Option.Option<readonly [B, NoInfer<A>]>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<B, ER | EW, RR | RW>
<A, ER, EW, RR, RW, B>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<readonly [B, A]>): Effect.Effect<B, ER | EW, RR | RW> <A, ER, EW, RR, RW, B>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<readonly [B, A]>): Effect.Effect<B, ER | EW, RR | RW>
} = Function.dual(3, <A, ER, EW, RR, RW, B>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<readonly [B, A]>) => } = Function.dual(3, <A, ER, EW, RR, RW, B>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<readonly [B, A]>) =>
self.modifyEffect<B, never, never>(a => Effect.succeed(Option.getOrElse(pf(a), () => [fallback, a] as const))), self.modifyEffect<B, never, never>(a => Effect.succeed(Option.getOrElse(pf(a), () => [fallback, a] as const))),
@@ -921,8 +921,8 @@ export const modifySome: {
* Conditionally modifies the value of a `Lens` with an effect, returning `fallback` when the function returns `None`. * Conditionally modifies the value of a `Lens` with an effect, returning `fallback` when the function returns `None`.
*/ */
export const modifySomeEffect: { export const modifySomeEffect: {
<B, A, E, R>(fallback: B, pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<B, ER | EW | E, RR | RW | R> <B, A, E = never, R = never>(fallback: B, pf: (a: NoInfer<A>) => Option.Option<Effect.Effect<readonly [B, NoInfer<A>], E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<B, ER | EW | E, RR | RW | R>
<A, ER, EW, RR, RW, B, E, R>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>): Effect.Effect<B, ER | EW | E, RR | RW | R> <A, ER, EW, RR, RW, B, E = never, R = never>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>): Effect.Effect<B, ER | EW | E, RR | RW | R>
} = Function.dual(3, <A, ER, EW, RR, RW, B, E, R>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>) => } = Function.dual(3, <A, ER, EW, RR, RW, B, E, R>(self: Lens<A, ER, EW, RR, RW>, fallback: B, pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>) =>
self.modifyEffect<B, E, R>(a => Option.getOrElse(pf(a), () => Effect.succeed([fallback, a] as const))), self.modifyEffect<B, E, R>(a => Option.getOrElse(pf(a), () => Effect.succeed([fallback, a] as const))),
) )
@@ -997,7 +997,7 @@ export const getAndUpdateEffect: {
* Conditionally updates a `Lens` and returns the previous value. * Conditionally updates a `Lens` and returns the previous value.
*/ */
export const getAndUpdateSome: { export const getAndUpdateSome: {
<A>(pf: (a: A) => Option.Option<A>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW, RR | RW> <A>(pf: (a: NoInfer<A>) => Option.Option<NoInfer<A>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW, RR | RW>
<A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>): Effect.Effect<A, ER | EW, RR | RW> <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>): Effect.Effect<A, ER | EW, RR | RW>
} = Function.dual(2, <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>) => } = Function.dual(2, <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>) =>
self.modifyEffect<A, never, never>(a => Effect.succeed([a, Option.getOrElse(pf(a), () => a)] as const)), self.modifyEffect<A, never, never>(a => Effect.succeed([a, Option.getOrElse(pf(a), () => a)] as const)),
@@ -1007,8 +1007,8 @@ export const getAndUpdateSome: {
* Conditionally updates a `Lens` with an effect and returns the previous value. * Conditionally updates a `Lens` with an effect and returns the previous value.
*/ */
export const getAndUpdateSomeEffect: { export const getAndUpdateSomeEffect: {
<A, E, R>(pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW | E, RR | RW | R> <A, E = never, R = never>(pf: (a: NoInfer<A>) => Option.Option<Effect.Effect<NoInfer<A>, E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW | E, RR | RW | R>
<A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): Effect.Effect<A, ER | EW | E, RR | RW | R> <A, ER, EW, RR, RW, E = never, R = never>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): Effect.Effect<A, ER | EW | E, RR | RW | R>
} = Function.dual(2, <A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>) => } = Function.dual(2, <A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>) =>
self.modifyEffect<A, E, R>(a => Effect.map( self.modifyEffect<A, E, R>(a => Effect.map(
Option.getOrElse(pf(a), () => Effect.succeed(a)), Option.getOrElse(pf(a), () => Effect.succeed(a)),
@@ -1056,7 +1056,7 @@ export const updateAndGetEffect: {
* Conditionally updates the value of a `Lens`. * Conditionally updates the value of a `Lens`.
*/ */
export const updateSome: { export const updateSome: {
<A>(pf: (a: A) => Option.Option<A>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<void, ER | EW, RR | RW> <A>(pf: (a: NoInfer<A>) => Option.Option<NoInfer<A>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<void, ER | EW, RR | RW>
<A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>): Effect.Effect<void, ER | EW, RR | RW> <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>): Effect.Effect<void, ER | EW, RR | RW>
} = Function.dual(2, <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>) => } = Function.dual(2, <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>) =>
self.modifyEffect<void, never, never>(a => Effect.succeed([void 0, Option.getOrElse(pf(a), () => a)] as const)), self.modifyEffect<void, never, never>(a => Effect.succeed([void 0, Option.getOrElse(pf(a), () => a)] as const)),
@@ -1066,8 +1066,8 @@ export const updateSome: {
* Conditionally updates the value of a `Lens` with an effect. * Conditionally updates the value of a `Lens` with an effect.
*/ */
export const updateSomeEffect: { export const updateSomeEffect: {
<A, E, R>(pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<void, ER | EW | E, RR | RW | R> <A, E = never, R = never>(pf: (a: NoInfer<A>) => Option.Option<Effect.Effect<NoInfer<A>, E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<void, ER | EW | E, RR | RW | R>
<A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): Effect.Effect<void, ER | EW | E, RR | RW | R> <A, ER, EW, RR, RW, E = never, R = never>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): Effect.Effect<void, ER | EW | E, RR | RW | R>
} = Function.dual(2, <A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>) => } = Function.dual(2, <A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>) =>
self.modifyEffect<void, E, R>(a => Effect.map( self.modifyEffect<void, E, R>(a => Effect.map(
Option.getOrElse(pf(a), () => Effect.succeed(a)), Option.getOrElse(pf(a), () => Effect.succeed(a)),
@@ -1079,7 +1079,7 @@ export const updateSomeEffect: {
* Conditionally updates a `Lens` and returns the resulting value. * Conditionally updates a `Lens` and returns the resulting value.
*/ */
export const updateSomeAndGet: { export const updateSomeAndGet: {
<A>(pf: (a: A) => Option.Option<A>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW, RR | RW> <A>(pf: (a: NoInfer<A>) => Option.Option<NoInfer<A>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW, RR | RW>
<A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>): Effect.Effect<A, ER | EW, RR | RW> <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>): Effect.Effect<A, ER | EW, RR | RW>
} = Function.dual(2, <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>) => } = Function.dual(2, <A, ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<A>) =>
self.modifyEffect<A, never, never>(a => { self.modifyEffect<A, never, never>(a => {
@@ -1092,8 +1092,8 @@ export const updateSomeAndGet: {
* Conditionally updates a `Lens` with an effect and returns the resulting value. * Conditionally updates a `Lens` with an effect and returns the resulting value.
*/ */
export const updateSomeAndGetEffect: { export const updateSomeAndGetEffect: {
<A, E, R>(pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW | E, RR | RW | R> <A, E = never, R = never>(pf: (a: NoInfer<A>) => Option.Option<Effect.Effect<NoInfer<A>, E, R>>): <ER, EW, RR, RW>(self: Lens<A, ER, EW, RR, RW>) => Effect.Effect<A, ER | EW | E, RR | RW | R>
<A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): Effect.Effect<A, ER | EW | E, RR | RW | R> <A, ER, EW, RR, RW, E = never, R = never>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>): Effect.Effect<A, ER | EW | E, RR | RW | R>
} = Function.dual(2, <A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>) => } = Function.dual(2, <A, ER, EW, RR, RW, E, R>(self: Lens<A, ER, EW, RR, RW>, pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>) =>
self.modifyEffect<A, E, R>(a => Effect.map( self.modifyEffect<A, E, R>(a => Effect.map(
Option.getOrElse(pf(a), () => Effect.succeed(a)), Option.getOrElse(pf(a), () => Effect.succeed(a)),