@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.
- package/README.md +10 -2
- package/dist/{editor-sync-types-CTKArS8n.d.mts → editor-sync-types-DB1N6QUK.d.mts} +0 -1
- package/dist/{editorHostSession-shrjfosC.mjs → editorHostSession-DNpXPNAc.mjs} +0 -1
- package/dist/{editorHostSession-CWAuoMtC.d.mts → editorHostSession-vSt07IJV.d.mts} +1 -1
- package/dist/editorHostSession.d.mts +1 -1
- package/dist/editorHostSession.mjs +1 -1
- package/dist/embed.d.mts +2 -2
- package/dist/embed.mjs +2 -1
- package/dist/{graph-BwHnhzpC.d.mts → graph-C8E1Exad.d.mts} +1 -1
- package/dist/graph.d.mts +1 -1
- package/dist/{index-D2I1qPsf.d.mts → index-D4pdeDpT.d.mts} +38 -6
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +6 -6
- package/dist/{inspect-DSDnyzZ5.mjs → inspect-dmCvrIl1.mjs} +1 -1
- package/dist/inspect.mjs +2 -2
- package/dist/patchTypes.d.mts +1 -1
- package/dist/protocol.d.mts +7 -5
- package/dist/{statelyPragma-ByF0-L-N.mjs → statelyPragma-p1vu8PmH.mjs} +1000 -57
- package/dist/{studio-B9-1Ynrx.d.mts → studio-D-yqFd0u.d.mts} +87 -10
- package/dist/{studio-CNkxMZyz.mjs → studio-rSI54Ese.mjs} +210 -7
- package/dist/studio.d.mts +1 -1
- package/dist/studio.mjs +1 -1
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +10 -9
- package/dist/{version-D_SqbrSy.mjs → version-DC3yW9Dk.mjs} +4 -3
- package/package.json +3 -3
|
@@ -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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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(
|
|
3797
|
-
...node.data.exit?.length ? { exit: node.data.exit.map(
|
|
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(
|
|
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)
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
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
|
-
|
|
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
|
|
4960
|
-
if (ts.isNumericLiteral(node)) return
|
|
4961
|
-
if (node.kind === ts.SyntaxKind.TrueKeyword) return
|
|
4962
|
-
if (node.kind === ts.SyntaxKind.FalseKeyword) return
|
|
4963
|
-
if (node.kind === ts.SyntaxKind.NullKeyword) return
|
|
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)
|
|
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 (
|
|
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,
|
|
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
|
-
|
|
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 = (
|
|
5913
|
-
|
|
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
|
-
|
|
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.
|
|
6004
|
-
|
|
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 {
|
|
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 };
|