@statelyai/sdk 0.5.1 → 0.6.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/dist/embed.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as EmbedMode, c as ExportFormatMap, f as UploadResult, i as EmbedEventName, l as InitOptions, n as EmbedEventHandler, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat, t as CommentsConfig, u as MachineSourceLocations } from "./protocol-BPuwbNCz.mjs";
1
+ import { a as EmbedMode, c as ExportFormatMap, d as MachineSourceLocations, f as ProjectEmbedMachine, i as EmbedEventName, l as InitOptions, m as UploadResult, n as EmbedEventHandler, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat, t as CommentsConfig, u as MachineInitOptions } from "./protocol-CEbWQPYe.mjs";
2
2
 
3
3
  //#region src/embed.d.ts
4
4
  interface AssetConfig {
@@ -21,10 +21,24 @@ interface AssetConfig {
21
21
  */
22
22
  maxFileSize?: number;
23
23
  }
24
- interface StatelyEmbedOptions {
24
+ interface StatelyEmbedOptions extends Partial<MachineInitOptions> {
25
25
  baseUrl: string;
26
26
  apiKey?: string;
27
27
  origin?: string;
28
+ /**
29
+ * Optional iframe to attach to immediately. Equivalent to calling
30
+ * `embed.attach(iframe)` after construction.
31
+ */
32
+ iframe?: HTMLIFrameElement;
33
+ /**
34
+ * Project mode: pass machines instead of `machine`. If set, an init is
35
+ * auto-sent on attach using these machines.
36
+ */
37
+ machines?: ProjectEmbedMachine[];
38
+ /** Project mode only — initially selected machine id. */
39
+ currentMachineId?: string;
40
+ /** Project mode only — initial comments keyed by machine id. */
41
+ commentsByMachineId?: Record<string, CommentsConfig>;
28
42
  /** Asset upload configuration. If omitted, files are stored as base64 data URLs. */
29
43
  assets?: AssetConfig;
30
44
  onReady?: () => void;
@@ -45,6 +59,10 @@ interface StatelyEmbed {
45
59
  init(options: InitOptions): void;
46
60
  /** Update the machine (shorthand for update message). */
47
61
  updateMachine(machine: unknown, format?: string, sourceLocations?: MachineSourceLocations): void;
62
+ /** Update the project machine list without re-creating the iframe. */
63
+ updateProject(machines: ProjectEmbedMachine[], currentMachineId?: string, commentsByMachineId?: Record<string, CommentsConfig>): void;
64
+ /** Select the active machine in project mode. */
65
+ selectMachine(machineId: string): void;
48
66
  /** Change the embed mode. */
49
67
  setMode(mode: EmbedMode): void;
50
68
  /** Change the embed theme. */
@@ -64,4 +82,4 @@ interface StatelyEmbed {
64
82
  }
65
83
  declare function createStatelyEmbed(options: StatelyEmbedOptions): StatelyEmbed;
66
84
  //#endregion
67
- export { AssetConfig, type CommentsConfig, type EmbedEventHandler, type EmbedEventMap, type EmbedEventName, type EmbedMode, type ExportCallOptions, type ExportFormat, type ExportFormatMap, type InitOptions, type MachineSourceLocations, StatelyEmbed, StatelyEmbedOptions, type UploadResult, createStatelyEmbed };
85
+ export { AssetConfig, type CommentsConfig, type EmbedEventHandler, type EmbedEventMap, type EmbedEventName, type EmbedMode, type ExportCallOptions, type ExportFormat, type ExportFormatMap, type InitOptions, type MachineInitOptions, type MachineSourceLocations, type ProjectEmbedMachine, StatelyEmbed, StatelyEmbedOptions, type UploadResult, createStatelyEmbed };
package/dist/embed.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as toInitMessage, i as createPendingExportManager, r as createEventRegistry, t as createPostMessageTransport } from "./transport-DoCHBLTu.mjs";
1
+ import { a as toInitMessage, i as createPendingExportManager, r as createEventRegistry, t as createPostMessageTransport } from "./transport-C0eTgNNu.mjs";
2
2
 
3
3
  //#region src/embed.ts
4
4
  function buildEmbedUrl(options) {
@@ -7,6 +7,32 @@ function buildEmbedUrl(options) {
7
7
  if (options.apiKey) url.searchParams.set("api_key", options.apiKey);
8
8
  return url.toString();
9
9
  }
10
+ function extractInitOptions(options) {
11
+ if (options.machines) return {
12
+ machines: options.machines,
13
+ currentMachineId: options.currentMachineId,
14
+ mode: options.mode,
15
+ theme: options.theme,
16
+ readOnly: options.readOnly,
17
+ depth: options.depth,
18
+ panels: options.panels,
19
+ commentsByMachineId: options.commentsByMachineId,
20
+ unsavedIndicator: options.unsavedIndicator
21
+ };
22
+ if (options.machine !== void 0) return {
23
+ machine: options.machine,
24
+ format: options.format,
25
+ mode: options.mode,
26
+ theme: options.theme,
27
+ readOnly: options.readOnly,
28
+ depth: options.depth,
29
+ panels: options.panels,
30
+ comments: options.comments,
31
+ sourceLocations: options.sourceLocations,
32
+ unsavedIndicator: options.unsavedIndicator
33
+ };
34
+ return null;
35
+ }
10
36
  function createStatelyEmbed(options) {
11
37
  const embedUrl = buildEmbedUrl(options);
12
38
  const targetOrigin = options.origin ?? "*";
@@ -52,6 +78,7 @@ function createStatelyEmbed(options) {
52
78
  options.onLoaded?.(loaded.graph);
53
79
  events.emit("loaded", {
54
80
  graph: loaded.graph,
81
+ machineId: loaded.machineId,
55
82
  sourceLocations: loaded.sourceLocations
56
83
  });
57
84
  break;
@@ -62,6 +89,7 @@ function createStatelyEmbed(options) {
62
89
  events.emit("change", {
63
90
  graph: change.graph,
64
91
  machineConfig: change.machineConfig,
92
+ machineId: change.machineId,
65
93
  patches: change.patches,
66
94
  sourceLocations: change.sourceLocations
67
95
  });
@@ -73,12 +101,16 @@ function createStatelyEmbed(options) {
73
101
  events.emit("save", {
74
102
  graph: save.graph,
75
103
  machineConfig: save.machineConfig,
104
+ machineId: save.machineId,
76
105
  patches: save.patches,
77
106
  validations: save.validations,
78
107
  sourceLocations: save.sourceLocations
79
108
  });
80
109
  break;
81
110
  }
111
+ case "@statelyai.project.machineSelected":
112
+ events.emit("machineSelected", { machineId: String(data.machineId) });
113
+ break;
82
114
  case "@statelyai.retrieved": {
83
115
  const retrieved = data;
84
116
  exportManager.resolve(retrieved.requestId, retrieved.data);
@@ -151,7 +183,7 @@ function createStatelyEmbed(options) {
151
183
  nextTransport.onMessage(handleMessage);
152
184
  nextTransport.onReady(flush);
153
185
  }
154
- return {
186
+ const embed = {
155
187
  attach(el) {
156
188
  if (destroyed) return;
157
189
  const currentSrc = el.getAttribute("src");
@@ -190,6 +222,20 @@ function createStatelyEmbed(options) {
190
222
  sourceLocations
191
223
  });
192
224
  },
225
+ updateProject(machines, currentMachineId, commentsByMachineId) {
226
+ send({
227
+ type: "@statelyai.project.update",
228
+ machines,
229
+ currentMachineId,
230
+ commentsByMachineId
231
+ });
232
+ },
233
+ selectMachine(machineId) {
234
+ send({
235
+ type: "@statelyai.project.selectMachine",
236
+ machineId
237
+ });
238
+ },
193
239
  setMode(mode) {
194
240
  send({
195
241
  type: "@statelyai.setMode",
@@ -236,6 +282,10 @@ function createStatelyEmbed(options) {
236
282
  iframe = null;
237
283
  }
238
284
  };
285
+ if (options.iframe) embed.attach(options.iframe);
286
+ const autoInit = extractInitOptions(options);
287
+ if (autoInit) embed.init(autoInit);
288
+ return embed;
239
289
  }
240
290
 
241
291
  //#endregion
package/dist/graph.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as studioMachineConverter, a as StatelyGraphData, c as StatelyInvoke, d as StudioAction, f as StudioEdge, g as fromStudioMachine, h as StudioNode, i as StatelyGraph, l as StatelyNodeData, m as StudioMachine, n as StatelyActorImplementation, o as StatelyGuard, p as StudioEventTypeData, r as StatelyEdgeData, s as StatelyImplementation, t as StatelyAction, u as StatelyTagImplementation, v as toStudioMachine } from "./graph-BfezxFKJ.mjs";
1
+ import { _ as studioMachineConverter, a as StatelyGraphData, c as StatelyInvoke, d as StudioAction, f as StudioEdge, g as fromStudioMachine, h as StudioNode, i as StatelyGraph, l as StatelyNodeData, m as StudioMachine, n as StatelyActorImplementation, o as StatelyGuard, p as StudioEventTypeData, r as StatelyEdgeData, s as StatelyImplementation, t as StatelyAction, u as StatelyTagImplementation, v as toStudioMachine } from "./graph-CB-ALrdk.mjs";
2
2
  export { StatelyAction, StatelyActorImplementation, StatelyEdgeData, StatelyGraph, StatelyGraphData, StatelyGuard, StatelyImplementation, StatelyInvoke, StatelyNodeData, StatelyTagImplementation, StudioAction, StudioEdge, StudioEventTypeData, StudioMachine, StudioNode, fromStudioMachine, studioMachineConverter, toStudioMachine };
package/dist/graph.mjs CHANGED
@@ -2,6 +2,9 @@ import { createFormatConverter, createGraph } from "@statelyai/graph";
2
2
 
3
3
  //#region src/graph.ts
4
4
  const EXPR_ACTION_TYPE = "xstate.expr";
5
+ function stripExportDefault(code) {
6
+ return code.match(/^export\s+default\s+(.+)/s)?.[1]?.trim() ?? code.trim();
7
+ }
5
8
  function toJsonObject(value) {
6
9
  return value;
7
10
  }
@@ -126,7 +129,7 @@ function toStudioAction(action) {
126
129
  }
127
130
  };
128
131
  }
129
- function fromStudioAction(action) {
132
+ function fromStudioAction(action, actionImplementations) {
130
133
  if (action.kind === "inline") return {
131
134
  type: EXPR_ACTION_TYPE,
132
135
  params: {
@@ -134,6 +137,16 @@ function fromStudioAction(action) {
134
137
  lang: "ts"
135
138
  }
136
139
  };
140
+ if (action.action.type.startsWith("inline:") && actionImplementations?.[action.action.type]?.code) {
141
+ const implementation = actionImplementations[action.action.type];
142
+ return {
143
+ type: EXPR_ACTION_TYPE,
144
+ params: {
145
+ code: stripExportDefault(implementation.code),
146
+ lang: "ts"
147
+ }
148
+ };
149
+ }
137
150
  if ("params" in action.action && action.action.params) return {
138
151
  type: action.action.type,
139
152
  params: toUnknownRecord(action.action.params)
@@ -204,7 +217,7 @@ function toStudioNode(graph, nodeId, pathIds, parentPath) {
204
217
  nodes: childNodes
205
218
  };
206
219
  }
207
- function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId) {
220
+ function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId, actionImplementations) {
208
221
  const nodeId = studioNode.id;
209
222
  pathIdToNodeId.set(studioNode.id, nodeId);
210
223
  const initialId = studioNode.data.initial ? `${studioNode.id}.${studioNode.data.initial}` : void 0;
@@ -227,8 +240,8 @@ function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId) {
227
240
  ...normalizeStudioNodeType(studioNode.data.type) ? { type: normalizeStudioNodeType(studioNode.data.type) } : {},
228
241
  ...studioNode.data.history ? { history: studioNode.data.history } : {},
229
242
  ...initialId ? { initialId } : {},
230
- entry: studioNode.data.entry.map(fromStudioAction),
231
- exit: studioNode.data.exit.map(fromStudioAction),
243
+ entry: studioNode.data.entry.map((action) => fromStudioAction(action, actionImplementations)),
244
+ exit: studioNode.data.exit.map((action) => fromStudioAction(action, actionImplementations)),
232
245
  invokes: studioNode.data.invoke.map((invoke) => ({
233
246
  src: invoke.src,
234
247
  id: invoke.id,
@@ -240,7 +253,7 @@ function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId) {
240
253
  ...studioNode.data.metaEntries ? { meta: Object.fromEntries(studioNode.data.metaEntries) } : {}
241
254
  }
242
255
  });
243
- studioNode.nodes.forEach((child) => flattenStudioNodes(child, nodeId, nodes, pathIdToNodeId));
256
+ studioNode.nodes.forEach((child) => flattenStudioNodes(child, nodeId, nodes, pathIdToNodeId, actionImplementations));
244
257
  }
245
258
  function toStudioMachine(graph) {
246
259
  const rootNode = graph.nodes.find((node) => node.parentId == null);
@@ -298,7 +311,7 @@ function toStudioMachine(graph) {
298
311
  function fromStudioMachine(studioMachine) {
299
312
  const nodes = [];
300
313
  const pathIdToNodeId = /* @__PURE__ */ new Map();
301
- flattenStudioNodes(studioMachine.rootNode, null, nodes, pathIdToNodeId);
314
+ flattenStudioNodes(studioMachine.rootNode, null, nodes, pathIdToNodeId, studioMachine.implementations?.actions);
302
315
  const edges = studioMachine.edges.map((edge) => ({
303
316
  type: "edge",
304
317
  id: edge.id,
@@ -321,7 +334,7 @@ function fromStudioMachine(studioMachine) {
321
334
  params: toUnknownRecord(edge.data.guard.params),
322
335
  ...edge.data.guard.kind === "inline" ? { code: edge.data.guard.type } : {}
323
336
  } } : {},
324
- actions: edge.data.actions.map(fromStudioAction),
337
+ actions: edge.data.actions.map((action) => fromStudioAction(action, studioMachine.implementations?.actions)),
325
338
  ...edge.data.description ? { description: edge.data.description } : {},
326
339
  ...edge.data.color ? { color: edge.data.color } : {},
327
340
  ...edge.data.metaEntries ? { meta: Object.fromEntries(edge.data.metaEntries) } : {}
@@ -0,0 +1,344 @@
1
+ import ts from "typescript";
2
+ import { RawCode, graphToMachineConfig, raw, serializeJS } from "@statelyai/graph-tools";
3
+
4
+ //#region src/statelyPragma.ts
5
+ function findStatelyPragmaAttachments(sourceText, fileName = "machine.ts") {
6
+ const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
7
+ const attachments = [];
8
+ const visit = (node) => {
9
+ if (ts.isCallExpression(node) && isCreateMachineExpression(node.expression)) {
10
+ const attachNode = findAttachNode(node);
11
+ if (attachNode) attachments.push({
12
+ machineStart: getMachineExpressionStart(node.expression, sourceFile),
13
+ attachStart: attachNode.getStart(sourceFile),
14
+ pragma: findAttachedStatelyPragma(sourceText, attachNode)
15
+ });
16
+ }
17
+ ts.forEachChild(node, visit);
18
+ };
19
+ visit(sourceFile);
20
+ return attachments;
21
+ }
22
+ function getStatelyPragma(sourceText, fileName = "machine.ts", machineIndex = 0) {
23
+ return findStatelyPragmaAttachments(sourceText, fileName)[machineIndex]?.pragma;
24
+ }
25
+ function upsertStatelyPragma(sourceText, id, options = {}) {
26
+ const attachment = findStatelyPragmaAttachments(sourceText, options.fileName ?? "machine.ts")[options.machineIndex ?? 0];
27
+ if (!attachment) return sourceText;
28
+ const lineEnding = options.lineEnding ?? detectLineEnding(sourceText);
29
+ const canonicalComment = `// @statelyai id=${id}`;
30
+ if (attachment.pragma) return sourceText.slice(0, attachment.pragma.start) + canonicalComment + sourceText.slice(attachment.pragma.end);
31
+ const insertText = `${getIndentationAtOffset(sourceText, attachment.attachStart)}${canonicalComment}${lineEnding}`;
32
+ return sourceText.slice(0, attachment.attachStart) + insertText + sourceText.slice(attachment.attachStart);
33
+ }
34
+ function findAttachedStatelyPragma(sourceText, node) {
35
+ const comments = ts.getLeadingCommentRanges(sourceText, node.getFullStart()) ?? [];
36
+ for (let index = comments.length - 1; index >= 0; index -= 1) {
37
+ const comment = comments[index];
38
+ const parsed = parseStatelyPragma(sourceText, comment.pos, comment.end);
39
+ if (parsed) return parsed;
40
+ }
41
+ }
42
+ function parseStatelyPragma(sourceText, start, end) {
43
+ const match = normalizeCommentContent(sourceText.slice(start, end)).match(/^@statelyai(?:\s+(.*))?$/s);
44
+ if (!match) return;
45
+ const fields = parseFields(match[1] ?? "");
46
+ return {
47
+ tag: "@statelyai",
48
+ id: fields.id,
49
+ fields,
50
+ start,
51
+ end
52
+ };
53
+ }
54
+ function normalizeCommentContent(rawComment) {
55
+ if (rawComment.startsWith("//")) return rawComment.slice(2).trim();
56
+ if (rawComment.startsWith("/*")) return rawComment.slice(2, rawComment.endsWith("*/") ? -2 : void 0).split(/\r?\n/).map((line) => line.replace(/^\s*\*\s?/, "")).join(" ").trim();
57
+ return rawComment.trim();
58
+ }
59
+ function parseFields(input) {
60
+ const fields = {};
61
+ for (const token of input.split(/\s+/)) {
62
+ if (!token) continue;
63
+ const equalsIndex = token.indexOf("=");
64
+ if (equalsIndex <= 0) continue;
65
+ const key = token.slice(0, equalsIndex);
66
+ const value = token.slice(equalsIndex + 1);
67
+ if (!key || !value) continue;
68
+ fields[key] = value;
69
+ }
70
+ return fields;
71
+ }
72
+ function findAttachNode(node) {
73
+ let current = node;
74
+ while (current?.parent) {
75
+ if (ts.isVariableStatement(current.parent) || ts.isExpressionStatement(current.parent) || ts.isExportAssignment(current.parent)) return current.parent;
76
+ current = current.parent;
77
+ }
78
+ return current;
79
+ }
80
+ function isCreateMachineExpression(expression) {
81
+ return ts.isIdentifier(expression) && expression.text === "createMachine" || ts.isPropertyAccessExpression(expression) && expression.name.text === "createMachine";
82
+ }
83
+ function getMachineExpressionStart(expression, sourceFile) {
84
+ if (ts.isPropertyAccessExpression(expression)) return expression.name.getStart(sourceFile);
85
+ return expression.getStart(sourceFile);
86
+ }
87
+ function getIndentationAtOffset(sourceText, offset) {
88
+ const lineStart = sourceText.lastIndexOf("\n", Math.max(0, offset - 1)) + 1;
89
+ return sourceText.slice(lineStart, offset).match(/^[ \t]*/)?.[0] ?? "";
90
+ }
91
+ function detectLineEnding(sourceText) {
92
+ return sourceText.includes("\r\n") ? "\r\n" : "\n";
93
+ }
94
+ function getScriptKind(fileName) {
95
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
96
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
97
+ if (fileName.endsWith(".js")) return ts.ScriptKind.JS;
98
+ return ts.ScriptKind.TS;
99
+ }
100
+
101
+ //#endregion
102
+ //#region src/jsonSchemaToTSType.ts
103
+ function jsonSchemaToTSType(schema) {
104
+ if (!schema) return "unknown";
105
+ if (schema.enum) return schema.enum.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
106
+ if (schema.const !== void 0) return typeof schema.const === "string" ? `'${schema.const}'` : String(schema.const);
107
+ if (schema.oneOf) return schema.oneOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" | ");
108
+ if (schema.anyOf) return schema.anyOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" | ");
109
+ if (schema.allOf) return schema.allOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" & ");
110
+ if (schema.type === "array") return `Array<${jsonSchemaToTSType(resolveDef(schema.items))}>`;
111
+ if (Array.isArray(schema.type)) return schema.type.map((t) => primitiveType(t)).join(" | ");
112
+ if (schema.type === "object" || schema.properties) return objectType(schema);
113
+ if (schema.type) return primitiveType(schema.type);
114
+ return "unknown";
115
+ }
116
+ function primitiveType(type) {
117
+ switch (type) {
118
+ case "string": return "string";
119
+ case "number":
120
+ case "integer": return "number";
121
+ case "boolean": return "boolean";
122
+ case "null": return "null";
123
+ default: return "unknown";
124
+ }
125
+ }
126
+ function objectType(schema) {
127
+ const props = schema.properties;
128
+ if (!props || Object.keys(props).length === 0) {
129
+ if (schema.additionalProperties) return `Record<string, ${jsonSchemaToTSType(resolveDef(schema.additionalProperties))}>`;
130
+ return "Record<string, unknown>";
131
+ }
132
+ const required = new Set(schema.required ?? []);
133
+ return `{ ${Object.entries(props).map(([key, def]) => {
134
+ const type = jsonSchemaToTSType(resolveDef(def));
135
+ return `${key}${required.has(key) ? "" : "?"}: ${type}`;
136
+ }).join("; ")} }`;
137
+ }
138
+ function resolveDef(def) {
139
+ if (!def) return void 0;
140
+ if (Array.isArray(def)) return resolveDef(def[0]);
141
+ if (typeof def === "boolean") return void 0;
142
+ return def;
143
+ }
144
+ /**
145
+ * Build an inline context type string from the schemas.context record.
146
+ * Each key is a context property name, value is its JSONSchema7.
147
+ */
148
+ function contextSchemaToTSType(context) {
149
+ if (!context || Object.keys(context).length === 0) return null;
150
+ return `{ ${Object.entries(context).map(([key, schema]) => {
151
+ return `${key}: ${jsonSchemaToTSType(schema)}`;
152
+ }).join("; ")} }`;
153
+ }
154
+ /**
155
+ * Build an event union type from the schemas.events record.
156
+ * Each key is the event type name, value describes the payload properties.
157
+ */
158
+ function eventsSchemaToTSType(events) {
159
+ if (!events || Object.keys(events).length === 0) return null;
160
+ return Object.entries(events).map(([eventType, schema]) => {
161
+ const props = schema.properties;
162
+ if (!props || Object.keys(props).length === 0) return `{ type: '${eventType}' }`;
163
+ const required = new Set(schema.required ?? []);
164
+ const extraProps = Object.entries(props).filter(([k]) => k !== "type").map(([key, def]) => {
165
+ const type = jsonSchemaToTSType(resolveDef(def));
166
+ return `${key}${required.has(key) ? "" : "?"}: ${type}`;
167
+ });
168
+ if (extraProps.length === 0) return `{ type: '${eventType}' }`;
169
+ return `{ type: '${eventType}'; ${extraProps.join("; ")} }`;
170
+ }).join("\n | ");
171
+ }
172
+
173
+ //#endregion
174
+ //#region src/textUtils.ts
175
+ /**
176
+ * Pure string utilities used by codegen.
177
+ */
178
+ /**
179
+ * Removes common leading whitespace from all non-empty lines.
180
+ */
181
+ function dedent(text) {
182
+ const lines = text.split("\n");
183
+ const nonEmptyLines = lines.filter((l) => l.trim().length > 0);
184
+ if (nonEmptyLines.length === 0) return text;
185
+ const minIndent = Math.min(...nonEmptyLines.map((l) => l.match(/^(\s*)/)[1].length));
186
+ if (minIndent === 0) return text;
187
+ return lines.map((l) => l.trim().length > 0 ? l.slice(minIndent) : l).join("\n");
188
+ }
189
+ /**
190
+ * Strips `export default` wrapper from an expression string.
191
+ * E.g. `"export default assign({ ... })"` → `"assign({ ... })"`
192
+ */
193
+ function stripExportDefault(code) {
194
+ const trimmed = code.trim();
195
+ if (trimmed.startsWith("export default ")) return trimmed.slice(15).replace(/;$/, "");
196
+ return trimmed;
197
+ }
198
+
199
+ //#endregion
200
+ //#region src/graphToXStateTS.ts
201
+ function graphToXStateTS(graph, options = {}) {
202
+ const { exportStyle = "named", ...configOptions } = options;
203
+ const schemas = graph.data.schemas;
204
+ const impls = graph.data.implementations;
205
+ const hasSchemas = !!(schemas && (schemas.context || schemas.events || schemas.input || schemas.output));
206
+ const hasActions = !!impls?.actions.length;
207
+ const hasGuards = !!impls?.guards.length;
208
+ const hasActors = !!impls?.actors.length;
209
+ const hasDelays = !!impls?.delays.length;
210
+ const hasSetup = hasSchemas || hasActions || hasGuards || hasActors || hasDelays;
211
+ const builtInActions = getUsedBuiltInActions(graph);
212
+ const imports = buildImports({
213
+ hasSetup,
214
+ hasActors,
215
+ actors: impls?.actors ?? [],
216
+ builtInActions
217
+ });
218
+ const machineConfig = graphToMachineConfig(graph, configOptions);
219
+ let machineExpr;
220
+ if (hasSetup) {
221
+ const setupObj = buildSetupObject(schemas, impls);
222
+ const configStr = serializeJS(machineConfig, 2);
223
+ machineExpr = `setup(${serializeJS(setupObj, 0)}).createMachine(${configStr})`;
224
+ } else machineExpr = `createMachine(${serializeJS(machineConfig, 0)})`;
225
+ const lines = [];
226
+ lines.push(imports);
227
+ lines.push("");
228
+ lines.push(`const machine = ${machineExpr};`);
229
+ if (exportStyle === "named") {
230
+ lines.push("");
231
+ lines.push("export { machine };");
232
+ } else if (exportStyle === "default") {
233
+ lines.push("");
234
+ lines.push("export default machine;");
235
+ }
236
+ return lines.join("\n") + "\n";
237
+ }
238
+ /** Map from xstate action type to the import name */
239
+ const BUILTIN_ACTION_IMPORTS = {
240
+ "xstate.raise": "raise",
241
+ "xstate.sendTo": "sendTo",
242
+ "xstate.cancel": "cancel",
243
+ "xstate.emit": "emit",
244
+ "xstate.spawnChild": "spawnChild",
245
+ "xstate.stopChild": "stopChild",
246
+ "xstate.log": "log",
247
+ "xstate.assign": "assign"
248
+ };
249
+ /** Check inline action/entry/exit code for references to xstate builtins */
250
+ function scanInlineCodeForBuiltins(code, used) {
251
+ const expr = stripExportDefault(code);
252
+ for (const importName of Object.values(BUILTIN_ACTION_IMPORTS)) if (new RegExp(`\\b${importName}\\b`).test(expr)) used.add(importName);
253
+ }
254
+ function getExprActionCode(action) {
255
+ return action.type === "xstate.expr" && typeof action.params?.code === "string" ? action.params.code : void 0;
256
+ }
257
+ function getUsedBuiltInActions(graph) {
258
+ const used = /* @__PURE__ */ new Set();
259
+ for (const node of graph.nodes) for (const action of [...node.data.entry ?? [], ...node.data.exit ?? []]) {
260
+ const imp = BUILTIN_ACTION_IMPORTS[action.type];
261
+ if (imp) used.add(imp);
262
+ const exprCode = getExprActionCode(action);
263
+ if (exprCode) scanInlineCodeForBuiltins(exprCode, used);
264
+ }
265
+ for (const edge of graph.edges) for (const action of edge.data.actions ?? []) {
266
+ const imp = BUILTIN_ACTION_IMPORTS[action.type];
267
+ if (imp) used.add(imp);
268
+ const exprCode = getExprActionCode(action);
269
+ if (exprCode) scanInlineCodeForBuiltins(exprCode, used);
270
+ }
271
+ return used;
272
+ }
273
+ function buildImports({ hasSetup, hasActors, actors, builtInActions }) {
274
+ const xstateImports = [];
275
+ if (hasSetup) xstateImports.push("setup");
276
+ else xstateImports.push("createMachine");
277
+ for (const name of builtInActions) xstateImports.push(name);
278
+ if (hasActors) {
279
+ if (actors.some((a) => a.code?.body)) xstateImports.push("fromPromise");
280
+ }
281
+ return `import { ${xstateImports.join(", ")} } from 'xstate';`;
282
+ }
283
+ function buildSetupObject(schemas, impls) {
284
+ const setup = {};
285
+ const types = buildTypesBlock(schemas);
286
+ if (types) setup.types = types;
287
+ if (impls?.actions.length) setup.actions = buildActionsBlock(impls.actions);
288
+ if (impls?.guards.length) setup.guards = buildGuardsBlock(impls.guards);
289
+ if (impls?.actors.length) setup.actors = buildActorsBlock(impls.actors);
290
+ if (impls?.delays.length) setup.delays = buildDelaysBlock(impls.delays);
291
+ return setup;
292
+ }
293
+ function buildTypesBlock(schemas) {
294
+ if (!schemas) return void 0;
295
+ const types = {};
296
+ const contextType = contextSchemaToTSType(schemas.context);
297
+ if (contextType) types.context = raw(`{} as ${contextType}`);
298
+ const eventsType = eventsSchemaToTSType(schemas.events);
299
+ if (eventsType) types.events = raw(`{} as\n | ${eventsType}`);
300
+ if (schemas.input) types.input = raw(`{} as ${jsonSchemaToTSType(schemas.input)}`);
301
+ if (schemas.output) types.output = raw(`{} as ${jsonSchemaToTSType(schemas.output)}`);
302
+ return Object.keys(types).length > 0 ? types : void 0;
303
+ }
304
+ function hasSchemaProperties(schema) {
305
+ if (!schema) return false;
306
+ if (schema.type === "object" || schema.properties) {
307
+ const props = schema.properties;
308
+ return !!props && Object.keys(props).length > 0;
309
+ }
310
+ return true;
311
+ }
312
+ function buildActionsBlock(actions) {
313
+ const block = {};
314
+ for (const implementation of actions) if (implementation.code?.body) {
315
+ const params = hasSchemaProperties(implementation.paramsSchema) ? `, params: ${jsonSchemaToTSType(implementation.paramsSchema)}` : "";
316
+ block[implementation.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(implementation.code.body)}\n}`);
317
+ } else block[implementation.name] = raw(`function ({ context, event }) {\n // TODO: implement ${implementation.name}\n}`);
318
+ return block;
319
+ }
320
+ function buildGuardsBlock(guards) {
321
+ const block = {};
322
+ for (const guard of guards) if (guard.code?.body) {
323
+ const params = hasSchemaProperties(guard.paramsSchema) ? `, params: ${jsonSchemaToTSType(guard.paramsSchema)}` : "";
324
+ block[guard.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(guard.code.body)}\n}`);
325
+ } else block[guard.name] = raw(`function ({ context, event }) {\n // TODO: implement ${guard.name}\n return false;\n}`);
326
+ return block;
327
+ }
328
+ function buildActorsBlock(actors) {
329
+ const block = {};
330
+ for (const actor of actors) if (actor.code?.body) {
331
+ const inputType = hasSchemaProperties(actor.inputSchema) ? `: ${jsonSchemaToTSType(actor.inputSchema)}` : "";
332
+ block[actor.name] = raw(`fromPromise(async ({ input }${inputType ? `: { input${inputType} }` : ""}) => {\n ${dedent(actor.code.body)}\n})`);
333
+ } else block[actor.name] = raw(`fromPromise(async ({ input }) => {\n // TODO: implement ${actor.name}\n})`);
334
+ return block;
335
+ }
336
+ function buildDelaysBlock(delays) {
337
+ const block = {};
338
+ for (const delay of delays) if (delay.code?.body) block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
339
+ else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
340
+ return block;
341
+ }
342
+
343
+ //#endregion
344
+ export { RawCode as a, graphToMachineConfig as c, upsertStatelyPragma as d, jsonSchemaToTSType as i, findStatelyPragmaAttachments as l, contextSchemaToTSType as n, raw as o, eventsSchemaToTSType as r, serializeJS as s, graphToXStateTS as t, getStatelyPragma as u };