@typeonce/effect-machine 0.31.1 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +145 -140
  2. package/dist/Machine.d.ts +428 -254
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +91 -111
  5. package/dist/Machine.js.map +1 -1
  6. package/dist/internal/machine/atom.d.ts +3 -4
  7. package/dist/internal/machine/atom.d.ts.map +1 -1
  8. package/dist/internal/machine/atom.js +0 -2
  9. package/dist/internal/machine/atom.js.map +1 -1
  10. package/dist/internal/machine/childRegistry.d.ts +52 -0
  11. package/dist/internal/machine/childRegistry.d.ts.map +1 -0
  12. package/dist/internal/machine/childRegistry.js +74 -0
  13. package/dist/internal/machine/childRegistry.js.map +1 -0
  14. package/dist/internal/machine/cluster.d.ts +2 -3
  15. package/dist/internal/machine/cluster.d.ts.map +1 -1
  16. package/dist/internal/machine/cluster.js.map +1 -1
  17. package/dist/internal/machine/configuration.d.ts.map +1 -1
  18. package/dist/internal/machine/configuration.js +14 -4
  19. package/dist/internal/machine/configuration.js.map +1 -1
  20. package/dist/internal/machine/executionPlan.d.ts +1 -0
  21. package/dist/internal/machine/executionPlan.d.ts.map +1 -1
  22. package/dist/internal/machine/executionPlan.js +97 -53
  23. package/dist/internal/machine/executionPlan.js.map +1 -1
  24. package/dist/internal/machine/invocation.d.ts.map +1 -1
  25. package/dist/internal/machine/invocation.js +4 -2
  26. package/dist/internal/machine/invocation.js.map +1 -1
  27. package/dist/internal/machine/invocationDefinition.d.ts +35 -0
  28. package/dist/internal/machine/invocationDefinition.d.ts.map +1 -0
  29. package/dist/internal/machine/invocationDefinition.js +21 -0
  30. package/dist/internal/machine/invocationDefinition.js.map +1 -0
  31. package/dist/internal/machine/invocationEvent.d.ts +0 -2
  32. package/dist/internal/machine/invocationEvent.d.ts.map +1 -1
  33. package/dist/internal/machine/invocationEvent.js +0 -8
  34. package/dist/internal/machine/invocationEvent.js.map +1 -1
  35. package/dist/internal/machine/machine.d.ts +21 -43
  36. package/dist/internal/machine/machine.d.ts.map +1 -1
  37. package/dist/internal/machine/machine.js +98 -374
  38. package/dist/internal/machine/machine.js.map +1 -1
  39. package/dist/internal/machine/planner.d.ts +13 -19
  40. package/dist/internal/machine/planner.d.ts.map +1 -1
  41. package/dist/internal/machine/planner.js +71 -39
  42. package/dist/internal/machine/planner.js.map +1 -1
  43. package/dist/internal/machine/process.d.ts +6 -8
  44. package/dist/internal/machine/process.d.ts.map +1 -1
  45. package/dist/internal/machine/process.js +1 -0
  46. package/dist/internal/machine/process.js.map +1 -1
  47. package/dist/internal/machine/protocol.d.ts +2 -2
  48. package/dist/internal/machine/protocol.d.ts.map +1 -1
  49. package/dist/internal/machine/protocol.js +4 -18
  50. package/dist/internal/machine/protocol.js.map +1 -1
  51. package/dist/internal/machine/readiness.d.ts +1 -1
  52. package/dist/internal/machine/readiness.d.ts.map +1 -1
  53. package/dist/internal/machine/requirements.d.ts +4 -0
  54. package/dist/internal/machine/requirements.d.ts.map +1 -0
  55. package/dist/internal/machine/requirements.js +2 -0
  56. package/dist/internal/machine/requirements.js.map +1 -0
  57. package/dist/internal/machine/runtime.d.ts +4 -58
  58. package/dist/internal/machine/runtime.d.ts.map +1 -1
  59. package/dist/internal/machine/runtime.js +1 -69
  60. package/dist/internal/machine/runtime.js.map +1 -1
  61. package/dist/internal/machine/serialization.d.ts.map +1 -1
  62. package/dist/internal/machine/serialization.js +16 -0
  63. package/dist/internal/machine/serialization.js.map +1 -1
  64. package/dist/internal/machine/stateDefinition.d.ts +3 -1
  65. package/dist/internal/machine/stateDefinition.d.ts.map +1 -1
  66. package/dist/internal/machine/stateDefinition.js +36 -2
  67. package/dist/internal/machine/stateDefinition.js.map +1 -1
  68. package/dist/internal/machine/targetBuilder.d.ts +16 -0
  69. package/dist/internal/machine/targetBuilder.d.ts.map +1 -0
  70. package/dist/internal/machine/targetBuilder.js +333 -0
  71. package/dist/internal/machine/targetBuilder.js.map +1 -0
  72. package/dist/internal/machine/topology.js +3 -3
  73. package/dist/internal/machine/topology.js.map +1 -1
  74. package/dist/internal/machine/transition.d.ts +16 -0
  75. package/dist/internal/machine/transition.d.ts.map +1 -0
  76. package/dist/internal/machine/transition.js +2 -0
  77. package/dist/internal/machine/transition.js.map +1 -0
  78. package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
  79. package/dist/internal/testing/machine/finiteModel.js +10 -12
  80. package/dist/internal/testing/machine/finiteModel.js.map +1 -1
  81. package/dist/internal/testing/machine/format.d.ts +7 -0
  82. package/dist/internal/testing/machine/format.d.ts.map +1 -0
  83. package/dist/internal/testing/machine/format.js +104 -0
  84. package/dist/internal/testing/machine/format.js.map +1 -0
  85. package/dist/internal/testing/machine/probe.d.ts +1 -1
  86. package/dist/internal/testing/machine/probe.d.ts.map +1 -1
  87. package/dist/internal/testing/machine/probe.js +1 -1
  88. package/dist/internal/testing/machine/probe.js.map +1 -1
  89. package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -1
  90. package/dist/internal/testing/machine/referenceModel.js +15 -19
  91. package/dist/internal/testing/machine/referenceModel.js.map +1 -1
  92. package/dist/internal/testing/machine/trace.d.ts +1 -1
  93. package/dist/internal/testing/machine/trace.d.ts.map +1 -1
  94. package/dist/internal/testing/machine/trace.js +3 -3
  95. package/dist/internal/testing/machine/trace.js.map +1 -1
  96. package/dist/internal/testing/machine/value.d.ts +8 -0
  97. package/dist/internal/testing/machine/value.d.ts.map +1 -0
  98. package/dist/internal/testing/machine/value.js +82 -0
  99. package/dist/internal/testing/machine/value.js.map +1 -0
  100. package/dist/internal/testing/machine/verification.d.ts +2 -13
  101. package/dist/internal/testing/machine/verification.d.ts.map +1 -1
  102. package/dist/internal/testing/machine/verification.js +21 -113
  103. package/dist/internal/testing/machine/verification.js.map +1 -1
  104. package/dist/testing/MachineTest.d.ts +89 -104
  105. package/dist/testing/MachineTest.d.ts.map +1 -1
  106. package/dist/testing/MachineTest.js +70 -84
  107. package/dist/testing/MachineTest.js.map +1 -1
  108. package/dist/unstable/cluster/ClusterMachine.d.ts +10 -13
  109. package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -1
  110. package/dist/unstable/cluster/ClusterMachine.js +5 -8
  111. package/dist/unstable/cluster/ClusterMachine.js.map +1 -1
  112. package/dist/unstable/reactivity/AtomMachine.d.ts +26 -61
  113. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
  114. package/dist/unstable/reactivity/AtomMachine.js +17 -26
  115. package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
  116. package/docs/agent-guide.md +45 -45
  117. package/docs/effect-atom-react.md +35 -63
  118. package/docs/machine-review.md +7 -7
  119. package/docs/root-api.md +214 -0
  120. package/package.json +1 -1
  121. package/src/Machine.ts +778 -437
  122. package/src/internal/machine/atom.ts +3 -13
  123. package/src/internal/machine/childRegistry.ts +141 -0
  124. package/src/internal/machine/cluster.ts +5 -14
  125. package/src/internal/machine/configuration.ts +20 -4
  126. package/src/internal/machine/executionPlan.ts +109 -52
  127. package/src/internal/machine/invocation.ts +10 -6
  128. package/src/internal/machine/invocationDefinition.ts +52 -0
  129. package/src/internal/machine/invocationEvent.ts +0 -8
  130. package/src/internal/machine/machine.ts +154 -679
  131. package/src/internal/machine/planner.ts +82 -66
  132. package/src/internal/machine/process.ts +14 -21
  133. package/src/internal/machine/protocol.ts +9 -32
  134. package/src/internal/machine/readiness.ts +1 -0
  135. package/src/internal/machine/requirements.ts +11 -0
  136. package/src/internal/machine/runtime.ts +17 -186
  137. package/src/internal/machine/serialization.ts +22 -0
  138. package/src/internal/machine/stateDefinition.ts +36 -3
  139. package/src/internal/machine/targetBuilder.ts +525 -0
  140. package/src/internal/machine/topology.ts +3 -3
  141. package/src/internal/machine/transition.ts +26 -0
  142. package/src/internal/testing/machine/finiteModel.ts +22 -23
  143. package/src/internal/testing/machine/format.ts +120 -0
  144. package/src/internal/testing/machine/probe.ts +4 -4
  145. package/src/internal/testing/machine/referenceModel.ts +25 -17
  146. package/src/internal/testing/machine/trace.ts +4 -4
  147. package/src/internal/testing/machine/value.ts +77 -0
  148. package/src/internal/testing/machine/verification.ts +904 -1109
  149. package/src/testing/MachineTest.ts +103 -114
  150. package/src/unstable/cluster/ClusterMachine.ts +10 -20
  151. package/src/unstable/reactivity/AtomMachine.ts +42 -79
