@statelyai/sdk 0.20.2 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/embed.d.mts +47 -3
- package/dist/embed.mjs +134 -3
- package/dist/{graph-yDK-MM3G.d.mts → graph-B4WM_nYg.d.mts} +1 -1
- package/dist/graph.d.mts +1 -1
- package/dist/{index-BAkQThnl.d.mts → index-BABex8NE.d.mts} +65 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +3 -3
- package/dist/{inspect-CwN52e61.mjs → inspect-CnOHdMYX.mjs} +1 -1
- package/dist/inspect.mjs +2 -2
- package/dist/patchTypes.d.mts +1 -1
- package/dist/protocol.d.mts +38 -4
- package/dist/{statelyPragma-Cnj58Rua.mjs → statelyPragma-mii-qTXd.mjs} +825 -65
- package/dist/{studio-YSppd-am.d.mts → studio-CjnsqD8j.d.mts} +1 -1
- package/dist/studio.d.mts +1 -1
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +1 -1
- package/dist/{version-C-1n7MoR.mjs → version-CNeiHhaT.mjs} +4 -3
- package/package.json +3 -3
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { a as discriminatedUnion, c as object, d as union, f as unknown, i as custom, l as record, n as array, o as literal, r as boolean, s as number, t as _enum, u as string } from "./schemas-b9wG-zYl.mjs";
|
|
2
2
|
import ts from "typescript";
|
|
3
|
-
import "xstate";
|
|
4
3
|
import "xstate/graph";
|
|
5
4
|
|
|
6
5
|
//#region ../../node_modules/.pnpm/js-yaml@4.2.0/node_modules/js-yaml/dist/js-yaml.mjs
|
|
@@ -2636,7 +2635,8 @@ function formatEventParam(event) {
|
|
|
2636
2635
|
return "undefined";
|
|
2637
2636
|
}
|
|
2638
2637
|
function formatStringParam(value) {
|
|
2639
|
-
|
|
2638
|
+
if (typeof value === "string") return `'${value}'`;
|
|
2639
|
+
return isCodeExpression$1(value) ? serializeJS(value) : "undefined";
|
|
2640
2640
|
}
|
|
2641
2641
|
function formatInlineObject(value) {
|
|
2642
2642
|
return `{ ${Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => `${formatObjectKey(key)}: ${serializeJS(item)}`).join(", ")} }`;
|
|
@@ -3013,6 +3013,123 @@ const INLINE_EXPRESSION_DIRECTIVE_FIELDS = [
|
|
|
3013
3013
|
"initialInput",
|
|
3014
3014
|
"route"
|
|
3015
3015
|
];
|
|
3016
|
+
const EXACT_SEMVER$1 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
3017
|
+
function parseProfileSpecifier(specifier) {
|
|
3018
|
+
const separator = specifier.lastIndexOf("@");
|
|
3019
|
+
const name = specifier.slice(0, separator);
|
|
3020
|
+
const version = specifier.slice(separator + 1);
|
|
3021
|
+
if (separator <= 0 || !/^@[^/]+\/[^@/]+$/.test(name) || !version) throw new Error(`Invalid profile specifier: ${specifier}`);
|
|
3022
|
+
return {
|
|
3023
|
+
name,
|
|
3024
|
+
version,
|
|
3025
|
+
kind: EXACT_SEMVER$1.test(version) ? "exact" : "range"
|
|
3026
|
+
};
|
|
3027
|
+
}
|
|
3028
|
+
function normalizeProfileRef(profile) {
|
|
3029
|
+
return profile === "xstate-v5" || profile === "xstate-v6-alpha" ? normalizeMachineProfile(profile) : profile;
|
|
3030
|
+
}
|
|
3031
|
+
/** Stately's semantic projection of the LangGraph 1.x APIs across runtimes. */
|
|
3032
|
+
const LANGGRAPH_PROFILE = "@statelyai/langgraph@1.0.0";
|
|
3033
|
+
const LANGGRAPH_PROFILE_MANIFEST = {
|
|
3034
|
+
profile: LANGGRAPH_PROFILE,
|
|
3035
|
+
name: "LangGraph",
|
|
3036
|
+
description: "LangGraph 1.x graph semantics for Python and JavaScript/TypeScript source.",
|
|
3037
|
+
restrictFormatsToListed: true,
|
|
3038
|
+
authoring: {
|
|
3039
|
+
terminology: {
|
|
3040
|
+
node: "node",
|
|
3041
|
+
edge: "edge",
|
|
3042
|
+
graph: "graph"
|
|
3043
|
+
},
|
|
3044
|
+
nodeTypes: [
|
|
3045
|
+
{
|
|
3046
|
+
kind: "node",
|
|
3047
|
+
label: "Node",
|
|
3048
|
+
description: "Graph API node",
|
|
3049
|
+
authorable: true
|
|
3050
|
+
},
|
|
3051
|
+
{
|
|
3052
|
+
kind: "task",
|
|
3053
|
+
label: "Task",
|
|
3054
|
+
description: "Functional API task",
|
|
3055
|
+
authorable: true
|
|
3056
|
+
},
|
|
3057
|
+
{
|
|
3058
|
+
kind: "entrypoint",
|
|
3059
|
+
label: "Entrypoint",
|
|
3060
|
+
description: "Functional API entrypoint",
|
|
3061
|
+
authorable: true
|
|
3062
|
+
},
|
|
3063
|
+
{
|
|
3064
|
+
kind: "agent",
|
|
3065
|
+
label: "Agent",
|
|
3066
|
+
description: "Prebuilt agent",
|
|
3067
|
+
authorable: true
|
|
3068
|
+
},
|
|
3069
|
+
{
|
|
3070
|
+
kind: "end",
|
|
3071
|
+
label: "END",
|
|
3072
|
+
description: "Terminal sentinel",
|
|
3073
|
+
authorable: true,
|
|
3074
|
+
terminal: true
|
|
3075
|
+
}
|
|
3076
|
+
],
|
|
3077
|
+
edgeTypes: [
|
|
3078
|
+
{
|
|
3079
|
+
kind: "edge",
|
|
3080
|
+
label: "Edge",
|
|
3081
|
+
description: "Direct route",
|
|
3082
|
+
authorable: true
|
|
3083
|
+
},
|
|
3084
|
+
{
|
|
3085
|
+
kind: "conditional",
|
|
3086
|
+
label: "Conditional edge",
|
|
3087
|
+
description: "Runtime-routed branch",
|
|
3088
|
+
authorable: true
|
|
3089
|
+
},
|
|
3090
|
+
{
|
|
3091
|
+
kind: "call",
|
|
3092
|
+
label: "Call",
|
|
3093
|
+
description: "Functional API call",
|
|
3094
|
+
authorable: true
|
|
3095
|
+
}
|
|
3096
|
+
],
|
|
3097
|
+
attachments: {},
|
|
3098
|
+
supportsInitialNode: false,
|
|
3099
|
+
supportsTargetlessEdges: false,
|
|
3100
|
+
supportsReenterEdges: false
|
|
3101
|
+
},
|
|
3102
|
+
operations: {
|
|
3103
|
+
simulate: false,
|
|
3104
|
+
validate: false,
|
|
3105
|
+
export: false
|
|
3106
|
+
},
|
|
3107
|
+
formats: [
|
|
3108
|
+
{
|
|
3109
|
+
format: "python",
|
|
3110
|
+
import: true,
|
|
3111
|
+
export: false,
|
|
3112
|
+
sourcePreserving: true
|
|
3113
|
+
},
|
|
3114
|
+
{
|
|
3115
|
+
format: "typescript",
|
|
3116
|
+
import: true,
|
|
3117
|
+
export: false,
|
|
3118
|
+
sourcePreserving: true
|
|
3119
|
+
},
|
|
3120
|
+
{
|
|
3121
|
+
format: "javascript",
|
|
3122
|
+
import: true,
|
|
3123
|
+
export: false,
|
|
3124
|
+
sourcePreserving: true
|
|
3125
|
+
}
|
|
3126
|
+
],
|
|
3127
|
+
features: {
|
|
3128
|
+
graphApi: true,
|
|
3129
|
+
functionalApi: true,
|
|
3130
|
+
prebuiltAgents: true
|
|
3131
|
+
}
|
|
3132
|
+
};
|
|
3016
3133
|
const XSTATE_FORMATS = [
|
|
3017
3134
|
{
|
|
3018
3135
|
format: "typescript",
|
|
@@ -3037,16 +3154,99 @@ const XSTATE_FORMATS = [
|
|
|
3037
3154
|
export: true
|
|
3038
3155
|
}
|
|
3039
3156
|
];
|
|
3157
|
+
const XSTATE_AUTHORING = {
|
|
3158
|
+
terminology: {
|
|
3159
|
+
node: "state",
|
|
3160
|
+
edge: "transition",
|
|
3161
|
+
graph: "machine"
|
|
3162
|
+
},
|
|
3163
|
+
nodeTypes: [
|
|
3164
|
+
{
|
|
3165
|
+
kind: "normal",
|
|
3166
|
+
label: "Normal",
|
|
3167
|
+
description: "Basic state",
|
|
3168
|
+
authorable: true,
|
|
3169
|
+
canContain: true
|
|
3170
|
+
},
|
|
3171
|
+
{
|
|
3172
|
+
kind: "parallel",
|
|
3173
|
+
label: "Parallel",
|
|
3174
|
+
description: "Concurrent child states",
|
|
3175
|
+
authorable: true,
|
|
3176
|
+
canContain: true
|
|
3177
|
+
},
|
|
3178
|
+
{
|
|
3179
|
+
kind: "final",
|
|
3180
|
+
label: "Final",
|
|
3181
|
+
description: "Terminal state",
|
|
3182
|
+
authorable: true,
|
|
3183
|
+
terminal: true
|
|
3184
|
+
},
|
|
3185
|
+
{
|
|
3186
|
+
kind: "history",
|
|
3187
|
+
label: "History",
|
|
3188
|
+
description: "Restores previous state",
|
|
3189
|
+
authorable: true
|
|
3190
|
+
},
|
|
3191
|
+
{
|
|
3192
|
+
kind: "choice",
|
|
3193
|
+
label: "Choice",
|
|
3194
|
+
description: "Guarded eventless routing",
|
|
3195
|
+
authorable: true
|
|
3196
|
+
}
|
|
3197
|
+
],
|
|
3198
|
+
edgeTypes: [{
|
|
3199
|
+
kind: "transition",
|
|
3200
|
+
label: "Transition",
|
|
3201
|
+
authorable: true
|
|
3202
|
+
}],
|
|
3203
|
+
attachments: {
|
|
3204
|
+
actions: true,
|
|
3205
|
+
guards: true,
|
|
3206
|
+
invokes: true,
|
|
3207
|
+
tags: true
|
|
3208
|
+
},
|
|
3209
|
+
supportsInitialNode: true,
|
|
3210
|
+
supportsTargetlessEdges: true,
|
|
3211
|
+
supportsReenterEdges: true
|
|
3212
|
+
};
|
|
3040
3213
|
const XSTATE_PROFILE_MANIFESTS = [{
|
|
3041
3214
|
profile: XSTATE_V5_PROFILE,
|
|
3042
3215
|
name: "XState v5",
|
|
3043
|
-
formats: [...XSTATE_FORMATS]
|
|
3216
|
+
formats: [...XSTATE_FORMATS],
|
|
3217
|
+
authoring: XSTATE_AUTHORING,
|
|
3218
|
+
operations: {
|
|
3219
|
+
simulate: true,
|
|
3220
|
+
validate: true,
|
|
3221
|
+
export: true
|
|
3222
|
+
}
|
|
3044
3223
|
}, {
|
|
3045
3224
|
profile: XSTATE_V6_PROFILE,
|
|
3046
3225
|
name: "XState v6",
|
|
3047
|
-
formats: [...XSTATE_FORMATS]
|
|
3226
|
+
formats: [...XSTATE_FORMATS],
|
|
3227
|
+
authoring: XSTATE_AUTHORING,
|
|
3228
|
+
operations: {
|
|
3229
|
+
simulate: true,
|
|
3230
|
+
validate: true,
|
|
3231
|
+
export: true
|
|
3232
|
+
}
|
|
3048
3233
|
}];
|
|
3049
|
-
const PROFILE_MANIFESTS = new Map(XSTATE_PROFILE_MANIFESTS.map((manifest) => [manifest.profile, manifest]));
|
|
3234
|
+
const PROFILE_MANIFESTS = new Map([...XSTATE_PROFILE_MANIFESTS, LANGGRAPH_PROFILE_MANIFEST].map((manifest) => [manifest.profile, manifest]));
|
|
3235
|
+
function getProfileManifest(profile) {
|
|
3236
|
+
return PROFILE_MANIFESTS.get(profile);
|
|
3237
|
+
}
|
|
3238
|
+
function isXStateV6ProfileRef(profile) {
|
|
3239
|
+
let current = normalizeProfileRef(profile);
|
|
3240
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3241
|
+
while (!seen.has(current)) {
|
|
3242
|
+
if (isXStateV6Profile(current)) return true;
|
|
3243
|
+
seen.add(current);
|
|
3244
|
+
const parent = getProfileManifest(current)?.extends;
|
|
3245
|
+
if (!parent || parseProfileSpecifier(parent).kind !== "exact") return false;
|
|
3246
|
+
current = parent;
|
|
3247
|
+
}
|
|
3248
|
+
return false;
|
|
3249
|
+
}
|
|
3050
3250
|
const XSTATE_V6_FN_TRANSITION_META = "@statelyai.xstate.v6.fnTransition";
|
|
3051
3251
|
const XSTATE_V6_FN_SOURCE_META = "@statelyai.xstate.v6.fnSource";
|
|
3052
3252
|
function sourceFile(source) {
|
|
@@ -3060,7 +3260,193 @@ function unwrapExpression(node) {
|
|
|
3060
3260
|
if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node) || ts.isParenthesizedExpression(node)) return unwrapExpression(node.expression);
|
|
3061
3261
|
return node;
|
|
3062
3262
|
}
|
|
3263
|
+
function canReplaceIdentifier(node) {
|
|
3264
|
+
const parent = node.parent;
|
|
3265
|
+
if (ts.isPropertyAccessExpression(parent) && parent.name === node) return false;
|
|
3266
|
+
if (ts.isPropertyAssignment(parent) && parent.name === node) return false;
|
|
3267
|
+
if (ts.isMethodDeclaration(parent) && parent.name === node) return false;
|
|
3268
|
+
return true;
|
|
3269
|
+
}
|
|
3270
|
+
function bindingNameContains(name, identifier) {
|
|
3271
|
+
if (ts.isIdentifier(name)) return name.text === identifier;
|
|
3272
|
+
return name.elements.some((element) => ts.isBindingElement(element) && bindingNameContains(element.name, identifier));
|
|
3273
|
+
}
|
|
3274
|
+
function scopeBindsName(node, identifier) {
|
|
3275
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.parameters.some((parameter) => bindingNameContains(parameter.name, identifier))) return true;
|
|
3276
|
+
if (ts.isCatchClause(node) && node.variableDeclaration) return bindingNameContains(node.variableDeclaration.name, identifier);
|
|
3277
|
+
if (ts.isBlock(node)) return node.statements.some((statement) => {
|
|
3278
|
+
if (ts.isVariableStatement(statement)) return statement.declarationList.declarations.some((declaration) => bindingNameContains(declaration.name, identifier));
|
|
3279
|
+
return ts.isFunctionDeclaration(statement) && statement.name?.text === identifier;
|
|
3280
|
+
});
|
|
3281
|
+
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));
|
|
3282
|
+
return false;
|
|
3283
|
+
}
|
|
3284
|
+
function isShadowedWithinExpression(node, expression) {
|
|
3285
|
+
let ancestor = node.parent;
|
|
3286
|
+
while (ancestor && ancestor !== expression.parent) {
|
|
3287
|
+
if (scopeBindsName(ancestor, node.text)) return true;
|
|
3288
|
+
ancestor = ancestor.parent;
|
|
3289
|
+
}
|
|
3290
|
+
return false;
|
|
3291
|
+
}
|
|
3292
|
+
function replacementText(node, expression) {
|
|
3293
|
+
if (ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node) return `${node.text}: (${expression})`;
|
|
3294
|
+
return `(${expression})`;
|
|
3295
|
+
}
|
|
3296
|
+
function isSafeInlineExpression(expression) {
|
|
3297
|
+
let safe = true;
|
|
3298
|
+
function visit(node) {
|
|
3299
|
+
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) {
|
|
3300
|
+
safe = false;
|
|
3301
|
+
return;
|
|
3302
|
+
}
|
|
3303
|
+
ts.forEachChild(node, visit);
|
|
3304
|
+
}
|
|
3305
|
+
visit(expression);
|
|
3306
|
+
return safe;
|
|
3307
|
+
}
|
|
3308
|
+
function hasUnsafeVariableInitializer(node) {
|
|
3309
|
+
let unsafe = false;
|
|
3310
|
+
function visit(current) {
|
|
3311
|
+
if (unsafe) return;
|
|
3312
|
+
if (current !== node && (ts.isArrowFunction(current) || ts.isFunctionExpression(current) || ts.isFunctionDeclaration(current))) return;
|
|
3313
|
+
if (ts.isVariableDeclaration(current) && current.initializer && !isSafeInlineExpression(current.initializer)) {
|
|
3314
|
+
unsafe = true;
|
|
3315
|
+
return;
|
|
3316
|
+
}
|
|
3317
|
+
ts.forEachChild(current, visit);
|
|
3318
|
+
}
|
|
3319
|
+
visit(node);
|
|
3320
|
+
return unsafe;
|
|
3321
|
+
}
|
|
3322
|
+
function resolvedExpressionText(expression, bindings, resolving = /* @__PURE__ */ new Set()) {
|
|
3323
|
+
const source = expression.getSourceFile();
|
|
3324
|
+
const start = expression.getStart(source);
|
|
3325
|
+
const replacements = [];
|
|
3326
|
+
function visit(node) {
|
|
3327
|
+
if (ts.isIdentifier(node) && canReplaceIdentifier(node) && !isShadowedWithinExpression(node, expression)) {
|
|
3328
|
+
const binding = bindings.get(node.text);
|
|
3329
|
+
if (binding && !ts.isFunctionDeclaration(binding) && isSafeInlineExpression(binding) && binding !== expression && !resolving.has(node.text)) {
|
|
3330
|
+
const nextResolving = new Set(resolving).add(node.text);
|
|
3331
|
+
replacements.push({
|
|
3332
|
+
start: node.getStart(source) - start,
|
|
3333
|
+
end: node.getEnd() - start,
|
|
3334
|
+
text: replacementText(node, resolvedExpressionText(binding, bindings, nextResolving))
|
|
3335
|
+
});
|
|
3336
|
+
return;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
ts.forEachChild(node, visit);
|
|
3340
|
+
}
|
|
3341
|
+
visit(expression);
|
|
3342
|
+
let result = expression.getText(source);
|
|
3343
|
+
for (const replacement of replacements.sort((a, b) => b.start - a.start)) result = result.slice(0, replacement.start) + replacement.text + result.slice(replacement.end);
|
|
3344
|
+
return result;
|
|
3345
|
+
}
|
|
3346
|
+
function typeNodeToJsonSchema(node) {
|
|
3347
|
+
if (ts.isParenthesizedTypeNode(node)) return typeNodeToJsonSchema(node.type);
|
|
3348
|
+
if (ts.isLiteralTypeNode(node)) {
|
|
3349
|
+
const literal = node.literal;
|
|
3350
|
+
if (ts.isStringLiteral(literal) || ts.isNumericLiteral(literal)) return { const: ts.isNumericLiteral(literal) ? Number(literal.text) : literal.text };
|
|
3351
|
+
if (literal.kind === ts.SyntaxKind.TrueKeyword) return { const: true };
|
|
3352
|
+
if (literal.kind === ts.SyntaxKind.FalseKeyword) return { const: false };
|
|
3353
|
+
return null;
|
|
3354
|
+
}
|
|
3355
|
+
if (ts.isUnionTypeNode(node)) {
|
|
3356
|
+
const members = node.types.map(typeNodeToJsonSchema);
|
|
3357
|
+
if (members.some((member) => !member)) return null;
|
|
3358
|
+
const constants = members.map((member) => member?.const);
|
|
3359
|
+
if (constants.every((value) => value !== void 0)) return { enum: constants };
|
|
3360
|
+
return { anyOf: members };
|
|
3361
|
+
}
|
|
3362
|
+
if (ts.isArrayTypeNode(node)) {
|
|
3363
|
+
const items = typeNodeToJsonSchema(node.elementType);
|
|
3364
|
+
return items ? {
|
|
3365
|
+
type: "array",
|
|
3366
|
+
items
|
|
3367
|
+
} : null;
|
|
3368
|
+
}
|
|
3369
|
+
if (ts.isTupleTypeNode(node)) {
|
|
3370
|
+
const items = node.elements.map((element) => typeNodeToJsonSchema(element));
|
|
3371
|
+
if (items.some((item) => !item)) return null;
|
|
3372
|
+
return {
|
|
3373
|
+
type: "array",
|
|
3374
|
+
items,
|
|
3375
|
+
minItems: items.length,
|
|
3376
|
+
maxItems: items.length
|
|
3377
|
+
};
|
|
3378
|
+
}
|
|
3379
|
+
if (ts.isTypeLiteralNode(node)) {
|
|
3380
|
+
const properties = {};
|
|
3381
|
+
const required = [];
|
|
3382
|
+
for (const member of node.members) {
|
|
3383
|
+
if (!ts.isPropertySignature(member) || !member.type || !member.name) return null;
|
|
3384
|
+
const name = propName(member.name);
|
|
3385
|
+
const schema = typeNodeToJsonSchema(member.type);
|
|
3386
|
+
if (!name || !schema) return null;
|
|
3387
|
+
properties[name] = schema;
|
|
3388
|
+
if (!member.questionToken) required.push(name);
|
|
3389
|
+
}
|
|
3390
|
+
return {
|
|
3391
|
+
type: "object",
|
|
3392
|
+
properties,
|
|
3393
|
+
...required.length ? { required } : void 0,
|
|
3394
|
+
additionalProperties: false
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3397
|
+
switch (node.kind) {
|
|
3398
|
+
case ts.SyntaxKind.StringKeyword: return { type: "string" };
|
|
3399
|
+
case ts.SyntaxKind.NumberKeyword: return { type: "number" };
|
|
3400
|
+
case ts.SyntaxKind.BooleanKeyword: return { type: "boolean" };
|
|
3401
|
+
case ts.SyntaxKind.NullKeyword: return { type: "null" };
|
|
3402
|
+
case ts.SyntaxKind.UnknownKeyword:
|
|
3403
|
+
case ts.SyntaxKind.AnyKeyword: return {};
|
|
3404
|
+
default: return null;
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
function typesCallSchema(node) {
|
|
3408
|
+
const value = unwrapExpression(node);
|
|
3409
|
+
if (!ts.isCallExpression(value) || value.expression.getText() !== "types" || value.typeArguments?.length !== 1) return null;
|
|
3410
|
+
return typeNodeToJsonSchema(value.typeArguments[0]);
|
|
3411
|
+
}
|
|
3412
|
+
function schemasObjectToValue(node) {
|
|
3413
|
+
const value = unwrapExpression(node);
|
|
3414
|
+
if (!ts.isObjectLiteralExpression(value)) return null;
|
|
3415
|
+
const result = {};
|
|
3416
|
+
for (const property of value.properties) {
|
|
3417
|
+
if (!ts.isPropertyAssignment(property)) continue;
|
|
3418
|
+
const key = propName(property.name);
|
|
3419
|
+
if (!key) continue;
|
|
3420
|
+
if (key === "events" && ts.isObjectLiteralExpression(property.initializer)) {
|
|
3421
|
+
const events = {};
|
|
3422
|
+
for (const eventProperty of property.initializer.properties) {
|
|
3423
|
+
if (!ts.isPropertyAssignment(eventProperty)) continue;
|
|
3424
|
+
const eventType = propName(eventProperty.name);
|
|
3425
|
+
const schema = typesCallSchema(eventProperty.initializer);
|
|
3426
|
+
if (eventType && schema) events[eventType] = schema;
|
|
3427
|
+
}
|
|
3428
|
+
result.events = events;
|
|
3429
|
+
continue;
|
|
3430
|
+
}
|
|
3431
|
+
const schema = typesCallSchema(property.initializer);
|
|
3432
|
+
if (!schema) continue;
|
|
3433
|
+
result[key] = key === "context" ? schema.properties ?? {} : schema;
|
|
3434
|
+
}
|
|
3435
|
+
return result;
|
|
3436
|
+
}
|
|
3063
3437
|
function propertyContext(parent, key) {
|
|
3438
|
+
if (parent.setupValue && (key === "actions" || key === "guards" || key === "actors" || key === "delays")) return {
|
|
3439
|
+
v6: parent.v6,
|
|
3440
|
+
implementationMap: true
|
|
3441
|
+
};
|
|
3442
|
+
if (parent.implementationMap) return {
|
|
3443
|
+
v6: parent.v6,
|
|
3444
|
+
implementationValue: true
|
|
3445
|
+
};
|
|
3446
|
+
if (parent.effectArgumentValue) return {
|
|
3447
|
+
v6: parent.v6,
|
|
3448
|
+
effectArgumentValue: true
|
|
3449
|
+
};
|
|
3064
3450
|
if (parent.invokeValue && key === "src") return {
|
|
3065
3451
|
v6: parent.v6,
|
|
3066
3452
|
actorSourceValue: true
|
|
@@ -3078,6 +3464,14 @@ function propertyContext(parent, key) {
|
|
|
3078
3464
|
assignmentMap: true,
|
|
3079
3465
|
transitionContext: true
|
|
3080
3466
|
};
|
|
3467
|
+
if (key === "context") return {
|
|
3468
|
+
v6: parent.v6,
|
|
3469
|
+
machineContextValue: true
|
|
3470
|
+
};
|
|
3471
|
+
if (parent.transitionValue && key === "target") return {
|
|
3472
|
+
v6: parent.v6,
|
|
3473
|
+
targetValue: true
|
|
3474
|
+
};
|
|
3081
3475
|
if (parent.assignmentMap) return {
|
|
3082
3476
|
v6: parent.v6,
|
|
3083
3477
|
assignmentValue: true
|
|
@@ -3124,14 +3518,11 @@ function propertyContext(parent, key) {
|
|
|
3124
3518
|
};
|
|
3125
3519
|
return { v6: parent.v6 };
|
|
3126
3520
|
}
|
|
3127
|
-
function fallbackFunctionTransition(fn
|
|
3128
|
-
return {
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
[XSTATE_V6_FN_SOURCE_META]: fn.getText()
|
|
3133
|
-
}
|
|
3134
|
-
};
|
|
3521
|
+
function fallbackFunctionTransition(fn) {
|
|
3522
|
+
return { meta: {
|
|
3523
|
+
[XSTATE_V6_FN_TRANSITION_META]: true,
|
|
3524
|
+
[XSTATE_V6_FN_SOURCE_META]: fn.getText()
|
|
3525
|
+
} };
|
|
3135
3526
|
}
|
|
3136
3527
|
function conditionText(cond) {
|
|
3137
3528
|
return cond.negated ? `!(${cond.text})` : cond.text;
|
|
@@ -3152,7 +3543,7 @@ function hashString(value) {
|
|
|
3152
3543
|
return (hash >>> 0).toString(36);
|
|
3153
3544
|
}
|
|
3154
3545
|
function inlineGuardCode(params, condition) {
|
|
3155
|
-
return `${params} => ${condition}`;
|
|
3546
|
+
return `${params} => ${condition.trimStart().startsWith("{") ? `(${condition})` : condition}`;
|
|
3156
3547
|
}
|
|
3157
3548
|
function guardFromConditions(conds, params) {
|
|
3158
3549
|
const simplified = simplifyConditions(conds);
|
|
@@ -3188,7 +3579,7 @@ function transitionFromValue(value, actions) {
|
|
|
3188
3579
|
function expressionBranches(expression, bindings, depth) {
|
|
3189
3580
|
const node = unwrapExpression(expression);
|
|
3190
3581
|
if (ts.isConditionalExpression(node)) {
|
|
3191
|
-
const cond = node.condition
|
|
3582
|
+
const cond = resolvedExpressionText(node.condition, bindings);
|
|
3192
3583
|
return [...expressionBranches(node.whenTrue, bindings, depth + 1).map((branch) => ({
|
|
3193
3584
|
...branch,
|
|
3194
3585
|
conds: [{ text: cond }, ...branch.conds]
|
|
@@ -3201,7 +3592,7 @@ function expressionBranches(expression, bindings, depth) {
|
|
|
3201
3592
|
}))];
|
|
3202
3593
|
}
|
|
3203
3594
|
if (ts.isBinaryExpression(node) && (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === ts.SyntaxKind.BarBarToken)) {
|
|
3204
|
-
const cond = node.left
|
|
3595
|
+
const cond = resolvedExpressionText(node.left, bindings);
|
|
3205
3596
|
if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) return [...expressionBranches(node.right, bindings, depth + 1).map((branch) => ({
|
|
3206
3597
|
...branch,
|
|
3207
3598
|
conds: [{ text: cond }, ...branch.conds]
|
|
@@ -3259,7 +3650,7 @@ function expressionStatementAction(statement, enqName, bindings) {
|
|
|
3259
3650
|
if (ts.isIdentifier(callee) && callee.text === enqName) return {
|
|
3260
3651
|
type: "xstate.expr",
|
|
3261
3652
|
params: {
|
|
3262
|
-
code: expression
|
|
3653
|
+
code: resolvedExpressionText(expression, bindings),
|
|
3263
3654
|
lang: "ts"
|
|
3264
3655
|
}
|
|
3265
3656
|
};
|
|
@@ -3269,7 +3660,7 @@ function expressionStatementAction(statement, enqName, bindings) {
|
|
|
3269
3660
|
const args = expression.arguments;
|
|
3270
3661
|
const value = (index) => {
|
|
3271
3662
|
const arg = args[index];
|
|
3272
|
-
return arg && ts.isExpression(arg) ? expressionToValue(arg, bindings, {}, 0) : void 0;
|
|
3663
|
+
return arg && ts.isExpression(arg) ? expressionToValue(arg, bindings, { effectArgumentValue: true }, 0) : void 0;
|
|
3273
3664
|
};
|
|
3274
3665
|
const spreadOpts = (index) => {
|
|
3275
3666
|
const opts = value(index);
|
|
@@ -3358,7 +3749,7 @@ function statementBranches(statements, bindings, enqName, prefixes = [{
|
|
|
3358
3749
|
}
|
|
3359
3750
|
}
|
|
3360
3751
|
if (ts.isIfStatement(statement)) {
|
|
3361
|
-
const cond = statement.expression
|
|
3752
|
+
const cond = resolvedExpressionText(statement.expression, scopedBindings);
|
|
3362
3753
|
const thenBranches = statementBranches(ts.isBlock(statement.thenStatement) ? statement.thenStatement.statements : [statement.thenStatement], scopedBindings, enqName, [{
|
|
3363
3754
|
...prefix,
|
|
3364
3755
|
conds: [...prefix.conds, { text: cond }]
|
|
@@ -3382,7 +3773,14 @@ function statementBranches(statements, bindings, enqName, prefixes = [{
|
|
|
3382
3773
|
continue;
|
|
3383
3774
|
}
|
|
3384
3775
|
if (ts.isSwitchStatement(statement)) {
|
|
3385
|
-
|
|
3776
|
+
if (statement.caseBlock.clauses.some((clause) => clause.statements.length === 0)) {
|
|
3777
|
+
nextOpen.push({
|
|
3778
|
+
...prefix,
|
|
3779
|
+
unknown: true
|
|
3780
|
+
});
|
|
3781
|
+
continue;
|
|
3782
|
+
}
|
|
3783
|
+
const expr = resolvedExpressionText(statement.expression, scopedBindings);
|
|
3386
3784
|
const prior = [];
|
|
3387
3785
|
for (const clause of statement.caseBlock.clauses) {
|
|
3388
3786
|
const ownCond = ts.isCaseClause(clause) ? { text: `${expr} === ${clause.expression.getText()}` } : null;
|
|
@@ -3419,9 +3817,11 @@ function guardParams(fn) {
|
|
|
3419
3817
|
return `(${param.getText()})`;
|
|
3420
3818
|
}
|
|
3421
3819
|
function normalizeFunctionTransition(fn, bindings, depth) {
|
|
3422
|
-
|
|
3423
|
-
const
|
|
3424
|
-
|
|
3820
|
+
if (fn.body && ts.isBlock(fn.body) && hasUnsafeVariableInitializer(fn.body)) return fallbackFunctionTransition(fn);
|
|
3821
|
+
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)) : [];
|
|
3822
|
+
if (branches.some((branch) => branch.unknown)) return fallbackFunctionTransition(fn);
|
|
3823
|
+
const transitions = branches.map((branch) => {
|
|
3824
|
+
const transition = transitionFromValue(branch.result, branch.actions);
|
|
3425
3825
|
if (!transition) return null;
|
|
3426
3826
|
if (typeof transition === "string") {
|
|
3427
3827
|
const guard = guardFromConditions(branch.conds, guardParams(fn));
|
|
@@ -3438,7 +3838,7 @@ function normalizeFunctionTransition(fn, bindings, depth) {
|
|
|
3438
3838
|
}).filter((transition) => Boolean(transition));
|
|
3439
3839
|
if (transitions.length === 1) return transitions[0];
|
|
3440
3840
|
if (transitions.length > 1) return transitions;
|
|
3441
|
-
return fallbackFunctionTransition(fn
|
|
3841
|
+
return fallbackFunctionTransition(fn);
|
|
3442
3842
|
}
|
|
3443
3843
|
function inlineAction(fn) {
|
|
3444
3844
|
return {
|
|
@@ -3483,11 +3883,24 @@ function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__
|
|
|
3483
3883
|
result[key] = overrides.get(key);
|
|
3484
3884
|
continue;
|
|
3485
3885
|
}
|
|
3886
|
+
if (context.v6 && key === "schemas" && ts.isPropertyAssignment(property)) {
|
|
3887
|
+
const schemas = schemasObjectToValue(property.initializer);
|
|
3888
|
+
if (schemas) {
|
|
3889
|
+
result[key] = schemas;
|
|
3890
|
+
continue;
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3486
3893
|
if (ts.isShorthandPropertyAssignment(property)) {
|
|
3487
|
-
|
|
3894
|
+
const childContext = propertyContext(context, key);
|
|
3895
|
+
const childValue = expressionToValue(property.name, bindings, childContext, depth + 1);
|
|
3896
|
+
if (childContext.implementationValue && childValue === void 0) continue;
|
|
3897
|
+
result[key] = childValue;
|
|
3488
3898
|
continue;
|
|
3489
3899
|
}
|
|
3490
|
-
|
|
3900
|
+
const childContext = propertyContext(context, key);
|
|
3901
|
+
const childValue = expressionToValue(property.initializer, bindings, childContext, depth + 1);
|
|
3902
|
+
if (childContext.implementationValue && childValue === void 0) continue;
|
|
3903
|
+
result[key] = childValue;
|
|
3491
3904
|
}
|
|
3492
3905
|
if (context.transitionValue && "to" in result) {
|
|
3493
3906
|
const to = result.to;
|
|
@@ -3513,6 +3926,23 @@ function objectLiteralToValue(node, bindings, context, depth, overrides = /* @__
|
|
|
3513
3926
|
function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
3514
3927
|
if (depth > 30) return void 0;
|
|
3515
3928
|
const node = unwrapExpression(expression);
|
|
3929
|
+
if (context.implementationValue) {
|
|
3930
|
+
if (ts.isIdentifier(node)) {
|
|
3931
|
+
const binding = bindings.get(node.text);
|
|
3932
|
+
if (binding) return inlineCodeExpression(ts.isFunctionDeclaration(binding) ? binding.getText() : unwrapExpression(binding).getText());
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3935
|
+
return inlineCodeExpression(node.getText());
|
|
3936
|
+
}
|
|
3937
|
+
if (context.machineContextValue && (ts.isArrowFunction(node) || ts.isFunctionExpression(node))) return inlineCodeExpression(node.getText());
|
|
3938
|
+
if (context.targetValue) {
|
|
3939
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
3940
|
+
if (ts.isIdentifier(node)) {
|
|
3941
|
+
const binding = bindings.get(node.text);
|
|
3942
|
+
if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
|
|
3943
|
+
}
|
|
3944
|
+
return inlineCodeExpression(resolvedExpressionText(node, bindings));
|
|
3945
|
+
}
|
|
3516
3946
|
if (context.actorSourceValue) {
|
|
3517
3947
|
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
3518
3948
|
if (ts.isIdentifier(node)) {
|
|
@@ -3534,6 +3964,10 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
|
3534
3964
|
if (node.kind === ts.SyntaxKind.TrueKeyword) return context.ioValue ? inlineCodeExpression("true") : true;
|
|
3535
3965
|
if (node.kind === ts.SyntaxKind.FalseKeyword) return context.ioValue ? inlineCodeExpression("false") : false;
|
|
3536
3966
|
if (node.kind === ts.SyntaxKind.NullKeyword) return context.ioValue ? inlineCodeExpression("null") : null;
|
|
3967
|
+
if (context.effectArgumentValue && !ts.isObjectLiteralExpression(node) && !ts.isArrayLiteralExpression(node)) {
|
|
3968
|
+
if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
|
|
3969
|
+
return inlineCodeExpression(resolvedExpressionText(node, bindings));
|
|
3970
|
+
}
|
|
3537
3971
|
if (context.ioPropertyValue) {
|
|
3538
3972
|
if (ts.isIdentifier(node) && node.text === "undefined") return void 0;
|
|
3539
3973
|
if (ts.isIdentifier(node)) {
|
|
@@ -3548,7 +3982,7 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
|
3548
3982
|
const binding = bindings.get(node.text);
|
|
3549
3983
|
if (binding && !ts.isFunctionDeclaration(binding)) return expressionToValue(binding, bindings, context, depth + 1);
|
|
3550
3984
|
}
|
|
3551
|
-
return wrapAssignExpression(node
|
|
3985
|
+
return wrapAssignExpression(resolvedExpressionText(node, bindings));
|
|
3552
3986
|
}
|
|
3553
3987
|
if (context.transitionContext && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
|
|
3554
3988
|
if (context.ioValue && !ts.isObjectLiteralExpression(node)) return inlineCodeExpression(node.getText());
|
|
@@ -3628,10 +4062,20 @@ function isCreateMachineCall(node) {
|
|
|
3628
4062
|
if (ts.isPropertyAccessExpression(expression)) return expression.name.text === "createMachine";
|
|
3629
4063
|
return false;
|
|
3630
4064
|
}
|
|
4065
|
+
function setupCallForCreateMachine(node, bindings) {
|
|
4066
|
+
if (!ts.isPropertyAccessExpression(node.expression)) return null;
|
|
4067
|
+
let receiver = unwrapExpression(node.expression.expression);
|
|
4068
|
+
if (ts.isIdentifier(receiver)) {
|
|
4069
|
+
const binding = bindings.get(receiver.text);
|
|
4070
|
+
if (binding && !ts.isFunctionDeclaration(binding)) receiver = unwrapExpression(binding);
|
|
4071
|
+
}
|
|
4072
|
+
return ts.isCallExpression(receiver) && ts.isIdentifier(receiver.expression) && receiver.expression.text === "setup" ? receiver : null;
|
|
4073
|
+
}
|
|
3631
4074
|
function hasV6Syntax(source) {
|
|
3632
4075
|
const file = sourceFile(source);
|
|
3633
4076
|
const bindings = collectBindings(file);
|
|
3634
4077
|
let found = false;
|
|
4078
|
+
const visitedSyntaxBindings = /* @__PURE__ */ new Set();
|
|
3635
4079
|
function containsFunction(expression, seenBindings = /* @__PURE__ */ new Set()) {
|
|
3636
4080
|
if (ts.isFunctionDeclaration(expression)) return true;
|
|
3637
4081
|
const node = unwrapExpression(expression);
|
|
@@ -3652,8 +4096,16 @@ function hasV6Syntax(source) {
|
|
|
3652
4096
|
if (ts.isCallExpression(node)) return ts.isIdentifier(node.expression) && containsFunction(node.expression, seenBindings) || node.arguments.some((argument) => ts.isExpression(argument) && containsFunction(argument, seenBindings));
|
|
3653
4097
|
return false;
|
|
3654
4098
|
}
|
|
3655
|
-
function
|
|
4099
|
+
function visitSyntax(node) {
|
|
3656
4100
|
if (found) return;
|
|
4101
|
+
if (ts.isIdentifier(node)) {
|
|
4102
|
+
const binding = bindings.get(node.text);
|
|
4103
|
+
if (binding && !visitedSyntaxBindings.has(binding)) {
|
|
4104
|
+
visitedSyntaxBindings.add(binding);
|
|
4105
|
+
visitSyntax(binding);
|
|
4106
|
+
}
|
|
4107
|
+
if (found) return;
|
|
4108
|
+
}
|
|
3657
4109
|
if (ts.isPropertyAssignment(node) && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name))) {
|
|
3658
4110
|
const key = node.name.text;
|
|
3659
4111
|
if (key === "triggers" || key === "internalEvents" || key === "matches" || key === "actorSources" || key === "timeout" || key === "onTimeout" || key === "choice" || key === "route") {
|
|
@@ -3665,9 +4117,19 @@ function hasV6Syntax(source) {
|
|
|
3665
4117
|
return;
|
|
3666
4118
|
}
|
|
3667
4119
|
}
|
|
3668
|
-
ts.forEachChild(node,
|
|
4120
|
+
ts.forEachChild(node, visitSyntax);
|
|
3669
4121
|
}
|
|
3670
|
-
|
|
4122
|
+
function visitMachineCalls(node) {
|
|
4123
|
+
if (ts.isCallExpression(node) && isCreateMachineCall(node)) {
|
|
4124
|
+
const config = node.arguments[0];
|
|
4125
|
+
if (config) visitSyntax(config);
|
|
4126
|
+
const setupConfig = setupCallForCreateMachine(node, bindings)?.arguments[0];
|
|
4127
|
+
if (setupConfig) visitSyntax(setupConfig);
|
|
4128
|
+
return;
|
|
4129
|
+
}
|
|
4130
|
+
ts.forEachChild(node, visitMachineCalls);
|
|
4131
|
+
}
|
|
4132
|
+
visitMachineCalls(file);
|
|
3671
4133
|
return found;
|
|
3672
4134
|
}
|
|
3673
4135
|
function detectXStateSourceProfile(source) {
|
|
@@ -3695,7 +4157,18 @@ function extractXStateMachineConfigs(source, options = {}) {
|
|
|
3695
4157
|
const arg = node.arguments[0];
|
|
3696
4158
|
if (!arg) return;
|
|
3697
4159
|
const value = expressionToValue(arg, bindings, { v6: profile === "xstate-v6-alpha" });
|
|
3698
|
-
if (value && typeof value === "object" && !Array.isArray(value))
|
|
4160
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
4161
|
+
const setupArg = setupCallForCreateMachine(node, bindings)?.arguments[0];
|
|
4162
|
+
const setupValue = setupArg ? expressionToValue(setupArg, bindings, {
|
|
4163
|
+
v6: profile === "xstate-v6-alpha",
|
|
4164
|
+
setupValue: true
|
|
4165
|
+
}) : null;
|
|
4166
|
+
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))) : {};
|
|
4167
|
+
found.push({
|
|
4168
|
+
...setupRecord,
|
|
4169
|
+
...value
|
|
4170
|
+
});
|
|
4171
|
+
}
|
|
3699
4172
|
}
|
|
3700
4173
|
visit(file);
|
|
3701
4174
|
return found;
|
|
@@ -3777,7 +4250,8 @@ function isRequiredProperty(key, def, required) {
|
|
|
3777
4250
|
return typeof def === "object" && def !== null && def.required === true;
|
|
3778
4251
|
}
|
|
3779
4252
|
function graphToXStateTS(graph, options = {}) {
|
|
3780
|
-
const
|
|
4253
|
+
const inferredXStateVersion = isXStateV6ProfileRef(graph.data.profile ?? "xstate-v5") ? 6 : 5;
|
|
4254
|
+
const { exportStyle = "named", targetLanguage = "typescript", xstateVersion = inferredXStateVersion, ...configOptions } = options;
|
|
3781
4255
|
const schemas = graph.data.schemas;
|
|
3782
4256
|
const impls = filterInlineImplementations(graph.data.implementations);
|
|
3783
4257
|
const supportsTypeSyntax = targetLanguage === "typescript";
|
|
@@ -3789,12 +4263,14 @@ function graphToXStateTS(graph, options = {}) {
|
|
|
3789
4263
|
const hasSetup = hasSchemas || hasActions || hasGuards || hasActors || hasDelays;
|
|
3790
4264
|
const builtInActions = getUsedBuiltInActions(graph, xstateVersion);
|
|
3791
4265
|
const actorSourceImports = getActorSourceImports(graph);
|
|
4266
|
+
const implementationImports = getImplementationImports(impls);
|
|
3792
4267
|
const imports = buildImports({
|
|
3793
4268
|
hasSetup,
|
|
3794
4269
|
hasActors,
|
|
3795
4270
|
actors: impls?.actors ?? [],
|
|
3796
4271
|
builtInActions,
|
|
3797
4272
|
actorSourceImports,
|
|
4273
|
+
implementationImports,
|
|
3798
4274
|
usesTypes: xstateVersion === 6 && supportsTypeSyntax && hasSchemas
|
|
3799
4275
|
});
|
|
3800
4276
|
const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, configOptions)) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
|
|
@@ -3875,9 +4351,9 @@ function toV6MachineConfig(machineConfig) {
|
|
|
3875
4351
|
return mapV6MachineConfig(machineConfig);
|
|
3876
4352
|
}
|
|
3877
4353
|
function mapV6MachineConfig(value, context = {}) {
|
|
4354
|
+
if (context.transitionValue) return toV6TransitionValue(value);
|
|
3878
4355
|
if (Array.isArray(value)) return value.map((item) => mapV6MachineConfig(item, context));
|
|
3879
4356
|
if (!value || typeof value !== "object") return value;
|
|
3880
|
-
if (context.transitionValue) return toV6TransitionValue(value);
|
|
3881
4357
|
const result = {};
|
|
3882
4358
|
for (const [key, item] of Object.entries(value)) {
|
|
3883
4359
|
if (key === "entry" || key === "exit" || key === "actions") {
|
|
@@ -3903,7 +4379,7 @@ function mapV6TransitionMap(value) {
|
|
|
3903
4379
|
return result;
|
|
3904
4380
|
}
|
|
3905
4381
|
function toV6TransitionValue(value) {
|
|
3906
|
-
if (Array.isArray(value)) return value.map((item) => toV6TransitionValue(item));
|
|
4382
|
+
if (Array.isArray(value)) return buildV6TransitionFunction(value) ?? value.map((item) => toV6TransitionValue(item));
|
|
3907
4383
|
if (!value || typeof value !== "object") return value;
|
|
3908
4384
|
const transition = value;
|
|
3909
4385
|
if (transition.guard || transition.description || transition.input !== void 0) return mapV6MachineConfig(transition);
|
|
@@ -3920,6 +4396,148 @@ function toV6TransitionValue(value) {
|
|
|
3920
4396
|
context
|
|
3921
4397
|
}) ?? mapV6MachineConfig(transition);
|
|
3922
4398
|
}
|
|
4399
|
+
function guardCondition(value) {
|
|
4400
|
+
const expression = inlineExpr(value);
|
|
4401
|
+
if (!expression) return value === void 0 ? { condition: "true" } : null;
|
|
4402
|
+
const arrow = expression.indexOf("=>");
|
|
4403
|
+
if (arrow < 0) return null;
|
|
4404
|
+
const params = expression.slice(0, arrow).trim();
|
|
4405
|
+
const body = expression.slice(arrow + 2).trim();
|
|
4406
|
+
if (body.startsWith("{")) return null;
|
|
4407
|
+
return {
|
|
4408
|
+
condition: body,
|
|
4409
|
+
firstParam: params.startsWith("(") && params.endsWith(")") ? params.slice(1, -1).trim() : params
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4412
|
+
const V6_ARG_BINDINGS = [
|
|
4413
|
+
"context",
|
|
4414
|
+
"event",
|
|
4415
|
+
"actions",
|
|
4416
|
+
"children",
|
|
4417
|
+
"self",
|
|
4418
|
+
"system"
|
|
4419
|
+
];
|
|
4420
|
+
const V6_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
4421
|
+
function inferV6ArgBindings(code) {
|
|
4422
|
+
return V6_ARG_BINDINGS.filter((name) => new RegExp(`\\b${name}\\b`).test(code));
|
|
4423
|
+
}
|
|
4424
|
+
/** Splits a destructuring pattern body on its top-level commas. */
|
|
4425
|
+
function splitV6PatternEntries(body) {
|
|
4426
|
+
const entries = [];
|
|
4427
|
+
let depth = 0;
|
|
4428
|
+
let start = 0;
|
|
4429
|
+
let quote;
|
|
4430
|
+
for (let index = 0; index < body.length; index++) {
|
|
4431
|
+
const char = body[index];
|
|
4432
|
+
if (quote) {
|
|
4433
|
+
if (char === "\\") index++;
|
|
4434
|
+
else if (char === quote) quote = void 0;
|
|
4435
|
+
continue;
|
|
4436
|
+
}
|
|
4437
|
+
if (char === "\"" || char === "'" || char === "`") quote = char;
|
|
4438
|
+
else if (char === "{" || char === "[" || char === "(") depth++;
|
|
4439
|
+
else if (char === "}" || char === "]" || char === ")") {
|
|
4440
|
+
depth--;
|
|
4441
|
+
if (depth < 0) return void 0;
|
|
4442
|
+
} else if (char === "," && depth === 0) {
|
|
4443
|
+
entries.push(body.slice(start, index));
|
|
4444
|
+
start = index + 1;
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
if (depth !== 0 || quote) return void 0;
|
|
4448
|
+
entries.push(body.slice(start));
|
|
4449
|
+
return entries.map((entry) => entry.trim()).filter(Boolean);
|
|
4450
|
+
}
|
|
4451
|
+
/** Local name a destructuring entry binds, or `undefined` if not a plain one. */
|
|
4452
|
+
function getV6PatternBinding(entry) {
|
|
4453
|
+
const colon = entry.indexOf(":");
|
|
4454
|
+
const name = (colon < 0 ? entry : entry.slice(colon + 1)).split("=")[0].trim();
|
|
4455
|
+
return V6_IDENTIFIER.test(name) ? name : void 0;
|
|
4456
|
+
}
|
|
4457
|
+
/**
|
|
4458
|
+
* Unions the bindings referenced by generated code into the parameter authored
|
|
4459
|
+
* on a guard, so a collapsed transition function never references unbound
|
|
4460
|
+
* variables. Returns `undefined` when the authored parameter cannot be
|
|
4461
|
+
* extended safely, in which case the transition array is kept as-is.
|
|
4462
|
+
*/
|
|
4463
|
+
function mergeV6FirstParam(authoredFirstParam, inferred) {
|
|
4464
|
+
if (!authoredFirstParam) return {
|
|
4465
|
+
firstParam: inferred.length ? `{ ${inferred.join(", ")} }` : "_",
|
|
4466
|
+
prelude: []
|
|
4467
|
+
};
|
|
4468
|
+
if (inferred.length === 0) return {
|
|
4469
|
+
firstParam: authoredFirstParam,
|
|
4470
|
+
prelude: []
|
|
4471
|
+
};
|
|
4472
|
+
if (V6_IDENTIFIER.test(authoredFirstParam)) {
|
|
4473
|
+
if (inferred.includes(authoredFirstParam)) return void 0;
|
|
4474
|
+
return {
|
|
4475
|
+
firstParam: authoredFirstParam,
|
|
4476
|
+
prelude: [`const { ${inferred.join(", ")} } = ${authoredFirstParam};`]
|
|
4477
|
+
};
|
|
4478
|
+
}
|
|
4479
|
+
if (!authoredFirstParam.startsWith("{") || !authoredFirstParam.endsWith("}")) return;
|
|
4480
|
+
const entries = splitV6PatternEntries(authoredFirstParam.slice(1, -1));
|
|
4481
|
+
if (!entries) return void 0;
|
|
4482
|
+
const bound = new Set(entries.map(getV6PatternBinding).filter((name) => name !== void 0));
|
|
4483
|
+
const missing = inferred.filter((name) => !bound.has(name));
|
|
4484
|
+
if (missing.length === 0) return {
|
|
4485
|
+
firstParam: authoredFirstParam,
|
|
4486
|
+
prelude: []
|
|
4487
|
+
};
|
|
4488
|
+
const restIndex = entries.findIndex((entry) => entry.startsWith("..."));
|
|
4489
|
+
return {
|
|
4490
|
+
firstParam: `{ ${(restIndex < 0 ? [...entries, ...missing] : [
|
|
4491
|
+
...entries.slice(0, restIndex),
|
|
4492
|
+
...missing,
|
|
4493
|
+
...entries.slice(restIndex)
|
|
4494
|
+
]).join(", ")} }`,
|
|
4495
|
+
prelude: []
|
|
4496
|
+
};
|
|
4497
|
+
}
|
|
4498
|
+
function buildV6TransitionFunction(transitions) {
|
|
4499
|
+
const branches = [];
|
|
4500
|
+
let authoredFirstParam;
|
|
4501
|
+
for (const item of transitions) {
|
|
4502
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return;
|
|
4503
|
+
const transition = item;
|
|
4504
|
+
if (transition.description !== void 0 || transition.input !== void 0 || transition.matches !== void 0) return;
|
|
4505
|
+
const guard = guardCondition(transition.guard);
|
|
4506
|
+
if (!guard) return;
|
|
4507
|
+
if (guard.firstParam) {
|
|
4508
|
+
if (authoredFirstParam && authoredFirstParam !== guard.firstParam) return;
|
|
4509
|
+
authoredFirstParam = guard.firstParam;
|
|
4510
|
+
}
|
|
4511
|
+
const actionValue = transition.actions;
|
|
4512
|
+
const effects = (Array.isArray(actionValue) ? actionValue : actionValue === void 0 ? [] : [actionValue]).map(actionToV6Effect);
|
|
4513
|
+
if (effects.some((effect) => !effect)) return;
|
|
4514
|
+
const rendered = renderV6Effects(effects.filter((effect) => Boolean(effect)), transition.context === void 0 ? void 0 : serializeJS(unwrapTemplateExpressions(transition.context)));
|
|
4515
|
+
const returnValue = buildV6TransitionReturnValue({
|
|
4516
|
+
target: typeof transition.target === "string" ? transition.target : void 0,
|
|
4517
|
+
reenter: transition.reenter === true,
|
|
4518
|
+
meta: transition.meta
|
|
4519
|
+
}, rendered.contextValue);
|
|
4520
|
+
if (!returnValue) return;
|
|
4521
|
+
const body = [...rendered.statements.map(formatV6Statement), `return ${returnValue};`];
|
|
4522
|
+
if (body.length === 0) return;
|
|
4523
|
+
branches.push({
|
|
4524
|
+
condition: guard.condition,
|
|
4525
|
+
body
|
|
4526
|
+
});
|
|
4527
|
+
}
|
|
4528
|
+
if (branches.length === 0) return;
|
|
4529
|
+
const generated = branches.flatMap((branch) => branch.body).join("\n");
|
|
4530
|
+
const merged = mergeV6FirstParam(authoredFirstParam, inferV6ArgBindings(generated));
|
|
4531
|
+
if (!merged) return;
|
|
4532
|
+
const lines = merged.prelude.map((statement) => ` ${statement}`);
|
|
4533
|
+
for (const branch of branches) if (branch.condition === "true") lines.push(...branch.body.map((line) => ` ${line}`));
|
|
4534
|
+
else {
|
|
4535
|
+
lines.push(` if (${branch.condition}) {`);
|
|
4536
|
+
lines.push(...branch.body.map((line) => ` ${line}`));
|
|
4537
|
+
lines.push(" }");
|
|
4538
|
+
}
|
|
4539
|
+
return raw(`(${merged.firstParam}, enq) => {\n${lines.join("\n")}\n}`);
|
|
4540
|
+
}
|
|
3923
4541
|
function toV6ActionField(actions) {
|
|
3924
4542
|
if (actions.length === 1) {
|
|
3925
4543
|
const expr = inlineExpr(actions[0]);
|
|
@@ -3930,16 +4548,33 @@ function toV6ActionField(actions) {
|
|
|
3930
4548
|
function buildV6ActionFunction(actions, transition) {
|
|
3931
4549
|
const effects = actions.map(actionToV6Effect);
|
|
3932
4550
|
if (effects.some((effect) => !effect)) return void 0;
|
|
3933
|
-
const
|
|
3934
|
-
|
|
3935
|
-
|
|
4551
|
+
const explicitContext = transition?.context === void 0 ? void 0 : serializeJS(unwrapTemplateExpressions(transition.context));
|
|
4552
|
+
const rendered = renderV6Effects(effects.filter((effect) => Boolean(effect)), explicitContext);
|
|
4553
|
+
const statements = rendered.statements;
|
|
4554
|
+
let returnValue = rendered.contextValue ? `{ context: ${rendered.contextValue} }` : void 0;
|
|
4555
|
+
if (transition) returnValue = buildV6TransitionReturnValue(transition, rendered.contextValue);
|
|
4556
|
+
if (statements.length === 0 && !returnValue) return void 0;
|
|
4557
|
+
const bindings = inferV6ArgBindings([...statements, returnValue ?? ""].join("\n"));
|
|
4558
|
+
return raw(`(${bindings.length ? `{ ${bindings.join(", ")} }` : "_"}, enq) => {\n${[...statements.map((statement) => ` ${formatV6Statement(statement)}`), ...returnValue ? [` return ${returnValue};`] : []].join("\n")}\n}`);
|
|
4559
|
+
}
|
|
4560
|
+
function formatV6Statement(statement) {
|
|
4561
|
+
return statement === "{" || statement === "}" || statement.endsWith(";") ? statement : `${statement};`;
|
|
4562
|
+
}
|
|
4563
|
+
function renderV6Effects(effects, finalContext) {
|
|
4564
|
+
if (!(finalContext !== void 0 || effects.some((effect) => effect.contextValue))) return { statements: effects.flatMap((effect) => effect.statements ?? []) };
|
|
4565
|
+
const statements = ["let nextContext = context"];
|
|
4566
|
+
const inCurrentContext = (statement) => {
|
|
4567
|
+
statements.push("{", " const context = nextContext", ` ${statement}`, "}");
|
|
4568
|
+
};
|
|
3936
4569
|
for (const effect of effects) {
|
|
3937
|
-
|
|
3938
|
-
contextValue = effect
|
|
4570
|
+
for (const statement of effect.statements ?? []) inCurrentContext(statement);
|
|
4571
|
+
if (effect.contextValue) inCurrentContext(`nextContext = { ...nextContext, ...(${effect.contextValue}) }`);
|
|
3939
4572
|
}
|
|
3940
|
-
if (
|
|
3941
|
-
|
|
3942
|
-
|
|
4573
|
+
if (finalContext !== void 0) inCurrentContext(`nextContext = { ...nextContext, ...(${finalContext}) }`);
|
|
4574
|
+
return {
|
|
4575
|
+
statements,
|
|
4576
|
+
contextValue: "nextContext"
|
|
4577
|
+
};
|
|
3943
4578
|
}
|
|
3944
4579
|
function unwrapTemplateExpressions(value) {
|
|
3945
4580
|
if (typeof value === "string") {
|
|
@@ -3987,6 +4622,8 @@ function inlineExpr(value) {
|
|
|
3987
4622
|
function actionToV6Effect(action) {
|
|
3988
4623
|
const expr = inlineExpr(action);
|
|
3989
4624
|
if (expr) {
|
|
4625
|
+
const assignment = getV6AssignmentContextValue(expr);
|
|
4626
|
+
if (assignment) return { contextValue: assignment };
|
|
3990
4627
|
if (expr.startsWith("enq(") || expr.startsWith("enq.")) return { statements: [expr] };
|
|
3991
4628
|
const builtIn = expr.match(/^(raise|emit|sendTo|cancel|log|spawnChild|stopChild)\(([\s\S]*)\)$/);
|
|
3992
4629
|
if (builtIn) {
|
|
@@ -4016,45 +4653,127 @@ function actionToV6Effect(action) {
|
|
|
4016
4653
|
return { statements: [`enq.spawn(${serializeJS(params.src)}${options})`] };
|
|
4017
4654
|
}
|
|
4018
4655
|
if (type === "xstate.stopChild") return { statements: [`enq.stop(${serializeJS(params.actorRef)})`] };
|
|
4019
|
-
if (type === "xstate.assign") {
|
|
4020
|
-
|
|
4021
|
-
return {
|
|
4022
|
-
contextValue,
|
|
4023
|
-
returnValue: `{ context: ${contextValue} }`
|
|
4024
|
-
};
|
|
4025
|
-
}
|
|
4656
|
+
if (type === "xstate.assign") return { contextValue: serializeJS(params.assignment ?? params) };
|
|
4657
|
+
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)}` : ""})`] };
|
|
4026
4658
|
return null;
|
|
4027
4659
|
}
|
|
4660
|
+
function getV6AssignmentArgs(code, includeAll = false) {
|
|
4661
|
+
const entries = [
|
|
4662
|
+
"context",
|
|
4663
|
+
"event",
|
|
4664
|
+
"self",
|
|
4665
|
+
"children",
|
|
4666
|
+
"system"
|
|
4667
|
+
].filter((name) => includeAll || new RegExp(`\\b${name}\\b`).test(code));
|
|
4668
|
+
if (includeAll || /\bspawn\b/.test(code)) entries.push("spawn: enq.spawn");
|
|
4669
|
+
return `{ ${entries.join(", ")} }`;
|
|
4670
|
+
}
|
|
4671
|
+
function getV6AssignmentContextValue(code) {
|
|
4672
|
+
const parsed = parseSingleExpression(code);
|
|
4673
|
+
const expression = parsed?.expression;
|
|
4674
|
+
if (!expression || !ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "assign" || expression.arguments.length !== 1) return;
|
|
4675
|
+
const [assignment] = expression.arguments;
|
|
4676
|
+
if (!assignment) return;
|
|
4677
|
+
if (ts.isArrowFunction(assignment) || ts.isFunctionExpression(assignment)) {
|
|
4678
|
+
const source = assignment.getText(parsed.source);
|
|
4679
|
+
return `(${source})(${getV6AssignmentArgs(source)})`;
|
|
4680
|
+
}
|
|
4681
|
+
if (!ts.isObjectLiteralExpression(assignment)) return getDynamicV6AssignmentContextValue(assignment.getText(parsed.source));
|
|
4682
|
+
const properties = [];
|
|
4683
|
+
for (const property of assignment.properties) {
|
|
4684
|
+
if (ts.isPropertyAssignment(property)) {
|
|
4685
|
+
const value = property.initializer;
|
|
4686
|
+
const source = value.getText(parsed.source);
|
|
4687
|
+
properties.push(`${property.name.getText(parsed.source)}: ${ts.isArrowFunction(value) || ts.isFunctionExpression(value) ? `(${source})(${getV6AssignmentArgs(source)})` : source}`);
|
|
4688
|
+
continue;
|
|
4689
|
+
}
|
|
4690
|
+
if (ts.isMethodDeclaration(property) && property.body) {
|
|
4691
|
+
const source = property.getText(parsed.source);
|
|
4692
|
+
const params = property.parameters.map((param) => param.getText(parsed.source)).join(", ");
|
|
4693
|
+
properties.push(`${property.name.getText(parsed.source)}: (function (${params}) ${property.body.getText(parsed.source)})(${getV6AssignmentArgs(source)})`);
|
|
4694
|
+
continue;
|
|
4695
|
+
}
|
|
4696
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
4697
|
+
properties.push(property.getText(parsed.source));
|
|
4698
|
+
continue;
|
|
4699
|
+
}
|
|
4700
|
+
return getDynamicV6AssignmentContextValue(assignment.getText(parsed.source));
|
|
4701
|
+
}
|
|
4702
|
+
return `{ ${properties.join(", ")} }`;
|
|
4703
|
+
}
|
|
4704
|
+
function getDynamicV6AssignmentContextValue(assignment) {
|
|
4705
|
+
const args = getV6AssignmentArgs(assignment, true);
|
|
4706
|
+
return `((assignment) => typeof assignment === 'function'
|
|
4707
|
+
? assignment(${args})
|
|
4708
|
+
: Object.fromEntries(Object.entries(assignment).map(([key, value]) => [
|
|
4709
|
+
key,
|
|
4710
|
+
typeof value === 'function' ? value(${args}) : value,
|
|
4711
|
+
])))(${assignment})`;
|
|
4712
|
+
}
|
|
4028
4713
|
function actionOptions(params, consumedKeys) {
|
|
4029
4714
|
const rest = Object.fromEntries(Object.entries(params).filter(([key, value]) => !consumedKeys.includes(key) && value !== void 0));
|
|
4030
4715
|
return Object.keys(rest).length ? `, ${serializeJS(rest)}` : "";
|
|
4031
4716
|
}
|
|
4032
|
-
function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, usesTypes }) {
|
|
4717
|
+
function buildImports({ hasSetup, hasActors, actors, builtInActions, actorSourceImports, implementationImports, usesTypes }) {
|
|
4033
4718
|
const xstateImports = [];
|
|
4034
4719
|
if (hasSetup) xstateImports.push("setup");
|
|
4035
4720
|
else xstateImports.push("createMachine");
|
|
4036
4721
|
for (const name of builtInActions) xstateImports.push(name);
|
|
4037
4722
|
for (const name of actorSourceImports) xstateImports.push(name);
|
|
4723
|
+
for (const name of implementationImports) xstateImports.push(name);
|
|
4038
4724
|
if (usesTypes) xstateImports.push("types");
|
|
4039
4725
|
if (hasActors) {
|
|
4040
4726
|
if (actors.length > 0) xstateImports.push("fromPromise");
|
|
4041
4727
|
}
|
|
4042
4728
|
return `import { ${[...new Set(xstateImports)].join(", ")} } from 'xstate';`;
|
|
4043
4729
|
}
|
|
4730
|
+
const XSTATE_ACTOR_LOGIC_HELPERS = new Set([
|
|
4731
|
+
"createMachine",
|
|
4732
|
+
"createAsyncLogic",
|
|
4733
|
+
"fromPromise",
|
|
4734
|
+
"fromCallback",
|
|
4735
|
+
"fromObservable",
|
|
4736
|
+
"fromEventObservable",
|
|
4737
|
+
"fromTransition"
|
|
4738
|
+
]);
|
|
4739
|
+
const XSTATE_IMPLEMENTATION_HELPERS = new Set([
|
|
4740
|
+
...Object.values(BUILTIN_ACTION_IMPORTS),
|
|
4741
|
+
"enqueueActions",
|
|
4742
|
+
"sendParent",
|
|
4743
|
+
"forwardTo",
|
|
4744
|
+
"stop",
|
|
4745
|
+
"and",
|
|
4746
|
+
"or",
|
|
4747
|
+
"not",
|
|
4748
|
+
"stateIn",
|
|
4749
|
+
...XSTATE_ACTOR_LOGIC_HELPERS
|
|
4750
|
+
]);
|
|
4751
|
+
function getImplementationImports(impls) {
|
|
4752
|
+
const imports = /* @__PURE__ */ new Set();
|
|
4753
|
+
if (!impls) return imports;
|
|
4754
|
+
for (const implementation of [
|
|
4755
|
+
...impls.actions,
|
|
4756
|
+
...impls.guards,
|
|
4757
|
+
...impls.actors,
|
|
4758
|
+
...impls.delays
|
|
4759
|
+
]) {
|
|
4760
|
+
const code = implementation.code?.body;
|
|
4761
|
+
if (!code) continue;
|
|
4762
|
+
const source = ts.createSourceFile("implementation.ts", code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
4763
|
+
function visit(node) {
|
|
4764
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && XSTATE_IMPLEMENTATION_HELPERS.has(node.expression.text)) imports.add(node.expression.text);
|
|
4765
|
+
ts.forEachChild(node, visit);
|
|
4766
|
+
}
|
|
4767
|
+
visit(source);
|
|
4768
|
+
}
|
|
4769
|
+
return imports;
|
|
4770
|
+
}
|
|
4044
4771
|
function getActorSourceImports(graph) {
|
|
4045
4772
|
const imports = /* @__PURE__ */ new Set();
|
|
4046
|
-
const candidates = [
|
|
4047
|
-
"createAsyncLogic",
|
|
4048
|
-
"fromPromise",
|
|
4049
|
-
"fromCallback",
|
|
4050
|
-
"fromObservable",
|
|
4051
|
-
"fromEventObservable",
|
|
4052
|
-
"fromTransition"
|
|
4053
|
-
];
|
|
4054
4773
|
for (const node of graph.nodes) for (const invoke of node.data.invokes ?? []) {
|
|
4055
4774
|
const expression = invoke.srcExpression?.expr;
|
|
4056
4775
|
if (!expression) continue;
|
|
4057
|
-
for (const candidate of
|
|
4776
|
+
for (const candidate of XSTATE_ACTOR_LOGIC_HELPERS) if (new RegExp(`\\b${candidate}\\b`).test(expression)) imports.add(candidate);
|
|
4058
4777
|
}
|
|
4059
4778
|
return imports;
|
|
4060
4779
|
}
|
|
@@ -4141,11 +4860,27 @@ function buildGuardsBlock(guards, options) {
|
|
|
4141
4860
|
function buildActorsBlock(actors, options) {
|
|
4142
4861
|
const block = {};
|
|
4143
4862
|
for (const actor of actors) if (actor.code?.body) {
|
|
4863
|
+
const inlineExpression = getActorLogicExpression(actor.code.body);
|
|
4864
|
+
if (inlineExpression) {
|
|
4865
|
+
block[actor.name] = raw(inlineExpression);
|
|
4866
|
+
continue;
|
|
4867
|
+
}
|
|
4868
|
+
const functionExpression = stripExportDefault(actor.code.body);
|
|
4869
|
+
if (isCompleteFunctionExpression(functionExpression)) {
|
|
4870
|
+
block[actor.name] = raw(`fromPromise(${functionExpression})`);
|
|
4871
|
+
continue;
|
|
4872
|
+
}
|
|
4144
4873
|
const inputType = options.includeTypeSyntax && hasSchemaProperties(actor.inputSchema) ? `: ${jsonSchemaToTSType(actor.inputSchema)}` : "";
|
|
4145
4874
|
block[actor.name] = raw(`fromPromise(async ({ input }${inputType ? `: { input${inputType} }` : ""}) => {\n ${dedent(actor.code.body)}\n})`);
|
|
4146
4875
|
} else block[actor.name] = raw(`fromPromise(async ({ input }) => {\n // TODO: implement ${actor.name}\n})`);
|
|
4147
4876
|
return block;
|
|
4148
4877
|
}
|
|
4878
|
+
function getActorLogicExpression(code) {
|
|
4879
|
+
const parsed = parseSingleExpression(stripExportDefault(code));
|
|
4880
|
+
const expression = parsed?.expression;
|
|
4881
|
+
if (!parsed || !expression || !ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || !XSTATE_ACTOR_LOGIC_HELPERS.has(expression.expression.text)) return;
|
|
4882
|
+
return parsed.candidate;
|
|
4883
|
+
}
|
|
4149
4884
|
function buildDelaysBlock(delays) {
|
|
4150
4885
|
const block = {};
|
|
4151
4886
|
for (const delay of delays) if (delay.code?.body) {
|
|
@@ -4154,6 +4889,11 @@ function buildDelaysBlock(delays) {
|
|
|
4154
4889
|
block[delay.name] = raw(inlineExpression);
|
|
4155
4890
|
continue;
|
|
4156
4891
|
}
|
|
4892
|
+
const constantExpression = getConstantImplementationExpression(delay.code.body);
|
|
4893
|
+
if (constantExpression) {
|
|
4894
|
+
block[delay.name] = raw(constantExpression);
|
|
4895
|
+
continue;
|
|
4896
|
+
}
|
|
4157
4897
|
block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
|
|
4158
4898
|
} else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
|
|
4159
4899
|
return block;
|
|
@@ -4170,17 +4910,37 @@ function buildDelaysBlock(delays) {
|
|
|
4170
4910
|
function getInlineExpression(code) {
|
|
4171
4911
|
const stripped = stripExportDefault(code);
|
|
4172
4912
|
if (stripped !== code.trim()) return stripped;
|
|
4173
|
-
return isCompleteFunctionExpression(stripped) ? stripped : void 0;
|
|
4913
|
+
return isCompleteFunctionExpression(stripped) || isCompleteXStateHelperExpression(stripped) ? stripped : void 0;
|
|
4174
4914
|
}
|
|
4175
|
-
|
|
4176
|
-
function isCompleteFunctionExpression(code) {
|
|
4915
|
+
function parseSingleExpression(code) {
|
|
4177
4916
|
const candidate = code.trim().replace(/;$/, "");
|
|
4178
|
-
const source = ts.createSourceFile("
|
|
4179
|
-
if ((source.parseDiagnostics ?? []).length > 0 || source.statements.length !== 1) return
|
|
4917
|
+
const source = ts.createSourceFile("implementation.ts", `(${candidate})`, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
4918
|
+
if ((source.parseDiagnostics ?? []).length > 0 || source.statements.length !== 1) return;
|
|
4180
4919
|
const [statement] = source.statements;
|
|
4181
|
-
if (!statement || !ts.isExpressionStatement(statement)) return
|
|
4920
|
+
if (!statement || !ts.isExpressionStatement(statement)) return;
|
|
4182
4921
|
let expression = statement.expression;
|
|
4183
4922
|
if (ts.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
4923
|
+
return {
|
|
4924
|
+
candidate,
|
|
4925
|
+
expression,
|
|
4926
|
+
source
|
|
4927
|
+
};
|
|
4928
|
+
}
|
|
4929
|
+
function getConstantImplementationExpression(code) {
|
|
4930
|
+
const parsed = parseSingleExpression(code);
|
|
4931
|
+
if (!parsed) return;
|
|
4932
|
+
const { candidate, expression } = parsed;
|
|
4933
|
+
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;
|
|
4934
|
+
}
|
|
4935
|
+
function isCompleteXStateHelperExpression(code) {
|
|
4936
|
+
const expression = parseSingleExpression(code)?.expression;
|
|
4937
|
+
if (!expression) return false;
|
|
4938
|
+
return ts.isCallExpression(expression) && ts.isIdentifier(expression.expression) && XSTATE_IMPLEMENTATION_HELPERS.has(expression.expression.text);
|
|
4939
|
+
}
|
|
4940
|
+
/** True when `code` is a single function or arrow-function expression. */
|
|
4941
|
+
function isCompleteFunctionExpression(code) {
|
|
4942
|
+
const expression = parseSingleExpression(code)?.expression;
|
|
4943
|
+
if (!expression) return false;
|
|
4184
4944
|
return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
|
|
4185
4945
|
}
|
|
4186
4946
|
const colorSchema = _enum([
|