From d69c8facff7d1444bd868c2233ce892aafb9572b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 1 May 2026 23:25:10 +0200 Subject: [PATCH] Refactor --- packages/effect-fc/src/SynchronizedForm.ts | 37 ++++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/effect-fc/src/SynchronizedForm.ts b/packages/effect-fc/src/SynchronizedForm.ts index 451a30c..ebf83b2 100644 --- a/packages/effect-fc/src/SynchronizedForm.ts +++ b/packages/effect-fc/src/SynchronizedForm.ts @@ -1,4 +1,4 @@ -import { Array, Cause, Chunk, type Context, Effect, Exit, Fiber, Option, ParseResult, Pipeable, Predicate, Schema, type Scope, SubscriptionRef } from "effect" +import { Array, Cause, Chunk, type Context, Effect, Exit, Fiber, Option, ParseResult, Pipeable, Predicate, Schema, type Scope, Stream, SubscriptionRef } from "effect" import * as Form from "./Form.js" import * as Lens from "./Lens.js" import * as Subscribable from "./Subscribable.js" @@ -39,6 +39,7 @@ export class SynchronizedFormImpl< readonly [SynchronizedFormTypeId]: SynchronizedFormTypeId = SynchronizedFormTypeId readonly path = [] as const + readonly value: Subscribable.Subscribable, never, never> readonly encodedValue: Lens.Lens constructor( @@ -46,7 +47,6 @@ export class SynchronizedFormImpl< readonly context: Context.Context, readonly target: Lens.Lens, - readonly value: Lens.Lens, never, never, never, never>, readonly internalEncodedValue: Lens.Lens, readonly issues: Lens.Lens, readonly validationFiber: Lens.Lens>, never, never, never, never>, @@ -58,6 +58,8 @@ export class SynchronizedFormImpl< readonly runSemaphore: Effect.Semaphore, ) { super() + + this.value = makeValueSubscribable(this) this.encodedValue = makeEncodedValueLens(this) } @@ -72,10 +74,7 @@ export class SynchronizedFormImpl< Schema.decode(this.schema, { errors: "all" })(encodedValue), exit => Effect.andThen( Exit.matchEffect(exit, { - onSuccess: v => Effect.andThen( - Lens.set(this.value, Option.some(v)), - Lens.set(this.issues, Array.empty()), - ), + onSuccess: () => Lens.set(this.issues, Array.empty()), onFailure: c => Option.match( Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), { @@ -127,7 +126,6 @@ export class SynchronizedFormImpl< // ), // ), // Effect.andThen( - // Lens.set(this.value, Option.some(targetValue)), // Lens.set(this.issues, Array.empty()), // ), // )), @@ -141,6 +139,13 @@ export class SynchronizedFormImpl< } } +const makeValueSubscribable = ( + self: SynchronizedFormImpl +): Subscribable.Subscribable, never, never> => Subscribable.make({ + get get() { return Effect.provide(Effect.option(self.target.get), self.context) }, + get changes() { return Stream.provideContext(self.target.changes, self.context) } +}) + const makeEncodedValueLens = ( self: SynchronizedFormImpl ): Lens.Lens => Lens.make({ @@ -184,11 +189,6 @@ export const make = Effect.fnUntraced(function* { - const valueLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none())) - const issuesLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Array.empty())) - const validationFiberLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())) - const isCommittingLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(false)) - const initialEncodedValue = options.initialEncodedValue !== undefined ? options.initialEncodedValue : yield* Effect.flatMap( @@ -196,21 +196,24 @@ export const make = Effect.fnUntraced(function* (Array.empty())) + const validationFiberLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())) + const isCommittingLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(false)) + return new SynchronizedFormImpl( options.schema, yield* Effect.context(), options.target, - valueLens, - Lens.fromSubscriptionRef(yield* SubscriptionRef.make(initialEncodedValue)), + internalEncodedValueLens, issuesLens, validationFiberLens, Subscribable.map(validationFiberLens, Option.isSome), Subscribable.map( - Subscribable.zipLatestAll(valueLens, issuesLens, validationFiberLens, isCommittingLens), - ([value, issues, validationFiber, isCommitting]) => ( - Option.isSome(value) && + Subscribable.zipLatestAll(issuesLens, validationFiberLens, isCommittingLens), + ([issues, validationFiber, isCommitting]) => ( Array.isEmptyReadonlyArray(issues) && Option.isNone(validationFiber) && !isCommitting