refactor(core): make state transforms synchronous

This commit is contained in:
Dax Raad 2026-07-16 13:55:14 -04:00
commit 72af084dc1
2 changed files with 8 additions and 11 deletions

View file

@ -6,9 +6,9 @@ import { Clock, Context, Deferred, Effect, Scope, Semaphore } from "effect"
* A replayable transform applied to a draft during reload. * A replayable transform applied to a draft during reload.
* *
* Domain drafts expose readable and writable state while preserving concise * Domain drafts expose readable and writable state while preserving concise
* plugin/config code. Transforms may perform Effects before returning. * plugin/config code. Transforms synchronously rebuild derived state.
*/ */
type TransformCallback<DraftApi> = (draft: DraftApi) => Effect.Effect<void> | void type TransformCallback<DraftApi> = (draft: DraftApi) => void
export type MakeDraft<State, DraftApi> = (state: State) => DraftApi export type MakeDraft<State, DraftApi> = (state: State) => DraftApi
export interface Registration { export interface Registration {
@ -87,9 +87,8 @@ export function create<State, DraftApi>(options: Options<State, DraftApi>): Inte
}) })
const apply = (transform: TransformCallback<DraftApi>, draft: DraftApi) => const apply = (transform: TransformCallback<DraftApi>, draft: DraftApi) =>
Effect.suspend(() => { Effect.sync(() => {
const result = transform(draft) transform(draft)
return Effect.isEffect(result) ? Effect.asVoid(result).pipe(Effect.orDie) : Effect.void
}) })
const materialize = Effect.fnUntraced(function* () { const materialize = Effect.fnUntraced(function* () {

View file

@ -36,7 +36,7 @@ describe("State", () => {
}), }),
) )
it.effect("runs effectful transforms during every reload", () => it.effect("runs transforms during every reload", () =>
Effect.gen(function* () { Effect.gen(function* () {
let value = "first" let value = "first"
const state = State.create({ const state = State.create({
@ -44,11 +44,9 @@ describe("State", () => {
draft: (draft) => ({ add: (item: string) => draft.values.push(item) }), draft: (draft) => ({ add: (item: string) => draft.values.push(item) }),
}) })
yield* state.transform((editor) => yield* state.transform((editor) => {
Effect.sync(() => { editor.add(value)
editor.add(value) })
}),
)
expect(state.get().values).toEqual(["first"]) expect(state.get().values).toEqual(["first"])
value = "second" value = "second"