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