@@ -3,15 +3,18 @@ import * as Inspectable from "effect/Inspectable";
3
3
  import * as Option from "effect/Option";
4
4
  import { Prototype as PipeablePrototype } from "effect/Pipeable";
5
5
  import { hasProperty } from "effect/Predicate";
6
+ import * as Schema from "effect/Schema";
6
7
  import * as Activities from "./activities.js";
7
8
  import * as Configuration from "./configuration.js";
9
+ import * as InvocationDefinition from "./invocationDefinition.js";
8
10
  import * as internalPlanner from "./planner.js";
9
11
  import * as internalProcess from "./process.js";
10
12
  import * as Protocol from "./protocol.js";
11
13
  import * as internalRuntime from "./runtime.js";
12
14
  import * as Serialization from "./serialization.js";
13
15
  import * as StateDefinition from "./stateDefinition.js";
14
- import { ChildMachineLogicTypeId, SnapshotBuilderStateTypeId } from "./symbols.js";
16
+ import { ChildMachineLogicTypeId } from "./symbols.js";
17
+ import { getLocalTargetScope, getTargetBuilderNode, makeSnapshotBuilder, makeTargetBuilder, withFrom } from "./targetBuilder.js";
15
18
  import * as Topology from "./topology.js";
16
19
  export { ChildAlreadyExistsError, InfiniteTransitionError, MachineSchemaDecodeError, MachineSchemaEncodeError, ProcessLocalError, StartupError, StoppedError } from "./errors.js";
