@statelyai/sdk 0.28.0 → 0.29.1

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,6 +1,5 @@
1
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 "./openapi-BTDjYWXd.mjs";
2
2
  import ts from "typescript";
3
- import "xstate";
4
3
  import "xstate/graph";
5
4
 
6
5
  //#region ../../node_modules/.pnpm/js-yaml@4.2.0/node_modules/js-yaml/dist/js-yaml.mjs
@@ -3487,10 +3486,16 @@ function singleOrArrayRecord(record) {
3487
3486
  * Remove empty arrays/objects/strings, unwrap single-element arrays.
3488
3487
  * Matches studio's simplifyAttributes behavior.
3489
3488
  */
3489
+ /**
3490
+ * Keys whose empty object value is authored, not incidental: `context: {}`
3491
+ * declares that the machine has context, so dropping it loses information.
3492
+ */
3493
+ const KEEP_WHEN_EMPTY = new Set(["context"]);
3490
3494
  function simplifyAttributes(obj) {
3491
3495
  for (const key of Object.keys(obj)) {
3492
3496
  const value = obj[key];
3493
3497
  if (value === void 0 || value === null) delete obj[key];
3498
+ else if (KEEP_WHEN_EMPTY.has(key)) continue;
3494
3499
  else if (Array.isArray(value)) {
3495
3500
  if (value.length === 0) delete obj[key];
3496
3501
  else if (value.length === 1) obj[key] = value[0];
@@ -3535,7 +3540,7 @@ function deepSimplify(config) {
3535
3540
  return config;
3536
3541
  }
3537
3542
  function buildMeta(meta, color) {
3538
- if (isCodeExpression$3(meta)) return meta;
3543
+ if (isCodeExpression$4(meta)) return meta;
3539
3544
  const result = {};
3540
3545
  if (meta) {
3541
3546
  for (const [k, v] of Object.entries(meta)) if (v !== void 0 && v !== null) result[k] = v;
@@ -3543,7 +3548,7 @@ function buildMeta(meta, color) {
3543
3548
  if (color) result["@statelyai.color"] = color;
3544
3549
  return Object.keys(result).length > 0 ? result : void 0;
3545
3550
  }
3546
- function isCodeExpression$3(value) {
3551
+ function isCodeExpression$4(value) {
3547
3552
  return Boolean(value && typeof value === "object" && !Array.isArray(value) && value["@type"] === "code" && typeof value.expr === "string");
3548
3553
  }
3549
3554
  /** Format event param — supports { type: string } (new) and plain string (legacy) */
@@ -3554,7 +3559,7 @@ function formatEventParam(event) {
3554
3559
  }
3555
3560
  function formatStringParam(value) {
3556
3561
  if (typeof value === "string") return `'${value}'`;
3557
- return isCodeExpression$3(value) ? serializeJS(value) : "undefined";
3562
+ return isCodeExpression$4(value) ? serializeJS(value) : "undefined";
3558
3563
  }
3559
3564
  function formatInlineObject(value) {
3560
3565
  return `{ ${Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => `${formatObjectKey(key)}: ${serializeJS(item)}`).join(", ")} }`;
@@ -3589,7 +3594,11 @@ const builtInActionParamSchemas = {
3589
3594
  }),
3590
3595
  "xstate.stopChild": object({ actorRef: string().optional() }),
3591
3596
  "xstate.log": object({ label: string().optional() }),
3592
- "xstate.assign": object({ assignment: record(string(), unknown()).optional() }).catchall(unknown())
3597
+ "xstate.assign": object({ assignment: record(string(), unknown()).optional() }).catchall(unknown()),
3598
+ "xstate.choose": object({ branches: array(object({
3599
+ guard: unknown().optional(),
3600
+ actions: array(unknown()).optional()
3601
+ })).optional() })
3593
3602
  };
3594
3603
  const XSTATE_BUILT_IN_ACTIONS = {
3595
3604
  "xstate.enqueue": {
@@ -3685,6 +3694,16 @@ const XSTATE_BUILT_IN_ACTIONS = {
3685
3694
  return `log(${(params?.label ? `'${params.label}'` : void 0) ?? ""})`;
3686
3695
  }
3687
3696
  },
3697
+ "xstate.choose": {
3698
+ package: "xstate",
3699
+ version: "^5",
3700
+ import: "enqueueActions",
3701
+ importKind: "named",
3702
+ paramsSchema: builtInActionParamSchemas["xstate.choose"],
3703
+ emit(params) {
3704
+ return emitChooseBranches(params?.branches ?? []);
3705
+ }
3706
+ },
3688
3707
  "xstate.assign": {
3689
3708
  package: "xstate",
3690
3709
  version: "^5",
@@ -3692,7 +3711,7 @@ const XSTATE_BUILT_IN_ACTIONS = {
3692
3711
  importKind: "named",
3693
3712
  paramsSchema: builtInActionParamSchemas["xstate.assign"],
3694
3713
  emit(params) {
3695
- if (isCodeExpression$3(params?.assignment)) return `assign(${serializeJS(params.assignment)})`;
3714
+ if (isCodeExpression$4(params?.assignment)) return `assign(${serializeJS(params.assignment)})`;
3696
3715
  const assignments = params?.assignment && typeof params.assignment === "object" && !Array.isArray(params.assignment) ? params.assignment : params;
3697
3716
  const entries = Object.entries(assignments ?? {}).filter(([k, v]) => k && v !== void 0);
3698
3717
  if (entries.length === 0) return "assign({})";
@@ -3703,6 +3722,35 @@ const XSTATE_BUILT_IN_ACTIONS = {
3703
3722
  function isBuiltInActionType(type) {
3704
3723
  return type in XSTATE_BUILT_IN_ACTIONS;
3705
3724
  }
3725
+ /** Lower `xstate.choose` branches to an `enqueueActions` if/else-if chain. */
3726
+ function emitChooseBranches(branches) {
3727
+ const lines = [];
3728
+ const indent = (depth) => " ".repeat(depth);
3729
+ const serializeEnqueued = (action, depth) => {
3730
+ if (action && typeof action === "object" && !Array.isArray(action) && Object.keys(action).length === 1 && typeof action.type === "string") return serializeJS(action.type);
3731
+ return serializeJS(action, depth * 2);
3732
+ };
3733
+ const body = (actions, depth) => (actions ?? []).map((action) => `${indent(depth)}enqueue(${serializeEnqueued(action, depth)});`);
3734
+ let closed = false;
3735
+ let opened = false;
3736
+ for (const branch of branches) {
3737
+ if (closed) break;
3738
+ if (branch.guard === void 0) {
3739
+ if (opened) {
3740
+ lines.push(` } else {`);
3741
+ lines.push(...body(branch.actions, 2));
3742
+ lines.push(" }");
3743
+ } else lines.push(...body(branch.actions, 1));
3744
+ closed = true;
3745
+ continue;
3746
+ }
3747
+ lines.push(` ${opened ? "} else if" : "if"} (check(${serializeJS(branch.guard)})) {`);
3748
+ lines.push(...body(branch.actions, 2));
3749
+ opened = true;
3750
+ }
3751
+ if (opened && !closed) lines.push(" }");
3752
+ return `enqueueActions(({ check, enqueue }) => {\n${lines.join("\n")}\n})`;
3753
+ }
3706
3754
  function emitBuiltInAction(type, params) {
3707
3755
  return XSTATE_BUILT_IN_ACTIONS[type].emit(params);
3708
3756
  }
@@ -3743,8 +3791,12 @@ function serializeGuard(guard, asTypeRef) {
3743
3791
  * Converts a built-in xstate ActionItem to a code expression directive,
3744
3792
  * or returns a plain { type, params } object for user-defined actions.
3745
3793
  */
3746
- function serializeActionItem(action) {
3794
+ function serializeActionItem(action, keepChooseStructured = false) {
3747
3795
  const { type, params } = action;
3796
+ if (keepChooseStructured && type === "xstate.choose") return {
3797
+ type,
3798
+ params
3799
+ };
3748
3800
  if (type === "xstate.enqueue" && typeof params?.code === "string") return inlineCodeExpression$1(params.code);
3749
3801
  const exprCode = type === "xstate.expr" && typeof params?.code === "string" ? params.code : void 0;
3750
3802
  if (isBuiltInActionType(type)) {
@@ -3770,7 +3822,8 @@ function tagToString(tag) {
3770
3822
  }
3771
3823
  function graphToMachineConfig(graph, options = {}) {
3772
3824
  const v6 = isXStateV6Profile(graph.data.profile);
3773
- const { showDescriptions = true, showMeta = true, inlineGuardsAsTypeRef = false } = options;
3825
+ const { showDescriptions = true, showMeta = true, inlineGuardsAsTypeRef = false, keepChooseStructured = false } = options;
3826
+ const serializeAction = (action) => serializeActionItem(action, keepChooseStructured);
3774
3827
  const config = {};
3775
3828
  function getNodeConfig(node) {
3776
3829
  const nodeConfig = node.parentId ? {} : config;
@@ -3790,11 +3843,11 @@ function graphToMachineConfig(graph, options = {}) {
3790
3843
  target: initialNode.data.key,
3791
3844
  input: node.data.initialInput
3792
3845
  } : initialNode.data.key : void 0,
3793
- target: nodeType === "history" && initialNode ? initialNode.data.key : void 0,
3846
+ target: nodeType === "history" && initialNode ? resolveTransitionTarget(graph, node, initialNode) : void 0,
3794
3847
  ...node.data.timeout !== void 0 ? { timeout: node.data.timeout } : void 0,
3795
3848
  ...node.data.route !== void 0 ? { route: node.data.route } : void 0,
3796
- ...node.data.entry?.length ? { entry: node.data.entry.map(serializeActionItem) } : void 0,
3797
- ...node.data.exit?.length ? { exit: node.data.exit.map(serializeActionItem) } : void 0,
3849
+ ...node.data.entry?.length ? { entry: node.data.entry.map(serializeAction) } : void 0,
3850
+ ...node.data.exit?.length ? { exit: node.data.exit.map(serializeAction) } : void 0,
3798
3851
  ...node.data.invokes?.length ? { invoke: node.data.invokes.map((inv) => ({
3799
3852
  src: inv.srcExpression ?? inv.src,
3800
3853
  id: inv.invocationId ?? inv.id,
@@ -3833,7 +3886,7 @@ function graphToMachineConfig(graph, options = {}) {
3833
3886
  guard: edge.data.guard ? serializeGuard(edge.data.guard, inlineGuardsAsTypeRef) : void 0,
3834
3887
  ...edge.data.context !== void 0 ? { context: edge.data.context } : void 0,
3835
3888
  ...edge.data.input !== void 0 ? { input: edge.data.input } : void 0,
3836
- actions: edge.data.actions?.length ? edge.data.actions.map(serializeActionItem) : void 0,
3889
+ actions: edge.data.actions?.length ? edge.data.actions.map(serializeAction) : void 0,
3837
3890
  description: edge.data.description ?? void 0,
3838
3891
  ...transitionMeta ? { meta: transitionMeta } : void 0
3839
3892
  };
@@ -4212,7 +4265,8 @@ function isShadowedWithinExpression(node, expression) {
4212
4265
  }
4213
4266
  return false;
4214
4267
  }
4215
- function replacementText(node, expression) {
4268
+ function replacementText(node, expression, nested = true) {
4269
+ if (!nested) return expression;
4216
4270
  if (ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node) return `${node.text}: (${expression})`;
4217
4271
  return `(${expression})`;
4218
4272
  }
@@ -4254,7 +4308,7 @@ function resolvedExpressionText(expression, bindings, resolving = /* @__PURE__ *
4254
4308
  replacements.push({
4255
4309
  start: node.getStart(source) - start,
4256
4310
  end: node.getEnd() - start,
4257
- text: replacementText(node, resolvedExpressionText(binding, bindings, nextResolving))
4311
+ text: replacementText(node, resolvedExpressionText(binding, bindings, nextResolving), node !== expression)
4258
4312
  });
4259
4313
  return;
4260
4314
  }
@@ -4359,6 +4413,15 @@ function schemasObjectToValue(node) {
4359
4413
  }
4360
4414
  function propertyContext(parent, key) {
4361
4415
  const inherited = parent.imports ? { imports: parent.imports } : {};
4416
+ if (parent.statesMap) return {
4417
+ ...inherited,
4418
+ v6: parent.v6
4419
+ };
4420
+ if (key === "states") return {
4421
+ ...inherited,
4422
+ v6: parent.v6,
4423
+ statesMap: true
4424
+ };
4362
4425
  if (parent.machineValue && (key === "actors" || key === "actorSources")) return {
4363
4426
  ...inherited,
4364
4427
  v6: parent.v6,
@@ -4497,9 +4560,40 @@ function hashString(value) {
4497
4560
  function inlineGuardCode(params, condition) {
4498
4561
  return `${params} => ${condition.trimStart().startsWith("{") ? `(${condition})` : condition}`;
4499
4562
  }
4563
+ function namedReferenceName(node, objectName) {
4564
+ if (!node) return null;
4565
+ const target = unwrapExpression(node);
4566
+ if (ts.isElementAccessExpression(target) && ts.isIdentifier(target.expression) && target.expression.text === objectName && ts.isStringLiteralLike(target.argumentExpression)) return target.argumentExpression.text;
4567
+ if (ts.isPropertyAccessExpression(target) && ts.isIdentifier(target.expression) && target.expression.text === objectName) return target.name.text;
4568
+ return null;
4569
+ }
4570
+ function namedReferenceParams(node, bindings) {
4571
+ if (!node) return {};
4572
+ const target = unwrapExpression(node);
4573
+ if (!ts.isObjectLiteralExpression(target) && !ts.isArrayLiteralExpression(target)) return {};
4574
+ const value = expressionToValue(target, bindings, { effectArgumentValue: true }, 0);
4575
+ return value && typeof value === "object" ? value : {};
4576
+ }
4577
+ function namedGuardFromCondition(text) {
4578
+ const [statement] = ts.createSourceFile("guard.ts", text, ts.ScriptTarget.Latest, true).statements;
4579
+ if (!statement || !ts.isExpressionStatement(statement)) return void 0;
4580
+ const call = unwrapExpression(statement.expression);
4581
+ if (!ts.isCallExpression(call)) return void 0;
4582
+ const name = namedReferenceName(call.expression, "guards");
4583
+ if (!name) return void 0;
4584
+ return {
4585
+ type: name,
4586
+ params: namedReferenceParams(call.arguments[1], /* @__PURE__ */ new Map())
4587
+ };
4588
+ }
4500
4589
  function guardFromConditions(conds, params) {
4501
4590
  const simplified = simplifyConditions(conds);
4502
4591
  if (simplified.length === 0) return void 0;
4592
+ const only = simplified.length === 1 ? simplified[0] : void 0;
4593
+ if (only) {
4594
+ const named = namedGuardFromCondition(conditionText(only));
4595
+ if (named) return named;
4596
+ }
4503
4597
  const code = inlineGuardCode(params, simplified.map(conditionText).join(" && "));
4504
4598
  return {
4505
4599
  type: `inline:${hashString(code)}`,
@@ -4599,13 +4693,20 @@ function expressionStatementAction(statement, enqName, bindings) {
4599
4693
  const expression = unwrapExpression(statement.expression);
4600
4694
  if (!ts.isCallExpression(expression)) return null;
4601
4695
  const callee = expression.expression;
4602
- if (ts.isIdentifier(callee) && callee.text === enqName) return {
4603
- type: "xstate.expr",
4604
- params: {
4605
- code: resolvedExpressionText(expression, bindings),
4606
- lang: "ts"
4607
- }
4608
- };
4696
+ if (ts.isIdentifier(callee) && callee.text === enqName) {
4697
+ const actionName = namedReferenceName(expression.arguments[0], "actions");
4698
+ if (actionName) return {
4699
+ type: actionName,
4700
+ params: namedReferenceParams(expression.arguments[1], bindings)
4701
+ };
4702
+ return {
4703
+ type: "xstate.expr",
4704
+ params: {
4705
+ code: resolvedExpressionText(expression, bindings),
4706
+ lang: "ts"
4707
+ }
4708
+ };
4709
+ }
4609
4710
  if (!ts.isPropertyAccessExpression(callee)) return null;
4610
4711
  if (!ts.isIdentifier(callee.expression) || callee.expression.text !== enqName) return null;
4611
4712
  const method = callee.name.text;
@@ -4813,6 +4914,79 @@ function normalizeFunctionTransition(fn, bindings, depth) {
4813
4914
  if (transitions.length > 1) return transitions;
4814
4915
  return fallbackFunctionTransition(fn);
4815
4916
  }
4917
+ /**
4918
+ * XState v5 has no `choose()`, so `xstate.choose` is exported as the canonical
4919
+ * `enqueueActions(({ check, enqueue }) => { if (check(g)) { enqueue(a); } ... })`
4920
+ * if/else-if chain. Read exactly that shape back into structured branches so
4921
+ * the action round-trips; anything else stays an opaque inline action.
4922
+ */
4923
+ function chooseActionFromEnqueueActions(node, bindings) {
4924
+ if (!ts.isIdentifier(node.expression) || node.expression.text !== "enqueueActions" || node.arguments.length !== 1) return null;
4925
+ const fn = unwrapExpression(node.arguments[0]);
4926
+ if (!ts.isArrowFunction(fn) && !ts.isFunctionExpression(fn)) return null;
4927
+ if (fn.parameters.length !== 1) return null;
4928
+ const pattern = fn.parameters[0].name;
4929
+ if (!ts.isObjectBindingPattern(pattern)) return null;
4930
+ const bound = /* @__PURE__ */ new Map();
4931
+ for (const element of pattern.elements) {
4932
+ if (element.dotDotDotToken || !ts.isIdentifier(element.name)) return null;
4933
+ const key = element.propertyName ? propName(element.propertyName) : element.name.text;
4934
+ if (!key) return null;
4935
+ bound.set(key, element.name.text);
4936
+ }
4937
+ const checkName = bound.get("check");
4938
+ const enqueueName = bound.get("enqueue");
4939
+ if (!checkName || !enqueueName || bound.size !== 2) return null;
4940
+ const body = fn.body;
4941
+ if (!body || !ts.isBlock(body)) return null;
4942
+ const enqueuedAction = (statement) => {
4943
+ if (!ts.isExpressionStatement(statement)) return null;
4944
+ const call = unwrapExpression(statement.expression);
4945
+ if (!ts.isCallExpression(call) || !ts.isIdentifier(call.expression) || call.expression.text !== enqueueName || call.arguments.length !== 1) return null;
4946
+ const value = expressionToValue(call.arguments[0], bindings, { effectArgumentValue: true }, 0);
4947
+ return typeof value === "string" ? { type: value } : value;
4948
+ };
4949
+ const blockActions = (statements) => {
4950
+ const actions = [];
4951
+ for (const statement of statements) {
4952
+ const action = enqueuedAction(statement);
4953
+ if (action === null) return null;
4954
+ actions.push(action);
4955
+ }
4956
+ return actions;
4957
+ };
4958
+ const branches = [];
4959
+ const readChain = (statement) => {
4960
+ const condition = unwrapExpression(statement.expression);
4961
+ if (!ts.isCallExpression(condition) || !ts.isIdentifier(condition.expression) || condition.expression.text !== checkName || condition.arguments.length !== 1) return false;
4962
+ if (!ts.isBlock(statement.thenStatement)) return false;
4963
+ const actions = blockActions(statement.thenStatement.statements);
4964
+ if (!actions) return false;
4965
+ branches.push({
4966
+ guard: expressionToValue(condition.arguments[0], bindings, { effectArgumentValue: true }, 0),
4967
+ actions
4968
+ });
4969
+ const alternate = statement.elseStatement;
4970
+ if (!alternate) return true;
4971
+ if (ts.isIfStatement(alternate)) return readChain(alternate);
4972
+ if (!ts.isBlock(alternate)) return false;
4973
+ const elseActions = blockActions(alternate.statements);
4974
+ if (!elseActions) return false;
4975
+ branches.push({ actions: elseActions });
4976
+ return true;
4977
+ };
4978
+ if (body.statements.length === 1 && ts.isIfStatement(body.statements[0])) {
4979
+ if (!readChain(body.statements[0])) return null;
4980
+ } else {
4981
+ const actions = blockActions(body.statements);
4982
+ if (!actions || actions.length === 0) return null;
4983
+ branches.push({ actions });
4984
+ }
4985
+ return {
4986
+ type: "xstate.choose",
4987
+ params: { branches }
4988
+ };
4989
+ }
4816
4990
  function inlineAction(fn) {
4817
4991
  return {
4818
4992
  type: "xstate.expr",
@@ -4859,7 +5033,34 @@ function codeImportsForExpression(expression, imports) {
4859
5033
  visit(file);
4860
5034
  return found.size ? [...found.values()] : void 0;
4861
5035
  }
4862
- function normalizeFunctionAction(fn, _bindings) {
5036
+ /**
5037
+ * `entry: ({ actions }, enq) => { enq(actions['NAME'], params); ... }` is the
5038
+ * shape the exporter writes for a plain list of *named* actions, so it is
5039
+ * decomposed back into those actions instead of surviving as one opaque
5040
+ * `xstate.enqueue` code action. Direct `enq.raise(...)` / `enq(() => ...)`
5041
+ * bodies are deliberately left alone: they are authored code, not a list.
5042
+ */
5043
+ function enqueuedNamedActions(fn, bindings) {
5044
+ const body = fn.body;
5045
+ if (!body || !ts.isBlock(body) || body.statements.length === 0) return null;
5046
+ const enqName = enqueueParamName(fn);
5047
+ const actions = [];
5048
+ for (const statement of body.statements) {
5049
+ if (!ts.isExpressionStatement(statement)) return null;
5050
+ const expression = unwrapExpression(statement.expression);
5051
+ if (!ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== enqName) return null;
5052
+ const name = namedReferenceName(expression.arguments[0], "actions");
5053
+ if (!name) return null;
5054
+ actions.push({
5055
+ type: name,
5056
+ params: namedReferenceParams(expression.arguments[1], bindings)
5057
+ });
5058
+ }
5059
+ return actions;
5060
+ }
5061
+ function normalizeFunctionAction(fn, bindings) {
5062
+ const actions = enqueuedNamedActions(fn, bindings);
5063
+ if (actions) return actions.length === 1 ? actions[0] : actions;
4863
5064
  return enqueueAction(fn);
4864
5065
  }
4865
5066
  function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__PURE__ */ new Map()) {
@@ -4934,6 +5135,7 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
4934
5135
  if (context.machineContextValue && (ts.isArrowFunction(node) || ts.isFunctionExpression(node))) return inlineCodeExpression(node.getText());
4935
5136
  if (context.targetValue) {
4936
5137
  if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
5138
+ if (ts.isArrayLiteralExpression(node) && node.elements.length > 0 && node.elements.every((element) => ts.isStringLiteral(element) || ts.isNoSubstitutionTemplateLiteral(element))) return node.elements.map((element) => element.text);
4937
5139
  if (ts.isIdentifier(node)) {
4938
5140
  const binding = bindings.get(node.text);
4939
5141
  if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
@@ -4956,11 +5158,11 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
4956
5158
  return inlineCodeExpression(node.getText());
4957
5159
  }
4958
5160
  if (context.timeoutValue && (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isCallExpression(node))) return inlineCodeExpression(node.getText());
4959
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return context.ioValue ? inlineCodeExpression(JSON.stringify(node.text)) : node.text;
4960
- if (ts.isNumericLiteral(node)) return context.ioValue ? inlineCodeExpression(node.text) : Number(node.text);
4961
- if (node.kind === ts.SyntaxKind.TrueKeyword) return context.ioValue ? inlineCodeExpression("true") : true;
4962
- if (node.kind === ts.SyntaxKind.FalseKeyword) return context.ioValue ? inlineCodeExpression("false") : false;
4963
- if (node.kind === ts.SyntaxKind.NullKeyword) return context.ioValue ? inlineCodeExpression("null") : null;
5161
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
5162
+ if (ts.isNumericLiteral(node)) return Number(node.text);
5163
+ if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
5164
+ if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
5165
+ if (node.kind === ts.SyntaxKind.NullKeyword) return null;
4964
5166
  if (context.effectArgumentValue && !ts.isObjectLiteralExpression(node) && !ts.isArrayLiteralExpression(node)) {
4965
5167
  if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
4966
5168
  return inlineCodeExpression(resolvedExpressionText(node, bindings));
@@ -5020,7 +5222,11 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
5020
5222
  const configArg = node.arguments.length > 1 ? node.arguments[1] : node.arguments[0];
5021
5223
  return configArg ? expressionToValue(configArg, bindings, { v6: context.v6 }, depth + 1) : {};
5022
5224
  }
5023
- if (context.actionValue) return inlineAction(node);
5225
+ if (context.actionValue) {
5226
+ const choose = chooseActionFromEnqueueActions(node, bindings);
5227
+ if (choose) return choose;
5228
+ return inlineAction(node);
5229
+ }
5024
5230
  const callee = node.expression.getText();
5025
5231
  const type = callee.includes(".") ? callee.split(".").pop() : callee;
5026
5232
  return { type: type === "assign" ? "xstate.assign" : type };
@@ -5118,16 +5324,53 @@ function hasV6Syntax(source) {
5118
5324
  if (!binding) return false;
5119
5325
  return containsFunction(binding, new Set([...seenBindings, node.text]));
5120
5326
  }
5121
- if (ts.isObjectLiteralExpression(node)) return node.properties.some((property) => {
5122
- if (ts.isPropertyAssignment(property)) return containsFunction(property.initializer, seenBindings);
5123
- if (ts.isShorthandPropertyAssignment(property)) return containsFunction(property.name, seenBindings);
5124
- if (ts.isSpreadAssignment(property)) return containsFunction(property.expression, seenBindings);
5125
- return false;
5126
- });
5127
5327
  if (ts.isArrayLiteralExpression(node)) return node.elements.some((element) => ts.isExpression(element) && containsFunction(element, seenBindings));
5128
5328
  if (ts.isCallExpression(node)) return ts.isIdentifier(node.expression) && containsFunction(node.expression, seenBindings) || node.arguments.some((argument) => ts.isExpression(argument) && containsFunction(argument, seenBindings));
5129
5329
  return false;
5130
5330
  }
5331
+ function containsEnqueueAction(expression, seen = /* @__PURE__ */ new Set()) {
5332
+ if (seen.has(expression)) return false;
5333
+ seen.add(expression);
5334
+ const node = ts.isFunctionDeclaration(expression) ? expression : unwrapExpression(expression);
5335
+ if (ts.isIdentifier(node)) {
5336
+ const binding = bindings.get(node.text);
5337
+ return binding ? containsEnqueueAction(binding, seen) : false;
5338
+ }
5339
+ if (ts.isArrayLiteralExpression(node)) return node.elements.some((element) => ts.isSpreadElement(element) ? containsEnqueueAction(element.expression, seen) : ts.isExpression(element) && containsEnqueueAction(element, seen));
5340
+ if (!isFunctionBinding(node)) return false;
5341
+ const enqueue = node.parameters[1]?.name;
5342
+ if (!enqueue || !ts.isIdentifier(enqueue) || !node.body) return false;
5343
+ const enqueueName = enqueue.text;
5344
+ let callsEnqueue = false;
5345
+ function visit(node) {
5346
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) return;
5347
+ if (ts.isCallExpression(node)) {
5348
+ const callee = node.expression;
5349
+ const receiver = ts.isPropertyAccessExpression(callee) ? callee.expression : callee;
5350
+ if (ts.isIdentifier(receiver) && receiver.text === enqueueName) callsEnqueue = true;
5351
+ }
5352
+ ts.forEachChild(node, visit);
5353
+ }
5354
+ visit(node.body);
5355
+ return callsEnqueue;
5356
+ }
5357
+ function containsFunctionTransitionMap(expression, seen = /* @__PURE__ */ new Set()) {
5358
+ if (seen.has(expression) || ts.isFunctionDeclaration(expression)) return false;
5359
+ seen.add(expression);
5360
+ const node = unwrapExpression(expression);
5361
+ if (ts.isIdentifier(node)) {
5362
+ const binding = bindings.get(node.text);
5363
+ return binding ? containsFunctionTransitionMap(binding, seen) : false;
5364
+ }
5365
+ if (!ts.isObjectLiteralExpression(node)) return false;
5366
+ return node.properties.some((property) => {
5367
+ if (ts.isMethodDeclaration(property)) return true;
5368
+ if (ts.isPropertyAssignment(property)) return containsFunction(property.initializer);
5369
+ if (ts.isShorthandPropertyAssignment(property)) return containsFunction(property.name);
5370
+ if (ts.isSpreadAssignment(property)) return containsFunctionTransitionMap(property.expression, seen);
5371
+ return false;
5372
+ });
5373
+ }
5131
5374
  function visitSyntax(node) {
5132
5375
  if (found) return;
5133
5376
  if (ts.isIdentifier(node)) {
@@ -5144,7 +5387,24 @@ function hasV6Syntax(source) {
5144
5387
  found = true;
5145
5388
  return;
5146
5389
  }
5147
- 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)) {
5390
+ if ([
5391
+ "entry",
5392
+ "exit",
5393
+ "actions"
5394
+ ].includes(key) && containsEnqueueAction(node.initializer)) {
5395
+ found = true;
5396
+ return;
5397
+ }
5398
+ if ((key === "on" || key === "after") && containsFunctionTransitionMap(node.initializer)) {
5399
+ found = true;
5400
+ return;
5401
+ }
5402
+ if ([
5403
+ "always",
5404
+ "onDone",
5405
+ "onError",
5406
+ "onSnapshot"
5407
+ ].includes(key) && containsFunction(node.initializer)) {
5148
5408
  found = true;
5149
5409
  return;
5150
5410
  }
@@ -5499,7 +5759,7 @@ function graphToXStateTS(graph, options = {}) {
5499
5759
  const inferredXStateVersion = isXStateV6ProfileRef(graph.data.profile ?? "xstate-v5") ? 6 : 5;
5500
5760
  const { exportStyle = "named", targetLanguage = "typescript", xstateVersion = inferredXStateVersion, xstateV6SchemaFormat = "types", ...configOptions } = options;
5501
5761
  const schemas = graph.data.schemas;
5502
- const impls = filterInlineImplementations(graph.data.implementations);
5762
+ const impls = filterInlineImplementations$1(graph.data.implementations);
5503
5763
  const supportsTypeSyntax = targetLanguage === "typescript";
5504
5764
  const hasSchemas = !!(schemas && (schemas.context || schemas.events || schemas.input || schemas.output));
5505
5765
  const hasStateSchemas = graph.nodes.some((node) => node.data.schemas);
@@ -5511,8 +5771,8 @@ function graphToXStateTS(graph, options = {}) {
5511
5771
  const builtInActions = getUsedBuiltInActions(graph, xstateVersion);
5512
5772
  const actorSourceImports = getActorSourceImports(graph);
5513
5773
  const implementationImports = getImplementationImports(impls);
5514
- const codeImports = getCodeExpressionImports(graph);
5515
- const imports = buildImports({
5774
+ const codeImports = getCodeExpressionImports$1(graph);
5775
+ const imports = buildImports$1({
5516
5776
  hasSetup,
5517
5777
  hasActors,
5518
5778
  actors: impls?.actors ?? [],
@@ -5524,7 +5784,10 @@ function graphToXStateTS(graph, options = {}) {
5524
5784
  usesTypes: xstateVersion === 6 && supportsTypeSyntax && (hasSchemas || hasStateSchemas) && xstateV6SchemaFormat === "types",
5525
5785
  usesZod: xstateVersion === 6 && (hasSchemas || hasStateSchemas) && xstateV6SchemaFormat === "zod"
5526
5786
  });
5527
- const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, configOptions)) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
5787
+ const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, {
5788
+ ...configOptions,
5789
+ keepChooseStructured: true
5790
+ })) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
5528
5791
  if (xstateVersion === 6) stripStateSchemas(machineConfig);
5529
5792
  let machineExpr;
5530
5793
  if (hasSetup) {
@@ -5601,7 +5864,7 @@ function buildV6StateSchemasBlock(schemas, options) {
5601
5864
  }
5602
5865
  return Object.keys(result).length ? result : void 0;
5603
5866
  }
5604
- function filterInlineImplementations(impls) {
5867
+ function filterInlineImplementations$1(impls) {
5605
5868
  if (!impls) return impls;
5606
5869
  return {
5607
5870
  ...impls,
@@ -5619,7 +5882,8 @@ const BUILTIN_ACTION_IMPORTS = {
5619
5882
  "xstate.spawnChild": "spawnChild",
5620
5883
  "xstate.stopChild": "stopChild",
5621
5884
  "xstate.log": "log",
5622
- "xstate.assign": "assign"
5885
+ "xstate.assign": "assign",
5886
+ "xstate.choose": "enqueueActions"
5623
5887
  };
5624
5888
  /** Check inline action/entry/exit code for references to xstate builtins */
5625
5889
  function scanInlineCodeForBuiltins(code, used) {
@@ -5661,6 +5925,10 @@ function mapV6MachineConfig(value, context = {}) {
5661
5925
  if (!value || typeof value !== "object") return value;
5662
5926
  const result = {};
5663
5927
  for (const [key, item] of Object.entries(value)) {
5928
+ if (key === "states") {
5929
+ result[key] = mapV6StatesMap(item);
5930
+ continue;
5931
+ }
5664
5932
  if (key === "entry" || key === "exit" || key === "actions") {
5665
5933
  result[key] = toV6ActionField(Array.isArray(item) ? item : item === void 0 ? [] : [item]);
5666
5934
  continue;
@@ -5677,6 +5945,13 @@ function mapV6MachineConfig(value, context = {}) {
5677
5945
  }
5678
5946
  return result;
5679
5947
  }
5948
+ /** Walks a `states` map, treating every entry as a state node. */
5949
+ function mapV6StatesMap(value) {
5950
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
5951
+ const result = {};
5952
+ for (const [key, item] of Object.entries(value)) result[key] = mapV6MachineConfig(item);
5953
+ return result;
5954
+ }
5680
5955
  function mapV6TransitionMap(value) {
5681
5956
  if (!value || typeof value !== "object" || Array.isArray(value)) return value;
5682
5957
  const result = {};
@@ -5863,6 +6138,7 @@ function buildV6TransitionFunction(transitions) {
5863
6138
  });
5864
6139
  }
5865
6140
  if (branches.length === 0) return;
6141
+ if (branches.slice(0, -1).some((branch) => branch.condition === "true")) return;
5866
6142
  const generated = branches.flatMap((branch) => [branch.condition, ...branch.body]).join("\n");
5867
6143
  let renderedBranches = branches;
5868
6144
  let merged = mergeV6FirstParam(authoredFirstParam, inferV6ArgBindings(generated));
@@ -5904,19 +6180,21 @@ function buildV6ActionFunction(actions, transition) {
5904
6180
  return raw(`(${bindings.length ? `{ ${bindings.join(", ")} }` : "_"}, enq) => {\n${[...statements.map((statement) => ` ${formatV6Statement(statement)}`), ...returnValue ? [` return ${returnValue};`] : []].join("\n")}\n}`);
5905
6181
  }
5906
6182
  function formatV6Statement(statement) {
5907
- return statement === "{" || statement === "}" || statement.endsWith(";") ? statement : `${statement};`;
6183
+ const trimmed = statement.trim();
6184
+ return trimmed.endsWith("{") || trimmed.startsWith("}") || trimmed.endsWith(";") ? statement : `${statement};`;
5908
6185
  }
5909
6186
  function renderV6Effects(effects, finalContext) {
5910
- if (!(finalContext !== void 0 || effects.some((effect) => effect.contextValue))) return { statements: effects.flatMap((effect) => effect.statements ?? []) };
6187
+ if (!(finalContext !== void 0 || effects.some((effect) => effect.contextValue || effect.mutatesContext))) return { statements: effects.flatMap((effect) => effect.statements ?? []) };
5911
6188
  const statements = ["let nextContext = context"];
5912
- const inCurrentContext = (statement) => {
5913
- statements.push("{", " const context = nextContext", ` ${statement}`, "}");
6189
+ const inCurrentContext = (body) => {
6190
+ if (body.length === 0) return;
6191
+ statements.push("{", " const context = nextContext", ...body.map((line) => ` ${line}`), "}");
5914
6192
  };
5915
6193
  for (const effect of effects) {
5916
- for (const statement of effect.statements ?? []) inCurrentContext(statement);
5917
- if (effect.contextValue) inCurrentContext(`nextContext = { ...nextContext, ...(${effect.contextValue}) }`);
6194
+ inCurrentContext(effect.statements ?? []);
6195
+ if (effect.contextValue) inCurrentContext([`nextContext = { ...nextContext, ...(${effect.contextValue}) }`]);
5918
6196
  }
5919
- if (finalContext !== void 0) inCurrentContext(`nextContext = { ...nextContext, ...(${finalContext}) }`);
6197
+ if (finalContext !== void 0) inCurrentContext([`nextContext = { ...nextContext, ...(${finalContext}) }`]);
5920
6198
  return {
5921
6199
  statements,
5922
6200
  contextValue: "nextContext"
@@ -5946,6 +6224,10 @@ function mapMachineActionFields(value, mapActions) {
5946
6224
  if (!value || typeof value !== "object") return value;
5947
6225
  const result = {};
5948
6226
  for (const [key, item] of Object.entries(value)) {
6227
+ if (key === "states" && item && typeof item === "object" && !Array.isArray(item)) {
6228
+ result[key] = Object.fromEntries(Object.entries(item).map(([stateKey, state]) => [stateKey, mapMachineActionFields(state, mapActions)]));
6229
+ continue;
6230
+ }
5949
6231
  if (key === "entry" || key === "exit" || key === "actions") {
5950
6232
  const wasArray = Array.isArray(item);
5951
6233
  result[key] = mapActions(wasArray ? item : item === void 0 ? [] : [item], wasArray);
@@ -5984,6 +6266,7 @@ function actionToV6Effect(action) {
5984
6266
  const type = record.type;
5985
6267
  if (typeof type !== "string") return null;
5986
6268
  const params = record.params && typeof record.params === "object" && !Array.isArray(record.params) ? record.params : {};
6269
+ const rawParams = record.params;
5987
6270
  if (type === "xstate.raise") {
5988
6271
  const options = actionOptions(params, ["event"]);
5989
6272
  return { statements: [`enq.raise(${serializeJS(params.event)}${options})`] };
@@ -6000,8 +6283,49 @@ function actionToV6Effect(action) {
6000
6283
  return { statements: [`enq.spawn(${serializeJS(params.src)}${options})`] };
6001
6284
  }
6002
6285
  if (type === "xstate.stopChild") return { statements: [`enq.stop(${serializeJS(params.actorRef)})`] };
6003
- if (type === "xstate.assign") return { contextValue: serializeJS(params.assignment ?? params) };
6004
- if (!type.startsWith("xstate.")) return { statements: [`enq(${/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(type) ? `actions.${type}` : `actions[${serializeJS(type)}]`}${Object.keys(params).length > 0 ? `, ${serializeJS(params)}` : ""})`] };
6286
+ if (type === "xstate.choose") {
6287
+ const branches = Array.isArray(params.branches) ? params.branches : [];
6288
+ const statements = [];
6289
+ let mutatesContext = false;
6290
+ let opened = false;
6291
+ for (const raw of branches) {
6292
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
6293
+ const branch = raw;
6294
+ const effects = (Array.isArray(branch.actions) ? branch.actions : []).map(actionToV6Effect);
6295
+ if (effects.some((effect) => !effect)) return null;
6296
+ const body = effects.flatMap((effect) => {
6297
+ const lines = [...effect.statements ?? []];
6298
+ if (effect.mutatesContext) mutatesContext = true;
6299
+ if (effect.contextValue) {
6300
+ mutatesContext = true;
6301
+ lines.push(`nextContext = { ...nextContext, ...(${effect.contextValue}) }`);
6302
+ }
6303
+ return lines;
6304
+ });
6305
+ if (branch.guard === void 0) {
6306
+ if (opened) {
6307
+ statements.push("} else {");
6308
+ statements.push(...body.map((line) => ` ${line}`));
6309
+ statements.push("}");
6310
+ } else statements.push(...body);
6311
+ opened = false;
6312
+ break;
6313
+ }
6314
+ const guard = guardCondition(typeof branch.guard === "string" ? { type: branch.guard } : branch.guard);
6315
+ if (!guard) return null;
6316
+ statements.push(`${opened ? "} else if" : "if"} (${guard.condition}) {`);
6317
+ statements.push(...body.map((line) => ` ${line}`));
6318
+ opened = true;
6319
+ }
6320
+ if (opened) statements.push("}");
6321
+ if (statements.length === 0) return null;
6322
+ return mutatesContext ? {
6323
+ statements,
6324
+ mutatesContext
6325
+ } : { statements };
6326
+ }
6327
+ if (type === "xstate.assign") return { contextValue: serializeJS(unwrapTemplateExpressions(params.assignment ?? params)) };
6328
+ if (!type.startsWith("xstate.")) return { statements: [`enq(${/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(type) ? `actions.${type}` : `actions[${serializeJS(type)}]`}${(Array.isArray(rawParams) ? rawParams.length > 0 : Object.keys(params).length > 0) ? `, ${serializeJS(rawParams)}` : ""})`] };
6005
6329
  return null;
6006
6330
  }
6007
6331
  function getV6AssignmentArgs(code, includeAll = false) {
@@ -6061,7 +6385,7 @@ function actionOptions(params, consumedKeys) {
6061
6385
  const rest = Object.fromEntries(Object.entries(params).filter(([key, value]) => !consumedKeys.includes(key) && value !== void 0));
6062
6386
  return Object.keys(rest).length ? `, ${serializeJS(rest)}` : "";
6063
6387
  }
6064
- function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, implementationImports, codeImports, xstateVersion, usesTypes, usesZod }) {
6388
+ function buildImports$1({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, implementationImports, codeImports, xstateVersion, usesTypes, usesZod }) {
6065
6389
  const xstateImports = [];
6066
6390
  if (hasSetup) xstateImports.push("setup");
6067
6391
  else xstateImports.push("createMachine");
@@ -6089,7 +6413,7 @@ function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSource
6089
6413
  if (usesZod && !externalImports.get("zod")?.has("z")) imports.push("import { z } from 'zod';");
6090
6414
  return imports.join("\n");
6091
6415
  }
6092
- function getCodeExpressionImports(graph) {
6416
+ function getCodeExpressionImports$1(graph) {
6093
6417
  const imports = /* @__PURE__ */ new Map();
6094
6418
  function visit(value) {
6095
6419
  if (!value || typeof value !== "object") return;
@@ -6238,7 +6562,7 @@ function hasSchemaProperties(schema) {
6238
6562
  function buildActionsBlock(actions, options) {
6239
6563
  const block = {};
6240
6564
  for (const implementation of actions) if (implementation.code?.body) {
6241
- const inlineExpression = getInlineExpression(implementation.code.body);
6565
+ const inlineExpression = getInlineExpression$1(implementation.code.body);
6242
6566
  if (inlineExpression) {
6243
6567
  block[implementation.name] = raw(inlineExpression);
6244
6568
  continue;
@@ -6251,7 +6575,7 @@ function buildActionsBlock(actions, options) {
6251
6575
  function buildGuardsBlock(guards, options) {
6252
6576
  const block = {};
6253
6577
  for (const guard of guards) if (guard.code?.body) {
6254
- const inlineExpression = getInlineExpression(guard.code.body);
6578
+ const inlineExpression = getInlineExpression$1(guard.code.body);
6255
6579
  if (inlineExpression) {
6256
6580
  block[guard.name] = raw(inlineExpression);
6257
6581
  continue;
@@ -6289,7 +6613,7 @@ function getActorLogicExpression(code) {
6289
6613
  function buildDelaysBlock(delays) {
6290
6614
  const block = {};
6291
6615
  for (const delay of delays) if (delay.code?.body) {
6292
- const inlineExpression = getInlineExpression(delay.code.body);
6616
+ const inlineExpression = getInlineExpression$1(delay.code.body);
6293
6617
  if (inlineExpression) {
6294
6618
  block[delay.name] = raw(inlineExpression);
6295
6619
  continue;
@@ -6312,7 +6636,7 @@ function buildDelaysBlock(delays) {
6312
6636
  * on import) → the expression itself.
6313
6637
  * Returns undefined for a plain statement body, which still needs wrapping.
6314
6638
  */
6315
- function getInlineExpression(code) {
6639
+ function getInlineExpression$1(code) {
6316
6640
  const stripped = stripExportDefault(code);
6317
6641
  if (stripped !== code.trim()) return stripped;
6318
6642
  return isCompleteFunctionExpression(stripped) || isCompleteXStateHelperExpression(stripped) ? stripped : void 0;
@@ -6348,6 +6672,624 @@ function isCompleteFunctionExpression(code) {
6348
6672
  if (!expression) return false;
6349
6673
  return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
6350
6674
  }
6675
+ /**
6676
+ * Escapes text that is interpolated into a `/* ... *\/` marker so it cannot
6677
+ * close the comment early.
6678
+ */
6679
+ function escapeMarkerText(text) {
6680
+ return text.replace(/\*\//g, "*\\/");
6681
+ }
6682
+ /** Builds a `TODO: v5-only` block comment around untrusted text. */
6683
+ function v5OnlyMarker(detail) {
6684
+ return `/* TODO: v5-only (${escapeMarkerText(detail)}); no XState v4 equivalent */`;
6685
+ }
6686
+ /**
6687
+ * Emits XState **v4** (deprecated) TypeScript for a graph.
6688
+ *
6689
+ * The v4 surface differs from v5 in ways this emitter downgrades:
6690
+ * `createMachine(config, options)` instead of `setup().createMachine()`,
6691
+ * `cond` instead of `guard`, `services` instead of `actors`, `internal: false`
6692
+ * instead of `reenter: true`, `done.invoke.X` / `error.platform.X` /
6693
+ * `done.state.X` event names, and positional `(context, event)` implementation
6694
+ * arguments (enabled by `predictableActionArguments`).
6695
+ *
6696
+ * Concepts with no v4 equivalent (`emit`, `spawnChild`, `enqueueActions`,
6697
+ * actor-logic creators such as `fromPromise`) are emitted verbatim with a
6698
+ * `// TODO: v5-only` marker rather than silently dropped.
6699
+ */
6700
+ function graphToXStateV4TS(graph, options = {}) {
6701
+ const { exportStyle = "named", targetLanguage = "typescript", ...configOptions } = options;
6702
+ const supportsTypeSyntax = targetLanguage === "typescript";
6703
+ const schemas = graph.data.schemas;
6704
+ const impls = filterInlineImplementations(graph.data.implementations);
6705
+ const rawConfig = graphToMachineConfig(graph, configOptions);
6706
+ const services = {};
6707
+ const config = transformState(rawConfig, { services });
6708
+ const machineConfig = {};
6709
+ if (config.id !== void 0) machineConfig.id = config.id;
6710
+ machineConfig.predictableActionArguments = true;
6711
+ machineConfig.preserveActionOrder = true;
6712
+ const schemaBlock = supportsTypeSyntax ? buildSchemaBlock(schemas) : void 0;
6713
+ if (schemaBlock) machineConfig.schema = schemaBlock;
6714
+ for (const [key, value] of Object.entries(config)) {
6715
+ if (key === "id") continue;
6716
+ machineConfig[key] = value;
6717
+ }
6718
+ const machineOptions = buildMachineOptions(impls, services);
6719
+ const configStr = serializeJS(machineConfig, 0);
6720
+ const optionsStr = Object.keys(machineOptions).length ? serializeJS(machineOptions, 0) : void 0;
6721
+ const machineExpr = optionsStr ? `createMachine(${configStr}, ${optionsStr})` : `createMachine(${configStr})`;
6722
+ const lines = [
6723
+ buildImports(machineExpr, getCodeExpressionImports(graph)),
6724
+ "",
6725
+ `const machine = ${machineExpr};`
6726
+ ];
6727
+ if (exportStyle === "named") lines.push("", "export { machine };");
6728
+ else if (exportStyle === "default") lines.push("", "export default machine;");
6729
+ return lines.join("\n") + "\n";
6730
+ }
6731
+ /** Keys emitted by the shared config builder that v4 has no place for. */
6732
+ const DROPPED_STATE_KEYS = new Set([
6733
+ "schemas",
6734
+ "timeout",
6735
+ "route",
6736
+ "onTimeout",
6737
+ "onSnapshot",
6738
+ "version",
6739
+ "options"
6740
+ ]);
6741
+ function transformState(state, ctx, sourceKey) {
6742
+ const result = {};
6743
+ let choiceBranches;
6744
+ for (const [key, value] of Object.entries(state)) {
6745
+ if (value === void 0 || DROPPED_STATE_KEYS.has(key)) continue;
6746
+ switch (key) {
6747
+ case "type":
6748
+ if (value !== "choice") result.type = value;
6749
+ break;
6750
+ case "choice":
6751
+ choiceBranches = transformTransitionValue(value, sourceKey);
6752
+ break;
6753
+ case "initial":
6754
+ result.initial = value && typeof value === "object" && !Array.isArray(value) ? value.target : value;
6755
+ break;
6756
+ case "output":
6757
+ result.data = transformCodeValues(value);
6758
+ break;
6759
+ case "entry":
6760
+ case "exit":
6761
+ result[key] = transformActions(value);
6762
+ break;
6763
+ case "invoke":
6764
+ result.invoke = transformInvoke(value, ctx, sourceKey);
6765
+ break;
6766
+ case "on":
6767
+ case "after":
6768
+ result[key] = transformTransitionMap(value, key === "on", sourceKey);
6769
+ break;
6770
+ case "always":
6771
+ case "onDone":
6772
+ case "onError":
6773
+ result[key] = transformTransitionValue(value, sourceKey);
6774
+ break;
6775
+ case "states": {
6776
+ const states = value;
6777
+ result.states = Object.fromEntries(Object.entries(states).map(([stateKey, child]) => [stateKey, transformState(child, ctx, stateKey)]));
6778
+ break;
6779
+ }
6780
+ default: result[key] = value;
6781
+ }
6782
+ }
6783
+ if (choiceBranches !== void 0) {
6784
+ const existing = result.always === void 0 ? [] : Array.isArray(result.always) ? result.always : [result.always];
6785
+ const branches = Array.isArray(choiceBranches) ? choiceBranches : [choiceBranches];
6786
+ result.always = [...existing, ...branches];
6787
+ }
6788
+ return result;
6789
+ }
6790
+ /** Rewrites embedded code expressions of a plain data value for v4. */
6791
+ function transformCodeValues(value) {
6792
+ if (isCodeExpression$3(value)) return raw(toV4Code(value.expr));
6793
+ if (Array.isArray(value)) return value.map(transformCodeValues);
6794
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, transformCodeValues(item)]));
6795
+ return value;
6796
+ }
6797
+ /** v5 event names → their v4 spellings. */
6798
+ function toV4EventName(eventName) {
6799
+ if (eventName.startsWith("xstate.done.actor.")) return `done.invoke.${eventName.slice(18)}`;
6800
+ if (eventName.startsWith("xstate.error.actor.")) return `error.platform.${eventName.slice(19)}`;
6801
+ if (eventName.startsWith("xstate.done.state.")) return `done.state.${eventName.slice(18)}`;
6802
+ return eventName;
6803
+ }
6804
+ function transformTransitionMap(value, renameEvents, sourceKey) {
6805
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
6806
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [renameEvents ? toV4EventName(key) : key, transformTransitionValue(item, sourceKey)]));
6807
+ }
6808
+ /**
6809
+ * True when a resolved v4 target points at the source state itself or one of
6810
+ * its descendants — the only targets for which `internal` changes behaviour.
6811
+ * Targets resolve against the source's parent, so a descendant of the source
6812
+ * is spelled `<sourceKey>.<child>` (or `.<child>` for root transitions).
6813
+ */
6814
+ function targetsSelfOrDescendant(target, sourceKey) {
6815
+ if (typeof target !== "string" || !target) return false;
6816
+ if (sourceKey === void 0) return target.startsWith(".");
6817
+ return target === sourceKey || target.startsWith(`${sourceKey}.`);
6818
+ }
6819
+ /** Renders a v6 `matches` guard as readable text for the TODO marker. */
6820
+ function describeMatches(matches) {
6821
+ if (typeof matches === "string") return matches;
6822
+ if (isCodeExpression$3(matches)) return matches.expr;
6823
+ try {
6824
+ return serializeJS(matches, 0).replace(/\s+/g, " ");
6825
+ } catch {
6826
+ return String(matches);
6827
+ }
6828
+ }
6829
+ function transformTransitionValue(value, sourceKey) {
6830
+ if (Array.isArray(value)) return value.map((item) => transformTransitionValue(item, sourceKey));
6831
+ if (!value || typeof value !== "object") return value;
6832
+ if (isCodeExpression$3(value)) return raw(toV4Code(value.expr));
6833
+ const transition = value;
6834
+ const result = {};
6835
+ let reenter;
6836
+ let contextUpdate;
6837
+ let matches;
6838
+ for (const [key, item] of Object.entries(transition)) {
6839
+ if (item === void 0) continue;
6840
+ switch (key) {
6841
+ case "guard":
6842
+ result.cond = transformGuard(item);
6843
+ break;
6844
+ case "reenter":
6845
+ reenter = item;
6846
+ break;
6847
+ case "actions":
6848
+ result.actions = transformActions(item);
6849
+ break;
6850
+ case "context":
6851
+ contextUpdate = item;
6852
+ break;
6853
+ case "matches":
6854
+ matches = item;
6855
+ break;
6856
+ case "input": break;
6857
+ default: result[key] = item;
6858
+ }
6859
+ }
6860
+ if (reenter === true) result.internal = false;
6861
+ else if (targetsSelfOrDescendant(result.target, sourceKey)) result.internal = true;
6862
+ if (matches !== void 0) {
6863
+ const marker = v5OnlyMarker(`matches guard: ${describeMatches(matches)}`);
6864
+ result.cond = result.cond === void 0 ? raw(`undefined ${marker}`) : raw(`${serializeJS(result.cond, 0)} ${marker}`);
6865
+ }
6866
+ if (contextUpdate !== void 0) {
6867
+ const assignAction = raw(`assign(${serializeJS(transformCodeValues(contextUpdate), 0)})`);
6868
+ result.actions = [...result.actions === void 0 ? [] : Array.isArray(result.actions) ? result.actions : [result.actions], assignAction];
6869
+ }
6870
+ return result;
6871
+ }
6872
+ /** v4 reads parameters off the action/cond object itself, so they are spread. */
6873
+ function toV4ParameterizedObject(value) {
6874
+ const { type, params } = value;
6875
+ if (typeof type !== "string") return value;
6876
+ if (!params || typeof params !== "object") return type;
6877
+ const v4Params = transformCodeValues(params);
6878
+ const name = "type" in v4Params ? raw(`'${type}' ${v5OnlyMarker(`param named \`type\` collides with the ${JSON.stringify(type)} name`)}`) : type;
6879
+ return {
6880
+ ...v4Params,
6881
+ type: name
6882
+ };
6883
+ }
6884
+ function transformGuard(guard) {
6885
+ if (isCodeExpression$3(guard)) return raw(toV4Code(guard.expr));
6886
+ if (guard && typeof guard === "object" && !Array.isArray(guard)) return toV4ParameterizedObject(guard);
6887
+ return guard;
6888
+ }
6889
+ function transformActions(value) {
6890
+ const wasArray = Array.isArray(value);
6891
+ const mapped = (wasArray ? value : [value]).map(transformAction);
6892
+ return wasArray ? mapped : mapped[0];
6893
+ }
6894
+ function transformAction(action) {
6895
+ if (isCodeExpression$3(action)) return raw(toV4Code(action.expr));
6896
+ if (action && typeof action === "object" && !Array.isArray(action)) return toV4ParameterizedObject(action);
6897
+ return action;
6898
+ }
6899
+ function transformInvoke(value, ctx, sourceKey) {
6900
+ if (Array.isArray(value)) return value.map((item) => transformInvoke(item, ctx, sourceKey));
6901
+ if (!value || typeof value !== "object") return value;
6902
+ const invoke = value;
6903
+ const result = {};
6904
+ for (const [key, item] of Object.entries(invoke)) {
6905
+ if (item === void 0) continue;
6906
+ switch (key) {
6907
+ case "src":
6908
+ if (isCodeExpression$3(item)) {
6909
+ const name = typeof invoke.id === "string" && invoke.id ? invoke.id : `service${Object.keys(ctx.services).length + 1}`;
6910
+ ctx.services[name] = raw(toV4Code(item.expr));
6911
+ result.src = name;
6912
+ } else result.src = item;
6913
+ break;
6914
+ case "input":
6915
+ result.data = transformCodeValues(item);
6916
+ break;
6917
+ case "onDone":
6918
+ case "onError":
6919
+ result[key] = transformTransitionValue(item, sourceKey);
6920
+ break;
6921
+ case "output":
6922
+ case "timeout":
6923
+ case "registryKey":
6924
+ case "onSnapshot":
6925
+ case "onTimeout": break;
6926
+ default: result[key] = item;
6927
+ }
6928
+ }
6929
+ return result;
6930
+ }
6931
+ /** v5 helpers that exist in v4 under a different name. */
6932
+ const RENAMED_HELPERS = { stopChild: "stop" };
6933
+ /**
6934
+ * v4 helpers that are not root exports of `xstate@4`; they live on the
6935
+ * `actions` namespace export.
6936
+ */
6937
+ const V4_ACTIONS_NAMESPACE_HELPERS = ["respond", "escalate"];
6938
+ /** v5-only helpers with no v4 equivalent. */
6939
+ const V5_ONLY_HELPERS = [
6940
+ "emit",
6941
+ "spawnChild",
6942
+ "enqueueActions",
6943
+ "fromPromise",
6944
+ "fromCallback",
6945
+ "fromObservable",
6946
+ "fromEventObservable",
6947
+ "fromTransition",
6948
+ "createAsyncLogic"
6949
+ ];
6950
+ /**
6951
+ * Bindings the emitter re-binds itself, so dropping them from a destructured
6952
+ * parameter list is not a loss the user has to act on.
6953
+ */
6954
+ const REBOUND_BINDINGS = new Set(["params", "input"]);
6955
+ /** Bindings v4 passes positionally, so they survive the rewrite. */
6956
+ const V4_BOUND_BINDINGS = new Set(["context", "event"]);
6957
+ /**
6958
+ * Names that mark a destructured parameter list as a v5 implementation
6959
+ * signature rather than an object literal argument.
6960
+ */
6961
+ const V5_DESTRUCTURED_BINDINGS = new Set([
6962
+ "context",
6963
+ "event",
6964
+ "params",
6965
+ "input",
6966
+ "self",
6967
+ "system",
6968
+ "enqueue",
6969
+ "spawn",
6970
+ "emit",
6971
+ "check",
6972
+ "signal"
6973
+ ]);
6974
+ /** Parses a snippet permissively so positions can be read off the AST. */
6975
+ function parseSnippet(source) {
6976
+ return ts.createSourceFile("snippet.tsx", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
6977
+ }
6978
+ /** True when the snippet parsed without syntax errors. */
6979
+ function parsedCleanly(sourceFile) {
6980
+ const diagnostics = sourceFile.parseDiagnostics;
6981
+ return !diagnostics || diagnostics.length === 0;
6982
+ }
6983
+ /**
6984
+ * The positional v4 parameter list for a v5 destructured binding list, or
6985
+ * `undefined` when the bindings are not a v5 implementation signature.
6986
+ */
6987
+ function v4ParameterList(names) {
6988
+ if (!names.length) return void 0;
6989
+ if (!names.some((name) => V5_DESTRUCTURED_BINDINGS.has(name))) return;
6990
+ if (names.includes("context")) return names.includes("event") ? "context, event" : "context";
6991
+ return names.includes("event") ? "_, event" : "";
6992
+ }
6993
+ /**
6994
+ * Rewrites v5 destructured *parameter* lists (`({ context, event }) => ...`)
6995
+ * to positional v4 ones. Only parameter positions of functions and arrows are
6996
+ * touched, so a shorthand object *argument* such as `send({ context, event })`
6997
+ * is left alone. Bindings v4 cannot supply are collected into `dropped`.
6998
+ */
6999
+ function rewriteDestructuredParameters(code, dropped) {
7000
+ const sourceFile = parseSnippet(code);
7001
+ const edits = [];
7002
+ const visit = (node) => {
7003
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
7004
+ const [parameter] = node.parameters;
7005
+ if (parameter && node.parameters.length === 1 && !parameter.type && !parameter.initializer && !parameter.dotDotDotToken && ts.isObjectBindingPattern(parameter.name)) {
7006
+ const elements = parameter.name.elements;
7007
+ if (elements.every((element) => !element.propertyName && !element.initializer && !element.dotDotDotToken && ts.isIdentifier(element.name))) {
7008
+ const names = elements.map((element) => element.name.getText());
7009
+ const replacement = v4ParameterList(names);
7010
+ if (replacement !== void 0) {
7011
+ for (const name of names) if (!V4_BOUND_BINDINGS.has(name) && !REBOUND_BINDINGS.has(name)) dropped.add(name);
7012
+ edits.push({
7013
+ start: parameter.getStart(sourceFile),
7014
+ end: parameter.getEnd(),
7015
+ text: replacement
7016
+ });
7017
+ }
7018
+ }
7019
+ }
7020
+ }
7021
+ ts.forEachChild(node, visit);
7022
+ };
7023
+ ts.forEachChild(sourceFile, visit);
7024
+ let result = code;
7025
+ for (const edit of edits.sort((a, b) => b.start - a.start)) result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
7026
+ return result;
7027
+ }
7028
+ /**
7029
+ * Rewrites a v5 implementation expression for v4: positional implementation
7030
+ * arguments, renamed helpers, and a marker on anything v4 cannot express.
7031
+ */
7032
+ function toV4Code(code) {
7033
+ const dropped = /* @__PURE__ */ new Set();
7034
+ let result = rewriteDestructuredParameters(stripExportDefault(code), dropped);
7035
+ for (const [from, to] of Object.entries(RENAMED_HELPERS)) result = result.replace(new RegExp(`\\b${from}\\(`, "g"), `${to}(`);
7036
+ for (const helper of V4_ACTIONS_NAMESPACE_HELPERS) result = result.replace(new RegExp(`(?<!\\.)\\b${helper}\\(`, "g"), `actions.${helper}(`);
7037
+ const unsupported = [...V5_ONLY_HELPERS.filter((helper) => new RegExp(`\\b${helper}\\s*\\(`).test(result)), ...dropped];
7038
+ if (unsupported.length) result = `${result} ${v5OnlyMarker(unsupported.join(", "))}`;
7039
+ return result;
7040
+ }
7041
+ /**
7042
+ * True when a body is a single expression, so `return` can be prefixed. Parsed
7043
+ * as `(body)`: a statement such as `if (x) run()` fails to parse that way, and
7044
+ * an object literal such as `{ a: 1 }` parses as an expression rather than a
7045
+ * block.
7046
+ */
7047
+ function isBareExpression(body) {
7048
+ const trimmed = body.trim();
7049
+ if (!trimmed) return false;
7050
+ const sourceFile = parseSnippet(`(${trimmed})`);
7051
+ if (!parsedCleanly(sourceFile)) return false;
7052
+ if (sourceFile.statements.length !== 1) return false;
7053
+ const statement = sourceFile.statements[0];
7054
+ return !!statement && ts.isExpressionStatement(statement) && ts.isParenthesizedExpression(statement.expression);
7055
+ }
7056
+ /** True when an implementation body reads a re-bound v5 binding. */
7057
+ function referencesBinding(body, name) {
7058
+ return new RegExp(`\\b${name}\\b`).test(body);
7059
+ }
7060
+ /**
7061
+ * True when `name` is referenced free in a block body: it is read somewhere
7062
+ * that no enclosing declaration inside the body binds. Declarations tracked
7063
+ * are variable declarations, function/arrow/catch parameters, function and
7064
+ * class names, so a nested `(params) => params.id` shadows without suppressing
7065
+ * an outer read.
7066
+ */
7067
+ function referencesFreeBinding(body, name) {
7068
+ const sourceFile = parseSnippet(body);
7069
+ const scopes = [/* @__PURE__ */ new Set()];
7070
+ let found = false;
7071
+ const declare = (bindingName) => {
7072
+ if (ts.isIdentifier(bindingName)) {
7073
+ scopes[scopes.length - 1]?.add(bindingName.text);
7074
+ return;
7075
+ }
7076
+ for (const element of bindingName.elements) if (ts.isBindingElement(element)) declare(element.name);
7077
+ };
7078
+ const isDeclared = () => scopes.some((scope) => scope.has(name));
7079
+ /** True when an identifier node is a value reference, not a name position. */
7080
+ const isReference = (node) => {
7081
+ const parent = node.parent;
7082
+ if (!parent) return true;
7083
+ if (ts.isPropertyAccessExpression(parent) && parent.name === node) return false;
7084
+ if (ts.isQualifiedName(parent) && parent.right === node) return false;
7085
+ if ((ts.isPropertyAssignment(parent) || ts.isMethodDeclaration(parent) || ts.isPropertyDeclaration(parent) || ts.isEnumMember(parent)) && parent.name === node) return false;
7086
+ if (ts.isBindingElement(parent) && parent.propertyName === node) return false;
7087
+ if (ts.isJsxAttribute(parent) && parent.name === node) return false;
7088
+ if (ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent)) return false;
7089
+ if ((ts.isVariableDeclaration(parent) || ts.isParameter(parent) || ts.isFunctionDeclaration(parent) || ts.isFunctionExpression(parent) || ts.isClassDeclaration(parent) || ts.isClassExpression(parent) || ts.isBindingElement(parent)) && parent.name === node) return false;
7090
+ if (ts.isLabeledStatement(parent) && parent.label === node) return false;
7091
+ return true;
7092
+ };
7093
+ const withScope = (run) => {
7094
+ scopes.push(/* @__PURE__ */ new Set());
7095
+ run();
7096
+ scopes.pop();
7097
+ };
7098
+ const visit = (node) => {
7099
+ if (found) return;
7100
+ if (ts.isIdentifier(node)) {
7101
+ if (node.text === name && isReference(node) && !isDeclared()) found = true;
7102
+ return;
7103
+ }
7104
+ if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node)) {
7105
+ if (ts.isFunctionDeclaration(node) && node.name) declare(node.name);
7106
+ withScope(() => {
7107
+ for (const parameter of node.parameters) declare(parameter.name);
7108
+ if (ts.isFunctionExpression(node) && node.name) declare(node.name);
7109
+ for (const parameter of node.parameters) if (parameter.initializer) visit(parameter.initializer);
7110
+ if (node.body) visit(node.body);
7111
+ });
7112
+ return;
7113
+ }
7114
+ if (ts.isBlock(node) || ts.isCaseBlock(node)) {
7115
+ withScope(() => ts.forEachChild(node, visit));
7116
+ return;
7117
+ }
7118
+ if (ts.isCatchClause(node)) {
7119
+ withScope(() => {
7120
+ if (node.variableDeclaration) declare(node.variableDeclaration.name);
7121
+ visit(node.block);
7122
+ });
7123
+ return;
7124
+ }
7125
+ if (ts.isVariableDeclaration(node)) {
7126
+ if (node.initializer) visit(node.initializer);
7127
+ declare(node.name);
7128
+ return;
7129
+ }
7130
+ if ((ts.isClassDeclaration(node) || ts.isClassExpression(node)) && node.name) declare(node.name);
7131
+ ts.forEachChild(node, visit);
7132
+ };
7133
+ ts.forEachChild(sourceFile, visit);
7134
+ return found;
7135
+ }
7136
+ /**
7137
+ * True when the emitter should re-bind `name` around a block body: the body
7138
+ * reads it free and does not declare it itself.
7139
+ */
7140
+ function needsRebind(body, name) {
7141
+ return referencesFreeBinding(body, name);
7142
+ }
7143
+ function filterInlineImplementations(impls) {
7144
+ if (!impls) return impls;
7145
+ return {
7146
+ ...impls,
7147
+ actions: impls.actions.filter((action) => !action.name.startsWith("inline:")),
7148
+ guards: impls.guards.filter((guard) => !guard.name.startsWith("inline:")),
7149
+ delays: impls.delays.filter((delay) => !delay.name.startsWith("inline:"))
7150
+ };
7151
+ }
7152
+ function buildMachineOptions(impls, liftedServices) {
7153
+ const result = {};
7154
+ if (impls?.actions.length) result.actions = Object.fromEntries(impls.actions.map((action) => [action.name, raw(implementationFunction(action, "// TODO: implement"))]));
7155
+ if (impls?.guards.length) result.guards = Object.fromEntries(impls.guards.map((guard) => [guard.name, raw(implementationFunction(guard, "// TODO: implement\n return false;", "cond"))]));
7156
+ const services = { ...liftedServices };
7157
+ for (const actor of impls?.actors ?? []) services[actor.name] = raw(serviceImplementation(actor));
7158
+ if (Object.keys(services).length) result.services = services;
7159
+ if (impls?.delays.length) result.delays = Object.fromEntries(impls.delays.map((delay) => [delay.name, raw(implementationFunction(delay, "// TODO: implement\n return 1000;", "delay"))]));
7160
+ return result;
7161
+ }
7162
+ /**
7163
+ * Emits a v4 implementation. v4 calls actions/guards with
7164
+ * `(context, event, meta)`, where `meta.action` (actions, delays) and
7165
+ * `meta.cond` (guards) carry the action/cond object that parameters were
7166
+ * spread onto, so `params` is re-bound from there when the body reads it.
7167
+ */
7168
+ function implementationFunction(implementation, todo, kind = "action") {
7169
+ const body = implementation.code?.body;
7170
+ if (!body) return `function (context, event) {\n ${todo}\n}`;
7171
+ const inline = getInlineExpression(body);
7172
+ const canRebind = kind !== "delay";
7173
+ const metaKey = kind === "cond" ? "cond" : "action";
7174
+ const readsParams = inline ? referencesBinding(body, "params") : needsRebind(body, "params");
7175
+ const usesParams = readsParams && canRebind;
7176
+ const marker = readsParams && !canRebind ? ` ${PARAMS_IN_DELAY_MARKER}` : "";
7177
+ if (inline) {
7178
+ const converted = toV4Code(inline);
7179
+ if (!usesParams) return `${converted}${marker}`;
7180
+ return `function (context, event, meta) {\n const params = meta.${metaKey};\n return (${converted})(context, event);\n}`;
7181
+ }
7182
+ const code = toV4Code(dedent(body));
7183
+ const statement = isBareExpression(code) ? `return ${code};` : code;
7184
+ if (!usesParams) return `function (context, event) {\n ${statement}\n}${marker}`;
7185
+ return `function (context, event, meta) {\n const params = meta.${metaKey};\n ${statement}\n}`;
7186
+ }
7187
+ /** Marks a delay body that reads `params`, which v4 cannot supply. */
7188
+ const PARAMS_IN_DELAY_MARKER = "/* TODO: v5-only (params in delay); no XState v4 equivalent */";
7189
+ /**
7190
+ * Emits a v4 service. v4 invoke creators are called with
7191
+ * `(context, event, { data, src, meta })`, so a body reading v5 `input` gets it
7192
+ * re-bound from `meta.data` (what `invoke.data` resolves to).
7193
+ */
7194
+ function serviceImplementation(actor) {
7195
+ const body = actor.code?.body;
7196
+ if (!body) return `async function (context, event) {\n // TODO: implement ${actor.name}\n}`;
7197
+ const inline = getInlineExpression(body);
7198
+ const usesInput = inline ? referencesBinding(body, "input") : needsRebind(body, "input");
7199
+ if (inline) {
7200
+ if (!usesInput) return toV4Code(inline);
7201
+ return `async function (context, event, meta) {\n return (${stripExportDefault(inline)})({ context, event, input: meta.data });\n}`;
7202
+ }
7203
+ const code = toV4Code(dedent(body));
7204
+ const statement = isBareExpression(code) ? `return ${code};` : code;
7205
+ if (!usesInput) return `async function (context, event) {\n ${statement}\n}`;
7206
+ return `async function (context, event, meta) {\n const input = meta.data;\n ${statement}\n}`;
7207
+ }
7208
+ /** A body that is already a complete expression is emitted verbatim. */
7209
+ function getInlineExpression(code) {
7210
+ const stripped = stripExportDefault(code);
7211
+ if (stripped !== code.trim()) return stripped;
7212
+ return /^\s*(async\s+)?(function\b|\(|[A-Za-z_$][\w$]*\s*=>)/.test(stripped) && !/;\s*\n/.test(stripped) ? stripped : void 0;
7213
+ }
7214
+ function buildSchemaBlock(schemas) {
7215
+ if (!schemas) return void 0;
7216
+ const result = {};
7217
+ const contextType = contextSchemaToTSType(schemas.context);
7218
+ if (contextType) result.context = raw(`{} as ${contextType}`);
7219
+ const eventsType = eventsSchemaToTSType(schemas.events);
7220
+ if (eventsType) result.events = raw(`{} as\n | ${eventsType}`);
7221
+ return Object.keys(result).length ? result : void 0;
7222
+ }
7223
+ /** Named exports of `xstate` v4 that generated code may reference. */
7224
+ const V4_XSTATE_HELPERS = [
7225
+ "assign",
7226
+ "raise",
7227
+ "send",
7228
+ "sendTo",
7229
+ "sendParent",
7230
+ "sendUpdate",
7231
+ "forwardTo",
7232
+ "log",
7233
+ "cancel",
7234
+ "stop",
7235
+ "choose",
7236
+ "pure",
7237
+ "spawn",
7238
+ "actions",
7239
+ "doneInvoke",
7240
+ "interpret"
7241
+ ];
7242
+ function buildImports(machineExpr, codeImports) {
7243
+ const xstateImports = new Set(["createMachine"]);
7244
+ for (const helper of V4_XSTATE_HELPERS) if (new RegExp(`\\b${helper}\\s*\\(`).test(machineExpr)) xstateImports.add(helper);
7245
+ if (/\bactions\s*\./.test(machineExpr)) xstateImports.add("actions");
7246
+ const externalImports = /* @__PURE__ */ new Map();
7247
+ for (const codeImport of codeImports) {
7248
+ if ((codeImport.importKind ?? "named") !== "named") continue;
7249
+ const specifier = codeImport.local && codeImport.local !== codeImport.import ? `${codeImport.import} as ${codeImport.local}` : codeImport.import;
7250
+ if (codeImport.package === "xstate") {
7251
+ if (V4_ACTIONS_NAMESPACE_HELPERS.includes(codeImport.import)) xstateImports.add("actions");
7252
+ else if (V4_XSTATE_HELPERS.includes(codeImport.import)) xstateImports.add(specifier);
7253
+ continue;
7254
+ }
7255
+ const names = externalImports.get(codeImport.package) ?? /* @__PURE__ */ new Set();
7256
+ names.add(specifier);
7257
+ externalImports.set(codeImport.package, names);
7258
+ }
7259
+ const imports = [`import { ${[...xstateImports].join(", ")} } from 'xstate';`];
7260
+ for (const [packageName, names] of externalImports) imports.push(`import { ${[...names].sort().join(", ")} } from '${packageName}';`);
7261
+ return imports.join("\n");
7262
+ }
7263
+ function getCodeExpressionImports(graph) {
7264
+ const imports = /* @__PURE__ */ new Map();
7265
+ function visit(value) {
7266
+ if (!value || typeof value !== "object") return;
7267
+ if (Array.isArray(value)) {
7268
+ value.forEach(visit);
7269
+ return;
7270
+ }
7271
+ const record = value;
7272
+ if (Array.isArray(record.imports)) for (const item of record.imports) {
7273
+ if (!item || typeof item !== "object") continue;
7274
+ const candidate = item;
7275
+ if (typeof candidate.package !== "string" || typeof candidate.import !== "string") continue;
7276
+ const key = `${candidate.package}:${candidate.import}:${candidate.local ?? ""}:${candidate.importKind ?? "named"}`;
7277
+ imports.set(key, {
7278
+ package: candidate.package,
7279
+ import: candidate.import,
7280
+ local: candidate.local,
7281
+ importKind: candidate.importKind,
7282
+ version: candidate.version
7283
+ });
7284
+ }
7285
+ Object.values(record).forEach(visit);
7286
+ }
7287
+ visit(graph);
7288
+ return [...imports.values()];
7289
+ }
7290
+ function isCodeExpression$3(value) {
7291
+ return !!value && typeof value === "object" && value["@type"] === "code" && typeof value.expr === "string";
7292
+ }
6351
7293
  function getXStateFSMCompatibilityIssues(graph) {
6352
7294
  const root = graph.nodes.find((node) => node.parentId == null);
6353
7295
  if (!root) return ["missing root state"];
@@ -6636,6 +7578,7 @@ const validationIssueCodeSchema = _enum([
6636
7578
  "missing_delay_implementation",
6637
7579
  "invalid_final_transition",
6638
7580
  "invalid_history_transition",
7581
+ "invalid_choice_event",
6639
7582
  "parallel_region_transition",
6640
7583
  "duplicate_source_name",
6641
7584
  "undefined_action",
@@ -6831,4 +7774,4 @@ function getScriptKind(fileName) {
6831
7774
  }
6832
7775
 
6833
7776
  //#endregion
6834
- export { normalizeMachineProfile as _, RawCode as a, xstateSourceToConfig as b, detectXStateSourceProfile as c, getXStateFSMCompatibilityIssues as d, graphChangeToPatchesResult as f, jsonSchemaToTSType as g, graphToXStateTS as h, INLINE_EXPRESSION_DIRECTIVE_FIELDS as i, diffGraphsSemantically as l, graphToXStateFSM as m, getStatelyPragma as n, alignCompareGraphIds as o, graphToMachineConfig as p, upsertStatelyPragma as r, contextSchemaToTSType as s, findStatelyPragmaAttachments as t, eventsSchemaToTSType as u, raw as v, serializeJS as y };
7777
+ export { jsonSchemaToTSType as _, RawCode as a, serializeJS as b, detectXStateSourceProfile as c, getXStateFSMCompatibilityIssues as d, graphChangeToPatchesResult as f, graphToXStateV4TS as g, graphToXStateTS as h, INLINE_EXPRESSION_DIRECTIVE_FIELDS as i, diffGraphsSemantically as l, graphToXStateFSM as m, getStatelyPragma as n, alignCompareGraphIds as o, graphToMachineConfig as p, upsertStatelyPragma as r, contextSchemaToTSType as s, findStatelyPragmaAttachments as t, eventsSchemaToTSType as u, normalizeMachineProfile as v, xstateSourceToConfig as x, raw as y };