@statelyai/sdk 0.20.1 → 0.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/embed.mjs +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{inspect-DWu20a8g.mjs → inspect-DU-gHyef.mjs} +1 -1
- package/dist/inspect.mjs +2 -2
- package/dist/oauth.mjs +1 -0
- package/dist/{statelyPragma-CIzsR_Sx.mjs → statelyPragma-Cesya0Pk.mjs} +752 -234
- package/dist/sync.mjs +1 -1
- package/dist/{version-YJizbJxR.mjs → version-DoNMw8g6.mjs} +1 -1
- package/package.json +4 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { a as discriminatedUnion, c as object, d as union, f as unknown, i as custom, l as record, n as array, o as literal, r as boolean, s as number, t as _enum, u as string } from "./schemas-b9wG-zYl.mjs";
|
|
2
2
|
import ts from "typescript";
|
|
3
|
+
import "xstate";
|
|
3
4
|
import "xstate/graph";
|
|
4
5
|
|
|
5
6
|
//#region ../../node_modules/.pnpm/js-yaml@4.2.0/node_modules/js-yaml/dist/js-yaml.mjs
|
|
@@ -2333,175 +2334,6 @@ var index_vite_proxy_tmp_default = import_js_yaml.default;
|
|
|
2333
2334
|
|
|
2334
2335
|
//#endregion
|
|
2335
2336
|
//#region ../graph-tools/dist/index.mjs
|
|
2336
|
-
/**
|
|
2337
|
-
* Converts a graph to an adjacency list representation.
|
|
2338
|
-
*
|
|
2339
|
-
* @example
|
|
2340
|
-
* ```ts
|
|
2341
|
-
* import { createGraph, toAdjacencyList } from '@statelyai/graph';
|
|
2342
|
-
*
|
|
2343
|
-
* const graph = createGraph({
|
|
2344
|
-
* nodes: { a: {}, b: {}, c: {} },
|
|
2345
|
-
* edges: [{ source: 'a', target: 'b' }, { source: 'a', target: 'c' }],
|
|
2346
|
-
* });
|
|
2347
|
-
*
|
|
2348
|
-
* toAdjacencyList(graph);
|
|
2349
|
-
* // { a: ['b', 'c'], b: [], c: [] }
|
|
2350
|
-
* ```
|
|
2351
|
-
*/
|
|
2352
|
-
function toAdjacencyList(graph) {
|
|
2353
|
-
const adj = {};
|
|
2354
|
-
for (const node of graph.nodes) adj[node.id] = [];
|
|
2355
|
-
for (const edge of graph.edges) {
|
|
2356
|
-
adj[edge.sourceId]?.push(edge.targetId);
|
|
2357
|
-
if (graph.mode !== "directed") adj[edge.targetId]?.push(edge.sourceId);
|
|
2358
|
-
}
|
|
2359
|
-
return adj;
|
|
2360
|
-
}
|
|
2361
|
-
/**
|
|
2362
|
-
* Parses an adjacency list into a graph.
|
|
2363
|
-
*
|
|
2364
|
-
* @example
|
|
2365
|
-
* ```ts
|
|
2366
|
-
* import { fromAdjacencyList } from '@statelyai/graph';
|
|
2367
|
-
*
|
|
2368
|
-
* const graph = fromAdjacencyList({
|
|
2369
|
-
* a: ['b', 'c'],
|
|
2370
|
-
* b: ['c'],
|
|
2371
|
-
* c: [],
|
|
2372
|
-
* });
|
|
2373
|
-
*
|
|
2374
|
-
* graph.nodes; // [{id: 'a', ...}, {id: 'b', ...}, {id: 'c', ...}]
|
|
2375
|
-
* graph.edges; // [{sourceId: 'a', targetId: 'b', ...}, ...]
|
|
2376
|
-
* ```
|
|
2377
|
-
*/
|
|
2378
|
-
function fromAdjacencyList(adj, options) {
|
|
2379
|
-
const directed = options?.directed ?? true;
|
|
2380
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2381
|
-
const nodes = Object.keys(adj).map((id) => ({
|
|
2382
|
-
type: "node",
|
|
2383
|
-
id,
|
|
2384
|
-
parentId: null,
|
|
2385
|
-
initialNodeId: null,
|
|
2386
|
-
label: "",
|
|
2387
|
-
data: void 0
|
|
2388
|
-
}));
|
|
2389
|
-
const edges = [];
|
|
2390
|
-
let edgeIdx = 0;
|
|
2391
|
-
for (const [sourceId, targets] of Object.entries(adj)) for (const targetId of targets) {
|
|
2392
|
-
const key = directed ? `${sourceId}->${targetId}` : [sourceId, targetId].sort().join("<->");
|
|
2393
|
-
if (!seen.has(key)) {
|
|
2394
|
-
seen.add(key);
|
|
2395
|
-
edges.push({
|
|
2396
|
-
type: "edge",
|
|
2397
|
-
id: `e${edgeIdx++}`,
|
|
2398
|
-
sourceId,
|
|
2399
|
-
targetId,
|
|
2400
|
-
label: "",
|
|
2401
|
-
data: void 0
|
|
2402
|
-
});
|
|
2403
|
-
}
|
|
2404
|
-
}
|
|
2405
|
-
return {
|
|
2406
|
-
id: options?.id ?? "",
|
|
2407
|
-
mode: directed ? "directed" : "undirected",
|
|
2408
|
-
initialNodeId: null,
|
|
2409
|
-
nodes,
|
|
2410
|
-
edges,
|
|
2411
|
-
data: void 0
|
|
2412
|
-
};
|
|
2413
|
-
}
|
|
2414
|
-
/**
|
|
2415
|
-
* Converts a graph to an edge list of `[source, target]` tuples.
|
|
2416
|
-
*
|
|
2417
|
-
* @example
|
|
2418
|
-
* ```ts
|
|
2419
|
-
* import { createGraph, toEdgeList } from '@statelyai/graph';
|
|
2420
|
-
*
|
|
2421
|
-
* const graph = createGraph({
|
|
2422
|
-
* nodes: { a: {}, b: {}, c: {} },
|
|
2423
|
-
* edges: [{ source: 'a', target: 'b' }, { source: 'b', target: 'c' }],
|
|
2424
|
-
* });
|
|
2425
|
-
*
|
|
2426
|
-
* toEdgeList(graph);
|
|
2427
|
-
* // [['a', 'b'], ['b', 'c']]
|
|
2428
|
-
* ```
|
|
2429
|
-
*/
|
|
2430
|
-
function toEdgeList(graph) {
|
|
2431
|
-
return graph.edges.map((e) => [e.sourceId, e.targetId]);
|
|
2432
|
-
}
|
|
2433
|
-
/**
|
|
2434
|
-
* Parses an edge list of `[source, target]` tuples into a graph.
|
|
2435
|
-
*
|
|
2436
|
-
* @example
|
|
2437
|
-
* ```ts
|
|
2438
|
-
* import { fromEdgeList } from '@statelyai/graph';
|
|
2439
|
-
*
|
|
2440
|
-
* const graph = fromEdgeList([
|
|
2441
|
-
* ['a', 'b'],
|
|
2442
|
-
* ['b', 'c'],
|
|
2443
|
-
* ]);
|
|
2444
|
-
*
|
|
2445
|
-
* graph.nodes; // [{id: 'a', ...}, {id: 'b', ...}, {id: 'c', ...}]
|
|
2446
|
-
* graph.edges; // [{sourceId: 'a', targetId: 'b', ...}, ...]
|
|
2447
|
-
* ```
|
|
2448
|
-
*/
|
|
2449
|
-
function fromEdgeList(edges, options) {
|
|
2450
|
-
const directed = options?.directed ?? true;
|
|
2451
|
-
const nodeIds = /* @__PURE__ */ new Set();
|
|
2452
|
-
for (const [source, target] of edges) {
|
|
2453
|
-
nodeIds.add(source);
|
|
2454
|
-
nodeIds.add(target);
|
|
2455
|
-
}
|
|
2456
|
-
const nodes = [...nodeIds].map((id) => ({
|
|
2457
|
-
type: "node",
|
|
2458
|
-
id,
|
|
2459
|
-
parentId: null,
|
|
2460
|
-
initialNodeId: null,
|
|
2461
|
-
label: "",
|
|
2462
|
-
data: void 0
|
|
2463
|
-
}));
|
|
2464
|
-
const edgeObjects = edges.map(([sourceId, targetId], i) => ({
|
|
2465
|
-
type: "edge",
|
|
2466
|
-
id: `e${i}`,
|
|
2467
|
-
sourceId,
|
|
2468
|
-
targetId,
|
|
2469
|
-
label: "",
|
|
2470
|
-
data: void 0
|
|
2471
|
-
}));
|
|
2472
|
-
return {
|
|
2473
|
-
id: options?.id ?? "",
|
|
2474
|
-
mode: directed ? "directed" : "undirected",
|
|
2475
|
-
initialNodeId: null,
|
|
2476
|
-
nodes,
|
|
2477
|
-
edges: edgeObjects,
|
|
2478
|
-
data: void 0
|
|
2479
|
-
};
|
|
2480
|
-
}
|
|
2481
|
-
/**
|
|
2482
|
-
* Create a `GraphFormatConverter` from a pair of `to`/`from` functions.
|
|
2483
|
-
*
|
|
2484
|
-
* @example
|
|
2485
|
-
* ```ts
|
|
2486
|
-
* import { createFormatConverter } from '@statelyai/graph';
|
|
2487
|
-
*
|
|
2488
|
-
* const yamlConverter = createFormatConverter(
|
|
2489
|
-
* (graph) => toYAML(graph),
|
|
2490
|
-
* (yaml) => fromYAML(yaml),
|
|
2491
|
-
* );
|
|
2492
|
-
*
|
|
2493
|
-
* const yaml = yamlConverter.to(graph);
|
|
2494
|
-
* const graph = yamlConverter.from(yaml);
|
|
2495
|
-
* ```
|
|
2496
|
-
*/
|
|
2497
|
-
function createFormatConverter(to, from) {
|
|
2498
|
-
return {
|
|
2499
|
-
to,
|
|
2500
|
-
from
|
|
2501
|
-
};
|
|
2502
|
-
}
|
|
2503
|
-
createFormatConverter(toAdjacencyList, fromAdjacencyList);
|
|
2504
|
-
createFormatConverter(toEdgeList, fromEdgeList);
|
|
2505
2337
|
const LAYOUT_KEYS = {
|
|
2506
2338
|
node: [
|
|
2507
2339
|
"x",
|
|
@@ -2517,6 +2349,8 @@ const LAYOUT_KEYS = {
|
|
|
2517
2349
|
"y",
|
|
2518
2350
|
"width",
|
|
2519
2351
|
"height",
|
|
2352
|
+
"points",
|
|
2353
|
+
"routing",
|
|
2520
2354
|
"style",
|
|
2521
2355
|
"color"
|
|
2522
2356
|
]
|
|
@@ -2802,7 +2636,8 @@ function formatEventParam(event) {
|
|
|
2802
2636
|
return "undefined";
|
|
2803
2637
|
}
|
|
2804
2638
|
function formatStringParam(value) {
|
|
2805
|
-
|
|
2639
|
+
if (typeof value === "string") return `'${value}'`;
|
|
2640
|
+
return isCodeExpression$1(value) ? serializeJS(value) : "undefined";
|
|
2806
2641
|
}
|
|
2807
2642
|
function formatInlineObject(value) {
|
|
2808
2643
|
return `{ ${Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => `${formatObjectKey(key)}: ${serializeJS(item)}`).join(", ")} }`;
|
|
@@ -3165,7 +3000,7 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
3165
3000
|
}
|
|
3166
3001
|
return nodeConfig;
|
|
3167
3002
|
}
|
|
3168
|
-
const rootNode = graph.nodes.find((node) => node.
|
|
3003
|
+
const rootNode = graph.nodes.find((node) => node.parentId === null || node.parentId == null);
|
|
3169
3004
|
if (!rootNode) throw new Error("No root node found");
|
|
3170
3005
|
getNodeConfig(rootNode);
|
|
3171
3006
|
if (graph.data.context !== void 0 && graph.data.context !== null) config.context = graph.data.context;
|
|
@@ -3179,6 +3014,123 @@ const INLINE_EXPRESSION_DIRECTIVE_FIELDS = [
|
|
|
3179
3014
|
"initialInput",
|
|
3180
3015
|
"route"
|
|
3181
3016
|
];
|
|
3017
|
+
const EXACT_SEMVER$1 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
3018
|
+
function parseProfileSpecifier(specifier) {
|
|
3019
|
+
const separator = specifier.lastIndexOf("@");
|
|
3020
|
+
const name = specifier.slice(0, separator);
|
|
3021
|
+
const version = specifier.slice(separator + 1);
|
|
3022
|
+
if (separator <= 0 || !/^@[^/]+\/[^@/]+$/.test(name) || !version) throw new Error(`Invalid profile specifier: ${specifier}`);
|
|
3023
|
+
return {
|
|
3024
|
+
name,
|
|
3025
|
+
version,
|
|
3026
|
+
kind: EXACT_SEMVER$1.test(version) ? "exact" : "range"
|
|
3027
|
+
};
|
|
3028
|
+
}
|
|
3029
|
+
function normalizeProfileRef(profile) {
|
|
3030
|
+
return profile === "xstate-v5" || profile === "xstate-v6-alpha" ? normalizeMachineProfile(profile) : profile;
|
|
3031
|
+
}
|
|
3032
|
+
/** Stately's semantic projection of the LangGraph 1.x APIs across runtimes. */
|
|
3033
|
+
const LANGGRAPH_PROFILE = "@statelyai/langgraph@1.0.0";
|
|
3034
|
+
const LANGGRAPH_PROFILE_MANIFEST = {
|
|
3035
|
+
profile: LANGGRAPH_PROFILE,
|
|
3036
|
+
name: "LangGraph",
|
|
3037
|
+
description: "LangGraph 1.x graph semantics for Python and JavaScript/TypeScript source.",
|
|
3038
|
+
restrictFormatsToListed: true,
|
|
3039
|
+
authoring: {
|
|
3040
|
+
terminology: {
|
|
3041
|
+
node: "node",
|
|
3042
|
+
edge: "edge",
|
|
3043
|
+
graph: "graph"
|
|
3044
|
+
},
|
|
3045
|
+
nodeTypes: [
|
|
3046
|
+
{
|
|
3047
|
+
kind: "node",
|
|
3048
|
+
label: "Node",
|
|
3049
|
+
description: "Graph API node",
|
|
3050
|
+
authorable: true
|
|
3051
|
+
},
|
|
3052
|
+
{
|
|
3053
|
+
kind: "task",
|
|
3054
|
+
label: "Task",
|
|
3055
|
+
description: "Functional API task",
|
|
3056
|
+
authorable: true
|
|
3057
|
+
},
|
|
3058
|
+
{
|
|
3059
|
+
kind: "entrypoint",
|
|
3060
|
+
label: "Entrypoint",
|
|
3061
|
+
description: "Functional API entrypoint",
|
|
3062
|
+
authorable: true
|
|
3063
|
+
},
|
|
3064
|
+
{
|
|
3065
|
+
kind: "agent",
|
|
3066
|
+
label: "Agent",
|
|
3067
|
+
description: "Prebuilt agent",
|
|
3068
|
+
authorable: true
|
|
3069
|
+
},
|
|
3070
|
+
{
|
|
3071
|
+
kind: "end",
|
|
3072
|
+
label: "END",
|
|
3073
|
+
description: "Terminal sentinel",
|
|
3074
|
+
authorable: true,
|
|
3075
|
+
terminal: true
|
|
3076
|
+
}
|
|
3077
|
+
],
|
|
3078
|
+
edgeTypes: [
|
|
3079
|
+
{
|
|
3080
|
+
kind: "edge",
|
|
3081
|
+
label: "Edge",
|
|
3082
|
+
description: "Direct route",
|
|
3083
|
+
authorable: true
|
|
3084
|
+
},
|
|
3085
|
+
{
|
|
3086
|
+
kind: "conditional",
|
|
3087
|
+
label: "Conditional edge",
|
|
3088
|
+
description: "Runtime-routed branch",
|
|
3089
|
+
authorable: true
|
|
3090
|
+
},
|
|
3091
|
+
{
|
|
3092
|
+
kind: "call",
|
|
3093
|
+
label: "Call",
|
|
3094
|
+
description: "Functional API call",
|
|
3095
|
+
authorable: true
|
|
3096
|
+
}
|
|
3097
|
+
],
|
|
3098
|
+
attachments: {},
|
|
3099
|
+
supportsInitialNode: false,
|
|
3100
|
+
supportsTargetlessEdges: false,
|
|
3101
|
+
supportsReenterEdges: false
|
|
3102
|
+
},
|
|
3103
|
+
operations: {
|
|
3104
|
+
simulate: false,
|
|
3105
|
+
validate: false,
|
|
3106
|
+
export: false
|
|
3107
|
+
},
|
|
3108
|
+
formats: [
|
|
3109
|
+
{
|
|
3110
|
+
format: "python",
|
|
3111
|
+
import: true,
|
|
3112
|
+
export: false,
|
|
3113
|
+
sourcePreserving: true
|
|
3114
|
+
},
|
|
3115
|
+
{
|
|
3116
|
+
format: "typescript",
|
|
3117
|
+
import: true,
|
|
3118
|
+
export: false,
|
|
3119
|
+
sourcePreserving: true
|
|
3120
|
+
},
|
|
3121
|
+
{
|
|
3122
|
+
format: "javascript",
|
|
3123
|
+
import: true,
|
|
3124
|
+
export: false,
|
|
3125
|
+
sourcePreserving: true
|
|
3126
|
+
}
|
|
3127
|
+
],
|
|
3128
|
+
features: {
|
|
3129
|
+
graphApi: true,
|
|
3130
|
+
functionalApi: true,
|
|
3131
|
+
prebuiltAgents: true
|
|
3132
|
+
}
|
|
3133
|
+
};
|
|
3182
3134
|
const XSTATE_FORMATS = [
|
|
3183
3135
|
{
|
|
3184
3136
|
format: "typescript",
|
|
@@ -3203,16 +3155,99 @@ const XSTATE_FORMATS = [
|
|
|
3203
3155
|
export: true
|
|
3204
3156
|
}
|
|
3205
3157
|
];
|
|
3158
|
+
const XSTATE_AUTHORING = {
|
|
3159
|
+
terminology: {
|
|
3160
|
+
node: "state",
|
|
3161
|
+
edge: "transition",
|
|
3162
|
+
graph: "machine"
|
|
3163
|
+
},
|
|
3164
|
+
nodeTypes: [
|
|
3165
|
+
{
|
|
3166
|
+
kind: "normal",
|
|
3167
|
+
label: "Normal",
|
|
3168
|
+
description: "Basic state",
|
|
3169
|
+
authorable: true,
|
|
3170
|
+
canContain: true
|
|
3171
|
+
},
|
|
3172
|
+
{
|
|
3173
|
+
kind: "parallel",
|
|
3174
|
+
label: "Parallel",
|
|
3175
|
+
description: "Concurrent child states",
|
|
3176
|
+
authorable: true,
|
|
3177
|
+
canContain: true
|
|
3178
|
+
},
|
|
3179
|
+
{
|
|
3180
|
+
kind: "final",
|
|
3181
|
+
label: "Final",
|
|
3182
|
+
description: "Terminal state",
|
|
3183
|
+
authorable: true,
|
|
3184
|
+
terminal: true
|
|
3185
|
+
},
|
|
3186
|
+
{
|
|
3187
|
+
kind: "history",
|
|
3188
|
+
label: "History",
|
|
3189
|
+
description: "Restores previous state",
|
|
3190
|
+
authorable: true
|
|
3191
|
+
},
|
|
3192
|
+
{
|
|
3193
|
+
kind: "choice",
|
|
3194
|
+
label: "Choice",
|
|
3195
|
+
description: "Guarded eventless routing",
|
|
3196
|
+
authorable: true
|
|
3197
|
+
}
|
|
3198
|
+
],
|
|
3199
|
+
edgeTypes: [{
|
|
3200
|
+
kind: "transition",
|
|
3201
|
+
label: "Transition",
|
|
3202
|
+
authorable: true
|
|
3203
|
+
}],
|
|
3204
|
+
attachments: {
|
|
3205
|
+
actions: true,
|
|
3206
|
+
guards: true,
|
|
3207
|
+
invokes: true,
|
|
3208
|
+
tags: true
|
|
3209
|
+
},
|
|
3210
|
+
supportsInitialNode: true,
|
|
3211
|
+
supportsTargetlessEdges: true,
|
|
3212
|
+
supportsReenterEdges: true
|
|
3213
|
+
};
|
|
3206
3214
|
const XSTATE_PROFILE_MANIFESTS = [{
|
|
3207
3215
|
profile: XSTATE_V5_PROFILE,
|
|
3208
3216
|
name: "XState v5",
|
|
3209
|
-
formats: [...XSTATE_FORMATS]
|
|
3217
|
+
formats: [...XSTATE_FORMATS],
|
|
3218
|
+
authoring: XSTATE_AUTHORING,
|
|
3219
|
+
operations: {
|
|
3220
|
+
simulate: true,
|
|
3221
|
+
validate: true,
|
|
3222
|
+
export: true
|
|
3223
|
+
}
|
|
3210
3224
|
}, {
|
|
3211
3225
|
profile: XSTATE_V6_PROFILE,
|
|
3212
3226
|
name: "XState v6",
|
|
3213
|
-
formats: [...XSTATE_FORMATS]
|
|
3227
|
+
formats: [...XSTATE_FORMATS],
|
|
3228
|
+
authoring: XSTATE_AUTHORING,
|
|
3229
|
+
operations: {
|
|
3230
|
+
simulate: true,
|
|
3231
|
+
validate: true,
|
|
3232
|
+
export: true
|
|
3233
|
+
}
|
|
3214
3234
|
}];
|
|
3215
|
-
const PROFILE_MANIFESTS = new Map(XSTATE_PROFILE_MANIFESTS.map((manifest) => [manifest.profile, manifest]));
|
|
3235
|
+
const PROFILE_MANIFESTS = new Map([...XSTATE_PROFILE_MANIFESTS, LANGGRAPH_PROFILE_MANIFEST].map((manifest) => [manifest.profile, manifest]));
|
|
3236
|
+
function getProfileManifest(profile) {
|
|
3237
|
+
return PROFILE_MANIFESTS.get(profile);
|
|
3238
|
+
}
|
|
3239
|
+
function isXStateV6ProfileRef(profile) {
|
|
3240
|
+
let current = normalizeProfileRef(profile);
|
|
3241
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3242
|
+
while (!seen.has(current)) {
|
|
3243
|
+
if (isXStateV6Profile(current)) return true;
|
|
3244
|
+
seen.add(current);
|
|
3245
|
+
const parent = getProfileManifest(current)?.extends;
|
|
3246
|
+
if (!parent || parseProfileSpecifier(parent).kind !== "exact") return false;
|
|
3247
|
+
current = parent;
|
|
3248
|
+
}
|
|
3249
|
+
return false;
|
|
3250
|
+
}
|
|
3216
3251
|
const XSTATE_V6_FN_TRANSITION_META = "@statelyai.xstate.v6.fnTransition";
|
|
3217
3252
|
const XSTATE_V6_FN_SOURCE_META = "@statelyai.xstate.v6.fnSource";
|
|
3218
3253
|
function sourceFile(source) {
|
|
@@ -3226,7 +3261,193 @@ function unwrapExpression(node) {
|
|
|
3226
3261
|
if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isParenthesizedExpression(node)) return unwrapExpression(node.expression);
|
|
3227
3262
|
return node;
|
|
3228
3263
|
}
|
|
3264
|
+
function canReplaceIdentifier(node) {
|
|
3265
|
+
const parent = node.parent;
|
|
3266
|
+
if (ts.isPropertyAccessExpression(parent) && parent.name === node) return false;
|
|
3267
|
+
if (ts.isPropertyAssignment(parent) && parent.name === node) return false;
|
|
3268
|
+
if (ts.isMethodDeclaration(parent) && parent.name === node) return false;
|
|
3269
|
+
return true;
|
|
3270
|
+
}
|
|
3271
|
+
function bindingNameContains(name, identifier) {
|
|
3272
|
+
if (ts.isIdentifier(name)) return name.text === identifier;
|
|
3273
|
+
return name.elements.some((element) => ts.isBindingElement(element) && bindingNameContains(element.name, identifier));
|
|
3274
|
+
}
|
|
3275
|
+
function scopeBindsName(node, identifier) {
|
|
3276
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.parameters.some((parameter) => bindingNameContains(parameter.name, identifier))) return true;
|
|
3277
|
+
if (ts.isCatchClause(node) && node.variableDeclaration) return bindingNameContains(node.variableDeclaration.name, identifier);
|
|
3278
|
+
if (ts.isBlock(node)) return node.statements.some((statement) => {
|
|
3279
|
+
if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContains(declaration.name, identifier));
|
|
3280
|
+
return ts.isFunctionDeclaration(statement) && statement.name?.text === identifier;
|
|
3281
|
+
});
|
|
3282
|
+
if ((ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) && node.initializer && ts.isVariableDeclarationList(node.initializer)) return node.initializer.declarations.some((declaration) => bindingNameContains(declaration.name, identifier));
|
|
3283
|
+
return false;
|
|
3284
|
+
}
|
|
3285
|
+
function isShadowedWithinExpression(node, expression) {
|
|
3286
|
+
let ancestor = node.parent;
|
|
3287
|
+
while (ancestor && ancestor !== expression.parent) {
|
|
3288
|
+
if (scopeBindsName(ancestor, node.text)) return true;
|
|
3289
|
+
ancestor = ancestor.parent;
|
|
3290
|
+
}
|
|
3291
|
+
return false;
|
|
3292
|
+
}
|
|
3293
|
+
function replacementText(node, expression) {
|
|
3294
|
+
if (ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node) return `${node.text}: (${expression})`;
|
|
3295
|
+
return `(${expression})`;
|
|
3296
|
+
}
|
|
3297
|
+
function isSafeInlineExpression(expression) {
|
|
3298
|
+
let safe = true;
|
|
3299
|
+
function visit(node) {
|
|
3300
|
+
if (ts.isCallExpression(node) || ts.isNewExpression(node) || ts.isAwaitExpression(node) || ts.isYieldExpression(node) || ts.isDeleteExpression(node) || ts.isPostfixUnaryExpression(node) || ts.isPrefixUnaryExpression(node) && (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) || ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment) {
|
|
3301
|
+
safe = false;
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
ts.forEachChild(node, visit);
|
|
3305
|
+
}
|
|
3306
|
+
visit(expression);
|
|
3307
|
+
return safe;
|
|
3308
|
+
}
|
|
3309
|
+
function hasUnsafeVariableInitializer(node) {
|
|
3310
|
+
let unsafe = false;
|
|
3311
|
+
function visit(current) {
|
|
3312
|
+
if (unsafe) return;
|
|
3313
|
+
if (current !== node && (ts.isArrowFunction(current) || ts.isFunctionExpression(current) || ts.isFunctionDeclaration(current))) return;
|
|
3314
|
+
if (ts.isVariableDeclaration(current) && current.initializer && !isSafeInlineExpression(current.initializer)) {
|
|
3315
|
+
unsafe = true;
|
|
3316
|
+
return;
|
|
3317
|
+
}
|
|
3318
|
+
ts.forEachChild(current, visit);
|
|
3319
|
+
}
|
|
3320
|
+
visit(node);
|
|
3321
|
+
return unsafe;
|
|
3322
|
+
}
|
|
3323
|
+
function resolvedExpressionText(expression, bindings, resolving = /* @__PURE__ */ new Set()) {
|
|
3324
|
+
const source = expression.getSourceFile();
|
|
3325
|
+
const start = expression.getStart(source);
|
|
3326
|
+
const replacements = [];
|
|
3327
|
+
function visit(node) {
|
|
3328
|
+
if (ts.isIdentifier(node) && canReplaceIdentifier(node) && !isShadowedWithinExpression(node, expression)) {
|
|
3329
|
+
const binding = bindings.get(node.text);
|
|
3330
|
+
if (binding && !ts.isFunctionDeclaration(binding) && isSafeInlineExpression(binding) && binding !== expression && !resolving.has(node.text)) {
|
|
3331
|
+
const nextResolving = new Set(resolving).add(node.text);
|
|
3332
|
+
replacements.push({
|
|
3333
|
+
start: node.getStart(source) - start,
|
|
3334
|
+
end: node.getEnd() - start,
|
|
3335
|
+
text: replacementText(node, resolvedExpressionText(binding, bindings, nextResolving))
|
|
3336
|
+
});
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
ts.forEachChild(node, visit);
|
|
3341
|
+
}
|
|
3342
|
+
visit(expression);
|
|
3343
|
+
let result = expression.getText(source);
|
|
3344
|
+
for (const replacement of replacements.sort((a, b) => b.start - a.start)) result = result.slice(0, replacement.start) + replacement.text + result.slice(replacement.end);
|
|
3345
|
+
return result;
|
|
3346
|
+
}
|
|
3347
|
+
function typeNodeToJsonSchema(node) {
|
|
3348
|
+
if (ts.isParenthesizedTypeNode(node)) return typeNodeToJsonSchema(node.type);
|
|
3349
|
+
if (ts.isLiteralTypeNode(node)) {
|
|
3350
|
+
const literal = node.literal;
|
|
3351
|
+
if (ts.isStringLiteral(literal) || ts.isNumericLiteral(literal)) return { const: ts.isNumericLiteral(literal) ? Number(literal.text) : literal.text };
|
|
3352
|
+
if (literal.kind === ts.SyntaxKind.TrueKeyword) return { const: true };
|
|
3353
|
+
if (literal.kind === ts.SyntaxKind.FalseKeyword) return { const: false };
|
|
3354
|
+
return null;
|
|
3355
|
+
}
|
|
3356
|
+
if (ts.isUnionTypeNode(node)) {
|
|
3357
|
+
const members = node.types.map(typeNodeToJsonSchema);
|
|
3358
|
+
if (members.some((member) => !member)) return null;
|
|
3359
|
+
const constants = members.map((member) => member?.const);
|
|
3360
|
+
if (constants.every((value) => value !== void 0)) return { enum: constants };
|
|
3361
|
+
return { anyOf: members };
|
|
3362
|
+
}
|
|
3363
|
+
if (ts.isArrayTypeNode(node)) {
|
|
3364
|
+
const items = typeNodeToJsonSchema(node.elementType);
|
|
3365
|
+
return items ? {
|
|
3366
|
+
type: "array",
|
|
3367
|
+
items
|
|
3368
|
+
} : null;
|
|
3369
|
+
}
|
|
3370
|
+
if (ts.isTupleTypeNode(node)) {
|
|
3371
|
+
const items = node.elements.map((element) => typeNodeToJsonSchema(element));
|
|
3372
|
+
if (items.some((item) => !item)) return null;
|
|
3373
|
+
return {
|
|
3374
|
+
type: "array",
|
|
3375
|
+
items,
|
|
3376
|
+
minItems: items.length,
|
|
3377
|
+
maxItems: items.length
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
if (ts.isTypeLiteralNode(node)) {
|
|
3381
|
+
const properties = {};
|
|
3382
|
+
const required = [];
|
|
3383
|
+
for (const member of node.members) {
|
|
3384
|
+
if (!ts.isPropertySignature(member) || !member.type || !member.name) return null;
|
|
3385
|
+
const name = propName(member.name);
|
|
3386
|
+
const schema = typeNodeToJsonSchema(member.type);
|
|
3387
|
+
if (!name || !schema) return null;
|
|
3388
|
+
properties[name] = schema;
|
|
3389
|
+
if (!member.questionToken) required.push(name);
|
|
3390
|
+
}
|
|
3391
|
+
return {
|
|
3392
|
+
type: "object",
|
|
3393
|
+
properties,
|
|
3394
|
+
...required.length ? { required } : void 0,
|
|
3395
|
+
additionalProperties: false
|
|
3396
|
+
};
|
|
3397
|
+
}
|
|
3398
|
+
switch (node.kind) {
|
|
3399
|
+
case ts.SyntaxKind.StringKeyword: return { type: "string" };
|
|
3400
|
+
case ts.SyntaxKind.NumberKeyword: return { type: "number" };
|
|
3401
|
+
case ts.SyntaxKind.BooleanKeyword: return { type: "boolean" };
|
|
3402
|
+
case ts.SyntaxKind.NullKeyword: return { type: "null" };
|
|
3403
|
+
case ts.SyntaxKind.UnknownKeyword:
|
|
3404
|
+
case ts.SyntaxKind.AnyKeyword: return {};
|
|
3405
|
+
default: return null;
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
function typesCallSchema(node) {
|
|
3409
|
+
const value = unwrapExpression(node);
|
|
3410
|
+
if (!ts.isCallExpression(value) || value.expression.getText() !== "types" || value.typeArguments?.length !== 1) return null;
|
|
3411
|
+
return typeNodeToJsonSchema(value.typeArguments[0]);
|
|
3412
|
+
}
|
|
3413
|
+
function schemasObjectToValue(node) {
|
|
3414
|
+
const value = unwrapExpression(node);
|
|
3415
|
+
if (!ts.isObjectLiteralExpression(value)) return null;
|
|
3416
|
+
const result = {};
|
|
3417
|
+
for (const property of value.properties) {
|
|
3418
|
+
if (!ts.isPropertyAssignment(property)) continue;
|
|
3419
|
+
const key = propName(property.name);
|
|
3420
|
+
if (!key) continue;
|
|
3421
|
+
if (key === "events" && ts.isObjectLiteralExpression(property.initializer)) {
|
|
3422
|
+
const events = {};
|
|
3423
|
+
for (const eventProperty of property.initializer.properties) {
|
|
3424
|
+
if (!ts.isPropertyAssignment(eventProperty)) continue;
|
|
3425
|
+
const eventType = propName(eventProperty.name);
|
|
3426
|
+
const schema = typesCallSchema(eventProperty.initializer);
|
|
3427
|
+
if (eventType && schema) events[eventType] = schema;
|
|
3428
|
+
}
|
|
3429
|
+
result.events = events;
|
|
3430
|
+
continue;
|
|
3431
|
+
}
|
|
3432
|
+
const schema = typesCallSchema(property.initializer);
|
|
3433
|
+
if (!schema) continue;
|
|
3434
|
+
result[key] = key === "context" ? schema.properties ?? {} : schema;
|
|
3435
|
+
}
|
|
3436
|
+
return result;
|
|
3437
|
+
}
|
|
3229
3438
|
function propertyContext(parent, key) {
|
|
3439
|
+
if (parent.setupValue && (key === "actions" || key === "guards" || key === "actors" || key === "delays")) return {
|
|
3440
|
+
v6: parent.v6,
|
|
3441
|
+
implementationMap: true
|
|
3442
|
+
};
|
|
3443
|
+
if (parent.implementationMap) return {
|
|
3444
|
+
v6: parent.v6,
|
|
3445
|
+
implementationValue: true
|
|
3446
|
+
};
|
|
3447
|
+
if (parent.effectArgumentValue) return {
|
|
3448
|
+
v6: parent.v6,
|
|
3449
|
+
effectArgumentValue: true
|
|
3450
|
+
};
|
|
3230
3451
|
if (parent.invokeValue && key === "src") return {
|
|
3231
3452
|
v6: parent.v6,
|
|
3232
3453
|
actorSourceValue: true
|
|
@@ -3244,6 +3465,14 @@ function propertyContext(parent, key) {
|
|
|
3244
3465
|
assignmentMap: true,
|
|
3245
3466
|
transitionContext: true
|
|
3246
3467
|
};
|
|
3468
|
+
if (key === "context") return {
|
|
3469
|
+
v6: parent.v6,
|
|
3470
|
+
machineContextValue: true
|
|
3471
|
+
};
|
|
3472
|
+
if (parent.transitionValue && key === "target") return {
|
|
3473
|
+
v6: parent.v6,
|
|
3474
|
+
targetValue: true
|
|
3475
|
+
};
|
|
3247
3476
|
if (parent.assignmentMap) return {
|
|
3248
3477
|
v6: parent.v6,
|
|
3249
3478
|
assignmentValue: true
|
|
@@ -3290,14 +3519,11 @@ function propertyContext(parent, key) {
|
|
|
3290
3519
|
};
|
|
3291
3520
|
return { v6: parent.v6 };
|
|
3292
3521
|
}
|
|
3293
|
-
function fallbackFunctionTransition(fn
|
|
3294
|
-
return {
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
[XSTATE_V6_FN_SOURCE_META]: fn.getText()
|
|
3299
|
-
}
|
|
3300
|
-
};
|
|
3522
|
+
function fallbackFunctionTransition(fn) {
|
|
3523
|
+
return { meta: {
|
|
3524
|
+
[XSTATE_V6_FN_TRANSITION_META]: true,
|
|
3525
|
+
[XSTATE_V6_FN_SOURCE_META]: fn.getText()
|
|
3526
|
+
} };
|
|
3301
3527
|
}
|
|
3302
3528
|
function conditionText(cond) {
|
|
3303
3529
|
return cond.negated ? `!(${cond.text})` : cond.text;
|
|
@@ -3318,7 +3544,7 @@ function hashString(value) {
|
|
|
3318
3544
|
return (hash >>> 0).toString(36);
|
|
3319
3545
|
}
|
|
3320
3546
|
function inlineGuardCode(params, condition) {
|
|
3321
|
-
return `${params} => ${condition}`;
|
|
3547
|
+
return `${params} => ${condition.trimStart().startsWith("{") ? `(${condition})` : condition}`;
|
|
3322
3548
|
}
|
|
3323
3549
|
function guardFromConditions(conds, params) {
|
|
3324
3550
|
const simplified = simplifyConditions(conds);
|
|
@@ -3354,7 +3580,7 @@ function transitionFromValue(value, actions) {
|
|
|
3354
3580
|
function expressionBranches(expression, bindings, depth) {
|
|
3355
3581
|
const node = unwrapExpression(expression);
|
|
3356
3582
|
if (ts.isConditionalExpression(node)) {
|
|
3357
|
-
const cond = node.condition
|
|
3583
|
+
const cond = resolvedExpressionText(node.condition, bindings);
|
|
3358
3584
|
return [...expressionBranches(node.whenTrue, bindings, depth + 1).map((branch) => ({
|
|
3359
3585
|
...branch,
|
|
3360
3586
|
conds: [{ text: cond }, ...branch.conds]
|
|
@@ -3367,7 +3593,7 @@ function expressionBranches(expression, bindings, depth) {
|
|
|
3367
3593
|
}))];
|
|
3368
3594
|
}
|
|
3369
3595
|
if (ts.isBinaryExpression(node) && (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken)) {
|
|
3370
|
-
const cond = node.left
|
|
3596
|
+
const cond = resolvedExpressionText(node.left, bindings);
|
|
3371
3597
|
if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) return [...expressionBranches(node.right, bindings, depth + 1).map((branch) => ({
|
|
3372
3598
|
...branch,
|
|
3373
3599
|
conds: [{ text: cond }, ...branch.conds]
|
|
@@ -3425,7 +3651,7 @@ function expressionStatementAction(statement, enqName, bindings) {
|
|
|
3425
3651
|
if (ts.isIdentifier(callee) && callee.text === enqName) return {
|
|
3426
3652
|
type: "xstate.expr",
|
|
3427
3653
|
params: {
|
|
3428
|
-
code: expression
|
|
3654
|
+
code: resolvedExpressionText(expression, bindings),
|
|
3429
3655
|
lang: "ts"
|
|
3430
3656
|
}
|
|
3431
3657
|
};
|
|
@@ -3435,7 +3661,7 @@ function expressionStatementAction(statement, enqName, bindings) {
|
|
|
3435
3661
|
const args = expression.arguments;
|
|
3436
3662
|
const value = (index) => {
|
|
3437
3663
|
const arg = args[index];
|
|
3438
|
-
return arg && ts.isExpression(arg) ? expressionToValue(arg, bindings, {}, 0) : void 0;
|
|
3664
|
+
return arg && ts.isExpression(arg) ? expressionToValue(arg, bindings, { effectArgumentValue: true }, 0) : void 0;
|
|
3439
3665
|
};
|
|
3440
3666
|
const spreadOpts = (index) => {
|
|
3441
3667
|
const opts = value(index);
|
|
@@ -3524,7 +3750,7 @@ function statementBranches(statements, bindings, enqName, prefixes = [{
|
|
|
3524
3750
|
}
|
|
3525
3751
|
}
|
|
3526
3752
|
if (ts.isIfStatement(statement)) {
|
|
3527
|
-
const cond = statement.expression
|
|
3753
|
+
const cond = resolvedExpressionText(statement.expression, scopedBindings);
|
|
3528
3754
|
const thenBranches = statementBranches(ts.isBlock(statement.thenStatement) ? statement.thenStatement.statements : [statement.thenStatement], scopedBindings, enqName, [{
|
|
3529
3755
|
...prefix,
|
|
3530
3756
|
conds: [...prefix.conds, { text: cond }]
|
|
@@ -3548,7 +3774,14 @@ function statementBranches(statements, bindings, enqName, prefixes = [{
|
|
|
3548
3774
|
continue;
|
|
3549
3775
|
}
|
|
3550
3776
|
if (ts.isSwitchStatement(statement)) {
|
|
3551
|
-
|
|
3777
|
+
if (statement.caseBlock.clauses.some((clause) => clause.statements.length === 0)) {
|
|
3778
|
+
nextOpen.push({
|
|
3779
|
+
...prefix,
|
|
3780
|
+
unknown: true
|
|
3781
|
+
});
|
|
3782
|
+
continue;
|
|
3783
|
+
}
|
|
3784
|
+
const expr = resolvedExpressionText(statement.expression, scopedBindings);
|
|
3552
3785
|
const prior = [];
|
|
3553
3786
|
for (const clause of statement.caseBlock.clauses) {
|
|
3554
3787
|
const ownCond = ts.isCaseClause(clause) ? { text: `${expr} === ${clause.expression.getText()}` } : null;
|
|
@@ -3585,9 +3818,11 @@ function guardParams(fn) {
|
|
|
3585
3818
|
return `(${param.getText()})`;
|
|
3586
3819
|
}
|
|
3587
3820
|
function normalizeFunctionTransition(fn, bindings, depth) {
|
|
3588
|
-
|
|
3589
|
-
const
|
|
3590
|
-
|
|
3821
|
+
if (fn.body && ts.isBlock(fn.body) && hasUnsafeVariableInitializer(fn.body)) return fallbackFunctionTransition(fn);
|
|
3822
|
+
const branches = 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)) : [];
|
|
3823
|
+
if (branches.some((branch) => branch.unknown)) return fallbackFunctionTransition(fn);
|
|
3824
|
+
const transitions = branches.map((branch) => {
|
|
3825
|
+
const transition = transitionFromValue(branch.result, branch.actions);
|
|
3591
3826
|
if (!transition) return null;
|
|
3592
3827
|
if (typeof transition === "string") {
|
|
3593
3828
|
const guard = guardFromConditions(branch.conds, guardParams(fn));
|
|
@@ -3604,7 +3839,7 @@ function normalizeFunctionTransition(fn, bindings, depth) {
|
|
|
3604
3839
|
}).filter((transition) => Boolean(transition));
|
|
3605
3840
|
if (transitions.length === 1) return transitions[0];
|
|
3606
3841
|
if (transitions.length > 1) return transitions;
|
|
3607
|
-
return fallbackFunctionTransition(fn
|
|
3842
|
+
return fallbackFunctionTransition(fn);
|
|
3608
3843
|
}
|
|
3609
3844
|
function inlineAction(fn) {
|
|
3610
3845
|
return {
|
|
@@ -3649,11 +3884,24 @@ function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__
|
|
|
3649
3884
|
result[key] = overrides.get(key);
|
|
3650
3885
|
continue;
|
|
3651
3886
|
}
|
|
3887
|
+
if (context.v6 && key === "schemas" && ts.isPropertyAssignment(property)) {
|
|
3888
|
+
const schemas = schemasObjectToValue(property.initializer);
|
|
3889
|
+
if (schemas) {
|
|
3890
|
+
result[key] = schemas;
|
|
3891
|
+
continue;
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3652
3894
|
if (ts.isShorthandPropertyAssignment(property)) {
|
|
3653
|
-
|
|
3895
|
+
const childContext = propertyContext(context, key);
|
|
3896
|
+
const childValue = expressionToValue(property.name, bindings, childContext, depth + 1);
|
|
3897
|
+
if (childContext.implementationValue && childValue === void 0) continue;
|
|
3898
|
+
result[key] = childValue;
|
|
3654
3899
|
continue;
|
|
3655
3900
|
}
|
|
3656
|
-
|
|
3901
|
+
const childContext = propertyContext(context, key);
|
|
3902
|
+
const childValue = expressionToValue(property.initializer, bindings, childContext, depth + 1);
|
|
3903
|
+
if (childContext.implementationValue && childValue === void 0) continue;
|
|
3904
|
+
result[key] = childValue;
|
|
3657
3905
|
}
|
|
3658
3906
|
if (context.transitionValue && "to" in result) {
|
|
3659
3907
|
const to = result.to;
|
|
@@ -3679,6 +3927,23 @@ function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__
|
|
|
3679
3927
|
function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
3680
3928
|
if (depth > 30) return void 0;
|
|
3681
3929
|
const node = unwrapExpression(expression);
|
|
3930
|
+
if (context.implementationValue) {
|
|
3931
|
+
if (ts.isIdentifier(node)) {
|
|
3932
|
+
const binding = bindings.get(node.text);
|
|
3933
|
+
if (binding) return inlineCodeExpression(ts.isFunctionDeclaration(binding) ? binding.getText() : unwrapExpression(binding).getText());
|
|
3934
|
+
return;
|
|
3935
|
+
}
|
|
3936
|
+
return inlineCodeExpression(node.getText());
|
|
3937
|
+
}
|
|
3938
|
+
if (context.machineContextValue && (ts.isArrowFunction(node) || ts.isFunctionExpression(node))) return inlineCodeExpression(node.getText());
|
|
3939
|
+
if (context.targetValue) {
|
|
3940
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
3941
|
+
if (ts.isIdentifier(node)) {
|
|
3942
|
+
const binding = bindings.get(node.text);
|
|
3943
|
+
if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
|
|
3944
|
+
}
|
|
3945
|
+
return inlineCodeExpression(resolvedExpressionText(node, bindings));
|
|
3946
|
+
}
|
|
3682
3947
|
if (context.actorSourceValue) {
|
|
3683
3948
|
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
3684
3949
|
if (ts.isIdentifier(node)) {
|
|
@@ -3700,6 +3965,10 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
|
3700
3965
|
if (node.kind === ts.SyntaxKind.TrueKeyword) return context.ioValue ? inlineCodeExpression("true") : true;
|
|
3701
3966
|
if (node.kind === ts.SyntaxKind.FalseKeyword) return context.ioValue ? inlineCodeExpression("false") : false;
|
|
3702
3967
|
if (node.kind === ts.SyntaxKind.NullKeyword) return context.ioValue ? inlineCodeExpression("null") : null;
|
|
3968
|
+
if (context.effectArgumentValue && !ts.isObjectLiteralExpression(node) && !ts.isArrayLiteralExpression(node)) {
|
|
3969
|
+
if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
|
|
3970
|
+
return inlineCodeExpression(resolvedExpressionText(node, bindings));
|
|
3971
|
+
}
|
|
3703
3972
|
if (context.ioPropertyValue) {
|
|
3704
3973
|
if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
|
|
3705
3974
|
if (ts.isIdentifier(node)) {
|
|
@@ -3714,7 +3983,7 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
|
3714
3983
|
const binding = bindings.get(node.text);
|
|
3715
3984
|
if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
|
|
3716
3985
|
}
|
|
3717
|
-
return wrapAssignExpression(node
|
|
3986
|
+
return wrapAssignExpression(resolvedExpressionText(node, bindings));
|
|
3718
3987
|
}
|
|
3719
3988
|
if (context.transitionContext && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
|
|
3720
3989
|
if (context.ioValue && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
|
|
@@ -3794,10 +4063,20 @@ function isCreateMachineCall(node) {
|
|
|
3794
4063
|
if (ts.isPropertyAccessExpression(expression)) return expression.name.text === "createMachine";
|
|
3795
4064
|
return false;
|
|
3796
4065
|
}
|
|
4066
|
+
function setupCallForCreateMachine(node, bindings) {
|
|
4067
|
+
if (!ts.isPropertyAccessExpression(node.expression)) return null;
|
|
4068
|
+
let receiver = unwrapExpression(node.expression.expression);
|
|
4069
|
+
if (ts.isIdentifier(receiver)) {
|
|
4070
|
+
const binding = bindings.get(receiver.text);
|
|
4071
|
+
if (binding && !ts.isFunctionDeclaration(binding)) receiver = unwrapExpression(binding);
|
|
4072
|
+
}
|
|
4073
|
+
return ts.isCallExpression(receiver) && ts.isIdentifier(receiver.expression) && receiver.expression.text === "setup" ? receiver : null;
|
|
4074
|
+
}
|
|
3797
4075
|
function hasV6Syntax(source) {
|
|
3798
4076
|
const file = sourceFile(source);
|
|
3799
4077
|
const bindings = collectBindings(file);
|
|
3800
4078
|
let found = false;
|
|
4079
|
+
const visitedSyntaxBindings = /* @__PURE__ */ new Set();
|
|
3801
4080
|
function containsFunction(expression, seenBindings = /* @__PURE__ */ new Set()) {
|
|
3802
4081
|
if (ts.isFunctionDeclaration(expression)) return true;
|
|
3803
4082
|
const node = unwrapExpression(expression);
|
|
@@ -3818,8 +4097,16 @@ function hasV6Syntax(source) {
|
|
|
3818
4097
|
if (ts.isCallExpression(node)) return ts.isIdentifier(node.expression) && containsFunction(node.expression, seenBindings) || node.arguments.some((argument) => ts.isExpression(argument) && containsFunction(argument, seenBindings));
|
|
3819
4098
|
return false;
|
|
3820
4099
|
}
|
|
3821
|
-
function
|
|
4100
|
+
function visitSyntax(node) {
|
|
3822
4101
|
if (found) return;
|
|
4102
|
+
if (ts.isIdentifier(node)) {
|
|
4103
|
+
const binding = bindings.get(node.text);
|
|
4104
|
+
if (binding && !visitedSyntaxBindings.has(binding)) {
|
|
4105
|
+
visitedSyntaxBindings.add(binding);
|
|
4106
|
+
visitSyntax(binding);
|
|
4107
|
+
}
|
|
4108
|
+
if (found) return;
|
|
4109
|
+
}
|
|
3823
4110
|
if (ts.isPropertyAssignment(node) && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name))) {
|
|
3824
4111
|
const key = node.name.text;
|
|
3825
4112
|
if (key === "triggers" || key === "internalEvents" || key === "matches" || key === "actorSources" || key === "timeout" || key === "onTimeout" || key === "choice" || key === "route") {
|
|
@@ -3831,9 +4118,19 @@ function hasV6Syntax(source) {
|
|
|
3831
4118
|
return;
|
|
3832
4119
|
}
|
|
3833
4120
|
}
|
|
3834
|
-
ts.forEachChild(node,
|
|
4121
|
+
ts.forEachChild(node, visitSyntax);
|
|
3835
4122
|
}
|
|
3836
|
-
|
|
4123
|
+
function visitMachineCalls(node) {
|
|
4124
|
+
if (ts.isCallExpression(node) && isCreateMachineCall(node)) {
|
|
4125
|
+
const config = node.arguments[0];
|
|
4126
|
+
if (config) visitSyntax(config);
|
|
4127
|
+
const setupConfig = setupCallForCreateMachine(node, bindings)?.arguments[0];
|
|
4128
|
+
if (setupConfig) visitSyntax(setupConfig);
|
|
4129
|
+
return;
|
|
4130
|
+
}
|
|
4131
|
+
ts.forEachChild(node, visitMachineCalls);
|
|
4132
|
+
}
|
|
4133
|
+
visitMachineCalls(file);
|
|
3837
4134
|
return found;
|
|
3838
4135
|
}
|
|
3839
4136
|
function detectXStateSourceProfile(source) {
|
|
@@ -3861,7 +4158,18 @@ function extractXStateMachineConfigs(source, options = {}) {
|
|
|
3861
4158
|
const arg = node.arguments[0];
|
|
3862
4159
|
if (!arg) return;
|
|
3863
4160
|
const value = expressionToValue(arg, bindings, { v6: profile === "xstate-v6-alpha" });
|
|
3864
|
-
if (value && typeof value === "object" && !Array.isArray(value))
|
|
4161
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
4162
|
+
const setupArg = setupCallForCreateMachine(node, bindings)?.arguments[0];
|
|
4163
|
+
const setupValue = setupArg ? expressionToValue(setupArg, bindings, {
|
|
4164
|
+
v6: profile === "xstate-v6-alpha",
|
|
4165
|
+
setupValue: true
|
|
4166
|
+
}) : null;
|
|
4167
|
+
const setupRecord = setupValue && typeof setupValue === "object" && !Array.isArray(setupValue) ? Object.fromEntries(Object.entries(setupValue).filter(([, item]) => !(item && typeof item === "object" && !Array.isArray(item) && Object.keys(item).length === 0))) : {};
|
|
4168
|
+
found.push({
|
|
4169
|
+
...setupRecord,
|
|
4170
|
+
...value
|
|
4171
|
+
});
|
|
4172
|
+
}
|
|
3865
4173
|
}
|
|
3866
4174
|
visit(file);
|
|
3867
4175
|
return found;
|
|
@@ -3943,7 +4251,8 @@ function isRequiredProperty(key, def, required) {
|
|
|
3943
4251
|
return typeof def === "object" && def !== null && def.required === true;
|
|
3944
4252
|
}
|
|
3945
4253
|
function graphToXStateTS(graph, options = {}) {
|
|
3946
|
-
const
|
|
4254
|
+
const inferredXStateVersion = isXStateV6ProfileRef(graph.data.profile ?? "xstate-v5") ? 6 : 5;
|
|
4255
|
+
const { exportStyle = "named", targetLanguage = "typescript", xstateVersion = inferredXStateVersion, ...configOptions } = options;
|
|
3947
4256
|
const schemas = graph.data.schemas;
|
|
3948
4257
|
const impls = filterInlineImplementations(graph.data.implementations);
|
|
3949
4258
|
const supportsTypeSyntax = targetLanguage === "typescript";
|
|
@@ -3955,12 +4264,14 @@ function graphToXStateTS(graph, options = {}) {
|
|
|
3955
4264
|
const hasSetup = hasSchemas || hasActions || hasGuards || hasActors || hasDelays;
|
|
3956
4265
|
const builtInActions = getUsedBuiltInActions(graph, xstateVersion);
|
|
3957
4266
|
const actorSourceImports = getActorSourceImports(graph);
|
|
4267
|
+
const implementationImports = getImplementationImports(impls);
|
|
3958
4268
|
const imports = buildImports({
|
|
3959
4269
|
hasSetup,
|
|
3960
4270
|
hasActors,
|
|
3961
4271
|
actors: impls?.actors ?? [],
|
|
3962
4272
|
builtInActions,
|
|
3963
4273
|
actorSourceImports,
|
|
4274
|
+
implementationImports,
|
|
3964
4275
|
usesTypes: xstateVersion === 6 && supportsTypeSyntax && hasSchemas
|
|
3965
4276
|
});
|
|
3966
4277
|
const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, configOptions)) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
|
|
@@ -4041,9 +4352,9 @@ function toV6MachineConfig(machineConfig) {
|
|
|
4041
4352
|
return mapV6MachineConfig(machineConfig);
|
|
4042
4353
|
}
|
|
4043
4354
|
function mapV6MachineConfig(value, context = {}) {
|
|
4355
|
+
if (context.transitionValue) return toV6TransitionValue(value);
|
|
4044
4356
|
if (Array.isArray(value)) return value.map((item) => mapV6MachineConfig(item, context));
|
|
4045
4357
|
if (!value || typeof value !== "object") return value;
|
|
4046
|
-
if (context.transitionValue) return toV6TransitionValue(value);
|
|
4047
4358
|
const result = {};
|
|
4048
4359
|
for (const [key, item] of Object.entries(value)) {
|
|
4049
4360
|
if (key === "entry" || key === "exit" || key === "actions") {
|
|
@@ -4069,7 +4380,7 @@ function mapV6TransitionMap(value) {
|
|
|
4069
4380
|
return result;
|
|
4070
4381
|
}
|
|
4071
4382
|
function toV6TransitionValue(value) {
|
|
4072
|
-
if (Array.isArray(value)) return value.map((item) => toV6TransitionValue(item));
|
|
4383
|
+
if (Array.isArray(value)) return buildV6TransitionFunction(value) ?? value.map((item) => toV6TransitionValue(item));
|
|
4073
4384
|
if (!value || typeof value !== "object") return value;
|
|
4074
4385
|
const transition = value;
|
|
4075
4386
|
if (transition.guard || transition.description || transition.input !== void 0) return mapV6MachineConfig(transition);
|
|
@@ -4086,6 +4397,63 @@ function toV6TransitionValue(value) {
|
|
|
4086
4397
|
context
|
|
4087
4398
|
}) ?? mapV6MachineConfig(transition);
|
|
4088
4399
|
}
|
|
4400
|
+
function guardCondition(value) {
|
|
4401
|
+
const expression = inlineExpr(value);
|
|
4402
|
+
if (!expression) return value === void 0 ? { condition: "true" } : null;
|
|
4403
|
+
const arrow = expression.indexOf("=>");
|
|
4404
|
+
if (arrow < 0) return null;
|
|
4405
|
+
const params = expression.slice(0, arrow).trim();
|
|
4406
|
+
const body = expression.slice(arrow + 2).trim();
|
|
4407
|
+
if (body.startsWith("{")) return null;
|
|
4408
|
+
return {
|
|
4409
|
+
condition: body,
|
|
4410
|
+
firstParam: params.startsWith("(") && params.endsWith(")") ? params.slice(1, -1).trim() : params
|
|
4411
|
+
};
|
|
4412
|
+
}
|
|
4413
|
+
function buildV6TransitionFunction(transitions) {
|
|
4414
|
+
const branches = [];
|
|
4415
|
+
let authoredFirstParam;
|
|
4416
|
+
for (const item of transitions) {
|
|
4417
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return;
|
|
4418
|
+
const transition = item;
|
|
4419
|
+
if (transition.description !== void 0 || transition.input !== void 0 || transition.matches !== void 0) return;
|
|
4420
|
+
const guard = guardCondition(transition.guard);
|
|
4421
|
+
if (!guard) return;
|
|
4422
|
+
if (guard.firstParam) {
|
|
4423
|
+
if (authoredFirstParam && authoredFirstParam !== guard.firstParam) return;
|
|
4424
|
+
authoredFirstParam = guard.firstParam;
|
|
4425
|
+
}
|
|
4426
|
+
const actionValue = transition.actions;
|
|
4427
|
+
const effects = (Array.isArray(actionValue) ? actionValue : actionValue === void 0 ? [] : [actionValue]).map(actionToV6Effect);
|
|
4428
|
+
if (effects.some((effect) => !effect)) return;
|
|
4429
|
+
const rendered = renderV6Effects(effects.filter((effect) => Boolean(effect)), transition.context === void 0 ? void 0 : serializeJS(unwrapTemplateExpressions(transition.context)));
|
|
4430
|
+
const returnValue = buildV6TransitionReturnValue({
|
|
4431
|
+
target: typeof transition.target === "string" ? transition.target : void 0,
|
|
4432
|
+
reenter: transition.reenter === true,
|
|
4433
|
+
meta: transition.meta
|
|
4434
|
+
}, rendered.contextValue);
|
|
4435
|
+
if (!returnValue) return;
|
|
4436
|
+
const body = [...rendered.statements.map(formatV6Statement), `return ${returnValue};`];
|
|
4437
|
+
if (body.length === 0) return;
|
|
4438
|
+
if (guard.condition === "true") branches.push(...body.map((line) => ` ${line}`));
|
|
4439
|
+
else {
|
|
4440
|
+
branches.push(` if (${guard.condition}) {`);
|
|
4441
|
+
branches.push(...body.map((line) => ` ${line}`));
|
|
4442
|
+
branches.push(" }");
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
if (branches.length === 0) return;
|
|
4446
|
+
const referenced = branches.join("\n");
|
|
4447
|
+
const inferredBindings = [
|
|
4448
|
+
"context",
|
|
4449
|
+
"event",
|
|
4450
|
+
"actions",
|
|
4451
|
+
"children",
|
|
4452
|
+
"self",
|
|
4453
|
+
"system"
|
|
4454
|
+
].filter((name) => new RegExp(`\\b${name}\\b`).test(referenced));
|
|
4455
|
+
return raw(`(${authoredFirstParam ?? (inferredBindings.length ? `{ ${inferredBindings.join(", ")} }` : "_")}, enq) => {\n${branches.join("\n")}\n}`);
|
|
4456
|
+
}
|
|
4089
4457
|
function toV6ActionField(actions) {
|
|
4090
4458
|
if (actions.length === 1) {
|
|
4091
4459
|
const expr = inlineExpr(actions[0]);
|
|
@@ -4096,16 +4464,41 @@ function toV6ActionField(actions) {
|
|
|
4096
4464
|
function buildV6ActionFunction(actions, transition) {
|
|
4097
4465
|
const effects = actions.map(actionToV6Effect);
|
|
4098
4466
|
if (effects.some((effect) => !effect)) return void 0;
|
|
4099
|
-
const
|
|
4100
|
-
|
|
4101
|
-
|
|
4467
|
+
const explicitContext = transition?.context === void 0 ? void 0 : serializeJS(unwrapTemplateExpressions(transition.context));
|
|
4468
|
+
const rendered = renderV6Effects(effects.filter((effect) => Boolean(effect)), explicitContext);
|
|
4469
|
+
const statements = rendered.statements;
|
|
4470
|
+
let returnValue = rendered.contextValue ? `{ context: ${rendered.contextValue} }` : void 0;
|
|
4471
|
+
if (transition) returnValue = buildV6TransitionReturnValue(transition, rendered.contextValue);
|
|
4472
|
+
if (statements.length === 0 && !returnValue) return void 0;
|
|
4473
|
+
const referenced = [...statements, returnValue ?? ""].join("\n");
|
|
4474
|
+
const bindings = [
|
|
4475
|
+
"context",
|
|
4476
|
+
"event",
|
|
4477
|
+
"actions",
|
|
4478
|
+
"children",
|
|
4479
|
+
"self",
|
|
4480
|
+
"system"
|
|
4481
|
+
].filter((name) => new RegExp(`\\b${name}\\b`).test(referenced));
|
|
4482
|
+
return raw(`(${bindings.length ? `{ ${bindings.join(", ")} }` : "_"}, enq) => {\n${[...statements.map((statement) => ` ${formatV6Statement(statement)}`), ...returnValue ? [` return ${returnValue};`] : []].join("\n")}\n}`);
|
|
4483
|
+
}
|
|
4484
|
+
function formatV6Statement(statement) {
|
|
4485
|
+
return statement === "{" || statement === "}" || statement.endsWith(";") ? statement : `${statement};`;
|
|
4486
|
+
}
|
|
4487
|
+
function renderV6Effects(effects, finalContext) {
|
|
4488
|
+
if (!(finalContext !== void 0 || effects.some((effect) => effect.contextValue))) return { statements: effects.flatMap((effect) => effect.statements ?? []) };
|
|
4489
|
+
const statements = ["let nextContext = context"];
|
|
4490
|
+
const inCurrentContext = (statement) => {
|
|
4491
|
+
statements.push("{", " const context = nextContext", ` ${statement}`, "}");
|
|
4492
|
+
};
|
|
4102
4493
|
for (const effect of effects) {
|
|
4103
|
-
|
|
4104
|
-
contextValue = effect
|
|
4494
|
+
for (const statement of effect.statements ?? []) inCurrentContext(statement);
|
|
4495
|
+
if (effect.contextValue) inCurrentContext(`nextContext = { ...nextContext, ...(${effect.contextValue}) }`);
|
|
4105
4496
|
}
|
|
4106
|
-
if (
|
|
4107
|
-
|
|
4108
|
-
|
|
4497
|
+
if (finalContext !== void 0) inCurrentContext(`nextContext = { ...nextContext, ...(${finalContext}) }`);
|
|
4498
|
+
return {
|
|
4499
|
+
statements,
|
|
4500
|
+
contextValue: "nextContext"
|
|
4501
|
+
};
|
|
4109
4502
|
}
|
|
4110
4503
|
function unwrapTemplateExpressions(value) {
|
|
4111
4504
|
if (typeof value === "string") {
|
|
@@ -4153,6 +4546,8 @@ function inlineExpr(value) {
|
|
|
4153
4546
|
function actionToV6Effect(action) {
|
|
4154
4547
|
const expr = inlineExpr(action);
|
|
4155
4548
|
if (expr) {
|
|
4549
|
+
const assignment = getV6AssignmentContextValue(expr);
|
|
4550
|
+
if (assignment) return { contextValue: assignment };
|
|
4156
4551
|
if (expr.startsWith("enq(") || expr.startsWith("enq.")) return { statements: [expr] };
|
|
4157
4552
|
const builtIn = expr.match(/^(raise|emit|sendTo|cancel|log|spawnChild|stopChild)\(([\s\S]*)\)$/);
|
|
4158
4553
|
if (builtIn) {
|
|
@@ -4182,45 +4577,127 @@ function actionToV6Effect(action) {
|
|
|
4182
4577
|
return { statements: [`enq.spawn(${serializeJS(params.src)}${options})`] };
|
|
4183
4578
|
}
|
|
4184
4579
|
if (type === "xstate.stopChild") return { statements: [`enq.stop(${serializeJS(params.actorRef)})`] };
|
|
4185
|
-
if (type === "xstate.assign") {
|
|
4186
|
-
|
|
4187
|
-
return {
|
|
4188
|
-
contextValue,
|
|
4189
|
-
returnValue: `{ context: ${contextValue} }`
|
|
4190
|
-
};
|
|
4191
|
-
}
|
|
4580
|
+
if (type === "xstate.assign") return { contextValue: serializeJS(params.assignment ?? params) };
|
|
4581
|
+
if (!type.startsWith("xstate.")) return { statements: [`enq(${/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(type) ? `actions.${type}` : `actions[${serializeJS(type)}]`}${Object.keys(params).length > 0 ? `, ${serializeJS(params)}` : ""})`] };
|
|
4192
4582
|
return null;
|
|
4193
4583
|
}
|
|
4584
|
+
function getV6AssignmentArgs(code, includeAll = false) {
|
|
4585
|
+
const entries = [
|
|
4586
|
+
"context",
|
|
4587
|
+
"event",
|
|
4588
|
+
"self",
|
|
4589
|
+
"children",
|
|
4590
|
+
"system"
|
|
4591
|
+
].filter((name) => includeAll || new RegExp(`\\b${name}\\b`).test(code));
|
|
4592
|
+
if (includeAll || /\bspawn\b/.test(code)) entries.push("spawn: enq.spawn");
|
|
4593
|
+
return `{ ${entries.join(", ")} }`;
|
|
4594
|
+
}
|
|
4595
|
+
function getV6AssignmentContextValue(code) {
|
|
4596
|
+
const parsed = parseSingleExpression(code);
|
|
4597
|
+
const expression = parsed?.expression;
|
|
4598
|
+
if (!expression || !ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "assign" || expression.arguments.length !== 1) return;
|
|
4599
|
+
const [assignment] = expression.arguments;
|
|
4600
|
+
if (!assignment) return;
|
|
4601
|
+
if (ts.isArrowFunction(assignment) || ts.isFunctionExpression(assignment)) {
|
|
4602
|
+
const source = assignment.getText(parsed.source);
|
|
4603
|
+
return `(${source})(${getV6AssignmentArgs(source)})`;
|
|
4604
|
+
}
|
|
4605
|
+
if (!ts.isObjectLiteralExpression(assignment)) return getDynamicV6AssignmentContextValue(assignment.getText(parsed.source));
|
|
4606
|
+
const properties = [];
|
|
4607
|
+
for (const property of assignment.properties) {
|
|
4608
|
+
if (ts.isPropertyAssignment(property)) {
|
|
4609
|
+
const value = property.initializer;
|
|
4610
|
+
const source = value.getText(parsed.source);
|
|
4611
|
+
properties.push(`${property.name.getText(parsed.source)}: ${ts.isArrowFunction(value) || ts.isFunctionExpression(value) ? `(${source})(${getV6AssignmentArgs(source)})` : source}`);
|
|
4612
|
+
continue;
|
|
4613
|
+
}
|
|
4614
|
+
if (ts.isMethodDeclaration(property) && property.body) {
|
|
4615
|
+
const source = property.getText(parsed.source);
|
|
4616
|
+
const params = property.parameters.map((param) => param.getText(parsed.source)).join(", ");
|
|
4617
|
+
properties.push(`${property.name.getText(parsed.source)}: (function (${params}) ${property.body.getText(parsed.source)})(${getV6AssignmentArgs(source)})`);
|
|
4618
|
+
continue;
|
|
4619
|
+
}
|
|
4620
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
4621
|
+
properties.push(property.getText(parsed.source));
|
|
4622
|
+
continue;
|
|
4623
|
+
}
|
|
4624
|
+
return getDynamicV6AssignmentContextValue(assignment.getText(parsed.source));
|
|
4625
|
+
}
|
|
4626
|
+
return `{ ${properties.join(", ")} }`;
|
|
4627
|
+
}
|
|
4628
|
+
function getDynamicV6AssignmentContextValue(assignment) {
|
|
4629
|
+
const args = getV6AssignmentArgs(assignment, true);
|
|
4630
|
+
return `((assignment) => typeof assignment === 'function'
|
|
4631
|
+
? assignment(${args})
|
|
4632
|
+
: Object.fromEntries(Object.entries(assignment).map(([key, value]) => [
|
|
4633
|
+
key,
|
|
4634
|
+
typeof value === 'function' ? value(${args}) : value,
|
|
4635
|
+
])))(${assignment})`;
|
|
4636
|
+
}
|
|
4194
4637
|
function actionOptions(params, consumedKeys) {
|
|
4195
4638
|
const rest = Object.fromEntries(Object.entries(params).filter(([key, value]) => !consumedKeys.includes(key) && value !== void 0));
|
|
4196
4639
|
return Object.keys(rest).length ? `, ${serializeJS(rest)}` : "";
|
|
4197
4640
|
}
|
|
4198
|
-
function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, usesTypes }) {
|
|
4641
|
+
function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, implementationImports, usesTypes }) {
|
|
4199
4642
|
const xstateImports = [];
|
|
4200
4643
|
if (hasSetup) xstateImports.push("setup");
|
|
4201
4644
|
else xstateImports.push("createMachine");
|
|
4202
4645
|
for (const name of builtInActions) xstateImports.push(name);
|
|
4203
4646
|
for (const name of actorSourceImports) xstateImports.push(name);
|
|
4647
|
+
for (const name of implementationImports) xstateImports.push(name);
|
|
4204
4648
|
if (usesTypes) xstateImports.push("types");
|
|
4205
4649
|
if (hasActors) {
|
|
4206
4650
|
if (actors.length > 0) xstateImports.push("fromPromise");
|
|
4207
4651
|
}
|
|
4208
4652
|
return `import { ${[...new Set(xstateImports)].join(", ")} } from 'xstate';`;
|
|
4209
4653
|
}
|
|
4654
|
+
const XSTATE_ACTOR_LOGIC_HELPERS = new Set([
|
|
4655
|
+
"createMachine",
|
|
4656
|
+
"createAsyncLogic",
|
|
4657
|
+
"fromPromise",
|
|
4658
|
+
"fromCallback",
|
|
4659
|
+
"fromObservable",
|
|
4660
|
+
"fromEventObservable",
|
|
4661
|
+
"fromTransition"
|
|
4662
|
+
]);
|
|
4663
|
+
const XSTATE_IMPLEMENTATION_HELPERS = new Set([
|
|
4664
|
+
...Object.values(BUILTIN_ACTION_IMPORTS),
|
|
4665
|
+
"enqueueActions",
|
|
4666
|
+
"sendParent",
|
|
4667
|
+
"forwardTo",
|
|
4668
|
+
"stop",
|
|
4669
|
+
"and",
|
|
4670
|
+
"or",
|
|
4671
|
+
"not",
|
|
4672
|
+
"stateIn",
|
|
4673
|
+
...XSTATE_ACTOR_LOGIC_HELPERS
|
|
4674
|
+
]);
|
|
4675
|
+
function getImplementationImports(impls) {
|
|
4676
|
+
const imports = /* @__PURE__ */ new Set();
|
|
4677
|
+
if (!impls) return imports;
|
|
4678
|
+
for (const implementation of [
|
|
4679
|
+
...impls.actions,
|
|
4680
|
+
...impls.guards,
|
|
4681
|
+
...impls.actors,
|
|
4682
|
+
...impls.delays
|
|
4683
|
+
]) {
|
|
4684
|
+
const code = implementation.code?.body;
|
|
4685
|
+
if (!code) continue;
|
|
4686
|
+
const source = ts.createSourceFile("implementation.ts", code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
4687
|
+
function visit(node) {
|
|
4688
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && XSTATE_IMPLEMENTATION_HELPERS.has(node.expression.text)) imports.add(node.expression.text);
|
|
4689
|
+
ts.forEachChild(node, visit);
|
|
4690
|
+
}
|
|
4691
|
+
visit(source);
|
|
4692
|
+
}
|
|
4693
|
+
return imports;
|
|
4694
|
+
}
|
|
4210
4695
|
function getActorSourceImports(graph) {
|
|
4211
4696
|
const imports = /* @__PURE__ */ new Set();
|
|
4212
|
-
const candidates = [
|
|
4213
|
-
"createAsyncLogic",
|
|
4214
|
-
"fromPromise",
|
|
4215
|
-
"fromCallback",
|
|
4216
|
-
"fromObservable",
|
|
4217
|
-
"fromEventObservable",
|
|
4218
|
-
"fromTransition"
|
|
4219
|
-
];
|
|
4220
4697
|
for (const node of graph.nodes) for (const invoke of node.data.invokes ?? []) {
|
|
4221
4698
|
const expression = invoke.srcExpression?.expr;
|
|
4222
4699
|
if (!expression) continue;
|
|
4223
|
-
for (const candidate of
|
|
4700
|
+
for (const candidate of XSTATE_ACTOR_LOGIC_HELPERS) if (new RegExp(`\\b${candidate}\\b`).test(expression)) imports.add(candidate);
|
|
4224
4701
|
}
|
|
4225
4702
|
return imports;
|
|
4226
4703
|
}
|
|
@@ -4307,11 +4784,27 @@ function buildGuardsBlock(guards, options) {
|
|
|
4307
4784
|
function buildActorsBlock(actors, options) {
|
|
4308
4785
|
const block = {};
|
|
4309
4786
|
for (const actor of actors) if (actor.code?.body) {
|
|
4787
|
+
const inlineExpression = getActorLogicExpression(actor.code.body);
|
|
4788
|
+
if (inlineExpression) {
|
|
4789
|
+
block[actor.name] = raw(inlineExpression);
|
|
4790
|
+
continue;
|
|
4791
|
+
}
|
|
4792
|
+
const functionExpression = stripExportDefault(actor.code.body);
|
|
4793
|
+
if (isCompleteFunctionExpression(functionExpression)) {
|
|
4794
|
+
block[actor.name] = raw(`fromPromise(${functionExpression})`);
|
|
4795
|
+
continue;
|
|
4796
|
+
}
|
|
4310
4797
|
const inputType = options.includeTypeSyntax && hasSchemaProperties(actor.inputSchema) ? `: ${jsonSchemaToTSType(actor.inputSchema)}` : "";
|
|
4311
4798
|
block[actor.name] = raw(`fromPromise(async ({ input }${inputType ? `: { input${inputType} }` : ""}) => {\n ${dedent(actor.code.body)}\n})`);
|
|
4312
4799
|
} else block[actor.name] = raw(`fromPromise(async ({ input }) => {\n // TODO: implement ${actor.name}\n})`);
|
|
4313
4800
|
return block;
|
|
4314
4801
|
}
|
|
4802
|
+
function getActorLogicExpression(code) {
|
|
4803
|
+
const parsed = parseSingleExpression(stripExportDefault(code));
|
|
4804
|
+
const expression = parsed?.expression;
|
|
4805
|
+
if (!parsed || !expression || !ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || !XSTATE_ACTOR_LOGIC_HELPERS.has(expression.expression.text)) return;
|
|
4806
|
+
return parsed.candidate;
|
|
4807
|
+
}
|
|
4315
4808
|
function buildDelaysBlock(delays) {
|
|
4316
4809
|
const block = {};
|
|
4317
4810
|
for (const delay of delays) if (delay.code?.body) {
|
|
@@ -4320,6 +4813,11 @@ function buildDelaysBlock(delays) {
|
|
|
4320
4813
|
block[delay.name] = raw(inlineExpression);
|
|
4321
4814
|
continue;
|
|
4322
4815
|
}
|
|
4816
|
+
const constantExpression = getConstantImplementationExpression(delay.code.body);
|
|
4817
|
+
if (constantExpression) {
|
|
4818
|
+
block[delay.name] = raw(constantExpression);
|
|
4819
|
+
continue;
|
|
4820
|
+
}
|
|
4323
4821
|
block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
|
|
4324
4822
|
} else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
|
|
4325
4823
|
return block;
|
|
@@ -4336,17 +4834,37 @@ function buildDelaysBlock(delays) {
|
|
|
4336
4834
|
function getInlineExpression(code) {
|
|
4337
4835
|
const stripped = stripExportDefault(code);
|
|
4338
4836
|
if (stripped !== code.trim()) return stripped;
|
|
4339
|
-
return isCompleteFunctionExpression(stripped) ? stripped : void 0;
|
|
4837
|
+
return isCompleteFunctionExpression(stripped) || isCompleteXStateHelperExpression(stripped) ? stripped : void 0;
|
|
4340
4838
|
}
|
|
4341
|
-
|
|
4342
|
-
function isCompleteFunctionExpression(code) {
|
|
4839
|
+
function parseSingleExpression(code) {
|
|
4343
4840
|
const candidate = code.trim().replace(/;$/, "");
|
|
4344
|
-
const source = ts.createSourceFile("
|
|
4345
|
-
if ((source.parseDiagnostics ?? []).length > 0 || source.statements.length !== 1) return
|
|
4841
|
+
const source = ts.createSourceFile("implementation.ts", `(${candidate})`, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
4842
|
+
if ((source.parseDiagnostics ?? []).length > 0 || source.statements.length !== 1) return;
|
|
4346
4843
|
const [statement] = source.statements;
|
|
4347
|
-
if (!statement || !ts.isExpressionStatement(statement)) return
|
|
4844
|
+
if (!statement || !ts.isExpressionStatement(statement)) return;
|
|
4348
4845
|
let expression = statement.expression;
|
|
4349
4846
|
if (ts.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
4847
|
+
return {
|
|
4848
|
+
candidate,
|
|
4849
|
+
expression,
|
|
4850
|
+
source
|
|
4851
|
+
};
|
|
4852
|
+
}
|
|
4853
|
+
function getConstantImplementationExpression(code) {
|
|
4854
|
+
const parsed = parseSingleExpression(code);
|
|
4855
|
+
if (!parsed) return;
|
|
4856
|
+
const { candidate, expression } = parsed;
|
|
4857
|
+
if (ts.isStringLiteral(expression) || ts.isNumericLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression) || expression.kind === ts.SyntaxKind.TrueKeyword || expression.kind === ts.SyntaxKind.FalseKeyword || expression.kind === ts.SyntaxKind.NullKeyword || ts.isPrefixUnaryExpression(expression) && ts.isNumericLiteral(expression.operand)) return candidate;
|
|
4858
|
+
}
|
|
4859
|
+
function isCompleteXStateHelperExpression(code) {
|
|
4860
|
+
const expression = parseSingleExpression(code)?.expression;
|
|
4861
|
+
if (!expression) return false;
|
|
4862
|
+
return ts.isCallExpression(expression) && ts.isIdentifier(expression.expression) && XSTATE_IMPLEMENTATION_HELPERS.has(expression.expression.text);
|
|
4863
|
+
}
|
|
4864
|
+
/** True when `code` is a single function or arrow-function expression. */
|
|
4865
|
+
function isCompleteFunctionExpression(code) {
|
|
4866
|
+
const expression = parseSingleExpression(code)?.expression;
|
|
4867
|
+
if (!expression) return false;
|
|
4350
4868
|
return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
|
|
4351
4869
|
}
|
|
4352
4870
|
const colorSchema = _enum([
|