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 { 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 * as React from "react"
import { Hooks } from "./hooks/index.js"
@@ -19,7 +19,7 @@ extends Pipeable.Pipeable {
readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>,
readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
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 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 encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
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 canSubmitSubscribable: Subscribable.Subscribable<boolean>,
@@ -62,7 +62,7 @@ export const make: {
) {
const valueRef = yield* SubscriptionRef.make(Option.none<A>())
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>())
return new FormImpl(
@@ -72,25 +72,25 @@ export const make: {
valueRef,
yield* SubscriptionRef.make(options.initialEncodedValue),
errorRef,
isValidatingRef,
validationFiberRef,
submitStateRef,
pipe(
<A>([value, error, isValidating, submitState]: readonly [
<A>([value, error, validationFiber, submitState]: readonly [
Option.Option<A>,
Option.Option<ParseResult.ParseError>,
boolean,
Option.Option<Fiber.Fiber<void, never>>,
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({
get: Effect.map(Effect.all([valueRef, errorRef, isValidatingRef, submitStateRef]), filter),
get: Effect.map(Effect.all([valueRef, errorRef, validationFiberRef, submitStateRef]), filter),
get changes() {
return Stream.map(
Stream.zipLatestAll(
valueRef.changes,
errorRef.changes,
isValidatingRef.changes,
validationFiberRef.changes,
submitStateRef.changes,
),
filter,
@@ -103,14 +103,38 @@ export const make: {
export const run = <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,
encodedValue => SubscriptionRef.set(self.isValidatingRef, true).pipe(
encodedValue => self.validationFiberRef.pipe(
Effect.andThen(Option.match({
onSome: Fiber.interrupt,
onNone: () => Effect.void,
})),
Effect.andThen(
Effect.addFinalizer(() => SubscriptionRef.set(self.validationFiberRef, Option.none())).pipe(
Effect.andThen(Schema.decode(self.schema, { errors: "all" })(encodedValue)),
Effect.andThen(v => SubscriptionRef.set(self.valueRef, Option.some(v))),
Effect.andThen(SubscriptionRef.set(self.errorRef, Option.none())),
Effect.catchTag("ParseError", e => SubscriptionRef.set(self.errorRef, Option.some(e))),
Effect.andThen(SubscriptionRef.set(self.isValidatingRef, false)),
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(
AsyncData.isLoading,