@doeixd/machine 0.0.4 → 0.0.6

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.
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @file Runtime statechart extraction utilities
3
+ * @description Extract statecharts from running machine instances using Symbol-based metadata
4
+ */
5
+
6
+ import { RUNTIME_META, type RuntimeTransitionMeta } from './primitives';
7
+
8
+ /**
9
+ * Extract metadata from a single function if it has runtime metadata attached
10
+ *
11
+ * @param fn - Function to extract from
12
+ * @returns Metadata object or null if no metadata
13
+ */
14
+ export function extractFunctionMetadata(fn: any): RuntimeTransitionMeta | null {
15
+ if (typeof fn !== 'function') {
16
+ return null;
17
+ }
18
+
19
+ const meta = fn[RUNTIME_META];
20
+ return meta || null;
21
+ }
22
+
23
+ /**
24
+ * Extract state node from a machine class instance
25
+ *
26
+ * @param stateInstance - Instance of a machine state class
27
+ * @returns State node with transitions
28
+ */
29
+ export function extractStateNode(stateInstance: any): any {
30
+ const stateNode: any = { on: {} };
31
+ const invoke: any[] = [];
32
+
33
+ // Iterate over all properties
34
+ for (const key in stateInstance) {
35
+ const value = stateInstance[key];
36
+
37
+ if (typeof value !== 'function') {
38
+ continue;
39
+ }
40
+
41
+ const meta = extractFunctionMetadata(value);
42
+ if (!meta) {
43
+ continue;
44
+ }
45
+
46
+ // Separate invoke from transitions
47
+ if (meta.invoke) {
48
+ invoke.push({
49
+ src: meta.invoke.src,
50
+ onDone: { target: meta.invoke.onDone },
51
+ onError: { target: meta.invoke.onError },
52
+ description: meta.invoke.description
53
+ });
54
+ }
55
+
56
+ // If has target, it's a transition
57
+ if (meta.target) {
58
+ const transition: any = { target: meta.target };
59
+
60
+ if (meta.description) {
61
+ transition.description = meta.description;
62
+ }
63
+
64
+ if (meta.guards && meta.guards.length > 0) {
65
+ transition.cond = meta.guards.map(g => g.name).join(' && ');
66
+ }
67
+
68
+ if (meta.actions && meta.actions.length > 0) {
69
+ transition.actions = meta.actions.map(a => a.name);
70
+ }
71
+
72
+ stateNode.on[key] = transition;
73
+ }
74
+ }
75
+
76
+ if (invoke.length > 0) {
77
+ stateNode.invoke = invoke;
78
+ }
79
+
80
+ return stateNode;
81
+ }
82
+
83
+ /**
84
+ * Generate a complete statechart from multiple state class instances
85
+ *
86
+ * @param states - Object mapping state names to state instances
87
+ * @param config - Chart configuration
88
+ * @returns XState-compatible statechart JSON
89
+ *
90
+ * @example
91
+ * const chart = generateStatechart({
92
+ * 'LoggedOut': new LoggedOutMachine(),
93
+ * 'LoggedIn': new LoggedInMachine()
94
+ * }, {
95
+ * id: 'auth',
96
+ * initial: 'LoggedOut'
97
+ * });
98
+ */
99
+ export function generateStatechart(
100
+ states: Record<string, any>,
101
+ config: { id: string; initial: string; description?: string }
102
+ ): any {
103
+ const chart: any = {
104
+ id: config.id,
105
+ initial: config.initial,
106
+ states: {}
107
+ };
108
+
109
+ if (config.description) {
110
+ chart.description = config.description;
111
+ }
112
+
113
+ for (const [stateName, stateInstance] of Object.entries(states)) {
114
+ chart.states[stateName] = extractStateNode(stateInstance);
115
+ }
116
+
117
+ return chart;
118
+ }
119
+
120
+ /**
121
+ * Convenience function to extract statechart from a single machine instance
122
+ * Useful for simple machines with a single context but multiple transitions
123
+ *
124
+ * @param machineInstance - Machine instance
125
+ * @param config - Chart configuration
126
+ * @returns XState-compatible statechart JSON
127
+ */
128
+ export function extractFromInstance(
129
+ machineInstance: any,
130
+ config: { id: string; stateName?: string }
131
+ ): any {
132
+ const stateName = config.stateName || machineInstance.constructor.name || 'State';
133
+
134
+ return {
135
+ id: config.id,
136
+ initial: stateName,
137
+ states: {
138
+ [stateName]: extractStateNode(machineInstance)
139
+ }
140
+ };
141
+ }
package/src/solid.ts CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  type Accessor,
23
23
  type Setter
24
24
  } from 'solid-js';
25
- import { createStore, type SetStoreFunction, type Store, produce } from 'solid-js/store';
25
+ import { createStore, type SetStoreFunction, type Store } from 'solid-js/store';
26
26
  import { Machine, AsyncMachine, Event, Context, runMachine as runMachineCore } from './index';
27
27
 
28
28
  // =============================================================================
@@ -86,12 +86,12 @@ export function createMachine<M extends Machine<any>>(
86
86
  const { context, ...transitions } = machine();
87
87
 
88
88
  const handlers = Object.fromEntries(
89
- Object.entries(transitions).map(([key, fn]) => [
89
+ Object.entries(transitions).map(([key]) => [
90
90
  key,
91
91
  (...args: any[]) => {
92
92
  const currentMachine = machine();
93
93
  const nextMachine = (currentMachine as any)[key](...args);
94
- setMachine(() => nextMachine);
94
+ setMachine(nextMachine);
95
95
  return nextMachine;
96
96
  }
97
97
  ])
@@ -153,11 +153,11 @@ export function createMachineStore<M extends Machine<any>>(
153
153
  const { context, ...transitions } = initial;
154
154
 
155
155
  const handlers = Object.fromEntries(
156
- Object.entries(transitions).map(([key, fn]) => [
156
+ Object.entries(transitions).map(([key]) => [
157
157
  key,
158
158
  (...args: any[]) => {
159
159
  const nextMachine = (store as any)[key](...args);
160
- setStore(() => nextMachine);
160
+ setStore(nextMachine);
161
161
  return nextMachine;
162
162
  }
163
163
  ])
@@ -289,12 +289,12 @@ export function createMachineContext<C extends object, M extends Machine<C>>(
289
289
  const { context: _, ...transitions } = currentMachine;
290
290
 
291
291
  const handlers = Object.fromEntries(
292
- Object.entries(transitions).map(([key, fn]) => [
292
+ Object.entries(transitions).map(([key]) => [
293
293
  key,
294
294
  (...args: any[]) => {
295
295
  const nextMachine = (currentMachine as any)[key](...args);
296
296
  currentMachine = nextMachine;
297
- setContext(() => nextMachine.context);
297
+ setContext(nextMachine.context);
298
298
  return nextMachine;
299
299
  }
300
300
  ])
@@ -383,7 +383,7 @@ export function batchTransitions<M extends Machine<any>>(
383
383
 
384
384
  return batch(() => {
385
385
  const finalMachine = transitions.reduce((m, transition) => transition(m), machine);
386
- setMachine(finalMachine);
386
+ setMachine(() => finalMachine);
387
387
  return finalMachine;
388
388
  });
389
389
  }