17
20
  export { ChildMachineLogicTypeId, InitialEventTypeId, SnapshotBuilderStateTypeId } from "./symbols.js";
@@ -34,6 +37,7 @@ const Proto = {
34
37
  const makeWithHandlers = (self, handlers) => {
35
38
  const machine = Object.create(Proto);
36
39
  machine.states = self.states;
40
+ machine.root = self.root;
37
41
  machine.events = self.events;
38
42
  machine.internalEvents = self.internalEvents;
39
43
  machine.emittedEvents = self.emittedEvents;
@@ -71,10 +75,22 @@ const makeDirectTransitionDescriptor = (selection, resolve, options) => {
71
75
  };
72
76
  return resolve === undefined
73
77
  ? Object.freeze(shared)
74
- : Object.freeze({ ...shared, resolve });
78
+ : Object.freeze({ ...shared, resolver: resolve });
79
+ };
80
+ const guardedSelection = (selection, predicate) => {
81
+ const wrap = (resolve, options) => makeDirectTransitionDescriptor(selection, (context, enqueue) => predicate(context) ? resolve(context, enqueue) : Topology.makeDeclined(), { ...transitionOptions(options), declinable: true });
82
+ return Object.freeze({
83
+ ...wrap((context) => (selection.kind === "none" ? Topology.makeNoTarget() : constructSelectedTarget(context.target))),
84
+ from: (value) => wrap((context) => context.target.from(value(context))),
85
+ decoded: (value) => wrap((context) => context.target.decoded(value(context))),
86
+ resolve: wrap
87
+ });
75
88
  };
76
89
  const decorateTransitionSelection = (selection) => Object.freeze({
77
90
  ...selection,
91
+ guard: (predicate) => guardedSelection(selection, predicate),
92
+ from: (value) => makeDirectTransitionDescriptor(selection, (context) => context.target.from(value(context)), undefined),
93
+ decoded: (value) => makeDirectTransitionDescriptor(selection, (context) => context.target.decoded(value(context)), undefined),
78
94
  resolve: (resolve, options) => makeDirectTransitionDescriptor(selection, resolve, options),
79
95
  reenter: () => makeDirectTransitionDescriptor(selection, undefined, { reenter: true }),
80
96
  updating: (owner) => {
@@ -89,11 +105,12 @@ const decorateTransitionSelection = (selection) => Object.freeze({
89
105
  return decorateTransitionSelection(Topology.makeTargetSelection(selection.kind, selection.path, selection.scope, ownerSelection.path));
90
106
  }
91
107
  });
92
- const decorateStateUpdateSelection = (selection) => {
93
- const update = (resolve, options) => makeDirectTransitionDescriptor(selection, resolve, options);
94
- Object.assign(update, selection);
95
- return Object.freeze(update);
96
- };
108
+ const decorateStateUpdateSelection = (selection) => Object.freeze({
109
+ ...selection,
110
+ from: (value) => makeDirectTransitionDescriptor(selection, (context) => context.owner.from(value(context)), undefined),
111
+ decoded: (value) => makeDirectTransitionDescriptor(selection, (context) => context.owner.decoded(value(context)), undefined),
112
+ resolve: (resolve, options) => makeDirectTransitionDescriptor(selection, resolve, options)
113
+ });
97
114
  const noneTransitionSelection = decorateTransitionSelection(Topology.noneTargetSelection);
98
115
  const makeInitialBuilderDescriptor = (selection, resolve) => Object.freeze({
99
116
  [InitialBuilderDescriptorTypeId]: InitialBuilderDescriptorTypeId,
@@ -102,6 +119,8 @@ const makeInitialBuilderDescriptor = (selection, resolve) => Object.freeze({
102
119
  });
103
120
  const decorateInitialSelection = (selection) => Object.freeze({
104
121
  ...selection,
122
+ from: (value) => makeInitialBuilderDescriptor(selection, (context) => context.target.from(value(context))),
123
+ decoded: (value) => makeInitialBuilderDescriptor(selection, (context) => context.target.decoded(value(context))),
105
124
  resolve: (resolve) => makeInitialBuilderDescriptor(selection, resolve)
106
125
  });
107
126
  const decorateInitialSelectorNode = (node) => {
@@ -125,6 +144,12 @@ const decorateInitialSelectorNode = (node) => {
125
144
  };
126
145
  const decorateTransitionSelectorNode = (node) => {
127
146
  if (Topology.isTargetSelection(node)) {
147
+ if (node.kind === "state" && node.scope === "full" && hasProperty(node, "initial")) {
148
+ return Object.freeze({
149
+ ...decorateTransitionSelection(node),
150
+ initial: decorateTransitionSelection(node.initial)
151
+ });
152
+ }
128
153
  if (node.kind === "update")
129
154
  return decorateStateUpdateSelection(node);
130
155
  return node === Topology.noneTargetSelection ? noneTransitionSelection : decorateTransitionSelection(node);
@@ -179,7 +204,7 @@ const normalizeTransitionBuilder = (transition, stateNodes, path) => {
179
204
  }
180
205
  return {
181
206
  target: () => descriptor.selection,
182
- resolve: descriptor.resolve,
207
+ resolve: descriptor.resolver,
183
208
  reenter: descriptor.reenter,
184
209
  declinable: descriptor.declinable
185
210
  };
@@ -215,7 +240,7 @@ const makeSelectionNode = (stateNodes, path, scope, source) => {
215
240
  addSelectionChildren(method, stateNodes, path, scope, source);
216
241
  }
217
242
  if (scope === "branch" && source !== undefined && node.schema !== undefined &&
218
- (source === path || source.startsWith(`${path}.`)) &&
243
+ (source === path || Configuration.isDescendantOf(source, path)) &&
219
244
  getTargetBuilderNode(stateNodes, source).type !== "choice") {
220
245
  Object.defineProperty(method, "update", {
221
246
  value: makeStateUpdateSelection(path, "branch"),
@@ -223,6 +248,9 @@ const makeSelectionNode = (stateNodes, path, scope, source) => {
223
248
  });
224
249
  }
225
250
  }
251
+ if (node.type === "atomic" && scope === "branch" && source === path && node.schema !== undefined) {
252
+ Object.defineProperty(method, "update", { value: makeStateUpdateSelection(path, "branch"), enumerable: true });
253
+ }
226
254
  return method;
227
255
  };
228
256
  const makeHistorySelectionTree = (stateNodes, parent) => {
@@ -242,15 +270,12 @@ const makeHistorySelectionTree = (stateNodes, parent) => {
242
270
  return builder;
243
271
  };
244
272
  const makeTargetSelector = (stateNodes, source) => {
245
- const full = {};
246
- for (const node of stateNodes.byPath.values()) {
247
- if (node.parent === undefined && node.type !== "history" && node.type !== "choice") {
248
- full[node.key] = makeSelectionNode(stateNodes, node.path, "full");
249
- }
250
- }
273
+ const full = Object.assign({}, makeSelectionValue("state", "", "full"), {
274
+ initial: makeSelectionValue("initial", "", "full")
275
+ });
251
276
  const branch = {};
252
- const root = getTargetBuilderNode(stateNodes, source.split(".")[0]);
253
- branch[root.key] = makeSelectionNode(stateNodes, root.path, "branch", source);
277
+ const root = getTargetBuilderNode(stateNodes, stateNodes.roots[0]);
278
+ addSelectionChildren(branch, stateNodes, root.path, "branch", source);
254
279
  const local = {};
255
280
  const localScope = getLocalTargetScope(stateNodes, source);
256
281
  if (localScope !== undefined) {
@@ -265,10 +290,15 @@ const makeTargetSelector = (stateNodes, source) => {
265
290
  }
266
291
  return {
267
292
  none: Topology.noneTargetSelection,
293
+ self: getTargetBuilderNode(stateNodes, source).schema === undefined ||
294
+ getTargetBuilderNode(stateNodes, source).type === "final"
295
+ ? {}
296
+ : { update: makeStateUpdateSelection(source, "branch") },
297
+ root: makeSelectionNode(stateNodes, root.path, "branch", source),
268
298
  local,
269
299
  branch,
270
300
  full,
271
- history: makeHistorySelectionTree(stateNodes, undefined)
301
+ history: makeHistorySelectionTree(stateNodes, "")
272
302
  };
273
303
  };
274
304
  const captureDefinitionBranch = (branch, selector, stateNodes, path, trigger) => {
@@ -327,6 +357,8 @@ const getSelectionBuilder = (target, selection, stateNodes, source) => {
327
357
  let parts = selection.path.split(".");
328
358
  if (selection.kind === "history") {
329
359
  builder = target.history;
360
+ if (selection.path !== "")
361
+ parts.unshift("");
330
362
  }
331
363
  else if (selection.scope === "local") {
332
364
  builder = target.local;
@@ -337,12 +369,14 @@ const getSelectionBuilder = (target, selection, stateNodes, source) => {
337
369
  parts = [];
338
370
  }
339
371
  else {
340
- parts = selection.path.slice(scope.length + 1).split(".");
372
+ parts = (scope === "" ? selection.path : selection.path.slice(scope.length + 1)).split(".");
341
373
  }
342
374
  }
343
375
  }
344
376
  else if (selection.scope === "branch") {
345
377
  builder = target.branch;
378
+ if (selection.path !== "")
379
+ parts.unshift("");
346
380
  }
347
381
  else {
348
382
  builder = target.full;
@@ -390,7 +424,7 @@ const validateResolvedSelection = (result, selection, stateNodes) => {
390
424
  const acceptsDescendant = (selection.scope === "local" || selection.scope === "branch") &&
391
425
  (selectedNode?.type === "compound" || selectedNode?.type === "parallel");
392
426
  if (resultPath === undefined ||
393
- (resultPath !== selection.path && !(acceptsDescendant && resultPath.startsWith(`${selection.path}.`)))) {
427
+ (resultPath !== selection.path && !(acceptsDescendant && Configuration.isDescendantOf(resultPath, selection.path)))) {
394
428
  throw new Error(`Machine transition resolver selected "${selection.path}" but constructed "${resultPath ?? "<invalid>"}"`);
395
429
  }
396
430
  };
@@ -654,10 +688,10 @@ const captureInvokeDefinition = (invoke, stateNodes, path) => {
654
688
  captured[key] = captureTransition(captured[key], stateNodes, path, key);
655
689
  }
656
690
  }
657
- return captured;
691
+ return InvocationDefinition.capture(captured, path);
658
692
  });
659
693
  if (Array.isArray(authored))
660
- return capturedDefinitions;
694
+ return Object.freeze(capturedDefinitions);
661
695
  return capturedDefinitions[0];
662
696
  };
663
697
  const flattenHandlers = (handlers, stateNodes, states, prefix, config) => {
@@ -671,6 +705,12 @@ const flattenHandlers = (handlers, stateNodes, states, prefix, config) => {
671
705
  throw new Error(`Machine expected state "${path}" handler to be an object`);
672
706
  }
673
707
  const { states: childConfig, ...stateConfig } = nodeConfig;
708
+ if (typeof stateConfig.history === "object" && stateConfig.history !== null) {
709
+ stateConfig.history = Object.freeze(Object.fromEntries(Object.entries(stateConfig.history).map(([key, entry]) => [
710
+ key,
711
+ typeof entry === "object" && entry !== null ? Object.freeze({ ...entry }) : entry
712
+ ])));
713
+ }
674
714
  const on = stateConfig.on;
675
715
  if (typeof on === "object" && on !== null) {
676
716
  const capturedOn = captureEventHandlers(on, stateNodes, path);
@@ -712,340 +752,11 @@ const flattenHandlers = (handlers, stateNodes, states, prefix, config) => {
712
752
  };
713
753
  const makeHandle = (self) => ((config) => {
714
754
  const handlers = Object.create(null);
715
- flattenHandlers(handlers, self.stateNodes, self.states, "", config);
755
+ flattenHandlers(handlers, self.stateNodes, self.states, "", { "": config });
716
756
  return makeWithHandlers(self, handlers);
717
757
  });
718
758
  export const isMachine = (u) => hasProperty(u, TypeId) && u[TypeId] === TypeId;
719
759
  export const isFinal = (machine, state) => internalPlanner.isFinal(machine, state);
720
- const withFrom = (method, kind, valued) => {
721
- const builder = {};
722
- if (valued) {
723
- Object.defineProperty(builder, "decoded", {
724
- value: method,
725
- enumerable: false
726
- });
727
- }
728
- Object.defineProperty(builder, "from", {
729
- value: (...args) => {
730
- if (!valued) {
731
- return method(undefined, ...args);
732
- }
733
- const omitted = args.length === 0 || (kind === "nested" && args.length === 1 && typeof args[0] === "function");
734
- const input = omitted ? {} : args[0];
735
- const rest = omitted ? args : args.slice(1);
736
- return method(Topology.makeStateInput(input), ...rest);
737
- },
738
- enumerable: false
739
- });
740
- return builder;
741
- };
742
- const withInitial = (builder, path, valued, values) => {
743
- const initial = withFrom((value) => Topology.makeInitialTarget(path, value, values), "leaf", valued);
744
- Object.defineProperty(builder, "initial", {
745
- value: initial,
746
- enumerable: false
747
- });
748
- return builder;
749
- };
750
- const makeSnapshotBuilder = (states, options) => {
751
- const builder = {};
752
- for (const key of Object.keys(states)) {
753
- const definition = states[key];
754
- const pseudoType = definition.type;
755
- if (pseudoType === "history") {
756
- continue;
757
- }
758
- const path = options.prefix === "" ? key : `${options.prefix}.${key}`;
759
- if (pseudoType === "choice") {
760
- builder[key] = () => Topology.makeChoiceTarget(path, getParentPathRuntime(path));
761
- continue;
762
- }
763
- const node = Topology.getStateNodeDefinition(path, definition);
764
- const method = withFrom((value, selector) => makeSnapshotForNode(definition, key, value, selector, options), node.states === undefined ? "leaf" : "nested", node.schema !== undefined);
765
- builder[key] = node.states === undefined || options.mode !== "full" || options.prefix !== ""
766
- ? method
767
- : withInitial(method, path, node.schema !== undefined);
768
- }
769
- return builder;
770
- };
771
- const makeParallelSnapshotBuilder = (states, options, regions) => {
772
- const builder = {};
773
- Object.defineProperty(builder, SnapshotBuilderStateTypeId, {
774
- value: regions,
775
- enumerable: false
776
- });
777
- for (const key of Object.keys(states)) {
778
- const definition = states[key];
779
- const pseudoType = definition.type;
780
- if (pseudoType === "history" || pseudoType === "choice") {
781
- continue;
782
- }
783
- if (hasProperty(regions, key)) {
784
- continue;
785
- }
786
- const path = options.prefix === "" ? key : `${options.prefix}.${key}`;
787
- const node = Topology.getStateNodeDefinition(path, definition);
788
- const method = withFrom((value, selector) => {
789
- const nextRegions = {};
790
- for (const regionKey of Object.keys(regions)) {
791
- nextRegions[regionKey] = regions[regionKey];
792
- }
793
- nextRegions[key] = makeSnapshotForNode(definition, key, value, selector, options);
794
- return makeParallelSnapshotBuilder(states, options, nextRegions);
795
- }, node.states === undefined ? "leaf" : "nested", node.schema !== undefined);
796
- builder[key] = method;
797
- }
798
- return builder;
799
- };
800
- const getParallelSnapshotBuilderRegions = (path, states, builder) => {
801
- if (typeof builder !== "object" || builder === null || !hasProperty(builder, SnapshotBuilderStateTypeId)) {
802
- throw new Error(`Machine expected parallel state "${path}" builder callback to return a builder`);
803
- }
804
- const regions = builder[SnapshotBuilderStateTypeId];
805
- for (const key of Object.keys(states)) {
806
- const pseudoType = states[key].type;
807
- if (pseudoType === "history" || pseudoType === "choice") {
808
- continue;
809
- }
810
- if (!hasProperty(regions, key)) {
811
- throw new Error(`Machine expected parallel state "${path}" builder callback to provide region "${key}"`);
812
- }
813
- }
814
- return regions;
815
- };
816
- const makeSnapshotForNode = (definition, key, value, selector, options) => {
817
- const path = options.prefix === "" ? key : `${options.prefix}.${key}`;
818
- const node = Topology.getStateNodeDefinition(path, definition);
819
- const snapshot = {
820
- path,
821
- value
822
- };
823
- if (node.states === undefined) {
824
- return snapshot;
825
- }
826
- if (selector === undefined) {
827
- throw new Error(`Machine expected state "${path}" builder to provide active child states`);
828
- }
829
- if (node.type === "parallel") {
830
- const builder = makeParallelSnapshotBuilder(node.states, { ...options, prefix: path }, {});
831
- const selected = selector(builder);
832
- snapshot.states = getParallelSnapshotBuilderRegions(path, node.states, selected);
833
- return snapshot;
834
- }
835
- const childStates = options.mode === "initial" && node.initial !== undefined
836
- ? { [node.initial]: node.states[node.initial] }
837
- : node.states;
838
- const selected = selector(makeSnapshotBuilder(childStates, { ...options, prefix: path }));
839
- snapshot.state = selected;
840
- return snapshot;
841
- };
842
- const getTargetBuilderNode = (stateNodes, path) => {
843
- const node = stateNodes.byPath.get(path);
844
- if (node === undefined) {
845
- throw new Error(`Machine expected state path "${path}" to exist`);
846
- }
847
- return node;
848
- };
849
- const getLocalTargetScope = (stateNodes, source) => {
850
- let current = source;
851
- while (current !== undefined) {
852
- const node = stateNodes.byPath.get(current);
853
- if (node === undefined) {
854
- return undefined;
855
- }
856
- if (node.type === "compound") {
857
- return node.path;
858
- }
859
- current = node.parent;
860
- }
861
- return undefined;
862
- };
863
- const hasTargetValues = (values) => values !== undefined && Object.keys(values).length > 0;
864
- const makeTargetWithValues = (path, value, values) => hasTargetValues(values)
865
- ? Topology.makeTarget(path, value, { values: values })
866
- : Topology.makeTarget(path, value);
867
- const getTargetBuilderDefinition = (states, targetPath) => {
868
- let children = states;
869
- let path = "";
870
- let definition;
871
- for (const key of targetPath.split(".")) {
872
- if (!hasProperty(children, key)) {
873
- throw new Error(`Machine expected state path "${targetPath}" to exist`);
874
- }
875
- definition = children[key];
876
- path = path === "" ? key : `${path}.${key}`;
877
- const node = Topology.getStateNodeDefinition(path, definition);
878
- children = node.states ?? {};
879
- }
880
- return definition;
881
- };
882
- const makeParallelTarget = (states, node, value, selector, values) => {
883
- if (selector === undefined) {
884
- throw new Error(`Machine expected parallel target "${node.path}" builder to provide every active region`);
885
- }
886
- const snapshot = makeSnapshotForNode(getTargetBuilderDefinition(states, node.path), node.key, value, selector, { mode: "full", prefix: node.parent ?? "" });
887
- return Topology.makeTarget(node.path, value, {
888
- snapshot: snapshot,
889
- values: values
890
- });
891
- };
892
- const extendTargetValues = (values, path, value) => {
893
- const next = {};
894
- if (values !== undefined) {
895
- for (const key of Object.keys(values)) {
896
- next[key] = values[key];
897
- }
898
- }
899
- next[path] = value;
900
- return next;
901
- };
902
- const makeLocalTargetChildBuilder = (states, stateNodes, parentPath, values, source) => {
903
- const parent = getTargetBuilderNode(stateNodes, parentPath);
904
- const builder = {};
905
- for (const childPath of Array.from(stateNodes.byPath.values())
906
- .filter((node) => node.parent === parent.path && node.type !== "history")
907
- .map((node) => node.path)) {
908
- const child = getTargetBuilderNode(stateNodes, childPath);
909
- if (child.type === "choice") {
910
- builder[child.key] = () => Topology.makeChoiceTarget(child.path, parent.path, values);
911
- continue;
912
- }
913
- const method = withFrom((value, selector) => {
914
- if (child.type === "atomic" || child.type === "final") {
915
- return makeTargetWithValues(child.path, value, values);
916
- }
917
- if (child.type === "parallel") {
918
- if (source !== child.path && !source.startsWith(`${child.path}.`)) {
919
- return makeParallelTarget(states, child, value, selector, values);
920
- }
921
- if (selector === undefined) {
922
- throw new Error(`Machine expected target "${child.path}" builder to provide an active child state`);
923
- }
924
- return selector(makeLocalTargetChildBuilder(states, stateNodes, child.path, child.schema === undefined ? values : extendTargetValues(values, child.path, value), source));
925
- }
926
- if (selector === undefined) {
927
- throw new Error(`Machine expected target "${child.path}" builder to provide an active child state`);
928
- }
929
- return selector(makeLocalTargetChildBuilder(states, stateNodes, child.path, child.schema === undefined ? values : extendTargetValues(values, child.path, value), source));
930
- }, child.type === "atomic" || child.type === "final" ? "leaf" : "nested", child.schema !== undefined);
931
- builder[child.key] = child.type === "atomic" || child.type === "final"
932
- ? method
933
- : withInitial(method, child.path, child.schema !== undefined, values);
934
- }
935
- return builder;
936
- };
937
- const makeLocalTargetBuilder = (states, stateNodes, source) => {
938
- const scope = getLocalTargetScope(stateNodes, source);
939
- if (scope === undefined) {
940
- return {};
941
- }
942
- const builder = makeLocalTargetChildBuilder(states, stateNodes, scope, undefined, source);
943
- const scopeNode = getTargetBuilderNode(stateNodes, scope);
944
- if (scopeNode.schema !== undefined) {
945
- builder.with = withFrom((value, selector) => {
946
- if (selector === undefined) {
947
- throw new Error(`Machine expected target "${scope}" builder to provide an active child state`);
948
- }
949
- return selector(makeLocalTargetChildBuilder(states, stateNodes, scope, { [scope]: value }, source));
950
- }, "nested", true);
951
- }
952
- return builder;
953
- };
954
- const addBranchTargetChildren = (builder, states, stateNodes, parentPath, values, source) => {
955
- const parent = getTargetBuilderNode(stateNodes, parentPath);
956
- for (const childPath of Array.from(stateNodes.byPath.values())
957
- .filter((node) => node.parent === parent.path && node.type !== "history")
958
- .map((node) => node.path)) {
959
- const child = getTargetBuilderNode(stateNodes, childPath);
960
- if (child.type === "choice") {
961
- builder[child.key] = () => Topology.makeChoiceTarget(child.path, parent.path, values);
962
- continue;
963
- }
964
- builder[child.key] = makeBranchTargetNodeBuilder(states, stateNodes, child.path, values, source);
965
- }
966
- };
967
- const makeBranchTargetNodeBuilder = (states, stateNodes, path, values, source) => {
968
- const node = getTargetBuilderNode(stateNodes, path);
969
- if (node.type === "atomic" || node.type === "final") {
970
- return withFrom((value) => makeTargetWithValues(node.path, value, values), "leaf", node.schema !== undefined);
971
- }
972
- const builder = withFrom((value, selector) => {
973
- if (node.type === "parallel") {
974
- if (source !== node.path && !source.startsWith(`${node.path}.`)) {
975
- return makeParallelTarget(states, node, value, selector, values);
976
- }
977
- if (selector === undefined) {
978
- throw new Error(`Machine expected target "${node.path}" builder to provide an active child state`);
979
- }
980
- const nextBuilder = {};
981
- addBranchTargetChildren(nextBuilder, states, stateNodes, node.path, node.schema === undefined ? values : extendTargetValues(values, node.path, value), source);
982
- return selector(nextBuilder);
983
- }
984
- if (selector === undefined) {
985
- throw new Error(`Machine expected target "${node.path}" builder to provide an active child state`);
986
- }
987
- const nextBuilder = {};
988
- addBranchTargetChildren(nextBuilder, states, stateNodes, node.path, node.schema === undefined ? values : extendTargetValues(values, node.path, value), source);
989
- return selector(nextBuilder);
990
- }, "nested", node.schema !== undefined);
991
- withInitial(builder, node.path, node.schema !== undefined, values);
992
- if (node.type !== "parallel" || source === node.path || source.startsWith(`${node.path}.`)) {
993
- addBranchTargetChildren(builder, states, stateNodes, node.path, values, source);
994
- }
995
- return builder;
996
- };
997
- const makeBranchTargetBuilder = (states, stateNodes, source) => {
998
- const rootPath = source.split(".")[0];
999
- const root = getTargetBuilderNode(stateNodes, rootPath);
1000
- return {
1001
- [root.key]: makeBranchTargetNodeBuilder(states, stateNodes, root.path, undefined, source)
1002
- };
1003
- };
1004
- const makeHistoryTargetBuilder = (states, prefix) => {
1005
- const builder = {};
1006
- for (const key of Object.keys(states)) {
1007
- const path = prefix === "" ? key : `${prefix}.${key}`;
1008
- const definition = Topology.getStateNodeDefinition(path, states[key]);
1009
- if (definition.type === "history") {
1010
- const parent = getParentPathRuntime(path);
1011
- builder[key] = () => Topology.makeHistoryTarget(path, parent);
1012
- continue;
1013
- }
1014
- if (definition.states !== undefined) {
1015
- builder[key] = makeHistoryTargetBuilder(definition.states, path);
1016
- }
1017
- }
1018
- return builder;
1019
- };
1020
- const getParentPathRuntime = (path) => {
1021
- const separator = path.lastIndexOf(".");
1022
- if (separator < 0) {
1023
- throw new Error(`Machine expected history state "${path}" to have an active parent`);
1024
- }
1025
- return path.slice(0, separator);
1026
- };
1027
- const makeTargetBuilder = (states, stateNodes) => {
1028
- const full = makeSnapshotBuilder(states, { mode: "full", prefix: "" });
1029
- const history = makeHistoryTargetBuilder(states, "");
1030
- return (source) => ({
1031
- none: Topology.makeNoTarget,
1032
- local: makeLocalTargetBuilder(states, stateNodes, source),
1033
- branch: makeBranchTargetBuilder(states, stateNodes, source),
1034
- full,
1035
- history
1036
- });
1037
- };
1038
- const makeInitialSelector = (stateNodes) => {
1039
- const selector = {};
1040
- for (const node of stateNodes.byPath.values()) {
1041
- if (node.parent === undefined && node.type !== "history" && node.type !== "choice") {
1042
- selector[node.key] = node.type === "atomic" || node.type === "final"
1043
- ? makeSelectionMethod("state", node.path, "initial")
1044
- : Object.freeze({ initial: makeSelectionValue("initial", node.path, "initial") });
1045
- }
1046
- }
1047
- return Object.freeze(selector);
1048
- };
1049
760
  const getInitialSelectionBuilder = (initialBuilder, selection) => {
1050
761
  const path = selection.path;
1051
762
  if (path === undefined || path.includes(".")) {
@@ -1057,11 +768,12 @@ const getInitialSelectionBuilder = (initialBuilder, selection) => {
1057
768
  }
1058
769
  return builder;
1059
770
  };
1060
- const captureInitialBranch = (definition, stateNodes, initialBuilder) => {
1061
- if (typeof definition !== "function") {
771
+ const captureInitialBranch = (definition, initialBuilder, configuration) => {
772
+ if (definition !== undefined && typeof definition !== "function") {
1062
773
  throw new Error("Machine initial definition must be a target-first callback");
1063
774
  }
1064
- const result = definition(decorateInitialSelectorNode(makeInitialSelector(stateNodes)));
775
+ const selector = decorateInitialSelection(makeSelectionValue(configuration ? "state" : "initial", "", "initial"));
776
+ const result = definition === undefined ? selector : definition(selector);
1065
777
  let selection;
1066
778
  let resolve;
1067
779
  if (Topology.isTargetSelection(result)) {
@@ -1092,9 +804,12 @@ const validateInitialSelection = (result, selection) => {
1092
804
  throw new Error(`Machine initial resolver selected "${selection.path}" but constructed "${resultPath}"`);
1093
805
  }
1094
806
  };
1095
- const compileInitial = (definition, states, stateNodes) => {
1096
- const initialBuilder = makeSnapshotBuilder(states, { mode: "initial", prefix: "" });
1097
- const branch = captureInitialBranch(definition, stateNodes, initialBuilder);
807
+ const compileInitial = (definition, states, stateNodes, configuration = false) => {
808
+ const rootNode = getTargetBuilderNode(stateNodes, "");
809
+ const initialBuilder = configuration ?
810
+ makeSnapshotBuilder(states, { mode: "full", prefix: "" })
811
+ : { "": withFrom((value) => Topology.makeInitialTarget("", value), "leaf", rootNode.schema !== undefined) };
812
+ const branch = captureInitialBranch(definition, initialBuilder, configuration);
1098
813
  return {
1099
814
  initial: (input) => {
1100
815
  const result = branch.resolve === undefined
@@ -1109,15 +824,13 @@ const compileInitial = (definition, states, stateNodes) => {
1109
824
  })
1110
825
  };
1111
826
  };
1112
- export const state = ((node) => {
1113
- StateDefinition.validateStateDefinitions({ state: node }, "Machine.state");
1114
- return StateDefinition.captureStateDefinitions({ state: node }).state;
1115
- });
1116
- export const states = ((states) => {
1117
- StateDefinition.validateStateDefinitions(states, "Machine.states");
1118
- const captured = StateDefinition.captureStateDefinitions(states);
827
+ export const state = (node) => {
828
+ const captured = StateDefinition.captureRoot(node);
829
+ const access = makeStateHelpers();
830
+ return Object.freeze({ ...access, "~effect/Machine/State": "~effect/Machine/State", node: captured });
831
+ };
832
+ const makeStateHelpers = () => {
1119
833
  return {
1120
- states: captured,
1121
834
  path: ((path) => path),
1122
835
  get: ((snapshot, path) => Topology.getSnapshotByPath(snapshot, path).pipe(Option.map((snapshot) => snapshot.value))),
1123
836
  getWithParents: ((snapshot, path) => {
@@ -1127,31 +840,42 @@ export const states = ((states) => {
1127
840
  getSnapshot: Topology.getSnapshotByPath,
1128
841
  matches: ((snapshot, path) => Option.isSome(Topology.getSnapshotByPath(snapshot, path)))
1129
842
  };
1130
- });
1131
- export const make = ((config) => {
1132
- StateDefinition.validateStateDefinitions(config.states, "Machine.make");
843
+ };
844
+ export const make = (config) => {
845
+ const states = Object.freeze({ "": config.root.node });
1133
846
  const self = Object.create(Proto);
1134
- self.states = config.states;
847
+ self.states = states;
848
+ self.root = config.root;
1135
849
  self.events = config.events;
1136
850
  self.internalEvents = config.internalEvents ?? Protocol.makeEventProtocol("internal", []);
1137
851
  self.emittedEvents = config.emittedEvents ?? Protocol.makeEventProtocol("emitted", []);
1138
852
  self.parent = config.parent;
1139
853
  self.input = config.input;
1140
854
  self.id = config.id;
1141
- self.stateNodes = Topology.compileStateNodes(config.states);
1142
- const compiledInitial = compileInitial(config.initial, config.states, self.stateNodes);
855
+ self.stateNodes = Topology.compileStateNodes(states);
856
+ const compiledInitial = compileInitial(config.initialConfiguration ?? config.initial, states, self.stateNodes, config.initialConfiguration !== undefined);
1143
857
  self.initial = compiledInitial.initial;
1144
858
  self.initialDefinition = compiledInitial.definition;
1145
- self.makeTargetBuilder = makeTargetBuilder(config.states, self.stateNodes);
859
+ self.makeTargetBuilder = makeTargetBuilder(states, self.stateNodes);
1146
860
  self.handlers = Object.create(null);
1147
861
  self.handle = makeHandle(self);
1148
862
  Protocol.setProtocol(self);
1149
863
  return self;
1150
- });
864
+ };
1151
865
  const flattenEventProtocolInputs = (kind, inputs) => inputs.flatMap((input) => Protocol.isEventProtocol(input, kind)
1152
866
  ? Protocol.eventProtocolSchemas(input)
1153
867
  : [input]);
1154
868
  export const events = (...inputs) => Protocol.makeEventProtocol("public", flattenEventProtocolInputs("public", inputs));
869
+ const eventFieldSchemas = (cases) => {
870
+ for (const [tag, fields] of Object.entries(cases)) {
871
+ if (Object.hasOwn(fields, "_tag"))
872
+ throw new Error(`Machine event "${tag}" fields cannot declare _tag`);
873
+ }
874
+ return Object.keys(cases).length === 0 ? [] : [Schema.TaggedUnion(cases)];
875
+ };
876
+ export const eventsFromFields = (cases) => Protocol.makeEventProtocol("public", eventFieldSchemas(cases));
877
+ export const internalEventsFromFields = (cases) => Protocol.makeEventProtocol("internal", eventFieldSchemas(cases));
878
+ export const emittedEventsFromFields = (cases) => Protocol.makeEventProtocol("emitted", eventFieldSchemas(cases));
1155
879
  const makeParent = (mode, events) => {
1156
880
  if (!Protocol.isEventProtocol(events, "public")) {
1157
881
  throw new Error("Machine parent declarations require a protocol created with Machine.events");