@statelyai/sdk 0.20.0 → 0.20.2

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.
@@ -1,4 +1,4 @@
1
- import { a as literal, c as record, d as unknown, i as discriminatedUnion, l as string, n as array, o as number, r as boolean, s as object, t as _enum, u as union } from "./schemas-C2raUv-n.mjs";
1
+ import { a as discriminatedUnion, c as object, d as union, f as unknown, i as custom, l as record, n as array, o as literal, r as boolean, s as number, t as _enum, u as string } from "./schemas-b9wG-zYl.mjs";
2
2
  import ts from "typescript";
3
3
  import "xstate";
4
4
  import "xstate/graph";
@@ -2334,175 +2334,6 @@ var index_vite_proxy_tmp_default = import_js_yaml.default;
2334
2334
 
2335
2335
  //#endregion
2336
2336
  //#region ../graph-tools/dist/index.mjs
2337
- /**
2338
- * Converts a graph to an adjacency list representation.
2339
- *
2340
- * @example
2341
- * ```ts
2342
- * import { createGraph, toAdjacencyList } from '@statelyai/graph';
2343
- *
2344
- * const graph = createGraph({
2345
- * nodes: { a: {}, b: {}, c: {} },
2346
- * edges: [{ source: 'a', target: 'b' }, { source: 'a', target: 'c' }],
2347
- * });
2348
- *
2349
- * toAdjacencyList(graph);
2350
- * // { a: ['b', 'c'], b: [], c: [] }
2351
- * ```
2352
- */
2353
- function toAdjacencyList(graph) {
2354
- const adj = {};
2355
- for (const node of graph.nodes) adj[node.id] = [];
2356
- for (const edge of graph.edges) {
2357
- adj[edge.sourceId]?.push(edge.targetId);
2358
- if (graph.mode !== "directed") adj[edge.targetId]?.push(edge.sourceId);
2359
- }
2360
- return adj;
2361
- }
2362
- /**
2363
- * Parses an adjacency list into a graph.
2364
- *
2365
- * @example
2366
- * ```ts
2367
- * import { fromAdjacencyList } from '@statelyai/graph';
2368
- *
2369
- * const graph = fromAdjacencyList({
2370
- * a: ['b', 'c'],
2371
- * b: ['c'],
2372
- * c: [],
2373
- * });
2374
- *
2375
- * graph.nodes; // [{id: 'a', ...}, {id: 'b', ...}, {id: 'c', ...}]
2376
- * graph.edges; // [{sourceId: 'a', targetId: 'b', ...}, ...]
2377
- * ```
2378
- */
2379
- function fromAdjacencyList(adj, options) {
2380
- const directed = options?.directed ?? true;
2381
- const seen = /* @__PURE__ */ new Set();
2382
- const nodes = Object.keys(adj).map((id) => ({
2383
- type: "node",
2384
- id,
2385
- parentId: null,
2386
- initialNodeId: null,
2387
- label: "",
2388
- data: void 0
2389
- }));
2390
- const edges = [];
2391
- let edgeIdx = 0;
2392
- for (const [sourceId, targets] of Object.entries(adj)) for (const targetId of targets) {
2393
- const key = directed ? `${sourceId}->${targetId}` : [sourceId, targetId].sort().join("<->");
2394
- if (!seen.has(key)) {
2395
- seen.add(key);
2396
- edges.push({
2397
- type: "edge",
2398
- id: `e${edgeIdx++}`,
2399
- sourceId,
2400
- targetId,
2401
- label: "",
2402
- data: void 0
2403
- });
2404
- }
2405
- }
2406
- return {
2407
- id: options?.id ?? "",
2408
- mode: directed ? "directed" : "undirected",
2409
- initialNodeId: null,
2410
- nodes,
2411
- edges,
2412
- data: void 0
2413
- };
2414
- }
2415
- /**
2416
- * Converts a graph to an edge list of `[source, target]` tuples.
2417
- *
2418
- * @example
2419
- * ```ts
2420
- * import { createGraph, toEdgeList } from '@statelyai/graph';
2421
- *
2422
- * const graph = createGraph({
2423
- * nodes: { a: {}, b: {}, c: {} },
2424
- * edges: [{ source: 'a', target: 'b' }, { source: 'b', target: 'c' }],
2425
- * });
2426
- *
2427
- * toEdgeList(graph);
2428
- * // [['a', 'b'], ['b', 'c']]
2429
- * ```
2430
- */
2431
- function toEdgeList(graph) {
2432
- return graph.edges.map((e) => [e.sourceId, e.targetId]);
2433
- }
2434
- /**
2435
- * Parses an edge list of `[source, target]` tuples into a graph.
2436
- *
2437
- * @example
2438
- * ```ts
2439
- * import { fromEdgeList } from '@statelyai/graph';
2440
- *
2441
- * const graph = fromEdgeList([
2442
- * ['a', 'b'],
2443
- * ['b', 'c'],
2444
- * ]);
2445
- *
2446
- * graph.nodes; // [{id: 'a', ...}, {id: 'b', ...}, {id: 'c', ...}]
2447
- * graph.edges; // [{sourceId: 'a', targetId: 'b', ...}, ...]
2448
- * ```
2449
- */
2450
- function fromEdgeList(edges, options) {
2451
- const directed = options?.directed ?? true;
2452
- const nodeIds = /* @__PURE__ */ new Set();
2453
- for (const [source, target] of edges) {
2454
- nodeIds.add(source);
2455
- nodeIds.add(target);
2456
- }
2457
- const nodes = [...nodeIds].map((id) => ({
2458
- type: "node",
2459
- id,
2460
- parentId: null,
2461
- initialNodeId: null,
2462
- label: "",
2463
- data: void 0
2464
- }));
2465
- const edgeObjects = edges.map(([sourceId, targetId], i) => ({
2466
- type: "edge",
2467
- id: `e${i}`,
2468
- sourceId,
2469
- targetId,
2470
- label: "",
2471
- data: void 0
2472
- }));
2473
- return {
2474
- id: options?.id ?? "",
2475
- mode: directed ? "directed" : "undirected",
2476
- initialNodeId: null,
2477
- nodes,
2478
- edges: edgeObjects,
2479
- data: void 0
2480
- };
2481
- }
2482
- /**
2483
- * Create a `GraphFormatConverter` from a pair of `to`/`from` functions.
2484
- *
2485
- * @example
2486
- * ```ts
2487
- * import { createFormatConverter } from '@statelyai/graph';
2488
- *
2489
- * const yamlConverter = createFormatConverter(
2490
- * (graph) => toYAML(graph),
2491
- * (yaml) => fromYAML(yaml),
2492
- * );
2493
- *
2494
- * const yaml = yamlConverter.to(graph);
2495
- * const graph = yamlConverter.from(yaml);
2496
- * ```
2497
- */
2498
- function createFormatConverter(to, from) {
2499
- return {
2500
- to,
2501
- from
2502
- };
2503
- }
2504
- createFormatConverter(toAdjacencyList, fromAdjacencyList);
2505
- createFormatConverter(toEdgeList, fromEdgeList);
2506
2337
  const LAYOUT_KEYS = {
2507
2338
  node: [
2508
2339
  "x",
@@ -2518,6 +2349,8 @@ const LAYOUT_KEYS = {
2518
2349
  "y",
2519
2350
  "width",
2520
2351
  "height",
2352
+ "points",
2353
+ "routing",
2521
2354
  "style",
2522
2355
  "color"
2523
2356
  ]
@@ -2638,9 +2471,14 @@ function stripExportDefault(code) {
2638
2471
  if (trimmed.startsWith("export default ")) return trimmed.slice(15).replace(/;$/, "");
2639
2472
  return trimmed;
2640
2473
  }
2641
- const MACHINE_PROFILES = ["xstate-v5", "xstate-v6-alpha"];
2474
+ const XSTATE_V5_PROFILE = "@statelyai/xstate@5.30.0";
2475
+ const XSTATE_V6_PROFILE = "@statelyai/xstate@6.0.0-alpha.24";
2476
+ const LEGACY_MACHINE_PROFILES = ["xstate-v5", "xstate-v6-alpha"];
2477
+ function normalizeMachineProfile(profile) {
2478
+ return profile === "xstate-v5" ? XSTATE_V5_PROFILE : profile === "xstate-v6-alpha" ? XSTATE_V6_PROFILE : profile;
2479
+ }
2642
2480
  function isXStateV6Profile(profile) {
2643
- return profile === "xstate-v6-alpha";
2481
+ return (profile === "xstate-v5" || profile === "xstate-v6-alpha" ? normalizeMachineProfile(profile) : profile ?? XSTATE_V5_PROFILE).startsWith("@statelyai/xstate@6.");
2644
2482
  }
2645
2483
  /**
2646
2484
  * Graph-native transition references. Transitions point at invoke/action/state
@@ -3161,7 +2999,7 @@ function graphToMachineConfig(graph, options = {}) {
3161
2999
  }
3162
3000
  return nodeConfig;
3163
3001
  }
3164
- const rootNode = graph.nodes.find((node) => node.data.parentId === null || node.parentId == null);
3002
+ const rootNode = graph.nodes.find((node) => node.parentId === null || node.parentId == null);
3165
3003
  if (!rootNode) throw new Error("No root node found");
3166
3004
  getNodeConfig(rootNode);
3167
3005
  if (graph.data.context !== void 0 && graph.data.context !== null) config.context = graph.data.context;
@@ -3175,703 +3013,254 @@ const INLINE_EXPRESSION_DIRECTIVE_FIELDS = [
3175
3013
  "initialInput",
3176
3014
  "route"
3177
3015
  ];
3178
- function jsonSchemaToTSType(schema) {
3179
- if (!schema) return "unknown";
3180
- if (schema.enum) return schema.enum.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
3181
- if (schema.const !== void 0) return typeof schema.const === "string" ? `'${schema.const}'` : String(schema.const);
3182
- if (schema.oneOf) return schema.oneOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" | ");
3183
- if (schema.anyOf) return schema.anyOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" | ");
3184
- if (schema.allOf) return schema.allOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" & ");
3185
- if (schema.type === "array") return `Array<${jsonSchemaToTSType(resolveDef(schema.items))}>`;
3186
- if (Array.isArray(schema.type)) return schema.type.map((t) => primitiveType(t)).join(" | ");
3187
- if (schema.type === "object" || schema.properties) return objectType(schema);
3188
- if (schema.type) return primitiveType(schema.type);
3189
- return "unknown";
3190
- }
3191
- function primitiveType(type) {
3192
- switch (type) {
3193
- case "string": return "string";
3194
- case "number":
3195
- case "integer": return "number";
3196
- case "boolean": return "boolean";
3197
- case "null": return "null";
3198
- default: return "unknown";
3199
- }
3200
- }
3201
- function objectType(schema) {
3202
- const props = schema.properties;
3203
- if (!props || Object.keys(props).length === 0) {
3204
- if (schema.additionalProperties) return `Record<string, ${jsonSchemaToTSType(resolveDef(schema.additionalProperties))}>`;
3205
- return "Record<string, unknown>";
3016
+ const XSTATE_FORMATS = [
3017
+ {
3018
+ format: "typescript",
3019
+ import: true,
3020
+ export: true,
3021
+ sourcePreserving: true
3022
+ },
3023
+ {
3024
+ format: "javascript",
3025
+ import: true,
3026
+ export: true,
3027
+ sourcePreserving: true
3028
+ },
3029
+ {
3030
+ format: "json",
3031
+ import: true,
3032
+ export: true
3033
+ },
3034
+ {
3035
+ format: "yaml",
3036
+ import: true,
3037
+ export: true
3206
3038
  }
3207
- const required = getRequiredKeys(schema);
3208
- return `{ ${Object.entries(props).map(([key, def]) => {
3209
- const type = jsonSchemaToTSType(resolveDef(def));
3210
- return `${key}${isRequiredProperty(key, def, required) ? "" : "?"}: ${type}`;
3211
- }).join("; ")} }`;
3039
+ ];
3040
+ const XSTATE_PROFILE_MANIFESTS = [{
3041
+ profile: XSTATE_V5_PROFILE,
3042
+ name: "XState v5",
3043
+ formats: [...XSTATE_FORMATS]
3044
+ }, {
3045
+ profile: XSTATE_V6_PROFILE,
3046
+ name: "XState v6",
3047
+ formats: [...XSTATE_FORMATS]
3048
+ }];
3049
+ const PROFILE_MANIFESTS = new Map(XSTATE_PROFILE_MANIFESTS.map((manifest) => [manifest.profile, manifest]));
3050
+ const XSTATE_V6_FN_TRANSITION_META = "@statelyai.xstate.v6.fnTransition";
3051
+ const XSTATE_V6_FN_SOURCE_META = "@statelyai.xstate.v6.fnSource";
3052
+ function sourceFile(source) {
3053
+ return ts.createSourceFile("machine.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
3212
3054
  }
3213
- function resolveDef(def) {
3214
- if (!def) return void 0;
3215
- if (Array.isArray(def)) return resolveDef(def[0]);
3216
- if (typeof def === "boolean") return void 0;
3217
- return def;
3055
+ function propName(name) {
3056
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
3057
+ return null;
3218
3058
  }
3219
- /**
3220
- * Build an inline context type string from the schemas.context record.
3221
- * Each key is a context property name, value is its JSONSchema7.
3222
- */
3223
- function contextSchemaToTSType(context) {
3224
- if (!context || Object.keys(context).length === 0) return null;
3225
- return `{ ${Object.entries(context).map(([key, schema]) => {
3226
- return `${key}: ${jsonSchemaToTSType(schema)}`;
3227
- }).join("; ")} }`;
3059
+ function unwrapExpression(node) {
3060
+ if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isParenthesizedExpression(node)) return unwrapExpression(node.expression);
3061
+ return node;
3228
3062
  }
3229
- /**
3230
- * Build an event union type from the schemas.events record.
3231
- * Each key is the event type name, value describes the payload properties.
3232
- */
3233
- function eventsSchemaToTSType(events) {
3234
- if (!events || Object.keys(events).length === 0) return null;
3235
- return Object.entries(events).map(([eventType, schema]) => {
3236
- const props = schema.properties;
3237
- if (!props || Object.keys(props).length === 0) return `{ type: '${eventType}' }`;
3238
- const required = getRequiredKeys(schema);
3239
- const extraProps = Object.entries(props).filter(([k]) => k !== "type").map(([key, def]) => {
3240
- const type = jsonSchemaToTSType(resolveDef(def));
3241
- return `${key}${isRequiredProperty(key, def, required) ? "" : "?"}: ${type}`;
3242
- });
3243
- if (extraProps.length === 0) return `{ type: '${eventType}' }`;
3244
- return `{ type: '${eventType}'; ${extraProps.join("; ")} }`;
3245
- }).join("\n | ");
3063
+ function propertyContext(parent, key) {
3064
+ if (parent.invokeValue && key === "src") return {
3065
+ v6: parent.v6,
3066
+ actorSourceValue: true
3067
+ };
3068
+ if (parent.transitionMap) return {
3069
+ v6: parent.v6,
3070
+ transitionValue: true
3071
+ };
3072
+ if (parent.transitionValue && key === "actions") return {
3073
+ v6: parent.v6,
3074
+ actionValue: true
3075
+ };
3076
+ if (parent.transitionValue && key === "context") return {
3077
+ v6: parent.v6,
3078
+ assignmentMap: true,
3079
+ transitionContext: true
3080
+ };
3081
+ if (parent.assignmentMap) return {
3082
+ v6: parent.v6,
3083
+ assignmentValue: true
3084
+ };
3085
+ if (key === "meta") return {
3086
+ v6: parent.v6,
3087
+ metaValue: true
3088
+ };
3089
+ if (parent.transitionValue && key === "to") return {
3090
+ v6: parent.v6,
3091
+ transitionValue: true
3092
+ };
3093
+ if (key === "entry" || key === "exit") return {
3094
+ v6: parent.v6,
3095
+ actionValue: true
3096
+ };
3097
+ if (key === "input" || key === "output") return {
3098
+ v6: parent.v6,
3099
+ ioValue: true
3100
+ };
3101
+ if (parent.ioValue || parent.ioPropertyValue) return {
3102
+ v6: parent.v6,
3103
+ ioPropertyValue: true
3104
+ };
3105
+ if (key === "invoke") return {
3106
+ v6: parent.v6,
3107
+ invokeValue: true
3108
+ };
3109
+ if (key === "timeout") return {
3110
+ v6: parent.v6,
3111
+ timeoutValue: true
3112
+ };
3113
+ if (key === "route") return {
3114
+ v6: parent.v6,
3115
+ routeValue: true
3116
+ };
3117
+ if (key === "on" || key === "after") return {
3118
+ v6: parent.v6,
3119
+ transitionMap: true
3120
+ };
3121
+ if (key === "always" || key === "choice" || key === "onDone" || key === "onError" || key === "onSnapshot" || key === "onTimeout") return {
3122
+ v6: parent.v6,
3123
+ transitionValue: true
3124
+ };
3125
+ return { v6: parent.v6 };
3246
3126
  }
3247
- function getRequiredKeys(schema) {
3248
- return new Set(Array.isArray(schema.required) ? schema.required : []);
3127
+ function fallbackFunctionTransition(fn, actions = []) {
3128
+ return {
3129
+ ...actions.length ? { actions } : void 0,
3130
+ meta: {
3131
+ [XSTATE_V6_FN_TRANSITION_META]: true,
3132
+ [XSTATE_V6_FN_SOURCE_META]: fn.getText()
3133
+ }
3134
+ };
3249
3135
  }
3250
- function isRequiredProperty(key, def, required) {
3251
- if (required.has(key)) return true;
3252
- return typeof def === "object" && def !== null && def.required === true;
3136
+ function conditionText(cond) {
3137
+ return cond.negated ? `!(${cond.text})` : cond.text;
3253
3138
  }
3254
- function graphToXStateTS(graph, options = {}) {
3255
- const { exportStyle = "named", targetLanguage = "typescript", xstateVersion = 5, ...configOptions } = options;
3256
- const schemas = graph.data.schemas;
3257
- const impls = filterInlineImplementations(graph.data.implementations);
3258
- const supportsTypeSyntax = targetLanguage === "typescript";
3259
- const hasSchemas = !!(schemas && (schemas.context || schemas.events || schemas.input || schemas.output));
3260
- const hasActions = !!impls?.actions.length;
3261
- const hasGuards = !!impls?.guards.length;
3262
- const hasActors = !!impls?.actors.length;
3263
- const hasDelays = !!impls?.delays.length;
3264
- const hasSetup = hasSchemas || hasActions || hasGuards || hasActors || hasDelays;
3265
- const builtInActions = getUsedBuiltInActions(graph, xstateVersion);
3266
- const actorSourceImports = getActorSourceImports(graph);
3267
- const imports = buildImports({
3268
- hasSetup,
3269
- hasActors,
3270
- actors: impls?.actors ?? [],
3271
- builtInActions,
3272
- actorSourceImports,
3273
- usesTypes: xstateVersion === 6 && supportsTypeSyntax && hasSchemas
3139
+ function simplifyConditions(conds) {
3140
+ const seen = /* @__PURE__ */ new Set();
3141
+ return conds.filter((cond) => {
3142
+ if (cond.negated) return false;
3143
+ const key = conditionText(cond);
3144
+ if (seen.has(key)) return false;
3145
+ seen.add(key);
3146
+ return true;
3274
3147
  });
3275
- const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, configOptions)) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
3276
- let machineExpr;
3277
- if (hasSetup) {
3278
- const setupObj = buildSetupObject(schemas, impls, {
3279
- includeTypeSyntax: supportsTypeSyntax,
3280
- xstateVersion
3281
- });
3282
- const configStr = serializeJS(machineConfig, 2);
3283
- machineExpr = `setup(${serializeJS(setupObj, 0)}).createMachine(${configStr})`;
3284
- } else machineExpr = `createMachine(${serializeJS(machineConfig, 0)})`;
3285
- const lines = [];
3286
- lines.push(imports);
3287
- lines.push("");
3288
- lines.push(`const machine = ${machineExpr};`);
3289
- if (exportStyle === "named") {
3290
- lines.push("");
3291
- lines.push("export { machine };");
3292
- } else if (exportStyle === "default") {
3293
- lines.push("");
3294
- lines.push("export default machine;");
3295
- }
3296
- return lines.join("\n") + "\n";
3297
3148
  }
3298
- function filterInlineImplementations(impls) {
3299
- if (!impls) return impls;
3149
+ function hashString(value) {
3150
+ let hash = 5381;
3151
+ for (let i = 0; i < value.length; i++) hash = hash * 33 ^ value.charCodeAt(i);
3152
+ return (hash >>> 0).toString(36);
3153
+ }
3154
+ function inlineGuardCode(params, condition) {
3155
+ return `${params} => ${condition}`;
3156
+ }
3157
+ function guardFromConditions(conds, params) {
3158
+ const simplified = simplifyConditions(conds);
3159
+ if (simplified.length === 0) return void 0;
3160
+ const code = inlineGuardCode(params, simplified.map(conditionText).join(" && "));
3300
3161
  return {
3301
- ...impls,
3302
- actions: impls.actions.filter((action) => !action.name.startsWith("inline:")),
3303
- guards: impls.guards.filter((guard) => !guard.name.startsWith("inline:")),
3304
- delays: impls.delays.filter((delay) => !delay.name.startsWith("inline:"))
3162
+ type: `inline:${hashString(code)}`,
3163
+ code
3305
3164
  };
3306
3165
  }
3307
- /** Map from xstate action type to the import name */
3308
- const BUILTIN_ACTION_IMPORTS = {
3309
- "xstate.raise": "raise",
3310
- "xstate.sendTo": "sendTo",
3311
- "xstate.cancel": "cancel",
3312
- "xstate.emit": "emit",
3313
- "xstate.spawnChild": "spawnChild",
3314
- "xstate.stopChild": "stopChild",
3315
- "xstate.log": "log",
3316
- "xstate.assign": "assign"
3317
- };
3318
- /** Check inline action/entry/exit code for references to xstate builtins */
3319
- function scanInlineCodeForBuiltins(code, used) {
3320
- const expr = stripExportDefault(code);
3321
- for (const importName of Object.values(BUILTIN_ACTION_IMPORTS)) if (new RegExp(`\\b${importName}\\b`).test(expr)) used.add(importName);
3322
- }
3323
- function getExprActionCode(action) {
3324
- return action.type === "xstate.expr" && typeof action.params?.code === "string" ? action.params.code : void 0;
3325
- }
3326
- function getUsedBuiltInActions(graph, xstateVersion) {
3327
- const used = /* @__PURE__ */ new Set();
3328
- if (xstateVersion === 6) return used;
3329
- for (const node of graph.nodes) for (const action of [...node.data.entry ?? [], ...node.data.exit ?? []]) {
3330
- const imp = BUILTIN_ACTION_IMPORTS[action.type];
3331
- if (imp) used.add(imp);
3332
- const exprCode = getExprActionCode(action);
3333
- if (exprCode) scanInlineCodeForBuiltins(exprCode, used);
3334
- }
3335
- for (const edge of graph.edges) for (const action of edge.data.actions ?? []) {
3336
- const imp = BUILTIN_ACTION_IMPORTS[action.type];
3337
- if (imp) used.add(imp);
3338
- const exprCode = getExprActionCode(action);
3339
- if (exprCode) scanInlineCodeForBuiltins(exprCode, used);
3340
- }
3341
- return used;
3342
- }
3343
- function toV5MachineConfig(machineConfig) {
3344
- return mapMachineActionFields(machineConfig, (actions, wasArray) => {
3345
- const mapped = actions.map(unwrapDirectEnqExpression);
3346
- return wasArray ? mapped : mapped[0];
3347
- });
3348
- }
3349
- function toV6MachineConfig(machineConfig) {
3350
- return mapV6MachineConfig(machineConfig);
3351
- }
3352
- function mapV6MachineConfig(value, context = {}) {
3353
- if (Array.isArray(value)) return value.map((item) => mapV6MachineConfig(item, context));
3354
- if (!value || typeof value !== "object") return value;
3355
- if (context.transitionValue) return toV6TransitionValue(value);
3356
- const result = {};
3357
- for (const [key, item] of Object.entries(value)) {
3358
- if (key === "entry" || key === "exit" || key === "actions") {
3359
- result[key] = toV6ActionField(Array.isArray(item) ? item : item === void 0 ? [] : [item]);
3360
- continue;
3361
- }
3362
- if (key === "on" || key === "after") {
3363
- result[key] = mapV6TransitionMap(item);
3364
- continue;
3365
- }
3366
- if (key === "always" || key === "onDone" || key === "onError" || key === "onSnapshot" || key === "onTimeout") {
3367
- result[key] = mapV6MachineConfig(item, { transitionValue: true });
3368
- continue;
3369
- }
3370
- result[key] = mapV6MachineConfig(item);
3371
- }
3372
- return result;
3166
+ function wrapAssignExpression(expr) {
3167
+ return `{{ ${expr.trim()} }}`;
3373
3168
  }
3374
- function mapV6TransitionMap(value) {
3375
- if (!value || typeof value !== "object" || Array.isArray(value)) return value;
3376
- const result = {};
3377
- for (const [key, item] of Object.entries(value)) result[key] = mapV6MachineConfig(item, { transitionValue: true });
3378
- return result;
3169
+ function hasSpreadAssignment(node) {
3170
+ return node.properties.some((property) => ts.isSpreadAssignment(property));
3379
3171
  }
3380
- function toV6TransitionValue(value) {
3381
- if (Array.isArray(value)) return value.map((item) => toV6TransitionValue(item));
3382
- if (!value || typeof value !== "object") return value;
3383
- const transition = value;
3384
- if (transition.guard || transition.description || transition.input !== void 0) return mapV6MachineConfig(transition);
3385
- const target = transition.target;
3386
- const context = transition.context;
3387
- const actionsValue = transition.actions;
3388
- const actions = Array.isArray(actionsValue) ? actionsValue : actionsValue === void 0 ? [] : [actionsValue];
3389
- if (actions.length === 0 && typeof target === "string" && context === void 0 && !transition.reenter && !transition.meta) return target;
3390
- if (actions.length === 0 && target === void 0 && context === void 0) return mapV6MachineConfig(transition);
3391
- return buildV6ActionFunction(actions, {
3392
- target: typeof target === "string" ? target : void 0,
3393
- reenter: transition.reenter === true,
3394
- meta: transition.meta,
3395
- context
3396
- }) ?? mapV6MachineConfig(transition);
3172
+ function mergeActions(left, right) {
3173
+ return [...left ?? [], ...right];
3397
3174
  }
3398
- function toV6ActionField(actions) {
3399
- if (actions.length === 1) {
3400
- const expr = inlineExpr(actions[0]);
3401
- if (expr && isCompleteFunctionExpression(stripExportDefault(expr))) return raw(stripExportDefault(expr));
3175
+ function transitionFromValue(value, actions) {
3176
+ if (typeof value === "string") {
3177
+ if (actions.length === 0) return value;
3178
+ return {
3179
+ target: value,
3180
+ actions
3181
+ };
3402
3182
  }
3403
- return buildV6ActionFunction(actions) ?? actions;
3183
+ if (!value || typeof value !== "object" || Array.isArray(value)) return actions.length ? { actions } : null;
3184
+ const record = { ...value };
3185
+ if (actions.length) record.actions = mergeActions(Array.isArray(record.actions) ? record.actions : record.actions ? [record.actions] : void 0, actions);
3186
+ return record;
3404
3187
  }
3405
- function buildV6ActionFunction(actions, transition) {
3406
- const effects = actions.map(actionToV6Effect);
3407
- if (effects.some((effect) => !effect)) return void 0;
3408
- const statements = effects.flatMap((effect) => effect?.statements ?? []);
3409
- let returnValue;
3410
- let contextValue;
3411
- for (const effect of effects) {
3412
- returnValue = effect?.returnValue ?? returnValue;
3413
- contextValue = effect?.contextValue ?? contextValue;
3188
+ function expressionBranches(expression, bindings, depth) {
3189
+ const node = unwrapExpression(expression);
3190
+ if (ts.isConditionalExpression(node)) {
3191
+ const cond = node.condition.getText();
3192
+ return [...expressionBranches(node.whenTrue, bindings, depth + 1).map((branch) => ({
3193
+ ...branch,
3194
+ conds: [{ text: cond }, ...branch.conds]
3195
+ })), ...expressionBranches(node.whenFalse, bindings, depth + 1).map((branch) => ({
3196
+ ...branch,
3197
+ conds: [{
3198
+ text: cond,
3199
+ negated: true
3200
+ }, ...branch.conds]
3201
+ }))];
3414
3202
  }
3415
- if (transition) returnValue = buildV6TransitionReturnValue(transition, transition.context === void 0 ? contextValue : serializeJS(unwrapTemplateExpressions(transition.context)));
3416
- if (statements.length === 0 && !returnValue) return void 0;
3417
- return raw(`(_, enq) => {\n${[...statements.map((statement) => ` ${statement};`), ...returnValue ? [` return ${returnValue};`] : []].join("\n")}\n}`);
3418
- }
3419
- function unwrapTemplateExpressions(value) {
3420
- if (typeof value === "string") {
3421
- const match = value.match(/^\{\{\s*([\s\S]*?)\s*\}\}$/);
3422
- return match?.[1] ? raw(match[1]) : value;
3203
+ if (ts.isBinaryExpression(node) && (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken)) {
3204
+ const cond = node.left.getText();
3205
+ if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) return [...expressionBranches(node.right, bindings, depth + 1).map((branch) => ({
3206
+ ...branch,
3207
+ conds: [{ text: cond }, ...branch.conds]
3208
+ })), {
3209
+ conds: [{
3210
+ text: cond,
3211
+ negated: true
3212
+ }],
3213
+ actions: []
3214
+ }];
3215
+ return [{
3216
+ conds: [{ text: cond }],
3217
+ actions: [],
3218
+ result: node.left.getText()
3219
+ }, ...expressionBranches(node.right, bindings, depth + 1).map((branch) => ({
3220
+ ...branch,
3221
+ conds: [{
3222
+ text: cond,
3223
+ negated: true
3224
+ }, ...branch.conds]
3225
+ }))];
3423
3226
  }
3424
- if (Array.isArray(value)) return value.map(unwrapTemplateExpressions);
3425
- if (!value || typeof value !== "object") return value;
3426
- return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, unwrapTemplateExpressions(item)]));
3427
- }
3428
- function buildV6TransitionReturnValue(transition, contextValue) {
3429
- if (!transition.reenter && !transition.meta && !contextValue) return transition.target ? `{ target: ${serializeJS(transition.target)} }` : void 0;
3430
- return serializeJS({
3431
- target: transition.target,
3432
- reenter: transition.reenter ? true : void 0,
3433
- meta: transition.meta,
3434
- context: contextValue ? raw(contextValue) : void 0
3435
- });
3436
- }
3437
- function mapMachineActionFields(value, mapActions) {
3438
- if (Array.isArray(value)) return value.map((item) => mapMachineActionFields(item, mapActions));
3439
- if (!value || typeof value !== "object") return value;
3440
- const result = {};
3441
- for (const [key, item] of Object.entries(value)) {
3442
- if (key === "entry" || key === "exit" || key === "actions") {
3443
- const wasArray = Array.isArray(item);
3444
- result[key] = mapActions(wasArray ? item : item === void 0 ? [] : [item], wasArray);
3445
- continue;
3446
- }
3447
- result[key] = mapMachineActionFields(item, mapActions);
3227
+ if (ts.isObjectLiteralExpression(node)) {
3228
+ const targetProperty = node.properties.find((property) => ts.isPropertyAssignment(property) && propName(property.name) === "target");
3229
+ const target = targetProperty ? unwrapExpression(targetProperty.initializer) : null;
3230
+ if (target && (ts.isConditionalExpression(target) || ts.isBinaryExpression(target) && (target.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || target.operatorToken.kind === ts.SyntaxKind.BarBarToken))) return expressionBranches(target, bindings, depth + 1).map((branch) => ({
3231
+ ...branch,
3232
+ result: objectLiteralToValue(node, bindings, {
3233
+ v6: true,
3234
+ transitionValue: true
3235
+ }, depth + 1, new Map([["target", branch.result]]))
3236
+ }));
3448
3237
  }
3449
- return result;
3450
- }
3451
- function unwrapDirectEnqExpression(action) {
3452
- const expr = inlineExpr(action);
3453
- if (!expr) return action;
3454
- const match = expr.match(/^enq\(([\s\S]*)\)$/);
3455
- return match?.[1] ? raw(match[1]) : action;
3238
+ return [{
3239
+ conds: [],
3240
+ actions: [],
3241
+ result: expressionToValue(node, bindings, {
3242
+ v6: true,
3243
+ transitionValue: true
3244
+ }, depth + 1)
3245
+ }];
3456
3246
  }
3457
- function inlineExpr(value) {
3458
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
3459
- const directive = value;
3460
- return directive["@type"] === "code" && typeof directive.expr === "string" ? directive.expr : void 0;
3247
+ function mergeBranchPrefix(prefix, branch) {
3248
+ return {
3249
+ conds: [...prefix.conds, ...branch.conds],
3250
+ actions: [...prefix.actions, ...branch.actions],
3251
+ result: branch.result,
3252
+ unknown: prefix.unknown || branch.unknown
3253
+ };
3461
3254
  }
3462
- function actionToV6Effect(action) {
3463
- const expr = inlineExpr(action);
3464
- if (expr) {
3465
- if (expr.startsWith("enq(") || expr.startsWith("enq.")) return { statements: [expr] };
3466
- const builtIn = expr.match(/^(raise|emit|sendTo|cancel|log|spawnChild|stopChild)\(([\s\S]*)\)$/);
3467
- if (builtIn) {
3468
- const [, name, args] = builtIn;
3469
- return { statements: [`enq.${name === "spawnChild" ? "spawn" : name === "stopChild" ? "stop" : name}(${args})`] };
3470
- }
3471
- return { statements: [`enq(${expr})`] };
3472
- }
3473
- if (!action || typeof action !== "object" || Array.isArray(action)) return null;
3474
- const record = action;
3475
- const type = record.type;
3476
- if (typeof type !== "string") return null;
3477
- const params = record.params && typeof record.params === "object" && !Array.isArray(record.params) ? record.params : {};
3478
- if (type === "xstate.raise") {
3479
- const options = actionOptions(params, ["event"]);
3480
- return { statements: [`enq.raise(${serializeJS(params.event)}${options})`] };
3481
- }
3482
- if (type === "xstate.emit") return { statements: [`enq.emit(${serializeJS(params.event)})`] };
3483
- if (type === "xstate.sendTo") {
3484
- const options = actionOptions(params, ["to", "event"]);
3485
- return { statements: [`enq.sendTo(${serializeJS(params.to)}, ${serializeJS(params.event)}${options})`] };
3486
- }
3487
- if (type === "xstate.cancel") return { statements: [`enq.cancel(${serializeJS(params.sendId)})`] };
3488
- if (type === "xstate.log") return { statements: [`enq.log(${serializeJS(params.label)})`] };
3489
- if (type === "xstate.spawnChild") {
3490
- const options = actionOptions(params, ["src"]);
3491
- return { statements: [`enq.spawn(${serializeJS(params.src)}${options})`] };
3492
- }
3493
- if (type === "xstate.stopChild") return { statements: [`enq.stop(${serializeJS(params.actorRef)})`] };
3494
- if (type === "xstate.assign") {
3495
- const contextValue = serializeJS(params.assignment ?? params);
3496
- return {
3497
- contextValue,
3498
- returnValue: `{ context: ${contextValue} }`
3499
- };
3500
- }
3501
- return null;
3502
- }
3503
- function actionOptions(params, consumedKeys) {
3504
- const rest = Object.fromEntries(Object.entries(params).filter(([key, value]) => !consumedKeys.includes(key) && value !== void 0));
3505
- return Object.keys(rest).length ? `, ${serializeJS(rest)}` : "";
3506
- }
3507
- function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, usesTypes }) {
3508
- const xstateImports = [];
3509
- if (hasSetup) xstateImports.push("setup");
3510
- else xstateImports.push("createMachine");
3511
- for (const name of builtInActions) xstateImports.push(name);
3512
- for (const name of actorSourceImports) xstateImports.push(name);
3513
- if (usesTypes) xstateImports.push("types");
3514
- if (hasActors) {
3515
- if (actors.length > 0) xstateImports.push("fromPromise");
3516
- }
3517
- return `import { ${[...new Set(xstateImports)].join(", ")} } from 'xstate';`;
3518
- }
3519
- function getActorSourceImports(graph) {
3520
- const imports = /* @__PURE__ */ new Set();
3521
- const candidates = [
3522
- "createAsyncLogic",
3523
- "fromPromise",
3524
- "fromCallback",
3525
- "fromObservable",
3526
- "fromEventObservable",
3527
- "fromTransition"
3528
- ];
3529
- for (const node of graph.nodes) for (const invoke of node.data.invokes ?? []) {
3530
- const expression = invoke.srcExpression?.expr;
3531
- if (!expression) continue;
3532
- for (const candidate of candidates) if (new RegExp(`\\b${candidate}\\b`).test(expression)) imports.add(candidate);
3533
- }
3534
- return imports;
3535
- }
3536
- function buildSetupObject(schemas, impls, options) {
3537
- const setup = {};
3538
- if (options.xstateVersion === 6) {
3539
- const schemasBlock = buildV6SchemasBlock(schemas, options);
3540
- if (schemasBlock) setup.schemas = schemasBlock;
3541
- } else {
3542
- const types = buildTypesBlock(schemas, options);
3543
- if (types) setup.types = types;
3544
- }
3545
- if (impls?.actions.length) setup.actions = buildActionsBlock(impls.actions, options);
3546
- if (impls?.guards.length) setup.guards = buildGuardsBlock(impls.guards, options);
3547
- if (impls?.actors.length) setup.actors = buildActorsBlock(impls.actors, options);
3548
- if (impls?.delays.length) setup.delays = buildDelaysBlock(impls.delays);
3549
- return setup;
3550
- }
3551
- function buildTypesBlock(schemas, options) {
3552
- if (!schemas || !options.includeTypeSyntax) return void 0;
3553
- const types = {};
3554
- const contextType = contextSchemaToTSType(schemas.context);
3555
- if (contextType) types.context = raw(`{} as ${contextType}`);
3556
- const eventsType = eventsSchemaToTSType(schemas.events);
3557
- if (eventsType) types.events = raw(`{} as\n | ${eventsType}`);
3558
- if (schemas.input) types.input = raw(`{} as ${jsonSchemaToTSType(schemas.input)}`);
3559
- if (schemas.output) types.output = raw(`{} as ${jsonSchemaToTSType(schemas.output)}`);
3560
- return Object.keys(types).length > 0 ? types : void 0;
3561
- }
3562
- function buildV6SchemasBlock(schemas, options) {
3563
- if (!schemas || !options.includeTypeSyntax) return void 0;
3564
- const result = {};
3565
- const contextType = contextSchemaToTSType(schemas.context);
3566
- if (contextType) result.context = raw(`types<${contextType}>()`);
3567
- if (schemas.events && Object.keys(schemas.events).length > 0) result.events = Object.fromEntries(Object.entries(schemas.events).map(([eventType, schema]) => [eventType, raw(`types<${eventPayloadSchemaToTSType(schema)}>()`)]));
3568
- if (schemas.input) result.input = raw(`types<${jsonSchemaToTSType(schemas.input)}>()`);
3569
- if (schemas.output) result.output = raw(`types<${jsonSchemaToTSType(schemas.output)}>()`);
3570
- return Object.keys(result).length > 0 ? result : void 0;
3571
- }
3572
- function eventPayloadSchemaToTSType(schema) {
3573
- const props = schema.properties ?? {};
3574
- const payloadProps = Object.fromEntries(Object.entries(props).filter(([key]) => key !== "type"));
3575
- if (Object.keys(payloadProps).length === 0) return "{}";
3576
- return jsonSchemaToTSType({
3577
- ...schema,
3578
- properties: payloadProps,
3579
- required: Array.isArray(schema.required) ? schema.required.filter((key) => key !== "type") : void 0
3580
- });
3581
- }
3582
- function hasSchemaProperties(schema) {
3583
- if (!schema) return false;
3584
- if (schema.type === "object" || schema.properties) {
3585
- const props = schema.properties;
3586
- return !!props && Object.keys(props).length > 0;
3587
- }
3588
- return true;
3589
- }
3590
- function buildActionsBlock(actions, options) {
3591
- const block = {};
3592
- for (const implementation of actions) if (implementation.code?.body) {
3593
- const inlineExpression = getInlineExpression(implementation.code.body);
3594
- if (inlineExpression) {
3595
- block[implementation.name] = raw(inlineExpression);
3596
- continue;
3597
- }
3598
- const params = hasSchemaProperties(implementation.paramsSchema) ? options.includeTypeSyntax ? `, params: ${jsonSchemaToTSType(implementation.paramsSchema)}` : ", params" : "";
3599
- block[implementation.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(implementation.code.body)}\n}`);
3600
- } else block[implementation.name] = raw(`function ({ context, event }) {\n // TODO: implement ${implementation.name}\n}`);
3601
- return block;
3602
- }
3603
- function buildGuardsBlock(guards, options) {
3604
- const block = {};
3605
- for (const guard of guards) if (guard.code?.body) {
3606
- const inlineExpression = getInlineExpression(guard.code.body);
3607
- if (inlineExpression) {
3608
- block[guard.name] = raw(inlineExpression);
3609
- continue;
3610
- }
3611
- const params = hasSchemaProperties(guard.paramsSchema) ? options.includeTypeSyntax ? `, params: ${jsonSchemaToTSType(guard.paramsSchema)}` : ", params" : "";
3612
- block[guard.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(guard.code.body)}\n}`);
3613
- } else block[guard.name] = raw(`function ({ context, event }) {\n // TODO: implement ${guard.name}\n return false;\n}`);
3614
- return block;
3615
- }
3616
- function buildActorsBlock(actors, options) {
3617
- const block = {};
3618
- for (const actor of actors) if (actor.code?.body) {
3619
- const inputType = options.includeTypeSyntax && hasSchemaProperties(actor.inputSchema) ? `: ${jsonSchemaToTSType(actor.inputSchema)}` : "";
3620
- block[actor.name] = raw(`fromPromise(async ({ input }${inputType ? `: { input${inputType} }` : ""}) => {\n ${dedent(actor.code.body)}\n})`);
3621
- } else block[actor.name] = raw(`fromPromise(async ({ input }) => {\n // TODO: implement ${actor.name}\n})`);
3622
- return block;
3623
- }
3624
- function buildDelaysBlock(delays) {
3625
- const block = {};
3626
- for (const delay of delays) if (delay.code?.body) {
3627
- const inlineExpression = getInlineExpression(delay.code.body);
3628
- if (inlineExpression) {
3629
- block[delay.name] = raw(inlineExpression);
3630
- continue;
3631
- }
3632
- block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
3633
- } else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
3634
- return block;
3635
- }
3636
- /**
3637
- * Returns the implementation to emit verbatim when `body` is already a complete
3638
- * expression, so it is NOT wrapped in another `function ({ context, event }) { ... }`.
3639
- * Handles two cases:
3640
- * - `export default <expr>` → the inner expression.
3641
- * - a bare function/arrow expression (e.g. a guard captured via `fn.toString()`
3642
- * on import) → the expression itself.
3643
- * Returns undefined for a plain statement body, which still needs wrapping.
3644
- */
3645
- function getInlineExpression(code) {
3646
- const stripped = stripExportDefault(code);
3647
- if (stripped !== code.trim()) return stripped;
3648
- return isCompleteFunctionExpression(stripped) ? stripped : void 0;
3649
- }
3650
- /** True when `code` is a single function or arrow-function expression. */
3651
- function isCompleteFunctionExpression(code) {
3652
- const candidate = code.trim().replace(/;$/, "");
3653
- const source = ts.createSourceFile("impl.ts", `(${candidate})`, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
3654
- if ((source.parseDiagnostics ?? []).length > 0 || source.statements.length !== 1) return false;
3655
- const [statement] = source.statements;
3656
- if (!statement || !ts.isExpressionStatement(statement)) return false;
3657
- let expression = statement.expression;
3658
- if (ts.isParenthesizedExpression(expression)) expression = expression.expression;
3659
- return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
3660
- }
3661
- const XSTATE_V6_FN_TRANSITION_META = "@statelyai.xstate.v6.fnTransition";
3662
- const XSTATE_V6_FN_SOURCE_META = "@statelyai.xstate.v6.fnSource";
3663
- function sourceFile(source) {
3664
- return ts.createSourceFile("machine.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
3665
- }
3666
- function propName(name) {
3667
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
3668
- return null;
3669
- }
3670
- function unwrapExpression(node) {
3671
- if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isParenthesizedExpression(node)) return unwrapExpression(node.expression);
3672
- return node;
3673
- }
3674
- function propertyContext(parent, key) {
3675
- if (parent.invokeValue && key === "src") return {
3676
- v6: parent.v6,
3677
- actorSourceValue: true
3678
- };
3679
- if (parent.transitionMap) return {
3680
- v6: parent.v6,
3681
- transitionValue: true
3682
- };
3683
- if (parent.transitionValue && key === "actions") return {
3684
- v6: parent.v6,
3685
- actionValue: true
3686
- };
3687
- if (parent.transitionValue && key === "context") return {
3688
- v6: parent.v6,
3689
- assignmentMap: true,
3690
- transitionContext: true
3691
- };
3692
- if (parent.assignmentMap) return {
3693
- v6: parent.v6,
3694
- assignmentValue: true
3695
- };
3696
- if (key === "meta") return {
3697
- v6: parent.v6,
3698
- metaValue: true
3699
- };
3700
- if (parent.transitionValue && key === "to") return {
3701
- v6: parent.v6,
3702
- transitionValue: true
3703
- };
3704
- if (key === "entry" || key === "exit") return {
3705
- v6: parent.v6,
3706
- actionValue: true
3707
- };
3708
- if (key === "input" || key === "output") return {
3709
- v6: parent.v6,
3710
- ioValue: true
3711
- };
3712
- if (parent.ioValue || parent.ioPropertyValue) return {
3713
- v6: parent.v6,
3714
- ioPropertyValue: true
3715
- };
3716
- if (key === "invoke") return {
3717
- v6: parent.v6,
3718
- invokeValue: true
3719
- };
3720
- if (key === "timeout") return {
3721
- v6: parent.v6,
3722
- timeoutValue: true
3723
- };
3724
- if (key === "route") return {
3725
- v6: parent.v6,
3726
- routeValue: true
3727
- };
3728
- if (key === "on" || key === "after") return {
3729
- v6: parent.v6,
3730
- transitionMap: true
3731
- };
3732
- if (key === "always" || key === "choice" || key === "onDone" || key === "onError" || key === "onSnapshot" || key === "onTimeout") return {
3733
- v6: parent.v6,
3734
- transitionValue: true
3735
- };
3736
- return { v6: parent.v6 };
3737
- }
3738
- function fallbackFunctionTransition(fn, actions = []) {
3739
- return {
3740
- ...actions.length ? { actions } : void 0,
3741
- meta: {
3742
- [XSTATE_V6_FN_TRANSITION_META]: true,
3743
- [XSTATE_V6_FN_SOURCE_META]: fn.getText()
3744
- }
3745
- };
3746
- }
3747
- function conditionText(cond) {
3748
- return cond.negated ? `!(${cond.text})` : cond.text;
3749
- }
3750
- function simplifyConditions(conds) {
3751
- const seen = /* @__PURE__ */ new Set();
3752
- return conds.filter((cond) => {
3753
- if (cond.negated) return false;
3754
- const key = conditionText(cond);
3755
- if (seen.has(key)) return false;
3756
- seen.add(key);
3757
- return true;
3758
- });
3759
- }
3760
- function hashString(value) {
3761
- let hash = 5381;
3762
- for (let i = 0; i < value.length; i++) hash = hash * 33 ^ value.charCodeAt(i);
3763
- return (hash >>> 0).toString(36);
3764
- }
3765
- function inlineGuardCode(params, condition) {
3766
- return `${params} => ${condition}`;
3767
- }
3768
- function guardFromConditions(conds, params) {
3769
- const simplified = simplifyConditions(conds);
3770
- if (simplified.length === 0) return void 0;
3771
- const code = inlineGuardCode(params, simplified.map(conditionText).join(" && "));
3772
- return {
3773
- type: `inline:${hashString(code)}`,
3774
- code
3775
- };
3776
- }
3777
- function wrapAssignExpression(expr) {
3778
- return `{{ ${expr.trim()} }}`;
3779
- }
3780
- function hasSpreadAssignment(node) {
3781
- return node.properties.some((property) => ts.isSpreadAssignment(property));
3782
- }
3783
- function mergeActions(left, right) {
3784
- return [...left ?? [], ...right];
3785
- }
3786
- function transitionFromValue(value, actions) {
3787
- if (typeof value === "string") {
3788
- if (actions.length === 0) return value;
3789
- return {
3790
- target: value,
3791
- actions
3792
- };
3793
- }
3794
- if (!value || typeof value !== "object" || Array.isArray(value)) return actions.length ? { actions } : null;
3795
- const record = { ...value };
3796
- if (actions.length) record.actions = mergeActions(Array.isArray(record.actions) ? record.actions : record.actions ? [record.actions] : void 0, actions);
3797
- return record;
3798
- }
3799
- function expressionBranches(expression, bindings, depth) {
3800
- const node = unwrapExpression(expression);
3801
- if (ts.isConditionalExpression(node)) {
3802
- const cond = node.condition.getText();
3803
- return [...expressionBranches(node.whenTrue, bindings, depth + 1).map((branch) => ({
3804
- ...branch,
3805
- conds: [{ text: cond }, ...branch.conds]
3806
- })), ...expressionBranches(node.whenFalse, bindings, depth + 1).map((branch) => ({
3807
- ...branch,
3808
- conds: [{
3809
- text: cond,
3810
- negated: true
3811
- }, ...branch.conds]
3812
- }))];
3813
- }
3814
- if (ts.isBinaryExpression(node) && (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken)) {
3815
- const cond = node.left.getText();
3816
- if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) return [...expressionBranches(node.right, bindings, depth + 1).map((branch) => ({
3817
- ...branch,
3818
- conds: [{ text: cond }, ...branch.conds]
3819
- })), {
3820
- conds: [{
3821
- text: cond,
3822
- negated: true
3823
- }],
3824
- actions: []
3825
- }];
3826
- return [{
3827
- conds: [{ text: cond }],
3828
- actions: [],
3829
- result: node.left.getText()
3830
- }, ...expressionBranches(node.right, bindings, depth + 1).map((branch) => ({
3831
- ...branch,
3832
- conds: [{
3833
- text: cond,
3834
- negated: true
3835
- }, ...branch.conds]
3836
- }))];
3837
- }
3838
- if (ts.isObjectLiteralExpression(node)) {
3839
- const targetProperty = node.properties.find((property) => ts.isPropertyAssignment(property) && propName(property.name) === "target");
3840
- const target = targetProperty ? unwrapExpression(targetProperty.initializer) : null;
3841
- if (target && (ts.isConditionalExpression(target) || ts.isBinaryExpression(target) && (target.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || target.operatorToken.kind === ts.SyntaxKind.BarBarToken))) return expressionBranches(target, bindings, depth + 1).map((branch) => ({
3842
- ...branch,
3843
- result: objectLiteralToValue(node, bindings, {
3844
- v6: true,
3845
- transitionValue: true
3846
- }, depth + 1, new Map([["target", branch.result]]))
3847
- }));
3848
- }
3849
- return [{
3850
- conds: [],
3851
- actions: [],
3852
- result: expressionToValue(node, bindings, {
3853
- v6: true,
3854
- transitionValue: true
3855
- }, depth + 1)
3856
- }];
3857
- }
3858
- function mergeBranchPrefix(prefix, branch) {
3859
- return {
3860
- conds: [...prefix.conds, ...branch.conds],
3861
- actions: [...prefix.actions, ...branch.actions],
3862
- result: branch.result,
3863
- unknown: prefix.unknown || branch.unknown
3864
- };
3865
- }
3866
- function expressionStatementAction(statement, enqName, bindings) {
3867
- const expression = unwrapExpression(statement.expression);
3868
- if (!ts.isCallExpression(expression)) return null;
3869
- const callee = expression.expression;
3870
- if (ts.isIdentifier(callee) && callee.text === enqName) return {
3871
- type: "xstate.expr",
3872
- params: {
3873
- code: expression.getText(),
3874
- lang: "ts"
3255
+ function expressionStatementAction(statement, enqName, bindings) {
3256
+ const expression = unwrapExpression(statement.expression);
3257
+ if (!ts.isCallExpression(expression)) return null;
3258
+ const callee = expression.expression;
3259
+ if (ts.isIdentifier(callee) && callee.text === enqName) return {
3260
+ type: "xstate.expr",
3261
+ params: {
3262
+ code: expression.getText(),
3263
+ lang: "ts"
3875
3264
  }
3876
3265
  };
3877
3266
  if (!ts.isPropertyAccessExpression(callee)) return null;
@@ -3916,400 +3305,883 @@ function expressionStatementAction(statement, enqName, bindings) {
3916
3305
  if (method === "spawn") return {
3917
3306
  type: "xstate.spawnChild",
3918
3307
  params: {
3919
- src: value(0),
3920
- ...spreadOpts(1)
3308
+ src: value(0),
3309
+ ...spreadOpts(1)
3310
+ }
3311
+ };
3312
+ if (method === "stop") return {
3313
+ type: "xstate.stopChild",
3314
+ params: { actorRef: value(0) }
3315
+ };
3316
+ return {
3317
+ type: "xstate.expr",
3318
+ params: {
3319
+ code: expression.getText(),
3320
+ lang: "ts"
3321
+ }
3322
+ };
3323
+ }
3324
+ function statementBranches(statements, bindings, enqName, prefixes = [{
3325
+ conds: [],
3326
+ actions: []
3327
+ }]) {
3328
+ let open = prefixes;
3329
+ const done = [];
3330
+ const scopedBindings = new Map(bindings);
3331
+ for (const statement of statements) {
3332
+ const nextOpen = [];
3333
+ for (const prefix of open) {
3334
+ if (ts.isVariableStatement(statement)) {
3335
+ for (const declaration of statement.declarationList.declarations) if (ts.isIdentifier(declaration.name) && declaration.initializer) scopedBindings.set(declaration.name.text, declaration.initializer);
3336
+ nextOpen.push(prefix);
3337
+ continue;
3338
+ }
3339
+ if (ts.isReturnStatement(statement)) {
3340
+ if (!statement.expression) {
3341
+ done.push({
3342
+ ...prefix,
3343
+ result: void 0
3344
+ });
3345
+ continue;
3346
+ }
3347
+ for (const branch of expressionBranches(statement.expression, scopedBindings, 0)) done.push(mergeBranchPrefix(prefix, branch));
3348
+ continue;
3349
+ }
3350
+ if (ts.isExpressionStatement(statement)) {
3351
+ const action = expressionStatementAction(statement, enqName, scopedBindings);
3352
+ if (action) {
3353
+ nextOpen.push({
3354
+ ...prefix,
3355
+ actions: [...prefix.actions, action]
3356
+ });
3357
+ continue;
3358
+ }
3359
+ }
3360
+ if (ts.isIfStatement(statement)) {
3361
+ const cond = statement.expression.getText();
3362
+ const thenBranches = statementBranches(ts.isBlock(statement.thenStatement) ? statement.thenStatement.statements : [statement.thenStatement], scopedBindings, enqName, [{
3363
+ ...prefix,
3364
+ conds: [...prefix.conds, { text: cond }]
3365
+ }]);
3366
+ const elseStatements = statement.elseStatement ? ts.isBlock(statement.elseStatement) ? statement.elseStatement.statements : [statement.elseStatement] : [];
3367
+ const elseBranches = elseStatements.length > 0 ? statementBranches(elseStatements, scopedBindings, enqName, [{
3368
+ ...prefix,
3369
+ conds: [...prefix.conds, {
3370
+ text: cond,
3371
+ negated: true
3372
+ }]
3373
+ }]) : [{
3374
+ ...prefix,
3375
+ conds: [...prefix.conds, {
3376
+ text: cond,
3377
+ negated: true
3378
+ }]
3379
+ }];
3380
+ for (const branch of [...thenBranches, ...elseBranches]) if ("result" in branch) done.push(branch);
3381
+ else nextOpen.push(branch);
3382
+ continue;
3383
+ }
3384
+ if (ts.isSwitchStatement(statement)) {
3385
+ const expr = statement.expression.getText();
3386
+ const prior = [];
3387
+ for (const clause of statement.caseBlock.clauses) {
3388
+ const ownCond = ts.isCaseClause(clause) ? { text: `${expr} === ${clause.expression.getText()}` } : null;
3389
+ const conds = ownCond ? [...prior, ownCond] : prior.length ? [...prior] : [];
3390
+ const branches = statementBranches(clause.statements, scopedBindings, enqName, [{
3391
+ ...prefix,
3392
+ conds: [...prefix.conds, ...conds]
3393
+ }]);
3394
+ for (const branch of branches) if ("result" in branch) done.push(branch);
3395
+ else nextOpen.push(branch);
3396
+ if (ownCond) prior.push({
3397
+ ...ownCond,
3398
+ negated: true
3399
+ });
3400
+ }
3401
+ continue;
3402
+ }
3403
+ nextOpen.push({
3404
+ ...prefix,
3405
+ unknown: true
3406
+ });
3407
+ }
3408
+ open = nextOpen;
3409
+ }
3410
+ return [...done, ...open];
3411
+ }
3412
+ function enqueueParamName(fn) {
3413
+ const param = fn.parameters[1];
3414
+ return param && ts.isIdentifier(param.name) ? param.name.text : "enq";
3415
+ }
3416
+ function guardParams(fn) {
3417
+ const param = fn.parameters[0];
3418
+ if (!param) return "()";
3419
+ return `(${param.getText()})`;
3420
+ }
3421
+ function normalizeFunctionTransition(fn, bindings, depth) {
3422
+ const preservedActions = fn.body && ts.isBlock(fn.body) && fn.body.statements.some((statement) => ts.isExpressionStatement(statement)) ? [enqueueAction(fn)] : [];
3423
+ const transitions = (ts.isArrowFunction(fn) && !ts.isBlock(fn.body) ? expressionBranches(fn.body, bindings, depth + 1) : fn.body && ts.isBlock(fn.body) ? statementBranches(fn.body.statements, bindings, enqueueParamName(fn)) : []).filter((branch) => !branch.unknown).map((branch) => {
3424
+ const transition = transitionFromValue(branch.result, branch.actions.length ? preservedActions : []);
3425
+ if (!transition) return null;
3426
+ if (typeof transition === "string") {
3427
+ const guard = guardFromConditions(branch.conds, guardParams(fn));
3428
+ return guard ? {
3429
+ target: transition,
3430
+ guard
3431
+ } : transition;
3432
+ }
3433
+ const guard = guardFromConditions(branch.conds, guardParams(fn));
3434
+ return guard ? {
3435
+ ...transition,
3436
+ guard
3437
+ } : transition;
3438
+ }).filter((transition) => Boolean(transition));
3439
+ if (transitions.length === 1) return transitions[0];
3440
+ if (transitions.length > 1) return transitions;
3441
+ return fallbackFunctionTransition(fn, preservedActions);
3442
+ }
3443
+ function inlineAction(fn) {
3444
+ return {
3445
+ type: "xstate.expr",
3446
+ params: {
3447
+ code: fn.getText(),
3448
+ lang: "ts"
3921
3449
  }
3922
3450
  };
3923
- if (method === "stop") return {
3924
- type: "xstate.stopChild",
3925
- params: { actorRef: value(0) }
3926
- };
3451
+ }
3452
+ function enqueueAction(fn) {
3927
3453
  return {
3928
- type: "xstate.expr",
3454
+ type: "xstate.enqueue",
3929
3455
  params: {
3930
- code: expression.getText(),
3456
+ code: fn.getText(),
3931
3457
  lang: "ts"
3932
3458
  }
3933
3459
  };
3934
3460
  }
3935
- function statementBranches(statements, bindings, enqName, prefixes = [{
3936
- conds: [],
3937
- actions: []
3938
- }]) {
3939
- let open = prefixes;
3940
- const done = [];
3941
- const scopedBindings = new Map(bindings);
3942
- for (const statement of statements) {
3943
- const nextOpen = [];
3944
- for (const prefix of open) {
3945
- if (ts.isVariableStatement(statement)) {
3946
- for (const declaration of statement.declarationList.declarations) if (ts.isIdentifier(declaration.name) && declaration.initializer) scopedBindings.set(declaration.name.text, declaration.initializer);
3947
- nextOpen.push(prefix);
3948
- continue;
3949
- }
3950
- if (ts.isReturnStatement(statement)) {
3951
- if (!statement.expression) {
3952
- done.push({
3953
- ...prefix,
3954
- result: void 0
3955
- });
3956
- continue;
3957
- }
3958
- for (const branch of expressionBranches(statement.expression, scopedBindings, 0)) done.push(mergeBranchPrefix(prefix, branch));
3959
- continue;
3960
- }
3961
- if (ts.isExpressionStatement(statement)) {
3962
- const action = expressionStatementAction(statement, enqName, scopedBindings);
3963
- if (action) {
3964
- nextOpen.push({
3965
- ...prefix,
3966
- actions: [...prefix.actions, action]
3967
- });
3968
- continue;
3969
- }
3461
+ function inlineCodeExpression(expr) {
3462
+ return {
3463
+ "@type": "code",
3464
+ lang: "ts",
3465
+ expr
3466
+ };
3467
+ }
3468
+ function normalizeFunctionAction(fn, _bindings) {
3469
+ return enqueueAction(fn);
3470
+ }
3471
+ function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__PURE__ */ new Map()) {
3472
+ const result = {};
3473
+ for (const property of node.properties) {
3474
+ if (ts.isSpreadAssignment(property)) {
3475
+ const spread = expressionToValue(property.expression, bindings, context, depth + 1);
3476
+ if (spread && typeof spread === "object" && !Array.isArray(spread)) Object.assign(result, spread);
3477
+ continue;
3478
+ }
3479
+ if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property)) continue;
3480
+ const key = propName(property.name);
3481
+ if (!key) continue;
3482
+ if (overrides.has(key)) {
3483
+ result[key] = overrides.get(key);
3484
+ continue;
3485
+ }
3486
+ if (ts.isShorthandPropertyAssignment(property)) {
3487
+ result[key] = expressionToValue(property.name, bindings, propertyContext(context, key), depth + 1);
3488
+ continue;
3489
+ }
3490
+ result[key] = expressionToValue(property.initializer, bindings, propertyContext(context, key), depth + 1);
3491
+ }
3492
+ if (context.transitionValue && "to" in result) {
3493
+ const to = result.to;
3494
+ const { to: _to, ...rest } = result;
3495
+ if (typeof to === "string") return {
3496
+ ...rest,
3497
+ target: to
3498
+ };
3499
+ if (Array.isArray(to)) return to.map((item) => typeof item === "string" ? {
3500
+ ...rest,
3501
+ target: item
3502
+ } : item && typeof item === "object" ? {
3503
+ ...rest,
3504
+ ...item
3505
+ } : rest);
3506
+ if (to && typeof to === "object" && !Array.isArray(to)) return {
3507
+ ...rest,
3508
+ ...to
3509
+ };
3510
+ }
3511
+ return result;
3512
+ }
3513
+ function expressionToValue(expression, bindings, context = {}, depth = 0) {
3514
+ if (depth > 30) return void 0;
3515
+ const node = unwrapExpression(expression);
3516
+ if (context.actorSourceValue) {
3517
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
3518
+ if (ts.isIdentifier(node)) {
3519
+ const binding = bindings.get(node.text);
3520
+ if (binding && !ts.isFunctionDeclaration(binding)) return inlineCodeExpression(unwrapExpression(binding).getText());
3521
+ }
3522
+ return inlineCodeExpression(node.getText());
3523
+ }
3524
+ if (context.routeValue && !ts.isObjectLiteralExpression(node)) {
3525
+ if (ts.isIdentifier(node)) {
3526
+ const binding = bindings.get(node.text);
3527
+ if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
3528
+ }
3529
+ return inlineCodeExpression(node.getText());
3530
+ }
3531
+ if (context.timeoutValue && (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isCallExpression(node))) return inlineCodeExpression(node.getText());
3532
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return context.ioValue ? inlineCodeExpression(JSON.stringify(node.text)) : node.text;
3533
+ if (ts.isNumericLiteral(node)) return context.ioValue ? inlineCodeExpression(node.text) : Number(node.text);
3534
+ if (node.kind === ts.SyntaxKind.TrueKeyword) return context.ioValue ? inlineCodeExpression("true") : true;
3535
+ if (node.kind === ts.SyntaxKind.FalseKeyword) return context.ioValue ? inlineCodeExpression("false") : false;
3536
+ if (node.kind === ts.SyntaxKind.NullKeyword) return context.ioValue ? inlineCodeExpression("null") : null;
3537
+ if (context.ioPropertyValue) {
3538
+ if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
3539
+ if (ts.isIdentifier(node)) {
3540
+ const binding = bindings.get(node.text);
3541
+ if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
3542
+ }
3543
+ if (!ts.isObjectLiteralExpression(node) && !ts.isArrayLiteralExpression(node)) return inlineCodeExpression(node.getText());
3544
+ }
3545
+ if (context.assignmentValue) {
3546
+ if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
3547
+ if (ts.isIdentifier(node)) {
3548
+ const binding = bindings.get(node.text);
3549
+ if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
3550
+ }
3551
+ return wrapAssignExpression(node.getText());
3552
+ }
3553
+ if (context.transitionContext && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
3554
+ if (context.ioValue && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
3555
+ if (context.transitionContext && ts.isObjectLiteralExpression(node) && hasSpreadAssignment(node)) return inlineCodeExpression(node.getText());
3556
+ if (ts.isIdentifier(node)) {
3557
+ if (node.text === "undefined") return void 0;
3558
+ const binding = bindings.get(node.text);
3559
+ if (binding) {
3560
+ if (ts.isFunctionDeclaration(binding)) {
3561
+ if (context.metaValue) return inlineCodeExpression(binding.name?.text ?? node.getText());
3562
+ if (context.v6 && context.transitionValue) return normalizeFunctionTransition(binding, bindings, depth + 1);
3563
+ if (context.v6 && context.actionValue) return normalizeFunctionAction(binding, bindings);
3564
+ return binding.name?.text ?? node.text;
3970
3565
  }
3971
- if (ts.isIfStatement(statement)) {
3972
- const cond = statement.expression.getText();
3973
- const thenBranches = statementBranches(ts.isBlock(statement.thenStatement) ? statement.thenStatement.statements : [statement.thenStatement], scopedBindings, enqName, [{
3974
- ...prefix,
3975
- conds: [...prefix.conds, { text: cond }]
3976
- }]);
3977
- const elseStatements = statement.elseStatement ? ts.isBlock(statement.elseStatement) ? statement.elseStatement.statements : [statement.elseStatement] : [];
3978
- const elseBranches = elseStatements.length > 0 ? statementBranches(elseStatements, scopedBindings, enqName, [{
3979
- ...prefix,
3980
- conds: [...prefix.conds, {
3981
- text: cond,
3982
- negated: true
3983
- }]
3984
- }]) : [{
3985
- ...prefix,
3986
- conds: [...prefix.conds, {
3987
- text: cond,
3988
- negated: true
3989
- }]
3990
- }];
3991
- for (const branch of [...thenBranches, ...elseBranches]) if ("result" in branch) done.push(branch);
3992
- else nextOpen.push(branch);
3993
- continue;
3566
+ return expressionToValue(binding, bindings, context, depth + 1);
3567
+ }
3568
+ return context.metaValue ? inlineCodeExpression(node.getText()) : node.text;
3569
+ }
3570
+ if (ts.isObjectLiteralExpression(node)) return objectLiteralToValue(node, bindings, context, depth);
3571
+ if (ts.isArrayLiteralExpression(node)) {
3572
+ const values = node.elements.map((element) => expressionToValue(element, bindings, context, depth + 1));
3573
+ return context.actionValue ? values.flat() : values;
3574
+ }
3575
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
3576
+ if (context.metaValue) return inlineCodeExpression(node.getText());
3577
+ if (context.v6 && context.transitionValue) return normalizeFunctionTransition(node, bindings, depth);
3578
+ if (context.v6 && context.actionValue) return normalizeFunctionAction(node, bindings);
3579
+ return node.getText();
3580
+ }
3581
+ if (ts.isCallExpression(node)) {
3582
+ if (context.metaValue) return inlineCodeExpression(node.getText());
3583
+ if (ts.isIdentifier(node.expression)) {
3584
+ const binding = bindings.get(node.expression.text);
3585
+ if (binding && isFunctionBinding(binding)) return evaluateFunctionCall(binding, node.arguments, bindings, context, depth + 1);
3586
+ }
3587
+ if (ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === "createStateConfig") {
3588
+ const configArg = node.arguments.length > 1 ? node.arguments[1] : node.arguments[0];
3589
+ return configArg ? expressionToValue(configArg, bindings, { v6: context.v6 }, depth + 1) : {};
3590
+ }
3591
+ if (context.actionValue) return inlineAction(node);
3592
+ const callee = node.expression.getText();
3593
+ const type = callee.includes(".") ? callee.split(".").pop() : callee;
3594
+ return { type: type === "assign" ? "xstate.assign" : type };
3595
+ }
3596
+ return context.metaValue ? inlineCodeExpression(node.getText()) : node.getText();
3597
+ }
3598
+ function isFunctionBinding(binding) {
3599
+ return ts.isArrowFunction(binding) || ts.isFunctionExpression(binding) || ts.isFunctionDeclaration(binding);
3600
+ }
3601
+ function evaluateFunctionCall(fn, args, bindings, context, depth) {
3602
+ const scopedBindings = new Map(bindings);
3603
+ for (const [index, parameter] of fn.parameters.entries()) {
3604
+ if (!ts.isIdentifier(parameter.name)) continue;
3605
+ const argument = args[index];
3606
+ if (argument) scopedBindings.set(parameter.name.text, argument);
3607
+ else if (parameter.initializer) scopedBindings.set(parameter.name.text, parameter.initializer);
3608
+ }
3609
+ if (ts.isArrowFunction(fn) && !ts.isBlock(fn.body)) return expressionToValue(fn.body, scopedBindings, context, depth + 1);
3610
+ if (context.v6 && context.transitionValue) return normalizeFunctionTransition(fn, scopedBindings, depth + 1);
3611
+ if (context.v6 && context.actionValue) return normalizeFunctionAction(fn, scopedBindings);
3612
+ return context.metaValue ? inlineCodeExpression(fn.getText()) : fn.name?.getText() ?? fn.getText();
3613
+ }
3614
+ function collectBindings(file) {
3615
+ const bindings = /* @__PURE__ */ new Map();
3616
+ for (const statement of file.statements) {
3617
+ if (ts.isVariableStatement(statement)) {
3618
+ for (const declaration of statement.declarationList.declarations) if (ts.isIdentifier(declaration.name) && declaration.initializer) bindings.set(declaration.name.text, declaration.initializer);
3619
+ continue;
3620
+ }
3621
+ if (ts.isFunctionDeclaration(statement) && statement.name) bindings.set(statement.name.text, statement);
3622
+ }
3623
+ return bindings;
3624
+ }
3625
+ function isCreateMachineCall(node) {
3626
+ const expression = node.expression;
3627
+ if (ts.isIdentifier(expression)) return expression.text === "createMachine";
3628
+ if (ts.isPropertyAccessExpression(expression)) return expression.name.text === "createMachine";
3629
+ return false;
3630
+ }
3631
+ function hasV6Syntax(source) {
3632
+ const file = sourceFile(source);
3633
+ const bindings = collectBindings(file);
3634
+ let found = false;
3635
+ function containsFunction(expression, seenBindings = /* @__PURE__ */ new Set()) {
3636
+ if (ts.isFunctionDeclaration(expression)) return true;
3637
+ const node = unwrapExpression(expression);
3638
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) return true;
3639
+ if (ts.isIdentifier(node)) {
3640
+ if (seenBindings.has(node.text)) return false;
3641
+ const binding = bindings.get(node.text);
3642
+ if (!binding) return false;
3643
+ return containsFunction(binding, new Set([...seenBindings, node.text]));
3644
+ }
3645
+ if (ts.isObjectLiteralExpression(node)) return node.properties.some((property) => {
3646
+ if (ts.isPropertyAssignment(property)) return containsFunction(property.initializer, seenBindings);
3647
+ if (ts.isShorthandPropertyAssignment(property)) return containsFunction(property.name, seenBindings);
3648
+ if (ts.isSpreadAssignment(property)) return containsFunction(property.expression, seenBindings);
3649
+ return false;
3650
+ });
3651
+ if (ts.isArrayLiteralExpression(node)) return node.elements.some((element) => ts.isExpression(element) && containsFunction(element, seenBindings));
3652
+ if (ts.isCallExpression(node)) return ts.isIdentifier(node.expression) && containsFunction(node.expression, seenBindings) || node.arguments.some((argument) => ts.isExpression(argument) && containsFunction(argument, seenBindings));
3653
+ return false;
3654
+ }
3655
+ function visit(node) {
3656
+ if (found) return;
3657
+ if (ts.isPropertyAssignment(node) && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name))) {
3658
+ const key = node.name.text;
3659
+ if (key === "triggers" || key === "internalEvents" || key === "matches" || key === "actorSources" || key === "timeout" || key === "onTimeout" || key === "choice" || key === "route") {
3660
+ found = true;
3661
+ return;
3994
3662
  }
3995
- if (ts.isSwitchStatement(statement)) {
3996
- const expr = statement.expression.getText();
3997
- const prior = [];
3998
- for (const clause of statement.caseBlock.clauses) {
3999
- const ownCond = ts.isCaseClause(clause) ? { text: `${expr} === ${clause.expression.getText()}` } : null;
4000
- const conds = ownCond ? [...prior, ownCond] : prior.length ? [...prior] : [];
4001
- const branches = statementBranches(clause.statements, scopedBindings, enqName, [{
4002
- ...prefix,
4003
- conds: [...prefix.conds, ...conds]
4004
- }]);
4005
- for (const branch of branches) if ("result" in branch) done.push(branch);
4006
- else nextOpen.push(branch);
4007
- if (ownCond) prior.push({
4008
- ...ownCond,
4009
- negated: true
4010
- });
4011
- }
4012
- continue;
3663
+ if ((key === "on" || key === "after" || key === "always" || key === "choice" || key === "onDone" || key === "onError" || key === "onSnapshot" || key === "onTimeout" || key === "entry" || key === "exit" || key === "actions" && !ts.isObjectLiteralExpression(node.initializer)) && containsFunction(node.initializer)) {
3664
+ found = true;
3665
+ return;
4013
3666
  }
4014
- nextOpen.push({
4015
- ...prefix,
4016
- unknown: true
4017
- });
4018
3667
  }
4019
- open = nextOpen;
3668
+ ts.forEachChild(node, visit);
4020
3669
  }
4021
- return [...done, ...open];
3670
+ visit(file);
3671
+ return found;
4022
3672
  }
4023
- function enqueueParamName(fn) {
4024
- const param = fn.parameters[1];
4025
- return param && ts.isIdentifier(param.name) ? param.name.text : "enq";
3673
+ function detectXStateSourceProfile(source) {
3674
+ return hasV6Syntax(source) ? "xstate-v6-alpha" : "xstate-v5";
4026
3675
  }
4027
- function guardParams(fn) {
4028
- const param = fn.parameters[0];
4029
- if (!param) return "()";
4030
- return `(${param.getText()})`;
3676
+ function xstateSourceToConfig(source, options = {}) {
3677
+ const [config] = extractXStateMachineConfigs(source, options);
3678
+ if (!config) throw new Error("No createMachine(...) or setup(...).createMachine(...) call found.");
3679
+ return config;
4031
3680
  }
4032
- function normalizeFunctionTransition(fn, bindings, depth) {
4033
- const preservedActions = fn.body && ts.isBlock(fn.body) && fn.body.statements.some((statement) => ts.isExpressionStatement(statement)) ? [enqueueAction(fn)] : [];
4034
- const transitions = (ts.isArrowFunction(fn) && !ts.isBlock(fn.body) ? expressionBranches(fn.body, bindings, depth + 1) : fn.body && ts.isBlock(fn.body) ? statementBranches(fn.body.statements, bindings, enqueueParamName(fn)) : []).filter((branch) => !branch.unknown).map((branch) => {
4035
- const transition = transitionFromValue(branch.result, branch.actions.length ? preservedActions : []);
4036
- if (!transition) return null;
4037
- if (typeof transition === "string") {
4038
- const guard = guardFromConditions(branch.conds, guardParams(fn));
4039
- return guard ? {
4040
- target: transition,
4041
- guard
4042
- } : transition;
3681
+ /**
3682
+ * Extract every XState machine config from source without executing code.
3683
+ * XState 5/6 syntax is inferred structurally unless a profile is supplied.
3684
+ */
3685
+ function extractXStateMachineConfigs(source, options = {}) {
3686
+ const file = sourceFile(source);
3687
+ const bindings = collectBindings(file);
3688
+ const found = [];
3689
+ const profile = options.profile === "auto" || !options.profile ? detectXStateSourceProfile(source) : options.profile;
3690
+ function visit(node) {
3691
+ if (!ts.isCallExpression(node) || !isCreateMachineCall(node)) {
3692
+ ts.forEachChild(node, visit);
3693
+ return;
4043
3694
  }
4044
- const guard = guardFromConditions(branch.conds, guardParams(fn));
4045
- return guard ? {
4046
- ...transition,
4047
- guard
4048
- } : transition;
4049
- }).filter((transition) => Boolean(transition));
4050
- if (transitions.length === 1) return transitions[0];
4051
- if (transitions.length > 1) return transitions;
4052
- return fallbackFunctionTransition(fn, preservedActions);
3695
+ const arg = node.arguments[0];
3696
+ if (!arg) return;
3697
+ const value = expressionToValue(arg, bindings, { v6: profile === "xstate-v6-alpha" });
3698
+ if (value && typeof value === "object" && !Array.isArray(value)) found.push(value);
3699
+ }
3700
+ visit(file);
3701
+ return found;
4053
3702
  }
4054
- function inlineAction(fn) {
4055
- return {
4056
- type: "xstate.expr",
4057
- params: {
4058
- code: fn.getText(),
4059
- lang: "ts"
4060
- }
4061
- };
3703
+ function jsonSchemaToTSType(schema) {
3704
+ if (!schema) return "unknown";
3705
+ if (schema.enum) return schema.enum.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
3706
+ if (schema.const !== void 0) return typeof schema.const === "string" ? `'${schema.const}'` : String(schema.const);
3707
+ if (schema.oneOf) return schema.oneOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" | ");
3708
+ if (schema.anyOf) return schema.anyOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" | ");
3709
+ if (schema.allOf) return schema.allOf.map((s) => jsonSchemaToTSType(resolveDef(s))).join(" & ");
3710
+ if (schema.type === "array") return `Array<${jsonSchemaToTSType(resolveDef(schema.items))}>`;
3711
+ if (Array.isArray(schema.type)) return schema.type.map((t) => primitiveType(t)).join(" | ");
3712
+ if (schema.type === "object" || schema.properties) return objectType(schema);
3713
+ if (schema.type) return primitiveType(schema.type);
3714
+ return "unknown";
4062
3715
  }
4063
- function enqueueAction(fn) {
3716
+ function primitiveType(type) {
3717
+ switch (type) {
3718
+ case "string": return "string";
3719
+ case "number":
3720
+ case "integer": return "number";
3721
+ case "boolean": return "boolean";
3722
+ case "null": return "null";
3723
+ default: return "unknown";
3724
+ }
3725
+ }
3726
+ function objectType(schema) {
3727
+ const props = schema.properties;
3728
+ if (!props || Object.keys(props).length === 0) {
3729
+ if (schema.additionalProperties) return `Record<string, ${jsonSchemaToTSType(resolveDef(schema.additionalProperties))}>`;
3730
+ return "Record<string, unknown>";
3731
+ }
3732
+ const required = getRequiredKeys(schema);
3733
+ return `{ ${Object.entries(props).map(([key, def]) => {
3734
+ const type = jsonSchemaToTSType(resolveDef(def));
3735
+ return `${key}${isRequiredProperty(key, def, required) ? "" : "?"}: ${type}`;
3736
+ }).join("; ")} }`;
3737
+ }
3738
+ function resolveDef(def) {
3739
+ if (!def) return void 0;
3740
+ if (Array.isArray(def)) return resolveDef(def[0]);
3741
+ if (typeof def === "boolean") return void 0;
3742
+ return def;
3743
+ }
3744
+ /**
3745
+ * Build an inline context type string from the schemas.context record.
3746
+ * Each key is a context property name, value is its JSONSchema7.
3747
+ */
3748
+ function contextSchemaToTSType(context) {
3749
+ if (!context || Object.keys(context).length === 0) return null;
3750
+ return `{ ${Object.entries(context).map(([key, schema]) => {
3751
+ return `${key}: ${jsonSchemaToTSType(schema)}`;
3752
+ }).join("; ")} }`;
3753
+ }
3754
+ /**
3755
+ * Build an event union type from the schemas.events record.
3756
+ * Each key is the event type name, value describes the payload properties.
3757
+ */
3758
+ function eventsSchemaToTSType(events) {
3759
+ if (!events || Object.keys(events).length === 0) return null;
3760
+ return Object.entries(events).map(([eventType, schema]) => {
3761
+ const props = schema.properties;
3762
+ if (!props || Object.keys(props).length === 0) return `{ type: '${eventType}' }`;
3763
+ const required = getRequiredKeys(schema);
3764
+ const extraProps = Object.entries(props).filter(([k]) => k !== "type").map(([key, def]) => {
3765
+ const type = jsonSchemaToTSType(resolveDef(def));
3766
+ return `${key}${isRequiredProperty(key, def, required) ? "" : "?"}: ${type}`;
3767
+ });
3768
+ if (extraProps.length === 0) return `{ type: '${eventType}' }`;
3769
+ return `{ type: '${eventType}'; ${extraProps.join("; ")} }`;
3770
+ }).join("\n | ");
3771
+ }
3772
+ function getRequiredKeys(schema) {
3773
+ return new Set(Array.isArray(schema.required) ? schema.required : []);
3774
+ }
3775
+ function isRequiredProperty(key, def, required) {
3776
+ if (required.has(key)) return true;
3777
+ return typeof def === "object" && def !== null && def.required === true;
3778
+ }
3779
+ function graphToXStateTS(graph, options = {}) {
3780
+ const { exportStyle = "named", targetLanguage = "typescript", xstateVersion = 5, ...configOptions } = options;
3781
+ const schemas = graph.data.schemas;
3782
+ const impls = filterInlineImplementations(graph.data.implementations);
3783
+ const supportsTypeSyntax = targetLanguage === "typescript";
3784
+ const hasSchemas = !!(schemas && (schemas.context || schemas.events || schemas.input || schemas.output));
3785
+ const hasActions = !!impls?.actions.length;
3786
+ const hasGuards = !!impls?.guards.length;
3787
+ const hasActors = !!impls?.actors.length;
3788
+ const hasDelays = !!impls?.delays.length;
3789
+ const hasSetup = hasSchemas || hasActions || hasGuards || hasActors || hasDelays;
3790
+ const builtInActions = getUsedBuiltInActions(graph, xstateVersion);
3791
+ const actorSourceImports = getActorSourceImports(graph);
3792
+ const imports = buildImports({
3793
+ hasSetup,
3794
+ hasActors,
3795
+ actors: impls?.actors ?? [],
3796
+ builtInActions,
3797
+ actorSourceImports,
3798
+ usesTypes: xstateVersion === 6 && supportsTypeSyntax && hasSchemas
3799
+ });
3800
+ const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, configOptions)) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
3801
+ let machineExpr;
3802
+ if (hasSetup) {
3803
+ const setupObj = buildSetupObject(schemas, impls, {
3804
+ includeTypeSyntax: supportsTypeSyntax,
3805
+ xstateVersion
3806
+ });
3807
+ const configStr = serializeJS(machineConfig, 2);
3808
+ machineExpr = `setup(${serializeJS(setupObj, 0)}).createMachine(${configStr})`;
3809
+ } else machineExpr = `createMachine(${serializeJS(machineConfig, 0)})`;
3810
+ const lines = [];
3811
+ lines.push(imports);
3812
+ lines.push("");
3813
+ lines.push(`const machine = ${machineExpr};`);
3814
+ if (exportStyle === "named") {
3815
+ lines.push("");
3816
+ lines.push("export { machine };");
3817
+ } else if (exportStyle === "default") {
3818
+ lines.push("");
3819
+ lines.push("export default machine;");
3820
+ }
3821
+ return lines.join("\n") + "\n";
3822
+ }
3823
+ function filterInlineImplementations(impls) {
3824
+ if (!impls) return impls;
4064
3825
  return {
4065
- type: "xstate.enqueue",
4066
- params: {
4067
- code: fn.getText(),
4068
- lang: "ts"
4069
- }
3826
+ ...impls,
3827
+ actions: impls.actions.filter((action) => !action.name.startsWith("inline:")),
3828
+ guards: impls.guards.filter((guard) => !guard.name.startsWith("inline:")),
3829
+ delays: impls.delays.filter((delay) => !delay.name.startsWith("inline:"))
4070
3830
  };
4071
3831
  }
4072
- function inlineCodeExpression(expr) {
4073
- return {
4074
- "@type": "code",
4075
- lang: "ts",
4076
- expr
4077
- };
3832
+ /** Map from xstate action type to the import name */
3833
+ const BUILTIN_ACTION_IMPORTS = {
3834
+ "xstate.raise": "raise",
3835
+ "xstate.sendTo": "sendTo",
3836
+ "xstate.cancel": "cancel",
3837
+ "xstate.emit": "emit",
3838
+ "xstate.spawnChild": "spawnChild",
3839
+ "xstate.stopChild": "stopChild",
3840
+ "xstate.log": "log",
3841
+ "xstate.assign": "assign"
3842
+ };
3843
+ /** Check inline action/entry/exit code for references to xstate builtins */
3844
+ function scanInlineCodeForBuiltins(code, used) {
3845
+ const expr = stripExportDefault(code);
3846
+ for (const importName of Object.values(BUILTIN_ACTION_IMPORTS)) if (new RegExp(`\\b${importName}\\b`).test(expr)) used.add(importName);
3847
+ }
3848
+ function getExprActionCode(action) {
3849
+ return action.type === "xstate.expr" && typeof action.params?.code === "string" ? action.params.code : void 0;
4078
3850
  }
4079
- function normalizeFunctionAction(fn, _bindings) {
4080
- return enqueueAction(fn);
3851
+ function getUsedBuiltInActions(graph, xstateVersion) {
3852
+ const used = /* @__PURE__ */ new Set();
3853
+ if (xstateVersion === 6) return used;
3854
+ for (const node of graph.nodes) for (const action of [...node.data.entry ?? [], ...node.data.exit ?? []]) {
3855
+ const imp = BUILTIN_ACTION_IMPORTS[action.type];
3856
+ if (imp) used.add(imp);
3857
+ const exprCode = getExprActionCode(action);
3858
+ if (exprCode) scanInlineCodeForBuiltins(exprCode, used);
3859
+ }
3860
+ for (const edge of graph.edges) for (const action of edge.data.actions ?? []) {
3861
+ const imp = BUILTIN_ACTION_IMPORTS[action.type];
3862
+ if (imp) used.add(imp);
3863
+ const exprCode = getExprActionCode(action);
3864
+ if (exprCode) scanInlineCodeForBuiltins(exprCode, used);
3865
+ }
3866
+ return used;
4081
3867
  }
4082
- function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__PURE__ */ new Map()) {
3868
+ function toV5MachineConfig(machineConfig) {
3869
+ return mapMachineActionFields(machineConfig, (actions, wasArray) => {
3870
+ const mapped = actions.map(unwrapDirectEnqExpression);
3871
+ return wasArray ? mapped : mapped[0];
3872
+ });
3873
+ }
3874
+ function toV6MachineConfig(machineConfig) {
3875
+ return mapV6MachineConfig(machineConfig);
3876
+ }
3877
+ function mapV6MachineConfig(value, context = {}) {
3878
+ if (Array.isArray(value)) return value.map((item) => mapV6MachineConfig(item, context));
3879
+ if (!value || typeof value !== "object") return value;
3880
+ if (context.transitionValue) return toV6TransitionValue(value);
4083
3881
  const result = {};
4084
- for (const property of node.properties) {
4085
- if (ts.isSpreadAssignment(property)) {
4086
- const spread = expressionToValue(property.expression, bindings, context, depth + 1);
4087
- if (spread && typeof spread === "object" && !Array.isArray(spread)) Object.assign(result, spread);
3882
+ for (const [key, item] of Object.entries(value)) {
3883
+ if (key === "entry" || key === "exit" || key === "actions") {
3884
+ result[key] = toV6ActionField(Array.isArray(item) ? item : item === void 0 ? [] : [item]);
4088
3885
  continue;
4089
3886
  }
4090
- if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property)) continue;
4091
- const key = propName(property.name);
4092
- if (!key) continue;
4093
- if (overrides.has(key)) {
4094
- result[key] = overrides.get(key);
3887
+ if (key === "on" || key === "after") {
3888
+ result[key] = mapV6TransitionMap(item);
4095
3889
  continue;
4096
3890
  }
4097
- if (ts.isShorthandPropertyAssignment(property)) {
4098
- result[key] = expressionToValue(property.name, bindings, propertyContext(context, key), depth + 1);
3891
+ if (key === "always" || key === "onDone" || key === "onError" || key === "onSnapshot" || key === "onTimeout") {
3892
+ result[key] = mapV6MachineConfig(item, { transitionValue: true });
4099
3893
  continue;
4100
3894
  }
4101
- result[key] = expressionToValue(property.initializer, bindings, propertyContext(context, key), depth + 1);
4102
- }
4103
- if (context.transitionValue && "to" in result) {
4104
- const to = result.to;
4105
- const { to: _to, ...rest } = result;
4106
- if (typeof to === "string") return {
4107
- ...rest,
4108
- target: to
4109
- };
4110
- if (Array.isArray(to)) return to.map((item) => typeof item === "string" ? {
4111
- ...rest,
4112
- target: item
4113
- } : item && typeof item === "object" ? {
4114
- ...rest,
4115
- ...item
4116
- } : rest);
4117
- if (to && typeof to === "object" && !Array.isArray(to)) return {
4118
- ...rest,
4119
- ...to
4120
- };
3895
+ result[key] = mapV6MachineConfig(item);
4121
3896
  }
4122
3897
  return result;
4123
3898
  }
4124
- function expressionToValue(expression, bindings, context = {}, depth = 0) {
4125
- if (depth > 30) return void 0;
4126
- const node = unwrapExpression(expression);
4127
- if (context.actorSourceValue) {
4128
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
4129
- if (ts.isIdentifier(node)) {
4130
- const binding = bindings.get(node.text);
4131
- if (binding && !ts.isFunctionDeclaration(binding)) return inlineCodeExpression(unwrapExpression(binding).getText());
4132
- }
4133
- return inlineCodeExpression(node.getText());
3899
+ function mapV6TransitionMap(value) {
3900
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
3901
+ const result = {};
3902
+ for (const [key, item] of Object.entries(value)) result[key] = mapV6MachineConfig(item, { transitionValue: true });
3903
+ return result;
3904
+ }
3905
+ function toV6TransitionValue(value) {
3906
+ if (Array.isArray(value)) return value.map((item) => toV6TransitionValue(item));
3907
+ if (!value || typeof value !== "object") return value;
3908
+ const transition = value;
3909
+ if (transition.guard || transition.description || transition.input !== void 0) return mapV6MachineConfig(transition);
3910
+ const target = transition.target;
3911
+ const context = transition.context;
3912
+ const actionsValue = transition.actions;
3913
+ const actions = Array.isArray(actionsValue) ? actionsValue : actionsValue === void 0 ? [] : [actionsValue];
3914
+ if (actions.length === 0 && typeof target === "string" && context === void 0 && !transition.reenter && !transition.meta) return target;
3915
+ if (actions.length === 0 && target === void 0 && context === void 0) return mapV6MachineConfig(transition);
3916
+ return buildV6ActionFunction(actions, {
3917
+ target: typeof target === "string" ? target : void 0,
3918
+ reenter: transition.reenter === true,
3919
+ meta: transition.meta,
3920
+ context
3921
+ }) ?? mapV6MachineConfig(transition);
3922
+ }
3923
+ function toV6ActionField(actions) {
3924
+ if (actions.length === 1) {
3925
+ const expr = inlineExpr(actions[0]);
3926
+ if (expr && isCompleteFunctionExpression(stripExportDefault(expr))) return raw(stripExportDefault(expr));
4134
3927
  }
4135
- if (context.routeValue && !ts.isObjectLiteralExpression(node)) {
4136
- if (ts.isIdentifier(node)) {
4137
- const binding = bindings.get(node.text);
4138
- if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
4139
- }
4140
- return inlineCodeExpression(node.getText());
3928
+ return buildV6ActionFunction(actions) ?? actions;
3929
+ }
3930
+ function buildV6ActionFunction(actions, transition) {
3931
+ const effects = actions.map(actionToV6Effect);
3932
+ if (effects.some((effect) => !effect)) return void 0;
3933
+ const statements = effects.flatMap((effect) => effect?.statements ?? []);
3934
+ let returnValue;
3935
+ let contextValue;
3936
+ for (const effect of effects) {
3937
+ returnValue = effect?.returnValue ?? returnValue;
3938
+ contextValue = effect?.contextValue ?? contextValue;
4141
3939
  }
4142
- if (context.timeoutValue && (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isCallExpression(node))) return inlineCodeExpression(node.getText());
4143
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return context.ioValue ? inlineCodeExpression(JSON.stringify(node.text)) : node.text;
4144
- if (ts.isNumericLiteral(node)) return context.ioValue ? inlineCodeExpression(node.text) : Number(node.text);
4145
- if (node.kind === ts.SyntaxKind.TrueKeyword) return context.ioValue ? inlineCodeExpression("true") : true;
4146
- if (node.kind === ts.SyntaxKind.FalseKeyword) return context.ioValue ? inlineCodeExpression("false") : false;
4147
- if (node.kind === ts.SyntaxKind.NullKeyword) return context.ioValue ? inlineCodeExpression("null") : null;
4148
- if (context.ioPropertyValue) {
4149
- if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
4150
- if (ts.isIdentifier(node)) {
4151
- const binding = bindings.get(node.text);
4152
- if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
4153
- }
4154
- if (!ts.isObjectLiteralExpression(node) && !ts.isArrayLiteralExpression(node)) return inlineCodeExpression(node.getText());
3940
+ if (transition) returnValue = buildV6TransitionReturnValue(transition, transition.context === void 0 ? contextValue : serializeJS(unwrapTemplateExpressions(transition.context)));
3941
+ if (statements.length === 0 && !returnValue) return void 0;
3942
+ return raw(`(_, enq) => {\n${[...statements.map((statement) => ` ${statement};`), ...returnValue ? [` return ${returnValue};`] : []].join("\n")}\n}`);
3943
+ }
3944
+ function unwrapTemplateExpressions(value) {
3945
+ if (typeof value === "string") {
3946
+ const match = value.match(/^\{\{\s*([\s\S]*?)\s*\}\}$/);
3947
+ return match?.[1] ? raw(match[1]) : value;
4155
3948
  }
4156
- if (context.assignmentValue) {
4157
- if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
4158
- if (ts.isIdentifier(node)) {
4159
- const binding = bindings.get(node.text);
4160
- if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
3949
+ if (Array.isArray(value)) return value.map(unwrapTemplateExpressions);
3950
+ if (!value || typeof value !== "object") return value;
3951
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, unwrapTemplateExpressions(item)]));
3952
+ }
3953
+ function buildV6TransitionReturnValue(transition, contextValue) {
3954
+ if (!transition.reenter && !transition.meta && !contextValue) return transition.target ? `{ target: ${serializeJS(transition.target)} }` : void 0;
3955
+ return serializeJS({
3956
+ target: transition.target,
3957
+ reenter: transition.reenter ? true : void 0,
3958
+ meta: transition.meta,
3959
+ context: contextValue ? raw(contextValue) : void 0
3960
+ });
3961
+ }
3962
+ function mapMachineActionFields(value, mapActions) {
3963
+ if (Array.isArray(value)) return value.map((item) => mapMachineActionFields(item, mapActions));
3964
+ if (!value || typeof value !== "object") return value;
3965
+ const result = {};
3966
+ for (const [key, item] of Object.entries(value)) {
3967
+ if (key === "entry" || key === "exit" || key === "actions") {
3968
+ const wasArray = Array.isArray(item);
3969
+ result[key] = mapActions(wasArray ? item : item === void 0 ? [] : [item], wasArray);
3970
+ continue;
4161
3971
  }
4162
- return wrapAssignExpression(node.getText());
3972
+ result[key] = mapMachineActionFields(item, mapActions);
4163
3973
  }
4164
- if (context.transitionContext && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
4165
- if (context.ioValue && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
4166
- if (context.transitionContext && ts.isObjectLiteralExpression(node) && hasSpreadAssignment(node)) return inlineCodeExpression(node.getText());
4167
- if (ts.isIdentifier(node)) {
4168
- if (node.text === "undefined") return void 0;
4169
- const binding = bindings.get(node.text);
4170
- if (binding) {
4171
- if (ts.isFunctionDeclaration(binding)) {
4172
- if (context.metaValue) return inlineCodeExpression(binding.name?.text ?? node.getText());
4173
- if (context.v6 && context.transitionValue) return normalizeFunctionTransition(binding, bindings, depth + 1);
4174
- if (context.v6 && context.actionValue) return normalizeFunctionAction(binding, bindings);
4175
- return binding.name?.text ?? node.text;
4176
- }
4177
- return expressionToValue(binding, bindings, context, depth + 1);
3974
+ return result;
3975
+ }
3976
+ function unwrapDirectEnqExpression(action) {
3977
+ const expr = inlineExpr(action);
3978
+ if (!expr) return action;
3979
+ const match = expr.match(/^enq\(([\s\S]*)\)$/);
3980
+ return match?.[1] ? raw(match[1]) : action;
3981
+ }
3982
+ function inlineExpr(value) {
3983
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
3984
+ const directive = value;
3985
+ return directive["@type"] === "code" && typeof directive.expr === "string" ? directive.expr : void 0;
3986
+ }
3987
+ function actionToV6Effect(action) {
3988
+ const expr = inlineExpr(action);
3989
+ if (expr) {
3990
+ if (expr.startsWith("enq(") || expr.startsWith("enq.")) return { statements: [expr] };
3991
+ const builtIn = expr.match(/^(raise|emit|sendTo|cancel|log|spawnChild|stopChild)\(([\s\S]*)\)$/);
3992
+ if (builtIn) {
3993
+ const [, name, args] = builtIn;
3994
+ return { statements: [`enq.${name === "spawnChild" ? "spawn" : name === "stopChild" ? "stop" : name}(${args})`] };
4178
3995
  }
4179
- return context.metaValue ? inlineCodeExpression(node.getText()) : node.text;
3996
+ return { statements: [`enq(${expr})`] };
4180
3997
  }
4181
- if (ts.isObjectLiteralExpression(node)) return objectLiteralToValue(node, bindings, context, depth);
4182
- if (ts.isArrayLiteralExpression(node)) {
4183
- const values = node.elements.map((element) => expressionToValue(element, bindings, context, depth + 1));
4184
- return context.actionValue ? values.flat() : values;
3998
+ if (!action || typeof action !== "object" || Array.isArray(action)) return null;
3999
+ const record = action;
4000
+ const type = record.type;
4001
+ if (typeof type !== "string") return null;
4002
+ const params = record.params && typeof record.params === "object" && !Array.isArray(record.params) ? record.params : {};
4003
+ if (type === "xstate.raise") {
4004
+ const options = actionOptions(params, ["event"]);
4005
+ return { statements: [`enq.raise(${serializeJS(params.event)}${options})`] };
4006
+ }
4007
+ if (type === "xstate.emit") return { statements: [`enq.emit(${serializeJS(params.event)})`] };
4008
+ if (type === "xstate.sendTo") {
4009
+ const options = actionOptions(params, ["to", "event"]);
4010
+ return { statements: [`enq.sendTo(${serializeJS(params.to)}, ${serializeJS(params.event)}${options})`] };
4011
+ }
4012
+ if (type === "xstate.cancel") return { statements: [`enq.cancel(${serializeJS(params.sendId)})`] };
4013
+ if (type === "xstate.log") return { statements: [`enq.log(${serializeJS(params.label)})`] };
4014
+ if (type === "xstate.spawnChild") {
4015
+ const options = actionOptions(params, ["src"]);
4016
+ return { statements: [`enq.spawn(${serializeJS(params.src)}${options})`] };
4017
+ }
4018
+ if (type === "xstate.stopChild") return { statements: [`enq.stop(${serializeJS(params.actorRef)})`] };
4019
+ if (type === "xstate.assign") {
4020
+ const contextValue = serializeJS(params.assignment ?? params);
4021
+ return {
4022
+ contextValue,
4023
+ returnValue: `{ context: ${contextValue} }`
4024
+ };
4025
+ }
4026
+ return null;
4027
+ }
4028
+ function actionOptions(params, consumedKeys) {
4029
+ const rest = Object.fromEntries(Object.entries(params).filter(([key, value]) => !consumedKeys.includes(key) && value !== void 0));
4030
+ return Object.keys(rest).length ? `, ${serializeJS(rest)}` : "";
4031
+ }
4032
+ function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, usesTypes }) {
4033
+ const xstateImports = [];
4034
+ if (hasSetup) xstateImports.push("setup");
4035
+ else xstateImports.push("createMachine");
4036
+ for (const name of builtInActions) xstateImports.push(name);
4037
+ for (const name of actorSourceImports) xstateImports.push(name);
4038
+ if (usesTypes) xstateImports.push("types");
4039
+ if (hasActors) {
4040
+ if (actors.length > 0) xstateImports.push("fromPromise");
4185
4041
  }
4186
- if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
4187
- if (context.metaValue) return inlineCodeExpression(node.getText());
4188
- if (context.v6 && context.transitionValue) return normalizeFunctionTransition(node, bindings, depth);
4189
- if (context.v6 && context.actionValue) return normalizeFunctionAction(node, bindings);
4190
- return node.getText();
4042
+ return `import { ${[...new Set(xstateImports)].join(", ")} } from 'xstate';`;
4043
+ }
4044
+ function getActorSourceImports(graph) {
4045
+ const imports = /* @__PURE__ */ new Set();
4046
+ const candidates = [
4047
+ "createAsyncLogic",
4048
+ "fromPromise",
4049
+ "fromCallback",
4050
+ "fromObservable",
4051
+ "fromEventObservable",
4052
+ "fromTransition"
4053
+ ];
4054
+ for (const node of graph.nodes) for (const invoke of node.data.invokes ?? []) {
4055
+ const expression = invoke.srcExpression?.expr;
4056
+ if (!expression) continue;
4057
+ for (const candidate of candidates) if (new RegExp(`\\b${candidate}\\b`).test(expression)) imports.add(candidate);
4191
4058
  }
4192
- if (ts.isCallExpression(node)) {
4193
- if (context.metaValue) return inlineCodeExpression(node.getText());
4194
- if (ts.isIdentifier(node.expression)) {
4195
- const binding = bindings.get(node.expression.text);
4196
- if (binding && isFunctionBinding(binding)) return evaluateFunctionCall(binding, node.arguments, bindings, context, depth + 1);
4197
- }
4198
- if (ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === "createStateConfig") {
4199
- const configArg = node.arguments.length > 1 ? node.arguments[1] : node.arguments[0];
4200
- return configArg ? expressionToValue(configArg, bindings, { v6: context.v6 }, depth + 1) : {};
4201
- }
4202
- if (context.actionValue) return inlineAction(node);
4203
- const callee = node.expression.getText();
4204
- const type = callee.includes(".") ? callee.split(".").pop() : callee;
4205
- return { type: type === "assign" ? "xstate.assign" : type };
4059
+ return imports;
4060
+ }
4061
+ function buildSetupObject(schemas, impls, options) {
4062
+ const setup = {};
4063
+ if (options.xstateVersion === 6) {
4064
+ const schemasBlock = buildV6SchemasBlock(schemas, options);
4065
+ if (schemasBlock) setup.schemas = schemasBlock;
4066
+ } else {
4067
+ const types = buildTypesBlock(schemas, options);
4068
+ if (types) setup.types = types;
4206
4069
  }
4207
- return context.metaValue ? inlineCodeExpression(node.getText()) : node.getText();
4070
+ if (impls?.actions.length) setup.actions = buildActionsBlock(impls.actions, options);
4071
+ if (impls?.guards.length) setup.guards = buildGuardsBlock(impls.guards, options);
4072
+ if (impls?.actors.length) setup.actors = buildActorsBlock(impls.actors, options);
4073
+ if (impls?.delays.length) setup.delays = buildDelaysBlock(impls.delays);
4074
+ return setup;
4208
4075
  }
4209
- function isFunctionBinding(binding) {
4210
- return ts.isArrowFunction(binding) || ts.isFunctionExpression(binding) || ts.isFunctionDeclaration(binding);
4076
+ function buildTypesBlock(schemas, options) {
4077
+ if (!schemas || !options.includeTypeSyntax) return void 0;
4078
+ const types = {};
4079
+ const contextType = contextSchemaToTSType(schemas.context);
4080
+ if (contextType) types.context = raw(`{} as ${contextType}`);
4081
+ const eventsType = eventsSchemaToTSType(schemas.events);
4082
+ if (eventsType) types.events = raw(`{} as\n | ${eventsType}`);
4083
+ if (schemas.input) types.input = raw(`{} as ${jsonSchemaToTSType(schemas.input)}`);
4084
+ if (schemas.output) types.output = raw(`{} as ${jsonSchemaToTSType(schemas.output)}`);
4085
+ return Object.keys(types).length > 0 ? types : void 0;
4211
4086
  }
4212
- function evaluateFunctionCall(fn, args, bindings, context, depth) {
4213
- const scopedBindings = new Map(bindings);
4214
- for (const [index, parameter] of fn.parameters.entries()) {
4215
- if (!ts.isIdentifier(parameter.name)) continue;
4216
- const argument = args[index];
4217
- if (argument) scopedBindings.set(parameter.name.text, argument);
4218
- else if (parameter.initializer) scopedBindings.set(parameter.name.text, parameter.initializer);
4087
+ function buildV6SchemasBlock(schemas, options) {
4088
+ if (!schemas || !options.includeTypeSyntax) return void 0;
4089
+ const result = {};
4090
+ const contextType = contextSchemaToTSType(schemas.context);
4091
+ if (contextType) result.context = raw(`types<${contextType}>()`);
4092
+ if (schemas.events && Object.keys(schemas.events).length > 0) result.events = Object.fromEntries(Object.entries(schemas.events).map(([eventType, schema]) => [eventType, raw(`types<${eventPayloadSchemaToTSType(schema)}>()`)]));
4093
+ if (schemas.input) result.input = raw(`types<${jsonSchemaToTSType(schemas.input)}>()`);
4094
+ if (schemas.output) result.output = raw(`types<${jsonSchemaToTSType(schemas.output)}>()`);
4095
+ return Object.keys(result).length > 0 ? result : void 0;
4096
+ }
4097
+ function eventPayloadSchemaToTSType(schema) {
4098
+ const props = schema.properties ?? {};
4099
+ const payloadProps = Object.fromEntries(Object.entries(props).filter(([key]) => key !== "type"));
4100
+ if (Object.keys(payloadProps).length === 0) return "{}";
4101
+ return jsonSchemaToTSType({
4102
+ ...schema,
4103
+ properties: payloadProps,
4104
+ required: Array.isArray(schema.required) ? schema.required.filter((key) => key !== "type") : void 0
4105
+ });
4106
+ }
4107
+ function hasSchemaProperties(schema) {
4108
+ if (!schema) return false;
4109
+ if (schema.type === "object" || schema.properties) {
4110
+ const props = schema.properties;
4111
+ return !!props && Object.keys(props).length > 0;
4219
4112
  }
4220
- if (ts.isArrowFunction(fn) && !ts.isBlock(fn.body)) return expressionToValue(fn.body, scopedBindings, context, depth + 1);
4221
- if (context.v6 && context.transitionValue) return normalizeFunctionTransition(fn, scopedBindings, depth + 1);
4222
- if (context.v6 && context.actionValue) return normalizeFunctionAction(fn, scopedBindings);
4223
- return context.metaValue ? inlineCodeExpression(fn.getText()) : fn.name?.getText() ?? fn.getText();
4113
+ return true;
4224
4114
  }
4225
- function collectBindings(file) {
4226
- const bindings = /* @__PURE__ */ new Map();
4227
- for (const statement of file.statements) {
4228
- if (ts.isVariableStatement(statement)) {
4229
- for (const declaration of statement.declarationList.declarations) if (ts.isIdentifier(declaration.name) && declaration.initializer) bindings.set(declaration.name.text, declaration.initializer);
4115
+ function buildActionsBlock(actions, options) {
4116
+ const block = {};
4117
+ for (const implementation of actions) if (implementation.code?.body) {
4118
+ const inlineExpression = getInlineExpression(implementation.code.body);
4119
+ if (inlineExpression) {
4120
+ block[implementation.name] = raw(inlineExpression);
4230
4121
  continue;
4231
4122
  }
4232
- if (ts.isFunctionDeclaration(statement) && statement.name) bindings.set(statement.name.text, statement);
4233
- }
4234
- return bindings;
4235
- }
4236
- function isCreateMachineCall(node) {
4237
- const expression = node.expression;
4238
- if (ts.isIdentifier(expression)) return expression.text === "createMachine";
4239
- if (ts.isPropertyAccessExpression(expression)) return expression.name.text === "createMachine";
4240
- return false;
4123
+ const params = hasSchemaProperties(implementation.paramsSchema) ? options.includeTypeSyntax ? `, params: ${jsonSchemaToTSType(implementation.paramsSchema)}` : ", params" : "";
4124
+ block[implementation.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(implementation.code.body)}\n}`);
4125
+ } else block[implementation.name] = raw(`function ({ context, event }) {\n // TODO: implement ${implementation.name}\n}`);
4126
+ return block;
4241
4127
  }
4242
- function hasV6Syntax(source) {
4243
- const file = sourceFile(source);
4244
- const bindings = collectBindings(file);
4245
- let found = false;
4246
- function containsFunction(expression, seenBindings = /* @__PURE__ */ new Set()) {
4247
- if (ts.isFunctionDeclaration(expression)) return true;
4248
- const node = unwrapExpression(expression);
4249
- if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) return true;
4250
- if (ts.isIdentifier(node)) {
4251
- if (seenBindings.has(node.text)) return false;
4252
- const binding = bindings.get(node.text);
4253
- if (!binding) return false;
4254
- return containsFunction(binding, new Set([...seenBindings, node.text]));
4255
- }
4256
- if (ts.isObjectLiteralExpression(node)) return node.properties.some((property) => {
4257
- if (ts.isPropertyAssignment(property)) return containsFunction(property.initializer, seenBindings);
4258
- if (ts.isShorthandPropertyAssignment(property)) return containsFunction(property.name, seenBindings);
4259
- if (ts.isSpreadAssignment(property)) return containsFunction(property.expression, seenBindings);
4260
- return false;
4261
- });
4262
- if (ts.isArrayLiteralExpression(node)) return node.elements.some((element) => ts.isExpression(element) && containsFunction(element, seenBindings));
4263
- if (ts.isCallExpression(node)) return ts.isIdentifier(node.expression) && containsFunction(node.expression, seenBindings) || node.arguments.some((argument) => ts.isExpression(argument) && containsFunction(argument, seenBindings));
4264
- return false;
4265
- }
4266
- function visit(node) {
4267
- if (found) return;
4268
- if (ts.isPropertyAssignment(node) && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name))) {
4269
- const key = node.name.text;
4270
- if (key === "triggers" || key === "internalEvents" || key === "matches" || key === "actorSources" || key === "timeout" || key === "onTimeout" || key === "choice" || key === "route") {
4271
- found = true;
4272
- return;
4273
- }
4274
- if ((key === "on" || key === "after" || key === "always" || key === "choice" || key === "onDone" || key === "onError" || key === "onSnapshot" || key === "onTimeout" || key === "entry" || key === "exit" || key === "actions" && !ts.isObjectLiteralExpression(node.initializer)) && containsFunction(node.initializer)) {
4275
- found = true;
4276
- return;
4277
- }
4128
+ function buildGuardsBlock(guards, options) {
4129
+ const block = {};
4130
+ for (const guard of guards) if (guard.code?.body) {
4131
+ const inlineExpression = getInlineExpression(guard.code.body);
4132
+ if (inlineExpression) {
4133
+ block[guard.name] = raw(inlineExpression);
4134
+ continue;
4278
4135
  }
4279
- ts.forEachChild(node, visit);
4280
- }
4281
- visit(file);
4282
- return found;
4136
+ const params = hasSchemaProperties(guard.paramsSchema) ? options.includeTypeSyntax ? `, params: ${jsonSchemaToTSType(guard.paramsSchema)}` : ", params" : "";
4137
+ block[guard.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(guard.code.body)}\n}`);
4138
+ } else block[guard.name] = raw(`function ({ context, event }) {\n // TODO: implement ${guard.name}\n return false;\n}`);
4139
+ return block;
4283
4140
  }
4284
- function detectXStateSourceProfile(source) {
4285
- return hasV6Syntax(source) ? "xstate-v6-alpha" : "xstate-v5";
4141
+ function buildActorsBlock(actors, options) {
4142
+ const block = {};
4143
+ for (const actor of actors) if (actor.code?.body) {
4144
+ const inputType = options.includeTypeSyntax && hasSchemaProperties(actor.inputSchema) ? `: ${jsonSchemaToTSType(actor.inputSchema)}` : "";
4145
+ block[actor.name] = raw(`fromPromise(async ({ input }${inputType ? `: { input${inputType} }` : ""}) => {\n ${dedent(actor.code.body)}\n})`);
4146
+ } else block[actor.name] = raw(`fromPromise(async ({ input }) => {\n // TODO: implement ${actor.name}\n})`);
4147
+ return block;
4286
4148
  }
4287
- function xstateSourceToConfig(source, options = {}) {
4288
- const [config] = extractXStateMachineConfigs(source, options);
4289
- if (!config) throw new Error("No createMachine(...) or setup(...).createMachine(...) call found.");
4290
- return config;
4149
+ function buildDelaysBlock(delays) {
4150
+ const block = {};
4151
+ for (const delay of delays) if (delay.code?.body) {
4152
+ const inlineExpression = getInlineExpression(delay.code.body);
4153
+ if (inlineExpression) {
4154
+ block[delay.name] = raw(inlineExpression);
4155
+ continue;
4156
+ }
4157
+ block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
4158
+ } else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
4159
+ return block;
4291
4160
  }
4292
4161
  /**
4293
- * Extract every XState machine config from source without executing code.
4294
- * XState 5/6 syntax is inferred structurally unless a profile is supplied.
4162
+ * Returns the implementation to emit verbatim when `body` is already a complete
4163
+ * expression, so it is NOT wrapped in another `function ({ context, event }) { ... }`.
4164
+ * Handles two cases:
4165
+ * - `export default <expr>` → the inner expression.
4166
+ * - a bare function/arrow expression (e.g. a guard captured via `fn.toString()`
4167
+ * on import) → the expression itself.
4168
+ * Returns undefined for a plain statement body, which still needs wrapping.
4295
4169
  */
4296
- function extractXStateMachineConfigs(source, options = {}) {
4297
- const file = sourceFile(source);
4298
- const bindings = collectBindings(file);
4299
- const found = [];
4300
- const profile = options.profile === "auto" || !options.profile ? detectXStateSourceProfile(source) : options.profile;
4301
- function visit(node) {
4302
- if (!ts.isCallExpression(node) || !isCreateMachineCall(node)) {
4303
- ts.forEachChild(node, visit);
4304
- return;
4305
- }
4306
- const arg = node.arguments[0];
4307
- if (!arg) return;
4308
- const value = expressionToValue(arg, bindings, { v6: profile === "xstate-v6-alpha" });
4309
- if (value && typeof value === "object" && !Array.isArray(value)) found.push(value);
4310
- }
4311
- visit(file);
4312
- return found;
4170
+ function getInlineExpression(code) {
4171
+ const stripped = stripExportDefault(code);
4172
+ if (stripped !== code.trim()) return stripped;
4173
+ return isCompleteFunctionExpression(stripped) ? stripped : void 0;
4174
+ }
4175
+ /** True when `code` is a single function or arrow-function expression. */
4176
+ function isCompleteFunctionExpression(code) {
4177
+ const candidate = code.trim().replace(/;$/, "");
4178
+ const source = ts.createSourceFile("impl.ts", `(${candidate})`, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
4179
+ if ((source.parseDiagnostics ?? []).length > 0 || source.statements.length !== 1) return false;
4180
+ const [statement] = source.statements;
4181
+ if (!statement || !ts.isExpressionStatement(statement)) return false;
4182
+ let expression = statement.expression;
4183
+ if (ts.isParenthesizedExpression(expression)) expression = expression.expression;
4184
+ return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
4313
4185
  }
4314
4186
  const colorSchema = _enum([
4315
4187
  "green",
@@ -4553,7 +4425,12 @@ const machineFormatSchema = _enum([
4553
4425
  "scxml",
4554
4426
  "mermaid"
4555
4427
  ]);
4556
- const xstateSourceProfileSchema = _enum(["auto", ...MACHINE_PROFILES]);
4428
+ const canonicalMachineProfileSchema = custom((value) => typeof value === "string" && /^@statelyai\/xstate@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(value), "Expected an exact @statelyai/xstate profile reference.");
4429
+ const xstateSourceProfileSchema = union([
4430
+ literal("auto"),
4431
+ _enum(LEGACY_MACHINE_PROFILES),
4432
+ canonicalMachineProfileSchema
4433
+ ]);
4557
4434
  const machineInputSchema = object({
4558
4435
  machine: union([record(string(), unknown()), string()]),
4559
4436
  format: machineFormatSchema.optional(),
@@ -5078,4 +4955,4 @@ function getScriptKind(fileName) {
5078
4955
  }
5079
4956
 
5080
4957
  //#endregion
5081
- export { RawCode as a, eventsSchemaToTSType as c, jsonSchemaToTSType as d, raw as f, INLINE_EXPRESSION_DIRECTIVE_FIELDS as i, graphToMachineConfig as l, xstateSourceToConfig as m, getStatelyPragma as n, contextSchemaToTSType as o, serializeJS as p, upsertStatelyPragma as r, detectXStateSourceProfile as s, findStatelyPragmaAttachments as t, graphToXStateTS as u };
4958
+ export { RawCode as a, eventsSchemaToTSType as c, jsonSchemaToTSType as d, normalizeMachineProfile as f, xstateSourceToConfig as h, INLINE_EXPRESSION_DIRECTIVE_FIELDS as i, graphToMachineConfig as l, serializeJS as m, getStatelyPragma as n, contextSchemaToTSType as o, raw as p, upsertStatelyPragma as r, detectXStateSourceProfile as s, findStatelyPragmaAttachments as t, graphToXStateTS as u };