Refactoring
All checks were successful
Lint / lint (push) Successful in 12s

This commit is contained in:
Julien Valverdé
2025-09-30 19:43:39 +02:00
parent 9d978e709f
commit a1dc98aa04

View File

@@ -1,5 +1,5 @@
import * as AsyncData from "@typed/async-data" import * as AsyncData from "@typed/async-data"
import { Array, Duration, Effect, Equal, Exit, flow, identity, Option, ParseResult, pipe, Pipeable, Ref, Schema, Scope, Stream, Subscribable, SubscriptionRef } from "effect" import { Array, Cause, Chunk, Duration, Effect, Equal, Exit, Fiber, flow, identity, Option, ParseResult, pipe, Pipeable, Ref, Schema, Scope, Stream, Subscribable, SubscriptionRef } from "effect"
import type { NoSuchElementException } from "effect/Cause" import type { NoSuchElementException } from "effect/Cause"
import * as React from "react" import * as React from "react"
import { Hooks } from "./hooks/index.js" import { Hooks } from "./hooks/index.js"
@@ -19,7 +19,7 @@ extends Pipeable.Pipeable {
readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>, readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>,
readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>, readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>, readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>,
readonly isValidatingRef: SubscriptionRef.SubscriptionRef<boolean> readonly validationFiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<void, never>>>
readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>, readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>,
readonly canSubmitSubscribable: Subscribable.Subscribable<boolean> readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>
@@ -36,7 +36,7 @@ extends Pipeable.Class() implements Form<A, I, R, SA, SE, SR> {
readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>, readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>,
readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>, readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>, readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>,
readonly isValidatingRef: SubscriptionRef.SubscriptionRef<boolean>, readonly validationFiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<void, never>>>,
readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>, readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>,
readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>, readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>,
@@ -62,7 +62,7 @@ export const make: {
) { ) {
const valueRef = yield* SubscriptionRef.make(Option.none<A>()) const valueRef = yield* SubscriptionRef.make(Option.none<A>())
const errorRef = yield* SubscriptionRef.make(Option.none<ParseResult.ParseError>()) const errorRef = yield* SubscriptionRef.make(Option.none<ParseResult.ParseError>())
const isValidatingRef = yield* SubscriptionRef.make(false) const validationFiberRef = yield* SubscriptionRef.make(Option.none<Fiber.Fiber<void, never>>())
const submitStateRef = yield* SubscriptionRef.make(AsyncData.noData<SA, SE>()) const submitStateRef = yield* SubscriptionRef.make(AsyncData.noData<SA, SE>())
return new FormImpl( return new FormImpl(
@@ -72,25 +72,25 @@ export const make: {
valueRef, valueRef,
yield* SubscriptionRef.make(options.initialEncodedValue), yield* SubscriptionRef.make(options.initialEncodedValue),
errorRef, errorRef,
isValidatingRef, validationFiberRef,
submitStateRef, submitStateRef,
pipe( pipe(
<A>([value, error, isValidating, submitState]: readonly [ <A>([value, error, validationFiber, submitState]: readonly [
Option.Option<A>, Option.Option<A>,
Option.Option<ParseResult.ParseError>, Option.Option<ParseResult.ParseError>,
boolean, Option.Option<Fiber.Fiber<void, never>>,
AsyncData.AsyncData<SA, SE>, AsyncData.AsyncData<SA, SE>,
]) => Option.isSome(value) && Option.isNone(error) && !isValidating && !AsyncData.isLoading(submitState), ]) => Option.isSome(value) && Option.isNone(error) && Option.isNone(validationFiber) && !AsyncData.isLoading(submitState),
filter => SubscribableInternal.make({ filter => SubscribableInternal.make({
get: Effect.map(Effect.all([valueRef, errorRef, isValidatingRef, submitStateRef]), filter), get: Effect.map(Effect.all([valueRef, errorRef, validationFiberRef, submitStateRef]), filter),
get changes() { get changes() {
return Stream.map( return Stream.map(
Stream.zipLatestAll( Stream.zipLatestAll(
valueRef.changes, valueRef.changes,
errorRef.changes, errorRef.changes,
isValidatingRef.changes, validationFiberRef.changes,
submitStateRef.changes, submitStateRef.changes,
), ),
filter, filter,
@@ -103,14 +103,38 @@ export const make: {
export const run = <A, I, R, SA, SE, SR>( export const run = <A, I, R, SA, SE, SR>(
self: Form<A, I, R, SA, SE, SR> self: Form<A, I, R, SA, SE, SR>
): Effect.Effect<void, never, R> => Stream.runForEach( ): Effect.Effect<void, never, Scope.Scope | R> => Stream.runForEach(
self.encodedValueRef.changes, self.encodedValueRef.changes,
encodedValue => SubscriptionRef.set(self.isValidatingRef, true).pipe( encodedValue => self.validationFiberRef.pipe(
Effect.andThen(Schema.decode(self.schema, { errors: "all" })(encodedValue)), Effect.andThen(Option.match({
Effect.andThen(v => SubscriptionRef.set(self.valueRef, Option.some(v))), onSome: Fiber.interrupt,
Effect.andThen(SubscriptionRef.set(self.errorRef, Option.none())), onNone: () => Effect.void,
Effect.catchTag("ParseError", e => SubscriptionRef.set(self.errorRef, Option.some(e))), })),
Effect.andThen(SubscriptionRef.set(self.isValidatingRef, false)), Effect.andThen(
Effect.addFinalizer(() => SubscriptionRef.set(self.validationFiberRef, Option.none())).pipe(
Effect.andThen(Schema.decode(self.schema, { errors: "all" })(encodedValue)),
Effect.exit,
Effect.andThen(flow(
Exit.matchEffect({
onSuccess: v => Effect.andThen(
SubscriptionRef.set(self.valueRef, Option.some(v)),
SubscriptionRef.set(self.errorRef, Option.none()),
),
onFailure: c => Option.match(
Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"),
{
onSome: e => SubscriptionRef.set(self.errorRef, Option.some(e)),
onNone: () => Effect.void,
},
),
}),
Effect.uninterruptible,
)),
Effect.scoped,
Effect.forkScoped,
)
),
Effect.andThen(fiber => SubscriptionRef.set(self.validationFiberRef, Option.some(fiber)))
), ),
) )
@@ -177,7 +201,13 @@ export const field = <A, I, R, SA, SE, SR, const P extends PropertyPath.Paths<No
}), }),
), ),
self.isValidatingRef, pipe(
Option.isSome,
filter => SubscribableInternal.make({
get: Effect.map(self.validationFiberRef.get, filter),
get changes() { return Stream.map(self.validationFiberRef.changes, filter) },
}),
),
pipe( pipe(
AsyncData.isLoading, AsyncData.isLoading,