@statelyai/sdk 0.39.1 → 0.41.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.
- package/README.md +10 -0
- package/dist/assetStorage.d.mts +1 -1
- package/dist/chunk-D1OLi6Wq.mjs +46 -0
- package/dist/editorHostProtocol.d.mts +3 -3
- package/dist/embed.d.mts +4 -3
- package/dist/embed.mjs +10 -3
- package/dist/{graph-CfWCJS4m.d.mts → graph-DbZdSisK.d.mts} +1 -1
- package/dist/graph.d.mts +1 -1
- package/dist/{index-DfMkVP94.d.mts → index-DqF1xP8P.d.mts} +50 -406
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +3 -3
- package/dist/{inspect-DXtP_tPO.mjs → inspect-CDjr4saL.mjs} +1 -1
- package/dist/{inspect-JNvMtuzC.d.mts → inspect-ruD95iBM.d.mts} +1 -1
- package/dist/inspect.d.mts +2 -2
- package/dist/inspect.mjs +2 -2
- package/dist/machineGraph-DYtFKHlq-BpWpGU22.mjs +3 -0
- package/dist/machineGraph-DYtFKHlq-ChbeTHlv.mjs +1023 -0
- package/dist/patchTypes.d.mts +1 -1
- package/dist/{protocol-D3XQmmmv.d.mts → protocol-BvElOcXs.d.mts} +17 -5
- package/dist/protocol.d.mts +1 -1
- package/dist/relay.d.mts +1 -1
- package/dist/rolldown-runtime-95iHPtFO-Bo6l7CbO.mjs +114 -0
- package/dist/{studio-DL0yj2Pi.mjs → schemas-DsQ8UYlM.mjs} +36 -1642
- package/dist/sourceCoverage.d.mts +101 -0
- package/dist/sourceCoverage.mjs +3572 -0
- package/dist/studio-DH7OeLao.mjs +1604 -0
- package/dist/{studio-ClBs4caM.d.mts → studio-DRw9sxCm.d.mts} +20 -2
- package/dist/studio.d.mts +1 -1
- package/dist/studio.mjs +1 -1
- package/dist/{version-gEUUpYtd.mjs → version-eag6cuvm.mjs} +1 -1
- package/dist/xstateSource-BUCx2xA4-CWteIFJn.d.mts +451 -0
- package/dist/xstateSource-JvwXWv6G-KnMMoZlG.mjs +151753 -0
- package/package.json +9 -5
- /package/dist/{editor-sync-types-Ch5P5XRj.d.mts → editor-sync-types-BjgSBGxf.d.mts} +0 -0
- /package/dist/{patchTypes-BZ7gzwAP.d.mts → patchTypes-BFlvJTDJ.d.mts} +0 -0
|
@@ -0,0 +1,1023 @@
|
|
|
1
|
+
import { Et as array, Nn as record, Rn as string, Tn as object, Xn as union, Zn as unknown, dn as literal, wn as number } from "./schemas-DsQ8UYlM.mjs";
|
|
2
|
+
import { a as XSTATE_V5_PROFILE, d as isCodeExpression, f as isXStateV6Profile, h as serializeJS, i as SERIALIZED_SOURCE_ID, m as raw, n as FN_PROJECTION_META, o as XSTATE_V6_BRANCH_DESCRIPTION_META, p as normalizeMachineProfile, t as __exportAll } from "./rolldown-runtime-95iHPtFO-Bo6l7CbO.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../graph-tools/dist/machineGraph-DYtFKHlq.mjs
|
|
5
|
+
function normalizeProfileRef(profile) {
|
|
6
|
+
return profile === "xstate-v5" || profile === "xstate-v6-alpha" ? normalizeMachineProfile(profile) : profile;
|
|
7
|
+
}
|
|
8
|
+
const AFTER_EVENT_PREFIX = "xstate.after.";
|
|
9
|
+
/** Recovers an authored delay key from an internal after-event type. */
|
|
10
|
+
function getDelayKeyFromEventType(eventType, sourceId) {
|
|
11
|
+
if (!eventType.startsWith(AFTER_EVENT_PREFIX)) return null;
|
|
12
|
+
const encoded = eventType.slice(13);
|
|
13
|
+
const sourceSuffix = sourceId ? `.${sourceId}` : null;
|
|
14
|
+
if (sourceSuffix && encoded.endsWith(sourceSuffix)) return encoded.slice(0, -sourceSuffix.length);
|
|
15
|
+
return encoded.split(".")[0] ?? encoded;
|
|
16
|
+
}
|
|
17
|
+
function isAutoGeneratedId(id) {
|
|
18
|
+
return !!id && id.startsWith("$auto-");
|
|
19
|
+
}
|
|
20
|
+
function getAuthoredNodeId(node) {
|
|
21
|
+
const authored = node.data.nodeId ?? void 0;
|
|
22
|
+
return authored && !isAutoGeneratedId(authored) ? authored : void 0;
|
|
23
|
+
}
|
|
24
|
+
function getRootEmittedId(graph, node) {
|
|
25
|
+
if (graph.id === "root" && node.data.key && node.data.key !== "root") return getAuthoredNodeId(node) ?? node.data.key;
|
|
26
|
+
return getAuthoredNodeId(node) ?? (isAutoGeneratedId(graph.id) ? void 0 : graph.id);
|
|
27
|
+
}
|
|
28
|
+
function getDefaultPathId(graph, node) {
|
|
29
|
+
if (!node.parentId) return getRootEmittedId(graph, node) ?? "(machine)";
|
|
30
|
+
const parentNode = graph.nodes.find((candidate) => candidate.id === node.parentId);
|
|
31
|
+
if (!parentNode) return node.data.key;
|
|
32
|
+
return `${getDefaultPathId(graph, parentNode)}.${node.data.key}`;
|
|
33
|
+
}
|
|
34
|
+
function getEmittedNodeId(graph, node) {
|
|
35
|
+
const authored = getAuthoredNodeId(node);
|
|
36
|
+
if (!node.parentId) return getRootEmittedId(graph, node);
|
|
37
|
+
if (!authored) return void 0;
|
|
38
|
+
return authored;
|
|
39
|
+
}
|
|
40
|
+
function getResolvedNodeId(graph, node) {
|
|
41
|
+
return getEmittedNodeId(graph, node) ?? getDefaultPathId(graph, node);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Strips `export default` wrapper from an expression string.
|
|
45
|
+
* E.g. `"export default assign({ ... })"` → `"assign({ ... })"`
|
|
46
|
+
*/
|
|
47
|
+
function stripExportDefault(code) {
|
|
48
|
+
const trimmed = code.trim();
|
|
49
|
+
if (trimmed.startsWith("export default ")) return trimmed.slice(15).replace(/;$/, "");
|
|
50
|
+
return trimmed;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Graph-native transition references. Transitions point at invoke/action/state
|
|
54
|
+
* blocks by graph id (`@statelyai.*`); the literal `xstate.*` event is produced
|
|
55
|
+
* here at codegen time. Literal `xstate.*` strings (pre-resolved, e.g. baked by
|
|
56
|
+
* an import) are passed through unchanged.
|
|
57
|
+
*/
|
|
58
|
+
const STATELY_PREFIX = "@statelyai";
|
|
59
|
+
/** Legacy prefix accepted on read for graphs persisted before the rename. */
|
|
60
|
+
const LEGACY_STATELY_PREFIX = "@stately";
|
|
61
|
+
const STATELY_REF_PREFIX = {
|
|
62
|
+
invokeDone: "@statelyai.invoke.done",
|
|
63
|
+
invokeError: "@statelyai.invoke.error",
|
|
64
|
+
invokeSnapshot: "@statelyai.invoke.snapshot",
|
|
65
|
+
invokeTimeout: "@statelyai.invoke.timeout",
|
|
66
|
+
actionDone: "@statelyai.action.done",
|
|
67
|
+
actionError: "@statelyai.action.error",
|
|
68
|
+
stateDone: "@statelyai.state.done",
|
|
69
|
+
stateError: "@statelyai.state.error",
|
|
70
|
+
stateTimeout: "@statelyai.state.timeout"
|
|
71
|
+
};
|
|
72
|
+
function parseStatelyRef(eventType) {
|
|
73
|
+
if (eventType.startsWith(`${LEGACY_STATELY_PREFIX}.`)) eventType = `${STATELY_PREFIX}${eventType.slice(8)}`;
|
|
74
|
+
if (!eventType.startsWith(`${STATELY_PREFIX}.`)) return null;
|
|
75
|
+
for (const kind of Object.keys(STATELY_REF_PREFIX)) {
|
|
76
|
+
const prefix = STATELY_REF_PREFIX[kind];
|
|
77
|
+
if (eventType === prefix) return {
|
|
78
|
+
kind,
|
|
79
|
+
blockId: ""
|
|
80
|
+
};
|
|
81
|
+
if (eventType.startsWith(`${prefix}.`)) return {
|
|
82
|
+
kind,
|
|
83
|
+
blockId: eventType.slice(prefix.length + 1)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
/** Find an invoke block by its graph id, or by its emitted id (legacy literals). */
|
|
89
|
+
function findInvokeByActorId(node, actorId) {
|
|
90
|
+
const invokes = node.data.invokes ?? [];
|
|
91
|
+
return invokes.find((inv) => inv.id === actorId) ?? invokes.find((inv) => (inv.invocationId ?? inv.id) === actorId);
|
|
92
|
+
}
|
|
93
|
+
/** Resolve a spawn action block id to its spawned actor id (`params.id`). */
|
|
94
|
+
function resolveSpawnActorId(node, actionId) {
|
|
95
|
+
const spawnId = [...node.data.entry ?? [], ...node.data.exit ?? []].find((action) => action.id === actionId)?.params?.["id"];
|
|
96
|
+
return typeof spawnId === "string" && spawnId ? spawnId : actionId;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolve an edge's target into the string XState expects on the source state.
|
|
100
|
+
* Prefer a relative key path (resolved against the source's parent, or the root
|
|
101
|
+
* itself for root transitions) so output reads like a hand-written machine —
|
|
102
|
+
* e.g. a sibling's child becomes `Unlocked.Manual`. Fall back to an absolute
|
|
103
|
+
* `#id` reference only when the target lives outside the source's subtree.
|
|
104
|
+
*/
|
|
105
|
+
function resolveTransitionTarget(graph, sourceNode, targetNode) {
|
|
106
|
+
const isRootSource = sourceNode.parentId == null;
|
|
107
|
+
const baseId = sourceNode.parentId ?? sourceNode.id;
|
|
108
|
+
const keys = [];
|
|
109
|
+
let current = targetNode;
|
|
110
|
+
while (current) {
|
|
111
|
+
keys.unshift(current.data.key.replace(/\\/g, "\\\\").replace(/\./g, "\\."));
|
|
112
|
+
if (current.parentId === baseId) {
|
|
113
|
+
if (isRootSource) return `.${keys.join(".")}`;
|
|
114
|
+
return keys.join(".");
|
|
115
|
+
}
|
|
116
|
+
const parentId = current.parentId;
|
|
117
|
+
current = graph.nodes.find((n) => n.id === parentId);
|
|
118
|
+
}
|
|
119
|
+
return `#${getAbsoluteTargetId(graph, targetNode)}`;
|
|
120
|
+
}
|
|
121
|
+
function getAbsoluteTargetId(graph, targetNode) {
|
|
122
|
+
const resolved = getResolvedNodeId(graph, targetNode);
|
|
123
|
+
if (!resolved.startsWith("root.")) return resolved;
|
|
124
|
+
const rootNode = graph.nodes.find((node) => node.parentId === null);
|
|
125
|
+
const rootKey = rootNode?.data.nodeId && !isAutoGeneratedId(rootNode.data.nodeId) ? rootNode.data.nodeId : rootNode?.data.key;
|
|
126
|
+
return rootKey && rootKey !== "root" ? `${rootKey}.${resolved.slice(5)}` : resolved;
|
|
127
|
+
}
|
|
128
|
+
/** Unwrap single-element arrays to a single value (XState single-or-array convention) */
|
|
129
|
+
function singleOrArray(arr) {
|
|
130
|
+
return arr.length === 1 ? arr[0] : arr;
|
|
131
|
+
}
|
|
132
|
+
/** Unwrap each value in a record of arrays */
|
|
133
|
+
function singleOrArrayRecord(record) {
|
|
134
|
+
const result = {};
|
|
135
|
+
for (const [key, arr] of Object.entries(record)) result[key] = singleOrArray(arr);
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Remove empty arrays/objects/strings, unwrap single-element arrays.
|
|
140
|
+
* Matches studio's simplifyAttributes behavior.
|
|
141
|
+
*/
|
|
142
|
+
/**
|
|
143
|
+
* Keys whose empty object value is authored, not incidental: `context: {}`
|
|
144
|
+
* declares that the machine has context, so dropping it loses information.
|
|
145
|
+
*/
|
|
146
|
+
const KEEP_WHEN_EMPTY = new Set(["context"]);
|
|
147
|
+
const KEEP_SINGLETON_ARRAY = new Set(["internalEvents", "tags"]);
|
|
148
|
+
function simplifyAttributes(obj) {
|
|
149
|
+
for (const key of Object.keys(obj)) {
|
|
150
|
+
const value = obj[key];
|
|
151
|
+
if (value === void 0 || value === null) delete obj[key];
|
|
152
|
+
else if (KEEP_WHEN_EMPTY.has(key)) continue;
|
|
153
|
+
else if (Array.isArray(value)) {
|
|
154
|
+
if (value.length === 0) delete obj[key];
|
|
155
|
+
else if (value.length === 1 && !KEEP_SINGLETON_ARRAY.has(key)) obj[key] = value[0];
|
|
156
|
+
} else if (typeof value === "object" && Object.keys(value).length === 0) delete obj[key];
|
|
157
|
+
else if (typeof value === "string" && value === "") delete obj[key];
|
|
158
|
+
}
|
|
159
|
+
return obj;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Recursively apply simplifyAttributes to a config tree.
|
|
163
|
+
* Cleans up the config and all nested state nodes, transitions, and invokes.
|
|
164
|
+
*/
|
|
165
|
+
function deepSimplify(config) {
|
|
166
|
+
for (const mapKey of ["on", "after"]) {
|
|
167
|
+
const map = config[mapKey];
|
|
168
|
+
if (map && typeof map === "object" && !Array.isArray(map)) {
|
|
169
|
+
for (const [, val] of Object.entries(map)) if (val && typeof val === "object" && !Array.isArray(val)) simplifyAttributes(val);
|
|
170
|
+
else if (Array.isArray(val)) {
|
|
171
|
+
for (const item of val) if (item && typeof item === "object") simplifyAttributes(item);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
for (const key of [
|
|
176
|
+
"always",
|
|
177
|
+
"onDone",
|
|
178
|
+
"onError",
|
|
179
|
+
"onTimeout"
|
|
180
|
+
]) {
|
|
181
|
+
const val = config[key];
|
|
182
|
+
if (val && typeof val === "object" && !Array.isArray(val)) simplifyAttributes(val);
|
|
183
|
+
else if (Array.isArray(val)) {
|
|
184
|
+
for (const item of val) if (item && typeof item === "object") simplifyAttributes(item);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const invoke = config.invoke;
|
|
188
|
+
if (invoke && typeof invoke === "object" && !Array.isArray(invoke)) simplifyAttributes(invoke);
|
|
189
|
+
else if (Array.isArray(invoke)) {
|
|
190
|
+
for (const item of invoke) if (item && typeof item === "object") simplifyAttributes(item);
|
|
191
|
+
}
|
|
192
|
+
simplifyAttributes(config);
|
|
193
|
+
if (config.states && typeof config.states === "object") for (const stateConfig of Object.values(config.states)) deepSimplify(stateConfig);
|
|
194
|
+
return config;
|
|
195
|
+
}
|
|
196
|
+
function buildMeta(meta, color, showStatelyMeta = true) {
|
|
197
|
+
if (isCodeExpression(meta)) return meta;
|
|
198
|
+
const result = {};
|
|
199
|
+
if (meta) {
|
|
200
|
+
for (const [k, v] of Object.entries(meta)) if (v !== void 0 && v !== null && (showStatelyMeta || k === FN_PROJECTION_META || !k.startsWith("@statelyai"))) result[k] = v;
|
|
201
|
+
}
|
|
202
|
+
if (color !== void 0 && showStatelyMeta) result["@statelyai.color"] = color;
|
|
203
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
204
|
+
}
|
|
205
|
+
/** Format event param — supports { type: string } (new) and plain string (legacy) */
|
|
206
|
+
function formatEventParam(event) {
|
|
207
|
+
if (isCodeExpression(event)) return serializeJS(event);
|
|
208
|
+
if (event && typeof event === "object" && "type" in event) return formatInlineObject(event);
|
|
209
|
+
if (typeof event === "string") return `{ type: '${event}' }`;
|
|
210
|
+
return "undefined";
|
|
211
|
+
}
|
|
212
|
+
function formatStringParam(value) {
|
|
213
|
+
if (typeof value === "string") return `'${value}'`;
|
|
214
|
+
return isCodeExpression(value) ? serializeJS(value) : "undefined";
|
|
215
|
+
}
|
|
216
|
+
function formatInlineObject(value) {
|
|
217
|
+
return serializeJS(raw(`{ ${Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => `${formatObjectKey(key)}: ${serializeJS(item)}`).join(", ")} }`, value));
|
|
218
|
+
}
|
|
219
|
+
function formatObjectKey(key) {
|
|
220
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
|
|
221
|
+
}
|
|
222
|
+
const codeExpressionParamSchema = object({
|
|
223
|
+
"@type": literal("code"),
|
|
224
|
+
expr: string()
|
|
225
|
+
}).passthrough();
|
|
226
|
+
const eventParamSchema = union([
|
|
227
|
+
string(),
|
|
228
|
+
object({ type: string() }).catchall(unknown()),
|
|
229
|
+
codeExpressionParamSchema
|
|
230
|
+
]);
|
|
231
|
+
const stringOrCodeParamSchema = union([string(), codeExpressionParamSchema]);
|
|
232
|
+
const delayParamSchema = union([
|
|
233
|
+
number(),
|
|
234
|
+
string(),
|
|
235
|
+
codeExpressionParamSchema
|
|
236
|
+
]);
|
|
237
|
+
const builtInActionParamSchemas = {
|
|
238
|
+
"xstate.enqueue": object({
|
|
239
|
+
code: string().optional(),
|
|
240
|
+
lang: string().optional()
|
|
241
|
+
}),
|
|
242
|
+
"xstate.raise": object({
|
|
243
|
+
event: eventParamSchema.optional(),
|
|
244
|
+
id: stringOrCodeParamSchema.optional(),
|
|
245
|
+
delay: delayParamSchema.optional()
|
|
246
|
+
}),
|
|
247
|
+
"xstate.sendTo": object({
|
|
248
|
+
to: stringOrCodeParamSchema.optional(),
|
|
249
|
+
event: eventParamSchema.optional(),
|
|
250
|
+
id: stringOrCodeParamSchema.optional(),
|
|
251
|
+
delay: delayParamSchema.optional()
|
|
252
|
+
}),
|
|
253
|
+
"xstate.cancel": object({ sendId: stringOrCodeParamSchema.optional() }),
|
|
254
|
+
"xstate.emit": object({ event: eventParamSchema.optional() }),
|
|
255
|
+
"xstate.spawnChild": object({
|
|
256
|
+
src: stringOrCodeParamSchema.optional(),
|
|
257
|
+
id: stringOrCodeParamSchema.optional(),
|
|
258
|
+
systemId: stringOrCodeParamSchema.optional(),
|
|
259
|
+
input: unknown().optional()
|
|
260
|
+
}),
|
|
261
|
+
"xstate.stopChild": object({ actorRef: stringOrCodeParamSchema.optional() }),
|
|
262
|
+
"xstate.log": object({ label: unknown().optional() }),
|
|
263
|
+
"xstate.assign": object({ assignment: record(string(), unknown()).optional() }).catchall(unknown()),
|
|
264
|
+
"xstate.choose": object({ branches: array(object({
|
|
265
|
+
guard: unknown().optional(),
|
|
266
|
+
actions: array(unknown()).optional()
|
|
267
|
+
})).optional() })
|
|
268
|
+
};
|
|
269
|
+
const XSTATE_BUILT_IN_ACTIONS = {
|
|
270
|
+
"xstate.enqueue": {
|
|
271
|
+
package: "xstate",
|
|
272
|
+
version: "^6",
|
|
273
|
+
import: "enqueue",
|
|
274
|
+
importKind: "named",
|
|
275
|
+
paramsSchema: builtInActionParamSchemas["xstate.enqueue"],
|
|
276
|
+
emit(params) {
|
|
277
|
+
return typeof params?.code === "string" ? stripExportDefault(params.code) : "";
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"xstate.raise": {
|
|
281
|
+
package: "xstate",
|
|
282
|
+
version: "^5",
|
|
283
|
+
import: "raise",
|
|
284
|
+
importKind: "named",
|
|
285
|
+
paramsSchema: builtInActionParamSchemas["xstate.raise"],
|
|
286
|
+
emit(params) {
|
|
287
|
+
const eventStr = formatEventParam(params?.event);
|
|
288
|
+
const opts = [];
|
|
289
|
+
if (params?.id) opts.push(`id: ${formatStringParam(params.id)}`);
|
|
290
|
+
if (params?.delay != null) opts.push(`delay: ${serializeJS(params.delay)}`);
|
|
291
|
+
return `raise(${eventStr}${opts.length > 0 ? `, { ${opts.join(", ")} }` : ""})`;
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"xstate.sendTo": {
|
|
295
|
+
package: "xstate",
|
|
296
|
+
version: "^5",
|
|
297
|
+
import: "sendTo",
|
|
298
|
+
importKind: "named",
|
|
299
|
+
paramsSchema: builtInActionParamSchemas["xstate.sendTo"],
|
|
300
|
+
emit(params) {
|
|
301
|
+
const to = formatStringParam(params?.to);
|
|
302
|
+
const eventStr = formatEventParam(params?.event);
|
|
303
|
+
const opts = [];
|
|
304
|
+
if (params?.id) opts.push(`id: ${formatStringParam(params.id)}`);
|
|
305
|
+
if (params?.delay != null) opts.push(`delay: ${serializeJS(params.delay)}`);
|
|
306
|
+
return `sendTo(${to}, ${eventStr}${opts.length > 0 ? `, { ${opts.join(", ")} }` : ""})`;
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
"xstate.cancel": {
|
|
310
|
+
package: "xstate",
|
|
311
|
+
version: "^5",
|
|
312
|
+
import: "cancel",
|
|
313
|
+
importKind: "named",
|
|
314
|
+
paramsSchema: builtInActionParamSchemas["xstate.cancel"],
|
|
315
|
+
emit(params) {
|
|
316
|
+
return `cancel(${formatStringParam(params?.sendId)})`;
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
"xstate.emit": {
|
|
320
|
+
package: "xstate",
|
|
321
|
+
version: "^5",
|
|
322
|
+
import: "emit",
|
|
323
|
+
importKind: "named",
|
|
324
|
+
paramsSchema: builtInActionParamSchemas["xstate.emit"],
|
|
325
|
+
emit(params) {
|
|
326
|
+
return `emit(${formatEventParam(params?.event)})`;
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"xstate.spawnChild": {
|
|
330
|
+
package: "xstate",
|
|
331
|
+
version: "^5",
|
|
332
|
+
import: "spawnChild",
|
|
333
|
+
importKind: "named",
|
|
334
|
+
paramsSchema: builtInActionParamSchemas["xstate.spawnChild"],
|
|
335
|
+
emit(params) {
|
|
336
|
+
const src = formatStringParam(params?.src);
|
|
337
|
+
const opts = [];
|
|
338
|
+
if (params?.id) opts.push(`id: ${formatStringParam(params.id)}`);
|
|
339
|
+
if (params?.systemId) opts.push(`systemId: ${formatStringParam(params.systemId)}`);
|
|
340
|
+
if (params?.input !== void 0) opts.push(`input: ${serializeJS(params.input)}`);
|
|
341
|
+
return `spawnChild(${src}${opts.length > 0 ? `, { ${opts.join(", ")} }` : ""})`;
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
"xstate.stopChild": {
|
|
345
|
+
package: "xstate",
|
|
346
|
+
version: "^5",
|
|
347
|
+
import: "stopChild",
|
|
348
|
+
importKind: "named",
|
|
349
|
+
paramsSchema: builtInActionParamSchemas["xstate.stopChild"],
|
|
350
|
+
emit(params) {
|
|
351
|
+
return `stopChild(${formatStringParam(params?.actorRef)})`;
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
"xstate.log": {
|
|
355
|
+
package: "xstate",
|
|
356
|
+
version: "^5",
|
|
357
|
+
import: "log",
|
|
358
|
+
importKind: "named",
|
|
359
|
+
paramsSchema: builtInActionParamSchemas["xstate.log"],
|
|
360
|
+
emit(params) {
|
|
361
|
+
return `log(${(params?.label !== void 0 ? serializeJS(params.label) : void 0) ?? ""})`;
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
"xstate.choose": {
|
|
365
|
+
package: "xstate",
|
|
366
|
+
version: "^5",
|
|
367
|
+
import: "enqueueActions",
|
|
368
|
+
importKind: "named",
|
|
369
|
+
paramsSchema: builtInActionParamSchemas["xstate.choose"],
|
|
370
|
+
emit(params) {
|
|
371
|
+
return emitChooseBranches(params?.branches ?? []);
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
"xstate.assign": {
|
|
375
|
+
package: "xstate",
|
|
376
|
+
version: "^5",
|
|
377
|
+
import: "assign",
|
|
378
|
+
importKind: "named",
|
|
379
|
+
paramsSchema: builtInActionParamSchemas["xstate.assign"],
|
|
380
|
+
emit(params) {
|
|
381
|
+
if (isCodeExpression(params?.assignment)) return `assign(${serializeJS(params.assignment)})`;
|
|
382
|
+
const assignments = params?.assignment && typeof params.assignment === "object" && !Array.isArray(params.assignment) ? params.assignment : params;
|
|
383
|
+
const entries = Object.entries(assignments ?? {}).filter(([k, v]) => k && v !== void 0);
|
|
384
|
+
if (entries.length === 0) return "assign({})";
|
|
385
|
+
return `assign({ ${entries.map(([k, v]) => `${JSON.stringify(k)}: ${formatAssignValue(v)}`).join(", ")} })`;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
function isBuiltInActionType(type) {
|
|
390
|
+
return type in XSTATE_BUILT_IN_ACTIONS;
|
|
391
|
+
}
|
|
392
|
+
/** Lower `xstate.choose` branches to an `enqueueActions` if/else-if chain. */
|
|
393
|
+
function emitChooseBranches(branches) {
|
|
394
|
+
const lines = [];
|
|
395
|
+
const indent = (depth) => " ".repeat(depth);
|
|
396
|
+
const serializeEnqueued = (action, depth) => {
|
|
397
|
+
if (action && typeof action === "object" && !Array.isArray(action) && Object.keys(action).length === 1 && typeof action.type === "string") return serializeJS(action.type);
|
|
398
|
+
return serializeJS(action, depth * 2);
|
|
399
|
+
};
|
|
400
|
+
const body = (actions, depth) => (actions ?? []).map((action) => `${indent(depth)}enqueue(${serializeEnqueued(action, depth)});`);
|
|
401
|
+
let closed = false;
|
|
402
|
+
let opened = false;
|
|
403
|
+
for (const branch of branches) {
|
|
404
|
+
if (closed) break;
|
|
405
|
+
if (branch.guard === void 0) {
|
|
406
|
+
if (opened) {
|
|
407
|
+
lines.push(` } else {`);
|
|
408
|
+
lines.push(...body(branch.actions, 2));
|
|
409
|
+
lines.push(" }");
|
|
410
|
+
} else lines.push(...body(branch.actions, 1));
|
|
411
|
+
closed = true;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
lines.push(` ${opened ? "} else if" : "if"} (check(${serializeJS(branch.guard)})) {`);
|
|
415
|
+
lines.push(...body(branch.actions, 2));
|
|
416
|
+
opened = true;
|
|
417
|
+
}
|
|
418
|
+
if (opened && !closed) lines.push(" }");
|
|
419
|
+
return `enqueueActions(({ check, enqueue }) => {\n${lines.join("\n")}\n})`;
|
|
420
|
+
}
|
|
421
|
+
function emitBuiltInAction(type, params) {
|
|
422
|
+
return XSTATE_BUILT_IN_ACTIONS[type].emit(params);
|
|
423
|
+
}
|
|
424
|
+
function actionCodeExpression(expr, source) {
|
|
425
|
+
return {
|
|
426
|
+
"@type": "code",
|
|
427
|
+
lang: "ts",
|
|
428
|
+
expr,
|
|
429
|
+
imports: [{
|
|
430
|
+
package: source.package,
|
|
431
|
+
version: source.version,
|
|
432
|
+
import: source.import,
|
|
433
|
+
importKind: source.importKind
|
|
434
|
+
}]
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function inlineCodeExpression(expr, sourceValue) {
|
|
438
|
+
const result = {
|
|
439
|
+
"@type": "code",
|
|
440
|
+
lang: "ts",
|
|
441
|
+
expr: stripExportDefault(expr)
|
|
442
|
+
};
|
|
443
|
+
const sourceId = sourceValue?.[SERIALIZED_SOURCE_ID];
|
|
444
|
+
if (sourceId !== void 0) Object.defineProperty(result, SERIALIZED_SOURCE_ID, {
|
|
445
|
+
value: sourceId,
|
|
446
|
+
enumerable: true
|
|
447
|
+
});
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Serialize an edge guard for a machine config. Codegen emits inline guards as
|
|
452
|
+
* a code-expression directive so the source round-trips. The simulation passes
|
|
453
|
+
* `asTypeRef` to get a plain `{ type }` reference instead (it stubs guards by
|
|
454
|
+
* type and can't evaluate the source) — see MachineConfigOptions.
|
|
455
|
+
*/
|
|
456
|
+
function serializeGuard(guard, asTypeRef) {
|
|
457
|
+
if (asTypeRef) return guard.params ? {
|
|
458
|
+
type: guard.type,
|
|
459
|
+
params: guard.params
|
|
460
|
+
} : { type: guard.type };
|
|
461
|
+
return guard.code ? inlineCodeExpression(guard.code, guard) : guard;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Converts a built-in xstate ActionItem to a code expression directive,
|
|
465
|
+
* or returns a plain { type, params } object for user-defined actions.
|
|
466
|
+
*/
|
|
467
|
+
function serializeActionItem(action, keepChooseStructured = false) {
|
|
468
|
+
const { type, params } = action;
|
|
469
|
+
if (keepChooseStructured && type === "xstate.choose") return {
|
|
470
|
+
type,
|
|
471
|
+
params
|
|
472
|
+
};
|
|
473
|
+
if (type === "xstate.enqueue" && typeof params?.code === "string") return inlineCodeExpression(params.code, action);
|
|
474
|
+
const exprCode = type === "xstate.expr" && typeof params?.code === "string" ? params.code : void 0;
|
|
475
|
+
if (isBuiltInActionType(type)) {
|
|
476
|
+
const builtInAction = XSTATE_BUILT_IN_ACTIONS[type];
|
|
477
|
+
return actionCodeExpression(emitBuiltInAction(type, params), builtInAction);
|
|
478
|
+
}
|
|
479
|
+
if (exprCode) return inlineCodeExpression(exprCode, action);
|
|
480
|
+
if (!params || Object.keys(params).length === 0) return { type };
|
|
481
|
+
return {
|
|
482
|
+
type,
|
|
483
|
+
params
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function formatAssignValue(value) {
|
|
487
|
+
if (typeof value !== "string") return serializeJS(value);
|
|
488
|
+
const templateExpression = value.match(/^\{\{([\s\S]*)\}\}$/);
|
|
489
|
+
if (templateExpression) return templateExpression[1].trim();
|
|
490
|
+
return JSON.stringify(value);
|
|
491
|
+
}
|
|
492
|
+
/** Normalize tag to string — handles both `string` and `{ name: string }` */
|
|
493
|
+
function tagToString(tag) {
|
|
494
|
+
return typeof tag === "string" ? tag : tag.name;
|
|
495
|
+
}
|
|
496
|
+
function graphToMachineConfig(graph, options = {}) {
|
|
497
|
+
const v6 = isXStateV6Profile(graph.data.profile);
|
|
498
|
+
const { showDescriptions = true, showMeta = true, showStatelyMeta = true, inlineGuardsAsTypeRef = false, keepChooseStructured = false, timerActionsAsTypeRef = false } = options;
|
|
499
|
+
const serializeAction = (action) => timerActionsAsTypeRef && ["xstate.raise", "xstate.cancel"].includes(action.type) ? {
|
|
500
|
+
type: action.type,
|
|
501
|
+
params: action.params
|
|
502
|
+
} : serializeActionItem(action, keepChooseStructured);
|
|
503
|
+
const config = {};
|
|
504
|
+
function getNodeConfig(node) {
|
|
505
|
+
const nodeConfig = node.parentId ? {} : config;
|
|
506
|
+
const resolvedNodeId = getEmittedNodeId(graph, node);
|
|
507
|
+
const initialNode = node.data.initialId ? graph.nodes.find((n) => n.id === node.data.initialId) : null;
|
|
508
|
+
const nodeType = [
|
|
509
|
+
"final",
|
|
510
|
+
"history",
|
|
511
|
+
"parallel",
|
|
512
|
+
"choice"
|
|
513
|
+
].includes(node.data.type) ? node.data.type : void 0;
|
|
514
|
+
const tags = node.data.tags;
|
|
515
|
+
const stateMeta = showMeta ? buildMeta({
|
|
516
|
+
...node.data.meta,
|
|
517
|
+
...node.data.assets?.length ? { "@statelyai.assets": node.data.assets.map(({ type, url, size, width, height, name, metadata }) => ({
|
|
518
|
+
type,
|
|
519
|
+
url,
|
|
520
|
+
...size ? { size } : {},
|
|
521
|
+
...name !== void 0 ? { name } : {},
|
|
522
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
523
|
+
...type === "iframe" ? {
|
|
524
|
+
...width !== void 0 ? { width } : {},
|
|
525
|
+
...height !== void 0 ? { height } : {}
|
|
526
|
+
} : {}
|
|
527
|
+
})) } : {},
|
|
528
|
+
...node.data.appearance ? { "@statelyai.appearance": node.data.appearance } : {}
|
|
529
|
+
}, node.data.color, showStatelyMeta) : void 0;
|
|
530
|
+
Object.assign(nodeConfig, {
|
|
531
|
+
id: resolvedNodeId,
|
|
532
|
+
type: nodeType === "normal" ? void 0 : nodeType ?? void 0,
|
|
533
|
+
initial: initialNode ? nodeType === "history" ? void 0 : node.data.initialInput !== void 0 ? {
|
|
534
|
+
target: initialNode.data.key,
|
|
535
|
+
input: node.data.initialInput
|
|
536
|
+
} : initialNode.data.key : void 0,
|
|
537
|
+
target: nodeType === "history" && initialNode ? resolveTransitionTarget(graph, node, initialNode) : void 0,
|
|
538
|
+
...node.data.timeout !== void 0 ? { timeout: node.data.timeout } : void 0,
|
|
539
|
+
...node.data.route !== void 0 ? { route: node.data.route } : void 0,
|
|
540
|
+
...node.data.entry?.length ? { entry: node.data.entry.map(serializeAction) } : void 0,
|
|
541
|
+
...node.data.exit?.length ? { exit: node.data.exit.map(serializeAction) } : void 0,
|
|
542
|
+
...node.data.invokes?.length ? { invoke: node.data.invokes.map((inv) => ({
|
|
543
|
+
src: inv.srcExpression ?? inv.src,
|
|
544
|
+
id: inv.invocationId ?? inv.id,
|
|
545
|
+
...inv.registryKey ? { registryKey: inv.registryKey } : void 0,
|
|
546
|
+
...inv.timeout !== void 0 ? { timeout: inv.timeout } : void 0,
|
|
547
|
+
...inv.input !== void 0 ? { input: inv.input } : void 0,
|
|
548
|
+
...inv.output !== void 0 ? { output: inv.output } : void 0
|
|
549
|
+
})) } : void 0,
|
|
550
|
+
...node.data.output !== void 0 ? { output: node.data.output } : void 0,
|
|
551
|
+
...node.data.schemas ? { schemas: node.data.schemas } : void 0,
|
|
552
|
+
...tags?.length ? { tags: tags.map(tagToString) } : void 0,
|
|
553
|
+
...showDescriptions && node.data.description ? { description: node.data.description } : void 0,
|
|
554
|
+
...stateMeta ? { meta: stateMeta } : void 0,
|
|
555
|
+
...node.data.history ? { history: node.data.history } : void 0
|
|
556
|
+
});
|
|
557
|
+
const childNodes = graph.nodes.filter((n) => n.parentId === node.id && !n.data.temp);
|
|
558
|
+
const edges = graph.edges.filter((edge) => edge.sourceId === node.id && !edge.data.temp);
|
|
559
|
+
if (edges.length > 0) {
|
|
560
|
+
const on = {};
|
|
561
|
+
const transitionOrder = /* @__PURE__ */ new Map();
|
|
562
|
+
const scxmlTransitions = [];
|
|
563
|
+
const after = {};
|
|
564
|
+
const alwaysArr = [];
|
|
565
|
+
const choiceArr = [];
|
|
566
|
+
const onDone = {};
|
|
567
|
+
const onError = [];
|
|
568
|
+
const onTimeout = [];
|
|
569
|
+
const invokeMap = {};
|
|
570
|
+
for (const edge of edges) {
|
|
571
|
+
const targetNode = graph.nodes.find((n) => n.id === edge.targetId);
|
|
572
|
+
const resolvedTarget = targetNode ? resolveTransitionTarget(graph, node, targetNode) : "";
|
|
573
|
+
const resolvedTargets = [resolvedTarget, ...(edge.data.additionalTargetIds ?? []).flatMap((targetId) => {
|
|
574
|
+
const additionalTarget = graph.nodes.find((n) => n.id === targetId);
|
|
575
|
+
return additionalTarget ? [resolveTransitionTarget(graph, node, additionalTarget)] : [];
|
|
576
|
+
})].filter(Boolean);
|
|
577
|
+
const type = edge.data.eventType ?? "";
|
|
578
|
+
const transitionMeta = showMeta ? buildMeta({
|
|
579
|
+
...edge.data.meta,
|
|
580
|
+
...edge.data.assets?.length ? { "@statelyai.assets": edge.data.assets.map(({ type, url, size, width, height, name, metadata }) => ({
|
|
581
|
+
type,
|
|
582
|
+
url,
|
|
583
|
+
...size ? { size } : {},
|
|
584
|
+
...name !== void 0 ? { name } : {},
|
|
585
|
+
...metadata !== void 0 ? { metadata } : {},
|
|
586
|
+
...type === "iframe" ? {
|
|
587
|
+
...width !== void 0 ? { width } : {},
|
|
588
|
+
...height !== void 0 ? { height } : {}
|
|
589
|
+
} : {}
|
|
590
|
+
})) } : {},
|
|
591
|
+
...edge.data.appearance ? { "@statelyai.appearance": edge.data.appearance } : {}
|
|
592
|
+
}, edge.data.color, showStatelyMeta) : edge.data.meta?.[FN_PROJECTION_META] ? { [FN_PROJECTION_META]: edge.data.meta[FN_PROJECTION_META] } : void 0;
|
|
593
|
+
const transitionObject = {
|
|
594
|
+
...edge.data.matches ? { matches: edge.data.matches } : void 0,
|
|
595
|
+
target: edge.data.transitionType === "targetless" ? void 0 : resolvedTargets.length > 1 ? resolvedTargets : `${resolvedTarget}`,
|
|
596
|
+
...edge.data.transitionType === "reenter" ? { reenter: true } : void 0,
|
|
597
|
+
guard: edge.data.guard ? serializeGuard(edge.data.guard, inlineGuardsAsTypeRef) : void 0,
|
|
598
|
+
...edge.data.context !== void 0 ? { context: edge.data.context } : void 0,
|
|
599
|
+
...edge.data.input !== void 0 ? { input: edge.data.input } : void 0,
|
|
600
|
+
actions: edge.data.actions?.length ? edge.data.actions.map(serializeAction) : void 0,
|
|
601
|
+
description: showDescriptions ? edge.data.description ?? void 0 : void 0,
|
|
602
|
+
...transitionMeta ? { meta: transitionMeta } : void 0
|
|
603
|
+
};
|
|
604
|
+
transitionOrder.set(transitionObject, transitionOrder.size);
|
|
605
|
+
const pushOn = (key) => {
|
|
606
|
+
if (!on[key]) on[key] = [];
|
|
607
|
+
on[key].push(transitionObject);
|
|
608
|
+
};
|
|
609
|
+
const nestInvoke = (blockId, slot) => {
|
|
610
|
+
invokeMap[blockId] = {
|
|
611
|
+
...invokeMap[blockId],
|
|
612
|
+
[slot]: (invokeMap[blockId]?.[slot] ?? []).concat(transitionObject)
|
|
613
|
+
};
|
|
614
|
+
};
|
|
615
|
+
const ref = parseStatelyRef(type);
|
|
616
|
+
if (ref) if (ref.kind === "invokeDone") nestInvoke(ref.blockId, "onDone");
|
|
617
|
+
else if (ref.kind === "invokeError") nestInvoke(ref.blockId, "onError");
|
|
618
|
+
else if (ref.kind === "invokeSnapshot") nestInvoke(ref.blockId, "onSnapshot");
|
|
619
|
+
else if (ref.kind === "invokeTimeout") nestInvoke(ref.blockId, "onTimeout");
|
|
620
|
+
else if (ref.kind === "stateDone") {
|
|
621
|
+
if (!onDone[type]) onDone[type] = [];
|
|
622
|
+
onDone[type].push(transitionObject);
|
|
623
|
+
} else if (ref.kind === "stateError") onError.push(transitionObject);
|
|
624
|
+
else if (ref.kind === "stateTimeout") onTimeout.push(transitionObject);
|
|
625
|
+
else {
|
|
626
|
+
const verb = ref.kind === "actionDone" ? "done" : "error";
|
|
627
|
+
const actorId = resolveSpawnActorId(node, ref.blockId);
|
|
628
|
+
if (v6) {
|
|
629
|
+
const eventType = `xstate.${verb}.actor`;
|
|
630
|
+
if (!on[eventType]) on[eventType] = [];
|
|
631
|
+
on[eventType].push({
|
|
632
|
+
...transitionObject,
|
|
633
|
+
matches: {
|
|
634
|
+
...transitionObject.matches,
|
|
635
|
+
actorId
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
} else pushOn(`xstate.${verb}.actor.${actorId}`);
|
|
639
|
+
}
|
|
640
|
+
else if (edge.data.route) continue;
|
|
641
|
+
else if (type === "" && node.data.type === "choice") choiceArr.push(transitionObject);
|
|
642
|
+
else if (type === "") alwaysArr.push(transitionObject);
|
|
643
|
+
else if (type.startsWith("xstate.after.")) {
|
|
644
|
+
const delayKey = getDelayKeyFromEventType(type, edge.sourceId);
|
|
645
|
+
if (!after[delayKey]) after[delayKey] = [];
|
|
646
|
+
after[delayKey].push(transitionObject);
|
|
647
|
+
} else if (edge.data.meta?.["@statelyai.scxml.eventDescriptor"]) scxmlTransitions.push({
|
|
648
|
+
descriptor: type,
|
|
649
|
+
transition: transitionObject
|
|
650
|
+
});
|
|
651
|
+
else if (type === "*") pushOn("*");
|
|
652
|
+
else if (type.startsWith("xstate.done.state")) {
|
|
653
|
+
if (!onDone[type]) onDone[type] = [];
|
|
654
|
+
onDone[type].push(transitionObject);
|
|
655
|
+
} else if (type.startsWith("xstate.done.actor.") || type.startsWith("xstate.error.actor.") || type.startsWith("xstate.snapshot.actor.") || type.startsWith("xstate.snapshot.")) {
|
|
656
|
+
const verb = type.startsWith("xstate.done.actor.") ? "onDone" : type.startsWith("xstate.error.actor.") ? "onError" : "onSnapshot";
|
|
657
|
+
const invoke = findInvokeByActorId(node, type.startsWith("xstate.snapshot.") ? type.slice(16).replace(/^actor\./, "") : type.slice(type.lastIndexOf(".actor.") + 7));
|
|
658
|
+
if (invoke) nestInvoke(invoke.id, verb);
|
|
659
|
+
else pushOn(type);
|
|
660
|
+
} else pushOn(type);
|
|
661
|
+
}
|
|
662
|
+
const descriptorBase = (descriptor) => descriptor.replace(/\.\*$/, "");
|
|
663
|
+
const scxmlKeys = new Set([...Object.keys(on), ...scxmlTransitions.flatMap(({ descriptor }) => descriptor === "*" ? ["*"] : descriptorBase(descriptor) ? [descriptorBase(descriptor), `${descriptorBase(descriptor)}.*`] : [])]);
|
|
664
|
+
for (const key of scxmlKeys) {
|
|
665
|
+
const base = descriptorBase(key);
|
|
666
|
+
const matching = scxmlTransitions.filter(({ descriptor }) => {
|
|
667
|
+
const prefix = descriptorBase(descriptor);
|
|
668
|
+
return descriptor === "*" || base === prefix || base.startsWith(`${prefix}.`);
|
|
669
|
+
}).map(({ transition }) => transition);
|
|
670
|
+
on[key] = [...new Set([...on[key] ?? [], ...matching])].sort((a, b) => (transitionOrder.get(a) ?? 0) - (transitionOrder.get(b) ?? 0));
|
|
671
|
+
}
|
|
672
|
+
if (Object.keys(on).length > 0) nodeConfig.on = singleOrArrayRecord(on);
|
|
673
|
+
if (Object.keys(after).length > 0) nodeConfig.after = singleOrArrayRecord(after);
|
|
674
|
+
if (alwaysArr.length > 0) nodeConfig.always = singleOrArray(alwaysArr);
|
|
675
|
+
if (choiceArr.length > 0) nodeConfig.choice = singleOrArray(choiceArr);
|
|
676
|
+
if (Object.keys(onDone).length > 0) nodeConfig.onDone = singleOrArray(Object.values(onDone).flat());
|
|
677
|
+
if (onError.length > 0) nodeConfig.onError = singleOrArray(onError);
|
|
678
|
+
if (onTimeout.length > 0) nodeConfig.onTimeout = singleOrArray(onTimeout);
|
|
679
|
+
if (Object.keys(invokeMap).length > 0 && Array.isArray(nodeConfig.invoke)) nodeConfig.invoke = nodeConfig.invoke.map((inv, index) => {
|
|
680
|
+
const mapped = invokeMap[node.data.invokes?.[index]?.id ?? inv.id];
|
|
681
|
+
if (!mapped) return inv;
|
|
682
|
+
return {
|
|
683
|
+
...inv,
|
|
684
|
+
...mapped.onDone ? { onDone: singleOrArray(mapped.onDone) } : void 0,
|
|
685
|
+
...mapped.onError ? { onError: singleOrArray(mapped.onError) } : void 0,
|
|
686
|
+
...mapped.onSnapshot ? { onSnapshot: singleOrArray(mapped.onSnapshot) } : void 0,
|
|
687
|
+
...mapped.onTimeout ? { onTimeout: singleOrArray(mapped.onTimeout) } : void 0
|
|
688
|
+
};
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
if (Array.isArray(nodeConfig.invoke)) nodeConfig.invoke = nodeConfig.invoke.map((inv) => {
|
|
692
|
+
if (inv.id && !isAutoGeneratedId(inv.id)) return inv;
|
|
693
|
+
const { id: _id, ...rest } = inv;
|
|
694
|
+
return rest;
|
|
695
|
+
});
|
|
696
|
+
if (childNodes.length > 0) {
|
|
697
|
+
nodeConfig.states = {};
|
|
698
|
+
for (const childState of childNodes) nodeConfig.states[childState.data.key] = getNodeConfig(childState);
|
|
699
|
+
}
|
|
700
|
+
return nodeConfig;
|
|
701
|
+
}
|
|
702
|
+
const rootNode = graph.nodes.find((node) => node.parentId === null || node.parentId == null);
|
|
703
|
+
if (!rootNode) throw new Error("No root node found");
|
|
704
|
+
getNodeConfig(rootNode);
|
|
705
|
+
if (graph.data.context !== void 0 && graph.data.context !== null) config.context = graph.data.context;
|
|
706
|
+
if (graph.data.version) config.version = graph.data.version;
|
|
707
|
+
if (graph.data.options?.maxIterations !== void 0) config.options = { maxIterations: graph.data.options.maxIterations };
|
|
708
|
+
if (graph.data.internalEvents?.length) config.internalEvents = graph.data.internalEvents;
|
|
709
|
+
return deepSimplify(config);
|
|
710
|
+
}
|
|
711
|
+
var machineGraph_exports = /* @__PURE__ */ __exportAll({
|
|
712
|
+
applyDefaultInitialIds: () => applyDefaultInitialIds,
|
|
713
|
+
graphToNormalizedMachine: () => graphToNormalizedMachine,
|
|
714
|
+
machineConfigToGraph: () => machineConfigToGraph
|
|
715
|
+
});
|
|
716
|
+
/**
|
|
717
|
+
* A compound state node with no usable `initial` cannot be simulated (XState
|
|
718
|
+
* throws "No initial state specified for compound state node"). This walks a
|
|
719
|
+
* finished graph and defaults every such node's `initialId` to its first child,
|
|
720
|
+
* which also repairs `initial` references that resolved to no node at all.
|
|
721
|
+
*/
|
|
722
|
+
function applyDefaultInitialIds(nodes) {
|
|
723
|
+
const childrenByParentId = /* @__PURE__ */ new Map();
|
|
724
|
+
const nodeIds = new Set(nodes.map((node) => node.id));
|
|
725
|
+
for (const node of nodes) {
|
|
726
|
+
if (node.parentId === null || node.parentId === void 0) continue;
|
|
727
|
+
if (node.data.type === "annotation") continue;
|
|
728
|
+
const siblings = childrenByParentId.get(node.parentId);
|
|
729
|
+
if (siblings) siblings.push(node);
|
|
730
|
+
else childrenByParentId.set(node.parentId, [node]);
|
|
731
|
+
}
|
|
732
|
+
for (const node of nodes) {
|
|
733
|
+
const type = node.data.type;
|
|
734
|
+
if (type !== null && type !== void 0 && type !== "normal") continue;
|
|
735
|
+
if (node.data.initialId && nodeIds.has(node.data.initialId)) continue;
|
|
736
|
+
const firstChild = childrenByParentId.get(node.id)?.[0];
|
|
737
|
+
if (!firstChild) continue;
|
|
738
|
+
node.data.initialId = firstChild.id;
|
|
739
|
+
if ("initialNodeId" in node) node.initialNodeId = firstChild.id;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function toArray(value) {
|
|
743
|
+
return Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
744
|
+
}
|
|
745
|
+
function actionItems(value, idPrefix) {
|
|
746
|
+
return toArray(value).flat().map((item, index) => {
|
|
747
|
+
if (typeof item === "string") return {
|
|
748
|
+
id: `${idPrefix}-${index}`,
|
|
749
|
+
type: item
|
|
750
|
+
};
|
|
751
|
+
if (item && typeof item === "object" && "type" in item) {
|
|
752
|
+
const action = item;
|
|
753
|
+
if (typeof action.type === "string") return {
|
|
754
|
+
id: `${idPrefix}-${index}`,
|
|
755
|
+
type: action.type,
|
|
756
|
+
params: action.params
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
return null;
|
|
760
|
+
}).filter((item) => item !== null);
|
|
761
|
+
}
|
|
762
|
+
function invokeItems(value) {
|
|
763
|
+
return toArray(value).map((item, index) => {
|
|
764
|
+
if (typeof item === "string") return {
|
|
765
|
+
id: item || `invoke-${index}`,
|
|
766
|
+
src: item
|
|
767
|
+
};
|
|
768
|
+
if (!item || typeof item !== "object") return null;
|
|
769
|
+
const invoke = item;
|
|
770
|
+
const srcExpression = isCodeExpression(invoke.src) ? invoke.src : void 0;
|
|
771
|
+
if (typeof invoke.src !== "string" && !srcExpression) return null;
|
|
772
|
+
const src = typeof invoke.src === "string" ? invoke.src : "inline:";
|
|
773
|
+
return {
|
|
774
|
+
id: typeof invoke.id === "string" ? invoke.id : srcExpression ? `$auto-inline-${index}` : `$auto-invoke-${src || index}`,
|
|
775
|
+
...typeof invoke.id === "string" ? { invocationId: invoke.id } : {},
|
|
776
|
+
src,
|
|
777
|
+
...srcExpression ? { srcExpression } : {},
|
|
778
|
+
...typeof invoke.registryKey === "string" ? { registryKey: invoke.registryKey } : {},
|
|
779
|
+
...invoke.timeout !== void 0 ? { timeout: invoke.timeout } : {},
|
|
780
|
+
...invoke.input !== void 0 ? { input: invoke.input } : {},
|
|
781
|
+
...invoke.output !== void 0 ? { output: invoke.output } : {}
|
|
782
|
+
};
|
|
783
|
+
}).filter((item) => item !== null);
|
|
784
|
+
}
|
|
785
|
+
function transitionTargets(target) {
|
|
786
|
+
if (typeof target === "string") return [target];
|
|
787
|
+
if (Array.isArray(target)) return target.filter((item) => typeof item === "string");
|
|
788
|
+
return [];
|
|
789
|
+
}
|
|
790
|
+
function transitionObjects(value) {
|
|
791
|
+
return toArray(value).map((item) => {
|
|
792
|
+
if (typeof item === "string") return { target: item };
|
|
793
|
+
if (item && typeof item === "object") return item;
|
|
794
|
+
return {};
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
function guardObject(value) {
|
|
798
|
+
if (!value) return null;
|
|
799
|
+
if (typeof value === "string") return { type: value };
|
|
800
|
+
if (typeof value === "object" && "type" in value && typeof value.type === "string") {
|
|
801
|
+
const guard = value;
|
|
802
|
+
return {
|
|
803
|
+
type: guard.type,
|
|
804
|
+
code: guard.code,
|
|
805
|
+
params: guard.params
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
function implementationItems(value) {
|
|
811
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
812
|
+
return Object.entries(value).map(([name, body]) => ({
|
|
813
|
+
id: name,
|
|
814
|
+
name,
|
|
815
|
+
description: null,
|
|
816
|
+
paramsSchema: null,
|
|
817
|
+
code: typeof body === "string" || typeof body === "number" ? {
|
|
818
|
+
body: String(body),
|
|
819
|
+
lang: "ts"
|
|
820
|
+
} : isCodeExpression(body) ? {
|
|
821
|
+
body: body.expr,
|
|
822
|
+
lang: body.lang,
|
|
823
|
+
imports: body.imports
|
|
824
|
+
} : null
|
|
825
|
+
}));
|
|
826
|
+
}
|
|
827
|
+
function actorImplementationItems(value) {
|
|
828
|
+
return implementationItems(value).map((item) => ({
|
|
829
|
+
...item,
|
|
830
|
+
inputSchema: null,
|
|
831
|
+
outputSchema: null
|
|
832
|
+
}));
|
|
833
|
+
}
|
|
834
|
+
function machineConfigToGraph(config, options = {}) {
|
|
835
|
+
const rootState = config;
|
|
836
|
+
const rootConfig = config;
|
|
837
|
+
const rootKey = String(rootState.id ?? "machine");
|
|
838
|
+
const graph = {
|
|
839
|
+
id: "root",
|
|
840
|
+
nodes: [],
|
|
841
|
+
edges: [],
|
|
842
|
+
data: {
|
|
843
|
+
profile: normalizeProfileRef(options.profile ?? XSTATE_V5_PROFILE),
|
|
844
|
+
version: typeof rootConfig.version === "string" ? rootConfig.version : null,
|
|
845
|
+
options: rootConfig.options && typeof rootConfig.options === "object" && !Array.isArray(rootConfig.options) ? rootConfig.options : null,
|
|
846
|
+
internalEvents: Array.isArray(rootConfig.internalEvents) ? rootConfig.internalEvents.filter((event) => typeof event === "string") : null,
|
|
847
|
+
context: rootConfig.context && typeof rootConfig.context === "object" ? rootConfig.context : null,
|
|
848
|
+
implementations: {
|
|
849
|
+
actions: implementationItems(rootConfig.actions),
|
|
850
|
+
guards: implementationItems(rootConfig.guards),
|
|
851
|
+
actors: actorImplementationItems(rootConfig.actors ?? rootConfig.actorSources),
|
|
852
|
+
delays: implementationItems(rootConfig.delays)
|
|
853
|
+
},
|
|
854
|
+
schemas: config.schemas ?? null
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
const stateByGraphId = /* @__PURE__ */ new Map();
|
|
858
|
+
const explicitIdToGraphId = /* @__PURE__ */ new Map();
|
|
859
|
+
function initialParts(initial) {
|
|
860
|
+
return typeof initial === "string" ? {
|
|
861
|
+
target: initial,
|
|
862
|
+
input: void 0
|
|
863
|
+
} : initial && typeof initial === "object" ? {
|
|
864
|
+
target: initial.target,
|
|
865
|
+
input: initial.input
|
|
866
|
+
} : {
|
|
867
|
+
target: void 0,
|
|
868
|
+
input: void 0
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function collect(state, key, parentId) {
|
|
872
|
+
const id = parentId ? `${parentId}.${key}` : "root";
|
|
873
|
+
stateByGraphId.set(id, state);
|
|
874
|
+
if (state.id) explicitIdToGraphId.set(state.id.replace(/^#/, ""), id);
|
|
875
|
+
if (!parentId && state.id) explicitIdToGraphId.set(rootKey, id);
|
|
876
|
+
const initial = initialParts(state.initial);
|
|
877
|
+
graph.nodes.push({
|
|
878
|
+
id,
|
|
879
|
+
parentId,
|
|
880
|
+
data: {
|
|
881
|
+
nodeId: state.id ?? null,
|
|
882
|
+
key,
|
|
883
|
+
type: state.type === "parallel" || state.type === "final" || state.type === "history" || state.type === "choice" ? state.type : null,
|
|
884
|
+
initialId: null,
|
|
885
|
+
...initial.input !== void 0 ? { initialInput: initial.input } : {},
|
|
886
|
+
...state.timeout !== void 0 ? { timeout: state.timeout } : {},
|
|
887
|
+
...state.route !== void 0 ? { route: state.route } : {},
|
|
888
|
+
history: state.history ?? false,
|
|
889
|
+
...state.output !== void 0 ? { output: state.output } : {},
|
|
890
|
+
...parentId && state.schemas ? { schemas: state.schemas } : {},
|
|
891
|
+
entry: actionItems(state.entry, `${id}-entry`),
|
|
892
|
+
exit: actionItems(state.exit, `${id}-exit`),
|
|
893
|
+
invokes: invokeItems(state.invoke),
|
|
894
|
+
tags: Array.isArray(state.tags) ? state.tags : typeof state.tags === "string" ? [state.tags] : [],
|
|
895
|
+
description: state.description ?? null,
|
|
896
|
+
meta: state.meta ?? null
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
for (const [childKey, child] of Object.entries(state.states ?? {})) collect(child, childKey, id);
|
|
900
|
+
}
|
|
901
|
+
collect(rootState, rootKey, null);
|
|
902
|
+
function targetToNodeId(sourceId, target) {
|
|
903
|
+
if (!target) return sourceId;
|
|
904
|
+
if (target === ".") return sourceId;
|
|
905
|
+
if (target.startsWith(".")) return `${sourceId}${target}`;
|
|
906
|
+
if (target.startsWith("#")) {
|
|
907
|
+
const authored = target.slice(1);
|
|
908
|
+
const matchedId = [...explicitIdToGraphId.keys()].sort((a, b) => b.length - a.length).find((candidate) => authored === candidate || authored.startsWith(`${candidate}.`));
|
|
909
|
+
if (matchedId) {
|
|
910
|
+
const suffix = authored.slice(matchedId.length);
|
|
911
|
+
return `${explicitIdToGraphId.get(matchedId)}${suffix}`;
|
|
912
|
+
}
|
|
913
|
+
const rootPrefix = `${rootKey}.`;
|
|
914
|
+
const path = authored.startsWith(rootPrefix) ? authored.slice(rootPrefix.length) : authored;
|
|
915
|
+
return path ? `root.${path}` : "root";
|
|
916
|
+
}
|
|
917
|
+
return `${sourceId.split(".").slice(0, -1).join(".") || "root"}.${target}`;
|
|
918
|
+
}
|
|
919
|
+
function initialTargetToNodeId(sourceId, target) {
|
|
920
|
+
if (!target) return null;
|
|
921
|
+
if (target.startsWith("#")) return targetToNodeId(sourceId, target);
|
|
922
|
+
return `${sourceId}.${target.replace(/^\./, "")}`;
|
|
923
|
+
}
|
|
924
|
+
for (const node of graph.nodes) {
|
|
925
|
+
const state = stateByGraphId.get(node.id);
|
|
926
|
+
const historyTarget = transitionTargets(state.target)[0];
|
|
927
|
+
node.data.initialId = state.type === "history" ? historyTarget ? targetToNodeId(node.id, historyTarget) : null : initialTargetToNodeId(node.id, initialParts(state.initial).target);
|
|
928
|
+
}
|
|
929
|
+
applyDefaultInitialIds(graph.nodes);
|
|
930
|
+
function doneStateEventType(eventType) {
|
|
931
|
+
if (!eventType.startsWith("xstate.done.state.")) return null;
|
|
932
|
+
const stateId = eventType.slice(18);
|
|
933
|
+
const graphId = explicitIdToGraphId.get(stateId);
|
|
934
|
+
if (graphId) return `@statelyai.state.done.${graphId}`;
|
|
935
|
+
if (stateByGraphId.has(stateId)) return `@statelyai.state.done.${stateId}`;
|
|
936
|
+
const rootPrefix = `${rootKey}.`;
|
|
937
|
+
if (stateId.startsWith(rootPrefix)) {
|
|
938
|
+
const mapped = `root.${stateId.slice(rootPrefix.length)}`;
|
|
939
|
+
if (stateByGraphId.has(mapped)) return `@statelyai.state.done.${mapped}`;
|
|
940
|
+
}
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* `on: { 'xstate.done.actor.<invokeId>': ... }` is the same edge the exporter
|
|
945
|
+
* writes back as the invoke's `onDone`/`onError`, so it is stored as the
|
|
946
|
+
* canonical internal reference. Otherwise the two encodings do not
|
|
947
|
+
* round-trip.
|
|
948
|
+
*/
|
|
949
|
+
function invokeActorEventType(state, eventType) {
|
|
950
|
+
const match = /^xstate\.(done|error)\.actor\.(.+)$/.exec(eventType);
|
|
951
|
+
const snapshotMatch = /^xstate\.snapshot(?:\.actor)?\.(.+)$/.exec(eventType);
|
|
952
|
+
if (!match && !snapshotMatch) return null;
|
|
953
|
+
const verb = match?.[1] ?? "snapshot";
|
|
954
|
+
const actorId = match?.[2] ?? snapshotMatch?.[1];
|
|
955
|
+
const invoke = invokeItems(state.invoke).find((item) => item.invocationId === actorId);
|
|
956
|
+
if (!invoke) return null;
|
|
957
|
+
return `@statelyai.invoke.${verb}.${invoke.id}`;
|
|
958
|
+
}
|
|
959
|
+
function addTransitions(sourceId, value, eventType, idPrefix, extraData = {}) {
|
|
960
|
+
for (const [index, transition] of transitionObjects(value).entries()) {
|
|
961
|
+
const targets = transitionTargets(transition.target);
|
|
962
|
+
const target = targets[0];
|
|
963
|
+
const edgeId = `${sourceId}-${idPrefix}-${index}`;
|
|
964
|
+
graph.edges.push({
|
|
965
|
+
id: edgeId,
|
|
966
|
+
sourceId,
|
|
967
|
+
targetId: targetToNodeId(sourceId, target),
|
|
968
|
+
data: {
|
|
969
|
+
eventType,
|
|
970
|
+
...targets.length > 1 ? { additionalTargetIds: targets.slice(1).map((item) => targetToNodeId(sourceId, item)) } : {},
|
|
971
|
+
...transition.matches && typeof transition.matches === "object" ? { matches: transition.matches } : {},
|
|
972
|
+
transitionType: target ? transition.reenter ? "reenter" : "normal" : "targetless",
|
|
973
|
+
guard: guardObject(transition.guard),
|
|
974
|
+
...transition.context !== void 0 ? { context: transition.context } : {},
|
|
975
|
+
...transition.input !== void 0 ? { input: transition.input } : {},
|
|
976
|
+
actions: actionItems(transition.actions, `${edgeId}-actions`),
|
|
977
|
+
description: transition.meta && typeof transition.meta === "object" && Object.prototype.hasOwnProperty.call(transition.meta, XSTATE_V6_BRANCH_DESCRIPTION_META) ? typeof transition.meta[XSTATE_V6_BRANCH_DESCRIPTION_META] === "string" ? transition.meta[XSTATE_V6_BRANCH_DESCRIPTION_META] : null : typeof transition.description === "string" ? transition.description : null,
|
|
978
|
+
meta: transition.meta && typeof transition.meta === "object" ? transition.meta : null,
|
|
979
|
+
...extraData
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
for (const node of graph.nodes) {
|
|
985
|
+
const id = node.id;
|
|
986
|
+
const state = stateByGraphId.get(id);
|
|
987
|
+
for (const [eventType, value] of Object.entries(state.on ?? {})) addTransitions(id, value, doneStateEventType(eventType) ?? invokeActorEventType(state, eventType) ?? eventType, eventType);
|
|
988
|
+
for (const [delay, value] of Object.entries(state.after ?? {})) addTransitions(id, value, `xstate.after.${delay}.${id}`, `after-${delay}`);
|
|
989
|
+
addTransitions(id, state.always, "", "always");
|
|
990
|
+
addTransitions(id, state.choice, "", "choice");
|
|
991
|
+
addTransitions(id, state.onDone, `@statelyai.state.done.${id}`, "state-done");
|
|
992
|
+
addTransitions(id, state.onError, `@statelyai.state.error.${id}`, "state-error");
|
|
993
|
+
addTransitions(id, state.onTimeout, `@statelyai.state.timeout.${id}`, "state-timeout");
|
|
994
|
+
const invokes = invokeItems(state.invoke);
|
|
995
|
+
for (const [invokeIndex, rawInvoke] of toArray(state.invoke).entries()) {
|
|
996
|
+
if (!rawInvoke || typeof rawInvoke !== "object") continue;
|
|
997
|
+
const invoke = invokes[invokeIndex];
|
|
998
|
+
if (!invoke) continue;
|
|
999
|
+
const invokeConfig = rawInvoke;
|
|
1000
|
+
for (const [slot, refSlot] of [
|
|
1001
|
+
["onDone", "done"],
|
|
1002
|
+
["onError", "error"],
|
|
1003
|
+
["onSnapshot", "snapshot"],
|
|
1004
|
+
["onTimeout", "timeout"]
|
|
1005
|
+
]) addTransitions(id, invokeConfig[slot], `@statelyai.invoke.${refSlot}.${invoke.id}`, `invoke-${invoke.id}-${refSlot}`);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
for (const node of graph.nodes) {
|
|
1009
|
+
if (node.id === "root" || node.data.route === void 0) continue;
|
|
1010
|
+
const route = node.data.route;
|
|
1011
|
+
addTransitions("root", {
|
|
1012
|
+
...isCodeExpression(route) ? {} : route && typeof route === "object" ? route : {},
|
|
1013
|
+
target: `#${node.data.nodeId ?? node.id}`
|
|
1014
|
+
}, "xstate.route", `route-${node.id}`, { route: true });
|
|
1015
|
+
}
|
|
1016
|
+
return graph;
|
|
1017
|
+
}
|
|
1018
|
+
function graphToNormalizedMachine(graph) {
|
|
1019
|
+
return graphToMachineConfig(graph);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
//#endregion
|
|
1023
|
+
export { graphToNormalizedMachine as a, normalizeProfileRef as c, graphToMachineConfig as i, stripExportDefault as l, getDelayKeyFromEventType as n, machineConfigToGraph as o, getResolvedNodeId as r, machineGraph_exports as s, applyDefaultInitialIds as t };
|