diff --git a/.changeset/declared-state-path-tools.md b/.changeset/declared-state-path-tools.md new file mode 100644 index 0000000..429982a --- /dev/null +++ b/.changeset/declared-state-path-tools.md @@ -0,0 +1,6 @@ +--- +"@typeonce/effect-machine-devtools": patch +"@typeonce/oxlint-plugin-effect-machine": patch +--- + +Show transition declarations with declared state paths such as `{ target: "Checkout.Review" }` and `{ initialize: … }` in the devtools. `no-async-planning-callback` also checks `initialize` input mappers. diff --git a/.changeset/declared-state-paths.md b/.changeset/declared-state-paths.md new file mode 100644 index 0000000..0b7e891 --- /dev/null +++ b/.changeset/declared-state-paths.md @@ -0,0 +1,20 @@ +--- +"@typeonce/effect-machine": minor +--- + +Replace `Machine.targets(Root)` references with declared state paths. Transitions, initial edges, history, owner updates, and named branches now take dotted path strings, spelled the same way as snapshot paths. They are checked against the root passed to `make` and suggested by the editor. The root node is `"root"`, so a top-level state can no longer use that name. + +Restart the machine from fresh input with `initialize`, which replaces root targets. Machines without input use `initialize: true`, and branch declarations use `{ initialize: true }` with `select.branch({ input })`. + +```ts +Machine.make({ root: Root, input: Input, events: Events }).handle({ + initial: { target: "Idle" }, + on: { + Increment: { update: "root", data: ({ root }) => ({ ...root, count: root.count + 1 }) }, + Reset: { initialize: ({ event }) => ({ id: event.id }), reenter: true } + }, + states: { Idle: { on: { Resume: { history: "Checkout.recent" } } } } +}) +``` + +To migrate, remove `Machine.targets`. Replace `targets.root.A.B` with `"A.B"`, `update: targets.root` with `update: "root"`, and `{ target: targets.root, input }` with `{ initialize: input }`. Rename any top-level state named `root`. Declarations stored in variables before they reach `make` or `.handle` need `as const`. diff --git a/.changeset/typed-operation-boundary.md b/.changeset/typed-operation-boundary.md index dbb835e..bea0b73 100644 --- a/.changeset/typed-operation-boundary.md +++ b/.changeset/typed-operation-boundary.md @@ -4,4 +4,4 @@ Check the public `Machine` operations against their implementations at compile time. -`Machine.start`, `resume`, `plan`, `planInitial`, `can`, `enabled`, `isFinal`, `encodeSnapshot`, `decodeSnapshot`, `make`, `targets`, and the event protocol builders no longer rely on unchecked casts, so their documented signatures now stay in sync with runtime behavior. Planning failures are classified consistently across runtime strategies: non-stabilization and schema failures stay typed, startup throws become `StartupError`, and other handler throws remain defects. +`Machine.start`, `resume`, `plan`, `planInitial`, `can`, `enabled`, `isFinal`, `encodeSnapshot`, `decodeSnapshot`, `make`, and the event protocol builders no longer rely on unchecked casts, so their documented signatures now stay in sync with runtime behavior. Planning failures are classified consistently across runtime strategies: non-stabilization and schema failures stay typed, startup throws become `StartupError`, and other handler throws remain defects. diff --git a/README.md b/README.md index 296787d..b857be5 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,17 @@ import { Effect } from "effect" const Root = Machine.state({ states: { Locked: {}, Unlocked: {} } }) -const targets = Machine.targets(Root) const Events = Machine.events({ Coin: {}, Push: {} }) const Turnstile = Machine.make({ root: Root, events: Events }).handle({ initial: { - target: targets.root.Locked + target: "Locked" }, states: { - Locked: { on: { Coin: { target: targets.root.Unlocked } } }, - Unlocked: { on: { Push: { target: targets.root.Locked } } } + Locked: { on: { Coin: { target: "Unlocked" } } }, + Unlocked: { on: { Push: { target: "Locked" } } } } }) const program = Effect.gen(function*() { diff --git a/api-reference.config.json b/api-reference.config.json index 1d70cab..b4a5f6b 100644 --- a/api-reference.config.json +++ b/api-reference.config.json @@ -167,10 +167,6 @@ "title": "Transition declarations", "description": "Target selection, resolution, branching, and commands available to state and invocation transitions.", "roots": [ - { - "reflection": "Targets", - "label": "State references" - }, { "reflection": "Machine.Transition", "label": "Inline transitions" diff --git a/packages/devtools/src/internal/browser/example-machine.ts b/packages/devtools/src/internal/browser/example-machine.ts index b9dae35..e794146 100644 --- a/packages/devtools/src/internal/browser/example-machine.ts +++ b/packages/devtools/src/internal/browser/example-machine.ts @@ -95,11 +95,10 @@ export const snapshot = { const initialWorkflow = (): Machine.Machine.CompleteSnapshotContaining<{ readonly "": typeof States.node }, "application.workflow"> => snapshot -const targets1 = Machine.targets(States) export const machine = Machine.make({ branches: { transition1: { - destination: { target: targets1.root.application.workflow.running, update: targets1.root.application.workflow } + destination: { target: "application.workflow.running", update: "application.workflow" } } }, id: "inspection-example", @@ -107,7 +106,7 @@ export const machine = Machine.make({ events: Machine.eventsFromSchemas(Start, Finish, Disconnect, Refresh) }).handle({ initial: { - target: Machine.targets(States).root.application, + target: "application", decoded: true, data: new Application({ workspace: "effect-machine", revision: 7 }) }, @@ -126,7 +125,7 @@ export const machine = Machine.make({ states: { workflow: { initial: { - target: Machine.targets(States).root.application.workflow.idle, + target: "application.workflow.idle", decoded: true, data: new Idle({}) }, @@ -149,7 +148,7 @@ export const machine = Machine.make({ }) }, Refresh: { - update: targets1.root.application.workflow, + update: "application.workflow", decoded: true, data: () => (new Workflow({ document: "Machine.ts", unsavedChanges: 0 })) } @@ -157,7 +156,7 @@ export const machine = Machine.make({ }, running: { initial: { - target: Machine.targets(States).root.application.workflow.running.editing, + target: "application.workflow.running.editing", decoded: true, data: ({}) => new Editing({}) }, @@ -165,7 +164,7 @@ export const machine = Machine.make({ editing: { on: { Finish: { - target: targets1.root.application.workflow.running.complete, + target: "application.workflow.running.complete", decoded: true, data: () => (new Complete({})) } @@ -178,7 +177,7 @@ export const machine = Machine.make({ }, connection: { initial: { - target: Machine.targets(States).root.application.connection.online, + target: "application.connection.online", decoded: true, data: new Online({}) }, @@ -186,7 +185,7 @@ export const machine = Machine.make({ online: { on: { Disconnect: { - target: targets1.root.application.connection.offline, + target: "application.connection.offline", decoded: true, data: () => (new Offline({})) } diff --git a/packages/devtools/src/internal/browser/hierarchy-routing-example.ts b/packages/devtools/src/internal/browser/hierarchy-routing-example.ts index db8d342..4a35281 100644 --- a/packages/devtools/src/internal/browser/hierarchy-routing-example.ts +++ b/packages/devtools/src/internal/browser/hierarchy-routing-example.ts @@ -28,12 +28,11 @@ const ReviewEvents = Machine.eventsFromSchemas(Schema.TaggedUnion({ })) const saveReview: Effect.Effect = Effect.succeed("deterministic-chart") const publishReview = Effect.succeed("deterministic-chart") -const targets1 = Machine.targets(ReviewStates) export const hierarchyRoutingMachine = Machine.make({ branches: { transition1: { - save: { target: targets1.root.Workflow.Saving, title: "Save the review" }, - invalid: { target: targets1.root.Workflow.Review.Failed, title: "Show validation failure" } + save: { target: "Workflow.Saving", title: "Save the review" }, + invalid: { target: "Workflow.Review.Failed", title: "Show validation failure" } } }, effects: { source1: Effect.suspend(() => saveReview), source2: Effect.suspend(() => publishReview) }, @@ -42,18 +41,18 @@ export const hierarchyRoutingMachine = Machine.make({ events: ReviewEvents }).handle({ initial: { - target: Machine.targets(ReviewStates).root.Workflow + target: "Workflow" }, states: { Workflow: { initial: { - target: Machine.targets(ReviewStates).root.Workflow.Review, + target: "Workflow.Review", data: { title: "A deterministic chart" } }, states: { Review: { initial: { - target: Machine.targets(ReviewStates).root.Workflow.Review.Form + target: "Workflow.Review.Form" }, on: { Submit: { @@ -73,9 +72,9 @@ export const hierarchyRoutingMachine = Machine.make({ invoke: { src: "source1", id: "save-review", - onDone: { target: targets1.root.Workflow.Publishing }, + onDone: { target: "Workflow.Publishing" }, onFailure: { - target: targets1.root.Workflow.Review.Failed, + target: "Workflow.Review.Failed", data: () => ({ message: "The review could not be saved." }) } } @@ -84,7 +83,7 @@ export const hierarchyRoutingMachine = Machine.make({ invoke: { src: "source2", id: "publish-review", - onDone: { target: targets1.root.Workflow.Complete, data: ({ output }) => ({ slug: output }) } + onDone: { target: "Workflow.Complete", data: ({ output }) => ({ slug: output }) } } }, Complete: {} diff --git a/packages/devtools/src/internal/browser/invoke-outcomes-example.ts b/packages/devtools/src/internal/browser/invoke-outcomes-example.ts index 57e64fb..5e31cac 100644 --- a/packages/devtools/src/internal/browser/invoke-outcomes-example.ts +++ b/packages/devtools/src/internal/browser/invoke-outcomes-example.ts @@ -16,14 +16,13 @@ const ChildStates = Machine.state({ Done: { schema: ChildDone, type: "final", output: Schema.String } } }) -const targets1 = Machine.targets(ChildStates) export const invokeGalleryChildMachine = Machine.make({ id: "invoke-gallery-child", root: ChildStates, events: Machine.eventsFromSchemas(FinishChild) }).handle({ initial: { - target: Machine.targets(ChildStates).root.Working, + target: "Working", decoded: true, data: new ChildWorking({ task: "render-preview" }) }, @@ -31,7 +30,7 @@ export const invokeGalleryChildMachine = Machine.make({ Working: { on: { FinishChild: { - target: targets1.root.Done, + target: "Done", decoded: true, data: ({ state }) => (new ChildDone({ result: `${state.task}:complete` })) } @@ -122,11 +121,10 @@ const GalleryStates = Machine.state({ Failed } }) -const targets2 = Machine.targets(GalleryStates) export const invokeOutcomesMachine = Machine.make({ branches: { transition13: { - ready: { target: targets2.root.Completed, title: "Worker reports ready" }, + ready: { target: "Completed", title: "Worker reports ready" }, waiting: { none: true, title: "Worker is still starting" } } }, @@ -149,44 +147,44 @@ export const invokeOutcomesMachine = Machine.make({ internalEvents: GalleryInternalEvents }).handle({ initial: { - target: Machine.targets(GalleryStates).root.Gallery, + target: "Gallery", decoded: true, data: new Gallery({ selectedDemo: null }) }, states: { Gallery: { initial: { - target: Machine.targets(GalleryStates).root.Gallery.Choose, + target: "Gallery.Choose", decoded: true, data: ({}) => new Choose({}) }, on: { - Reset: { target: targets2.root.Gallery.Choose, decoded: true, data: () => (new Choose({})) } + Reset: { target: "Gallery.Choose", decoded: true, data: () => (new Choose({})) } }, states: { Choose: { on: { RunEffect: { - target: targets2.root.Gallery.LoadingDocument, + target: "Gallery.LoadingDocument", decoded: true, data: ({ event }) => (new LoadingDocument({ request: event.request })) }, RunStream: { - target: targets2.root.Gallery.StreamingUpdates, + target: "Gallery.StreamingUpdates", decoded: true, data: () => (new StreamingUpdates({ values: [] })) }, RunTimer: { - target: targets2.root.Gallery.WaitingForTimeout, + target: "Gallery.WaitingForTimeout", decoded: true, data: () => (new WaitingForTimeout({ delay: "2 seconds" })) }, RunProcess: { - target: targets2.root.Gallery.WatchingProcess, + target: "Gallery.WatchingProcess", decoded: true, data: () => (new WatchingProcess({ revision: 1 })) }, - RunChild: { target: targets2.root.Gallery.RunningChild, decoded: true, data: () => (new RunningChild({})) } + RunChild: { target: "Gallery.RunningChild", decoded: true, data: () => (new RunningChild({})) } } }, LoadingDocument: { @@ -195,12 +193,12 @@ export const invokeOutcomesMachine = Machine.make({ id: "load-document", input: (context) => context, onDone: { - target: targets2.root.Completed, + target: "Completed", decoded: true, data: ({ output }) => (new Completed({ source: "effect", result: output })) }, onFailure: { - target: targets2.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ source: "effect", message: error })) } @@ -217,19 +215,19 @@ export const invokeOutcomesMachine = Machine.make({ } }, onDone: { - target: targets2.root.Completed, + target: "Completed", decoded: true, data: ({ state }) => (new Completed({ source: "stream", result: state.values.join(", ") })) }, onFailure: { - target: targets2.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ source: "stream", message: error })) } }, on: { StreamValue: { - target: targets2.root.Gallery.StreamingUpdates, + target: "Gallery.StreamingUpdates", decoded: true, data: ({ event, state }) => (new StreamingUpdates({ values: [...state.values, event.value] })) } @@ -240,7 +238,7 @@ export const invokeOutcomesMachine = Machine.make({ src: "source3", id: "request-timeout", onDone: { - target: targets2.root.Completed, + target: "Completed", decoded: true, data: () => (new Completed({ source: "timer", result: "timeout elapsed" })) } @@ -252,7 +250,7 @@ export const invokeOutcomesMachine = Machine.make({ id: "status-worker", address: Machine.childAddress("status-worker"), onFailure: { - target: targets2.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ source: "process", message: String(error) })) }, @@ -269,7 +267,7 @@ export const invokeOutcomesMachine = Machine.make({ invoke: { src: "source5", onDone: { - target: targets2.root.Completed, + target: "Completed", decoded: true, data: ({ output }) => (new Completed({ source: "child machine", result: output })) } @@ -279,12 +277,12 @@ export const invokeOutcomesMachine = Machine.make({ }, Completed: { on: { - Reset: { target: targets2.root.Gallery, decoded: true, data: () => (new Gallery({ selectedDemo: null })) } + Reset: { target: "Gallery", decoded: true, data: () => (new Gallery({ selectedDemo: null })) } } }, Failed: { on: { - Reset: { target: targets2.root.Gallery, decoded: true, data: () => (new Gallery({ selectedDemo: null })) } + Reset: { target: "Gallery", decoded: true, data: () => (new Gallery({ selectedDemo: null })) } } } } diff --git a/packages/devtools/src/internal/browser/layout-resilience-example.ts b/packages/devtools/src/internal/browser/layout-resilience-example.ts index 98cc364..bbc8e87 100644 --- a/packages/devtools/src/internal/browser/layout-resilience-example.ts +++ b/packages/devtools/src/internal/browser/layout-resilience-example.ts @@ -47,16 +47,15 @@ const AuthEvents = Machine.eventsFromSchemas(Schema.TaggedUnion({ PasswordChanged: { value: Schema.String }, Submit: { route: Schema.Literals(["verification", "login", "invalid"]) } })) -const targets1 = Machine.targets(AuthStates) export const layoutResilienceMachine = Machine.make({ branches: { transition4: { requestVerification: { - target: targets1.root.Editing.RequestingVerification, + target: "Editing.RequestingVerification", title: "Request a verification code" }, - login: { target: targets1.root.Editing.SubmittingLogin, title: "Submit password login" }, - invalid: { target: targets1.root.Editing.Form.Failed, title: "Show validation failure" } + login: { target: "Editing.SubmittingLogin", title: "Submit password login" }, + invalid: { target: "Editing.Form.Failed", title: "Show validation failure" } } }, effects: { @@ -82,7 +81,7 @@ export const layoutResilienceMachine = Machine.make({ events: AuthEvents }).handle({ initial: { - target: Machine.targets(AuthStates).root.Editing, + target: "Editing", data: { mode: "login", email: "", @@ -93,24 +92,24 @@ export const layoutResilienceMachine = Machine.make({ states: { Editing: { initial: { - target: Machine.targets(AuthStates).root.Editing.Form + target: "Editing.Form" }, states: { Form: { initial: { - target: Machine.targets(AuthStates).root.Editing.Form.Ready + target: "Editing.Form.Ready" }, on: { EmailChanged: { - update: targets1.root.Editing, + update: "Editing", data: ({ ancestors: { "Editing": current }, event }) => ({ ...current, email: event.value }) }, LoginMethodChanged: { - update: targets1.root.Editing, + update: "Editing", data: ({ ancestors: { "Editing": current }, event }) => ({ ...current, loginMethod: event.value }) }, PasswordChanged: { - update: targets1.root.Editing, + update: "Editing", data: ({ ancestors: { "Editing": current }, event }) => ({ ...current, password: event.value }) }, Submit: { @@ -136,9 +135,9 @@ export const layoutResilienceMachine = Machine.make({ src: "source1", id: "submit-login", input: (context) => context, - onDone: { target: targets1.root.Navigating, data: ({ output }) => ({ href: output }) }, + onDone: { target: "Navigating", data: ({ output }) => ({ href: output }) }, onFailure: { - target: targets1.root.Editing.Form.Failed, + target: "Editing.Form.Failed", data: () => ({ message: "Email or password is incorrect." }) } } @@ -149,7 +148,7 @@ export const layoutResilienceMachine = Machine.make({ id: "request-verification", input: (context) => context, onDone: { - target: targets1.root.Verification, + target: "Verification", data: ({ containingState }) => ({ mode: containingState.mode, email: containingState.email, @@ -157,7 +156,7 @@ export const layoutResilienceMachine = Machine.make({ }) }, onFailure: { - target: targets1.root.Editing.Form.Failed, + target: "Editing.Form.Failed", data: () => ({ message: "The verification code could not be sent." }) } } @@ -166,7 +165,7 @@ export const layoutResilienceMachine = Machine.make({ }, Verification: { initial: { - target: Machine.targets(AuthStates).root.Verification.CodeEntry + target: "Verification.CodeEntry" }, states: { CodeEntry: {} diff --git a/packages/devtools/src/internal/browser/parallel-completion-example.ts b/packages/devtools/src/internal/browser/parallel-completion-example.ts index c797873..772b9db 100644 --- a/packages/devtools/src/internal/browser/parallel-completion-example.ts +++ b/packages/devtools/src/internal/browser/parallel-completion-example.ts @@ -104,7 +104,6 @@ const ParallelStates = Machine.state({ Cancelled: OrderCancelled } }) -const targets1 = Machine.targets(ParallelStates) export const parallelCompletionMachine = Machine.make({ timers: { source1: "5 seconds" }, id: "parallel-completion", @@ -122,7 +121,7 @@ export const parallelCompletionMachine = Machine.make({ internalEvents: ParallelInternalEvents }).handle({ initial: { - target: Machine.targets(ParallelStates).root.Cart, + target: "Cart", decoded: true, data: new Cart({ items: 2 }) }, @@ -130,7 +129,7 @@ export const parallelCompletionMachine = Machine.make({ Cart: { on: { Checkout: { - target: targets1.root.Order, + target: "Order", decoded: true, data: ({ event }) => (new Order({ orderId: event.orderId, total: event.total })) } @@ -140,36 +139,36 @@ export const parallelCompletionMachine = Machine.make({ initial: { payment: ({}) => ({ attempts: 0 }), fulfillment: ({}) => ({ warehouse: "north" }) }, on: { CancelOrder: { - target: targets1.root.Cancelled, + target: "Cancelled", decoded: true, data: ({ event }) => (new OrderCancelled({ reason: event.reason })) } }, onDone: { - target: targets1.root.Complete, + target: "Complete", decoded: true, data: () => (new OrderComplete({ orderId: "completed-order" })) }, states: { payment: { initial: { - target: Machine.targets(ParallelStates).root.Order.payment.AwaitingAuthorization + target: "Order.payment.AwaitingAuthorization" }, states: { AwaitingAuthorization: { on: { Authorize: { - target: targets1.root.Order.payment.Authorized, + target: "Order.payment.Authorized", decoded: true, data: ({ event }) => (new Authorized({ authorizationId: event.authorizationId })) }, CompleteAll: { - target: targets1.root.Order.payment.Authorized, + target: "Order.payment.Authorized", decoded: true, data: ({ event }) => (new Authorized({ authorizationId: event.authorizationId })) }, DeclinePayment: { - target: targets1.root.Cancelled, + target: "Cancelled", decoded: true, data: ({ event }) => (new OrderCancelled({ reason: event.reason })) } @@ -180,23 +179,23 @@ export const parallelCompletionMachine = Machine.make({ }, fulfillment: { initial: { - target: Machine.targets(ParallelStates).root.Order.fulfillment.WaitingForPayment + target: "Order.fulfillment.WaitingForPayment" }, states: { WaitingForPayment: { on: { Authorize: { - target: targets1.root.Order.fulfillment.Packing, + target: "Order.fulfillment.Packing", decoded: true, data: () => (new Packing({ packageCount: 1 })) }, Pack: { - target: targets1.root.Order.fulfillment.Packing, + target: "Order.fulfillment.Packing", decoded: true, data: ({ event }) => (new Packing({ packageCount: event.packages })) }, CompleteAll: { - target: targets1.root.Order.fulfillment.Shipped, + target: "Order.fulfillment.Shipped", decoded: true, data: ({ event }) => (new Shipped({ trackingCode: event.trackingCode })) } @@ -215,17 +214,17 @@ export const parallelCompletionMachine = Machine.make({ }, on: { AutoShip: { - target: targets1.root.Order.fulfillment.Shipped, + target: "Order.fulfillment.Shipped", decoded: true, data: () => (new Shipped({ trackingCode: "automatic" })) }, Ship: { - target: targets1.root.Order.fulfillment.Shipped, + target: "Order.fulfillment.Shipped", decoded: true, data: ({ event }) => (new Shipped({ trackingCode: event.trackingCode })) }, CompleteAll: { - target: targets1.root.Order.fulfillment.Shipped, + target: "Order.fulfillment.Shipped", decoded: true, data: ({ event }) => (new Shipped({ trackingCode: event.trackingCode })) } @@ -242,7 +241,7 @@ export const parallelCompletionMachine = Machine.make({ Cancelled: { on: { RetryOrder: { - target: targets1.root.Order, + target: "Order", decoded: true, data: () => (new Order({ orderId: "retry", total: 0 })) } diff --git a/packages/devtools/src/internal/browser/parallel-owner-routing-example.ts b/packages/devtools/src/internal/browser/parallel-owner-routing-example.ts index a08b49d..89513b3 100644 --- a/packages/devtools/src/internal/browser/parallel-owner-routing-example.ts +++ b/packages/devtools/src/internal/browser/parallel-owner-routing-example.ts @@ -51,7 +51,7 @@ export const parallelOwnerRoutingChildMachine = Machine.make({ parent: Machine.parent(ChildParentEvents) }).handle({ initial: { - target: Machine.targets(ParallelOwnerChildStates).root.Idle, + target: "Idle", decoded: true, data: new ChildIdle({}) }, @@ -91,7 +91,6 @@ const ParallelOwnerStates = Machine.state({ } } }) -const targets2 = Machine.targets(ParallelOwnerStates) export const parallelOwnerRoutingMachine = Machine.make({ children: { source1: ParallelOwnerChild }, id: "parallel-owner-routing", @@ -99,7 +98,7 @@ export const parallelOwnerRoutingMachine = Machine.make({ events: Machine.eventsFromSchemas(PrintRequested, ChildParentEvents) }).handle({ initial: { - target: Machine.targets(ParallelOwnerStates).root.Print, + target: "Print", decoded: true, data: new Print({}) }, @@ -108,11 +107,11 @@ export const parallelOwnerRoutingMachine = Machine.make({ initial: { Options: ({}) => ({}), Operation: ({}) => ({}) }, invoke: { src: "source1", - onFailure: { target: targets2.root.Print.Operation.Active, decoded: true, data: () => (new Active({})) } + onFailure: { target: "Print.Operation.Active", decoded: true, data: () => (new Active({})) } }, on: { PrintRequested: { - target: targets2.root.Print.Operation.Printing, + target: "Print.Operation.Printing", decoded: true, data: () => (new Printing({})) } @@ -120,7 +119,7 @@ export const parallelOwnerRoutingMachine = Machine.make({ states: { Options: { initial: { - target: Machine.targets(ParallelOwnerStates).root.Print.Options.Ready, + target: "Print.Options.Ready", data: ({}) => ({}) }, states: { @@ -129,7 +128,7 @@ export const parallelOwnerRoutingMachine = Machine.make({ }, Operation: { initial: { - target: Machine.targets(ParallelOwnerStates).root.Print.Operation.Active, + target: "Print.Operation.Active", data: ({}) => ({}) }, states: { diff --git a/packages/devtools/src/internal/browser/planner-example.ts b/packages/devtools/src/internal/browser/planner-example.ts index a029a76..1d9e5c4 100644 --- a/packages/devtools/src/internal/browser/planner-example.ts +++ b/packages/devtools/src/internal/browser/planner-example.ts @@ -109,12 +109,11 @@ const States = Machine.state({ Finished: { schema: Finished, type: "final", output: Schema.String } } }) -const targets1 = Machine.targets(States) export const plannerMachine = Machine.make({ branches: { transition1: { - urgent: { target: targets1.root.Working, title: "Finish immediately" }, - normal: { target: targets1.root.Working, title: "Wait in working" } + urgent: { target: "Working", title: "Finish immediately" }, + normal: { target: "Working", title: "Wait in working" } } }, effects: { source1: Effect.suspend(() => Effect.never) }, @@ -155,7 +154,7 @@ export const plannerMachine = Machine.make({ }) }).handle({ initial: { - target: Machine.targets(States).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ owner: input.owner }) }, @@ -183,12 +182,12 @@ export const plannerMachine = Machine.make({ invoke: { src: "source1", id: "monitor-job" }, on: { AutoFinish: { - target: targets1.root.Finished, + target: "Finished", decoded: true, data: ({ state }) => (new Finished({ job: state.job })) }, Cancel: { - target: targets1.root.Idle, + target: "Idle", decoded: true, data: ({ event, state }) => (new Idle({ owner: `${state.owner} · ${event.reason}` })) } diff --git a/packages/devtools/src/internal/browser/protocol-events-example.ts b/packages/devtools/src/internal/browser/protocol-events-example.ts index 9edef22..3a7f5b8 100644 --- a/packages/devtools/src/internal/browser/protocol-events-example.ts +++ b/packages/devtools/src/internal/browser/protocol-events-example.ts @@ -57,11 +57,10 @@ const ChildStates = Machine.state({ Cancelled: { schema: ChildCancelled, type: "final", output: Schema.String } } }) -const targets1 = Machine.targets(ChildStates) export const requiredParentChildMachine = Machine.make({ branches: { - transition1: { destination: { target: targets1.root.Working } }, - transition3: { destination: { target: targets1.root.Working } } + transition1: { destination: { target: "Working" } }, + transition3: { destination: { target: "Working" } } }, effects: { source1: ({ parent, state }: { @@ -77,7 +76,7 @@ export const requiredParentChildMachine = Machine.make({ parent: Machine.parent(ParentEvents) }).handle({ initial: { - target: Machine.targets(ChildStates).root.Idle, + target: "Idle", decoded: true, data: new ChildIdle({}) }, @@ -101,7 +100,7 @@ export const requiredParentChildMachine = Machine.make({ input: (context) => context, onDone: { none: true }, onFailure: { - target: targets1.root.Cancelled, + target: "Cancelled", decoded: true, data: ({ error }) => (new ChildCancelled({ reason: String(error) })) } @@ -115,12 +114,12 @@ export const requiredParentChildMachine = Machine.make({ } }, CommitChildWork: { - target: targets1.root.Done, + target: "Done", decoded: true, data: ({ state }) => (new ChildDone({ result: `${state.job}:complete` })) }, CancelChildWork: { - target: targets1.root.Cancelled, + target: "Cancelled", decoded: true, data: ({ event }) => (new ChildCancelled({ reason: event.reason })) } @@ -161,11 +160,10 @@ const ParentStates = Machine.state({ Failed: ParentFailed } }) -const targets2 = Machine.targets(ParentStates) export const parentProtocolMachine = Machine.make({ branches: { - transition1: { destination: { target: targets2.root.Supervising } }, - transition3: { destination: { target: targets2.root.Complete } } + transition1: { destination: { target: "Supervising" } }, + transition3: { destination: { target: "Complete" } } }, children: { source1: ProtocolChild }, id: "parent-child-protocol", @@ -173,7 +171,7 @@ export const parentProtocolMachine = Machine.make({ events: Machine.eventsFromSchemas(LaunchChild, ResetParent, ParentEvents) }).handle({ initial: { - target: Machine.targets(ParentStates).root.Idle, + target: "Idle", decoded: true, data: new ParentIdle({}) }, @@ -181,7 +179,7 @@ export const parentProtocolMachine = Machine.make({ Idle: { on: { LaunchChild: { - target: targets2.root.Supervising, + target: "Supervising", decoded: true, data: () => (new Supervising({ latestProgress: 0 })) } @@ -191,33 +189,33 @@ export const parentProtocolMachine = Machine.make({ invoke: { src: "source1", onDone: { - target: targets2.root.Complete, + target: "Complete", decoded: true, data: ({ output }) => (new ParentComplete({ result: output })) }, onFailure: { - target: targets2.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new ParentFailed({ message: String(error) })) } }, on: { ChildProgress: { - target: targets2.root.Supervising, + target: "Supervising", decoded: true, data: ({ event }) => (new Supervising({ latestProgress: event.percent })) }, ChildFinished: { - target: targets2.root.Complete, + target: "Complete", decoded: true, data: ({ event }) => (new ParentComplete({ result: event.result })) }, ChildProblem: { - target: targets2.root.Failed, + target: "Failed", decoded: true, data: ({ event }) => (new ParentFailed({ message: event.message })) }, - ResetParent: { target: targets2.root.Idle, decoded: true, data: () => (new ParentIdle({})) } + ResetParent: { target: "Idle", decoded: true, data: () => (new ParentIdle({})) } } }, Complete: { @@ -225,7 +223,7 @@ export const parentProtocolMachine = Machine.make({ }, Failed: { on: { - ResetParent: { target: targets2.root.Idle, decoded: true, data: () => (new ParentIdle({})) } + ResetParent: { target: "Idle", decoded: true, data: () => (new ParentIdle({})) } } } } @@ -241,16 +239,15 @@ class PublishOutside extends Schema.TaggedClass("OptionalParentP }) { } const OptionalParentStates = Machine.state({ states: { Detached, Published } }) -const targets3 = Machine.targets(OptionalParentStates) export const optionalParentMachine = Machine.make({ - branches: { transition1: { destination: { target: targets3.root.Published } } }, + branches: { transition1: { destination: { target: "Published" } } }, id: "optional-parent-protocol", root: OptionalParentStates, events: Machine.eventsFromSchemas(PublishOutside), parent: Machine.optionalParent(ParentEvents) }).handle({ initial: { - target: Machine.targets(OptionalParentStates).root.Detached, + target: "Detached", decoded: true, data: new Detached({}) }, diff --git a/packages/devtools/src/internal/browser/shared-terminal-routing-example.ts b/packages/devtools/src/internal/browser/shared-terminal-routing-example.ts index daab9e7..138cc06 100644 --- a/packages/devtools/src/internal/browser/shared-terminal-routing-example.ts +++ b/packages/devtools/src/internal/browser/shared-terminal-routing-example.ts @@ -23,7 +23,6 @@ const ReplicationEvents = Machine.eventsFromSchemas(Schema.TaggedUnion({ StopRequested: {} })) const operation: Effect.Effect = Effect.succeed(undefined) -const targets1 = Machine.targets(ReplicationStates) export const sharedTerminalRoutingMachine = Machine.make({ effects: { source1: operation, @@ -41,130 +40,130 @@ export const sharedTerminalRoutingMachine = Machine.make({ events: ReplicationEvents }).handle({ initial: { - target: Machine.targets(ReplicationStates).root.Connecting + target: "Connecting" }, states: { Connecting: { invoke: { src: "source1", id: "connect", - onDone: { target: targets1.root.IdentifyingSource }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "IdentifyingSource" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, IdentifyingSource: { invoke: { src: "source2", id: "identify-source", - onDone: { target: targets1.root.ReadingServerInfo }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "ReadingServerInfo" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, ReadingServerInfo: { invoke: { src: "source3", id: "read-server-info", - onDone: { target: targets1.root.ReadingSlot }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "ReadingSlot" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, ReadingSlot: { invoke: { src: "source4", id: "read-slot", - onDone: { target: targets1.root.CreatingSlot }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "CreatingSlot" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, CreatingSlot: { invoke: { src: "source5", id: "create-slot", - onDone: { target: targets1.root.CopyingSnapshot }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "CopyingSnapshot" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, CopyingSnapshot: { invoke: { src: "source6", id: "copy-snapshot", - onDone: { target: targets1.root.CatchingUp }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "CatchingUp" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, CatchingUp: { invoke: { src: "source7", id: "catch-up", - onDone: { target: targets1.root.ApplyingChanges }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "ApplyingChanges" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, ApplyingChanges: { invoke: { src: "source8", id: "apply-changes", - onDone: { target: targets1.root.Ready }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "Ready" }, + onFailure: { target: "Failed" } }, on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, Ready: { on: { - SessionUnavailable: { target: targets1.root.SessionUnavailable }, - StopRequested: { target: targets1.root.Stopping } + SessionUnavailable: { target: "SessionUnavailable" }, + StopRequested: { target: "Stopping" } } }, SessionUnavailable: { on: { - Retry: { target: targets1.root.Connecting }, - StopRequested: { target: targets1.root.Stopping } + Retry: { target: "Connecting" }, + StopRequested: { target: "Stopping" } } }, Stopping: { invoke: { src: "source9", id: "stop-session", - onDone: { target: targets1.root.Stopped }, - onFailure: { target: targets1.root.Failed } + onDone: { target: "Stopped" }, + onFailure: { target: "Failed" } } }, Stopped: {}, Failed: { on: { - Retry: { target: targets1.root.Connecting }, - StopRequested: { target: targets1.root.Stopping } + Retry: { target: "Connecting" }, + StopRequested: { target: "Stopping" } } } } diff --git a/packages/devtools/src/internal/browser/transition-semantics-example.ts b/packages/devtools/src/internal/browser/transition-semantics-example.ts index f08c94e..26fc4f8 100644 --- a/packages/devtools/src/internal/browser/transition-semantics-example.ts +++ b/packages/devtools/src/internal/browser/transition-semantics-example.ts @@ -128,19 +128,18 @@ const defaultWorkspaceSnapshot = () => ({ } } }) -const targets1 = Machine.targets(TransitionStates) export const transitionSemanticsMachine = Machine.make({ branches: { transition4: { - draft: { target: targets1.root.Workspace.Draft, title: "Preferred route is draft" }, - review: { target: targets1.root.Workspace.Review, title: "Preferred route is review" } + draft: { target: "Workspace.Draft", title: "Preferred route is draft" }, + review: { target: "Workspace.Review", title: "Preferred route is review" } }, transition7: { - review: { target: targets1.root.Workspace.Review, title: "Enter the review flow" }, - publish: { target: targets1.root.Workspace.Finished, title: "Publish without review" } + review: { target: "Workspace.Review", title: "Enter the review flow" }, + publish: { target: "Workspace.Finished", title: "Publish without review" } }, - transition14: { destination: { history: targets1.root.Workspace.recent } }, - transition15: { destination: { history: targets1.root.Workspace.exact } } + transition14: { destination: { history: "Workspace.recent" } }, + transition15: { destination: { history: "Workspace.exact" } } }, id: "transition-semantics", root: TransitionStates, @@ -164,14 +163,14 @@ export const transitionSemanticsMachine = Machine.make({ ) }).handle({ initial: { - target: Machine.targets(TransitionStates).root.Paused, + target: "Paused", decoded: true, data: new Paused({ reason: "not started" }) }, states: { Workspace: { initial: { - target: Machine.targets(TransitionStates).root.Workspace.Routing + target: "Workspace.Routing" }, history: { recent: { default: defaultWorkspaceSnapshot }, @@ -179,12 +178,12 @@ export const transitionSemanticsMachine = Machine.make({ }, on: { Pause: { - target: targets1.root.Paused, + target: "Paused", decoded: true, data: ({ event }) => (new Paused({ reason: event.reason })) }, BumpWorkspace: { - update: targets1.root.Workspace, + update: "Workspace", decoded: true, data: ({ state: current }) => (new Workspace({ revision: current.revision + 1, @@ -193,7 +192,7 @@ export const transitionSemanticsMachine = Machine.make({ } }, onDone: { - target: targets1.root.Published, + target: "Published", decoded: true, data: () => (new Published({ result: "workspace published" })) }, @@ -210,11 +209,11 @@ export const transitionSemanticsMachine = Machine.make({ Draft: { on: { Edit: { - target: targets1.root.Workspace.Draft, + target: "Workspace.Draft", decoded: true, data: ({ event, state }) => (new Draft({ text: event.text, autosaves: state.autosaves })) }, - Save: { target: targets1.root.Workspace.AutoSaving, decoded: true, data: () => (new AutoSaving({})) }, + Save: { target: "Workspace.AutoSaving", decoded: true, data: () => (new AutoSaving({})) }, Submit: { branches: "transition7", resolve: ({ event, select }) => @@ -233,19 +232,19 @@ export const transitionSemanticsMachine = Machine.make({ }, AutoSaving: { always: { - target: targets1.root.Workspace.Draft, + target: "Workspace.Draft", decoded: true, data: () => (new Draft({ text: "Autosaved draft", autosaves: 1 })) } }, Review: { initial: { - target: Machine.targets(TransitionStates).root.Workspace.Review.Checking, + target: "Workspace.Review.Checking", decoded: true, data: ({}) => new Checking({ checks: ["types", "tests"] }) }, onDone: { - target: targets1.root.Workspace.Finished, + target: "Workspace.Finished", decoded: true, data: () => (new WorkspaceFinished({ result: "approved review" })) }, @@ -253,12 +252,12 @@ export const transitionSemanticsMachine = Machine.make({ Checking: { on: { Approve: { - target: targets1.root.Workspace.Review.Approved, + target: "Workspace.Review.Approved", decoded: true, data: ({ event }) => (new Approved({ reviewer: event.reviewer })) }, Reject: { - target: targets1.root.Workspace.Review.ChangesRequested, + target: "Workspace.Review.ChangesRequested", decoded: true, data: ({ event }) => (new ChangesRequested({ reason: event.reason })) } @@ -267,7 +266,7 @@ export const transitionSemanticsMachine = Machine.make({ ChangesRequested: { on: { Revise: { - target: targets1.root.Workspace.Draft, + target: "Workspace.Draft", decoded: true, data: () => (new Draft({ text: "Revised draft", autosaves: 0 })) } @@ -282,14 +281,14 @@ export const transitionSemanticsMachine = Machine.make({ Paused: { on: { Create: { - target: targets1.root.Workspace, + target: "Workspace", decoded: true, data: ({ event }) => (new Workspace({ revision: 0, preferredRoute: event.route })) }, ResumeShallow: { branches: "transition14", resolve: ({ select: { destination: target } }) => target() }, ResumeDeep: { branches: "transition15", resolve: ({ select: { destination: target } }) => target() }, Restart: { - target: targets1.root.Workspace, + target: "Workspace", decoded: true, data: () => (new Workspace({ revision: 0, preferredRoute: "draft" })) } diff --git a/packages/devtools/src/internal/browser/visualizer-model.ts b/packages/devtools/src/internal/browser/visualizer-model.ts index daaff1f..3edec36 100644 --- a/packages/devtools/src/internal/browser/visualizer-model.ts +++ b/packages/devtools/src/internal/browser/visualizer-model.ts @@ -72,9 +72,7 @@ export const triggerLabel = (transition: VisualizationTransition): string => { } } -const propertyAccess = (key: string): string => /^[$A-Z_a-z][$\w]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]` - -const pathAccess = (path: string): string => path === "" ? "" : path.split(".").map(propertyAccess).join("") +const pathName = (path: string): string => JSON.stringify(path === "" ? "root" : path) /** Public declaration represented by a retained transition branch. */ export const branchTargetApi = (branch: VisualizationBranch): string | undefined => { @@ -84,9 +82,10 @@ export const branchTargetApi = (branch: VisualizationBranch): string | undefined if (path === null) return undefined if (selection.scope === "initial") return "initialConfiguration" const operation = selection.kind === "state" || selection.kind === "choice" ? "target" : selection.kind - const fields = [`${operation}: targets.root${pathAccess(path)}`] + if (operation === "target" && path === "") return "{ initialize: … }" + const fields = [`${operation}: ${pathName(path)}`] if (operation !== "update") { - for (const owner of branch.updates) fields.push(`update: targets.root${pathAccess(owner)}`) + for (const owner of branch.updates) fields.push(`update: ${pathName(owner)}`) } return `{ ${fields.join(", ")} }` } diff --git a/packages/devtools/test/internal/browser/ChartEndpoints.test.ts b/packages/devtools/test/internal/browser/ChartEndpoints.test.ts index 2536b7a..47debfa 100644 --- a/packages/devtools/test/internal/browser/ChartEndpoints.test.ts +++ b/packages/devtools/test/internal/browser/ChartEndpoints.test.ts @@ -21,7 +21,6 @@ const copyButtonModel = (): ChartModel => { Failed: { fields: { message: Schema.String } } } }) - const targets = Machine.targets(root) const machine = Machine.make({ id: "CopyButton", root, @@ -29,36 +28,36 @@ const copyButtonModel = (): ChartModel => { effects: { copy: (text: string) => text.length > 0 ? Effect.void : Effect.fail({ message: "failure" }) }, timers: { clicked: "120 millis", confirmation: "2 seconds", errorFeedback: "1 second" } }).handle({ - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { Copy: { - target: targets.root.Working, + target: "Working", guard: ({ event }) => event.text.length > 0, data: ({ event }) => ({ text: event.text }) } } }, Working: { - initial: { target: targets.root.Working.Clicked }, + initial: { target: "Working.Clicked" }, invoke: { src: "copy", input: ({ state }) => state.text, - onDone: { target: targets.root.Copied }, - onFailure: { target: targets.root.Failed, data: ({ error }) => ({ message: error.message }) } + onDone: { target: "Copied" }, + onFailure: { target: "Failed", data: ({ error }) => ({ message: error.message }) } }, states: { - Clicked: { invoke: { src: "clicked", onDone: { target: targets.root.Working.Copying } } }, + Clicked: { invoke: { src: "clicked", onDone: { target: "Working.Copying" } } }, Copying: {} } }, - Copied: { invoke: { src: "confirmation", onDone: { target: targets.root.Idle } } }, + Copied: { invoke: { src: "confirmation", onDone: { target: "Idle" } } }, Failed: { - invoke: { src: "errorFeedback", onDone: { target: targets.root.Idle } }, + invoke: { src: "errorFeedback", onDone: { target: "Idle" } }, on: { Copy: { - target: targets.root.Working, + target: "Working", guard: ({ event }) => event.text.length > 0, data: ({ event }) => ({ text: event.text }) } diff --git a/packages/devtools/test/internal/browser/InteractiveTextVisualization.test.ts b/packages/devtools/test/internal/browser/InteractiveTextVisualization.test.ts index e330950..ac2af16 100644 --- a/packages/devtools/test/internal/browser/InteractiveTextVisualization.test.ts +++ b/packages/devtools/test/internal/browser/InteractiveTextVisualization.test.ts @@ -128,16 +128,16 @@ describe("Interactive text visualization", () => { assert.deepStrictEqual( begin?.branches.map((branch) => branchTargetApi(branch)), - ["{ target: targets.root.Working }", "{ target: targets.root.Working }"] + ["{ target: \"Working\" }", "{ target: \"Working\" }"] ) assert.strictEqual( start === undefined ? undefined : branchTargetApi(start.branches[0]!), - "{ target: targets.root.application.workflow.running, update: targets.root.application.workflow }" + "{ target: \"application.workflow.running\", update: \"application.workflow\" }" ) assert.strictEqual( refresh === undefined ? undefined : branchTargetApi(refresh.branches[0]!), - "{ update: targets.root.application.workflow }" + "{ update: \"application.workflow\" }" ) assert.strictEqual( api("application.workflow.running.editing", { @@ -145,7 +145,7 @@ describe("Interactive text visualization", () => { kind: "state", scope: "branch" }), - "{ target: targets.root.application.workflow.running }" + "{ target: \"application.workflow.running\" }" ) assert.strictEqual( api("application.workflow.idle", { @@ -153,7 +153,7 @@ describe("Interactive text visualization", () => { kind: "initial", scope: "branch" }), - "{ initial: targets.root.application.workflow.running }" + "{ initial: \"application.workflow.running\" }" ) assert.strictEqual( api("application.workflow.idle", { @@ -161,7 +161,7 @@ describe("Interactive text visualization", () => { kind: "update", scope: "branch" }), - "{ update: targets.root.application.workflow }" + "{ update: \"application.workflow\" }" ) assert.strictEqual( api("application.workflow.idle", { @@ -169,7 +169,15 @@ describe("Interactive text visualization", () => { kind: "history", scope: "full" }), - "{ history: targets.root.application.workflow.recent }" + "{ history: \"application.workflow.recent\" }" + ) + assert.strictEqual( + api("application.workflow.idle", { path: "", kind: "state", scope: "branch" }), + "{ initialize: … }" + ) + assert.strictEqual( + api("application.workflow.idle", { path: "", kind: "update", scope: "branch" }), + "{ update: \"root\" }" ) assert.strictEqual( api("application.workflow.idle", { diff --git a/packages/effect-machine-react/test/MachineAtom.test.tsx b/packages/effect-machine-react/test/MachineAtom.test.tsx index c00e3be..c7d9cf6 100644 --- a/packages/effect-machine-react/test/MachineAtom.test.tsx +++ b/packages/effect-machine-react/test/MachineAtom.test.tsx @@ -15,14 +15,13 @@ class Active extends Schema.TaggedClass("Active")("Active", { class Increment extends Schema.TaggedClass("Increment")("Increment", {}) {} const States = Machine.state({ fields: { seed: Schema.Number }, states: { Active } }) const trackedMachine = (onStart: () => void) => { - const targets1 = Machine.targets(States) return Machine.make({ root: States, events: Machine.eventsFromSchemas(Increment), input: Schema.Number }).handle({ root: ({ input }) => ({ seed: input }), - initial: { target: targets1.root.Active, data: ({ root }) => ({ value: root.seed }) }, + initial: { target: "Active", data: ({ root }) => ({ value: root.seed }) }, entry: () => { onStart() return undefined @@ -31,7 +30,7 @@ const trackedMachine = (onStart: () => void) => { Active: { on: { Increment: { - target: targets1.root.Active, + target: "Active", decoded: true, data: ({ state }) => (new Active({ value: state.value + 1 })) } diff --git a/packages/effect-machine-react/test/RootContext.test.tsx b/packages/effect-machine-react/test/RootContext.test.tsx index 5f38f61..9126061 100644 --- a/packages/effect-machine-react/test/RootContext.test.tsx +++ b/packages/effect-machine-react/test/RootContext.test.tsx @@ -10,19 +10,18 @@ import { AtomMachine } from "../../effect-machine/src/unstable/reactivity/index. import { createMachineContext, MachineState } from "../src/index.js" const Events = Machine.events({ Increment: {}, Close: {} }) const root1 = Machine.state({ fields: { count: Schema.Number }, states: { Open: {}, Closed: {} } }) -const targets1 = Machine.targets(root1) const counter = Machine.make({ root: root1, events: Events, input: Schema.Number }).handle({ initial: { - target: Machine.targets(root1).root.Open + target: "Open" }, root: ({ input }) => ({ count: input }), - on: { Increment: { update: targets1.root, data: ({ root: current }) => ({ count: current.count + 1 }) } }, + on: { Increment: { update: "root", data: ({ root: current }) => ({ count: current.count + 1 }) } }, states: { - Open: { on: { Close: { target: targets1.root.Closed } } }, + Open: { on: { Close: { target: "Closed" } } }, Closed: {} } }) diff --git a/packages/effect-machine-react/typetest/MachineAtom.tst.ts b/packages/effect-machine-react/typetest/MachineAtom.tst.ts index 136b7c3..e309afa 100644 --- a/packages/effect-machine-react/typetest/MachineAtom.tst.ts +++ b/packages/effect-machine-react/typetest/MachineAtom.tst.ts @@ -12,7 +12,7 @@ const machine = Machine.make({ events: Machine.eventsFromSchemas(Continue) }).handle({ initial: { - target: Machine.targets(States).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -37,7 +37,7 @@ const withInput = Machine.make({ events: Machine.events({ Close: {} }) }).handle({ initial: { - target: Machine.targets(Root).root.Editing, + target: "Editing", data: ({}) => ({ draft: "" }) }, root: ({ input }) => ({ count: input }), diff --git a/packages/effect-machine/README.md b/packages/effect-machine/README.md index d4ea9e4..7214225 100644 --- a/packages/effect-machine/README.md +++ b/packages/effect-machine/README.md @@ -42,13 +42,12 @@ in lockstep with this package. ## Quick start -Declare the root once, derive its references, then add behavior with event maps: +Declare the root once, then add behavior with event maps: ```ts import { Machine } from "@typeonce/effect-machine" import { Effect, Schema } from "effect" const Root = Machine.state({ fields: { count: Schema.Number } }) -const targets = Machine.targets(Root) const Events = Machine.events({ Increment: { by: Schema.Number } }) const Counter = Machine.make({ root: Root, @@ -57,7 +56,7 @@ const Counter = Machine.make({ root: () => ({ count: 0 }), on: { Increment: { - update: targets.root, + update: "root", data: ({ root, event }) => ({ count: root.count + event.by }) } } @@ -68,7 +67,7 @@ const program = Effect.scoped(Effect.gen(function*() { })) ``` -Root data is shared state. `update: targets.root` replaces that value while +Root data is shared state. `update: "root"` replaces that value while retaining the active child configuration and its running work. Ordinary transitions target a descendant; the root itself is not a destination. @@ -97,10 +96,9 @@ const Root = Machine.state({ Ready: {} } }) -const targets = Machine.targets(Root) const machine = Machine.make({ root: Root, input: Schema.Number, events: Machine.events({}) }).handle({ root: ({ input }) => ({ seed: input }), - initial: { target: targets.root.Loading, data: ({ root }) => ({ count: root.seed }) } + initial: { target: "Loading", data: ({ root }) => ({ count: root.seed }) } }) ``` @@ -120,10 +118,9 @@ const Root = Machine.state({ Network: { fields: { online: Schema.Boolean } } } }) -const targets = Machine.targets(Root) const machine = Machine.make({ root: Root, events: Machine.events({}) }).handle({ initial: { Editor: { draft: "" }, Network: { online: false } }, - states: { Editor: { initial: { target: targets.root.Editor.Editing } } } + states: { Editor: { initial: { target: "Editor.Editing" } } } }) ``` @@ -148,25 +145,24 @@ const Root = Machine.state({ Failed: { fields: { message: Schema.String } } } }) -const targets = Machine.targets(Root) const Events = Machine.events({ Search: { query: Schema.String }, Reset: {} }) const Search = Machine.make({ root: Root, events: Events }).handle({ initial: { - target: targets.root.Idle + target: "Idle" }, states: { Idle: { on: { Search: { - target: targets.root.Loading, + target: "Loading", data: ({ event }) => ({ query: event.query }) } } }, - Loading: { on: { Reset: { target: targets.root.Idle } } }, + Loading: { on: { Reset: { target: "Idle" } } }, Ready: {}, Failed: {} } @@ -196,12 +192,12 @@ const machine = Machine.make({ events: Events, branches: { search: { - loading: { target: targets.root.Loading, title: "Query supplied" }, - idle: { target: targets.root.Idle, title: "Empty query" } + loading: { target: "Loading", title: "Query supplied" }, + idle: { target: "Idle", title: "Empty query" } } } }).handle({ - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { @@ -234,24 +230,31 @@ restart its lifecycle. ### Select destinations and retain owners -All references come from the same root descriptor supplied to `make`: - -| Declaration | Meaning | -| ----------------------------------------------------- | ------------------------------------------------------------------------- | -| `{ target: targets.root.Checkout.Review, data: ... }` | Enter a declared destination with its value. | -| `{ target: targets.root.Checkout, data: ... }` | Enter the declared initial configuration of a compound or parallel state. | -| `{ history: targets.root.Checkout.recent }` | Restore a declared history state. | -| `{ update: targets.root.Checkout, data: ... }` | Replace a retained active owner's value. | -| `{ target: targets.root, input: ... }` | Reconstruct root and its initial children using fresh machine input. | -| `{ update: targets.root, data: ... }` | Replace root data and retain active descendants. | -| `{ none: true }` | Accept an event without changing the configuration. | +Destinations are dotted paths through the root descriptor supplied to `make`, +spelled the same way as snapshot paths. The root node is `"root"`, so a +top-level state cannot use that name. Paths are checked at compile time and +suggested by the editor: + +| Declaration | Meaning | +| ------------------------------------------ | ------------------------------------------------------------------------- | +| `{ target: "Checkout.Review", data: ... }` | Enter a declared destination with its value. | +| `{ target: "Checkout", data: ... }` | Enter the declared initial configuration of a compound or parallel state. | +| `{ history: "Checkout.recent" }` | Restore a declared history state. | +| `{ update: "Checkout", data: ... }` | Replace a retained active owner's value. | +| `{ update: "root", data: ... }` | Replace root data and retain active descendants. | +| `{ initialize: ... }` | Reconstruct root and its initial children from fresh machine input. | +| `{ none: true }` | Accept an event without changing the configuration. | + +Declarations written inline are checked in place. A declaration stored in a +variable before it reaches `make` or `.handle` needs `as const` so its paths +remain literal. An atomic transition can enter a destination and update one retained owner: ```ts Save: { - target: targets.root.Checkout.Saving, - update: targets.root.Checkout, + target: "Checkout.Saving", + update: "Checkout", data: ({ event, ancestors }) => ({ target: { request: event.request }, update: { ...ancestors.Checkout, revision: event.revision } @@ -260,14 +263,18 @@ Save: { ``` The complete replacement values are validated before either change is applied. -Advanced construction declares both references in a branch and uses +Advanced construction declares both paths in a branch and uses `select.saved({ data: destinationValues, update: { data: ownerValues } })`. A retained owner must be active for that source and remain active through the transition. A sibling region's value cannot be updated through this operation. The runtime transition API does not replace arbitrary complete root -configurations. Root targets accept fresh input and follow the initial declarations in `.handle`; history -defaults retain complete subtree construction for restoration. +configurations. The root is not a destination. `initialize` restarts it: it +accepts fresh machine input, or `true` for a machine without input, and follows +the root constructor and initial declarations in `.handle`. Add `reenter: true` +to also exit and re-enter the root lifecycle. A branch declares +`{ initialize: true }` and its resolver supplies `select.branch({ input })`. +History defaults retain complete subtree construction for restoration. ### Protocols and ownership @@ -318,7 +325,7 @@ const Search = Machine.make({ children: { validation: ValidationChild } }).handle({ initial: { - target: Machine.targets(Root).root.Idle + target: "Idle" }, states: { Idle: {}, @@ -326,8 +333,8 @@ const Search = Machine.make({ invoke: { src: "load", input: ({ state }) => state.query, - onDone: { target: targets.root.Ready, data: ({ output }) => ({ items: output }) }, - onFailure: { target: targets.root.Failed, data: ({ error }) => ({ message: error.message }) } + onDone: { target: "Ready", data: ({ output }) => ({ items: output }) }, + onFailure: { target: "Failed", data: ({ error }) => ({ message: error.message }) } } }, Ready: {}, @@ -368,7 +375,7 @@ const invocations = [ onDone: { none: true }, onFailure: { none: true } }, - { src: "timeout", onDone: { target: targets.root.Expired } }, + { src: "timeout", onDone: { target: "Expired" } }, { src: "worker", id: "worker", address: WorkerAddress, onSnapshot: { none: true } }, { src: "validation", input: ({ state }) => ({ query: state.query }), onDone: { none: true } } ] diff --git a/packages/effect-machine/docs/agent-guide.md b/packages/effect-machine/docs/agent-guide.md index c15fa8e..44cc533 100644 --- a/packages/effect-machine/docs/agent-guide.md +++ b/packages/effect-machine/docs/agent-guide.md @@ -35,22 +35,20 @@ export const CounterEvents = Machine.eventsFromSchemas( }) ) -const targets = Machine.targets(CounterStates) - export const CounterMachine = Machine.make({ id: "Counter", root: CounterStates, events: CounterEvents, -}).handle({ initial: { target: targets.root.Idle }, states: { +}).handle({ initial: { target: "Idle" }, states: { Idle: { on: { - Start: { target: targets.root.Running, data: () => ({ count: 0 }) } + Start: { target: "Running", data: () => ({ count: 0 }) } } }, Running: { on: { - Increment: { update: targets.root.Running, data: ({ state }) => ({ count: state.count + 1 }) }, - Stop: { target: targets.root.Idle } + Increment: { update: "Running", data: ({ state }) => ({ count: state.count + 1 }) }, + Stop: { target: "Idle" } } } } }) @@ -72,7 +70,7 @@ Use `data` for schema make input. Constructor defaults and validation run while planning. Use `{ decoded: true, data }` for an existing schema Type; validation still applies. Named selectors take the same object format, with nested children under `states`. Structural states omit data. See [Root API](./root-api.md) for -startup input, root targets, subtree construction, and history fallbacks. +startup input, root initialization, subtree construction, and history fallbacks. The examples below show one modeling decision at a time. They omit unchanged state and event declarations already shown above. @@ -170,17 +168,16 @@ const DocumentEvents = Machine.eventsFromSchemas( }) ) -const documentTargets = Machine.targets(DocumentStates) const DocumentMachine = Machine.make({ root: DocumentStates, events: DocumentEvents -}).handle({ initial: { target: documentTargets.root.Closed }, states: { +}).handle({ initial: { target: "Closed" }, states: { Closed: {}, Open: { - initial: { target: documentTargets.root.Open.Editing }, + initial: { target: "Open.Editing" }, on: { // All Open children close the document in the same way. - Close: { target: documentTargets.root.Closed } + Close: { target: "Closed" } }, states: { Editing: {}, @@ -209,20 +206,19 @@ export const CheckoutEvents = Machine.eventsFromSchemas( }) ) -const checkoutTargets = Machine.targets(CheckoutStates) const CheckoutMachine = Machine.make({ root: CheckoutStates, events: CheckoutEvents }).handle({ states: { Editing: { on: { - Submit: { target: checkoutTargets.root.Submitting } + Submit: { target: "Submitting" } } }, Submitting: { on: { // Cancel has meaning while work is in progress. - Cancel: { target: checkoutTargets.root.Editing } + Cancel: { target: "Editing" } } }, Complete: {} @@ -262,12 +258,11 @@ const ScreenStates = Machine.state({ states: { } } } }) -const screenTargets = Machine.targets(ScreenStates) const ScreenMachine = Machine.make({ root: ScreenStates, events: Machine.events({}) }).handle({ - initial: { target: screenTargets.root.Screen }, + initial: { target: "Screen" }, states: { Screen: { states: { - connection: { initial: { target: screenTargets.root.Screen.connection.Online } }, - panel: { initial: { target: screenTargets.root.Screen.panel.Closed } } + connection: { initial: { target: "Screen.connection.Online" } }, + panel: { initial: { target: "Screen.panel.Closed" } } } } } }) @@ -300,19 +295,18 @@ const LoadStates = Machine.state({ states: { Failed: LoadState.cases.Failed } }) -const loadTargets = Machine.targets(LoadStates) const LoadMachine = Machine.make({ root: LoadStates, effects: { loadDocument }, events: Machine.eventsFromSchemas(), -}).handle({ initial: { target: loadTargets.root.Idle }, states: { +}).handle({ initial: { target: "Idle" }, states: { Idle: {}, Loading: { invoke: { src: "loadDocument", input: ({ state }) => state.documentId, - onDone: { target: loadTargets.root.Ready, data: ({ output }) => ({ content: output }) }, - onFailure: { target: loadTargets.root.Failed, data: ({ error }) => ({ message: String(error) }) } + onDone: { target: "Ready", data: ({ output }) => ({ content: output }) }, + onFailure: { target: "Failed", data: ({ error }) => ({ message: String(error) }) } } }, Ready: {}, @@ -338,10 +332,10 @@ Loading: { { src: "loadDocument", input: ({ state }) => state.documentId, - onDone: { target: loadTargets.root.Ready, data: ({ output }) => ({ content: output }) }, - onFailure: { target: loadTargets.root.Failed, data: ({ error }) => ({ message: String(error) }) } + onDone: { target: "Ready", data: ({ output }) => ({ content: output }) }, + onFailure: { target: "Failed", data: ({ error }) => ({ message: String(error) }) } }, - { src: "loadTimeout", onDone: { target: loadTargets.root.Idle } } + { src: "loadTimeout", onDone: { target: "Idle" } } ] } ``` @@ -381,17 +375,16 @@ const ReviewEvents = Machine.eventsFromSchemas( }) ) -const reviewTargets = Machine.targets(ReviewStates) const ReviewMachine = Machine.make({ root: ReviewStates, events: ReviewEvents, branches: { evaluate: { - accepted: { target: reviewTargets.root.Accepted }, - rejected: { target: reviewTargets.root.Rejected } + accepted: { target: "Accepted" }, + rejected: { target: "Rejected" } } } -}).handle({ initial: { target: reviewTargets.root.Pending }, states: { +}).handle({ initial: { target: "Pending" }, states: { Pending: { on: { Evaluate: { @@ -417,7 +410,7 @@ descendants and running work: ```ts Changed: { - update: targets.root.Document, + update: "Document", data: ({ ancestors }) => ({ ...ancestors.Document, revision: ancestors.Document.revision + 1 diff --git a/packages/effect-machine/docs/machine-review.md b/packages/effect-machine/docs/machine-review.md index 597519d..0669047 100644 --- a/packages/effect-machine/docs/machine-review.md +++ b/packages/effect-machine/docs/machine-review.md @@ -32,8 +32,8 @@ provider has no ownership purpose, inspect that code more closely. ## Keep ordinary transitions inline -Use `{ target: targets.root.Running }` for a state with default construction. -Use `{ target: targets.root.Running, from: ({ event }) => ({ count: event.count }) }` +Use `{ target: "Running" }` for a state with default construction. +Use `{ target: "Running", data: ({ event }) => ({ count: event.count }) }` when the destination needs data. The checker rejects missing required fields. Use `decoded` for values already decoded by their schema. @@ -155,19 +155,18 @@ and its lifetime: ```ts // In make: effects: { submitOrder } -// targets is Machine.targets(OrderStates). machine.handle({ states: { Editing: { on: { - Submit: { target: targets.root.Submitting, from: ({ event }) => ({ order: event.order }) } + Submit: { target: "Submitting", data: ({ event }) => ({ order: event.order }) } } }, Submitting: { invoke: { src: "submitOrder", input: ({ state }) => state.order, - onDone: { target: targets.root.Complete, from: ({ output }) => ({ order: output }) }, - onFailure: { target: targets.root.Failed, from: ({ error }) => ({ message: String(error) }) } + onDone: { target: "Complete", data: ({ output }) => ({ order: output }) }, + onFailure: { target: "Failed", data: ({ error }) => ({ message: String(error) }) } } } } }) diff --git a/packages/effect-machine/docs/root-api.md b/packages/effect-machine/docs/root-api.md index e03d6c2..f380545 100644 --- a/packages/effect-machine/docs/root-api.md +++ b/packages/effect-machine/docs/root-api.md @@ -17,7 +17,6 @@ const Root = Machine.state({ Ready: {} } }) -const targets = Machine.targets(Root) const Events = Machine.events({ Loaded: {}, Reload: { locale: Schema.String, documentId: Schema.String } @@ -29,18 +28,17 @@ const Document = Machine.make({ }).handle({ root: ({ input }) => ({ locale: input.locale }), initial: { - target: targets.root.Loading, + target: "Loading", data: ({ input }) => ({ documentId: input.documentId }) }, on: { Reload: { - target: targets.root, - input: ({ event }) => ({ locale: event.locale, documentId: event.documentId }), + initialize: ({ event }) => ({ locale: event.locale, documentId: event.documentId }), reenter: true } }, states: { - Loading: { on: { Loaded: { target: targets.root.Ready } } } + Loading: { on: { Loaded: { target: "Ready" } } } } }) ``` @@ -68,21 +66,26 @@ optional region data. Compound handlers declare one direct initial child with `initial: { target, data }`; each compound has its own initial declaration. There is no `initialConfiguration` or initializer in `make`. -## Root targets and updates +## Root initialization and updates -`{ target: targets.root, input: ... }` reconstructs root data and follows its -initial declarations using fresh input. Input is required exactly when it is -required by `Machine.start`. Machines without input omit it. Root targets reject -`data`, `decoded`, and explicit child construction. +The root is spelled `"root"` in declarations, so a top-level state cannot use +that name. It is not a transition destination. -Targeting root retains its lifecycle unless it is reentered. Put a machine-wide +`{ initialize: ... }` reconstructs root data and follows its initial +declarations using fresh machine input: a value or a callback of the transition +context. A machine without input declares `{ initialize: true }`. `initialize` +rejects `target`, `update`, `history`, `none`, `data`, and `decoded`. A named +branch declares `{ initialize: true }`, and its resolver passes the input with +`select.branch({ input })`. + +Initializing root retains its lifecycle unless it is reentered. Put a machine-wide reset handler at root and use `reenter: true` to exit and enter root as well as its descendants. Reentry restarts work owned by the exited states. Without reentry, retained root work continues; it does not automatically acquire new construction values. Ordinary transition conflict and lifecycle rules still apply. This does not create a new machine reference or discard history records. -`{ update: targets.root, data: ... }` instead replaces root's complete value, +`{ update: "root", data: ... }` instead replaces root's complete value, retaining its active children and running work. It takes no input and does not run initial constructors. Other source/ancestor updates follow the same rules. @@ -92,14 +95,14 @@ Ordinary transitions stay inline: ```ts Load: { - target: targets.root.Loading, + target: "Loading", data: ({ event }) => ({ documentId: event.documentId }) } ``` Targeting a compound or parallel state follows its initial declarations. Event transitions use `target`, never `initial`. `initial` names only handler startup -edges. `history` restores a declared history reference; `none: true` accepts an +edges. `history` restores a declared history state; `none: true` accepts an event without changing its target configuration. Declare branch topology in `make` when a resolver chooses an outcome, builds an @@ -108,7 +111,7 @@ explicit subtree, or enqueues commands: ```ts branches: { open: { - checkout: { target: targets.root.Checkout }, + checkout: { target: "Checkout" }, unchanged: { none: true } } } @@ -145,12 +148,12 @@ add static analysis of resolver bodies. ## Retained-owner updates -An inline combined transition keeps `target` and `update` references separate: +An inline combined transition keeps `target` and `update` paths separate: ```ts Save: { - target: targets.root.Checkout.Saving, - update: targets.root.Checkout, + target: "Checkout.Saving", + update: "Checkout", data: ({ event }) => ({ target: { requestId: event.requestId }, update: { cartId: event.cartId } @@ -203,7 +206,12 @@ entry/exit, and required outcome channels retain their existing contracts. - Root initial constructors can read `input`; remove root fields used only to forward that input to the initial child. -- Replace event `{ initial: reference, data }` with `{ target: reference, data }`. +- Remove `Machine.targets(Root)`. Replace `targets.root.A.B` with `"A.B"`, + `update: targets.root` with `update: "root"`, and + `{ target: targets.root, input }` with `{ initialize: input }` (or + `{ initialize: true }` without machine input). Rename a top-level state named + `root`. +- Replace event `{ initial: path, data }` with `{ target: path, data }`. - Replace `select.branch.from(value)` with `select.branch({ data: value })`. - Replace `.decoded(value)` with `({ decoded: true, data: value })`. - Replace child callbacks with `states: { Child: { data, states } }`. diff --git a/packages/effect-machine/perf/runtime/effect-machine-compatibility.mjs b/packages/effect-machine/perf/runtime/effect-machine-compatibility.mjs index 6b574d8..8604479 100644 --- a/packages/effect-machine/perf/runtime/effect-machine-compatibility.mjs +++ b/packages/effect-machine/perf/runtime/effect-machine-compatibility.mjs @@ -8,7 +8,32 @@ export const makeEffectMachineBenchmarkApi = (Machine) => { // The legacy process constructor takes `(initial, transition)`. The static // definition constructor is deliberately unary and returns its config. - const hasObjectTransitions = typeof Machine.targets === "function" + const hasReferenceTargets = typeof Machine.targets === "function" + const hasPathTargets = !hasReferenceTargets && typeof Machine.state === "function" && (() => { + try { + Machine.make({ root: Machine.state({ states: { Probe: {} } }), events: Machine.events({}) }) + .handle({ initial: { target: "Probe" } }) + return true + } catch { + return false + } + })() + const hasObjectTransitions = hasReferenceTargets || hasPathTargets + // Destinations are `Machine.targets` references or declared path strings. + const destination = Symbol("benchmark destination") + const targetTree = (root) => { + const build = (node, path, reference) => { + const tree = {} + Object.defineProperty(tree, destination, { value: reference ?? (path === "" ? "root" : path) }) + if (typeof node === "object" && node !== null && node.states !== undefined) { + for (const [key, child] of Object.entries(node.states)) { + tree[key] = build(child, path === "" ? key : `${path}.${key}`, reference?.[key]) + } + } + return tree + } + return build(root.node, "", hasReferenceTargets ? Machine.targets(root).root : undefined) + } const hasHandlerInitial = hasObjectTransitions && typeof Machine.state === "function" && (() => { try { Machine.state({ states: { Probe: {} } }) @@ -67,11 +92,11 @@ export const makeEffectMachineBenchmarkApi = (Machine) => { snapshot, effectLifecycle: hasHandlerInitial ? (work, output) => { const root = Machine.state({ states: { Working: {}, Complete: { type: "final", output } } }) - const targets = Machine.targets(root) + const targets = targetTree(root) return Machine.make({ root, events: Machine.events({}), effects: { work } }).handle({ - initial: { target: targets.root.Working }, + initial: { target: targets.Working[destination] }, states: { - Working: { invoke: { src: "work", onDone: { target: targets.root.Complete } } }, + Working: { invoke: { src: "work", onDone: { target: targets.Complete[destination] } } }, Complete: { output: () => undefined } } }) @@ -97,13 +122,13 @@ export const makeEffectMachineBenchmarkApi = (Machine) => { const machine = Machine.make({ ...rest, root, initialConfiguration }) return { handle: (states) => machine.handle({ states }) } } - const targets = Machine.targets(root) + const targets = targetTree(root) const referenceSelectors = (refs) => Object.fromEntries(Object.entries(refs).map(([key, ref]) => { - const selected = () => ref + const selected = () => ref[destination] Object.assign(selected, referenceSelectors(ref)) return [key, selected] })) - const selectorsForRoot = referenceSelectors(targets.root) + const selectorsForRoot = referenceSelectors(targets) const children = {} const transition = (value, siblings) => { const definition = value?.[transitionDefinition] @@ -131,7 +156,7 @@ export const makeEffectMachineBenchmarkApi = (Machine) => { return [key, result] })) return { handle: (states) => { - const handlers = walk(states, targets.root) + const handlers = walk(states, targets) if (hasHandlerInitial) { const declared = rootDefinitions.get(root) if (declared === undefined) throw new Error("Missing benchmark root declaration") @@ -144,12 +169,12 @@ export const makeEffectMachineBenchmarkApi = (Machine) => { const key = path === "" ? initialKey : node.initial if (key === undefined) throw new Error("Missing benchmark initial child") const childPath = path ? `${path}.${key}` : key - result.initial = { target: refs[key], ...(Object.hasOwn(definition.values ?? {}, childPath) ? { data: definition.values[childPath] } : {}) } + result.initial = { target: refs[key][destination], ...(Object.hasOwn(definition.values ?? {}, childPath) ? { data: definition.values[childPath] } : {}) } } result.states = Object.fromEntries(Object.entries(node.states).map(([key, child]) => [key, initialize(child, handler?.states?.[key] ?? {}, path ? `${path}.${key}` : key, refs[key])])) return result } - return Machine.make({ ...rest, root, children }).handle(initialize(declared, { states: handlers }, "", targets.root)) + return Machine.make({ ...rest, root, children }).handle(initialize(declared, { states: handlers }, "", targets)) } return Machine.make({ ...rest, root, initialConfiguration, children }).handle({ states: handlers }) } } diff --git a/packages/effect-machine/perf/types/adapter-readiness-control.ts b/packages/effect-machine/perf/types/adapter-readiness-control.ts index 475f30e..4a8e8be 100644 --- a/packages/effect-machine/perf/types/adapter-readiness-control.ts +++ b/packages/effect-machine/perf/types/adapter-readiness-control.ts @@ -26,20 +26,19 @@ export const snapshot = { value: undefined, state: { path: "Ready" as const, value: Ready.make({}) } } -const targets1 = Machine.targets(States) export const machine = Machine.make({ id: "perf-readiness", root: States, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.Ready, + target: "Ready", data: Ready.make({}) }, states: { Flow: { initial: { - target: Machine.targets(States).root.Flow.Idle + target: "Flow.Idle" }, history: { recent: { @@ -50,7 +49,7 @@ export const machine = Machine.make({ states: { Idle: {}, Route: { - choice: { target: targets1.root.Ready, data: () => (Ready.make({})) } + choice: { target: "Ready", data: () => (Ready.make({})) } } } }, diff --git a/packages/effect-machine/perf/types/composition.ts b/packages/effect-machine/perf/types/composition.ts index f77cf75..a49f8c1 100644 --- a/packages/effect-machine/perf/types/composition.ts +++ b/packages/effect-machine/perf/types/composition.ts @@ -10,21 +10,20 @@ class CompositionService extends Context.Service()(" } class CompositionFailure extends Data.TaggedError("CompositionFailure")<{}> { } -const targets = Machine.targets(States) const machine = Machine.make({ - branches: { enter: { app: { target: targets.root.App } } }, + branches: { enter: { app: { target: "App" } } }, root: States, events: Machine.eventsFromSchemas() }) const handled = machine.handle({ initial: { - target: Machine.targets(States).root.App, + target: "App", data: App.make({}) }, states: { App: { initial: { - target: Machine.targets(States).root.App.Workspace, + target: "App.Workspace", data: Workspace.make({}) }, states: { @@ -58,7 +57,7 @@ const handled = machine.handle({ states: { Editor: { initial: { - target: Machine.targets(States).root.App.Workspace.Editor.Editing, + target: "App.Workspace.Editor.Editing", data: Editing.make({}) }, states: { @@ -72,7 +71,7 @@ const handled = machine.handle({ }, Sync: { initial: { - target: Machine.targets(States).root.App.Workspace.Sync.Idle, + target: "App.Workspace.Sync.Idle", data: SyncIdle.make({}) }, states: { diff --git a/packages/effect-machine/perf/types/definition-variants.ts b/packages/effect-machine/perf/types/definition-variants.ts index c2521a5..f9d9aa4 100644 --- a/packages/effect-machine/perf/types/definition-variants.ts +++ b/packages/effect-machine/perf/types/definition-variants.ts @@ -5,12 +5,11 @@ type Equal = (() => Type extends Left ? 1 : 2) extends ( = Value type IsAny = 0 extends 1 & Value ? true : false -const targets = Machine.targets(States) const complete = machine.handle({ - initial: { target: targets.root.Flow }, + initial: { target: "Flow" }, states: { Flow: { - initial: { target: targets.root.Flow.Idle }, + initial: { target: "Flow.Idle" }, history: { recent: { default: ({ target }) => @@ -19,16 +18,16 @@ const complete = machine.handle({ }, states: { Route: { - choice: { target: targets.root.Flow.Idle } + choice: { target: "Flow.Idle" } }, Idle: { on: { - Start: { target: targets.root.Flow.Running } + Start: { target: "Flow.Running" } } }, Running: { on: { - Finish: { target: targets.root.Flow.Done, data: ({ event }) => ({ value: event.value }) } + Finish: { target: "Flow.Done", data: ({ event }) => ({ value: event.value }) } } }, Done: { @@ -39,14 +38,14 @@ const complete = machine.handle({ } }) const idleOnly = machine.handle({ - initial: { target: targets.root.Flow }, + initial: { target: "Flow" }, states: { Flow: { - initial: { target: targets.root.Flow.Idle }, + initial: { target: "Flow.Idle" }, states: { Idle: { on: { - Start: { target: targets.root.Flow.Running } + Start: { target: "Flow.Running" } } } } @@ -54,14 +53,14 @@ const idleOnly = machine.handle({ } }) const runningOnly = machine.handle({ - initial: { target: targets.root.Flow }, + initial: { target: "Flow" }, states: { Flow: { - initial: { target: targets.root.Flow.Idle }, + initial: { target: "Flow.Idle" }, states: { Running: { on: { - Finish: { target: targets.root.Flow.Done, data: ({ event }) => ({ value: event.value }) } + Finish: { target: "Flow.Done", data: ({ event }) => ({ value: event.value }) } } } } diff --git a/packages/effect-machine/perf/types/dynamic-invoke.ts b/packages/effect-machine/perf/types/dynamic-invoke.ts index f5ec9e7..e52c5bd 100644 --- a/packages/effect-machine/perf/types/dynamic-invoke.ts +++ b/packages/effect-machine/perf/types/dynamic-invoke.ts @@ -11,7 +11,7 @@ const machine = Machine.make({ }) const invoked = machine.handle({ initial: { - target: Machine.targets(States).root.Loading, + target: "Loading", data: Loading.make({ userId: "user-1" }) }, states: { diff --git a/packages/effect-machine/perf/types/exact-channels.ts b/packages/effect-machine/perf/types/exact-channels.ts index 6ef0c89..dfe96f1 100644 --- a/packages/effect-machine/perf/types/exact-channels.ts +++ b/packages/effect-machine/perf/types/exact-channels.ts @@ -6,9 +6,8 @@ type Equal = (() => Type extends Left ? 1 : 2) extends ( = Value type IsAny = 0 extends 1 & Value ? true : false -const targets = Machine.targets(States) const machine = Machine.make({ - branches: { finish: { done: { target: targets.root.Done } } }, + branches: { finish: { done: { target: "Done" } } }, root: States, events: Machine.eventsFromSchemas(Start), internalEvents: Machine.internalEventsFromSchemas(Loaded), @@ -17,7 +16,7 @@ const machine = Machine.make({ }) const complete = machine.handle({ root: ({ input }) => ({ input }), - initial: { target: targets.root.Idle, data: ({ root }) => ({ value: root.input.seed }) }, + initial: { target: "Idle", data: ({ root }) => ({ value: root.input.seed }) }, states: { Idle: { entry: () => {}, @@ -29,7 +28,7 @@ const complete = machine.handle({ return select.done({ data: Done.make({ value: event.value }) }) } }, - Loaded: { target: targets.root.Done, data: ({ event }) => ({ value: event.value }) } + Loaded: { target: "Done", data: ({ event }) => ({ value: event.value }) } } }, Done: { diff --git a/packages/effect-machine/perf/types/handle-depth-24.ts b/packages/effect-machine/perf/types/handle-depth-24.ts index 8672475..1f14f88 100644 --- a/packages/effect-machine/perf/types/handle-depth-24.ts +++ b/packages/effect-machine/perf/types/handle-depth-24.ts @@ -10,145 +10,119 @@ type Expect = Value class DeepService extends Context.Service()("perf/depth-24/DeepService") {} class DeepFailure extends Data.TaggedError("DeepFailure")<{}> {} -const targets = Machine.targets(States) const handled = machine.handle({ - initial: { target: targets.root.n0 }, + initial: { target: "n0" }, states: { n0: { - initial: { target: targets.root.n0.n1 }, + initial: { target: "n0.n1" }, states: { n1: { - initial: { target: targets.root.n0.n1.n2 }, + initial: { target: "n0.n1.n2" }, states: { n2: { - initial: { target: targets.root.n0.n1.n2.n3 }, + initial: { target: "n0.n1.n2.n3" }, states: { n3: { - initial: { target: targets.root.n0.n1.n2.n3.n4 }, + initial: { target: "n0.n1.n2.n3.n4" }, states: { n4: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5 }, + initial: { target: "n0.n1.n2.n3.n4.n5" }, states: { n5: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6" }, states: { n6: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6.n7" }, states: { n7: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6.n7.n8" }, states: { n8: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9" }, states: { n9: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10" }, states: { n10: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11" }, states: { n11: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11 - .n12 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12" }, states: { n12: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10 - .n11.n12.n13 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13" }, states: { n13: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9 - .n10.n11.n12.n13.n14 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14" }, states: { n14: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7 - .n8.n9.n10.n11.n12.n13.n14.n15 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15" }, states: { n15: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6 - .n7.n8.n9.n10.n11.n12.n13.n14.n15.n16 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16" }, states: { n16: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5 - .n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17" }, states: { n17: { initial: { - target: targets.root.n0.n1.n2.n3 - .n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14 - .n15.n16.n17.n18 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18" }, states: { n18: { initial: { - target: targets.root.n0.n1.n2 - .n3.n4.n5.n6.n7.n8.n9.n10.n11.n12 - .n13.n14.n15.n16.n17.n18.n19 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18.n19" }, states: { n19: { initial: { - target: targets.root.n0.n1 - .n2.n3.n4.n5.n6.n7.n8.n9.n10.n11 - .n12.n13.n14.n15.n16.n17.n18.n19 - .n20 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18.n19.n20" }, states: { n20: { initial: { - target: targets.root - .n0.n1.n2.n3.n4.n5.n6.n7.n8 - .n9.n10.n11.n12.n13.n14.n15 - .n16.n17.n18.n19.n20.n21 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18.n19.n20.n21" }, states: { n21: { initial: { target: - Machine.targets(States) - .root.n0.n1.n2.n3.n4.n5 - .n6.n7.n8.n9.n10.n11.n12 - .n13.n14.n15.n16.n17.n18 - .n19.n20.n21.n22 + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18.n19.n20.n21.n22" }, states: { n22: { initial: { - target: Machine.targets( - States - ).root.n0.n1.n2.n3.n4 - .n5.n6.n7.n8.n9.n10 - .n11.n12.n13.n14.n15 - .n16.n17.n18.n19.n20 - .n21.n22.n23 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18.n19.n20.n21.n22.n23" }, states: { n23: { initial: { target: - Machine.targets( - States - ).root.n0.n1.n2.n3 - .n4.n5.n6.n7.n8 - .n9.n10.n11.n12 - .n13.n14.n15.n16 - .n17.n18.n19.n20 - .n21.n22.n23.n24 + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16.n17.n18.n19.n20.n21.n22.n23.n24" }, states: { n24: { diff --git a/packages/effect-machine/perf/types/handle-depth-wide-16.ts b/packages/effect-machine/perf/types/handle-depth-wide-16.ts index f1d4065..da54cab 100644 --- a/packages/effect-machine/perf/types/handle-depth-wide-16.ts +++ b/packages/effect-machine/perf/types/handle-depth-wide-16.ts @@ -10,75 +10,71 @@ type Expect = Value class DeepService extends Context.Service()("perf/depth-wide-16/DeepService") {} class DeepFailure extends Data.TaggedError("DeepFailure")<{}> {} -const targets = Machine.targets(States) const handled = machine.handle({ - initial: { target: targets.root.n0 }, + initial: { target: "n0" }, states: { n0: { - initial: { target: targets.root.n0.n1 }, + initial: { target: "n0.n1" }, states: { n1: { - initial: { target: targets.root.n0.n1.n2 }, + initial: { target: "n0.n1.n2" }, states: { n2: { - initial: { target: targets.root.n0.n1.n2.n3 }, + initial: { target: "n0.n1.n2.n3" }, states: { n3: { - initial: { target: targets.root.n0.n1.n2.n3.n4 }, + initial: { target: "n0.n1.n2.n3.n4" }, states: { n4: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5 }, + initial: { target: "n0.n1.n2.n3.n4.n5" }, states: { n5: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6" }, states: { n6: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6.n7" }, states: { n7: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6.n7.n8" }, states: { n8: { - initial: { target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9 }, + initial: { target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9" }, states: { n9: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10" }, states: { n10: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11" }, states: { n11: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11 - .n12 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12" }, states: { n12: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10 - .n11.n12.n13 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13" }, states: { n13: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9 - .n10.n11.n12.n13.n14 + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14" }, states: { n14: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6.n7 - .n8.n9.n10.n11.n12.n13.n14.n15 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15" }, states: { n15: { initial: { - target: targets.root.n0.n1.n2.n3.n4.n5.n6 - .n7.n8.n9.n10.n11.n12.n13.n14.n15.n16 + target: + "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.n12.n13.n14.n15.n16" }, states: { n16: { diff --git a/packages/effect-machine/perf/types/handle.ts b/packages/effect-machine/perf/types/handle.ts index 850ae10..cb0d6a2 100644 --- a/packages/effect-machine/perf/types/handle.ts +++ b/packages/effect-machine/perf/types/handle.ts @@ -10,21 +10,20 @@ const Event = Schema.TaggedUnion({ Finish: { value: Schema.String } }) const States = Machine.state({ states: State.cases }) -const targets1 = Machine.targets(States) const machine = Machine.make({ root: States, events: Machine.eventsFromSchemas(Event) }).handle({ - initial: { target: targets1.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { - Start: { target: targets1.root.Running, data: () => (State.cases.Running.make({})) } + Start: { target: "Running", data: () => (State.cases.Running.make({})) } } }, Running: { on: { - Finish: { target: targets1.root.Done, data: ({ event }) => (State.cases.Done.make({ value: event.value })) } + Finish: { target: "Done", data: ({ event }) => (State.cases.Done.make({ value: event.value })) } } }, Done: {} diff --git a/packages/effect-machine/perf/types/named-branches.ts b/packages/effect-machine/perf/types/named-branches.ts index e1b9615..b34cf55 100644 --- a/packages/effect-machine/perf/types/named-branches.ts +++ b/packages/effect-machine/perf/types/named-branches.ts @@ -1,19 +1,18 @@ import { Machine } from "../../dist/index.js" import { Route, State, States } from "./named-branches-control.js" -const targets = Machine.targets(States) const machine = Machine.make({ branches: { route: { - length1: { target: targets.root.Text }, - length2: { target: targets.root.Count }, - length3: { target: targets.root.Text }, - length4: { target: targets.root.Count }, - length5: { target: targets.root.Text }, + length1: { target: "Text" }, + length2: { target: "Count" }, + length3: { target: "Text" }, + length4: { target: "Count" }, + length5: { target: "Text" }, length6: { none: true }, - length7: { target: targets.root.Count }, - length8: { target: targets.root.Text }, - length9: { target: targets.root.Count }, - length10: { target: targets.root.Idle }, + length7: { target: "Count" }, + length8: { target: "Text" }, + length9: { target: "Count" }, + length10: { target: "Idle" }, unchanged: { none: true } } }, @@ -21,7 +20,7 @@ const machine = Machine.make({ events: Machine.eventsFromSchemas(Route) }) const handled = machine.handle({ - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { diff --git a/packages/effect-machine/perf/types/transition-construction.ts b/packages/effect-machine/perf/types/transition-construction.ts index d9c11c6..115bd79 100644 --- a/packages/effect-machine/perf/types/transition-construction.ts +++ b/packages/effect-machine/perf/types/transition-construction.ts @@ -1,24 +1,23 @@ import { Schema } from "effect" import { Machine } from "../../dist/index.js" import { Root, Saved, States } from "./transition-construction-control.js" -const targets = Machine.targets(States) const machine = Machine.make({ - branches: { reset: { idle: { target: targets.root.Idle }, same: { none: true } } }, + branches: { reset: { idle: { target: "Idle" }, same: { none: true } } }, root: States, events: Machine.events({ Save: { text: Schema.String }, Retry: {}, Reset: {} }) }) const handled = machine.handle({ initial: { - target: Machine.targets(States).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), - on: { Reset: { update: targets.root, guard: ({ root }) => root.count > 0, data: () => ({ count: 0 }) } }, + on: { Reset: { update: "root", guard: ({ root }) => root.count > 0, data: () => ({ count: 0 }) } }, states: { Idle: { on: { Save: { - target: targets.root.Saved, - update: targets.root, + target: "Saved", + update: "root", guard: ({ event }) => event.text.length > 0, data: ({ root, event }) => ({ target: { text: event.text }, update: { count: root.count + 1 } }) } @@ -27,8 +26,8 @@ const handled = machine.handle({ Saved: { on: { Save: { - target: targets.root.Saved, - update: targets.root, + target: "Saved", + update: "root", reenter: true, decoded: true, data: ({ root, event }) => ({ @@ -36,7 +35,7 @@ const handled = machine.handle({ update: new Root({ count: root.count + 1 }) }) }, - Retry: { target: targets.root.Saved, reenter: true, data: ({ state }) => ({ text: state.text }) }, + Retry: { target: "Saved", reenter: true, data: ({ state }) => ({ text: state.text }) }, Reset: { branches: "reset", reenter: true, diff --git a/packages/effect-machine/src/Machine.ts b/packages/effect-machine/src/Machine.ts index 7ac24cb..97fdbc3 100644 --- a/packages/effect-machine/src/Machine.ts +++ b/packages/effect-machine/src/Machine.ts @@ -122,7 +122,6 @@ type IsAny = 0 extends (1 & A) ? true : false * import { Schema } from "effect" * const events = Machine.events({ Add: { by: Schema.Number } }) * const Root = Machine.state({ fields: { count: Schema.Number } }) - * const targets = Machine.targets(Root) * export const counter = Machine.make({ * root: Root, * events @@ -130,7 +129,7 @@ type IsAny = 0 extends (1 & A) ? true : false * root: () => ({ count: 0 }), * on: { * Add: { - * update: targets.root, + * update: "root", * guard: ({ event }) => event.by > 0, * data: ({ root, event }) => ({ count: root.count + event.by }) * } @@ -307,12 +306,11 @@ export interface Definition< * **Example** * * ```ts - * const targets = Machine.targets(States) * const counter = definition.handle({ states: { * Count: { * on: { * Increment: { - * update: targets.root.Count, + * update: "Count", * decoded: ({ event, state }) => new Count({ value: state.value + event.by }) * } * } @@ -5137,10 +5135,8 @@ export declare namespace Machine { * @category utility types * @since 0.4.0 */ - export type EventTransitionReturn = Transition extends - { readonly initial: TargetReference } ? InitialTarget

- : Transition extends { readonly resolve?: infer Resolve } ? - NonNullable extends (...args: any) => infer Ret ? Ret : never + export type EventTransitionReturn = Transition extends { readonly resolve?: infer Resolve } ? + NonNullable extends (...args: any) => infer Ret ? Ret : never : never /** * Extracts the return value from a state's event handlers. @@ -6385,15 +6381,13 @@ export declare namespace Machine { Sources[K] extends (...args: never[]) => unknown ? Parameters["length"] extends 1 ? unknown : never : unknown } - type ReferenceRoot = Extract - type ReferenceAt | HistoryIdentifier> = TargetReference< - ReferenceRoot, - P, - P extends HistoryIdentifier ? "history" : P extends ChoiceIdentifier ? "choice" : "state" + // Declarations spell descendants as dotted paths and the root node as "root". + type PathName

= P extends "" ? "root" : P + type PathOf = Name extends "root" ? "" : Name extends string ? Name : never + type ReferenceAt | HistoryIdentifier> = PathName

+ type ReferenceUnion | HistoryIdentifier> = PathName< + Paths > - type ReferenceUnion | HistoryIdentifier> = { - readonly [P in Paths]: ReferenceAt - }[Paths] type DestinationPath = Exclude, ""> type RootSchemas = { readonly "": Root } @@ -6406,7 +6400,7 @@ export declare namespace Machine { & ( | { /** Selects a declared descendant; its transition or bound branch constructor supplies required values. */ - readonly target: ReferenceUnion> | TargetReference + readonly target: ReferenceUnion> /** Replaces the complete value of a retained source or ancestor without replacing its active children. */ readonly update?: ReferenceUnion> /** Enters a compound or parallel subtree through its declared initialization. */ @@ -6415,6 +6409,22 @@ export declare namespace Machine { readonly history?: never /** Accepts the event without selecting a new destination. */ readonly none?: never + /** Reconstructs root and its initial children from fresh machine input. */ + readonly initialize?: never + } + | { + /** Reconstructs root and its initial children from fresh machine input supplied by the resolver. */ + readonly initialize: true + /** Selects a declared descendant; its transition or bound branch constructor supplies required values. */ + readonly target?: never + /** Replaces the complete value of a retained source or ancestor without replacing its active children. */ + readonly update?: never + /** Enters a compound or parallel subtree through its declared initialization. */ + readonly initial?: never + /** Restores the declared history reference, using its fallback on first entry. */ + readonly history?: never + /** Accepts the event without selecting a new destination. */ + readonly none?: never } | { /** Replaces the complete value of a retained source or ancestor without replacing its active children. */ @@ -6427,6 +6437,8 @@ export declare namespace Machine { readonly history?: never /** Accepts the event without selecting a new destination. */ readonly none?: never + /** Reconstructs root and its initial children from fresh machine input. */ + readonly initialize?: never } | { /** Restores the declared history reference, using its fallback on first entry. */ @@ -6439,6 +6451,8 @@ export declare namespace Machine { readonly initial?: never /** Accepts the event without selecting a new destination. */ readonly none?: never + /** Reconstructs root and its initial children from fresh machine input. */ + readonly initialize?: never } | { /** Accepts the event without selecting a new destination. */ @@ -6451,6 +6465,8 @@ export declare namespace Machine { readonly initial?: never /** Restores the declared history reference, using its fallback on first entry. */ readonly history?: never + /** Reconstructs root and its initial children from fresh machine input. */ + readonly initialize?: never } ) export type BranchDefinitions = Readonly< @@ -6473,7 +6489,7 @@ export declare namespace Machine { } type RegisteredInput = R extends { readonly "~input": infer I extends Schema.Top } ? I : typeof Schema.Void type Registered = Kind extends keyof R ? NonNullable : {} - type RefPath = R extends TargetReference ? P : never + type RefPath = PathOf type ConstructionData = [NodeSchema] extends [never] ? { readonly data?: never; readonly decoded?: never } : | ( @@ -6538,30 +6554,38 @@ export declare namespace Machine { > : never type SelectionOf, D, R = {}> = D extends { - readonly target: infer Ref - } ? - RefPath extends infer P extends StateNodeIdentifier ? - D extends { readonly update: infer Update } - ? RefPath extends - infer Owner extends Extract, ParentStateIdentifier

& ValuedStateIdentifier> - ? P extends StateIdentifier ? TargetSelection< - ConstructionCall< - ConstructionObject< - NodeByIdentifier, - Src extends `${P}.${infer Rest}` ? Rest : Src extends P ? "" : never - > & { - readonly update: ConstructionData> - }, - CombinedTarget, S, Owner> - >, - P, - "state", - "branch" - > : - never - : never - : TargetSelection, P, P extends ChoiceIdentifier ? "choice" : "state", "branch"> - : never + readonly initialize: true + } ? TargetSelection>, R>, "", "state", "branch"> + : D extends { + readonly target: infer Ref + } ? + RefPath extends infer P extends StateNodeIdentifier ? + D extends { readonly update: infer Update } + ? RefPath extends + infer Owner extends Extract, ParentStateIdentifier

& ValuedStateIdentifier> + ? P extends StateIdentifier ? TargetSelection< + ConstructionCall< + ConstructionObject< + NodeByIdentifier, + Src extends `${P}.${infer Rest}` ? Rest : Src extends P ? "" : never + > & { + readonly update: ConstructionData> + }, + CombinedTarget, S, Owner> + >, + P, + "state", + "branch" + > : + never + : never + : TargetSelection< + ObjectSelection, + P, + P extends ChoiceIdentifier ? "choice" : "state", + "branch" + > + : never : D extends { readonly history: infer Ref } ? RefPath extends infer P extends HistoryIdentifier ? TargetSelection<() => HistoryTarget, P, "history", "full"> : @@ -6609,22 +6633,20 @@ export declare namespace Machine { > = P extends ChoiceIdentifier ? { readonly from?: never; readonly decoded?: never } : P extends StateIdentifier ? InlineNodeConstruction> : never - type InlineRoot = - & { - readonly target: ReferenceAt>> - readonly update?: never - readonly branches?: never - readonly resolve?: never - readonly history?: never - readonly none?: never - } - & (RegisteredInput extends typeof Schema.Void ? { readonly input?: never } - : { - /** Fresh machine input used to reconstruct root and its initial children. */ readonly input: DataValue< - C, - RegisteredInput["Type"] - > - }) + type InlineRoot = { + /** + * Reconstructs root and its initial children from fresh machine input. + * Machines without an input schema use `true`. + */ + readonly initialize: RegisteredInput extends typeof Schema.Void ? true + : DataValue["Type"]> + readonly target?: never + readonly update?: never + readonly branches?: never + readonly resolve?: never + readonly history?: never + readonly none?: never + } type InlineDestination, C> = { readonly [P in DestinationPath]: & { @@ -6825,7 +6847,7 @@ export declare namespace Machine { | InlineDestination | InlineUpdate | InlineCombined - | InlineRoot + | InlineRoot | { /** Restores the declared history reference, using its fallback on first entry. */ readonly history: ReferenceUnion> @@ -7083,11 +7105,7 @@ export declare namespace Machine { { readonly states: infer Children extends StateSchemas } ? { readonly [K in ActiveStateKey | ChoiceStateKey]: & { - readonly target: TargetReference< - ReferenceRoot, - JoinPath, - Children[K] extends ChoiceStateNodeConfig ? "choice" : "state" - > + readonly target: JoinPath } & InitialData }[ActiveStateKey | ChoiceStateKey] @@ -7342,8 +7360,9 @@ export declare namespace Machine { }) : never) type ValidateObjectTransition = - & ("input" extends keyof T - ? T extends { readonly target: TargetReference } ? unknown : { readonly input: never } + & ("initialize" extends keyof T ? { + readonly [K in Exclude]: never + } : unknown) & { readonly [ @@ -7351,7 +7370,7 @@ export declare namespace Machine { keyof T, | "target" | "update" - | "input" + | "initialize" | "history" | "none" | "branches" @@ -7741,7 +7760,7 @@ export const isFinal: < /** * Defines root or nested state schemas while preserving the exact child topology. * - * Pass the root descriptor to {@link make} and {@link targets}. Nested states + * Pass the root descriptor to {@link make}. Nested states * can be declared inline or reused by mounting a descriptor in multiple places. * Initial edges and value constructors belong in the handler tree. * @@ -7776,67 +7795,6 @@ export const isFinal: < */ export const state: StateConstructor = internal.state as StateConstructor -/** - * An opaque reference to one node in a declared state tree. - * - * @category models - * @since 0.34.0 - */ -export interface TargetReference< - Root extends Machine.StateNodeConfig, - Path extends string, - Kind extends "state" | "choice" | "history" -> { - readonly [internal.TargetReferenceTypeId]: { - readonly root: { readonly node: Root } - readonly path: Path - readonly kind: Kind - } -} - -type TargetReferenceTree = - & TargetReference< - Root, - Path, - Node extends { readonly type: "history" } ? "history" - : Node extends { readonly type: "choice" } ? "choice" - : "state" - > - & (Node extends { - /** Child handlers nested according to the declared root topology. */ - readonly states: infer Children - } ? { - readonly [Key in Extract]: TargetReferenceTree< - Root, - Children[Key], - Machine.JoinPath - > - } : - {}) - -/** - * References for every path in a declared root tree. - * - * @category models - * @since 0.34.0 - */ -export interface Targets { - /** Root data owner and the starting point for descendant state references. */ - readonly root: TargetReferenceTree -} - -/** - * Derives immutable state references from a root descriptor. - * - * References follow the declared tree: `targets.root.Checkout.Review`. - * Creating references does not construct state values or start machine work. - * - * @category constructors - * @since 0.34.0 - */ -export const targets: (root: State) => Targets = - internal.targets - type UniqueSourceNames = [ | Extract | Extract @@ -7844,6 +7802,10 @@ type UniqueSourceNames = [ | Extract ] extends [never] ? unknown : { readonly "~effect/Machine/DuplicateSourceName": never } +type ReservedRootName = Root extends { readonly states: infer Children } + ? "root" extends keyof Children ? { readonly "~effect/Machine/ReservedRootStateName": never } : unknown + : unknown + type MakeConfig< Root extends Machine.StateNodeConfig, InputEvents extends ReadonlyArray, @@ -7877,7 +7839,9 @@ type MakeConfig< /** Stable definition identifier used by inspection and visualization. */ readonly id?: string /** State topology and value schemas, captured by a `Machine.state` descriptor. */ - readonly root: { readonly [StateTypeId]: typeof StateTypeId; readonly node: Root } + readonly root: + & { readonly [StateTypeId]: typeof StateTypeId; readonly node: Root } + & ReservedRootName> /** Public events accepted by independently running machine references. */ readonly events: & Machine.EventProtocol<"public", InputEvents> @@ -8034,13 +7998,12 @@ interface Make { * } * const States = Machine.state({ states: { Count } }) * const Events = Machine.eventsFromSchemas(Increment) - * const targets = Machine.targets(States) * const counter = Machine.make({ * root: States, * events: Events * }).handle({ * initial: { - * target: Machine.targets(States).root.Count, + * target: "Count", * decoded: true, * data: new Count({ value: 0 }) * }, @@ -8048,7 +8011,7 @@ interface Make { * Count: { * on: { * Increment: { - * update: targets.root.Count, + * update: "Count", * decoded: true, * data: ({ event, state }) => new Count({ value: state.value + event.by }) * } @@ -8286,7 +8249,7 @@ export const emittedEventsFromSchemas: { * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -8373,7 +8336,7 @@ export const encodeSnapshot: < * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -8445,7 +8408,10 @@ type ValidateTransitionBranchRecord = [keyof Branches] extends [never] readonly [K in keyof Branches]: & { readonly [ - Extra in Exclude + Extra in Exclude< + keyof Branches[K], + "target" | "update" | "initialize" | "initial" | "history" | "none" | "title" + > ]: never } & (Branches[K] extends { readonly title: "" } ? { readonly title: never } : unknown) @@ -8486,7 +8452,7 @@ type ValidateTransitionBranchRecord = [keyof Branches] extends [never] * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -8776,7 +8742,7 @@ export const enabled: < * events: Machine.eventsFromSchemas(), * internalEvents * }).handle({ - * initial: { target: Machine.targets(Root).root.Idle }, + * initial: { target: "Idle" }, * states: { Idle: { on: { Loaded: { none: true } } } } * }) * @@ -8898,18 +8864,17 @@ export const can: { * class Toggle extends Schema.TaggedClass("Toggle")("Toggle", {}) { * } * const States = Machine.state({ states: { Off, On } }) - * const targets = Machine.targets(States) * const machine = Machine.make({ * root: States, * events: Machine.eventsFromSchemas(Toggle) * }).handle({ * initial: { - * target: Machine.targets(States).root.Off + * target: "Off" * }, * states: { * Off: { * on: { - * Toggle: { target: targets.root.On } + * Toggle: { target: "On" } * } * }, * On: {} @@ -9349,7 +9314,7 @@ export const prepare: < * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -9465,7 +9430,7 @@ export const start: < * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} diff --git a/packages/effect-machine/src/internal/machine/declaration.ts b/packages/effect-machine/src/internal/machine/declaration.ts index 006f446..adbe445 100644 --- a/packages/effect-machine/src/internal/machine/declaration.ts +++ b/packages/effect-machine/src/internal/machine/declaration.ts @@ -1,9 +1,8 @@ /** Captures reusable sources and topology declarations before handler compilation. */ import * as Effect from "effect/Effect" -import { hasProperty } from "effect/Predicate" +import * as Schema from "effect/Schema" import * as Stream from "effect/Stream" import type { Machine } from "../../Machine.js" -import * as Reference from "./targetReference.js" import * as Topology from "./topology.js" type SourceKind = "effects" | "streams" | "timers" | "logic" | "children" @@ -11,9 +10,14 @@ interface Source { readonly kind: SourceKind readonly value: unknown } +type PathKind = "state" | "choice" | "history" export interface Declaration { readonly initialize?: (input: unknown) => unknown readonly root: Machine.Any["root"] + /** Whether the machine declares an input schema used by `initialize`. */ + readonly input: boolean + /** Declared state paths keyed by internal identifier; the root is `""`. */ + readonly paths: ReadonlyMap readonly sources: ReadonlyMap readonly branches: ReadonlyMap>>>> } @@ -21,10 +25,29 @@ const record = (value: unknown, message: string): Record => { if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(message) return value as Record } +/** The root node's public path name. Top-level states cannot use it. */ +export const rootPathName = "root" +const collectPaths = (root: Machine.Any["root"]): ReadonlyMap => { + const paths = new Map() + const visit = (node: Machine.StateNodeConfig | Machine.TaggedSchema, path: string): void => { + const type = !Schema.isSchema(node) && "type" in node ? node.type : undefined + paths.set(path, type === "history" || type === "choice" ? type : "state") + if (!Schema.isSchema(node) && "states" in node) { + for (const [key, child] of Object.entries(node.states)) visit(child, path === "" ? key : `${path}.${key}`) + } + } + visit(root.node, "") + if (paths.has(rootPathName)) { + throw new Error(`Machine top-level state name "${rootPathName}" is reserved for the root`) + } + return paths +} export const capture = ( root: Machine.Any["root"], config: Readonly> ): Declaration => { + const paths = collectPaths(root) + const input = config.input !== undefined const sources = new Map() for (const kind of ["effects", "streams", "timers", "logic", "children"] as const) { if (config[kind] === undefined) continue @@ -51,35 +74,44 @@ export const capture = ( const spec = { ...record(value, `Machine branch "${name}.${key}" must be a declaration`) } for (const field of Reflect.ownKeys(spec)) { if ( - typeof field !== "string" || !["target", "update", "history", "none", "title"].includes(field) + typeof field !== "string" || + !["target", "update", "history", "none", "initialize", "title"].includes(field) ) { throw new Error(`Machine branch "${name}.${key}" contains an unknown declaration field`) } } + if (spec.initialize !== undefined && spec.initialize !== true) { + throw new Error(`Machine branch "${name}.${key}" declares initialize: true; its resolver supplies input`) + } if (spec.title !== undefined && (typeof spec.title !== "string" || spec.title.length === 0)) { throw new Error("Machine branch title must be a non-empty string") } - selection({ root, sources, branches }, spec) + selection({ root, input, paths, sources, branches }, spec) return [key, Object.freeze(spec)] }))) ) } } - return { root, sources, branches } + return { root, input, paths, sources, branches } } -const reference = (value: unknown, root: Declaration["root"]): Reference.Reference[typeof Reference.TypeId] => { - if (!hasProperty(value, Reference.TypeId)) throw new Error("Machine target must be a declared state reference") - const ref = (value as Reference.Reference)[Reference.TypeId] - if (ref.root !== root) throw new Error("Machine target reference belongs to a different root descriptor") - return ref +const reference = ( + value: unknown, + declaration: Declaration +): { readonly path: string; readonly kind: PathKind } => { + const path = value === rootPathName ? "" : typeof value === "string" && value !== "" ? value : undefined + const kind = path === undefined ? undefined : declaration.paths.get(path) + if (path === undefined || kind === undefined) { + throw new Error(`Machine target ${String(value)} is not a declared state path`) + } + return { path, kind } } export const selection = ( declaration: Declaration, config: Readonly> ): Topology.TargetSelection => { - const keys = ["target", "history", "none"].filter((key) => config[key] !== undefined) + const keys = ["target", "history", "none", "initialize"].filter((key) => config[key] !== undefined) if (keys.length === 0 && config.update !== undefined) { - const owner = reference(config.update, declaration.root) + const owner = reference(config.update, declaration) if (owner.kind !== "state") throw new Error("Machine update requires an active state reference") return Topology.makeTargetSelection("update", owner.path, "branch") } @@ -91,11 +123,18 @@ export const selection = ( } return Topology.noneTargetSelection } - const ref = reference(config[key], declaration.root) + if (key === "initialize") { + if (config.update !== undefined) throw new Error("Machine initialize cannot update a retained owner") + return Topology.makeTargetSelection("state", "", "branch") + } + const ref = reference(config[key], declaration) + if (key === "target" && ref.path === "") { + throw new Error("Machine root is not a destination; use initialize to reconstruct it from machine input") + } if ((key === "history") !== (ref.kind === "history")) { throw new Error("Machine history references require a history transition") } - const update = config.update === undefined ? undefined : reference(config.update, declaration.root).path + const update = config.update === undefined ? undefined : reference(config.update, declaration).path if (update !== undefined && key !== "target") throw new Error("Machine owner updates require an ordinary destination") return Topology.makeTargetSelection( ref.kind, diff --git a/packages/effect-machine/src/internal/machine/initialDeclaration.ts b/packages/effect-machine/src/internal/machine/initialDeclaration.ts index a0a7426..b19c864 100644 --- a/packages/effect-machine/src/internal/machine/initialDeclaration.ts +++ b/packages/effect-machine/src/internal/machine/initialDeclaration.ts @@ -3,7 +3,6 @@ import { hasProperty } from "effect/Predicate" import * as Schema from "effect/Schema" import type { Machine } from "../../Machine.js" import { SnapshotBuilderStateTypeId } from "./symbols.js" -import * as Reference from "./targetReference.js" import * as Topology from "./topology.js" const initializers = new WeakSet() @@ -96,18 +95,17 @@ export const capture = ( if (Reflect.ownKeys(edge).some((key) => !["target", "data", "decoded"].includes(String(key)))) { throw new Error("Machine initial edge accepts only target, data, and decoded") } - if (!hasProperty(edge.target, Reference.TypeId)) throw new Error("Machine initial requires a target reference") - const ref = (edge.target as Reference.Reference)[Reference.TypeId] const prefix = path === "" ? "" : `${path}.` - const key = ref.path.slice(prefix.length) - if ( - ref.root !== root || !ref.path.startsWith(prefix) || key.includes(".") || !(key in node.states) || - ref.kind === "history" - ) { - throw new Error(`Machine initial target must be a direct child of "${path}"`) + const key = typeof edge.target === "string" && edge.target.startsWith(prefix) + ? edge.target.slice(prefix.length) + : undefined + const selected = key === undefined || !Object.hasOwn(node.states, key) ? undefined : node.states[key]! + const kind = selected === undefined || Schema.isSchema(selected) ? "state" : selected.type + if (key === undefined || selected === undefined || kind === "history") { + throw new Error(`Machine initial target must be a direct child of "${path === "" ? "root" : path}"`) } initialKey = key - if (ref.kind === "choice" && (hasProperty(edge, "data") || hasProperty(edge, "decoded"))) { + if (kind === "choice" && (hasProperty(edge, "data") || hasProperty(edge, "decoded"))) { throw new Error("Machine choice initial edges cannot construct data") } const construct = edgeConstruction(edge) diff --git a/packages/effect-machine/src/internal/machine/machine.ts b/packages/effect-machine/src/internal/machine/machine.ts index e3185c3..c984916 100644 --- a/packages/effect-machine/src/internal/machine/machine.ts +++ b/packages/effect-machine/src/internal/machine/machine.ts @@ -38,7 +38,6 @@ import * as internalRuntime from "./runtimeProtocol.js" import * as Serialization from "./serialization.js" import * as StateDefinition from "./stateDefinition.js" import { ChildMachineLogicTypeId } from "./symbols.js" -import * as TargetReference from "./targetReference.js" import * as Topology from "./topology.js" export { @@ -53,8 +52,6 @@ export { export { ChildMachineLogicTypeId, InitialEventTypeId, SnapshotBuilderStateTypeId } from "./symbols.js" /** Internal seam for the public target-reference factory and its opaque brand. */ -export const TargetReferenceTypeId: typeof TargetReference.TypeId = TargetReference.TypeId -export const targets: (root: Machine.Any["root"]) => any = TargetReference.make const TypeId = "~effect/Machine" const ParentTypeId = "~effect/Machine/Parent" @@ -310,7 +307,7 @@ const constructBranch = ( if (selection.kind === "update") return Construction.update(stateNodes, selection.path!, config) if (selection.path === "") { if (Reflect.ownKeys(config).some((key) => key !== "input")) { - throw new Error("Machine root targets accept input only") + throw new Error("Machine initialize branches accept input only") } if (declaration.initialize === undefined) throw new Error("Machine root initialization is unavailable") return declaration.initialize(config.input) @@ -379,7 +376,7 @@ const normalizeObjectTransition = ( const allowed = [ "target", "update", - "input", + "initialize", "history", "none", "branches", @@ -418,7 +415,7 @@ const normalizeObjectTransition = ( throw new Error("Machine branching transition requires a registered group and resolver") } if ( - ["target", "update", "input", "history", "none", "data", "decoded"].some((key) => config[key] !== undefined) + ["target", "update", "initialize", "history", "none", "data", "decoded"].some((key) => config[key] !== undefined) ) throw new Error("Machine branching transition cannot redeclare its destination") const entries = Object.fromEntries( Object.entries(group).map(([key, spec]) => [key, { @@ -445,14 +442,19 @@ const normalizeObjectTransition = ( if (resolve !== undefined && selection.kind !== "none") { throw new Error("Machine advanced construction requires a declared branch group") } - const input = config.input - const constructInput = typeof input === "function" ? input : () => input - if (selection.path !== "" && Object.hasOwn(config, "input")) { - throw new Error("Machine input belongs only to root targets") + const initialize = config.initialize + const initializes = initialize !== undefined + if (initializes && (hasData || config.decoded !== undefined)) { + throw new Error("Machine initialize accepts machine input instead of data") } - if (selection.path === "" && selection.kind !== "update" && (hasData || config.decoded !== undefined)) { - throw new Error("Machine root targets accept input instead of data") + if (initializes && !declaration.input && initialize !== true) { + throw new Error("Machine initialize requires true when the machine declares no input") } + const constructInput = !declaration.input + ? () => undefined + : typeof initialize === "function" + ? initialize + : () => initialize return { target: () => selection, reenter: config.reenter, @@ -460,7 +462,7 @@ const normalizeObjectTransition = ( resolve: (context: Record, enqueue: unknown) => { if (guarded && !guard(context)) return Topology.makeDeclined() if (resolve !== undefined) return resolve(context, enqueue) - if (selection.path === "" && selection.kind !== "update") { + if (initializes) { return constructBranch(selection, stateNodes, declaration, { input: constructInput(context) }) } const value = construct(context) @@ -726,7 +728,10 @@ const makeHandle = (self: Definition.Any, declaration: Declaration.Declaration): const handlers: Record = Object.create(null) flattenHandlers(handlers, compiled.stateNodes, compiled.states, "", { ...declaration, - initialize: (input) => compiled.initial(Protocol.decodeInputSync(compiled, compiled.input, input)) + initialize: (input) => + compiled.initial( + compiled.input === undefined ? undefined : Protocol.decodeInputSync(compiled, compiled.input, input) + ) }, { "": captured.handlers }) return makeWithHandlers(compiled, handlers) }) as Definition.Any["handle"] diff --git a/packages/effect-machine/src/internal/machine/targetReference.ts b/packages/effect-machine/src/internal/machine/targetReference.ts deleted file mode 100644 index 5a2bbcc..0000000 --- a/packages/effect-machine/src/internal/machine/targetReference.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as Schema from "effect/Schema" -import type { Machine } from "../../Machine.js" - -/** Reference metadata is separate from child names, including names such as `path`. */ -export const TypeId: unique symbol = Symbol.for("effect/Machine/TargetReference") - -export interface Reference { - readonly [TypeId]: { - readonly root: Machine.Any["root"] - readonly path: string - readonly kind: "state" | "choice" | "history" - } -} - -/** Captures an immutable reference tree without allocating or executing a machine. */ -export const make = (root: Machine.Any["root"]): { readonly root: Reference } => { - const nodes: Array<{ path: string; key: string; parent: string | undefined; type: string }> = [] - const visit = ( - node: Machine.StateNodeConfig | Machine.TaggedSchema, - path: string, - key: string, - parent: string | undefined - ): void => { - const type = !Schema.isSchema(node) && "type" in node ? node.type ?? "active" : "active" - nodes.push({ path, key, parent, type }) - if (!Schema.isSchema(node) && "states" in node) { - for (const [childKey, child] of Object.entries(node.states)) { - visit(child, path === "" ? childKey : `${path}.${childKey}`, childKey, path) - } - } - } - visit(root.node, "", "", undefined) - const references = new Map() - for (const node of nodes) { - const reference = Object.create(null) - Object.defineProperty(reference, TypeId, { - value: Object.freeze({ - root, - path: node.path, - kind: node.type === "history" || node.type === "choice" ? node.type : "state" - }) - }) - references.set(node.path, reference) - } - for (const node of nodes) { - if (node.parent !== undefined) { - Object.defineProperty(references.get(node.parent), node.key, { - value: references.get(node.path), - enumerable: true - }) - } - } - for (const reference of references.values()) Object.freeze(reference) - return Object.freeze({ root: references.get("")! }) -} diff --git a/packages/effect-machine/src/internal/testing/machine/finiteModel.ts b/packages/effect-machine/src/internal/testing/machine/finiteModel.ts index 06e865f..a48cc24 100644 --- a/packages/effect-machine/src/internal/testing/machine/finiteModel.ts +++ b/packages/effect-machine/src/internal/testing/machine/finiteModel.ts @@ -1311,7 +1311,6 @@ const selectableDefinitionTarget = ( } const selectDefinitionTarget = ( - references: Record, source: string, target: string, byPath: ReadonlyMap @@ -1322,9 +1321,7 @@ const selectDefinitionTarget = ( : selected.root !== byPath.get(source)!.root ? target.split(".")[0]! : selectableDefinitionTarget(source, target, byPath) - let reference = references - for (const part of selectedPath.split(".")) reference = reference[part] - return selected.node._tag === "History" ? { history: reference } : { target: reference } + return selected.node._tag === "History" ? { history: selectedPath } : { target: selectedPath } } const resolveDefinitionTarget = ( @@ -1348,7 +1345,6 @@ const makeHandlers = ( parent: string | undefined, byPath: ReadonlyMap, transitions: ReadonlyMap, - references: Record, branches: Record>> ): Record => { const handlers: Record = Object.create(null) @@ -1357,7 +1353,7 @@ const makeHandlers = ( if (node._tag === "History") continue if (node._tag === "Choice") { const group = `choice:${path}` - branches[group] = { destination: selectDefinitionTarget(references, path, node.selected, byPath) } + branches[group] = { destination: selectDefinitionTarget(path, node.selected, byPath) } handlers[node.key] = { choice: { branches: group, @@ -1379,7 +1375,7 @@ const makeHandlers = ( const group = `transition:${path}:${triggerKey(transition.trigger)}` if (transition.target !== undefined) { branches[group] = { - destination: selectDefinitionTarget(references, path, transition.target, byPath) + destination: selectDefinitionTarget(path, transition.target, byPath) } } const config = { @@ -1423,7 +1419,7 @@ const makeHandlers = ( ...(node._tag === "Compound" ? { initial: { - target: `${path}.${node.initial}`.split(".").reduce((ref, key) => ref[key], references), + target: `${path}.${node.initial}`, ...(byPath.get(`${path}.${node.initial}`)!.node._tag === "Choice" ? {} : { decoded: true, data: stateValue(byPath.get(`${path}.${node.initial}`)!) @@ -1437,7 +1433,7 @@ const makeHandlers = ( .map((child) => [child.key, { decoded: true, data: stateValue(byPath.get(`${path}.${child.key}`)!) }]) ) }), - states: makeHandlers(node.states, path, byPath, transitions, references, branches) + states: makeHandlers(node.states, path, byPath, transitions, branches) } : {}) } @@ -1468,7 +1464,7 @@ export const compileModel = (model: FiniteModel): Machine.Machine.Any => { transition ])) const branches: Record>> = Object.create(null) - const handlers = makeHandlers(model.roots, undefined, byPath, transitions, Machine.targets(defined).root, branches) + const handlers = makeHandlers(model.roots, undefined, byPath, transitions, branches) const machine = Machine.make({ root: defined, branches, @@ -1477,7 +1473,7 @@ export const compileModel = (model: FiniteModel): Machine.Machine.Any => { return machine.handle( { initial: { - target: (Machine.targets(defined).root as unknown as Record)[model.initial], + target: model.initial, decoded: true, data: stateValue(initial) }, diff --git a/packages/effect-machine/src/testing/MachineTest.ts b/packages/effect-machine/src/testing/MachineTest.ts index c45e099..1b7ab26 100644 --- a/packages/effect-machine/src/testing/MachineTest.ts +++ b/packages/effect-machine/src/testing/MachineTest.ts @@ -245,7 +245,7 @@ export interface Scenarios { * events: Machine.eventsFromSchemas(Reset) * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: { @@ -505,7 +505,7 @@ export { ProbeUnavailableError } from "../internal/testing/machine/probe.js" * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -1121,7 +1121,7 @@ export const Invariant: { * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Count, + * target: "Count", * decoded: true, * data: new Count({ value: 0 }) * }, @@ -1461,7 +1461,7 @@ export type ExploreOptions = IsAny< * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -1925,7 +1925,7 @@ export interface Coverage { * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -2153,7 +2153,7 @@ export interface VerifyOptions { * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} diff --git a/packages/effect-machine/src/unstable/cluster/ClusterMachine.ts b/packages/effect-machine/src/unstable/cluster/ClusterMachine.ts index 57ce171..867598c 100644 --- a/packages/effect-machine/src/unstable/cluster/ClusterMachine.ts +++ b/packages/effect-machine/src/unstable/cluster/ClusterMachine.ts @@ -352,7 +352,7 @@ export const layerMemory: Layer.Layer = internal.layerMemory * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} diff --git a/packages/effect-machine/src/unstable/reactivity/AtomMachine.ts b/packages/effect-machine/src/unstable/reactivity/AtomMachine.ts index 84ed010..6829774 100644 --- a/packages/effect-machine/src/unstable/reactivity/AtomMachine.ts +++ b/packages/effect-machine/src/unstable/reactivity/AtomMachine.ts @@ -397,7 +397,7 @@ type EnsureValuedSelectorPath = [Path] extends [Valu * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Count, + * target: "Count", * decoded: true, * data: new Count({ value: 0 }) * }, @@ -642,7 +642,7 @@ export const selectSnapshotChild: { * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} @@ -1125,7 +1125,7 @@ export const familyChild: < * events: Machine.eventsFromSchemas() * }).handle({ * initial: { - * target: Machine.targets(States).root.Idle + * target: "Idle" * }, * states: { * Idle: {} diff --git a/packages/effect-machine/test/examples/can.ts b/packages/effect-machine/test/examples/can.ts index 53a25df..ea2df66 100644 --- a/packages/effect-machine/test/examples/can.ts +++ b/packages/effect-machine/test/examples/can.ts @@ -8,7 +8,7 @@ const machine = Machine.make({ events: Machine.eventsFromSchemas(), internalEvents }).handle({ - initial: { target: Machine.targets(Root).root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { Loaded: { none: true } } } } }) diff --git a/packages/effect-machine/test/examples/guard.ts b/packages/effect-machine/test/examples/guard.ts index 7abd8cb..7328821 100644 --- a/packages/effect-machine/test/examples/guard.ts +++ b/packages/effect-machine/test/examples/guard.ts @@ -2,7 +2,6 @@ import { Machine } from "@typeonce/effect-machine" import { Schema } from "effect" const events = Machine.events({ Add: { by: Schema.Number } }) const Root = Machine.state({ fields: { count: Schema.Number } }) -const targets = Machine.targets(Root) export const counter = Machine.make({ root: Root, events @@ -10,7 +9,7 @@ export const counter = Machine.make({ root: () => ({ count: 0 }), on: { Add: { - update: targets.root, + update: "root", guard: ({ event }) => event.by > 0, data: ({ root, event }) => ({ count: root.count + event.by }) } diff --git a/packages/effect-machine/test/fixtures/observability.ts b/packages/effect-machine/test/fixtures/observability.ts index 124a4ed..3a86968 100644 --- a/packages/effect-machine/test/fixtures/observability.ts +++ b/packages/effect-machine/test/fixtures/observability.ts @@ -3,7 +3,6 @@ import { Machine } from "../../src/index.js" export const Events = Machine.events({ Start: {}, Reenter: {}, Finish: {} }) const Root = Machine.state({ states: { Idle: {}, Active: {}, Complete: { type: "final", output: Schema.Void } } }) -const targets = Machine.targets(Root) export const observedMachine = (work: Effect.Effect, stream: Stream.Stream = Stream.never) => Machine.make({ id: "Observed", @@ -13,18 +12,18 @@ export const observedMachine = (work: Effect.Effect, stream: Str streams: { updates: stream }, timers: { timeout: "1 hour" } }).handle({ - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { - Idle: { on: { Start: { target: targets.root.Active } } }, + Idle: { on: { Start: { target: "Active" } } }, Active: { invoke: [ - { src: "work", id: "custom-work", onDone: { none: true }, onFailure: { target: targets.root.Complete } }, + { src: "work", id: "custom-work", onDone: { none: true }, onFailure: { target: "Complete" } }, { src: "updates", onElement: { none: true }, onDone: { none: true } }, { src: "timeout", onDone: { none: true } } ], on: { - Reenter: { target: targets.root.Active, reenter: true }, - Finish: { target: targets.root.Complete } + Reenter: { target: "Active", reenter: true }, + Finish: { target: "Complete" } } }, Complete: { output: () => undefined } diff --git a/packages/effect-machine/test/internal/machine/ProtocolValidation.test.ts b/packages/effect-machine/test/internal/machine/ProtocolValidation.test.ts index 53565fe..e859429 100644 --- a/packages/effect-machine/test/internal/machine/ProtocolValidation.test.ts +++ b/packages/effect-machine/test/internal/machine/ProtocolValidation.test.ts @@ -16,7 +16,7 @@ describe("event validation across execution strategies", () => { events }).handle({ initial: { - target: Machine.targets(root1).root.Ready, + target: "Ready", decoded: true, data: { _tag: "Ready" } }, diff --git a/packages/effect-machine/test/internal/machine/activities.test.ts b/packages/effect-machine/test/internal/machine/activities.test.ts index 0d5916c..bf2c90d 100644 --- a/packages/effect-machine/test/internal/machine/activities.test.ts +++ b/packages/effect-machine/test/internal/machine/activities.test.ts @@ -18,7 +18,7 @@ const childMachine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(childStates).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({}) }, @@ -50,7 +50,7 @@ const activityMachine = Machine.make({ events: Machine.eventsFromSchemas(WorkSucceeded, WorkFailed, LoadTimedOut) }).handle({ initial: { - target: Machine.targets(activityStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({}) }, @@ -177,7 +177,7 @@ describe("machine activity metadata", () => { events: Machine.eventsFromSchemas(LoadTimedOut) }).handle({ initial: { - target: Machine.targets(activityStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({}) }, diff --git a/packages/effect-machine/test/internal/machine/planningFailures.test.ts b/packages/effect-machine/test/internal/machine/planningFailures.test.ts index 6bd7124..69a833b 100644 --- a/packages/effect-machine/test/internal/machine/planningFailures.test.ts +++ b/packages/effect-machine/test/internal/machine/planningFailures.test.ts @@ -16,13 +16,12 @@ const defect = new Error("handler defect") // paths are exercised alongside the generic reference. const makeDefectMachine = (options: { readonly failInitial: boolean }) => { const root = Machine.state({ states: { Idle, Busy } }) - const targets = Machine.targets(root) return Machine.make({ root, events: Machine.eventsFromSchemas(Go) }).handle({ initial: { - target: targets.root.Idle, + target: "Idle", decoded: true, data: () => { if (options.failInitial) throw defect @@ -33,7 +32,7 @@ const makeDefectMachine = (options: { readonly failInitial: boolean }) => { Idle: { on: { Go: { - target: targets.root.Busy, + target: "Busy", decoded: true, data: () => { throw defect @@ -50,10 +49,9 @@ const makeDefectMachine = (options: { readonly failInitial: boolean }) => { // stabilizes once either is entered. const makeLoopMachine = (options: { readonly loopInitial: boolean }) => { const root = Machine.state({ states: { Waiting, Idle, Busy } }) - const targets = Machine.targets(root) const loop = { - Idle: { always: { target: targets.root.Busy, decoded: true, data: () => new Busy() } }, - Busy: { always: { target: targets.root.Idle, decoded: true, data: () => new Idle() } } + Idle: { always: { target: "Busy", decoded: true, data: () => new Busy() } }, + Busy: { always: { target: "Idle", decoded: true, data: () => new Idle() } } } as const const machine = Machine.make({ root, @@ -61,13 +59,13 @@ const makeLoopMachine = (options: { readonly loopInitial: boolean }) => { }) return options.loopInitial ? machine.handle({ - initial: { target: targets.root.Idle, decoded: true, data: new Idle() }, + initial: { target: "Idle", decoded: true, data: new Idle() }, states: { Waiting: {}, ...loop } }) : machine.handle({ - initial: { target: targets.root.Waiting, decoded: true, data: new Waiting() }, + initial: { target: "Waiting", decoded: true, data: new Waiting() }, states: { - Waiting: { on: { Loop: { target: targets.root.Idle, decoded: true, data: () => new Idle() } } }, + Waiting: { on: { Loop: { target: "Idle", decoded: true, data: () => new Idle() } } }, ...loop } }) diff --git a/packages/effect-machine/test/internal/machine/protocol.test.ts b/packages/effect-machine/test/internal/machine/protocol.test.ts index aadebb4..632135a 100644 --- a/packages/effect-machine/test/internal/machine/protocol.test.ts +++ b/packages/effect-machine/test/internal/machine/protocol.test.ts @@ -29,7 +29,7 @@ describe("machine protocols", () => { internalEvents: Machine.internalEventsFromSchemas(InternalEvent) }).handle({ initial: { - target: Machine.targets(states).root.ProtocolIdle, + target: "ProtocolIdle", decoded: true, data: new ProtocolIdle({}) }, diff --git a/packages/effect-machine/test/internal/machine/rootStrategies.test.ts b/packages/effect-machine/test/internal/machine/rootStrategies.test.ts index 8b7de76..6ab2d2e 100644 --- a/packages/effect-machine/test/internal/machine/rootStrategies.test.ts +++ b/packages/effect-machine/test/internal/machine/rootStrategies.test.ts @@ -34,7 +34,6 @@ it.effect("matches generic startup with constructed and defaulted parallel regio it.effect("retains independent callback contexts across root, inline, and named transitions", () => Effect.gen(function*() { const root = Machine.state({ fields: { count: Schema.Number }, states: { Idle: {} } }) - const targets = Machine.targets(root) const retained: Array<{ readonly root: { readonly count: number @@ -47,12 +46,12 @@ it.effect("retains independent callback contexts across root, inline, and named branches: { observe: { stay: { none: true } } } }).handle({ initial: { - target: Machine.targets(root).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), on: { IncrementRoot: { - update: targets.root, + update: "root", data: (context) => { retained.push(context) return { count: context.root.count + 1 } @@ -63,7 +62,7 @@ it.effect("retains independent callback contexts across root, inline, and named Idle: { on: { Increment: { - update: targets.root, + update: "root", data: (context) => { retained.push(context) return { count: context.root.count + 1 } @@ -107,7 +106,7 @@ it.effect("constructs schema defaults throughout a parallel root", () => { const machine = Machine.make({ root: InitialRoot1, events: Machine.events({ Noop: {} }) - }).handle({ states: { Left: { initial: { target: Machine.targets(InitialRoot1).root.Left.Idle } } } }) + }).handle({ states: { Left: { initial: { target: "Left.Idle" } } } }) return verifyPlannerStrategies({ machine, expected: "indexed-hierarchical", @@ -117,16 +116,15 @@ it.effect("constructs schema defaults throughout a parallel root", () => { }) it.effect("compares structural leaves, reentry, raised events and completion with generic planning", () => { const root1 = Machine.state({ states: { Idle: {}, Busy: {}, Done: { type: "final" } } }) - const targets1 = Machine.targets(root1) const machine = Machine.make({ root: root1, events: Machine.events({ Begin: {}, Reenter: {}, Finish: {}, Complete: {} }) }).handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, states: { - Idle: { on: { Begin: { target: targets1.root.Busy } } }, + Idle: { on: { Begin: { target: "Busy" } } }, Busy: { on: { Reenter: { none: true, reenter: true }, @@ -136,7 +134,7 @@ it.effect("compares structural leaves, reentry, raised events and completion wit enqueue.raise({ _tag: "Complete" }) } }, - Complete: { target: targets1.root.Done } + Complete: { target: "Done" } } }, Done: {} @@ -155,14 +153,13 @@ it.effect("compares structural leaves, reentry, raised events and completion wit }) it.effect("keeps flat root updates and retained snapshots equal to generic planning", () => { const root = Machine.state({ fields: { count: Schema.Number } }) - const targets2 = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Increment: { by: Schema.Number }, Noop: {}, Reenter: {} }) }).handle({ root: () => ({ count: 0 }), on: { - Increment: { update: targets2.root, data: ({ root: current, event }) => ({ count: current.count + event.by }) }, + Increment: { update: "root", data: ({ root: current, event }) => ({ count: current.count + event.by }) }, Noop: { none: true }, Reenter: { none: true, reenter: true } } @@ -181,21 +178,20 @@ it.effect("keeps flat root updates and retained snapshots equal to generic plann }) it.effect("keeps root values and child transitions equal to generic planning", () => { const root = Machine.state({ fields: { count: Schema.Number }, states: { Idle: {}, Busy: {} } }) - const targets3 = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Increment: { by: Schema.Number }, Start: {}, Stop: {} }) }).handle({ initial: { - target: Machine.targets(root).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), on: { - Increment: { update: targets3.root, data: ({ root: current, event }) => ({ count: current.count + event.by }) } + Increment: { update: "root", data: ({ root: current, event }) => ({ count: current.count + event.by }) } }, states: { - Idle: { on: { Start: { target: targets3.root.Busy } } }, - Busy: { on: { Stop: { target: targets3.root.Idle } } } + Idle: { on: { Start: { target: "Busy" } } }, + Busy: { on: { Stop: { target: "Idle" } } } } }) return verifyPlannerStrategies({ @@ -222,10 +218,8 @@ it.effect("reuses only immutable startup builders and keeps input values indepen events: Machine.events({ Noop: {} }) }).handle({ root: ({ input }) => ({ count: input.count }), - initial: { target: Machine.targets(InitialRoot2).root.Idle, data: ({ root }) => ({ count: root.count }) } + initial: { target: "Idle", data: ({ root }) => ({ count: root.count }) } }) - const targets = Machine.targets(InitialRoot2) - assert.strictEqual(Reflect.set(targets.root, "Idle", targets.root.Busy), false) const first = yield* Machine.planInitial(machine, { count: 1 }) const second = yield* Machine.planInitial(machine, { count: 2 }) assert.deepStrictEqual(first.state, { @@ -249,6 +243,38 @@ it.effect("reuses only immutable startup builders and keeps input values indepen } })) +it.effect("compares input-less root initialization across planners", () => { + const root = Machine.state({ + fields: { count: Schema.Number }, + states: { Idle: {}, Busy: { fields: { step: Schema.Number } } } + }) + const machine = Machine.make({ + root, + events: Machine.events({ Work: {}, Count: {}, Reset: {}, Restart: {} }) + }).handle({ + root: { count: 0 }, + initial: { target: "Idle" }, + on: { + Count: { update: "root", data: ({ root }) => ({ count: root.count + 1 }) }, + Reset: { initialize: true }, + Restart: { initialize: true, reenter: true } + }, + states: { Idle: { on: { Work: { target: "Busy", data: ({ root }) => ({ step: root.count }) } } } } + }) + return verifyPlannerStrategies({ + machine, + label: "input-less root initialization", + events: [ + { _tag: "Count" }, + { _tag: "Work" }, + { _tag: "Reset" }, + { _tag: "Count" }, + { _tag: "Work" }, + { _tag: "Restart" } + ] + }) +}) + it.effect("compares fresh root input and parallel initial constructors across planners", () => { const root = Machine.state({ type: "parallel", @@ -257,7 +283,6 @@ it.effect("compares fresh root input and parallel initial constructors across pl Right: { fields: { label: Schema.String } } } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, input: Schema.Number, @@ -265,8 +290,8 @@ it.effect("compares fresh root input and parallel initial constructors across pl }).handle({ initial: { Left: ({ input }) => ({ count: input }), Right: ({ input }) => ({ label: String(input) }) }, on: { - Reset: { target: targets.root, input: ({ event }) => event.count }, - Restart: { target: targets.root, input: ({ event }) => event.count, reenter: true } + Reset: { initialize: ({ event }) => event.count }, + Restart: { initialize: ({ event }) => event.count, reenter: true } } }) return verifyPlannerStrategies({ @@ -285,21 +310,20 @@ it.effect("preserves owner updates while resolving compound initial descendants" Work: { fields: { title: Schema.String }, states: { Ready: { fields: { count: Schema.Number } } } } } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Open: {} }) }).handle({ root: { count: 0 }, - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { Open: { - target: targets.root.Work, - update: targets.root, + target: "Work", + update: "root", data: { target: { title: "new" }, update: { count: 1 } } } } }, - Work: { initial: { target: targets.root.Work.Ready, data: ({ root }) => ({ count: root.count }) } } + Work: { initial: { target: "Work.Ready", data: ({ root }) => ({ count: root.count }) } } } }) return verifyPlannerStrategies({ diff --git a/packages/effect-machine/test/internal/machine/strategyDifferential.test.ts b/packages/effect-machine/test/internal/machine/strategyDifferential.test.ts index 0632af2..6d3fd8b 100644 --- a/packages/effect-machine/test/internal/machine/strategyDifferential.test.ts +++ b/packages/effect-machine/test/internal/machine/strategyDifferential.test.ts @@ -32,13 +32,12 @@ const makeFlatMachine = () => { Done: { schema: Done, type: "final", output: Schema.Number } } }) - const targets1 = Machine.targets(states) return Machine.make({ root: states, events: Machine.eventsFromSchemas(Noop, Increment, Reenter, Finish) }).handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, @@ -47,12 +46,12 @@ const makeFlatMachine = () => { on: { Noop: { none: true }, Increment: { - target: targets1.root.Count, + target: "Count", decoded: true, data: ({ state }) => (new Count({ value: state.value + 1 })) }, Reenter: { none: true, reenter: true, resolve: () => undefined }, - Finish: { target: targets1.root.Done, decoded: true, data: ({ state }) => (new Done({ value: state.value })) } + Finish: { target: "Done", decoded: true, data: ({ state }) => (new Done({ value: state.value })) } } }, Done: { output: ({ state }) => state.value } @@ -92,7 +91,7 @@ describe("machine planner and runtime strategies", () => { events: Machine.eventsFromSchemas(Select) }).handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, @@ -129,14 +128,13 @@ describe("machine planner and runtime strategies", () => { }) it.effect("fails closed to generic planning for declinable transitions", () => { const states = Machine.state({ states: { Count } }) - const targets3 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets3.root.Count } } }, + branches: { transition1: { destination: { target: "Count" } } }, root: states, events: Machine.eventsFromSchemas(Select) }).handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, @@ -216,20 +214,19 @@ describe("machine planner and runtime strategies", () => { Outside } }) - const targets4 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(UpdateRegions, Compete, ExitRoot, ReenterUpdate) }).handle({ initial: { - target: Machine.targets(states).root.Root, + target: "Root", decoded: true, data: new Root({ revision: 0 }) }, states: { Root: { initial: { - target: Machine.targets(states).root.Root.Work, + target: "Root.Work", decoded: true, data: new Work({}) }, @@ -244,26 +241,26 @@ describe("machine planner and runtime strategies", () => { initial: { decoded: true, data: new Leaf({}), - target: Machine.targets(states).root.Root.Work.Left.Leaf + target: "Root.Work.Left.Leaf" }, states: { Leaf: { on: { UpdateRegions: { - update: targets4.root.Root.Work.Left, + update: "Root.Work.Left", decoded: true, data: ( { ancestors: { "Root.Work.Left": current } } ) => (new Left({ value: current.value + 1 })) }, - Compete: { update: targets4.root.Root, decoded: true, data: () => (new Root({ revision: 1 })) }, + Compete: { update: "Root", decoded: true, data: () => (new Root({ revision: 1 })) }, ExitRoot: { - update: targets4.root.Root, + update: "Root", decoded: true, data: () => (new Root({ revision: 3 })) }, ReenterUpdate: { - update: targets4.root.Root.Work.Left, + update: "Root.Work.Left", reenter: true, decoded: true, data: ( @@ -276,7 +273,7 @@ describe("machine planner and runtime strategies", () => { }, Right: { initial: { - target: Machine.targets(states).root.Root.Work.Right.Leaf, + target: "Root.Work.Right.Leaf", decoded: true, data: new Leaf({}) }, @@ -284,14 +281,14 @@ describe("machine planner and runtime strategies", () => { Leaf: { on: { UpdateRegions: { - update: targets4.root.Root.Work.Right, + update: "Root.Work.Right", decoded: true, data: ( { ancestors: { "Root.Work.Right": current } } ) => (new Right({ value: current.value + 2 })) }, - Compete: { update: targets4.root.Root, decoded: true, data: () => (new Root({ revision: 2 })) }, - ExitRoot: { target: targets4.root.Outside, decoded: true, data: () => (new Outside({})) } + Compete: { update: "Root", decoded: true, data: () => (new Root({ revision: 2 })) }, + ExitRoot: { target: "Outside", decoded: true, data: () => (new Outside({})) } } } } @@ -352,21 +349,20 @@ describe("machine planner and runtime strategies", () => { } } }) - const targets5 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets5.root.Ready.Saving, update: targets5.root.Ready } } }, + branches: { transition1: { destination: { target: "Ready.Saving", update: "Ready" } } }, root: states, events: Machine.eventsFromSchemas(Save) }).handle({ initial: { - target: Machine.targets(states).root.Ready, + target: "Ready", decoded: true, data: new Ready({ revision: 0 }) }, states: { Ready: { initial: { - target: Machine.targets(states).root.Ready.Idle, + target: "Ready.Idle", decoded: true, data: new Idle({}) }, @@ -435,13 +431,12 @@ describe("machine planner and runtime strategies", () => { } } }) - const targets6 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Advance) }).handle({ initial: { - target: Machine.targets(states).root.Root, + target: "Root", decoded: true, data: new Root({}) }, @@ -455,7 +450,7 @@ describe("machine planner and runtime strategies", () => { Left: { on: { Advance: { - target: targets6.root.Root.Left, + target: "Root.Left", decoded: true, data: ({ state }) => (new Left({ value: state.value + 1 })) } @@ -464,7 +459,7 @@ describe("machine planner and runtime strategies", () => { Right: { on: { Advance: { - target: targets6.root.Root.Right, + target: "Root.Right", decoded: true, data: ({ state }) => (new Right({ value: state.value + 10 })) } @@ -500,25 +495,24 @@ describe("machine planner and runtime strategies", () => { } } }) - const targets7 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Enter) }).handle({ initial: { - target: Machine.targets(states).root.Outside, + target: "Outside", decoded: true, data: new Outside({}) }, states: { Outside: { on: { - Enter: { target: targets7.root.Opened, decoded: true, data: () => (new Opened({})) } + Enter: { target: "Opened", decoded: true, data: () => (new Opened({})) } } }, Opened: { initial: { - target: Machine.targets(states).root.Opened.Idle, + target: "Opened.Idle", data: ({}) => ({ value: 1 }) }, states: { @@ -591,19 +585,18 @@ describe("machine planner and runtime strategies", () => { class Ready extends Schema.TaggedClass("StrategyFallbackReady")("Ready", {}) { } const states = Machine.state({ states: { Idle, Ready } }) - const targets8 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, states: { Idle: { - always: { target: targets8.root.Ready, decoded: true, data: () => (new Ready({})) } + always: { target: "Ready", decoded: true, data: () => (new Ready({})) } }, Ready: {} } @@ -624,7 +617,7 @@ describe("machine planner and runtime strategies", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle + target: "Idle" }, states: { Idle: {} @@ -665,7 +658,7 @@ describe("machine planner and runtime strategies", () => { input: Input }).handle({ initial: { - target: Machine.targets(states).root.Complete, + target: "Complete", decoded: true, data: ({ root: { input: input } }) => new Complete({ value: input.value }) }, @@ -721,7 +714,6 @@ describe("machine planner and runtime strategies", () => { } }) const seen: Array = [] - const targets9 = Machine.targets(states) const definition = Machine.make({ streams: { source1: Stream.suspend(() => Stream.fromIterable([1, 2, 3])) }, root: states, @@ -729,7 +721,7 @@ describe("machine planner and runtime strategies", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Streaming + target: "Streaming" }, states: { Streaming: { @@ -743,7 +735,7 @@ describe("machine planner and runtime strategies", () => { } }, onDone: { - target: targets9.root.StreamDone, + target: "StreamDone", decoded: true, data: () => (new StreamDone({ values: [...seen] })) } @@ -763,7 +755,6 @@ describe("machine planner and runtime strategies", () => { Effect.gen(function*() { const Event = Schema.TaggedUnion({ Set: { value: Schema.NonEmptyString } }) const states = Machine.state({ states: { Count } }) - const targets10 = Machine.targets(states) const definition = Machine.make({ root: states, events: Machine.eventsFromSchemas(Event) @@ -771,7 +762,7 @@ describe("machine planner and runtime strategies", () => { const events = definition.events const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, @@ -779,7 +770,7 @@ describe("machine planner and runtime strategies", () => { Count: { on: { Set: { - target: targets10.root.Count, + target: "Count", decoded: true, data: ({ event }) => (new Count({ value: event.value.length })) } @@ -829,7 +820,7 @@ describe("machine planner and runtime strategies", () => { emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -882,7 +873,7 @@ describe("machine planner and runtime strategies", () => { emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -1006,21 +997,20 @@ describe("machine planner and runtime strategies", () => { Success: { schema: Success, type: "final", output: Schema.String } } }) - const targets12 = Machine.targets(states) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.succeed(new Loaded({ value: "complete" }))) }, root: states, events: Machine.eventsFromSchemas(Load, Loaded) }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, states: { Idle: { on: { - Load: { target: targets12.root.Loading, decoded: true, data: () => (new Loading({})) } + Load: { target: "Loading", decoded: true, data: () => (new Loading({})) } } }, Loading: { @@ -1028,7 +1018,7 @@ describe("machine planner and runtime strategies", () => { src: "source1", id: "load", onDone: { - target: targets12.root.Success, + target: "Success", decoded: true, data: ({ output }) => (new Success({ value: output.value })) } @@ -1091,12 +1081,11 @@ describe("machine planner and runtime strategies", () => { for (const strategy of ["generic", "compiled"] as const) { let membershipAttempts = 0 let navigationRuns = 0 - const targets13 = Machine.targets(states) const machine = Machine.make({ branches: { transition1: { - authenticated: { target: targets13.root.Flow.Checking }, - anonymous: { target: targets13.root.Flow.Plans } + authenticated: { target: "Flow.Checking" }, + anonymous: { target: "Flow.Plans" } } }, effects: { @@ -1117,14 +1106,14 @@ describe("machine planner and runtime strategies", () => { input: Schema.Struct({ authenticated: Schema.Boolean }) }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", data: ({ root: { input: input } }) => input }, root: ({ input }) => ({ input }), states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Routing + target: "Flow.Routing" }, states: { Routing: { @@ -1138,13 +1127,13 @@ describe("machine planner and runtime strategies", () => { invoke: { src: "source1", id: "membership", - onDone: { target: targets13.root.Flow.MemberNavigating }, - onFailure: { target: targets13.root.Flow.Failed } + onDone: { target: "Flow.MemberNavigating" }, + onFailure: { target: "Flow.Failed" } } }, Failed: { on: { - StrategyChoiceRetry: { target: targets13.root.Flow.Checking } + StrategyChoiceRetry: { target: "Flow.Checking" } } }, Plans: {}, @@ -1189,14 +1178,13 @@ describe("machine planner and runtime strategies", () => { Failed: { schema: Failed, type: "final", output: Schema.String } } }) - const targets14 = Machine.targets(states) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.fail("unavailable")) }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Loading, + target: "Loading", decoded: true, data: new Loading({}) }, @@ -1205,7 +1193,7 @@ describe("machine planner and runtime strategies", () => { invoke: { src: "source1", id: "load", - onFailure: { target: targets14.root.Failed, decoded: true, data: ({ error }) => (new Failed({ error })) } + onFailure: { target: "Failed", decoded: true, data: ({ error }) => (new Failed({ error })) } } }, Failed: { output: ({ state }) => state.error } @@ -1266,7 +1254,7 @@ describe("machine planner and runtime strategies", () => { parent: Machine.parent(ParentEvents) }).handle({ initial: { - target: Machine.targets(childStates).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({}) }, @@ -1289,14 +1277,13 @@ describe("machine planner and runtime strategies", () => { ParentDone: { schema: ParentDone, type: "final", output: Schema.String } } }) - const targets16 = Machine.targets(parentStates) const parentMachine = Machine.make({ children: { source1: Child }, root: parentStates, events: ParentEvents }).handle({ initial: { - target: Machine.targets(parentStates).root.ParentWaiting, + target: "ParentWaiting", decoded: true, data: new ParentWaiting({}) }, @@ -1304,7 +1291,7 @@ describe("machine planner and runtime strategies", () => { ParentWaiting: { invoke: { src: "source1", onFailure: { none: true } }, on: { - ChildReady: { target: targets16.root.ParentDone, decoded: true, data: () => (new ParentDone({})) } + ChildReady: { target: "ParentDone", decoded: true, data: () => (new ParentDone({})) } } }, ParentDone: { output: () => "received" } @@ -1333,7 +1320,6 @@ describe("machine planner and runtime strategies", () => { const firstStarted = yield* Deferred.make() let generation = 0 const states = Machine.state({ states: { Loading, Failed } }) - const targets17 = Machine.targets(states) const definition = Machine.make({ logic: { worker: (_input: undefined) => { @@ -1353,7 +1339,7 @@ describe("machine planner and runtime strategies", () => { }, branches: { transition1: { - stale: { target: targets17.root.Failed, title: "Worker is stale" }, + stale: { target: "Failed", title: "Worker is stale" }, unchanged: { none: true } } }, @@ -1362,7 +1348,7 @@ describe("machine planner and runtime strategies", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Loading, + target: "Loading", decoded: true, data: new Loading({ epoch: 0 }) }, @@ -1384,12 +1370,12 @@ describe("machine planner and runtime strategies", () => { }, on: { Reenter: { - target: targets17.root.Loading, + target: "Loading", reenter: true, decoded: true, data: ({ state }) => (new Loading({ epoch: state.epoch + 1 })) }, - Stale: { target: targets17.root.Failed, decoded: true, data: () => (new Failed({})) } + Stale: { target: "Failed", decoded: true, data: () => (new Failed({})) } } }, Failed: {} @@ -1428,7 +1414,7 @@ describe("machine planner and runtime strategies", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(InitialRoot1).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({}) }, @@ -1444,7 +1430,6 @@ describe("machine planner and runtime strategies", () => { class Operating extends Schema.TaggedClass("StrategyDynamicOperating")("Operating", {}) { } const root18 = Machine.state({ states: { Commissioning, Operating } }) - const targets18 = Machine.targets(root18) const machine = Machine.make({ effects: { source1: ({ children }: Machine.Machine.InvokeContext< @@ -1470,7 +1455,7 @@ describe("machine planner and runtime strategies", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(root18).root.Commissioning, + target: "Commissioning", decoded: true, data: new Commissioning({}) }, @@ -1480,7 +1465,7 @@ describe("machine planner and runtime strategies", () => { src: "source1", id: "commission", input: (context) => context, - onDone: { target: targets18.root.Operating }, + onDone: { target: "Operating" }, onFailure: { none: true } } }, diff --git a/packages/effect-machine/test/internal/machine/transitionConstructionStrategies.test.ts b/packages/effect-machine/test/internal/machine/transitionConstructionStrategies.test.ts index b67dbf7..dfffbc7 100644 --- a/packages/effect-machine/test/internal/machine/transitionConstructionStrategies.test.ts +++ b/packages/effect-machine/test/internal/machine/transitionConstructionStrategies.test.ts @@ -7,7 +7,6 @@ it.effect("compares flat updates and verifies guarded updates retain generic pla for (const guarded of [false, true]) { const events = Machine.events({ Add: { by: Schema.Number }, Refresh: {} }) const root1 = Machine.state({ fields: { count: Schema.Number } }) - const targets1 = Machine.targets(root1) const machine = Machine.make({ root: root1, events @@ -15,7 +14,7 @@ it.effect("compares flat updates and verifies guarded updates retain generic pla root: () => ({ count: 0 }), on: { Add: { - update: targets1.root, + update: "root", guard: guarded ? ({ event }) => event.by > 0 : undefined, @@ -54,31 +53,30 @@ it.effect("compares atomic construction and verifies guards retain generic plann schema: Root, states: { Idle: {}, Saved: { schema: Saved }, Done: { type: "final" } } }) - const targets2 = Machine.targets(root2) const machine = Machine.make({ - branches: { transition1: { saved: { target: targets2.root.Saved } } }, + branches: { transition1: { saved: { target: "Saved" } } }, root: root2, events }).handle({ initial: { - target: Machine.targets(root2).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), - on: { Save: { update: targets2.root, data: ({ root: current }) => ({ count: current.count + 10 }) } }, + on: { Save: { update: "root", data: ({ root: current }) => ({ count: current.count + 10 }) } }, states: { Idle: { on: { Save: { - target: targets2.root.Saved, - update: targets2.root, + target: "Saved", + update: "root", guard: guarded ? ({ event }) => event.allowed : undefined, data: ({ root }) => ({ target: { text: "saved" }, update: { count: root.count + 1 } }) }, Decoded: { - target: targets2.root.Saved, - update: targets2.root, + target: "Saved", + update: "root", decoded: true, data: ({ root: current }) => ({ target: new Saved({ text: "decoded" }), @@ -90,8 +88,8 @@ it.effect("compares atomic construction and verifies guards retain generic plann Saved: { on: { Save: { - target: targets2.root.Saved, - update: targets2.root, + target: "Saved", + update: "root", reenter: true, guard: guarded ? ({ event }) => event.allowed @@ -103,7 +101,7 @@ it.effect("compares atomic construction and verifies guards retain generic plann reenter: true, resolve: ({ state, select }) => select.saved({ data: state, decoded: true }) }, - Finish: { target: targets2.root.Done } + Finish: { target: "Done" } } }, Done: {} diff --git a/packages/effect-machine/test/machine/ActivityLifecycleModel.test.ts b/packages/effect-machine/test/machine/ActivityLifecycleModel.test.ts index 97e4075..a18dc78 100644 --- a/packages/effect-machine/test/machine/ActivityLifecycleModel.test.ts +++ b/packages/effect-machine/test/machine/ActivityLifecycleModel.test.ts @@ -66,21 +66,20 @@ describe("machine activity lifecycle model", () => { Effect.gen(function*() { const probe = yield* makeActivityProbe const states = Machine.state({ states: { Idle, Active } }) - const targets1 = Machine.targets(states) const machine = Machine.make({ logic: { source1: probe.logic("active", { _tag: "Blocked" }) }, root: states, events: Machine.eventsFromSchemas(Enter, Leave, Restart) }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, states: { Idle: { on: { - Enter: { target: targets1.root.Active, decoded: true, data: () => (new Active({})) } + Enter: { target: "Active", decoded: true, data: () => (new Active({})) } } }, Active: { @@ -92,8 +91,8 @@ describe("machine activity lifecycle model", () => { onFailure: { none: true } }, on: { - Leave: { target: targets1.root.Idle, decoded: true, data: () => (new Idle({})) }, - Restart: { target: targets1.root.Active, reenter: true, decoded: true, data: () => (new Active({})) } + Leave: { target: "Idle", decoded: true, data: () => (new Idle({})) }, + Restart: { target: "Active", reenter: true, decoded: true, data: () => (new Active({})) } } } } @@ -144,7 +143,6 @@ describe("machine activity lifecycle model", () => { Done: { schema: Done, type: "final", output: Schema.Number } } }) - const targets2 = Machine.targets(states) const machine = Machine.make({ logic: { source1: probe.immediate("immediate", (epoch) => new Completed({ epoch })) }, root: states, @@ -152,7 +150,7 @@ describe("machine activity lifecycle model", () => { internalEvents: Machine.internalEventsFromSchemas(Completed) }).handle({ initial: { - target: Machine.targets(states).root.Active, + target: "Active", decoded: true, data: new Active({}) }, @@ -163,7 +161,7 @@ describe("machine activity lifecycle model", () => { id: "immediate", address: Machine.childAddress("immediate"), onDone: { - target: targets2.root.Done, + target: "Done", decoded: true, data: ({ output }) => (new Done({ epoch: output.epoch })) }, @@ -190,7 +188,6 @@ describe("machine activity lifecycle model", () => { }) { } const states = Machine.state({ states: { Active: EpochActive, Done } }) - const targets3 = Machine.targets(states) const machine = Machine.make({ logic: { source1: probe.logic("epoch", { @@ -203,7 +200,7 @@ describe("machine activity lifecycle model", () => { internalEvents: Machine.internalEventsFromSchemas(Completed) }).handle({ initial: { - target: Machine.targets(states).root.Active, + target: "Active", decoded: true, data: new EpochActive({ acknowledged: 0 }) }, @@ -218,18 +215,18 @@ describe("machine activity lifecycle model", () => { }, on: { Restart: { - target: targets3.root.Active, + target: "Active", reenter: true, decoded: true, data: ({ state }) => (new EpochActive({ acknowledged: state.acknowledged })) }, QueueBarrier: { - target: targets3.root.Active, + target: "Active", decoded: true, data: ({ state }) => (new EpochActive({ acknowledged: state.acknowledged + 1 })) }, Completed: { - target: targets3.root.Done, + target: "Done", decoded: true, data: ({ event }) => (new Done({ epoch: event.epoch })) } @@ -307,7 +304,6 @@ describe("machine activity lifecycle model", () => { } } }) - const targets4 = Machine.targets(root4) const machine = Machine.make({ logic: { source1: probe.logic("left", { _tag: "Blocked" }), @@ -317,7 +313,7 @@ describe("machine activity lifecycle model", () => { events: Machine.eventsFromSchemas(LeaveLeft) }).handle({ initial: { - target: Machine.targets(root4).root.Root, + target: "Root", decoded: true, data: new Root({}) }, @@ -327,7 +323,7 @@ describe("machine activity lifecycle model", () => { states: { left: { initial: { - target: Machine.targets(root4).root.Root.left.active, + target: "Root.left.active", decoded: true, data: new LeftActive({}) }, @@ -341,7 +337,7 @@ describe("machine activity lifecycle model", () => { onFailure: { none: true } }, on: { - LeaveLeft: { target: targets4.root.Root.left.idle, decoded: true, data: () => (new LeftIdle({})) } + LeaveLeft: { target: "Root.left.idle", decoded: true, data: () => (new LeftIdle({})) } } }, idle: {} @@ -349,7 +345,7 @@ describe("machine activity lifecycle model", () => { }, right: { initial: { - target: Machine.targets(root4).root.Root.right.active, + target: "Root.right.active", decoded: true, data: new RightActive({}) }, @@ -389,7 +385,6 @@ describe("machine activity lifecycle model", () => { Effect.gen(function*() { const probe = yield* makeActivityProbe const states = Machine.state({ states: { Idle, Active, Done } }) - const targets5 = Machine.targets(states) const machine = Machine.make({ timers: { source2: "1 hour" }, logic: { source1: probe.logic("timed", { _tag: "Blocked" }) }, @@ -398,7 +393,7 @@ describe("machine activity lifecycle model", () => { internalEvents: Machine.internalEventsFromSchemas(TimerFired) }).handle({ initial: { - target: Machine.targets(states).root.Active, + target: "Active", decoded: true, data: new Active({}) }, @@ -414,10 +409,10 @@ describe("machine activity lifecycle model", () => { }, { src: "source2", id: "deadline", - onDone: { target: targets5.root.Done, decoded: true, data: () => (new Done({ epoch: -1 })) } + onDone: { target: "Done", decoded: true, data: () => (new Done({ epoch: -1 })) } }], on: { - Leave: { target: targets5.root.Idle, decoded: true, data: () => (new Idle({})) } + Leave: { target: "Idle", decoded: true, data: () => (new Idle({})) } } }, Done: {} @@ -450,7 +445,7 @@ describe("machine activity lifecycle model", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Active, + target: "Active", decoded: true, data: new Active({}) }, @@ -505,7 +500,7 @@ describe("machine activity lifecycle model", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Active, + target: "Active", decoded: true, data: new Active({}) }, diff --git a/packages/effect-machine/test/machine/Annotations.test.ts b/packages/effect-machine/test/machine/Annotations.test.ts index bb5e033..fe1797d 100644 --- a/packages/effect-machine/test/machine/Annotations.test.ts +++ b/packages/effect-machine/test/machine/Annotations.test.ts @@ -45,20 +45,20 @@ const machine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.Workflow, + target: "Workflow", decoded: true, data: new Workflow({}) }, states: { Workflow: { initial: { - target: Machine.targets(States).root.Workflow.Idle, + target: "Workflow.Idle", decoded: true, data: new Idle({}) }, states: { Idle: {}, - Routing: { choice: { target: Machine.targets(States).root.Workflow.Done } }, + Routing: { choice: { target: "Workflow.Done" } }, Done: {} } } diff --git a/packages/effect-machine/test/machine/AnnotationsVisualization.test.ts b/packages/effect-machine/test/machine/AnnotationsVisualization.test.ts index 283f3ef..4b27857 100644 --- a/packages/effect-machine/test/machine/AnnotationsVisualization.test.ts +++ b/packages/effect-machine/test/machine/AnnotationsVisualization.test.ts @@ -33,20 +33,20 @@ const machine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.Workflow, + target: "Workflow", decoded: true, data: new Workflow({}) }, states: { Workflow: { initial: { - target: Machine.targets(States).root.Workflow.Idle, + target: "Workflow.Idle", decoded: true, data: new Idle({}) }, states: { Idle: {}, - Routing: { choice: { target: Machine.targets(States).root.Workflow.Done } }, + Routing: { choice: { target: "Workflow.Done" } }, Done: {} } } diff --git a/packages/effect-machine/test/machine/Choice.test.ts b/packages/effect-machine/test/machine/Choice.test.ts index c66d7f7..182f4ba 100644 --- a/packages/effect-machine/test/machine/Choice.test.ts +++ b/packages/effect-machine/test/machine/Choice.test.ts @@ -19,7 +19,6 @@ const States = Machine.state({ } }) let branchDeclarationReads = 0 -const targets1 = Machine.targets(States) const machine = Machine.make({ branches: { routing: { @@ -28,27 +27,27 @@ const machine = Machine.make({ branchDeclarationReads++ return "Score is perfect" }, - target: targets1.root.Flow.Approved + target: "Flow.Approved" }, - negative: { title: "Score is negative", target: targets1.root.Flow.Rejected }, - zero: { title: "Score is zero", target: targets1.root.Flow.Rejected }, - passing: { title: "Score is at least 70", target: targets1.root.Flow.Approved }, - failing: { target: targets1.root.Flow.Rejected } + negative: { title: "Score is negative", target: "Flow.Rejected" }, + zero: { title: "Score is zero", target: "Flow.Rejected" }, + passing: { title: "Score is at least 70", target: "Flow.Approved" }, + failing: { target: "Flow.Rejected" } }, - transition1: { destination: { target: targets1.root.Flow } } + transition1: { destination: { target: "Flow" } } }, root: States, events: Machine.eventsFromSchemas(Recheck) }).handle({ initial: { - target: Machine.targets(States).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 80 }) }, states: { Flow: { initial: { - target: Machine.targets(States).root.Flow.Routing + target: "Flow.Routing" }, states: { Routing: { @@ -71,7 +70,7 @@ const machine = Machine.make({ Approved: { on: { Recheck: { - target: targets1.root.Flow, + target: "Flow", decoded: true, data: ({ event }) => (new Flow({ score: event.score })) } @@ -183,12 +182,11 @@ describe("Machine choice pseudo-states", () => { readonly enabled: boolean readonly score: number } | undefined - const targets2 = Machine.targets(states) const inputChoice = Machine.make({ branches: { transition1: { - approved: { target: targets2.root.Root.Flow.Approved }, - rejected: { target: targets2.root.Root.Flow.Rejected } + approved: { target: "Root.Flow.Approved" }, + rejected: { target: "Root.Flow.Rejected" } } }, root: states, @@ -196,20 +194,20 @@ describe("Machine choice pseudo-states", () => { input: Schema.Struct({ enabled: Schema.Boolean, score: Schema.Number }) }).handle({ initial: { - target: Machine.targets(states).root.Root, + target: "Root", data: ({ root: { input: input } }) => ({ enabled: input.enabled }) }, root: ({ input }) => ({ input }), states: { Root: { initial: { - target: Machine.targets(states).root.Root.Flow, + target: "Root.Flow", data: ({ root: { input: input } }) => ({ score: input.score }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Root.Flow.Routing + target: "Root.Flow.Routing" }, states: { Routing: { @@ -264,28 +262,27 @@ describe("Machine choice pseudo-states", () => { } } }) - const targets3 = Machine.targets(states) const chained = Machine.make({ - branches: { transition1: { destination: { target: targets3.root.Flow.Second } } }, + branches: { transition1: { destination: { target: "Flow.Second" } } }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 80 }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.First + target: "Flow.First" }, states: { First: { choice: { branches: "transition1", resolve: ({ select: { destination: target } }) => target() } }, Second: { - choice: { target: targets3.root.Flow.Approved, decoded: true, data: () => (new Approved({})) } + choice: { target: "Flow.Approved", decoded: true, data: () => (new Approved({})) } }, Approved: {} } @@ -321,25 +318,24 @@ describe("Machine choice pseudo-states", () => { } } }) - const targets4 = Machine.targets(states) const looping = Machine.make({ branches: { - transition1: { destination: { target: targets4.root.Flow.Second } }, - transition2: { destination: { target: targets4.root.Flow.First } } + transition1: { destination: { target: "Flow.Second" } }, + transition2: { destination: { target: "Flow.First" } } }, id: "ChoiceLoopMachine", root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 80 }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.First + target: "Flow.First" }, states: { First: { @@ -372,21 +368,20 @@ describe("Machine choice pseudo-states", () => { } } }) - const targets5 = Machine.targets(states) const alwaysMachine = Machine.make({ - branches: { transition1: { destination: { target: targets5.root.Flow.Routing } } }, + branches: { transition1: { destination: { target: "Flow.Routing" } } }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 10 }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Approved, + target: "Flow.Approved", decoded: true, data: new Approved({}) }, @@ -395,7 +390,7 @@ describe("Machine choice pseudo-states", () => { always: { branches: "transition1", resolve: ({ select: { destination: target } }) => target() } }, Routing: { - choice: { target: targets5.root.Flow.Rejected, decoded: true, data: () => (new Rejected({})) } + choice: { target: "Flow.Rejected", decoded: true, data: () => (new Rejected({})) } }, Rejected: {} } @@ -436,21 +431,20 @@ describe("Machine choice pseudo-states", () => { } } }) - const targets6 = Machine.targets(states) const completion = Machine.make({ - branches: { transition1: { destination: { target: targets6.root.Flow } } }, + branches: { transition1: { destination: { target: "Flow" } } }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 0 }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Done, + target: "Flow.Done", decoded: true, data: new Done({}) }, @@ -462,7 +456,7 @@ describe("Machine choice pseudo-states", () => { states: { Done: {}, Routing: { - choice: { target: targets6.root.Flow.Rejected, decoded: true, data: () => (new Rejected({})) } + choice: { target: "Flow.Rejected", decoded: true, data: () => (new Rejected({})) } }, Rejected: {} } @@ -515,13 +509,12 @@ describe("Machine choice pseudo-states", () => { } } }) - const targets7 = Machine.targets(states) const parallel = Machine.make({ root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Board, + target: "Board", decoded: true, data: new Board({}) }, @@ -531,22 +524,22 @@ describe("Machine choice pseudo-states", () => { states: { Left: { initial: { - target: Machine.targets(states).root.Board.Left.Routing + target: "Board.Left.Routing" }, states: { Routing: { - choice: { target: targets7.root.Board.Left.Ready, decoded: true, data: () => (new Ready({})) } + choice: { target: "Board.Left.Ready", decoded: true, data: () => (new Ready({})) } }, Ready: {} } }, Right: { initial: { - target: Machine.targets(states).root.Board.Right.Routing + target: "Board.Right.Routing" }, states: { Routing: { - choice: { target: targets7.root.Board.Right.Ready, decoded: true, data: () => (new RightReady({})) } + choice: { target: "Board.Right.Ready", decoded: true, data: () => (new RightReady({})) } }, Ready: {} } @@ -588,24 +581,23 @@ describe("Machine choice pseudo-states", () => { Outside } }) - const targets8 = Machine.targets(states) const history = Machine.make({ branches: { - transition2: { destination: { history: targets8.root.Flow.Recent } }, - transition3: { destination: { target: targets8.root.Flow } } + transition2: { destination: { history: "Flow.Recent" } }, + transition3: { destination: { target: "Flow" } } }, root: states, events: Machine.eventsFromSchemas(Leave, Resume) }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 1 }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Active, + target: "Flow.Active", decoded: true, data: new Active({}) }, @@ -626,7 +618,7 @@ describe("Machine choice pseudo-states", () => { states: { Active: { on: { - Leave: { target: targets8.root.Outside, decoded: true, data: () => (new Outside({})) } + Leave: { target: "Outside", decoded: true, data: () => (new Outside({})) } } }, Routing: { @@ -672,21 +664,20 @@ describe("Machine choice pseudo-states", () => { } } }) - const targets9 = Machine.targets(states) const initialHistory = Machine.make({ - branches: { transition1: { destination: { history: targets9.root.Flow.Recent } } }, + branches: { transition1: { destination: { history: "Flow.Recent" } } }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({ score: 1 }) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Routing + target: "Flow.Routing" }, history: { Recent: { @@ -736,21 +727,20 @@ describe("Machine choice pseudo-states", () => { Outside } }) - const targets10 = Machine.targets(states) const historyChoice = Machine.make({ - branches: { transition2: { destination: { history: targets10.root.Flow.Recent } } }, + branches: { transition2: { destination: { history: "Flow.Recent" } } }, root: states, events: Machine.eventsFromSchemas(Resume) }).handle({ initial: { - target: Machine.targets(states).root.Outside, + target: "Outside", decoded: true, data: new Outside({}) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Active + target: "Flow.Active" }, history: { Recent: { @@ -761,7 +751,7 @@ describe("Machine choice pseudo-states", () => { states: { Active: {}, Routing: { - choice: { target: targets10.root.Flow.Active, decoded: true, data: () => (new Active({})) } + choice: { target: "Flow.Active", decoded: true, data: () => (new Active({})) } } } }, diff --git a/packages/effect-machine/test/machine/Declarative.test.ts b/packages/effect-machine/test/machine/Declarative.test.ts index 1c90586..35c6789 100644 --- a/packages/effect-machine/test/machine/Declarative.test.ts +++ b/packages/effect-machine/test/machine/Declarative.test.ts @@ -11,7 +11,6 @@ const Root = Machine.state({ } } }) -const targets = Machine.targets(Root) const events = Machine.events({ Complete: { count: Schema.Number } }) describe("declarative transitions", () => { it.effect("accepts a service class as a direct lazy Effect", () => @@ -26,17 +25,16 @@ describe("declarative transitions", () => { Done: { type: "final", fields: { count: Schema.Number }, output: Schema.Number } } }) - const refs = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({}), effects: { value: Value } }).handle({ initial: { - target: Machine.targets(root).root.Loading + target: "Loading" }, states: { - Loading: { invoke: { src: "value", onDone: { target: refs.root.Done, data: ({ output }) => output } } }, + Loading: { invoke: { src: "value", onDone: { target: "Done", data: ({ output }) => output } } }, Done: { output: ({ state }) => state.count } } }) @@ -54,14 +52,13 @@ describe("declarative transitions", () => { Done: { type: "final", fields: { value: Schema.Number }, output: Schema.Number } } }) - const refs = Machine.targets(root) const effects = { load: Effect.succeed(1) } - const branches = { finish: { done: { target: refs.root.Done } } } + const branches = { finish: { done: { target: "Done" } } } as const const definition = Machine.make({ root, events: Machine.events({}), effects, branches }) effects.load = Effect.succeed(99) const machine = definition.handle({ initial: { - target: Machine.targets(root).root.Loading + target: "Loading" }, states: { Loading: { @@ -79,17 +76,16 @@ describe("declarative transitions", () => { it.effect("allows inline entry into a choice with inspectable destinations", () => Effect.gen(function*() { const root = Machine.state({ states: { Idle: {}, Route: { type: "choice" }, Ready: {} } }) - const refs = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Go: {} }) }).handle({ initial: { - target: Machine.targets(root).root.Idle + target: "Idle" }, states: { - Idle: { on: { Go: { target: refs.root.Route } } }, - Route: { choice: { target: refs.root.Ready } }, + Idle: { on: { Go: { target: "Route" } } }, + Route: { choice: { target: "Ready" } }, Ready: {} } }) @@ -106,13 +102,13 @@ describe("declarative transitions", () => { events }).handle({ initial: { - target: Machine.targets(Root).root.Idle + target: "Idle" }, states: { Idle: { on: { Complete: { - target: targets.root.Ready, + target: "Ready", data: ({ event }) => { calls++ return { count: event.count } @@ -123,7 +119,7 @@ describe("declarative transitions", () => { Ready: {}, Checkout: { initial: { - target: Machine.targets(Root).root.Checkout.Review, + target: "Checkout.Review", data: { total: 0 } }, states: { @@ -150,11 +146,11 @@ describe("declarative transitions", () => { root: Root, events, branches: { - checkout: { review: { target: targets.root.Checkout } } + checkout: { review: { target: "Checkout" } } } }).handle({ initial: { - target: Machine.targets(Root).root.Idle + target: "Idle" }, states: { Idle: { @@ -174,7 +170,7 @@ describe("declarative transitions", () => { Ready: {}, Checkout: { initial: { - target: Machine.targets(Root).root.Checkout.Review, + target: "Checkout.Review", data: { total: 0 } }, states: { @@ -213,7 +209,6 @@ describe("declarative transitions", () => { Done: { type: "final", schema: Schema.TaggedStruct("Done", { count: Schema.Number }), output: Schema.Number } } }) - const refs = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({}), @@ -222,7 +217,7 @@ describe("declarative transitions", () => { } }).handle({ initial: { - target: Machine.targets(root).root.Idle + target: "Idle" }, states: { Idle: { @@ -230,7 +225,7 @@ describe("declarative transitions", () => { src: "load", input: () => 2, onDone: { - target: refs.root.Done, + target: "Done", data: ({ output }) => ({ count: output }) } } diff --git a/packages/effect-machine/test/machine/DeepHandlers.test.ts b/packages/effect-machine/test/machine/DeepHandlers.test.ts index 05c7ac5..25eb1fc 100644 --- a/packages/effect-machine/test/machine/DeepHandlers.test.ts +++ b/packages/effect-machine/test/machine/DeepHandlers.test.ts @@ -74,88 +74,84 @@ const States = Machine.state({ } } }) -const targets1 = Machine.targets(States) const machine = Machine.make({ root: States, events: Machine.eventsFromSchemas(Advance) }).handle({ - initial: { target: Machine.targets(States).root.n0, decoded: true, data: new NodeState({ level: 0 }) }, + initial: { target: "n0", decoded: true, data: new NodeState({ level: 0 }) }, states: { n0: { - initial: { target: Machine.targets(States).root.n0.n1, decoded: true, data: new NodeState({ level: 1 }) }, + initial: { target: "n0.n1", decoded: true, data: new NodeState({ level: 1 }) }, states: { n1: { - initial: { target: Machine.targets(States).root.n0.n1.n2, decoded: true, data: new NodeState({ level: 2 }) }, + initial: { target: "n0.n1.n2", decoded: true, data: new NodeState({ level: 2 }) }, states: { n2: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3, + target: "n0.n1.n2.n3", decoded: true, data: new NodeState({ level: 3 }) }, states: { n3: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4, + target: "n0.n1.n2.n3.n4", decoded: true, data: new NodeState({ level: 4 }) }, states: { n4: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4.n5, + target: "n0.n1.n2.n3.n4.n5", decoded: true, data: new NodeState({ level: 5 }) }, states: { n5: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6, + target: "n0.n1.n2.n3.n4.n5.n6", decoded: true, data: new NodeState({ level: 6 }) }, states: { n6: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6.n7, + target: "n0.n1.n2.n3.n4.n5.n6.n7", decoded: true, data: new NodeState({ level: 7 }) }, states: { n7: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6.n7.n8, + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8", decoded: true, data: new NodeState({ level: 8 }) }, states: { n8: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9, + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9", decoded: true, data: new NodeState({ level: 9 }) }, states: { n9: { initial: { - target: Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10, + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10", decoded: true, data: new NodeState({ level: 10 }) }, states: { n10: { initial: { - target: - Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11, + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11", decoded: true, data: new NodeState({ level: 11 }) }, states: { n11: { initial: { - target: - Machine.targets(States).root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11 - .idle, + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.idle", decoded: true, data: new DeepIdle({ value: "initial" }) }, @@ -163,8 +159,7 @@ const machine = Machine.make({ idle: { on: { Advance: { - target: - targets1.root.n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.done, + target: "n0.n1.n2.n3.n4.n5.n6.n7.n8.n9.n10.n11.done", decoded: true, data: ({ event }) => (new DeepDone({ value: event.value })) } diff --git a/packages/effect-machine/test/machine/DynamicChildren.test.ts b/packages/effect-machine/test/machine/DynamicChildren.test.ts index a642576..202498e 100644 --- a/packages/effect-machine/test/machine/DynamicChildren.test.ts +++ b/packages/effect-machine/test/machine/DynamicChildren.test.ts @@ -39,7 +39,6 @@ describe("dynamic child machines", () => { }, states: { PlantActive } }) - const targets1 = Machine.targets(plantStates) const plantMachine = Machine.make({ root: plantStates, events: Machine.eventsFromSchemas(Produce, Report), @@ -47,7 +46,7 @@ describe("dynamic child machines", () => { parent: Machine.parent(PlantOwnerEvents) }).handle({ initial: { - target: Machine.targets(plantStates).root.PlantActive, + target: "PlantActive", decoded: true, data: ({ root: { input: input } }) => new PlantActive({ id: input.id, produced: input.production }) }, @@ -56,7 +55,7 @@ describe("dynamic child machines", () => { PlantActive: { on: { Produce: { - target: targets1.root.PlantActive, + target: "PlantActive", decoded: true, data: ({ event, state }) => (new PlantActive({ ...state, produced: state.produced + event.amount })) }, @@ -93,7 +92,6 @@ describe("dynamic child machines", () => { }, states: { Commissioning, Operating } }) - const targets2 = Machine.targets(parentStates) const parentMachine = Machine.make({ effects: { source1: ({ children, state }: Machine.Machine.InvokeContext< @@ -120,7 +118,7 @@ describe("dynamic child machines", () => { input: Schema.Array(PlantInput) }).handle({ initial: { - target: Machine.targets(parentStates).root.Commissioning, + target: "Commissioning", decoded: true, data: ({ root: { input: input } }) => new Commissioning({ plants: input }) }, @@ -131,19 +129,19 @@ describe("dynamic child machines", () => { src: "source1", id: "commission-wave", input: (context) => context, - onDone: { target: targets2.root.Operating, decoded: true, data: () => (new Operating({ reports: 0 })) }, + onDone: { target: "Operating", decoded: true, data: () => (new Operating({ reports: 0 })) }, onFailure: { none: true } } }, Operating: { on: { PlantReported: { - target: targets2.root.Operating, + target: "Operating", decoded: true, data: ({ state }) => (new Operating({ reports: state.reports + 1 })) }, Grow: { - target: targets2.root.Commissioning, + target: "Commissioning", decoded: true, data: ({ event }) => (new Commissioning({ plants: event.plants })) }, @@ -250,7 +248,7 @@ describe("dynamic child machines", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(InitialRoot1).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({}) }, @@ -266,7 +264,6 @@ describe("dynamic child machines", () => { { } const root3 = Machine.state({ states: { Starting, DuplicateRejected } }) - const targets3 = Machine.targets(root3) const parentMachine = Machine.make({ effects: { source1: ({ children }: Machine.Machine.InvokeContext< @@ -292,7 +289,7 @@ describe("dynamic child machines", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(root3).root.Starting, + target: "Starting", decoded: true, data: new Starting({}) }, @@ -303,7 +300,7 @@ describe("dynamic child machines", () => { id: "spawn-duplicate", input: (context) => context, onDone: { none: true }, - onFailure: { target: targets3.root.DuplicateRejected } + onFailure: { target: "DuplicateRejected" } } }, DuplicateRejected: {} @@ -333,7 +330,7 @@ describe("dynamic child machines", () => { input: Input }).handle({ initial: { - target: Machine.targets(InitialRoot2).root.WorkerIdle, + target: "WorkerIdle", decoded: true, data: ({ root: { input: input } }) => new WorkerIdle({ id: input.id }) }, @@ -371,7 +368,7 @@ describe("dynamic child machines", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(root4).root.Running, + target: "Running", decoded: true, data: new Running({}) }, @@ -405,13 +402,12 @@ describe("dynamic child machines", () => { class Increment extends Schema.TaggedClass("DynamicControlIncrement")("Increment", {}) { } const root5 = Machine.state({ states: { UnitActive } }) - const targets5 = Machine.targets(root5) const unitMachine = Machine.make({ root: root5, events: Machine.eventsFromSchemas(Increment) }).handle({ initial: { - target: Machine.targets(root5).root.UnitActive, + target: "UnitActive", decoded: true, data: new UnitActive({ count: 0 }) }, @@ -419,7 +415,7 @@ describe("dynamic child machines", () => { UnitActive: { on: { Increment: { - target: targets5.root.UnitActive, + target: "UnitActive", decoded: true, data: ({ state }) => (new UnitActive({ count: state.count + 1 })) } @@ -433,7 +429,6 @@ describe("dynamic child machines", () => { class Ready extends Schema.TaggedClass("DynamicControlReady")("Ready", {}) { } const root6 = Machine.state({ states: { Managing, Ready } }) - const targets6 = Machine.targets(root6) const parentMachine = Machine.make({ effects: { source1: ({ children }: Machine.Machine.InvokeContext< @@ -465,7 +460,7 @@ describe("dynamic child machines", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(root6).root.Managing, + target: "Managing", decoded: true, data: new Managing({}) }, @@ -475,7 +470,7 @@ describe("dynamic child machines", () => { src: "source1", id: "control-units", input: (context) => context, - onDone: { target: targets6.root.Ready }, + onDone: { target: "Ready" }, onFailure: { none: true } } }, diff --git a/packages/effect-machine/test/machine/History.test.ts b/packages/effect-machine/test/machine/History.test.ts index 1ccc5bc..a865d25 100644 --- a/packages/effect-machine/test/machine/History.test.ts +++ b/packages/effect-machine/test/machine/History.test.ts @@ -125,23 +125,22 @@ const makeCheckoutMachine = ( onDefault?: () => void, exactDefault?: () => ReturnType ) => { - const targets1 = Machine.targets(CheckoutStates) return Machine.make({ branches: { - transition3: { destination: { history: targets1.root.checkout.exact } }, - transition4: { destination: { target: targets1.root.checkout.payment } }, - transition5: { destination: { history: targets1.root.checkout.recent } }, - transition6: { destination: { history: targets1.root.checkout.exact } } + transition3: { destination: { history: "checkout.exact" } }, + transition4: { destination: { target: "checkout.payment" } }, + transition5: { destination: { history: "checkout.recent" } }, + transition6: { destination: { history: "checkout.exact" } } }, root: CheckoutStates, events: Machine.eventsFromSchemas(Leave, ResumeShallow, ResumeDeep, GoShipping, EnterVerifying, ReenterHistory) }).handle({ initial: initial.state.path === "checkout" - ? { target: targets1.root.checkout, data: { orderId: "initial" } } - : { target: targets1.root.support, decoded: true, data: initial.state.value }, + ? { target: "checkout", data: { orderId: "initial" } } + : { target: "support", decoded: true, data: initial.state.value }, states: { checkout: { - initial: { target: targets1.root.checkout.shipping, data: { address: "initial" } }, + initial: { target: "checkout.shipping", data: { address: "initial" } }, entry: () => { lifecycle?.push("entry:checkout") }, @@ -163,9 +162,9 @@ const makeCheckoutMachine = ( } }, on: { - Leave: { target: targets1.root.support, decoded: true, data: () => (new Support({ ticket: "ticket-1" })) }, + Leave: { target: "support", decoded: true, data: () => (new Support({ ticket: "ticket-1" })) }, GoShipping: { - target: targets1.root.checkout.shipping, + target: "checkout.shipping", decoded: true, data: ({ event }) => (new Shipping({ address: event.address })) }, @@ -197,7 +196,7 @@ const makeCheckoutMachine = ( lifecycle?.push("exit:payment") }, initial: { - target: targets1.root.checkout.payment.cardEntry, + target: "checkout.payment.cardEntry", decoded: true, data: ({ state }) => { onInitialize?.() @@ -324,17 +323,16 @@ const activeWorkspace: Machine.Snapshot = { } } const makeWorkspaceMachine = (initialized: Array) => { - const targets2 = Machine.targets(WorkspaceStates) return Machine.make({ branches: { - transition2: { destination: { history: targets2.root.workspace.recent } }, - transition3: { destination: { history: targets2.root.workspace.exact } } + transition2: { destination: { history: "workspace.recent" } }, + transition3: { destination: { history: "workspace.exact" } } }, root: WorkspaceStates, events: Machine.eventsFromSchemas(LeaveWorkspace, ResumeWorkspaceShallow, ResumeWorkspaceDeep) }).handle({ initial: { - target: Machine.targets(WorkspaceStates).root.workspace, + target: "workspace", decoded: true, data: new Workspace({ id: "initial" }) }, @@ -390,12 +388,12 @@ const makeWorkspaceMachine = (initialized: Array) => { } }, on: { - LeaveWorkspace: { target: targets2.root.away, decoded: true, data: () => (new Away({})) } + LeaveWorkspace: { target: "away", decoded: true, data: () => (new Away({})) } }, states: { editor: { initial: { - target: targets2.root.workspace.editor.writing, + target: "workspace.editor.writing", decoded: true, data: ({ state }) => { initialized.push("editor") @@ -405,7 +403,7 @@ const makeWorkspaceMachine = (initialized: Array) => { }, sidebar: { initial: { - target: targets2.root.workspace.sidebar.files, + target: "workspace.sidebar.files", decoded: true, data: ({ state }) => { initialized.push("sidebar") @@ -471,18 +469,17 @@ const nestedParallelSnapshot: Machine.Snapshot = { } } } -const targets3 = Machine.targets(NestedHistoryStates) const nestedHistoryMachine = Machine.make({ branches: { - transition1: { destination: { history: targets3.root.workspace.editor.exact } }, - transition2: { destination: { history: targets3.root.workspace.editor.exact } }, - transition3: { destination: { history: targets3.root.workspace.editor.exact } } + transition1: { destination: { history: "workspace.editor.exact" } }, + transition2: { destination: { history: "workspace.editor.exact" } }, + transition3: { destination: { history: "workspace.editor.exact" } } }, root: NestedHistoryStates, events: Machine.eventsFromSchemas(RestoreEditor, DefaultEditor) }).handle({ initial: { - target: Machine.targets(NestedHistoryStates).root.workspace, + target: "workspace", decoded: true, data: new Workspace({ id: "workspace-1" }) }, @@ -497,7 +494,7 @@ const nestedHistoryMachine = Machine.make({ initial: { decoded: true, data: new Writing({ draft: "" }), - target: Machine.targets(NestedHistoryStates).root.workspace.editor.writing + target: "workspace.editor.writing" }, history: { exact: { diff --git a/packages/effect-machine/test/machine/InitialDeclaration.test.ts b/packages/effect-machine/test/machine/InitialDeclaration.test.ts index c87e7c3..b24ba4f 100644 --- a/packages/effect-machine/test/machine/InitialDeclaration.test.ts +++ b/packages/effect-machine/test/machine/InitialDeclaration.test.ts @@ -6,11 +6,10 @@ describe("handler initial declarations", () => { it.effect("selects an initial child and retains inspectable event targets", () => Effect.gen(function*() { const root = Machine.state({ states: { Locked: {}, Unlocked: {} } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Coin: {} }) }).handle({ - initial: { target: targets.root.Locked }, + initial: { target: "Locked" }, states: { - Locked: { on: { Coin: { target: targets.root.Unlocked } } }, + Locked: { on: { Coin: { target: "Unlocked" } } }, Unlocked: {} } }) @@ -26,14 +25,13 @@ describe("handler initial declarations", () => { fields: { query: Schema.String }, states: { Loading: { fields: { query: Schema.String } } } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, input: Schema.Struct({ query: Schema.String }), events: Machine.events({}) }).handle({ root: ({ input }) => ({ query: input.query }), - initial: { target: targets.root.Loading, data: ({ state }) => ({ query: state.query }) }, + initial: { target: "Loading", data: ({ state }) => ({ query: state.query }) }, states: { Loading: {} } }) const initial = yield* Machine.planInitial(machine, { query: "hello" }) @@ -65,10 +63,9 @@ describe("handler initial declarations", () => { it.effect("reuses a structural root without sharing initial selections", () => Effect.gen(function*() { const root = Machine.state({ states: { Left: {}, Right: {} } }) - const targets = Machine.targets(root) const definition = Machine.make({ root, events: Machine.events({}) }) - const left = definition.handle({ initial: { target: targets.root.Left } }) - const right = definition.handle({ initial: { target: targets.root.Right } }) + const left = definition.handle({ initial: { target: "Left" } }) + const right = definition.handle({ initial: { target: "Right" } }) assert.isTrue(root.matches((yield* Machine.planInitial(left)).state, "Left")) assert.isTrue(root.matches((yield* Machine.planInitial(right)).state, "Right")) assert.isFalse("initial" in root.node) @@ -85,7 +82,6 @@ describe("handler initial declarations", () => { Right: { fields: { count: Schema.Number } } } }) - const targets = Machine.targets(root) const order: string[] = [] const machine = Machine.make({ root, input: Schema.Number, events: Machine.events({}) }).handle({ root: ({ input }) => { @@ -108,7 +104,7 @@ describe("handler initial declarations", () => { states: { Left: { initial: { - target: targets.root.Left.Ready, + target: "Left.Ready", data: ({ state }) => { order.push("Ready") return { label: String(state.count) } @@ -126,10 +122,11 @@ describe("handler initial declarations", () => { assert.isTrue(order.includes("entry")) })) - it("rejects initial targets from another root", () => { - const root = Machine.state({ states: { Idle: {} } }) - const other = Machine.state({ states: { Idle: {} } }) + it("rejects initial targets that are not declared direct children", () => { + const root = Machine.state({ states: { Idle: {}, Nested: { states: { Child: {} } } } }) const definition = Machine.make({ root, events: Machine.events({}) }) - assert.throws(() => definition.handle({ initial: { target: Machine.targets(other).root.Idle } }), /direct child/) + assert.throws(() => definition.handle({ initial: { target: "Missing" } } as never), /direct child/) + assert.throws(() => definition.handle({ initial: { target: "Nested.Child" } } as never), /direct child/) + assert.throws(() => definition.handle({ initial: { target: "root" } } as never), /direct child/) }) }) diff --git a/packages/effect-machine/test/machine/InitialEntry.test.ts b/packages/effect-machine/test/machine/InitialEntry.test.ts index 301a192..848f1eb 100644 --- a/packages/effect-machine/test/machine/InitialEntry.test.ts +++ b/packages/effect-machine/test/machine/InitialEntry.test.ts @@ -35,26 +35,25 @@ const States = Machine.state({ } }) const makeMachine = () => { - const targets1 = Machine.targets(States) return Machine.make({ root: States, events: Machine.eventsFromSchemas(Open, OpenInvalid) }).handle({ initial: { - target: Machine.targets(States).root.closed, + target: "closed", decoded: true, data: new Closed({}) }, states: { closed: { on: { - Open: { target: targets1.root.opened, data: () => ({ id: "team-1" }) }, - OpenInvalid: { target: targets1.root.opened, data: () => ({ id: "" }) } + Open: { target: "opened", data: () => ({ id: "team-1" }) }, + OpenInvalid: { target: "opened", data: () => ({ id: "" }) } } }, opened: { initial: { - target: Machine.targets(States).root.opened.idle, + target: "opened.idle", data: ({}) => ({ count: 1 }) }, states: { @@ -82,20 +81,19 @@ const ParallelStates = Machine.state({ } }) const makeParallelMachine = () => { - const targets2 = Machine.targets(ParallelStates) return Machine.make({ root: ParallelStates, events: Machine.eventsFromSchemas(EnterDashboard) }).handle({ initial: { - target: Machine.targets(ParallelStates).root.outside, + target: "outside", decoded: true, data: new Outside({}) }, states: { outside: { on: { - EnterDashboard: { target: targets2.root.dashboard, decoded: true, data: () => (new Dashboard({})) } + EnterDashboard: { target: "dashboard", decoded: true, data: () => (new Dashboard({})) } } }, dashboard: { @@ -103,7 +101,7 @@ const makeParallelMachine = () => { states: { filters: { initial: { - target: Machine.targets(ParallelStates).root.dashboard.filters.ready, + target: "dashboard.filters.ready", data: ({}) => ({ enabled: true }) }, states: { @@ -129,29 +127,28 @@ const ChoiceStates = Machine.state({ } }) const makeChoiceMachine = () => { - const targets3 = Machine.targets(ChoiceStates) return Machine.make({ root: ChoiceStates, events: Machine.eventsFromSchemas(EnterFlow) }).handle({ initial: { - target: Machine.targets(ChoiceStates).root.outside, + target: "outside", decoded: true, data: new Outside({}) }, states: { outside: { on: { - EnterFlow: { target: targets3.root.flow, decoded: true, data: () => (new Flow({})) } + EnterFlow: { target: "flow", decoded: true, data: () => (new Flow({})) } } }, flow: { initial: { - target: Machine.targets(ChoiceStates).root.flow.routing + target: "flow.routing" }, states: { routing: { - choice: { target: targets3.root.flow.approved, decoded: true, data: () => (new Approved({})) } + choice: { target: "flow.approved", decoded: true, data: () => (new Approved({})) } }, approved: {} } @@ -168,25 +165,24 @@ const StructuralStates = Machine.state({ } }) const makeStructuralMachine = () => { - const targets4 = Machine.targets(StructuralStates) return Machine.make({ root: StructuralStates, events: Machine.eventsFromSchemas(EnterFlow) }).handle({ initial: { - target: Machine.targets(StructuralStates).root.outside, + target: "outside", decoded: true, data: new Outside({}) }, states: { outside: { on: { - EnterFlow: { target: targets4.root.group } + EnterFlow: { target: "group" } } }, group: { initial: { - target: Machine.targets(StructuralStates).root.group.idle + target: "group.idle" }, states: { idle: {} @@ -197,7 +193,7 @@ const makeStructuralMachine = () => { } const NestedStates = Machine.state({ states: { - root: { + main: { states: { closed: Closed, opened: { @@ -209,31 +205,30 @@ const NestedStates = Machine.state({ } }) const makeNestedMachine = () => { - const targets5 = Machine.targets(NestedStates) return Machine.make({ root: NestedStates, events: Machine.eventsFromSchemas(OpenLocal, OpenBranch) }).handle({ initial: { - target: Machine.targets(NestedStates).root.root + target: "main" }, states: { - root: { + main: { initial: { - target: Machine.targets(NestedStates).root.root.closed, + target: "main.closed", decoded: true, data: new Closed({}) }, states: { closed: { on: { - OpenLocal: { target: targets5.root.root.opened, data: () => ({ id: "local" }) }, - OpenBranch: { target: targets5.root.root.opened, data: () => ({ id: "branch" }) } + OpenLocal: { target: "main.opened", data: () => ({ id: "local" }) }, + OpenBranch: { target: "main.opened", data: () => ({ id: "branch" }) } } }, opened: { initial: { - target: Machine.targets(NestedStates).root.root.opened.idle, + target: "main.opened.idle", data: ({}) => ({ count: 3 }) }, states: { @@ -251,7 +246,7 @@ describe("declared initial entry", () => { Effect.gen(function*() { let resolves = 0 const root = Machine.state({ states: { closed: Closed } }) - const target = Machine.targets(root).root.closed + const target = "closed" const machine = Machine.make({ root, events: Machine.eventsFromSchemas() }).handle({ initial: { target, @@ -276,7 +271,7 @@ describe("declared initial entry", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(InitialRoot2).root.closed + target: "closed" }, states: { closed: {} @@ -372,12 +367,12 @@ describe("declared initial entry", () => { const branch = yield* Machine.plan(machine, initial.state, new OpenBranch({})) for (const [planned, id] of [[local, "local"], [branch, "branch"]] as const) { assert.deepStrictEqual(planned.next.state, { - path: "root" as const, + path: "main" as const, value: undefined, state: { - path: "root.opened" as const, + path: "main.opened" as const, value: new Opened({ id }), - state: { path: "root.opened.idle" as const, value: new Idle({ count: 3 }) } + state: { path: "main.opened.idle" as const, value: new Idle({ count: 3 }) } } }) } diff --git a/packages/effect-machine/test/machine/Inspection.test.ts b/packages/effect-machine/test/machine/Inspection.test.ts index bf1cc7c..24d101b 100644 --- a/packages/effect-machine/test/machine/Inspection.test.ts +++ b/packages/effect-machine/test/machine/Inspection.test.ts @@ -12,7 +12,7 @@ const RootOutput = Schema.String const DoneOutput = Schema.Number const States = Machine.state({ states: { - root: { + main: { schema: Root, type: "parallel", output: RootOutput, @@ -36,25 +36,25 @@ const machine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.root, + target: "main", decoded: true, data: new Root({}) }, states: { - root: { + main: { output: () => "done", initial: { flow: { decoded: true, data: new Flow({}) }, side: { decoded: true, data: new Side({}) } }, states: { flow: { initial: { - target: Machine.targets(States).root.root.flow.idle, + target: "main.flow.idle", decoded: true, data: new Idle({}) }, states: { idle: {}, done: { output: () => 0 }, - route: { choice: { target: Machine.targets(States).root.root.flow.done } } + route: { choice: { target: "main.flow.done" } } } }, side: {} @@ -73,24 +73,23 @@ const ChoiceStates = Machine.state({ } } }) -const targets1 = Machine.targets(ChoiceStates) const choiceMachine = Machine.make({ root: ChoiceStates, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(ChoiceStates).root.Flow, + target: "Flow", decoded: true, data: new ChoiceFlow({}) }, states: { Flow: { initial: { - target: Machine.targets(ChoiceStates).root.Flow.Routing + target: "Flow.Routing" }, states: { Routing: { - choice: { target: targets1.root.Flow.Ready, decoded: true, data: () => (new Ready({})) } + choice: { target: "Flow.Ready", decoded: true, data: () => (new Ready({})) } }, Ready: {} } @@ -100,48 +99,48 @@ const choiceMachine = Machine.make({ describe("Machine compiled state-node inspection", () => { it("exposes exact metadata for all six state-node kinds", () => { const nodes = new Map(Machine.stateNodes(machine).map((node) => [node.path, node])) - const parallel = nodes.get("root")! + const parallel = nodes.get("main")! assert.strictEqual(parallel.type, "parallel") assert.strictEqual(parallel.schema, Root) assert.strictEqual(parallel.output, RootOutput) assert.strictEqual(parallel.history, undefined) assert.strictEqual(parallel.initial, undefined) - assert.deepStrictEqual(parallel.children, ["root.flow", "root.side"]) - const compound = nodes.get("root.flow")! + assert.deepStrictEqual(parallel.children, ["main.flow", "main.side"]) + const compound = nodes.get("main.flow")! assert.strictEqual(compound.type, "compound") assert.strictEqual(compound.schema, Flow) assert.strictEqual(compound.output, undefined) assert.strictEqual(compound.history, undefined) - assert.strictEqual(compound.initial, "root.flow.idle") - assert.deepStrictEqual(compound.children, ["root.flow.idle", "root.flow.done"]) - const atomic = nodes.get("root.flow.idle")! + assert.strictEqual(compound.initial, "main.flow.idle") + assert.deepStrictEqual(compound.children, ["main.flow.idle", "main.flow.done"]) + const atomic = nodes.get("main.flow.idle")! assert.strictEqual(atomic.type, "atomic") assert.strictEqual(atomic.schema, Idle) assert.strictEqual(atomic.output, undefined) assert.strictEqual(atomic.history, undefined) assert.strictEqual(atomic.initial, undefined) assert.deepStrictEqual(atomic.children, []) - const final = nodes.get("root.flow.done")! + const final = nodes.get("main.flow.done")! assert.strictEqual(final.type, "final") assert.strictEqual(final.schema, Done) assert.strictEqual(final.output, DoneOutput) assert.strictEqual(final.history, undefined) assert.strictEqual(final.initial, undefined) assert.deepStrictEqual(final.children, []) - const history = nodes.get("root.flow.recent")! + const history = nodes.get("main.flow.recent")! assert.strictEqual(history.type, "history") assert.strictEqual(history.schema, undefined) assert.strictEqual(history.output, undefined) assert.strictEqual(history.history, "deep") - assert.strictEqual(history.parent, "root.flow") + assert.strictEqual(history.parent, "main.flow") assert.strictEqual(history.initial, undefined) assert.deepStrictEqual(history.children, []) - const choice = nodes.get("root.flow.route")! + const choice = nodes.get("main.flow.route")! assert.strictEqual(choice.type, "choice") assert.strictEqual(choice.schema, undefined) assert.strictEqual(choice.output, undefined) assert.strictEqual(choice.history, undefined) - assert.strictEqual(choice.parent, "root.flow") + assert.strictEqual(choice.parent, "main.flow") assert.strictEqual(choice.initial, undefined) assert.deepStrictEqual(choice.children, []) }) diff --git a/packages/effect-machine/test/machine/Invoke.test.ts b/packages/effect-machine/test/machine/Invoke.test.ts index 8c72bec..28da3a3 100644 --- a/packages/effect-machine/test/machine/Invoke.test.ts +++ b/packages/effect-machine/test/machine/Invoke.test.ts @@ -28,7 +28,7 @@ describe("inline invoke", () => { timers: { timeout: "1 second" } }).handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -43,15 +43,14 @@ describe("inline invoke", () => { }) it.effect("ignores an invocation outcome when its transition declines", () => Effect.gen(function*() { - const targets2 = Machine.targets(States) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets2.root.Complete } } }, + branches: { transition1: { destination: { target: "Complete" } } }, effects: { source1: Effect.suspend(() => Effect.succeed("ignored")) }, root: States, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -76,7 +75,6 @@ describe("inline invoke", () => { it.effect("handles Stream elements sequentially before completion", () => Effect.gen(function*() { const states = Machine.state({ states: { Collecting, Complete } }) - const targets3 = Machine.targets(states) const definition = Machine.make({ streams: { source1: Stream.suspend(() => Stream.fromIterable([1, 2, 3])) }, root: states, @@ -84,7 +82,7 @@ describe("inline invoke", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Collecting, + target: "Collecting", decoded: true, data: new Collecting({ values: [] }) }, @@ -100,14 +98,14 @@ describe("inline invoke", () => { } }, onDone: { - target: targets3.root.Complete, + target: "Complete", decoded: true, data: ({ state }) => (new Complete({ value: state.values.join(",") })) } }, on: { Add: { - target: targets3.root.Collecting, + target: "Collecting", decoded: true, data: ({ event, state }) => (new Collecting({ values: [...state.values, event.value] })) } @@ -167,7 +165,6 @@ describe("inline invoke", () => { })) it.effect("routes a Stream typed failure through onFailure", () => Effect.gen(function*() { - const targets4 = Machine.targets(States) const definition = Machine.make({ streams: { source1: Stream.suspend(() => Stream.fail("offline")) }, root: States, @@ -175,7 +172,7 @@ describe("inline invoke", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -185,7 +182,7 @@ describe("inline invoke", () => { id: "updates", onDone: { none: true }, onFailure: { - target: targets4.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ message: error })) } @@ -216,7 +213,7 @@ describe("inline invoke", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -246,7 +243,6 @@ describe("inline invoke", () => { finalized = true })) ) - const targets6 = Machine.targets(States) const definition = Machine.make({ streams: { source1: Stream.suspend(() => source) }, root: States, @@ -254,7 +250,7 @@ describe("inline invoke", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -272,7 +268,7 @@ describe("inline invoke", () => { }, on: { FinishStream: { - target: targets6.root.Complete, + target: "Complete", decoded: true, data: ({ event }) => (new Complete({ value: String(event.value) })) } @@ -295,14 +291,13 @@ describe("inline invoke", () => { })) it.effect("plans a successful Effect outcome directly", () => Effect.gen(function*() { - const targets7 = Machine.targets(States) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.succeed("ready")) }, root: States, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -311,7 +306,7 @@ describe("inline invoke", () => { src: "source1", id: "load", onDone: { - target: targets7.root.Complete, + target: "Complete", decoded: true, data: ({ output }) => (new Complete({ value: output })) } @@ -344,14 +339,13 @@ describe("inline invoke", () => { })) it.effect("plans a typed Effect failure directly", () => Effect.gen(function*() { - const targets8 = Machine.targets(States) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.fail("offline")) }, root: States, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.Loading + target: "Loading" }, states: { Idle: {}, @@ -360,7 +354,7 @@ describe("inline invoke", () => { src: "source1", id: "load", onFailure: { - target: targets8.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ message: error })) } @@ -382,7 +376,6 @@ describe("inline invoke", () => { it.effect("fails the owning machine when an Effect source factory defects", () => Effect.gen(function*() { const defect = new Error("source defect") - const targets9 = Machine.targets(States) const machine = Machine.make({ effects: { source1: Effect.suspend((): Effect.Effect => { @@ -393,12 +386,12 @@ describe("inline invoke", () => { events: Machine.eventsFromSchemas(Start) }).handle({ initial: { - target: Machine.targets(States).root.Idle + target: "Idle" }, states: { Idle: { on: { - Start: { target: targets9.root.Loading } + Start: { target: "Loading" } } }, Loading: { @@ -427,19 +420,18 @@ describe("inline invoke", () => { initial: () => Effect.fail(failure), run: () => Effect.never }) - const targets10 = Machine.targets(States) const machine = Machine.make({ logic: { source1: logic }, root: States, events: Machine.eventsFromSchemas(Start) }).handle({ initial: { - target: Machine.targets(States).root.Idle + target: "Idle" }, states: { Idle: { on: { - Start: { target: targets10.root.Loading } + Start: { target: "Loading" } } }, Loading: { diff --git a/packages/effect-machine/test/machine/LiveInspection.test.ts b/packages/effect-machine/test/machine/LiveInspection.test.ts index 3576741..4221790 100644 --- a/packages/effect-machine/test/machine/LiveInspection.test.ts +++ b/packages/effect-machine/test/machine/LiveInspection.test.ts @@ -11,16 +11,15 @@ class Notice extends Schema.TaggedClass("LiveInspectionNotice")("Notice" const states = Machine.state({ states: { Idle } }) const Events = Machine.eventsFromSchemas(Increment) const Emissions = Machine.emittedEventsFromSchemas(Notice) -const targets1 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets1.root.Idle } } }, + branches: { transition1: { destination: { target: "Idle" } } }, id: "counter", root: states, events: Events, emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -105,7 +104,7 @@ describe("Machine live inspection", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", data: () => { throw new Error("boom") } @@ -134,7 +133,7 @@ describe("Machine live inspection", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -190,7 +189,7 @@ describe("Machine live inspection", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -240,7 +239,7 @@ describe("Machine live inspection", () => { parent: Machine.parent(ParentEvents) }).handle({ initial: { - target: Machine.targets(childStates).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({}) }, @@ -265,7 +264,6 @@ describe("Machine live inspection", () => { ParentDone: { schema: ParentDone, type: "final" } } }) - const targets5 = Machine.targets(parentStates) const parentMachine = Machine.make({ children: { source1: Child }, id: "parent-machine", @@ -273,7 +271,7 @@ describe("Machine live inspection", () => { events: Machine.eventsFromSchemas(ParentEvents) }).handle({ initial: { - target: Machine.targets(parentStates).root.ParentIdle, + target: "ParentIdle", decoded: true, data: new ParentIdle({}) }, @@ -281,7 +279,7 @@ describe("Machine live inspection", () => { ParentIdle: { invoke: { src: "source1" }, on: { - ChildReady: { target: targets5.root.ParentDone, decoded: true, data: () => (new ParentDone({})) } + ChildReady: { target: "ParentDone", decoded: true, data: () => (new ParentDone({})) } } }, ParentDone: {} diff --git a/packages/effect-machine/test/machine/LocalTargetWith.test.ts b/packages/effect-machine/test/machine/LocalTargetWith.test.ts index de091e3..60c142a 100644 --- a/packages/effect-machine/test/machine/LocalTargetWith.test.ts +++ b/packages/effect-machine/test/machine/LocalTargetWith.test.ts @@ -24,20 +24,19 @@ describe("local compound target selection", () => { } } }) - const targets1 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets1.root.search } } }, + branches: { transition1: { destination: { target: "search" } } }, root: states, events: Machine.eventsFromSchemas(Events) }).handle({ initial: { - target: Machine.targets(states).root.search, + target: "search", data: { query: "" } }, states: { search: { initial: { - target: Machine.targets(states).root.search.Idle + target: "search.Idle" }, on: { UpdateQuery: { @@ -51,7 +50,7 @@ describe("local compound target selection", () => { Idle: {}, Updated: { on: { - Reset: { target: targets1.root.search.Idle } + Reset: { target: "search.Idle" } } } } @@ -121,21 +120,20 @@ describe("local compound target selection", () => { } } }) - const targets2 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets2.root.search } } }, + branches: { transition1: { destination: { target: "search" } } }, effects: { source1: Effect.suspend(() => Effect.succeed("resolved")) }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.search, + target: "search", data: { query: "pending" } }, states: { search: { initial: { - target: Machine.targets(states).root.search.Searching + target: "search.Searching" }, states: { Searching: { @@ -193,24 +191,23 @@ describe("local compound target selection", () => { } } }) - const targets3 = Machine.targets(states) - assert.notProperty(targets3.root.flow, "with") + assert.notProperty("flow", "with") Machine.make({ root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.flow + target: "flow" }, states: { flow: { initial: { - target: Machine.targets(states).root.flow.Idle + target: "flow.Idle" }, states: { Idle: { on: { - Advance: { target: targets3.root.flow.Updated } + Advance: { target: "flow.Updated" } } }, Updated: {} diff --git a/packages/effect-machine/test/machine/Machine.test.ts b/packages/effect-machine/test/machine/Machine.test.ts index cf6db5f..0d72599 100644 --- a/packages/effect-machine/test/machine/Machine.test.ts +++ b/packages/effect-machine/test/machine/Machine.test.ts @@ -126,7 +126,7 @@ describe("Machine", () => { }) const handlingPing = definition.handle({ initial: { - target: Machine.targets(states).root.Stable, + target: "Stable", decoded: true, data: new Stable({}) }, @@ -136,7 +136,7 @@ describe("Machine", () => { }) const ignoringPing = definition.handle({ initial: { - target: Machine.targets(states).root.Stable, + target: "Stable", decoded: true, data: new Stable({}) }, @@ -176,7 +176,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Ping) }).handle({ initial: { - target: Machine.targets(states).root.Stable, + target: "Stable", decoded: true, data: new Stable({}) }, @@ -220,16 +220,15 @@ describe("Machine", () => { class Finish extends Schema.TaggedClass("BareTargetFinish")("Finish", {}) { } const root3 = Machine.state({ states: { Idle, Done } }) - const targets3 = Machine.targets(root3) const machine = Machine.make({ root: root3, events: Machine.eventsFromSchemas(Finish) }).handle({ initial: { - target: Machine.targets(root3).root.Idle + target: "Idle" }, states: { - Idle: { on: { Finish: { target: targets3.root.Done } } }, + Idle: { on: { Finish: { target: "Done" } } }, Done: {} } }) @@ -251,7 +250,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Restart) }).handle({ initial: { - target: Machine.targets(root4).root.Stable + target: "Stable" }, states: { Stable: { on: { Restart: { none: true, reenter: true } } } @@ -271,10 +270,9 @@ describe("Machine", () => { class Ping extends Schema.TaggedClass("NamedBranchPing")("Ping", { route: Schema.Boolean }) { } const states = Machine.state({ states: { Stable } }) - const targets5 = Machine.targets(states) const declarations = { unchanged: { none: true as const }, - refresh: { title: "Refresh stable state", target: targets5.root.Stable } + refresh: { title: "Refresh stable state", target: "Stable" as const } } const definition = Machine.make({ branches: { refresh: declarations }, @@ -283,7 +281,7 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Stable, + target: "Stable", decoded: true, data: new Stable({}) }, @@ -342,7 +340,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Ping), branches: { invalid: group } as any }).handle({ - initial: { decoded: true, data: new Stable({}), target: Machine.targets(InvalidBranchRoot).root.Stable }, + initial: { decoded: true, data: new Stable({}), target: "Stable" }, states: { Stable: { on: { Ping: { branches: "invalid", resolve: () => undefined } as any } } } @@ -371,7 +369,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Capture, Reuse) }).handle({ initial: { - target: Machine.targets(root6).root.Stable, + target: "Stable", decoded: true, data: new Stable({}) }, @@ -570,7 +568,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -590,7 +588,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -606,15 +604,14 @@ describe("Machine", () => { class Convert extends Schema.TaggedClass("Convert")("Convert", {}) { } const states = Machine.state({ states: { Submit, RequestSucceeded } }) - const targets7 = Machine.targets(states) const definition = Machine.make({ - branches: { transition1: { destination: { target: targets7.root.RequestSucceeded } } }, + branches: { transition1: { destination: { target: "RequestSucceeded" } } }, root: states, events: Machine.eventsFromSchemas(Convert) }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Submit, + target: "Submit", decoded: true, data: new Submit({ value: "loaded" }) }, @@ -648,7 +645,6 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets8 = Machine.targets(states) const machine = Machine.make({ id: "UserMachine", root: states, @@ -656,7 +652,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -665,7 +661,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets8.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -689,7 +685,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(defined).root.idle, + target: "idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -813,14 +809,14 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Authorize) }).handle({ initial: { - target: Machine.targets(states).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(states).root.payment.entering, + target: "payment.entering", decoded: true, data: entering }, @@ -873,7 +869,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(states).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -883,7 +879,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(states).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: checking }, @@ -894,7 +890,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -951,7 +947,6 @@ describe("Machine", () => { const states = Machine.state({ states: { Active: State } }) const events = Machine.eventsFromSchemas(PublicEvent, Defaulted, FiniteEvent) const internalEvents = Machine.internalEventsFromSchemas(InternalEvent) - const targets9 = Machine.targets(states) const definition = Machine.make({ root: states, events, @@ -959,13 +954,13 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Active, + target: "Active", data: { value: "initial" } }, states: { Active: { on: { - SetValue: { target: targets9.root.Active, data: ({ event }) => ({ value: event.value }) }, + SetValue: { target: "Active", data: ({ event }) => ({ value: event.value }) }, Reset: { none: true, resolve: (_, enqueue) => { @@ -974,13 +969,13 @@ describe("Machine", () => { } }, Defaulted: { - target: targets9.root.Active, + target: "Active", data: ({ event }) => ({ value: event.label ?? "default-label" }) }, - Loaded: { target: targets9.root.Active, data: ({ event }) => ({ value: event.value }) }, - TimedOut: { target: targets9.root.Active, data: () => ({ value: "timed-out" }) }, - Alpha: { target: targets9.root.Active, data: ({ event }) => ({ value: event.value }) }, - Beta: { target: targets9.root.Active, data: ({ event }) => ({ value: event.value }) } + Loaded: { target: "Active", data: ({ event }) => ({ value: event.value }) }, + TimedOut: { target: "Active", data: () => ({ value: "timed-out" }) }, + Alpha: { target: "Active", data: ({ event }) => ({ value: event.value }) }, + Beta: { target: "Active", data: ({ event }) => ({ value: event.value }) } } } } @@ -1035,7 +1030,7 @@ describe("Machine", () => { const events = definition.events const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Idle + target: "Idle" }, states: { Idle: { @@ -1073,7 +1068,6 @@ describe("Machine", () => { const release = yield* Deferred.make() const InternalEvent = Schema.TaggedUnion({ Loaded: {}, TimedOut: {} }) const states = Machine.state({ states: { Loading: {}, Waiting: {}, Done: {} } }) - const targets11 = Machine.targets(states) const definition = Machine.make({ effects: { source1: Effect.suspend(() => Deferred.await(release)) }, timers: { source2: "1 second" }, @@ -1083,14 +1077,14 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(states).root.Loading + target: "Loading" }, states: { Loading: { - invoke: { src: "source1", id: "load", onDone: { target: targets11.root.Waiting } } + invoke: { src: "source1", id: "load", onDone: { target: "Waiting" } } }, Waiting: { - invoke: { src: "source2", id: "timeout", onDone: { target: targets11.root.Done } } + invoke: { src: "source2", id: "timeout", onDone: { target: "Done" } } }, Done: {} } @@ -1116,7 +1110,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(FirstEvent) }).handle({ initial: { - target: Machine.targets(states).root.Idle + target: "Idle" }, states: { Idle: {} @@ -1127,7 +1121,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(SecondEvent) }).handle({ initial: { - target: Machine.targets(states).root.Idle + target: "Idle" }, states: { Idle: { @@ -1156,7 +1150,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.idle, + target: "idle", data: { id: "idle-1" } }, states: { @@ -1185,18 +1179,17 @@ describe("Machine", () => { } } }) - const targets13 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.Idle + target: "Idle" }, states: { Idle: { on: { - Submit: { target: targets13.root.Done, data: ({ event }) => ({ requestId: event.requestId }) } + Submit: { target: "Done", data: ({ event }) => ({ requestId: event.requestId }) } } }, Done: {} @@ -1221,7 +1214,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.DefaultOnly + target: "DefaultOnly" }, states: { DefaultOnly: {} @@ -1269,11 +1262,10 @@ describe("Machine", () => { } } }) - const targets14 = Machine.targets(states) const machine = Machine.make({ branches: { - transition3: { destination: { target: targets14.root.Flow.Nested } }, - transition4: { destination: { target: targets14.root.Flow } } + transition3: { destination: { target: "Flow.Nested" } }, + transition4: { destination: { target: "Flow" } } }, id: "from-empty-targets", root: states, @@ -1286,18 +1278,18 @@ describe("Machine", () => { ) }).handle({ initial: { - target: Machine.targets(states).root.Flow + target: "Flow" }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Idle + target: "Flow.Idle" }, states: { Idle: { on: { - Local: { target: targets14.root.Flow.Running }, - LocalWith: { target: targets14.root.Flow.Running }, + Local: { target: "Flow.Running" }, + LocalWith: { target: "Flow.Running" }, Branch: { branches: "transition3", resolve: ({ select: { destination: target } }) => target({ states: { NestedIdle: {} } }) @@ -1307,13 +1299,13 @@ describe("Machine", () => { resolve: ({ select: { destination: target } }) => target({ states: { Nested: { states: { NestedIdle: {} } } } }) }, - Finish: { target: targets14.root.Flow.Done } + Finish: { target: "Flow.Done" } } }, Running: {}, Nested: { initial: { - target: Machine.targets(states).root.Flow.Nested.NestedIdle + target: "Flow.Nested.NestedIdle" }, states: { NestedIdle: {} @@ -1377,14 +1369,14 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Parallel + target: "Parallel" }, states: { Parallel: { states: { left: { initial: { - target: Machine.targets(states).root.Parallel.left.LeftIdle + target: "Parallel.left.LeftIdle" }, states: { LeftIdle: {} @@ -1392,7 +1384,7 @@ describe("Machine", () => { }, right: { initial: { - target: Machine.targets(states).root.Parallel.right.RightIdle + target: "Parallel.right.RightIdle" }, states: { RightIdle: {} @@ -1420,7 +1412,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Blocked + target: "Blocked" }, states: { Blocked: {} @@ -1439,7 +1431,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", data: { userId: "" } }, states: { @@ -1453,20 +1445,19 @@ describe("Machine", () => { it.effect("fails invalid transition construction in the typed machine error channel", () => Effect.gen(function*() { const states = Machine.state({ states: { NonEmptyIdle, NonEmptyLoading } }) - const targets15 = Machine.targets(states) const machine = Machine.make({ id: "from-transition-refinement", root: states, events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", data: { userId: "user-1" } }, states: { NonEmptyIdle: { on: { - NonEmptySubmit: { target: targets15.root.NonEmptyLoading, data: () => ({ requestId: "" }) } + NonEmptySubmit: { target: "NonEmptyLoading", data: () => ({ requestId: "" }) } } }, NonEmptyLoading: {} @@ -1506,14 +1497,13 @@ describe("Machine", () => { } } }) - const targets16 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets16.root.fulfillment } } }, + branches: { transition1: { destination: { target: "fulfillment" } } }, root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.idle, + target: "idle", data: { userId: "user-1" } }, states: { @@ -1543,7 +1533,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(states).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", data: { sku: "sku-1" } }, states: { @@ -1553,7 +1543,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", data: { postalCode: "12345" } }, states: { @@ -1599,20 +1589,19 @@ describe("Machine", () => { } } }) - const targets17 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets17.root.payment } } }, + branches: { transition1: { destination: { target: "payment" } } }, root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.payment, + target: "payment", data: { id: "payment-1" } }, states: { payment: { initial: { - target: Machine.targets(states).root.payment.entering, + target: "payment.entering", data: { amount: 1 } }, states: { @@ -1655,20 +1644,19 @@ describe("Machine", () => { } } }) - const targets18 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets18.root.workflow } } }, + branches: { transition1: { destination: { target: "workflow" } } }, root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.workflow, + target: "workflow", data: { id: "workflow-1" } }, states: { workflow: { initial: { - target: Machine.targets(states).root.workflow.idle, + target: "workflow.idle", data: { userId: "user-1" } }, states: { @@ -1691,7 +1679,7 @@ describe("Machine", () => { }, checkout: { initial: { - target: Machine.targets(states).root.workflow.checkout.quoted, + target: "workflow.checkout.quoted", data: { quoteId: "initial" } }, states: { @@ -1729,7 +1717,7 @@ describe("Machine", () => { input: NonEmptyInput }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: ({ root: { input: input } }) => new NonEmptyIdle({ userId: input.userId }) }, @@ -1749,7 +1737,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: unsafeTagged({ _tag: "NonEmptyIdle", userId: "" }) }, @@ -1763,20 +1751,19 @@ describe("Machine", () => { it.effect("decodes incoming events before handler selection", () => Effect.gen(function*() { const states = Machine.state({ states: { NonEmptyIdle } }) - const targets19 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, states: { NonEmptyIdle: { on: { - NonEmptySubmit: { target: targets19.root.NonEmptyIdle, decoded: true, data: ({ state }) => state } + NonEmptySubmit: { target: "NonEmptyIdle", decoded: true, data: ({ state }) => state } } } } @@ -1797,20 +1784,19 @@ describe("Machine", () => { it.effect("surfaces sent event decode failures through the machine lifecycle", () => Effect.gen(function*() { const states = Machine.state({ states: { NonEmptyIdle } }) - const targets20 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, states: { NonEmptyIdle: { on: { - NonEmptySubmit: { target: targets20.root.NonEmptyIdle, decoded: true, data: ({ state }) => state } + NonEmptySubmit: { target: "NonEmptyIdle", decoded: true, data: ({ state }) => state } } } } @@ -1836,13 +1822,12 @@ describe("Machine", () => { it.effect("decodes transition target values before accepting them", () => Effect.gen(function*() { const states = Machine.state({ states: { NonEmptyIdle, NonEmptyLoading } }) - const targets21 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -1850,7 +1835,7 @@ describe("Machine", () => { NonEmptyIdle: { on: { NonEmptySubmit: { - target: targets21.root.NonEmptyLoading, + target: "NonEmptyLoading", decoded: true, data: () => (unsafeTagged({ _tag: "NonEmptyLoading", requestId: "" })) } @@ -1869,13 +1854,12 @@ describe("Machine", () => { it.effect("decodes same-state atomic snapshot targets in the compiled runtime", () => Effect.gen(function*() { const states = Machine.state({ states: { NonEmptyIdle } }) - const targets22 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -1883,7 +1867,7 @@ describe("Machine", () => { NonEmptyIdle: { on: { NonEmptySubmit: { - target: targets22.root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: () => (unsafeTagged({ _tag: "NonEmptyIdle", userId: "" })) } @@ -1910,13 +1894,12 @@ describe("Machine", () => { } } }) - const targets23 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -1924,7 +1907,7 @@ describe("Machine", () => { NonEmptyIdle: { on: { NonEmptySubmit: { - target: targets23.root.done, + target: "done", decoded: true, data: ({ event }) => (new NonEmptyDone({ requestId: event.value })) } @@ -1968,7 +1951,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.all, + target: "all", decoded: true, data: new ParallelRoot({ id: "all" }) }, @@ -1997,7 +1980,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(NonEmptySubmit) }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -2026,7 +2009,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.count, + target: "count", decoded: true, data: new EncodedCount({ count: 1 }) }, @@ -2079,7 +2062,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.fulfillment, + target: "fulfillment", decoded: true, data: new Fulfillment({ id: "fulfillment-1" }) }, @@ -2092,7 +2075,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(states).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: new CheckingInventory({ sku: "sku-1" }) }, @@ -2103,7 +2086,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: new QuotingShipping({ postalCode: "12345" }) }, @@ -2152,7 +2135,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.all, + target: "all", decoded: true, data: new ParallelRoot({ id: "all" }) }, @@ -2199,7 +2182,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.all, + target: "all", decoded: true, data: new ParallelRoot({ id: "all" }) }, @@ -2238,7 +2221,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.done, + target: "done", decoded: true, data: new ParallelLeftDone({ id: "done" }) }, @@ -2266,7 +2249,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -2292,7 +2275,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -2319,7 +2302,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.NonEmptyIdle, + target: "NonEmptyIdle", decoded: true, data: new NonEmptyIdle({ userId: "user-1" }) }, @@ -2355,14 +2338,14 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.payment, + target: "payment", decoded: true, data: new Payment({ id: "payment-1" }) }, states: { payment: { initial: { - target: Machine.targets(states).root.payment.entering, + target: "payment.entering", decoded: true, data: new EnteringPayment({ amount: 1 }) }, @@ -2396,14 +2379,13 @@ describe("Machine", () => { loading: Loading } }) - const targets24 = Machine.targets(root24) const machine = Machine.make({ root: root24, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root24).root.idle, + target: "idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -2412,7 +2394,7 @@ describe("Machine", () => { idle: { on: { Submit: { - target: targets24.root.loading, + target: "loading", decoded: true, data: ({ event, state }) => (new Loading({ requestId: `${state.userId}:${event.value}` })) } @@ -2447,13 +2429,12 @@ describe("Machine", () => { b: Duplicate } }) - const targets25 = Machine.targets(root25) const machine = Machine.make({ root: root25, events: Machine.eventsFromSchemas(Submit, Reset) }).handle({ initial: { - target: Machine.targets(root25).root.a, + target: "a", decoded: true, data: new Duplicate({ value: "a" }) }, @@ -2461,7 +2442,7 @@ describe("Machine", () => { a: { on: { Submit: { - target: targets25.root.b, + target: "b", decoded: true, data: ({ event }) => (new Duplicate({ value: event.value })) } @@ -2469,7 +2450,7 @@ describe("Machine", () => { }, b: { on: { - Reset: { target: targets25.root.a, decoded: true, data: () => (new Duplicate({ value: "reset" })) } + Reset: { target: "a", decoded: true, data: () => (new Duplicate({ value: "reset" })) } } } } @@ -2501,13 +2482,12 @@ describe("Machine", () => { b: Duplicate } }) - const targets26 = Machine.targets(root26) const machine = Machine.make({ root: root26, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(root26).root.a, + target: "a", decoded: true, data: new Duplicate({ value: "a" }) }, @@ -2515,7 +2495,7 @@ describe("Machine", () => { a: { on: { Submit: { - target: targets26.root.b, + target: "b", decoded: true, data: ({ event }) => (new Duplicate({ value: event.value })) } @@ -2542,13 +2522,12 @@ describe("Machine", () => { } } }) - const targets27 = Machine.targets(root27) const machine = Machine.make({ root: root27, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(root27).root.idle, + target: "idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -2556,7 +2535,7 @@ describe("Machine", () => { idle: { on: { Submit: { - target: targets27.root.success, + target: "success", decoded: true, data: ({ event }) => (new Success({ requestId: event.value })) } @@ -2591,27 +2570,26 @@ describe("Machine", () => { failed: Failed } }) - const targets28 = Machine.targets(root28) const machine = Machine.make({ - branches: { transition2: { destination: { target: targets28.root.payment.authorized } } }, + branches: { transition2: { destination: { target: "payment.authorized" } } }, root: root28, events: Machine.eventsFromSchemas(Authorize) }).handle({ initial: { - target: Machine.targets(root28).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(root28).root.payment.entering, + target: "payment.entering", decoded: true, data: entering }, on: { Authorize: { - target: targets28.root.failed, + target: "failed", decoded: true, data: () => (new Failed({ message: "parent" })) } @@ -2670,15 +2648,14 @@ describe("Machine", () => { let declinableResolverCalls = 0 let raisedResolverCalls = 0 let lifecycleCalls = 0 - const targets29 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets29.root.Done } } }, + branches: { transition1: { destination: { target: "Done" } } }, root: states, events: Machine.eventsFromSchemas(Check, Consume, Finish, Ignore), internalEvents: Machine.internalEventsFromSchemas(Raised) }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -2767,30 +2744,29 @@ describe("Machine", () => { failed: Failed } }) - const targets30 = Machine.targets(root30) const machine = Machine.make({ branches: { - transition2: { authorize: { target: targets30.root.payment.authorized }, consume: { none: true } } + transition2: { authorize: { target: "payment.authorized" }, consume: { none: true } } }, root: root30, events: Machine.eventsFromSchemas(Authorize), emittedEvents: Machine.emittedEventsFromSchemas(Notice) }).handle({ initial: { - target: Machine.targets(root30).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(root30).root.payment.entering, + target: "payment.entering", decoded: true, data: entering }, on: { Authorize: { - target: targets30.root.failed, + target: "failed", decoded: true, data: () => (new Failed({ message: "parent" })) } @@ -2862,24 +2838,23 @@ describe("Machine", () => { finished: Finished } }) - const targets31 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.workflow, + target: "workflow", decoded: true, data: new Workflow({}) }, states: { workflow: { initial: { - target: Machine.targets(states).root.workflow.waiting, + target: "workflow.waiting", decoded: true, data: new Waiting({ ready: false }) }, - always: { target: targets31.root.finished, decoded: true, data: () => (new Finished({})) }, + always: { target: "finished", decoded: true, data: () => (new Finished({})) }, states: { waiting: { always: { @@ -2909,7 +2884,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Ping) }).handle({ initial: { - target: Machine.targets(states).root.Stable, + target: "Stable", decoded: true, data: new Stable({}) }, @@ -2947,21 +2922,20 @@ describe("Machine", () => { finished: Finished } }) - const targets33 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets33.root.finished } } }, + branches: { transition1: { destination: { target: "finished" } } }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.workflow, + target: "workflow", decoded: true, data: new Workflow({}) }, states: { workflow: { initial: { - target: Machine.targets(states).root.workflow.complete, + target: "workflow.complete", decoded: true, data: new Complete({}) }, @@ -2996,7 +2970,7 @@ describe("Machine", () => { } const states = Machine.state({ states: { - root: { + main: { schema: Root, type: "parallel", states: { left: Left, right: Right } @@ -3005,19 +2979,18 @@ describe("Machine", () => { } }) let parentCalls = 0 - const targets34 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets34.root.finished } } }, + branches: { transition1: { destination: { target: "finished" } } }, root: states, events: Machine.eventsFromSchemas(Ping) }).handle({ initial: { - target: Machine.targets(states).root.root, + target: "main", decoded: true, data: new Root({}) }, states: { - root: { + main: { initial: { left: { decoded: true, data: new Left({}) }, right: { decoded: true, data: new Right({}) } }, on: { Ping: { @@ -3054,12 +3027,12 @@ describe("Machine", () => { assert.isTrue(yield* Machine.can(machine, initial.state, new Ping({ handleRight: false }))) assert.strictEqual(parentCalls, 0) const descendant = yield* Machine.plan(machine, initial.state, new Ping({ handleRight: true })) - assert.strictEqual(descendant.next.state.path, "root") - assert.deepStrictEqual(descendant.microsteps[0]?.transitions.map(({ source }) => source), ["root.right"]) + assert.strictEqual(descendant.next.state.path, "main") + assert.deepStrictEqual(descendant.microsteps[0]?.transitions.map(({ source }) => source), ["main.right"]) assert.strictEqual(parentCalls, 0) const ancestor = yield* Machine.plan(machine, initial.state, new Ping({ handleRight: false })) assert.strictEqual(ancestor.next.state.path, "finished") - assert.deepStrictEqual(ancestor.microsteps[0]?.transitions.map(({ source }) => source), ["root"]) + assert.deepStrictEqual(ancestor.microsteps[0]?.transitions.map(({ source }) => source), ["main"]) assert.strictEqual(parentCalls, 1) })) it.effect("handles parent config and nested states in the same object", () => @@ -3082,31 +3055,30 @@ describe("Machine", () => { failed: Failed } }) - const targets35 = Machine.targets(root35) const machine = Machine.make({ root: root35, events: Machine.eventsFromSchemas(Authorize, Reset) }).handle({ initial: { - target: Machine.targets(root35).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(root35).root.payment.entering, + target: "payment.entering", decoded: true, data: entering }, on: { - Reset: { target: targets35.root.failed, decoded: true, data: () => (new Failed({ message: "reset" })) } + Reset: { target: "failed", decoded: true, data: () => (new Failed({ message: "reset" })) } }, states: { entering: { on: { Authorize: { - target: targets35.root.payment.authorized, + target: "payment.authorized", decoded: true, data: ({ event }) => (new AuthorizedPayment({ code: event.code })) } @@ -3151,13 +3123,12 @@ describe("Machine", () => { } } }) - const targets36 = Machine.targets(root36) const machine = Machine.make({ root: root36, events: Machine.eventsFromSchemas(Reset) }).handle({ initial: { - target: Machine.targets(root36).root.payment, + target: "payment", decoded: true, data: payment }, @@ -3165,12 +3136,12 @@ describe("Machine", () => { idle: {}, payment: { initial: { - target: Machine.targets(root36).root.payment.entering, + target: "payment.entering", decoded: true, data: entering }, on: { - Reset: { target: targets36.root.idle, decoded: true, data: () => (new Idle({ userId: "user-1" })) } + Reset: { target: "idle", decoded: true, data: () => (new Idle({ userId: "user-1" })) } }, states: { entering: {}, @@ -3217,14 +3188,13 @@ describe("Machine", () => { } } }) - const targets37 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets37.root.fulfillment } } }, + branches: { transition1: { destination: { target: "fulfillment" } } }, root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.idle, + target: "idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -3260,7 +3230,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(states).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", data: { sku: "sku-1" } }, states: { @@ -3270,7 +3240,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", data: { postalCode: "12345" } }, states: { @@ -3346,21 +3316,20 @@ describe("Machine", () => { } } }) - const targets38 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets38.root.workflow.fulfillment } } }, + branches: { transition1: { destination: { target: "workflow.fulfillment" } } }, root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.workflow, + target: "workflow", decoded: true, data: workflow }, states: { workflow: { initial: { - target: Machine.targets(states).root.workflow.idle, + target: "workflow.idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -3396,7 +3365,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(states).root.workflow.fulfillment.inventory.checking, + target: "workflow.fulfillment.inventory.checking", data: { sku: "sku-1" } }, states: { @@ -3406,7 +3375,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.workflow.fulfillment.shipping.quoting, + target: "workflow.fulfillment.shipping.quoting", data: { postalCode: "12345" } }, states: { @@ -3505,14 +3474,13 @@ describe("Machine", () => { } } } - const targets39 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets39.root.app.flow.fulfillment } } }, + branches: { transition1: { destination: { target: "app.flow.fulfillment" } } }, root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.app, + target: "app", decoded: true, data: app }, @@ -3522,7 +3490,7 @@ describe("Machine", () => { states: { flow: { initial: { - target: Machine.targets(states).root.app.flow.idle, + target: "app.flow.idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -3613,13 +3581,12 @@ describe("Machine", () => { const inventory = new Inventory({ warehouse: "warehouse-1" }) const shipping = new Shipping({ address: "Main Street" }) const quoting = new QuotingShipping({ postalCode: "12345" }) - const targets40 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(states).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -3631,13 +3598,13 @@ describe("Machine", () => { initial: { decoded: true, data: new CheckingInventory({ sku: "sku-1" }), - target: Machine.targets(states).root.fulfillment.inventory.checking + target: "fulfillment.inventory.checking" }, states: { checking: { on: { ReserveInventory: { - target: targets40.root.fulfillment.inventory.reserved, + target: "fulfillment.inventory.reserved", decoded: true, data: ({ event }) => (new InventoryReserved({ reservationId: event.reservationId })) } @@ -3648,7 +3615,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -3712,14 +3679,13 @@ describe("Machine", () => { const shipping = new Shipping({ address: "Main Street" }) const quoting = new QuotingShipping({ postalCode: "12345" }) const nextInventory = new Inventory({ warehouse: "warehouse-2" }) - const targets41 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets41.root.fulfillment.inventory } } }, + branches: { transition1: { destination: { target: "fulfillment.inventory" } } }, root: states, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(states).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -3734,7 +3700,7 @@ describe("Machine", () => { initial: { decoded: true, data: new CheckingInventory({ sku: "sku-1" }), - target: Machine.targets(states).root.fulfillment.inventory.checking + target: "fulfillment.inventory.checking" }, states: { checking: { @@ -3760,7 +3726,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -3825,14 +3791,13 @@ describe("Machine", () => { const shipping = new Shipping({ address: "Main Street" }) const quoting = new QuotingShipping({ postalCode: "12345" }) const nextInventory = new Inventory({ warehouse: "warehouse-2" }) - const targets42 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets42.root.fulfillment.inventory } } }, + branches: { transition1: { destination: { target: "fulfillment.inventory" } } }, root: states, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(states).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -3844,7 +3809,7 @@ describe("Machine", () => { initial: { decoded: true, data: new CheckingInventory({ sku: "sku-1" }), - target: Machine.targets(states).root.fulfillment.inventory.checking + target: "fulfillment.inventory.checking" }, states: { checking: { @@ -3870,7 +3835,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -3936,14 +3901,13 @@ describe("Machine", () => { const nextInventory = new Inventory({ warehouse: "warehouse-2" }) const shipping = new Shipping({ address: "Main Street" }) const quoting = new QuotingShipping({ postalCode: "12345" }) - const targets43 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets43.root.fulfillment } } }, + branches: { transition1: { destination: { target: "fulfillment" } } }, root: states, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(states).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -3955,7 +3919,7 @@ describe("Machine", () => { initial: { decoded: true, data: new CheckingInventory({ sku: "sku-1" }), - target: Machine.targets(states).root.fulfillment.inventory.checking + target: "fulfillment.inventory.checking" }, states: { checking: { @@ -3987,7 +3951,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -4049,28 +4013,27 @@ describe("Machine", () => { const payment = new Payment({ id: "payment-1" }) const inventory = new Inventory({ warehouse: "warehouse-1" }) const shipping = new Shipping({ address: "Main Street" }) - const targets44 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets44.root.payment.shipping } } }, + branches: { transition1: { destination: { target: "payment.shipping" } } }, root: states, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(states).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(states).root.payment.inventory, + target: "payment.inventory", decoded: true, data: inventory }, states: { inventory: { initial: { - target: Machine.targets(states).root.payment.inventory.checking, + target: "payment.inventory.checking", decoded: true, data: new CheckingInventory({ sku: "sku-1" }) }, @@ -4095,7 +4058,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(states).root.payment.shipping.quoting, + target: "payment.shipping.quoting", data: { postalCode: "12345" } }, states: { @@ -4136,26 +4099,25 @@ describe("Machine", () => { } } }) - const targets45 = Machine.targets(root45) const machine = Machine.make({ root: root45, events: Machine.eventsFromSchemas(Authorize, Reset) }).handle({ initial: { - target: Machine.targets(root45).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(root45).root.payment.entering, + target: "payment.entering", decoded: true, data: new EnteringPayment({ amount: 100 }) }, on: { Reset: { - target: targets45.root.payment.entering, + target: "payment.entering", decoded: true, data: () => (new EnteringPayment({ amount: 0 })) } @@ -4164,7 +4126,7 @@ describe("Machine", () => { entering: { on: { Authorize: { - target: targets45.root.payment.authorized, + target: "payment.authorized", decoded: true, data: ({ event }) => (new AuthorizedPayment({ code: event.code })) } @@ -4210,14 +4172,14 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Reset) }).handle({ initial: { - target: Machine.targets(InitialRoot1).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(InitialRoot1).root.payment.authorized, + target: "payment.authorized", decoded: true, data: authorized }, @@ -4257,13 +4219,12 @@ describe("Machine", () => { } } }) - const targets46 = Machine.targets(root46) const machine = Machine.make({ root: root46, events: Machine.eventsFromSchemas(Authorize, Reset) }).handle({ initial: { - target: Machine.targets(root46).root.payment, + target: "payment", decoded: true, data: payment }, @@ -4271,18 +4232,18 @@ describe("Machine", () => { idle: {}, payment: { initial: { - target: Machine.targets(root46).root.payment.entering, + target: "payment.entering", decoded: true, data: new EnteringPayment({ amount: 100 }) }, on: { - Reset: { target: targets46.root.idle, decoded: true, data: () => (new Idle({ userId: "user-1" })) } + Reset: { target: "idle", decoded: true, data: () => (new Idle({ userId: "user-1" })) } }, states: { entering: { on: { Authorize: { - target: targets46.root.payment.authorized, + target: "payment.authorized", decoded: true, data: ({ event }) => (new AuthorizedPayment({ code: event.code })) } @@ -4347,35 +4308,34 @@ describe("Machine", () => { failed: Failed } }) - const targets47 = Machine.targets(root47) const machine = Machine.make({ root: root47, events: Machine.eventsFromSchemas(ReserveInventory, Reset) }).handle({ initial: { - target: Machine.targets(root47).root.checkout, + target: "checkout", decoded: true, data: checkout }, states: { checkout: { initial: { - target: Machine.targets(root47).root.checkout.inventory, + target: "checkout.inventory", decoded: true, data: inventory }, on: { - Reset: { target: targets47.root.failed, decoded: true, data: () => (new Failed({ message: "reset" })) } + Reset: { target: "failed", decoded: true, data: () => (new Failed({ message: "reset" })) } }, states: { inventory: { initial: { - target: Machine.targets(root47).root.checkout.inventory.checking, + target: "checkout.inventory.checking", decoded: true, data: new CheckingInventory({ sku: "sku-1" }) }, onDone: { - target: targets47.root.checkout.shipped, + target: "checkout.shipped", decoded: true, data: ({ output }) => (new ShippingQuoted({ quoteId: String(output) })) }, @@ -4383,7 +4343,7 @@ describe("Machine", () => { checking: { on: { ReserveInventory: { - target: targets47.root.checkout.inventory.reserved, + target: "checkout.inventory.reserved", decoded: true, data: ({ event }) => (new InventoryReserved({ reservationId: event.reservationId })) } @@ -4447,13 +4407,12 @@ describe("Machine", () => { } } }) - const targets48 = Machine.targets(root48) const machine = Machine.make({ root: root48, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(root48).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -4463,7 +4422,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(root48).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: new CheckingInventory({ sku: "sku-1" }) }, @@ -4471,7 +4430,7 @@ describe("Machine", () => { checking: { on: { ReserveInventory: { - target: targets48.root.fulfillment.inventory.reserved, + target: "fulfillment.inventory.reserved", decoded: true, data: ({ event }) => (new InventoryReserved({ reservationId: event.reservationId })) } @@ -4482,7 +4441,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(root48).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -4562,13 +4521,12 @@ describe("Machine", () => { } } }) - const targets49 = Machine.targets(root49) const machine = Machine.make({ root: root49, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(root49).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -4582,7 +4540,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(root49).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: checking }, @@ -4590,7 +4548,7 @@ describe("Machine", () => { checking: { on: { ReserveInventory: { - target: targets49.root.fulfillment.inventory.reserved, + target: "fulfillment.inventory.reserved", decoded: true, data: ({ event }) => (new InventoryReserved({ reservationId: event.reservationId })) } @@ -4603,7 +4561,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(root49).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -4611,7 +4569,7 @@ describe("Machine", () => { quoting: { on: { ReserveInventory: { - target: targets49.root.fulfillment.shipping.quoted, + target: "fulfillment.shipping.quoted", decoded: true, data: ({ event }) => (new ShippingQuoted({ quoteId: event.reservationId })) } @@ -4701,13 +4659,12 @@ describe("Machine", () => { } } }) - const targets50 = Machine.targets(root50) const machine = Machine.make({ root: root50, events: Machine.eventsFromSchemas(ReserveInventory, Resolve) }).handle({ initial: { - target: Machine.targets(root50).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -4718,7 +4675,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(root50).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: new CheckingInventory({ sku: "sku-1" }) }, @@ -4726,7 +4683,7 @@ describe("Machine", () => { checking: { on: { ReserveInventory: { - target: targets50.root.fulfillment.inventory.reserved, + target: "fulfillment.inventory.reserved", decoded: true, data: ({ event }) => (new InventoryReserved({ reservationId: event.reservationId })) } @@ -4739,7 +4696,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(root50).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -4747,7 +4704,7 @@ describe("Machine", () => { quoting: { on: { Resolve: { - target: targets50.root.fulfillment.shipping.quoted, + target: "fulfillment.shipping.quoted", decoded: true, data: () => (new ShippingQuoted({ quoteId: "quote-1" })) } @@ -4816,13 +4773,12 @@ describe("Machine", () => { } } }) - const targets51 = Machine.targets(root51) const machine = Machine.make({ root: root51, events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(root51).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -4832,7 +4788,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(root51).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: checking }, @@ -4840,7 +4796,7 @@ describe("Machine", () => { checking: { on: { ReserveInventory: { - target: targets51.root.fulfillment.inventory.reserved, + target: "fulfillment.inventory.reserved", decoded: true, data: ({ event }) => (new InventoryReserved({ reservationId: event.reservationId })) } @@ -4851,7 +4807,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(root51).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -4859,7 +4815,7 @@ describe("Machine", () => { quoting: { on: { ReserveInventory: { - target: targets51.root.fulfillment.shipping.quoted, + target: "fulfillment.shipping.quoted", decoded: true, data: ({ event }) => (new ShippingQuoted({ quoteId: event.reservationId })) } @@ -4924,14 +4880,13 @@ describe("Machine", () => { } } }) - const targets52 = Machine.targets(root52) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets52.root.fulfillment.inventory.reserved } } }, + branches: { transition1: { destination: { target: "fulfillment.inventory.reserved" } } }, root: root52, events: Machine.eventsFromSchemas(ReserveInventory, Resolve) }).handle({ initial: { - target: Machine.targets(root52).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -4941,7 +4896,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(root52).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: checking }, @@ -4967,7 +4922,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(root52).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: quoting }, @@ -4975,7 +4930,7 @@ describe("Machine", () => { quoting: { on: { Resolve: { - target: targets52.root.fulfillment.shipping.quoted, + target: "fulfillment.shipping.quoted", decoded: true, data: () => (new ShippingQuoted({ quoteId: "raised" })) } @@ -5018,7 +4973,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(InitialRoot2).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -5037,14 +4992,13 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets53 = Machine.targets(root53) const machine = Machine.make({ root: root53, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root53).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5053,7 +5007,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets53.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5081,14 +5035,13 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets54 = Machine.targets(root54) const machine = Machine.make({ root: root54, events: Machine.eventsFromSchemas(Submit, Reset), input: Input }).handle({ initial: { - target: Machine.targets(root54).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5097,7 +5050,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets54.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5105,7 +5058,7 @@ describe("Machine", () => { }, Loading: { on: { - Reset: { target: targets54.root.Idle, decoded: true, data: () => (new Idle({ userId: "user-1" })) } + Reset: { target: "Idle", decoded: true, data: () => (new Idle({ userId: "user-1" })) } } } } @@ -5137,14 +5090,13 @@ describe("Machine", () => { Success: { schema: Success, type: "final" } } }) - const targets55 = Machine.targets(root55) const machine = Machine.make({ root: root55, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root55).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5153,7 +5105,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets55.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) } @@ -5179,14 +5131,13 @@ describe("Machine", () => { }, states: { Idle, Success: SuccessOutput } }) - const targets56 = Machine.targets(root56) const machine = Machine.make({ root: root56, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root56).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5195,7 +5146,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets56.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) } @@ -5226,14 +5177,13 @@ describe("Machine", () => { }, states: { Idle, Success: SuccessOutput } }) - const targets57 = Machine.targets(root57) const machine = Machine.make({ root: root57, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root57).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5242,7 +5192,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets57.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) } @@ -5269,7 +5219,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(InitialRoot3).root.Success, + target: "Success", decoded: true, data: new Success({ requestId: "request-1" }) }, @@ -5311,7 +5261,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(InitialRoot4).root.Success, + target: "Success", decoded: true, data: new Success({ requestId: "request-1" }) }, @@ -5347,14 +5297,13 @@ describe("Machine", () => { Success: { schema: Success, type: "final" } } }) - const targets58 = Machine.targets(root58) const machine = Machine.make({ root: root58, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root58).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5363,7 +5312,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets58.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) } @@ -5400,14 +5349,13 @@ describe("Machine", () => { Success: { schema: Success, type: "final" } } }) - const targets59 = Machine.targets(root59) const machine = Machine.make({ root: root59, events: Machine.eventsFromSchemas(Submit, Reset), input: Input }).handle({ initial: { - target: Machine.targets(root59).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5416,11 +5364,11 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets59.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) }, - Reset: { target: targets59.root.Idle, decoded: true, data: () => (new Idle({ userId: "user-2" })) } + Reset: { target: "Idle", decoded: true, data: () => (new Idle({ userId: "user-2" })) } } }, Success: {} @@ -5447,13 +5395,12 @@ describe("Machine", () => { it.effect("start keeps the machine alive after the starting fiber completes", () => Effect.gen(function*() { const root60 = Machine.state({ states: { Idle, Loading } }) - const targets60 = Machine.targets(root60) const machine = Machine.make({ root: root60, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(root60).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -5461,7 +5408,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets60.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5486,14 +5433,13 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets61 = Machine.targets(root61) const machine = Machine.make({ root: root61, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root61).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5502,7 +5448,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets61.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5540,7 +5486,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(InitialRoot5).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5574,7 +5520,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root62).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5601,14 +5547,13 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets63 = Machine.targets(root63) const machine = Machine.make({ root: root63, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root63).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5617,7 +5562,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets63.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5670,14 +5615,13 @@ describe("Machine", () => { }, states: { Idle, Success: SuccessOutput } }) - const targets64 = Machine.targets(root64) const machine = Machine.make({ root: root64, events: Machine.eventsFromSchemas(Submit), input: Input }).handle({ initial: { - target: Machine.targets(root64).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5686,7 +5630,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets64.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) } @@ -5722,7 +5666,6 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets65 = Machine.targets(root65) const machine = Machine.make({ id: "UserMachine", root: root65, @@ -5730,7 +5673,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root65).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5739,7 +5682,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets65.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5767,7 +5710,6 @@ describe("Machine", () => { }, states: { Idle, Loading, Success: SuccessOutput } }) - const targets66 = Machine.targets(root66) const definition = Machine.make({ effects: { source1: Effect.suspend(() => Effect.succeed("done:request-1")) }, root: root66, @@ -5776,7 +5718,7 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(root66).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5785,7 +5727,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets66.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5796,7 +5738,7 @@ describe("Machine", () => { src: "source1", id: "request", onDone: { - target: targets66.root.Success, + target: "Success", decoded: true, data: ({ output }) => (new Success({ requestId: output })) } @@ -5835,7 +5777,6 @@ describe("Machine", () => { }, states: { Idle, Loading, Success: SuccessOutput } }) - const targets67 = Machine.targets(root67) const definition = Machine.make({ effects: { source1: Effect.suspend(() => Effect.succeed("done:request-1")) }, root: root67, @@ -5844,7 +5785,7 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(root67).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -5853,7 +5794,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets67.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -5864,7 +5805,7 @@ describe("Machine", () => { src: "source1", id: "request", onDone: { - target: targets67.root.Success, + target: "Success", decoded: true, data: ({ output }) => (new Success({ requestId: output })) } @@ -5903,7 +5844,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(childStates).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "child" }) }, @@ -5919,7 +5860,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(parentStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "parent" }) }, @@ -5972,7 +5913,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(childStates).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "child" }) }, @@ -5988,7 +5929,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(parentStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "parent" }) }, @@ -6027,7 +5968,7 @@ describe("Machine", () => { }).handle({ root: ({ input }) => ({ input }), initial: { - target: Machine.targets(childStates).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => { starts += 1 @@ -6046,7 +5987,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(parentStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "parent" }) }, @@ -6086,7 +6027,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(childStates).root.Success, + target: "Success", decoded: true, data: new Success({ requestId: "child-output" }) }, @@ -6101,14 +6042,13 @@ describe("Machine", () => { Success: { schema: Success, type: "final", output: Schema.String } } }) - const targets71 = Machine.targets(parentStates) const parentMachine = Machine.make({ children: { source1: Child }, root: parentStates, events: Machine.eventsFromSchemas(ChildFinished) }).handle({ initial: { - target: Machine.targets(parentStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "parent" }) }, @@ -6117,7 +6057,7 @@ describe("Machine", () => { invoke: { src: "source1", onDone: { - target: targets71.root.Success, + target: "Success", decoded: true, data: ({ output }) => (new Success({ requestId: output })) } @@ -6143,7 +6083,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6174,7 +6114,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(childStates).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "child" }) }, @@ -6190,7 +6130,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(parentStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6220,7 +6160,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(parentStates).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6250,7 +6190,6 @@ describe("Machine", () => { }, states: { Idle, Loading, Failed: FailedOutput } }) - const targets74 = Machine.targets(root74) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.fail(error)) }, root: root74, @@ -6258,7 +6197,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root74).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6267,7 +6206,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets74.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6278,7 +6217,7 @@ describe("Machine", () => { src: "source1", id: "request", onFailure: { - target: targets74.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ message: error.message })) } @@ -6309,7 +6248,6 @@ describe("Machine", () => { it.effect("start delivers internal invoke events without exposing them through send", () => Effect.gen(function*() { const root75 = Machine.state({ states: { Idle, Loading, Success: SuccessOutput } }) - const targets75 = Machine.targets(root75) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.succeed("loaded")) }, root: root75, @@ -6317,7 +6255,7 @@ describe("Machine", () => { internalEvents: Machine.internalEventsFromSchemas(RequestSucceeded) }).handle({ initial: { - target: Machine.targets(root75).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -6325,7 +6263,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets75.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6336,7 +6274,7 @@ describe("Machine", () => { src: "source1", id: "request", onDone: { - target: targets75.root.Success, + target: "Success", decoded: true, data: ({ output }) => (new Success({ requestId: output })) } @@ -6355,7 +6293,6 @@ describe("Machine", () => { Effect.gen(function*() { const childStarted = yield* Deferred.make() const root76 = Machine.state({ states: { Loading, Success: SuccessOutput } }) - const targets76 = Machine.targets(root76) const machine = Machine.make({ logic: { source1: Machine.logic({ @@ -6373,7 +6310,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(RequestSucceeded) }).handle({ initial: { - target: Machine.targets(root76).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6387,7 +6324,7 @@ describe("Machine", () => { }, on: { RequestSucceeded: { - target: targets76.root.Success, + target: "Success", decoded: true, data: ({ event }) => (new Success({ requestId: event.value })) } @@ -6406,7 +6343,6 @@ describe("Machine", () => { Effect.gen(function*() { const childStarted = yield* Deferred.make() const root77 = Machine.state({ states: { Idle, Loading, Success: SuccessOutput } }) - const targets77 = Machine.targets(root77) const machine = Machine.make({ logic: { source1: Machine.logic({ @@ -6424,7 +6360,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Resolve, RequestSucceeded) }).handle({ initial: { - target: Machine.targets(root77).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6432,7 +6368,7 @@ describe("Machine", () => { Idle: { on: { RequestSucceeded: { - target: targets77.root.Success, + target: "Success", decoded: true, data: ({ event }) => (new Success({ requestId: event.value })) } @@ -6446,7 +6382,7 @@ describe("Machine", () => { onFailure: { none: true } }, on: { - Resolve: { target: targets77.root.Idle, decoded: true, data: () => (new Idle({ userId: "resolved" })) } + Resolve: { target: "Idle", decoded: true, data: () => (new Idle({ userId: "resolved" })) } } }, Success: { @@ -6473,7 +6409,6 @@ describe("Machine", () => { Effect.gen(function*() { const failure = new InvokeError({ message: "unavailable" }) const root78 = Machine.state({ states: { Loading, Failed: FailedOutput } }) - const targets78 = Machine.targets(root78) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.fail(failure)) }, root: root78, @@ -6481,7 +6416,7 @@ describe("Machine", () => { internalEvents: Machine.internalEventsFromSchemas(RequestSucceeded, RequestFailed) }).handle({ initial: { - target: Machine.targets(root78).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6491,7 +6426,7 @@ describe("Machine", () => { src: "source1", id: "request", onFailure: { - target: targets78.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ message: error.message })) } @@ -6511,7 +6446,6 @@ describe("Machine", () => { return (yield* InitialRequirement).initialMessage }) const root79 = Machine.state({ states: { Loading, Success: SuccessOutput } }) - const targets79 = Machine.targets(root79) const machine = Machine.make({ effects: { source1: Effect.suspend(() => requiredMessage) }, root: root79, @@ -6519,7 +6453,7 @@ describe("Machine", () => { internalEvents: Machine.internalEventsFromSchemas(RequestSucceeded) }).handle({ initial: { - target: Machine.targets(root79).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6529,7 +6463,7 @@ describe("Machine", () => { src: "source1", id: "request", onDone: { - target: targets79.root.Success, + target: "Success", decoded: true, data: ({ output }) => (new Success({ requestId: output })) } @@ -6548,7 +6482,6 @@ describe("Machine", () => { it.effect("after emits a state-scoped internal event", () => Effect.gen(function*() { const root80 = Machine.state({ states: { Loading, Success: SuccessOutput } }) - const targets80 = Machine.targets(root80) const machine = Machine.make({ timers: { source1: "1 hour" }, root: root80, @@ -6556,7 +6489,7 @@ describe("Machine", () => { internalEvents: Machine.internalEventsFromSchemas(RequestSucceeded) }).handle({ initial: { - target: Machine.targets(root80).root.Loading, + target: "Loading", decoded: true, data: new Loading({ requestId: "request-1" }) }, @@ -6566,7 +6499,7 @@ describe("Machine", () => { src: "source1", id: "timeout", onDone: { - target: targets80.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "timeout" })) } @@ -6590,7 +6523,6 @@ describe("Machine", () => { }, states: { Idle, Loading, Success: SuccessOutput } }) - const targets81 = Machine.targets(root81) const definition = Machine.make({ logic: { progress: Machine.logic({ initial: "pending", run: () => Effect.never }) }, root: root81, @@ -6599,7 +6531,7 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(root81).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6608,7 +6540,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets81.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6620,7 +6552,7 @@ describe("Machine", () => { id: "request", address: Machine.childAddress("progress-request"), onSnapshot: { - target: targets81.root.Success, + target: "Success", decoded: true, data: ({ id, snapshot }) => new Success({ requestId: `${id}:${snapshot.state}` }) } @@ -6660,7 +6592,6 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets82 = Machine.targets(root82) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.die(error)) }, root: root82, @@ -6668,7 +6599,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root82).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6677,7 +6608,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets82.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6711,7 +6642,6 @@ describe("Machine", () => { }, states: { Idle, Loading, Success: SuccessOutput } }) - const targets83 = Machine.targets(root83) const definition = Machine.make({ logic: { progress: Machine.logic({ @@ -6725,7 +6655,7 @@ describe("Machine", () => { }) }, branches: { - snapshots: { ready: { target: targets83.root.Success, title: "Request is ready" }, unchanged: { none: true } } + snapshots: { ready: { target: "Success", title: "Request is ready" }, unchanged: { none: true } } }, root: root83, events: Machine.eventsFromSchemas(Submit, RequestProgress), @@ -6733,7 +6663,7 @@ describe("Machine", () => { }) const machine = definition.handle({ initial: { - target: Machine.targets(root83).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6742,7 +6672,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets83.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6803,7 +6733,6 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets84 = Machine.targets(root84) const machine = Machine.make({ logic: { source1: Machine.logic({ @@ -6816,7 +6745,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root84).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6825,7 +6754,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets84.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6876,7 +6805,6 @@ describe("Machine", () => { }, states: { Idle, Loading, Success: SuccessOutput } }) - const targets85 = Machine.targets(root85) const machine = Machine.make({ logic: { source1: childLogic }, root: root85, @@ -6884,7 +6812,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root85).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -6893,7 +6821,7 @@ describe("Machine", () => { Idle: { on: { Submit: { - target: targets85.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } @@ -6903,12 +6831,12 @@ describe("Machine", () => { invoke: { src: "source1", id: "request", address: Machine.childAddress("stopping-request") }, on: { Resolve: { - target: targets85.root.Success, + target: "Success", decoded: true, data: () => (new Success({ requestId: "request-1" })) }, RequestSucceeded: { - target: targets85.root.Success, + target: "Success", decoded: true, data: ({ event }) => (new Success({ requestId: event.value })) } @@ -6978,7 +6906,6 @@ describe("Machine", () => { } } }) - const targets86 = Machine.targets(root86) const machine = Machine.make({ logic: { source1: makeInvokeLogic("parent", parentStarted), @@ -6989,14 +6916,14 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(Authorize) }).handle({ initial: { - target: Machine.targets(root86).root.payment, + target: "payment", decoded: true, data: payment }, states: { payment: { initial: { - target: Machine.targets(root86).root.payment.entering, + target: "payment.entering", decoded: true, data: entering }, @@ -7010,7 +6937,7 @@ describe("Machine", () => { invoke: { src: "source2", id: "request", address: Machine.childAddress("payment-entering") }, on: { Authorize: { - target: targets86.root.payment.authorized, + target: "payment.authorized", decoded: true, data: ({ event }) => (new AuthorizedPayment({ code: event.code })) } @@ -7087,7 +7014,6 @@ describe("Machine", () => { } } }) - const targets87 = Machine.targets(root87) const machine = Machine.make({ logic: { source1: makeInvokeLogic(parentStarted, parentStopping), @@ -7098,7 +7024,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(ReserveInventory) }).handle({ initial: { - target: Machine.targets(root87).root.fulfillment, + target: "fulfillment", decoded: true, data: fulfillment }, @@ -7109,7 +7035,7 @@ describe("Machine", () => { states: { inventory: { initial: { - target: Machine.targets(root87).root.fulfillment.inventory.checking, + target: "fulfillment.inventory.checking", decoded: true, data: new CheckingInventory({ sku: "sku-1" }) }, @@ -7118,7 +7044,7 @@ describe("Machine", () => { checking: { on: { ReserveInventory: { - target: targets87.root.success, + target: "success", decoded: true, data: () => (new Success({ requestId: "done" })) } @@ -7128,7 +7054,7 @@ describe("Machine", () => { }, shipping: { initial: { - target: Machine.targets(root87).root.fulfillment.shipping.quoting, + target: "fulfillment.shipping.quoting", decoded: true, data: new QuotingShipping({ postalCode: "12345" }) }, @@ -7167,7 +7093,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(InitialRoot6).root.Idle, + target: "Idle", data: () => { throw defect } @@ -7183,12 +7109,11 @@ describe("Machine", () => { assert.instanceOf(startupError, Machine.StartupError) assert(Cause.hasDies(startupError.cause)) })) - it("rejects a foreign initial target while capturing the definition", () => { + it("rejects an undeclared initial target while capturing the definition", () => { const root = Machine.state({ states: { Idle: {} } }) - const foreign = Machine.state({ states: { Other: {} } }) const definition = Machine.make({ root, events: Machine.eventsFromSchemas() }) assert.throws( - () => definition.handle({ initial: { target: Machine.targets(foreign).root.Other } } as never), + () => definition.handle({ initial: { target: "Other" } } as never), /direct child/ ) }) @@ -7200,7 +7125,6 @@ describe("Machine", () => { }, states: { Idle, Loading } }) - const targets88 = Machine.targets(root88) const machine = Machine.make({ id: "LoopMachine", root: root88, @@ -7208,7 +7132,7 @@ describe("Machine", () => { input: Input }).handle({ initial: { - target: Machine.targets(root88).root.Idle, + target: "Idle", decoded: true, data: ({ root: { input: input } }) => new Idle({ userId: input.userId }) }, @@ -7216,20 +7140,20 @@ describe("Machine", () => { states: { Idle: { always: { - target: targets88.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) }, on: { Submit: { - target: targets88.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } } }, Loading: { - always: { target: targets88.root.Idle, decoded: true, data: () => (new Idle({ userId: "user-1" })) } + always: { target: "Idle", decoded: true, data: () => (new Idle({ userId: "user-1" })) } } } }) @@ -7246,27 +7170,26 @@ describe("Machine", () => { it.effect("fails initial planning and startup when always transitions do not stabilize", () => Effect.gen(function*() { const root89 = Machine.state({ states: { Idle, Loading } }) - const targets89 = Machine.targets(root89) const machine = Machine.make({ id: "InitialLoopMachine", root: root89, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(root89).root.Idle, + target: "Idle", decoded: true, data: new Idle({ userId: "user-1" }) }, states: { Idle: { always: { - target: targets89.root.Loading, + target: "Loading", decoded: true, data: () => (new Loading({ requestId: "request-1" })) } }, Loading: { - always: { target: targets89.root.Idle, decoded: true, data: () => (new Idle({ userId: "user-1" })) } + always: { target: "Idle", decoded: true, data: () => (new Idle({ userId: "user-1" })) } } } }) @@ -7295,18 +7218,17 @@ describe("Machine", () => { } } }) - const targets90 = Machine.targets(states) const machine = Machine.make({ branches: { - transition1: { destination: { target: targets90.root.flow } }, - transition2: { destination: { target: targets90.root.flow } } + transition1: { destination: { target: "flow" } }, + transition2: { destination: { target: "flow" } } }, id: "CompletionLoopMachine", root: states, events: Machine.eventsFromSchemas(Submit) }).handle({ initial: { - target: Machine.targets(states).root.idle, + target: "idle", decoded: true, data: new Idle({ userId: "user-1" }) }, @@ -7326,7 +7248,7 @@ describe("Machine", () => { }, flow: { initial: { - target: Machine.targets(states).root.flow.done, + target: "flow.done", data: { requestId: "initial" } }, onDone: { @@ -7382,13 +7304,12 @@ describe("Machine", () => { } }) const makeParallelCounterMachine = () => { - const targets91 = Machine.targets(ParallelCounterStates) return Machine.make({ root: ParallelCounterStates, events: Machine.eventsFromSchemas(AdvanceCounters) }).handle({ initial: { - target: Machine.targets(ParallelCounterStates).root.running, + target: "running", decoded: true, data: new CounterRunning({}) }, @@ -7402,7 +7323,7 @@ describe("Machine", () => { left: { on: { AdvanceCounters: { - target: targets91.root.running.left, + target: "running.left", decoded: true, data: ({ state }) => (new LeftCounter({ value: state.value + 1 })) } @@ -7411,7 +7332,7 @@ describe("Machine", () => { right: { on: { AdvanceCounters: { - target: targets91.root.running.right, + target: "running.right", decoded: true, data: ({ state }) => (new RightCounter({ value: state.value + 1 })) } @@ -7429,7 +7350,7 @@ describe("Machine", () => { events: Machine.eventsFromSchemas(ConcurrentPing) }).handle({ initial: { - target: Machine.targets(states).root.ConcurrentIdle, + target: "ConcurrentIdle", decoded: true, data: new ConcurrentIdle({}) }, diff --git a/packages/effect-machine/test/machine/MachineReferences.test.ts b/packages/effect-machine/test/machine/MachineReferences.test.ts index 8942b6e..28e268f 100644 --- a/packages/effect-machine/test/machine/MachineReferences.test.ts +++ b/packages/effect-machine/test/machine/MachineReferences.test.ts @@ -31,7 +31,7 @@ describe("machine reference event channels", () => { emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: () => { initializations += 1 @@ -82,7 +82,7 @@ describe("machine reference event channels", () => { emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -123,7 +123,7 @@ describe("machine reference event channels", () => { emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -179,7 +179,7 @@ describe("machine reference event channels", () => { emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -237,16 +237,15 @@ describe("machine reference event channels", () => { const ChildEmissions = Machine.emittedEventsFromSchemas(Notice) const childStates = Machine.state({ states: { Waiting, Reported } }) let rootHadParent = true - const targets3 = Machine.targets(childStates) const childMachine = Machine.make({ - branches: { transition1: { destination: { target: targets3.root.Reported } } }, + branches: { transition1: { destination: { target: "Reported" } } }, root: childStates, events: ChildEvents, parent: Machine.optionalParent(ParentEvents), emittedEvents: ChildEmissions }).handle({ initial: { - target: Machine.targets(childStates).root.Waiting, + target: "Waiting", decoded: true, data: new Waiting({}) }, @@ -288,15 +287,14 @@ describe("machine reference event channels", () => { Finished: { schema: Finished, type: "final", output: Schema.String } } }) - const targets4 = Machine.targets(parentStates) const parentMachine = Machine.make({ - branches: { transition1: { destination: { target: targets4.root.Finished } } }, + branches: { transition1: { destination: { target: "Finished" } } }, children: { source1: Child }, root: parentStates, events: Machine.eventsFromSchemas(ParentEvents, Notice) }).handle({ initial: { - target: Machine.targets(parentStates).root.Awaiting, + target: "Awaiting", decoded: true, data: new Awaiting({}) }, @@ -305,12 +303,12 @@ describe("machine reference event channels", () => { invoke: { src: "source1" }, on: { ChildReported: { - target: targets4.root.Finished, + target: "Finished", decoded: true, data: () => (new Finished({ source: "parent event" })) }, Notice: { - target: targets4.root.Finished, + target: "Finished", decoded: true, data: () => (new Finished({ source: "emission" })) } @@ -370,7 +368,7 @@ describe("machine reference event channels", () => { }) const childMachine = childDefinition.handle({ initial: { - target: Machine.targets(childStates).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({}) }, @@ -394,14 +392,13 @@ describe("machine reference event channels", () => { ParentDone: { schema: ParentDone, type: "final", output: Schema.Void } } }) - const targets6 = Machine.targets(parentStates) const parentMachine = Machine.make({ children: { source1: Child }, root: parentStates, events: ParentEvents }).handle({ initial: { - target: Machine.targets(parentStates).root.ParentWaiting, + target: "ParentWaiting", decoded: true, data: new ParentWaiting({}) }, @@ -409,7 +406,7 @@ describe("machine reference event channels", () => { ParentWaiting: { invoke: { src: "source1", onFailure: { none: true } }, on: { - ChildReady: { target: targets6.root.ParentDone, decoded: true, data: () => (new ParentDone({})) } + ChildReady: { target: "ParentDone", decoded: true, data: () => (new ParentDone({})) } } }, ParentDone: { output: () => undefined } diff --git a/packages/effect-machine/test/machine/ObjectConstruction.test.ts b/packages/effect-machine/test/machine/ObjectConstruction.test.ts index aaa215a..0282296 100644 --- a/packages/effect-machine/test/machine/ObjectConstruction.test.ts +++ b/packages/effect-machine/test/machine/ObjectConstruction.test.ts @@ -23,13 +23,12 @@ it.effect("constructs complete parallel subtrees and resolves explicit nested ch } } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Open: {} }), - branches: { open: { work: { target: targets.root.Work } } } + branches: { open: { work: { target: "Work" } } } }).handle({ - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { @@ -49,17 +48,17 @@ it.effect("constructs complete parallel subtrees and resolves explicit nested ch initial: { Left: { id: "default" }, Right: { count: 0 } }, states: { Left: { - initial: { target: targets.root.Work.Left.Empty }, + initial: { target: "Work.Left.Empty" }, states: { Route: { choice: { - target: targets.root.Work.Left.Ready, + target: "Work.Left.Ready", data: ({ containingState }) => ({ id: containingState.id }) } } } }, - Right: { initial: { target: targets.root.Work.Right.Waiting } } + Right: { initial: { target: "Work.Right.Waiting" } } } } } @@ -86,23 +85,22 @@ it.effect("enters a compound's default child with a retained-owner replacement", } } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Open: {} }) }).handle({ root: { revision: 0 }, - initial: { target: targets.root.Idle }, + initial: { target: "Idle" }, states: { Idle: { on: { Open: { - target: targets.root.Flow, - update: targets.root, + target: "Flow", + update: "root", data: { target: { title: "new" }, update: { revision: 1 } } } } }, Flow: { initial: { - target: targets.root.Flow.Editing, + target: "Flow.Editing", data: ({ state, root }) => ({ title: state.title, revision: root.revision }) } } diff --git a/packages/effect-machine/test/machine/Paths.test.ts b/packages/effect-machine/test/machine/Paths.test.ts new file mode 100644 index 0000000..a10672e --- /dev/null +++ b/packages/effect-machine/test/machine/Paths.test.ts @@ -0,0 +1,96 @@ +import { assert, describe, it } from "@effect/vitest" +import { Effect, Schema } from "effect" +import { Machine } from "../../src/index.js" + +describe("declared state paths", () => { + it("reserves the top-level root name for the root node", () => { + const root = Machine.state({ states: { root: {}, Idle: {} } }) + assert.throws(() => Machine.make({ root, events: Machine.events({}) } as never), /reserved for the root/) + }) + + it.effect("allows nested states named root", () => + Effect.gen(function*() { + const root = Machine.state({ states: { Slot: { states: { root: {}, Done: {} } } } }) + const machine = Machine.make({ root, events: Machine.events({ Finish: {} }) }).handle({ + initial: { target: "Slot" }, + states: { + Slot: { + initial: { target: "Slot.root" }, + states: { root: { on: { Finish: { target: "Slot.Done" } } } } + } + } + }) + const initial = yield* Machine.planInitial(machine) + assert.strictEqual(initial.state.state.state.path, "Slot.root") + const finished = yield* Machine.plan(machine, initial.state, { _tag: "Finish" }) + assert.strictEqual(finished.next.state.state.path, "Slot.Done") + })) + + it("rejects undeclared paths and the root as a destination while capturing handlers", () => { + const root = Machine.state({ fields: { count: Schema.Number }, states: { Idle: {}, Busy: {} } }) + const definition = Machine.make({ root, events: Machine.events({ Go: {} }) }) + const handle = (on: unknown) => + definition.handle({ root: { count: 0 }, initial: { target: "Idle" }, on: { Go: on } } as never) + assert.throws(() => handle({ target: "Missing" }), /not a declared state path/) + assert.throws(() => handle({ target: "Idle.Missing" }), /not a declared state path/) + assert.throws(() => handle({ update: "" }), /not a declared state path/) + assert.throws(() => handle({ target: "root" }), /use initialize/) + assert.throws(() => handle({ initialize: {} }), /requires true/) + assert.throws(() => handle({ initialize: true, target: "Idle" }), /exactly one destination/) + assert.throws(() => handle({ initialize: true, update: "root" }), /cannot update/) + assert.throws(() => handle({ initialize: true, data: {} }), /instead of data/) + assert.doesNotThrow(() => handle({ update: "root", data: { count: 1 } })) + }) + + it("rejects branch declarations that supply initialize input", () => { + const root = Machine.state({ states: { Idle: {} } }) + assert.throws( + () => + Machine.make({ + root, + input: Schema.Number, + events: Machine.events({}), + branches: { reset: { root: { initialize: 1 } } } + } as never), + /initialize: true/ + ) + }) + + it.effect("keeps reused subtrees independently addressable", () => + Effect.gen(function*() { + const slot = Machine.state({ states: { Idle: {}, Done: {} } }) + const root = Machine.state({ type: "parallel", states: { Left: slot, Right: slot } }) + const machine = Machine.make({ root, events: Machine.events({ FinishLeft: {} }) }).handle({ + states: { + Left: { initial: { target: "Left.Idle" }, on: { FinishLeft: { target: "Left.Done" } } }, + Right: { initial: { target: "Right.Idle" } } + } + }) + const initial = yield* Machine.planInitial(machine) + const finished = yield* Machine.plan(machine, initial.state, { _tag: "FinishLeft" }) + assert.strictEqual(finished.next.states.Left.state.path, "Left.Done") + assert.strictEqual(finished.next.states.Right.state.path, "Right.Idle") + })) + + it.effect("reconstructs a machine without input through initialize: true", () => + Effect.gen(function*() { + const root = Machine.state({ fields: { count: Schema.Number }, states: { Idle: {}, Busy: {} } }) + const machine = Machine.make({ root, events: Machine.events({ Work: {}, Reset: {} }) }).handle({ + root: { count: 0 }, + initial: { target: "Idle" }, + on: { Reset: { initialize: true } }, + states: { + Idle: { on: { Work: { target: "Busy" } } }, + Busy: { on: { Work: { update: "root", data: ({ root }) => ({ count: root.count + 1 }) } } } + } + }) + const initial = yield* Machine.planInitial(machine) + const busy = yield* Machine.plan(machine, initial.state, { _tag: "Work" }) + const counted = yield* Machine.plan(machine, busy.next, { _tag: "Work" }) + assert.deepStrictEqual(counted.next.value, { _tag: "", count: 1 }) + assert.strictEqual(counted.next.state.path, "Busy") + const reset = yield* Machine.plan(machine, counted.next, { _tag: "Reset" }) + assert.deepStrictEqual(reset.next.value, { _tag: "", count: 0 }) + assert.strictEqual(reset.next.state.path, "Idle") + })) +}) diff --git a/packages/effect-machine/test/machine/ProtocolOwnership.test.ts b/packages/effect-machine/test/machine/ProtocolOwnership.test.ts index 1b22251..2f5d770 100644 --- a/packages/effect-machine/test/machine/ProtocolOwnership.test.ts +++ b/packages/effect-machine/test/machine/ProtocolOwnership.test.ts @@ -14,7 +14,7 @@ describe("protocol ownership", () => { events }).handle({ initial: { - target: Machine.targets(root1).root.State, + target: "State", decoded: true, data: { _tag: "State" } }, @@ -54,7 +54,7 @@ describe("protocol ownership", () => { }) .handle({ initial: { - target: Machine.targets(root2).root.State, + target: "State", decoded: true, data: { _tag: "State" } }, @@ -89,7 +89,7 @@ describe("protocol ownership", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(InitialRoot1).root.State, + target: "State", decoded: true, data: { _tag: "State", value: 1 } }, diff --git a/packages/effect-machine/test/machine/PublicPrototype.test.ts b/packages/effect-machine/test/machine/PublicPrototype.test.ts index 9b24af2..5863a68 100644 --- a/packages/effect-machine/test/machine/PublicPrototype.test.ts +++ b/packages/effect-machine/test/machine/PublicPrototype.test.ts @@ -10,7 +10,7 @@ it("uses the public pipeable and inspectable prototypes", () => { events: Machine.eventsFromSchemas(Start) }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle() }, diff --git a/packages/effect-machine/test/machine/Resume.test.ts b/packages/effect-machine/test/machine/Resume.test.ts index 85a0334..953784f 100644 --- a/packages/effect-machine/test/machine/Resume.test.ts +++ b/packages/effect-machine/test/machine/Resume.test.ts @@ -82,7 +82,7 @@ describe("Machine.resume", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Inactive, + target: "Inactive", decoded: true, data: new Inactive({}) }, @@ -92,7 +92,7 @@ describe("Machine.resume", () => { states: { left: { initial: { - target: Machine.targets(states).root.Root.left.On + target: "Root.left.On" }, invoke: { src: "source2", id: "left", address: Machine.childAddress("left") }, states: { @@ -104,7 +104,7 @@ describe("Machine.resume", () => { }, right: { initial: { - target: Machine.targets(states).root.Root.right.On + target: "Root.right.On" }, invoke: { src: "source4", id: "right", address: Machine.childAddress("right") }, states: { @@ -197,14 +197,13 @@ describe("Machine.resume", () => { } } } - const targets2 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Advance) }) .handle({ initial: { - target: Machine.targets(states).root.Root, + target: "Root", decoded: true, data: new Root({}) }, @@ -214,14 +213,14 @@ describe("Machine.resume", () => { states: { left: { initial: { - target: Machine.targets(states).root.Root.left.A, + target: "Root.left.A", decoded: true, data: new LeftA({}) }, states: { A: { on: { - Advance: { target: targets2.root.Root.left.B, decoded: true, data: () => (new LeftB({})) } + Advance: { target: "Root.left.B", decoded: true, data: () => (new LeftB({})) } } }, B: {} @@ -229,14 +228,14 @@ describe("Machine.resume", () => { }, right: { initial: { - target: Machine.targets(states).root.Root.right.A, + target: "Root.right.A", decoded: true, data: new RightA({}) }, states: { A: { on: { - Advance: { target: targets2.root.Root.right.B, decoded: true, data: () => (new RightB({})) } + Advance: { target: "Root.right.B", decoded: true, data: () => (new RightB({})) } } }, B: {} @@ -277,20 +276,19 @@ describe("Machine.resume", () => { Done: { schema: Done, type: "final", output: Schema.Number } } }) - const targets3 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Finish) }).handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, states: { Count: { on: { - Finish: { target: targets3.root.Done, decoded: true, data: () => (new Done({ value: 9 })) } + Finish: { target: "Done", decoded: true, data: () => (new Done({ value: 9 })) } } }, Done: { output: ({ state }) => state.value } @@ -336,25 +334,24 @@ describe("Machine.resume", () => { { path: "Flow" as const, output: undefined } ] } - const targets4 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Ping) }) .handle({ initial: { - target: Machine.targets(states).root.Flow, + target: "Flow", decoded: true, data: new Flow({}) }, states: { Flow: { initial: { - target: Machine.targets(states).root.Flow.Finished, + target: "Flow.Finished", decoded: true, data: new Finished({}) }, - onDone: { target: targets4.root.Next, decoded: true, data: () => (new Next({})) }, + onDone: { target: "Next", decoded: true, data: () => (new Next({})) }, states: { Finished: {} } @@ -377,19 +374,18 @@ describe("Machine.resume", () => { class B extends Schema.TaggedClass("B")("B", {}) { } const states = Machine.state({ states: { A, B } }) - const targets5 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Ping) }).handle({ initial: { - target: Machine.targets(states).root.A, + target: "A", decoded: true, data: new A({}) }, states: { A: { - always: { target: targets5.root.B, decoded: true, data: () => (new B({})) } + always: { target: "B", decoded: true, data: () => (new B({})) } }, B: {} } @@ -414,7 +410,6 @@ describe("Machine.resume", () => { class TimedOut extends Schema.TaggedClass("TimedOut")("TimedOut", {}) { } const states = Machine.state({ states: { Waiting, Cancelled, TimedOut } }) - const targets6 = Machine.targets(states) const machine = Machine.make({ timers: { source1: "1 second" }, root: states, @@ -422,7 +417,7 @@ describe("Machine.resume", () => { internalEvents: Machine.internalEventsFromSchemas(Timeout) }).handle({ initial: { - target: Machine.targets(states).root.Cancelled, + target: "Cancelled", decoded: true, data: new Cancelled({}) }, @@ -431,10 +426,10 @@ describe("Machine.resume", () => { invoke: { src: "source1", id: "timeout", - onDone: { target: targets6.root.TimedOut, decoded: true, data: () => (new TimedOut({})) } + onDone: { target: "TimedOut", decoded: true, data: () => (new TimedOut({})) } }, on: { - Cancel: { target: targets6.root.Cancelled, decoded: true, data: () => (new Cancelled({})) } + Cancel: { target: "Cancelled", decoded: true, data: () => (new Cancelled({})) } } }, Cancelled: {}, @@ -473,7 +468,6 @@ describe("Machine.resume", () => { } const runs = yield* Ref.make(0) const states = Machine.state({ states: { Loading, Loaded } }) - const targets7 = Machine.targets(states) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Ref.updateAndGet(runs, (n) => n + 1).pipe(Effect.as("fresh"))) }, root: states, @@ -481,7 +475,7 @@ describe("Machine.resume", () => { internalEvents: Machine.internalEventsFromSchemas(LoadedEvent) }).handle({ initial: { - target: Machine.targets(states).root.Loaded, + target: "Loaded", decoded: true, data: new Loaded({ value: "initial" }) }, @@ -491,7 +485,7 @@ describe("Machine.resume", () => { src: "source1", id: "load", onDone: { - target: targets7.root.Loaded, + target: "Loaded", decoded: true, data: ({ output }) => (new Loaded({ value: output })) } @@ -529,7 +523,6 @@ describe("Machine.resume", () => { } const runs = yield* Ref.make(0) const states = Machine.state({ states: { Loading, Failed } }) - const targets8 = Machine.targets(states) const machine = Machine.make({ effects: { source1: Effect.suspend(() => @@ -541,7 +534,7 @@ describe("Machine.resume", () => { internalEvents: Machine.internalEventsFromSchemas(FailedEvent) }).handle({ initial: { - target: Machine.targets(states).root.Failed, + target: "Failed", decoded: true, data: new Failed({ message: "initial" }) }, @@ -551,7 +544,7 @@ describe("Machine.resume", () => { src: "source1", id: "load", onFailure: { - target: targets8.root.Failed, + target: "Failed", decoded: true, data: ({ error }) => (new Failed({ message: error.message })) } @@ -593,13 +586,12 @@ describe("Machine.resume", () => { ChildDone: { schema: ChildDone, type: "final", output: Schema.Number } } }) - const targets9 = Machine.targets(childStates) const child = Machine.make({ root: childStates, events: Machine.eventsFromSchemas(ChildFinish) }).handle({ initial: { - target: Machine.targets(childStates).root.ChildIdle, + target: "ChildIdle", decoded: true, data: new ChildIdle({ value: 1 }) }, @@ -607,7 +599,7 @@ describe("Machine.resume", () => { ChildIdle: { on: { ChildFinish: { - target: targets9.root.ChildDone, + target: "ChildDone", decoded: true, data: ({ state }) => (new ChildDone({ value: state.value + 1 })) } @@ -618,14 +610,13 @@ describe("Machine.resume", () => { }) const Child = Machine.child("child", child) const states = Machine.state({ states: { Parent, ChildOutput } }) - const targets10 = Machine.targets(states) const machine = Machine.make({ children: { source1: Child }, root: states, events: Machine.eventsFromSchemas(ChildOutput) }).handle({ initial: { - target: Machine.targets(states).root.ChildOutput, + target: "ChildOutput", decoded: true, data: new ChildOutput({ value: 0 }) }, @@ -634,7 +625,7 @@ describe("Machine.resume", () => { invoke: { src: "source1", onDone: { - target: targets10.root.ChildOutput, + target: "ChildOutput", decoded: true, data: ({ output }) => (new ChildOutput({ value: output })) } @@ -712,7 +703,7 @@ describe("Machine.resume", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Root, + target: "Root", decoded: true, data: new Root({}) }, @@ -722,7 +713,7 @@ describe("Machine.resume", () => { states: { left: { initial: { - target: Machine.targets(states).root.Root.left.Leaf, + target: "Root.left.Leaf", decoded: true, data: new Leaf({ value: 1 }) }, @@ -732,7 +723,7 @@ describe("Machine.resume", () => { }, right: { initial: { - target: Machine.targets(states).root.Root.right.Leaf, + target: "Root.right.Leaf", decoded: true, data: new Leaf({ value: 2 }) }, @@ -781,13 +772,12 @@ describe("Machine.resume", () => { it.effect("obeys bounded encode/decode continuation equivalence", () => Effect.gen(function*() { const states = Machine.state({ states: { Count } }) - const targets11 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Add) }).handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, @@ -795,7 +785,7 @@ describe("Machine.resume", () => { Count: { on: { Add: { - target: targets11.root.Count, + target: "Count", decoded: true, data: ({ event, state }) => (new Count({ value: state.value + event.value })) } diff --git a/packages/effect-machine/test/machine/Root.test.ts b/packages/effect-machine/test/machine/Root.test.ts index 0221b3f..313ef14 100644 --- a/packages/effect-machine/test/machine/Root.test.ts +++ b/packages/effect-machine/test/machine/Root.test.ts @@ -3,14 +3,13 @@ import { describe, expect, it } from "vitest" import { Machine } from "../../src/index.js" const CounterRoot = Machine.state({ fields: { count: Schema.Number } }) const Events = Machine.events({ Increment: { by: Schema.Number } }) -const targets1 = Machine.targets(CounterRoot) const counter = Machine.make({ root: CounterRoot, events: Events }).handle({ root: () => ({ count: 0 }), on: { - Increment: { update: targets1.root, data: ({ root: current, event }) => ({ count: current.count + event.by }) } + Increment: { update: "root", data: ({ root: current, event }) => ({ count: current.count + event.by }) } } }) describe("root", () => { @@ -28,21 +27,20 @@ const EditorRoot = Machine.state({ states: { Editing: {}, Saving: {} } }) const EditorEvents = Machine.events({ Save: {}, Edit: {}, Increment: { by: Schema.Number } }) -const targets2 = Machine.targets(EditorRoot) const editor = Machine.make({ root: EditorRoot, events: EditorEvents }).handle({ initial: { - target: Machine.targets(EditorRoot).root.Editing + target: "Editing" }, root: () => ({ count: 0 }), on: { - Increment: { update: targets2.root, data: ({ root: current, event }) => ({ count: current.count + event.by }) } + Increment: { update: "root", data: ({ root: current, event }) => ({ count: current.count + event.by }) } }, states: { - Editing: { on: { Save: { target: targets2.root.Saving } } }, - Saving: { on: { Edit: { target: targets2.root.Editing } } } + Editing: { on: { Save: { target: "Saving" } } }, + Saving: { on: { Edit: { target: "Editing" } } } } }) it("retains root data while moving among children", async () => { @@ -76,7 +74,7 @@ it("defaults structural roots and allows an explicit starting configuration", as events: Machine.events({}) }).handle({ initial: { - target: Machine.targets(root).root.Editing + target: "Editing" }, states: { Editing: {}, @@ -88,7 +86,7 @@ it("defaults structural roots and allows an explicit starting configuration", as events: Machine.events({}) }).handle({ initial: { - target: Machine.targets(root).root.Saving + target: "Saving" }, states: { Editing: {}, @@ -110,17 +108,16 @@ it("declines guarded child transitions and tries the root handler", async () => const root = Machine.state({ fields: { count: Schema.Number }, states: { Idle: {}, Busy: {} } }) let constructed = 0 const events = Machine.events({ Go: { allowed: Schema.Boolean } }) - const targets3 = Machine.targets(root) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets3.root.Busy } } }, + branches: { transition1: { destination: { target: "Busy" } } }, root, events }).handle({ initial: { - target: Machine.targets(root).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), - on: { Go: { update: targets3.root, data: ({ root: current }) => ({ count: current.count + 1 }) } }, + on: { Go: { update: "root", data: ({ root: current }) => ({ count: current.count + 1 }) } }, states: { Idle: { on: { @@ -159,7 +156,7 @@ it("initializes required child values from root-owned data", async () => { events: Machine.events({}) }).handle({ initial: { - target: Machine.targets(root).root.Editing, + target: "Editing", data: ({ state }) => ({ draft: state.title }) }, root: () => ({ title: "Example" }), @@ -177,22 +174,21 @@ it("returns the completed workflow output through the root boundary", async () = Workflow: { states: { Working: {}, Finished: { type: "final", output: Schema.Number } } } } }) - const targets4 = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Finish: {} }) }).handle({ initial: { - target: Machine.targets(root).root.Workflow + target: "Workflow" }, root: () => ({ title: "Work" }), states: { Workflow: { initial: { - target: Machine.targets(root).root.Workflow.Working + target: "Workflow.Working" }, states: { - Working: { on: { Finish: { target: targets4.root.Workflow.Finished } } }, + Working: { on: { Finish: { target: "Workflow.Finished" } } }, Finished: { output: () => 42 } } } @@ -218,17 +214,17 @@ it("keeps completion inside an unfinished nested workflow", async () => { events: Machine.events({}) }).handle({ initial: { - target: Machine.targets(root).root.Outer + target: "Outer" }, states: { Outer: { initial: { - target: Machine.targets(root).root.Outer.Inner + target: "Outer.Inner" }, states: { Inner: { initial: { - target: Machine.targets(root).root.Outer.Inner.Finished + target: "Outer.Inner.Finished" }, states: { Finished: {} @@ -251,30 +247,29 @@ it("retains current root fields when restoring descendant history", async () => } }) const events = Machine.events({ Next: {}, Leave: {}, Return: {}, Increment: {} }) - const targets5 = Machine.targets(root) const machine = Machine.make({ - branches: { transition1: { destination: { history: targets5.root.Editing.recent } } }, + branches: { transition1: { destination: { history: "Editing.recent" } } }, root, events }).handle({ initial: { - target: Machine.targets(root).root.Editing + target: "Editing" }, root: () => ({ count: 0 }), - on: { Increment: { update: targets5.root, data: ({ root: current }) => ({ count: current.count + 1 }) } }, + on: { Increment: { update: "root", data: ({ root: current }) => ({ count: current.count + 1 }) } }, states: { Editing: { initial: { - target: Machine.targets(root).root.Editing.A + target: "Editing.A" }, - on: { Leave: { target: targets5.root.Away } }, + on: { Leave: { target: "Away" } }, history: { recent: { default: ({ target }) => target({ data: { count: 999 }, states: { Editing: { states: { A: {} } } } }) } }, states: { - A: { on: { Next: { target: targets5.root.Editing.B } } }, + A: { on: { Next: { target: "Editing.B" } } }, B: {} } }, @@ -290,16 +285,15 @@ it("retains current root fields when restoring descendant history", async () => }) it("checks a bare guard before selecting a default destination", async () => { const root = Machine.state({ states: { Idle: {}, Busy: {} } }) - const targets6 = Machine.targets(root) const machine = Machine.make({ root, events: Machine.events({ Start: { allowed: Schema.Boolean } }) }).handle({ initial: { - target: Machine.targets(root).root.Idle + target: "Idle" }, states: { - Idle: { on: { Start: { target: targets6.root.Busy, guard: ({ event }) => event.allowed } } }, + Idle: { on: { Start: { target: "Busy", guard: ({ event }) => event.allowed } } }, Busy: {} } }) diff --git a/packages/effect-machine/test/machine/RootInput.test.ts b/packages/effect-machine/test/machine/RootInput.test.ts index 4415782..ef2d0e1 100644 --- a/packages/effect-machine/test/machine/RootInput.test.ts +++ b/packages/effect-machine/test/machine/RootInput.test.ts @@ -8,22 +8,21 @@ it.effect("passes fresh input only through root initialization without retaining fields: { locale: Schema.String }, states: { Loading: { fields: { request: Schema.String } }, Idle: {} } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, input: Schema.Struct({ locale: Schema.String, request: Schema.String }), events: Machine.events({ Finish: {}, Reload: { request: Schema.String } }), - branches: { reload: { root: { target: targets.root } } } + branches: { reload: { root: { initialize: true } } } }).handle({ root: ({ input }) => ({ locale: input.locale }), - initial: { target: targets.root.Loading, data: ({ input }) => ({ request: input.request }) }, + initial: { target: "Loading", data: ({ input }) => ({ request: input.request }) }, on: { Reload: { branches: "reload", resolve: ({ event, select }) => select.root({ input: { locale: "it", request: event.request } }) } }, - states: { Loading: { on: { Finish: { target: targets.root.Idle } } } } + states: { Loading: { on: { Finish: { target: "Idle" } } } } }) const initial = yield* Machine.planInitial(machine, { locale: "en", request: "first" }) assert.deepStrictEqual(initial.state.value, { _tag: "", locale: "en" }) @@ -40,19 +39,18 @@ it.effect("restarts root lifecycle only with reenter and validates fresh input b fields: { count: Schema.Number }, states: { Loading: { fields: { id: Schema.String } }, Idle: {} } }) - const targets = Machine.targets(root) const machine = Machine.make({ root, input: Schema.Struct({ id: Schema.NonEmptyString, count: Schema.Number }), events: Machine.events({ Finish: {}, Reset: { id: Schema.String }, Restart: { id: Schema.String } }) }).handle({ root: ({ input }) => ({ count: input.count }), - initial: { target: targets.root.Loading, data: ({ input }) => ({ id: input.id }) }, + initial: { target: "Loading", data: ({ input }) => ({ id: input.id }) }, on: { - Reset: { target: targets.root, input: ({ event }) => ({ id: event.id, count: 2 }) }, - Restart: { target: targets.root, input: ({ event }) => ({ id: event.id, count: 3 }), reenter: true } + Reset: { initialize: ({ event }) => ({ id: event.id, count: 2 }) }, + Restart: { initialize: ({ event }) => ({ id: event.id, count: 3 }), reenter: true } }, - states: { Loading: { on: { Finish: { target: targets.root.Idle } } } } + states: { Loading: { on: { Finish: { target: "Idle" } } } } }) const initial = yield* Machine.planInitial(machine, { id: "one", count: 1 }) const idle = yield* Machine.plan(machine, initial.state, { _tag: "Finish" }) diff --git a/packages/effect-machine/test/machine/RuntimeDifferential.test.ts b/packages/effect-machine/test/machine/RuntimeDifferential.test.ts index 6ae9a1e..5d0e677 100644 --- a/packages/effect-machine/test/machine/RuntimeDifferential.test.ts +++ b/packages/effect-machine/test/machine/RuntimeDifferential.test.ts @@ -59,14 +59,13 @@ describe("pure planning and managed runtime differential", () => { Done: { schema: Done, type: "final", output: Schema.Number } } }) - const targets1 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Cascade, Ignore, Finish), internalEvents: Machine.internalEventsFromSchemas(Increment) }).handle({ initial: { - target: Machine.targets(states).root.Count, + target: "Count", decoded: true, data: new Count({ value: 0 }) }, @@ -81,12 +80,12 @@ describe("pure planning and managed runtime differential", () => { } }, Increment: { - target: targets1.root.Count, + target: "Count", decoded: true, data: ({ state }) => (new Count({ value: state.value + 1 })) }, Finish: { - target: targets1.root.Done, + target: "Done", decoded: true, data: ({ state }) => (new Done({ value: state.value })) } @@ -168,18 +167,17 @@ describe("pure planning and managed runtime differential", () => { readonly left: number readonly right: number }> = [] - const targets2 = Machine.targets(states) const machine = Machine.make({ branches: { - transition1: { destination: { target: targets2.root.Done } }, - transition2: { destination: { target: targets2.root.Running.Left } } + transition1: { destination: { target: "Done" } }, + transition2: { destination: { target: "Running.Left" } } }, root: states, events: Machine.eventsFromSchemas(Advance, Inspect, Finish), internalEvents: Machine.internalEventsFromSchemas(Bump) }).handle({ initial: { - target: Machine.targets(states).root.Running, + target: "Running", decoded: true, data: new Running({}) }, @@ -220,12 +218,12 @@ describe("pure planning and managed runtime differential", () => { Right: { on: { Advance: { - target: targets2.root.Running.Right, + target: "Running.Right", decoded: true, data: ({ state }) => (new Right({ value: state.value + 10 })) }, Bump: { - target: targets2.root.Running.Right, + target: "Running.Right", decoded: true, data: ({ state }) => (new Right({ value: state.value + 100 })) }, @@ -498,11 +496,10 @@ describe("pure planning and managed runtime differential", () => { Finished: { schema: Finished, type: "final", output: Schema.String } } }) - const targets3 = Machine.targets(states) const machine = Machine.make({ branches: { - transition1: { destination: { target: targets3.root.Working } }, - transition2: { destination: { target: targets3.root.Finished } } + transition1: { destination: { target: "Working" } }, + transition2: { destination: { target: "Finished" } } }, root: states, events: Machine.eventsFromSchemas(Begin), @@ -510,7 +507,7 @@ describe("pure planning and managed runtime differential", () => { emittedEvents: Machine.emittedEventsFromSchemas(Notice) }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -627,20 +624,19 @@ describe("pure planning and managed runtime differential", () => { class Go extends Schema.TaggedClass("DifferentialGo")("Go", {}) { } const states = Machine.state({ states: { Idle, Active } }) - const targets4 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Ignore, Go) }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, states: { Idle: { on: { - Go: { target: targets4.root.Active, decoded: true, data: () => (new Active({})) } + Go: { target: "Active", decoded: true, data: () => (new Active({})) } } }, Active: {} diff --git a/packages/effect-machine/test/machine/Scheduling.test.ts b/packages/effect-machine/test/machine/Scheduling.test.ts index 2ec1ea6..b9cb3ee 100644 --- a/packages/effect-machine/test/machine/Scheduling.test.ts +++ b/packages/effect-machine/test/machine/Scheduling.test.ts @@ -12,18 +12,17 @@ describe("machine scheduling", () => { it.effect("drains a large synchronous raised-event burst without growing the stack", () => Effect.gen(function*() { const states = Machine.state({ states: { SchedulingActive } }) - const targets1 = Machine.targets(states) const machine = Machine.make({ branches: { - transition1: { destination: { target: targets1.root.SchedulingActive } }, - transition2: { destination: { target: targets1.root.SchedulingActive } } + transition1: { destination: { target: "SchedulingActive" } }, + transition2: { destination: { target: "SchedulingActive" } } }, root: states, events: Machine.eventsFromSchemas(StartBurst), internalEvents: Machine.internalEventsFromSchemas(Burst) }).handle({ initial: { - target: Machine.targets(states).root.SchedulingActive, + target: "SchedulingActive", decoded: true, data: new SchedulingActive({ count: 0 }) }, diff --git a/packages/effect-machine/test/machine/SnapshotCodecAdversarial.test.ts b/packages/effect-machine/test/machine/SnapshotCodecAdversarial.test.ts index fb9b8df..208284a 100644 --- a/packages/effect-machine/test/machine/SnapshotCodecAdversarial.test.ts +++ b/packages/effect-machine/test/machine/SnapshotCodecAdversarial.test.ts @@ -53,7 +53,7 @@ const topologyMachine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(TopologyStates).root.Root, + target: "Root", decoded: true, data: new Root({ id: "root-1" }) }, @@ -72,7 +72,7 @@ const topologyMachine = Machine.make({ states: { left: { initial: { - target: Machine.targets(TopologyStates).root.Root.left.working, + target: "Root.left.working", decoded: true, data: new LeftWorking({ task: "left-1" }) }, @@ -83,7 +83,7 @@ const topologyMachine = Machine.make({ }, right: { initial: { - target: Machine.targets(TopologyStates).root.Root.right.working, + target: "Root.right.working", decoded: true, data: new RightWorking({ enabled: true }) }, @@ -180,20 +180,20 @@ const historyMachine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(HistoryStates).root.Outside, + target: "Outside", decoded: true, data: new Outside({}) }, states: { Workspace: { initial: { - target: Machine.targets(HistoryStates).root.Workspace.Editor, + target: "Workspace.Editor", data: { document: "initial" } }, states: { Editor: { initial: { - target: Machine.targets(HistoryStates).root.Workspace.Editor.editing, + target: "Workspace.Editor.editing", data: { contents: "", payload: undefined } }, states: { @@ -241,7 +241,7 @@ const richMachine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(RichStates).root.RichState, + target: "RichState", decoded: true, data: new RichState({ createdAt: new Date("2026-08-19T12:00:00.000Z"), sequence: 42n, missing: undefined }) }, @@ -264,7 +264,7 @@ const opaqueMachine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(OpaqueStates).root.OpaqueState, + target: "OpaqueState", decoded: true, data: { _tag: "CodecOpaqueState", resource: {} } }, @@ -284,7 +284,7 @@ const outputMachine = Machine.make({ events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(OutputStates).root.OutputDone, + target: "OutputDone", decoded: true, data: new OutputDone({}) }, @@ -459,40 +459,38 @@ describe("snapshot codec adversarial boundaries", () => { class After extends Schema.TaggedClass("CodecAutomaticAfter")("CodecAutomaticAfter", {}) { } const states = Machine.state({ states: { Before, Boundary, After } }) - const targets1 = Machine.targets(states) const original = Machine.make({ id: "codec-automatic-original", root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Before, + target: "Before", decoded: true, data: new Before({}) }, states: { Before: { - always: { target: targets1.root.Boundary, decoded: true, data: () => (new Boundary({})) } + always: { target: "Boundary", decoded: true, data: () => (new Boundary({})) } }, Boundary: {}, After: {} } }) - const targets2 = Machine.targets(states) const changed = Machine.make({ id: "codec-automatic-changed", root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Before, + target: "Before", decoded: true, data: new Before({}) }, states: { Before: {}, Boundary: { - always: { target: targets2.root.After, decoded: true, data: () => (new After({})) } + always: { target: "After", decoded: true, data: () => (new After({})) } }, After: {} } diff --git a/packages/effect-machine/test/machine/SnapshotContext.test.ts b/packages/effect-machine/test/machine/SnapshotContext.test.ts index bce97e2..69073ce 100644 --- a/packages/effect-machine/test/machine/SnapshotContext.test.ts +++ b/packages/effect-machine/test/machine/SnapshotContext.test.ts @@ -52,11 +52,10 @@ describe("Machine transition snapshot context", () => { it.effect("lets an effectful event handler inspect a sibling region", () => Effect.gen(function*() { let captured: Machine.Snapshot | undefined - const targets1 = Machine.targets(States) const machine = Machine.make({ branches: { transition1: { - online: { target: targets1.root.System.Playback.Playing, title: "Network is online" }, + online: { target: "System.Playback.Playing", title: "Network is online" }, unchanged: { none: true } } }, @@ -64,7 +63,7 @@ describe("Machine transition snapshot context", () => { events: Machine.eventsFromSchemas(BufferReady) }).handle({ initial: { - target: Machine.targets(States).root.System, + target: "System", decoded: true, data: new System({}) }, @@ -83,7 +82,7 @@ describe("Machine transition snapshot context", () => { states: { Playback: { initial: { - target: Machine.targets(States).root.System.Playback.Buffering, + target: "System.Playback.Buffering", decoded: true, data: new Buffering({}) }, @@ -106,7 +105,7 @@ describe("Machine transition snapshot context", () => { }, Network: { initial: { - target: Machine.targets(States).root.System.Network.Online, + target: "System.Network.Online", decoded: true, data: new Online({}) }, @@ -128,17 +127,16 @@ describe("Machine transition snapshot context", () => { it.effect("shares one beginning-of-microstep snapshot across parallel transitions", () => Effect.gen(function*() { const captured: Array> = [] - const targets2 = Machine.targets(States) const machine = Machine.make({ branches: { - transition1: { destination: { target: targets2.root.System.Playback.Playing } }, - transition2: { destination: { target: targets2.root.System.Network.Offline } } + transition1: { destination: { target: "System.Playback.Playing" } }, + transition2: { destination: { target: "System.Network.Offline" } } }, root: States, events: Machine.eventsFromSchemas(Disconnect) }).handle({ initial: { - target: Machine.targets(States).root.System, + target: "System", decoded: true, data: new System({}) }, @@ -157,7 +155,7 @@ describe("Machine transition snapshot context", () => { states: { Playback: { initial: { - target: Machine.targets(States).root.System.Playback.Buffering, + target: "System.Playback.Buffering", decoded: true, data: new Buffering({}) }, @@ -178,7 +176,7 @@ describe("Machine transition snapshot context", () => { }, Network: { initial: { - target: Machine.targets(States).root.System.Network.Online, + target: "System.Network.Online", decoded: true, data: new Online({}) }, @@ -213,11 +211,10 @@ describe("Machine transition snapshot context", () => { it.effect("captures the complete configuration for an eventless transition", () => Effect.gen(function*() { let captured: Machine.Snapshot | undefined - const targets3 = Machine.targets(States) const machine = Machine.make({ branches: { transition1: { - online: { target: targets3.root.System.Playback.Playing, title: "Network is online" }, + online: { target: "System.Playback.Playing", title: "Network is online" }, unchanged: { none: true } } }, @@ -225,7 +222,7 @@ describe("Machine transition snapshot context", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(States).root.System, + target: "System", decoded: true, data: new System({}) }, @@ -244,7 +241,7 @@ describe("Machine transition snapshot context", () => { states: { Playback: { initial: { - target: Machine.targets(States).root.System.Playback.Buffering, + target: "System.Playback.Buffering", decoded: true, data: new Buffering({}) }, @@ -265,7 +262,7 @@ describe("Machine transition snapshot context", () => { }, Network: { initial: { - target: Machine.targets(States).root.System.Network.Online, + target: "System.Network.Online", decoded: true, data: new Online({}) }, @@ -317,14 +314,13 @@ describe("Machine transition snapshot context", () => { } }) let captured: Machine.Snapshot | undefined - const targets4 = Machine.targets(completionStates) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets4.root.System.Work.Restarted } } }, + branches: { transition1: { destination: { target: "System.Work.Restarted" } } }, root: completionStates, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(completionStates).root.System, + target: "System", decoded: true, data: new System({}) }, @@ -336,7 +332,7 @@ describe("Machine transition snapshot context", () => { initial: { decoded: true, data: new Finished({}), - target: Machine.targets(completionStates).root.System.Work.Finished + target: "System.Work.Finished" }, onDone: { branches: "transition1", @@ -352,7 +348,7 @@ describe("Machine transition snapshot context", () => { }, Monitor: { initial: { - target: Machine.targets(completionStates).root.System.Monitor.Active, + target: "System.Monitor.Active", decoded: true, data: new Active({}) }, diff --git a/packages/effect-machine/test/machine/SnapshotStructure.test.ts b/packages/effect-machine/test/machine/SnapshotStructure.test.ts index c1c2dd5..45cacc2 100644 --- a/packages/effect-machine/test/machine/SnapshotStructure.test.ts +++ b/packages/effect-machine/test/machine/SnapshotStructure.test.ts @@ -17,7 +17,7 @@ it.effect("planning and encoding reject malformed snapshots through typed failur states: { Left: { initial: { - target: Machine.targets(InitialRoot1).root.Left.Ready + target: "Left.Ready" }, states: { Ready: {} diff --git a/packages/effect-machine/test/machine/StateDefinition.test.ts b/packages/effect-machine/test/machine/StateDefinition.test.ts index 9b35030..4a7e476 100644 --- a/packages/effect-machine/test/machine/StateDefinition.test.ts +++ b/packages/effect-machine/test/machine/StateDefinition.test.ts @@ -47,12 +47,12 @@ describe("exact state-definition runtime validation", () => { assert.isTrue(Object.isFrozen(machine.root.node.states.Root.states)) const compiled = machine.handle({ initial: { - target: Machine.targets(InitialRoot1).root.Root + target: "Root" }, states: { Root: { initial: { - target: Machine.targets(InitialRoot1).root.Root.Idle + target: "Root.Idle" }, states: { Idle: {}, @@ -128,13 +128,13 @@ describe("exact state-definition runtime validation", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle + target: "Idle" }, states: { Idle: {}, Flow: { initial: { - target: Machine.targets(states).root.Flow.Waiting + target: "Flow.Waiting" }, states: { Waiting: {}, @@ -170,7 +170,7 @@ describe("exact state-definition runtime validation", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Idle, + target: "Idle", decoded: true, data: new Idle({}) }, @@ -190,7 +190,7 @@ describe("exact state-definition runtime validation", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Opaque, + target: "Opaque", decoded: true, data: { _tag: "OpaqueState", value: 1 } }, diff --git a/packages/effect-machine/test/machine/StateUpdate.test.ts b/packages/effect-machine/test/machine/StateUpdate.test.ts index e100fa5..055291a 100644 --- a/packages/effect-machine/test/machine/StateUpdate.test.ts +++ b/packages/effect-machine/test/machine/StateUpdate.test.ts @@ -26,23 +26,22 @@ describe("state value updates", () => { readonly notice: string | null readonly request: string } | undefined - const targets1 = Machine.targets(states) const machine = Machine.make({ branches: { - transition1: { destination: { target: targets1.root.Ready.SavingPlan, update: targets1.root.Ready } }, - transition2: { destination: { target: targets1.root.Ready.SavingPlan, update: targets1.root.Ready } } + transition1: { destination: { target: "Ready.SavingPlan", update: "Ready" } }, + transition2: { destination: { target: "Ready.SavingPlan", update: "Ready" } } }, root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.Ready, + target: "Ready", data: { notice: "Previous notice" } }, states: { Ready: { initial: { - target: Machine.targets(states).root.Ready.Idle + target: "Ready.Idle" }, states: { Idle: { @@ -120,21 +119,20 @@ describe("state value updates", () => { } }) let idleSawDay: string | undefined - const targets2 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { target: targets2.root.Ready.Idle, update: targets2.root.Ready } } }, + branches: { transition1: { destination: { target: "Ready.Idle", update: "Ready" } } }, effects: { source1: Effect.suspend(() => Effect.succeed("Monday")) }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.Ready, + target: "Ready", data: { day: "Sunday", notice: "Saving" } }, states: { Ready: { initial: { - target: Machine.targets(states).root.Ready.Saving, + target: "Ready.Saving", data: { request: "change" } }, states: { @@ -200,31 +198,30 @@ describe("state value updates", () => { } } }) - const targets3 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.session, + target: "session", data: { count: 0 } }, states: { session: { initial: { - target: Machine.targets(states).root.session.editing, + target: "session.editing", data: { draft: "kept" } }, states: { editing: { initial: { - target: Machine.targets(states).root.session.editing.idle + target: "session.editing.idle" }, states: { idle: { on: { Increment: { - update: targets3.root.session, + update: "session", data: ({ ancestors: { session: current } }) => ({ count: current.count + 1 }) } } @@ -289,22 +286,21 @@ describe("state value updates", () => { } } }) - const targets4 = Machine.targets(states) const machine = Machine.make({ branches: { - transition1: { changed: { update: targets4.root.scope, title: "Value changed" }, unchanged: { none: true } } + transition1: { changed: { update: "scope", title: "Value changed" }, unchanged: { none: true } } }, root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.scope, + target: "scope", data: { count: 0 } }, states: { scope: { initial: { - target: Machine.targets(states).root.scope.idle + target: "scope.idle" }, states: { idle: { @@ -356,19 +352,18 @@ describe("state value updates", () => { } } }) - const targets5 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.scope, + target: "scope", data: { count: 0 } }, states: { scope: { initial: { - target: Machine.targets(states).root.scope.idle + target: "scope.idle" }, entry: () => { lifecycle.push("enter scope") @@ -390,11 +385,11 @@ describe("state value updates", () => { }, on: { Quiet: { - update: targets5.root.scope, + update: "scope", data: ({ ancestors: { scope: current } }) => ({ count: current.count + 1 }) }, Loud: { - update: targets5.root.scope, + update: "scope", reenter: true, data: ({ ancestors: { scope: current } }) => ({ count: current.count + 1 }) } @@ -426,20 +421,19 @@ describe("state value updates", () => { } } }) - const targets6 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { update: targets6.root.scope } } }, + branches: { transition1: { destination: { update: "scope" } } }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.scope, + target: "scope", data: { count: 0 } }, states: { scope: { initial: { - target: Machine.targets(states).root.scope.idle + target: "scope.idle" }, states: { idle: { @@ -467,7 +461,7 @@ describe("state value updates", () => { const Event = Schema.TaggedUnion({ Leave: {}, Return: {}, Update: {} }) const states = Machine.state({ states: { - root: { + main: { schema: State.cases.Root, states: { a: State.cases.A, @@ -481,26 +475,25 @@ describe("state value updates", () => { path: "" as const, value: undefined, state: { - path: "root" as const, + path: "main" as const, value: State.cases.Root.make({ count: 0 }), - state: { path: "root.a" as const, value: State.cases.A.make({}) } + state: { path: "main.a" as const, value: State.cases.A.make({}) } } }) - const targets7 = Machine.targets(states) const machine = Machine.make({ - branches: { transition3: { destination: { history: targets7.root.root.recent } } }, + branches: { transition3: { destination: { history: "main.recent" } } }, root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.root, + target: "main", decoded: true, data: State.cases.Root.make({ count: 0 }) }, states: { - root: { + main: { initial: { - target: Machine.targets(states).root.root.a, + target: "main.a", decoded: true, data: State.cases.A.make({}) }, @@ -508,10 +501,10 @@ describe("state value updates", () => { states: { a: { on: { - Leave: { target: targets7.root.outside }, + Leave: { target: "outside" }, Update: { - update: targets7.root.root, - data: ({ ancestors: { root: current } }) => ({ count: current.count + 1 }) + update: "main", + data: ({ ancestors: { main: current } }) => ({ count: current.count + 1 }) } } } @@ -530,11 +523,11 @@ describe("state value updates", () => { const historyBefore = restored.next.history const updated = yield* Machine.plan(machine, restored.next, Event.cases.Update.make({})) assert.deepStrictEqual(updated.next.history, historyBefore) - if (updated.next.state.path !== "root") { + if (updated.next.state.path !== "main") { throw new Error("expected restored root") } assert.strictEqual(updated.next.state.value.count, 1) - assert.strictEqual(updated.next.state.state.path, "root.a") + assert.strictEqual(updated.next.state.state.path, "main.a") })) it.effect("preserves completion outputs and does not replay completion", () => Effect.gen(function*() { @@ -548,7 +541,7 @@ describe("state value updates", () => { const Event = Schema.TaggedUnion({ Update: {} }) const states = Machine.state({ states: { - root: { + main: { schema: State.cases.Root, type: "parallel", states: { @@ -567,21 +560,20 @@ describe("state value updates", () => { } }) let completions = 0 - const targets8 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.root, + target: "main", data: { revision: 0 } }, states: { - root: { + main: { states: { left: { initial: { - target: Machine.targets(states).root.root.left.done + target: "main.left.done" }, onDone: { none: true, @@ -596,14 +588,14 @@ describe("state value updates", () => { }, right: { initial: { - target: Machine.targets(states).root.root.right.idle + target: "main.right.idle" }, states: { idle: { on: { Update: { - update: targets8.root.root, - data: ({ ancestors: { root: current } }) => ({ revision: current.revision + 1 }) + update: "main", + data: ({ ancestors: { main: current } }) => ({ revision: current.revision + 1 }) } } } @@ -633,25 +625,24 @@ describe("state value updates", () => { } } }) - const targets9 = Machine.targets(states) const machine = Machine.make({ id: "state-update-schema", root: states, events: Machine.eventsFromSchemas(Event) }).handle({ initial: { - target: Machine.targets(states).root.scope, + target: "scope", data: { count: 0 } }, states: { scope: { initial: { - target: Machine.targets(states).root.scope.idle + target: "scope.idle" }, states: { idle: { on: { - Break: { update: targets9.root.scope, data: () => ({ count: "bad" } as any) } + Break: { update: "scope", data: () => ({ count: "bad" } as any) } } } } @@ -676,27 +667,26 @@ describe("state value updates", () => { } }) let starts = 0 - const targets10 = Machine.targets(states) const machine = Machine.make({ effects: { source1: Effect.suspend(() => Effect.sync(() => ++starts)) }, root: states, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(states).root.scope, + target: "scope", data: { count: 0 } }, states: { scope: { initial: { - target: Machine.targets(states).root.scope.idle + target: "scope.idle" }, states: { idle: { invoke: { src: "source1", id: "load", - onDone: { update: targets10.root.scope, data: ({ output }) => ({ count: output }) } + onDone: { update: "scope", data: ({ output }) => ({ count: output }) } } } } @@ -726,21 +716,20 @@ describe("state value updates", () => { } } }) - const targets11 = Machine.targets(states) const machine = Machine.make({ - branches: { transition1: { destination: { update: targets11.root.scope } } }, + branches: { transition1: { destination: { update: "scope" } } }, root: states, events: Events, emittedEvents: Emissions }).handle({ initial: { - target: Machine.targets(states).root.scope, + target: "scope", data: { count: 0 } }, states: { scope: { initial: { - target: Machine.targets(states).root.scope.idle + target: "scope.idle" }, states: { idle: { diff --git a/packages/effect-machine/test/machine/StructuralStates.test.ts b/packages/effect-machine/test/machine/StructuralStates.test.ts index f7f6b43..ed51461 100644 --- a/packages/effect-machine/test/machine/StructuralStates.test.ts +++ b/packages/effect-machine/test/machine/StructuralStates.test.ts @@ -65,25 +65,24 @@ const States = Machine.state({ } }) const makeMachine = () => { - const targets1 = Machine.targets(States) return Machine.make({ branches: { - transition1: { destination: { target: targets1.root.player.transport.Loading } }, - transition2: { destination: { target: targets1.root.player.transport.Ready } }, - transition3: { destination: { target: targets1.root.player.transport.Ready.Playing } } + transition1: { destination: { target: "player.transport.Loading" } }, + transition2: { destination: { target: "player.transport.Ready" } }, + transition3: { destination: { target: "player.transport.Ready.Playing" } } }, root: States, events: Machine.eventsFromSchemas(SourceSelected, Loaded, Play, Mute) }).handle({ initial: { - target: Machine.targets(States).root.player + target: "player" }, states: { player: { states: { transport: { initial: { - target: Machine.targets(States).root.player.transport.Empty + target: "player.transport.Empty" }, states: { Empty: { @@ -110,7 +109,7 @@ const makeMachine = () => { }, Ready: { initial: { - target: Machine.targets(States).root.player.transport.Ready.Paused + target: "player.transport.Ready.Paused" }, states: { Paused: { @@ -127,7 +126,7 @@ const makeMachine = () => { Playing: { on: { Mute: { - target: targets1.root.player.settings.Muted, + target: "player.settings.Muted", data: ({ event }) => ({ volume: event.volume }) } } @@ -138,7 +137,7 @@ const makeMachine = () => { }, settings: { initial: { - target: Machine.targets(States).root.player.settings.Audible, + target: "player.settings.Audible", data: { volume: 1 } }, states: { @@ -181,41 +180,40 @@ const historyFallback = () => ({ } } }) -const targets2 = Machine.targets(HistoryStates) const historyMachine = Machine.make({ branches: { - transition1: { destination: { target: targets2.root.away } }, - transition2: { destination: { target: targets2.root.flow.section.Editing } }, - transition3: { destination: { history: targets2.root.flow.recent } }, - transition4: { destination: { history: targets2.root.flow.exact } } + transition1: { destination: { target: "away" } }, + transition2: { destination: { target: "flow.section.Editing" } }, + transition3: { destination: { history: "flow.recent" } }, + transition4: { destination: { history: "flow.exact" } } }, root: HistoryStates, events: Machine.eventsFromSchemas(Edit, Leave, ResumeShallow, ResumeDeep) }).handle({ initial: { - target: Machine.targets(HistoryStates).root.flow + target: "flow" }, states: { flow: { initial: { - target: Machine.targets(HistoryStates).root.flow.section + target: "flow.section" }, history: { recent: { default: historyFallback }, exact: { default: historyFallback } }, on: { - Leave: { target: targets2.root.away } + Leave: { target: "away" } }, states: { section: { initial: { - target: Machine.targets(HistoryStates).root.flow.section.Idle + target: "flow.section.Idle" }, states: { Idle: { on: { - Edit: { target: targets2.root.flow.section.Editing, data: ({ event }) => ({ draft: event.draft }) } + Edit: { target: "flow.section.Editing", data: ({ event }) => ({ draft: event.draft }) } } }, Editing: {} @@ -345,7 +343,7 @@ describe("structural active states", () => { events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(FinalStates).root.Done + target: "Done" }, states: { Done: { diff --git a/packages/effect-machine/test/machine/Targets.test.ts b/packages/effect-machine/test/machine/Targets.test.ts deleted file mode 100644 index 9297570..0000000 --- a/packages/effect-machine/test/machine/Targets.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { assert, describe, it } from "@effect/vitest" -import { Machine } from "../../src/index.js" - -describe("Machine.targets", () => { - it("preserves state names that also look like reference metadata", () => { - const root = Machine.state({ - states: { - root: { - states: { path: {}, from: {}, kind: {} } - } - } - }) - const targets = Machine.targets(root) - assert.deepStrictEqual(Object.keys(targets.root), ["root"]) - assert.deepStrictEqual(Object.keys(targets.root.root), ["path", "from", "kind"]) - assert.notStrictEqual(targets.root.root.path, targets.root.root.from) - assert.isTrue(Object.isFrozen(targets)) - assert.isTrue(Object.isFrozen(targets.root.root.path)) - assert.isFalse(Reflect.set(targets.root.root, "path", targets.root.root.kind)) - }) - - it("keeps reused subtrees independently addressable", () => { - const slot = Machine.state({ states: { Idle: {}, Done: {} } }) - const root = Machine.state({ states: { Left: slot, Right: slot } }) - const targets = Machine.targets(root) - assert.notStrictEqual(targets.root.Left, targets.root.Right) - assert.notStrictEqual(targets.root.Left.Idle, targets.root.Right.Idle) - }) -}) diff --git a/packages/effect-machine/test/machine/Totality.test.ts b/packages/effect-machine/test/machine/Totality.test.ts index a9c0ffb..d637377 100644 --- a/packages/effect-machine/test/machine/Totality.test.ts +++ b/packages/effect-machine/test/machine/Totality.test.ts @@ -230,20 +230,19 @@ describe("machine operation totality", () => { Done: { schema: Done, type: "final", output: Schema.NumberFromString } } }) - const targets1 = Machine.targets(states) const machine = Machine.make({ root: states, events: Machine.eventsFromSchemas(Finish) }).handle({ initial: { - target: Machine.targets(states).root.Value, + target: "Value", decoded: true, data: { _tag: "Value", amount: 42 } }, states: { Value: { on: { - Finish: { target: targets1.root.Done, decoded: true, data: () => ({ _tag: "Done" }) } + Finish: { target: "Done", decoded: true, data: () => ({ _tag: "Done" }) } } }, Done: { output: () => 42 } diff --git a/packages/effect-machine/test/machine/TransitionConstruction.test.ts b/packages/effect-machine/test/machine/TransitionConstruction.test.ts index 1f5364d..f985a1d 100644 --- a/packages/effect-machine/test/machine/TransitionConstruction.test.ts +++ b/packages/effect-machine/test/machine/TransitionConstruction.test.ts @@ -9,9 +9,8 @@ const events = Machine.events({ Change: { allowed: Schema.Boolean } }) const root1 = Machine.state({ schema: Root, states: { Idle: {}, Saved: { schema: Saved } } }) -const targets1 = Machine.targets(root1) const definition = Machine.make({ - branches: { rootUpdate: { updated: { update: targets1.root } } }, + branches: { rootUpdate: { updated: { update: "root" } } }, root: root1, events }) @@ -26,15 +25,15 @@ describe("transition construction", () => { > = [] const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), states: { Idle: { on: { Save: { - target: targets1.root.Saved, - update: targets1.root, + target: "Saved", + update: "root", data: ({ event }) => ({ target: { text: event.text }, update: { count: event.count } @@ -63,15 +62,15 @@ describe("transition construction", () => { const rootValue = new Root({ count: 2 }) const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), states: { Idle: { on: { Save: { - target: targets1.root.Saved, - update: targets1.root, + target: "Saved", + update: "root", decoded: true, data: () => ({ target: targetValue, update: rootValue }) } @@ -91,16 +90,16 @@ describe("transition construction", () => { Effect.gen(function*() { const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), states: { - Idle: { on: { Save: { target: targets1.root.Saved, data: ({ event }) => ({ text: event.text }) } } }, + Idle: { on: { Save: { target: "Saved", data: ({ event }) => ({ text: event.text }) } } }, Saved: { on: { Reset: { - target: targets1.root.Idle, - update: targets1.root, + target: "Idle", + update: "root", data: () => ({ target: undefined, update: { count: 5 } }) } } @@ -120,15 +119,15 @@ describe("transition construction", () => { let entered = false const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), states: { Idle: { on: { Save: { - target: targets1.root.Saved, - update: targets1.root, + target: "Saved", + update: "root", data: () => ({ target: { text: invalidOwner ? "valid" : 42 as unknown as string }, update: { count: invalidOwner ? "invalid" as unknown as number : 1 } @@ -158,17 +157,17 @@ describe("transition construction", () => { let constructed = 0 const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), - on: { Change: { update: targets1.root, data: ({ root: current }) => ({ count: current.count + 10 }) } }, + on: { Change: { update: "root", data: ({ root: current }) => ({ count: current.count + 10 }) } }, states: { Idle: { on: { Change: combined ? { - target: targets1.root.Saved, - update: targets1.root, + target: "Saved", + update: "root", guard: ({ root, event }) => root.count === 0 && event.allowed, data: () => { constructed++ @@ -207,14 +206,14 @@ describe("transition construction", () => { const lifecycle: Array = [] const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), entry: () => { lifecycle.push("root") }, states: { - Idle: { on: { Save: { target: targets1.root.Saved, data: ({ event }) => ({ text: event.text }) } } }, + Idle: { on: { Save: { target: "Saved", data: ({ event }) => ({ text: event.text }) } } }, Saved: { entry: () => { lifecycle.push("enter") @@ -224,8 +223,8 @@ describe("transition construction", () => { }, on: { Change: { - target: targets1.root.Saved, - update: targets1.root, + target: "Saved", + update: "root", reenter: true, guard: ({ event }) => event.allowed, data: ({ root: current, state }) => ({ @@ -262,7 +261,7 @@ describe("transition construction", () => { let entered = 0 const machine = definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), states: { @@ -289,7 +288,7 @@ describe("transition construction", () => { assert.throws(() => definition.handle({ initial: { - target: Machine.targets(root1).root.Idle + target: "Idle" }, root: () => ({ count: 0 }), states: { diff --git a/packages/effect-machine/test/machine/Visualization.test.ts b/packages/effect-machine/test/machine/Visualization.test.ts index 6ce078d..cafaec9 100644 --- a/packages/effect-machine/test/machine/Visualization.test.ts +++ b/packages/effect-machine/test/machine/Visualization.test.ts @@ -77,15 +77,14 @@ const initial = { const initialWorkflow = (): Machine.Machine.CompleteSnapshotContaining<{ readonly "": typeof States.node }, "application.workflow"> => initial -const targets1 = Machine.targets(States) const machineDefinition = Machine.make({ branches: { start: { - running: { target: targets1.root.application.workflow.running, update: targets1.root.application.workflow } + running: { target: "application.workflow.running", update: "application.workflow" } }, - unsafe: { disabled: { target: targets1.root.disabled } }, - transition1: { destination: { update: targets1.root.application.workflow } }, - transition2: { destination: { target: targets1.root.application.connection.offline } } + unsafe: { disabled: { target: "disabled" } }, + transition1: { destination: { update: "application.workflow" } }, + transition2: { destination: { target: "application.connection.offline" } } }, id: "inspection-example", root: States, @@ -95,7 +94,7 @@ const machineDefinition = Machine.make({ const makeMachine = (unsafeStart = false) => machineDefinition.handle({ initial: { - target: Machine.targets(States).root.application, + target: "application", decoded: true, data: new Application({}) }, @@ -108,7 +107,7 @@ const makeMachine = (unsafeStart = false) => states: { workflow: { initial: { - target: Machine.targets(States).root.application.workflow.idle, + target: "application.workflow.idle", decoded: true, data: new Idle({}) }, @@ -139,12 +138,12 @@ const makeMachine = (unsafeStart = false) => update: { data: new Workflow({}), decoded: true } }) }, - Refresh: { update: targets1.root.application.workflow, decoded: true, data: () => (new Workflow({})) } + Refresh: { update: "application.workflow", decoded: true, data: () => (new Workflow({})) } } }, running: { initial: { - target: Machine.targets(States).root.application.workflow.running.editing, + target: "application.workflow.running.editing", decoded: true, data: ({}) => new Editing({}) }, @@ -157,7 +156,7 @@ const makeMachine = (unsafeStart = false) => }, connection: { initial: { - target: Machine.targets(States).root.application.connection.online, + target: "application.connection.online", decoded: true, data: new Online({}) }, @@ -165,7 +164,7 @@ const makeMachine = (unsafeStart = false) => online: { on: { Disconnect: { - target: targets1.root.application.connection.offline, + target: "application.connection.offline", decoded: true, data: () => (new Offline({})) } @@ -197,11 +196,10 @@ const LifecycleStates = Machine.state({ disabled: Disabled } }) -const targets2 = Machine.targets(LifecycleStates) const lifecycleDefinition = Machine.make({ branches: { - transition1: { destination: { target: targets2.root.workflow } }, - transition2: { destination: { target: targets2.root.disabled } } + transition1: { destination: { target: "workflow" } }, + transition2: { destination: { target: "disabled" } } }, id: "lifecycle-inspection", root: LifecycleStates, @@ -210,7 +208,7 @@ const lifecycleDefinition = Machine.make({ const makeLifecycleMachine = (unsafe: "always" | "done" | undefined = undefined) => lifecycleDefinition.handle({ initial: { - target: Machine.targets(LifecycleStates).root.idle, + target: "idle", decoded: true, data: new Idle({}) }, @@ -232,7 +230,7 @@ const makeLifecycleMachine = (unsafe: "always" | "done" | undefined = undefined) }, workflow: { initial: { - target: Machine.targets(LifecycleStates).root.workflow.complete + target: "workflow.complete" }, onDone: { branches: "transition2", @@ -262,7 +260,7 @@ describe("Machine structural visualization", () => { const root = Machine.state({ states: { Idle: { fields: { count: Schema.Number } } } }) const inspectOnly = Machine.make({ root, events: Machine.eventsFromSchemas() }).handle({ initial: { - target: Machine.targets(root).root.Idle, + target: "Idle", data: () => { throw new Error("initial constructor unexpectedly executed during inspection") } @@ -348,7 +346,7 @@ describe("Machine structural visualization", () => { events: Machine.eventsFromSchemas(Refresh) }).handle({ initial: { - target: Machine.targets(root3).root.idle, + target: "idle", decoded: true, data: new Idle({}) }, diff --git a/packages/effect-machine/test/testing/Coverage.test.ts b/packages/effect-machine/test/testing/Coverage.test.ts index a38d2e9..6018eb6 100644 --- a/packages/effect-machine/test/testing/Coverage.test.ts +++ b/packages/effect-machine/test/testing/Coverage.test.ts @@ -14,14 +14,13 @@ class Add extends Schema.TaggedClass("Add")("Add", { }) {} class Finish extends Schema.TaggedClass("Finish")("Finish", {}) {} const CounterStates = Machine.state({ states: { count: Count, done: Done } }) -const targets1 = Machine.targets(CounterStates) const counterMachine = Machine.make({ - branches: { transition1: { destination: { target: targets1.root.count } } }, + branches: { transition1: { destination: { target: "count" } } }, root: CounterStates, events: Machine.eventsFromSchemas(Add, Finish) }).handle({ initial: { - target: Machine.targets(CounterStates).root.count, + target: "count", decoded: true, data: new Count({ value: 0 }) }, @@ -35,7 +34,7 @@ const counterMachine = Machine.make({ target({ data: new Count({ value: state.value + event.amount }), decoded: true }), declinable: true }, - Finish: { target: targets1.root.done, decoded: true, data: () => (new Done({})) } + Finish: { target: "done", decoded: true, data: () => (new Done({})) } } }, done: {} @@ -56,7 +55,7 @@ const opaqueMachine = Machine.make({ input: Schema.Any }).handle({ initial: { - target: Machine.targets(OpaqueStates).root.opaque, + target: "opaque", decoded: true, data: ({ root: { input: payload } }) => new Opaque({ payload }) }, @@ -66,16 +65,15 @@ const opaqueMachine = Machine.make({ } }) const StartupStates = Machine.state({ states: { count: Count } }) -const targets2 = Machine.targets(StartupStates) const startupMachine = Machine.make({ branches: { - transition1: { zero: { target: targets2.root.count, title: "Count is zero" }, unchanged: { none: true } } + transition1: { zero: { target: "count", title: "Count is zero" }, unchanged: { none: true } } }, root: StartupStates, events: Machine.eventsFromSchemas(Add) }).handle({ initial: { - target: Machine.targets(StartupStates).root.count, + target: "count", decoded: true, data: new Count({ value: 0 }) }, @@ -90,7 +88,7 @@ const startupMachine = Machine.make({ }, on: { Add: { - target: targets2.root.count, + target: "count", decoded: true, data: ({ event, state }) => (new Count({ value: state.value + event.amount })) } @@ -107,7 +105,7 @@ const branchMachine = Machine.make({ events: Machine.eventsFromSchemas(Select) }).handle({ initial: { - target: Machine.targets(StartupStates).root.count, + target: "count", decoded: true, data: new Count({ value: 0 }) }, @@ -139,7 +137,7 @@ const finiteEventMachine = Machine.make({ events: Machine.eventsFromSchemas(TickEvent, ChoiceEvent) }).handle({ initial: { - target: Machine.targets(EventStates).root.count, + target: "count", decoded: true, data: new Count({ value: 0 }) }, @@ -158,7 +156,7 @@ const openEventMachine = Machine.make({ events: Machine.eventsFromSchemas(OpenEvent) }).handle({ initial: { - target: Machine.targets(EventStates).root.count, + target: "count", decoded: true, data: new Count({ value: 0 }) }, diff --git a/packages/effect-machine/test/testing/Exploration.test.ts b/packages/effect-machine/test/testing/Exploration.test.ts index e4e49f4..6e7514e 100644 --- a/packages/effect-machine/test/testing/Exploration.test.ts +++ b/packages/effect-machine/test/testing/Exploration.test.ts @@ -13,14 +13,13 @@ class Select extends Schema.TaggedClass