xstate 5.32.2 → 6.0.0-alpha.10
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 +25 -24
- package/dist/StateMachine-0aa98f54.development.esm.js +746 -0
- package/dist/StateMachine-aef700df.cjs.js +732 -0
- package/dist/StateMachine-d4931336.esm.js +729 -0
- package/dist/StateMachine-da872dde.development.cjs.js +749 -0
- package/dist/declarations/src/State.d.ts +11 -13
- package/dist/declarations/src/StateMachine.d.ts +40 -26
- package/dist/declarations/src/StateNode.d.ts +18 -54
- package/dist/declarations/src/actions.d.ts +14 -9
- package/dist/declarations/src/actors/callback.d.ts +42 -16
- package/dist/declarations/src/actors/index.d.ts +9 -6
- package/dist/declarations/src/actors/listener.d.ts +18 -0
- package/dist/declarations/src/actors/logic.d.ts +105 -0
- package/dist/declarations/src/actors/observable.d.ts +72 -27
- package/dist/declarations/src/actors/promise.d.ts +133 -48
- package/dist/declarations/src/actors/subscription.d.ts +22 -0
- package/dist/declarations/src/createActor.d.ts +33 -34
- package/dist/declarations/src/createMachine.d.ts +38 -7
- package/dist/declarations/src/createMachineFromConfig.d.ts +177 -0
- package/dist/declarations/src/graph/graph.d.ts +6 -4
- package/dist/declarations/src/graph/shortestPaths.d.ts +2 -2
- package/dist/declarations/src/graph/simplePaths.d.ts +2 -2
- package/dist/declarations/src/index.d.ts +13 -9
- package/dist/declarations/src/inspection.d.ts +84 -30
- package/dist/declarations/src/mapState.d.ts +4 -2
- package/dist/declarations/src/schema.types.d.ts +90 -0
- package/dist/declarations/src/serialize.d.ts +50 -0
- package/dist/declarations/src/setup.d.ts +396 -136
- package/dist/declarations/src/spawn.d.ts +7 -32
- package/dist/declarations/src/stateUtils.d.ts +22 -19
- package/dist/declarations/src/system.d.ts +8 -7
- package/dist/declarations/src/transition.d.ts +8 -5
- package/dist/declarations/src/transitionActions.d.ts +4 -0
- package/dist/declarations/src/types.d.ts +494 -429
- package/dist/declarations/src/types.v6.d.ts +423 -0
- package/dist/declarations/src/utils.d.ts +5 -3
- package/dist/index-219cb621.development.cjs.js +4476 -0
- package/dist/index-2f2fbd9b.development.esm.js +4421 -0
- package/dist/index-559ceab3.cjs.js +4437 -0
- package/dist/index-8828376f.esm.js +4382 -0
- package/dist/xstate-actors.cjs.js +12 -838
- package/dist/xstate-actors.cjs.mjs +10 -5
- package/dist/xstate-actors.development.cjs.js +12 -838
- package/dist/xstate-actors.development.cjs.mjs +10 -5
- package/dist/xstate-actors.development.esm.js +1 -836
- package/dist/xstate-actors.esm.js +1 -836
- package/dist/xstate-actors.umd.min.js +1 -1
- package/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/xstate-graph.cjs.js +18 -29
- package/dist/xstate-graph.development.cjs.js +18 -29
- package/dist/xstate-graph.development.esm.js +15 -26
- package/dist/xstate-graph.esm.js +15 -26
- package/dist/xstate-graph.umd.min.js +1 -1
- package/dist/xstate-graph.umd.min.js.map +1 -1
- package/dist/xstate.cjs.js +1477 -122
- package/dist/xstate.cjs.mjs +19 -22
- package/dist/xstate.development.cjs.js +1477 -122
- package/dist/xstate.development.cjs.mjs +19 -22
- package/dist/xstate.development.esm.js +1442 -86
- package/dist/xstate.esm.js +1442 -86
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/package.json +3 -47
- package/dist/StateMachine-23c204bb.development.esm.js +0 -566
- package/dist/StateMachine-67a0f463.development.cjs.js +0 -569
- package/dist/StateMachine-94d215e3.cjs.js +0 -563
- package/dist/StateMachine-d1d80308.esm.js +0 -560
- package/dist/assign-43b1b558.development.esm.js +0 -133
- package/dist/assign-54b312bc.esm.js +0 -127
- package/dist/assign-b5bc78f7.cjs.js +0 -129
- package/dist/assign-f8f66278.development.cjs.js +0 -135
- package/dist/declarations/src/actions/assign.d.ts +0 -45
- package/dist/declarations/src/actions/cancel.d.ts +0 -39
- package/dist/declarations/src/actions/emit.d.ts +0 -44
- package/dist/declarations/src/actions/enqueueActions.d.ts +0 -57
- package/dist/declarations/src/actions/log.d.ts +0 -16
- package/dist/declarations/src/actions/raise.d.ts +0 -21
- package/dist/declarations/src/actions/send.d.ts +0 -42
- package/dist/declarations/src/actions/spawnChild.d.ts +0 -34
- package/dist/declarations/src/actions/stopChild.d.ts +0 -19
- package/dist/declarations/src/actors/transition.d.ts +0 -143
- package/dist/declarations/src/dev/index.d.ts +0 -14
- package/dist/declarations/src/guards.d.ts +0 -128
- package/dist/log-9b02c355.esm.js +0 -401
- package/dist/log-c94995c7.cjs.js +0 -409
- package/dist/log-d9f3f459.development.cjs.js +0 -437
- package/dist/log-db444cad.development.esm.js +0 -429
- package/dist/raise-235108c6.esm.js +0 -2762
- package/dist/raise-45f11c00.development.esm.js +0 -2824
- package/dist/raise-c445379d.cjs.js +0 -2817
- package/dist/raise-eca73993.development.cjs.js +0 -2879
- package/dist/xstate-actions.cjs.d.mts +0 -2
- package/dist/xstate-actions.cjs.d.ts +0 -2
- package/dist/xstate-actions.cjs.js +0 -23
- package/dist/xstate-actions.cjs.mjs +0 -14
- package/dist/xstate-actions.development.cjs.js +0 -23
- package/dist/xstate-actions.development.cjs.mjs +0 -14
- package/dist/xstate-actions.development.esm.js +0 -4
- package/dist/xstate-actions.esm.js +0 -4
- package/dist/xstate-actions.umd.min.js +0 -2
- package/dist/xstate-actions.umd.min.js.map +0 -1
- package/dist/xstate-dev.cjs.d.mts +0 -2
- package/dist/xstate-dev.cjs.d.ts +0 -2
- package/dist/xstate-dev.cjs.js +0 -48
- package/dist/xstate-dev.cjs.mjs +0 -5
- package/dist/xstate-dev.development.cjs.js +0 -51
- package/dist/xstate-dev.development.cjs.mjs +0 -5
- package/dist/xstate-dev.development.esm.js +0 -45
- package/dist/xstate-dev.esm.js +0 -42
- package/dist/xstate-dev.umd.min.js +0 -2
- package/dist/xstate-dev.umd.min.js.map +0 -1
- package/dist/xstate-guards.cjs.d.mts +0 -2
- package/dist/xstate-guards.cjs.d.ts +0 -2
- package/dist/xstate-guards.cjs.js +0 -14
- package/dist/xstate-guards.cjs.mjs +0 -7
- package/dist/xstate-guards.development.cjs.js +0 -14
- package/dist/xstate-guards.development.cjs.mjs +0 -7
- package/dist/xstate-guards.development.esm.js +0 -2
- package/dist/xstate-guards.esm.js +0 -2
- package/dist/xstate-guards.umd.min.js +0 -2
- package/dist/xstate-guards.umd.min.js.map +0 -1
package/dist/xstate.cjs.js
CHANGED
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var dist_xstateActors = require('./
|
|
6
|
-
var
|
|
7
|
-
var StateMachine = require('./StateMachine-94d215e3.cjs.js');
|
|
8
|
-
var assign = require('./assign-b5bc78f7.cjs.js');
|
|
9
|
-
var log = require('./log-c94995c7.cjs.js');
|
|
10
|
-
require('./xstate-dev.cjs.js');
|
|
5
|
+
var dist_xstateActors = require('./index-559ceab3.cjs.js');
|
|
6
|
+
var StateMachine = require('./StateMachine-aef700df.cjs.js');
|
|
11
7
|
|
|
12
8
|
/**
|
|
13
9
|
* Asserts that the given event object is of the specified type or types. Throws
|
|
@@ -33,8 +29,8 @@ require('./xstate-dev.cjs.js');
|
|
|
33
29
|
* ```
|
|
34
30
|
*/
|
|
35
31
|
function assertEvent(event, type) {
|
|
36
|
-
const types =
|
|
37
|
-
const matches = types.some(descriptor =>
|
|
32
|
+
const types = dist_xstateActors.toArray(type);
|
|
33
|
+
const matches = types.some(descriptor => dist_xstateActors.matchesEventDescriptor(event.type, descriptor));
|
|
38
34
|
if (!matches) {
|
|
39
35
|
const typesText = types.length === 1 ? `type matching "${types[0]}"` : `one of types matching "${types.join('", "')}"`;
|
|
40
36
|
throw new Error(`Expected event ${JSON.stringify(event)} to have ${typesText}`);
|
|
@@ -83,8 +79,1063 @@ function assertEvent(event, type) {
|
|
|
83
79
|
* @param options DEPRECATED: use `setup({ ... })` or `machine.provide({ ... })`
|
|
84
80
|
* to provide machine implementations instead.
|
|
85
81
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
// Overload 1: With schemas.context — context type inferred from schema
|
|
83
|
+
|
|
84
|
+
// Overload 2: Without schemas.context — context type inferred from config.context
|
|
85
|
+
|
|
86
|
+
// Implementation
|
|
87
|
+
function createMachine(config) {
|
|
88
|
+
return new StateMachine.StateMachine(config);
|
|
89
|
+
}
|
|
90
|
+
function createStateConfig(config) {
|
|
91
|
+
return config;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function delayToMs(delay) {
|
|
95
|
+
const parsedDelay = dist_xstateActors.parseDelayToMilliseconds(delay);
|
|
96
|
+
if (parsedDelay !== undefined) return parsedDelay;
|
|
97
|
+
return typeof delay === 'string' ? parseFloat(delay) || 0 : delay;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Isolated executable-content block. Errors in nested actions stop this block
|
|
102
|
+
* but do not propagate to the surrounding action list. Used to model SCXML's
|
|
103
|
+
* separate <onentry>/<onexit> blocks: each is its own block per spec.
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
function isUnserializableMarker(value) {
|
|
107
|
+
return !!value && typeof value === 'object' && '$unserializable' in value && typeof value.$unserializable === 'string';
|
|
108
|
+
}
|
|
109
|
+
function assertNoUnresolvedMarkers(value, path = '$') {
|
|
110
|
+
if (isUnserializableMarker(value)) {
|
|
111
|
+
if (value.$unserializable === 'actor' && path.endsWith('.src')) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Unresolved ${value.$unserializable} at ${path}`);
|
|
115
|
+
}
|
|
116
|
+
if (!value || typeof value !== 'object') {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (Array.isArray(value)) {
|
|
120
|
+
value.forEach((item, index) => assertNoUnresolvedMarkers(item, `${path}[${index}]`));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
for (const key of Object.keys(value)) {
|
|
124
|
+
const child = value[key];
|
|
125
|
+
const isImplementationMarker = path === '$' && (key === 'actions' || key === 'guards' || key === 'actorSources' || key === 'delays' || key === 'schemas');
|
|
126
|
+
if (isImplementationMarker) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
assertNoUnresolvedMarkers(child, `${path}.${key}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function assertRootImplementationMarkers(json, implementations) {
|
|
133
|
+
for (const kind of ['actions', 'guards', 'actorSources', 'delays']) {
|
|
134
|
+
const map = json[kind];
|
|
135
|
+
if (!map) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
for (const key of Object.keys(map)) {
|
|
139
|
+
const value = map[key];
|
|
140
|
+
if (!isUnserializableMarker(value)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (!implementations[kind]?.[key]) {
|
|
144
|
+
throw new Error(`Missing ${kind}.${key}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function extractSerializableDelays(delays) {
|
|
150
|
+
const result = {};
|
|
151
|
+
if (!delays) {
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
for (const key of Object.keys(delays)) {
|
|
155
|
+
const value = delays[key];
|
|
156
|
+
if (typeof value === 'number') {
|
|
157
|
+
result[key] = value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
function mergeImplementations(json, implementations) {
|
|
163
|
+
return {
|
|
164
|
+
actions: implementations.actions ?? {},
|
|
165
|
+
guards: implementations.guards ?? {},
|
|
166
|
+
actorSources: implementations.actorSources ?? {},
|
|
167
|
+
delays: {
|
|
168
|
+
...extractSerializableDelays(json.delays),
|
|
169
|
+
...(implementations.delays ?? {})
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
let _scxmlSessionId = 'session_' + Math.random().toString(36).slice(2);
|
|
174
|
+
let _scxmlMachineName = '';
|
|
175
|
+
|
|
176
|
+
/** Evaluates an SCXML expression with context variables available via `with`. */
|
|
177
|
+
function evaluateExpr(context, expr, event, self) {
|
|
178
|
+
const fnBody = `
|
|
179
|
+
with (context) {
|
|
180
|
+
return (${expr});
|
|
181
|
+
}
|
|
182
|
+
`.trim();
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
184
|
+
const fn = new Function('context', '_event', '_sessionid', '_name', '_ioprocessors', 'In', fnBody);
|
|
185
|
+
const In = stateId => {
|
|
186
|
+
if (!self) return false;
|
|
187
|
+
try {
|
|
188
|
+
const snap = self.getSnapshot?.();
|
|
189
|
+
if (snap?._nodes) {
|
|
190
|
+
const sanitized = stateId.replace(/\./g, '$');
|
|
191
|
+
return snap._nodes.some(node => node.id === sanitized || node.id.endsWith('.' + sanitized));
|
|
192
|
+
}
|
|
193
|
+
} catch {
|
|
194
|
+
// ignore
|
|
195
|
+
}
|
|
196
|
+
return false;
|
|
197
|
+
};
|
|
198
|
+
const SCXML_ORIGIN = '#_scxml_session';
|
|
199
|
+
const SCXML_ORIGIN_TYPE = 'http://www.w3.org/TR/scxml/#SCXMLEventProcessor';
|
|
200
|
+
const isExternal = event && event._scxmlExternal;
|
|
201
|
+
const isInitEvent = event && event.type === '@xstate.init';
|
|
202
|
+
// Per SCXML spec, _event has these fields. Fields that don't apply to a
|
|
203
|
+
// particular event are present with value `undefined` (so `'name' in _event`
|
|
204
|
+
// is true but `typeof _event.name === 'undefined'` for unset fields).
|
|
205
|
+
// For xstate.done.* events, _event.data is the `output` payload (matches
|
|
206
|
+
// SCXML's done event semantics where data is the donedata).
|
|
207
|
+
const isDoneEvent = event && typeof event.type === 'string' && event.type.startsWith('xstate.done.');
|
|
208
|
+
const explicitType = event && event._scxmlEventType;
|
|
209
|
+
const scxmlEvent = event && !isInitEvent ? {
|
|
210
|
+
name: event.type,
|
|
211
|
+
type: explicitType || (isExternal ? 'external' : 'internal'),
|
|
212
|
+
sendid: event._scxmlSendId,
|
|
213
|
+
origin: isExternal ? SCXML_ORIGIN : undefined,
|
|
214
|
+
origintype: isExternal ? SCXML_ORIGIN_TYPE : undefined,
|
|
215
|
+
invokeid: event._scxmlInvokeId,
|
|
216
|
+
data: isDoneEvent ? event.output : event._scxmlEventData !== undefined ? event._scxmlEventData : event
|
|
217
|
+
} : undefined;
|
|
218
|
+
const result = fn(context, scxmlEvent, _scxmlSessionId, _scxmlMachineName, {
|
|
219
|
+
scxml: {
|
|
220
|
+
location: `#_scxml_${_scxmlSessionId}`
|
|
221
|
+
}
|
|
222
|
+
}, In);
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Executes an SCXML script block and returns updated context values. */
|
|
227
|
+
function executeScript(context, code) {
|
|
228
|
+
// Create a proxy to track which properties are modified
|
|
229
|
+
const updates = {};
|
|
230
|
+
const contextKeys = Object.keys(context);
|
|
231
|
+
|
|
232
|
+
// Build variable declarations and reassignment capture
|
|
233
|
+
const varDeclarations = contextKeys.map(k => `let ${k} = context.${k};`).join('\n');
|
|
234
|
+
const captureUpdates = contextKeys.map(k => `updates.${k} = ${k};`).join('\n');
|
|
235
|
+
const fnBody = `
|
|
236
|
+
${varDeclarations}
|
|
237
|
+
${code}
|
|
238
|
+
${captureUpdates}
|
|
239
|
+
return updates;
|
|
240
|
+
`;
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
242
|
+
const fn = new Function('context', 'updates', fnBody);
|
|
243
|
+
return fn(context, updates);
|
|
244
|
+
}
|
|
245
|
+
function createMachineFromConfig(json, implementations = {}) {
|
|
246
|
+
assertRootImplementationMarkers(json, implementations);
|
|
247
|
+
assertNoUnresolvedMarkers(json);
|
|
248
|
+
const resolvedImplementations = mergeImplementations(json, implementations);
|
|
249
|
+
|
|
250
|
+
// Pending transition actions: set by .to functions, consumed by entry functions.
|
|
251
|
+
// This bridges SCXML's exit→transition→entry action ordering with XState's
|
|
252
|
+
// .to function receiving pre-exit context.
|
|
253
|
+
// Map keyed by target state ID so parallel transitions don't overwrite each other.
|
|
254
|
+
const pendingTransitionActionsMap = {};
|
|
255
|
+
|
|
256
|
+
// Ordered queue of ALL transition actions (targeted + targetless) for parallel
|
|
257
|
+
// context sharing. In SCXML, all transition actions execute sequentially in
|
|
258
|
+
// document order with a shared evolving data model.
|
|
259
|
+
const allTransitionActions = [];
|
|
260
|
+
// Pre-transition context saved when a targetless .to executes. Used by entry
|
|
261
|
+
// functions to re-execute all transition actions from scratch when parallel
|
|
262
|
+
// targetless transitions coexist with targeted transitions.
|
|
263
|
+
let contextBeforeTargetless = null;
|
|
264
|
+
// Platform errors collected during transition selection (e.g., failing
|
|
265
|
+
// <transition cond>). Drained by the next state's entry into the internal
|
|
266
|
+
// event queue so they're processed before any external events.
|
|
267
|
+
const pendingPlatformErrors = [];
|
|
268
|
+
function getMissingGuardMessage(type, guards) {
|
|
269
|
+
return `Guard '${type}' is not implemented in machine '${json.id ?? '(machine)'}'. Available guards: ${Object.keys(guards).map(key => `'${key}'`).join(', ') || '(none)'}.`;
|
|
270
|
+
}
|
|
271
|
+
function resolveGuardConfig(guard) {
|
|
272
|
+
if (!guard) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
return args => {
|
|
276
|
+
const guardImpl = args.guards?.[guard.type];
|
|
277
|
+
if (!guardImpl) {
|
|
278
|
+
throw new Error(getMissingGuardMessage(guard.type, args.guards ?? {}));
|
|
279
|
+
}
|
|
280
|
+
return guardImpl(args, guard.params);
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function resolveRouteConfig(route) {
|
|
284
|
+
if (!route || typeof route === 'function') {
|
|
285
|
+
return route;
|
|
286
|
+
}
|
|
287
|
+
const {
|
|
288
|
+
guard,
|
|
289
|
+
...routeConfig
|
|
290
|
+
} = route;
|
|
291
|
+
if (!guard) {
|
|
292
|
+
return routeConfig;
|
|
293
|
+
}
|
|
294
|
+
const resolvedGuard = resolveGuardConfig({
|
|
295
|
+
type: guard
|
|
296
|
+
});
|
|
297
|
+
return args => resolvedGuard(args) ? routeConfig : undefined;
|
|
298
|
+
}
|
|
299
|
+
function iterNode(node, nodeKey) {
|
|
300
|
+
const originalEntryActions = node.entry;
|
|
301
|
+
const stateId = node.id || nodeKey;
|
|
302
|
+
|
|
303
|
+
// Wrap entry to first execute any pending transition actions, then normal entry.
|
|
304
|
+
// This ensures SCXML execution order: exit → transition_actions → entry_actions
|
|
305
|
+
// because pending transition actions are set by .to (before exit) but executed
|
|
306
|
+
// in entry (after exit), thus seeing post-exit context.
|
|
307
|
+
const entryFn = (x, enq) => {
|
|
308
|
+
// Drain any platform errors queued during transition selection (e.g.,
|
|
309
|
+
// failing <transition cond="..."> evaluations). These must be raised
|
|
310
|
+
// internally so they're processed before subsequent external events.
|
|
311
|
+
while (pendingPlatformErrors.length) {
|
|
312
|
+
const err = pendingPlatformErrors.shift();
|
|
313
|
+
enq.raise({
|
|
314
|
+
type: 'error.execution',
|
|
315
|
+
_scxmlEventType: 'platform',
|
|
316
|
+
_scxmlEventData: err
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
let context;
|
|
320
|
+
|
|
321
|
+
// If targetless transitions were interleaved with targeted transitions
|
|
322
|
+
// (parallel state), re-execute ALL transition actions from the original
|
|
323
|
+
// pre-transition context. This overrides any .to-produced context with
|
|
324
|
+
// the correct SCXML document-order sequential execution.
|
|
325
|
+
// Only trigger when BOTH targeted (pending in map) and targetless fired
|
|
326
|
+
// in the same microstep — prevents stale data from previous events.
|
|
327
|
+
if (contextBeforeTargetless && allTransitionActions.length > 0 && Object.keys(pendingTransitionActionsMap).length > 0) {
|
|
328
|
+
let ctx = contextBeforeTargetless;
|
|
329
|
+
for (const actions of allTransitionActions) {
|
|
330
|
+
const mergedX = {
|
|
331
|
+
...x,
|
|
332
|
+
context: ctx
|
|
333
|
+
};
|
|
334
|
+
const result = executeActions(actions, mergedX, enq);
|
|
335
|
+
if (result.context) {
|
|
336
|
+
ctx = result.context;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
allTransitionActions.length = 0;
|
|
340
|
+
contextBeforeTargetless = null;
|
|
341
|
+
// Clear per-target map since we re-processed everything
|
|
342
|
+
for (const key of Object.keys(pendingTransitionActionsMap)) {
|
|
343
|
+
delete pendingTransitionActionsMap[key];
|
|
344
|
+
}
|
|
345
|
+
context = ctx;
|
|
346
|
+
} else {
|
|
347
|
+
// Normal path: consume pending transition actions for THIS state.
|
|
348
|
+
// In parallel states, each target gets its own pending actions.
|
|
349
|
+
const transActions = stateId ? pendingTransitionActionsMap[stateId] : undefined;
|
|
350
|
+
if (transActions) {
|
|
351
|
+
delete pendingTransitionActionsMap[stateId];
|
|
352
|
+
const result = executeActions(transActions, x, enq);
|
|
353
|
+
if (result.context) {
|
|
354
|
+
context = result.context;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Clear stale targetless data from previous microsteps
|
|
358
|
+
contextBeforeTargetless = null;
|
|
359
|
+
allTransitionActions.length = 0;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Execute normal entry actions
|
|
363
|
+
if (originalEntryActions?.length) {
|
|
364
|
+
const mergedX = context ? {
|
|
365
|
+
...x,
|
|
366
|
+
context
|
|
367
|
+
} : x;
|
|
368
|
+
const result = executeActions(originalEntryActions, mergedX, enq);
|
|
369
|
+
if (result.context) {
|
|
370
|
+
context = result.context;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
context
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
const nodeConfig = {
|
|
378
|
+
id: node.id,
|
|
379
|
+
initial: node.initial,
|
|
380
|
+
type: node.type,
|
|
381
|
+
history: node.history,
|
|
382
|
+
target: node.target,
|
|
383
|
+
description: node.description,
|
|
384
|
+
tags: node.tags,
|
|
385
|
+
input: node.input,
|
|
386
|
+
timeout: node.timeout,
|
|
387
|
+
states: node.states ? Object.entries(node.states).reduce((acc, [key, value]) => {
|
|
388
|
+
acc[key] = iterNode(value, key);
|
|
389
|
+
return acc;
|
|
390
|
+
}, {}) : undefined,
|
|
391
|
+
on: node.on ? Object.entries(node.on).reduce((acc, [key, value]) => {
|
|
392
|
+
acc[key] = getTransitionConfig(value);
|
|
393
|
+
return acc;
|
|
394
|
+
}, {}) : undefined,
|
|
395
|
+
always: node.always ? getTransitionConfig(node.always) : undefined,
|
|
396
|
+
choice: node.choice ? getTransitionConfig(node.choice) : undefined,
|
|
397
|
+
route: resolveRouteConfig(node.route),
|
|
398
|
+
after: node.after ? Object.entries(node.after).reduce((acc, [key, value]) => {
|
|
399
|
+
acc[key] = getTransitionConfig(value);
|
|
400
|
+
return acc;
|
|
401
|
+
}, {}) : undefined,
|
|
402
|
+
onTimeout: node.onTimeout ? getTransitionConfig(node.onTimeout) : undefined,
|
|
403
|
+
entry: entryFn,
|
|
404
|
+
exit: node.exit ? iterActions(node.exit) : undefined,
|
|
405
|
+
invoke: node.invoke ? iterInvokeConfigs(node.invoke) : undefined,
|
|
406
|
+
meta: node.meta,
|
|
407
|
+
output: node._scxmlDonedata ? makeDonedataOutput(node._scxmlDonedata) : node.output
|
|
408
|
+
};
|
|
409
|
+
return nodeConfig;
|
|
410
|
+
}
|
|
411
|
+
function makeDonedataOutput(donedata) {
|
|
412
|
+
return ({
|
|
413
|
+
context,
|
|
414
|
+
event,
|
|
415
|
+
self
|
|
416
|
+
}) => {
|
|
417
|
+
try {
|
|
418
|
+
if (donedata.params && donedata.params.length) {
|
|
419
|
+
const out = {};
|
|
420
|
+
for (const param of donedata.params) {
|
|
421
|
+
out[param.name] = evaluateExpr(context, param.expr, event, self);
|
|
422
|
+
}
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
if (donedata.contentExpr !== undefined) {
|
|
426
|
+
return evaluateExpr(context, donedata.contentExpr, event, self);
|
|
427
|
+
}
|
|
428
|
+
if (donedata.contentText !== undefined) {
|
|
429
|
+
// Try parsing as a JS expression (number/object/array literals);
|
|
430
|
+
// fall back to the raw string.
|
|
431
|
+
try {
|
|
432
|
+
return evaluateExpr(context, donedata.contentText, event, self);
|
|
433
|
+
} catch {
|
|
434
|
+
return donedata.contentText;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
} catch (err) {
|
|
438
|
+
// Per SCXML, donedata expression errors raise error.execution and
|
|
439
|
+
// result in undefined event.data. Queue for the next entry to drain.
|
|
440
|
+
const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
|
|
441
|
+
pendingPlatformErrors.push({
|
|
442
|
+
tagname: 'donedata',
|
|
443
|
+
message,
|
|
444
|
+
line: NaN,
|
|
445
|
+
column: NaN,
|
|
446
|
+
reason: message
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return undefined;
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function iterInvokeConfigs(invokes) {
|
|
453
|
+
const invokeArray = Array.isArray(invokes) ? invokes : [invokes];
|
|
454
|
+
return invokeArray.map(inv => {
|
|
455
|
+
const extInv = inv;
|
|
456
|
+
// Create child machine from nested SCXML JSON
|
|
457
|
+
let src;
|
|
458
|
+
if (extInv._nestedMachineJSON) {
|
|
459
|
+
src = createMachineFromConfig(extInv._nestedMachineJSON, resolvedImplementations);
|
|
460
|
+
} else if (isUnserializableMarker(inv.src)) {
|
|
461
|
+
src = inv.src.id ? resolvedImplementations.actorSources[inv.src.id] : undefined;
|
|
462
|
+
if (!src) {
|
|
463
|
+
throw new Error(`Missing actorSources.${inv.src.id ?? ''}`);
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
src = inv.src;
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
src,
|
|
470
|
+
id: inv.id,
|
|
471
|
+
registryKey: inv.registryKey,
|
|
472
|
+
input: inv.input,
|
|
473
|
+
onDone: inv.onDone ? getTransitionConfig(inv.onDone) : undefined,
|
|
474
|
+
onError: inv.onError ? getTransitionConfig(inv.onError) : undefined,
|
|
475
|
+
onSnapshot: inv.onSnapshot ? getTransitionConfig(inv.onSnapshot) : undefined,
|
|
476
|
+
timeout: inv.timeout,
|
|
477
|
+
onTimeout: inv.onTimeout ? getTransitionConfig(inv.onTimeout) : undefined
|
|
478
|
+
};
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Raise an SCXML error.execution platform event onto the internal queue. Per
|
|
484
|
+
* spec, error.execution is type='platform' and _event.data contains error
|
|
485
|
+
* info. The surrounding block of executable content stops.
|
|
486
|
+
*/
|
|
487
|
+
function raiseErrorExecution(state, tagname, err) {
|
|
488
|
+
const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
|
|
489
|
+
state.enq.raise({
|
|
490
|
+
type: 'error.execution',
|
|
491
|
+
_scxmlEventType: 'platform',
|
|
492
|
+
_scxmlEventData: {
|
|
493
|
+
tagname,
|
|
494
|
+
message,
|
|
495
|
+
line: NaN,
|
|
496
|
+
column: NaN,
|
|
497
|
+
reason: message
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
state.errored = true;
|
|
501
|
+
}
|
|
502
|
+
/** Execute an array of SCXML action JSON descriptors with context and enqueue. */
|
|
503
|
+
function executeActions(actions, x, enq, parentState) {
|
|
504
|
+
const state = parentState ?? {
|
|
505
|
+
enq,
|
|
506
|
+
errored: false
|
|
507
|
+
};
|
|
508
|
+
let context;
|
|
509
|
+
for (const action of actions) {
|
|
510
|
+
if (state.errored) break;
|
|
511
|
+
if (isBuiltInActionJSON(action)) {
|
|
512
|
+
switch (action.type) {
|
|
513
|
+
case '@xstate.raise':
|
|
514
|
+
{
|
|
515
|
+
// Tag as external if it has a delay (from <send>, not <raise>).
|
|
516
|
+
// Attach _scxmlSendId so _event.sendid can be read in expressions.
|
|
517
|
+
const isExternal = action.delay !== undefined;
|
|
518
|
+
const event = isExternal || action.id !== undefined ? {
|
|
519
|
+
...action.event,
|
|
520
|
+
...(isExternal ? {
|
|
521
|
+
_scxmlExternal: true
|
|
522
|
+
} : {}),
|
|
523
|
+
...(action.id !== undefined ? {
|
|
524
|
+
_scxmlSendId: action.id
|
|
525
|
+
} : {})
|
|
526
|
+
} : action.event;
|
|
527
|
+
enq.raise(event, {
|
|
528
|
+
id: action.id,
|
|
529
|
+
delay: action.delay
|
|
530
|
+
});
|
|
531
|
+
break;
|
|
532
|
+
}
|
|
533
|
+
case '@xstate.cancel':
|
|
534
|
+
enq.cancel(action.id);
|
|
535
|
+
break;
|
|
536
|
+
case '@xstate.log':
|
|
537
|
+
enq.log(...action.args);
|
|
538
|
+
break;
|
|
539
|
+
case '@xstate.emit':
|
|
540
|
+
enq.emit(action.event);
|
|
541
|
+
break;
|
|
542
|
+
case '@xstate.assign':
|
|
543
|
+
context ??= {};
|
|
544
|
+
Object.assign(context, action.context);
|
|
545
|
+
break;
|
|
546
|
+
default:
|
|
547
|
+
throw new Error(`Unknown built-in action: ${action.type}`);
|
|
548
|
+
}
|
|
549
|
+
} else if (action.type === 'scxml.assign') {
|
|
550
|
+
const scxmlAction = action;
|
|
551
|
+
const mergedContext = {
|
|
552
|
+
...x.context,
|
|
553
|
+
...context
|
|
554
|
+
};
|
|
555
|
+
let value;
|
|
556
|
+
try {
|
|
557
|
+
value = evaluateExpr(mergedContext, scxmlAction.expr, x.event, x.self);
|
|
558
|
+
} catch (err) {
|
|
559
|
+
raiseErrorExecution(state, 'assign', err);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
// Per SCXML, assigning to a location that doesn't exist on the
|
|
563
|
+
// datamodel is an error. Allow setting an own property via context;
|
|
564
|
+
// detect deep paths (a.b.c) which we don't support.
|
|
565
|
+
if (scxmlAction.location.includes('.')) {
|
|
566
|
+
raiseErrorExecution(state, 'assign', new Error(`Invalid assign location: ${scxmlAction.location}`));
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
context ??= {};
|
|
570
|
+
context[scxmlAction.location] = value;
|
|
571
|
+
} else if (action.type === 'scxml.raise') {
|
|
572
|
+
const scxmlAction = action;
|
|
573
|
+
const mergedContext = {
|
|
574
|
+
...x.context,
|
|
575
|
+
...context
|
|
576
|
+
};
|
|
577
|
+
let eventType;
|
|
578
|
+
let eventData;
|
|
579
|
+
let target;
|
|
580
|
+
let delay;
|
|
581
|
+
try {
|
|
582
|
+
eventType = scxmlAction.eventexpr ? evaluateExpr(mergedContext, scxmlAction.eventexpr, x.event, x.self) : scxmlAction.event || 'unknown';
|
|
583
|
+
eventData = {
|
|
584
|
+
type: eventType
|
|
585
|
+
};
|
|
586
|
+
if (scxmlAction.params) {
|
|
587
|
+
for (const param of scxmlAction.params) {
|
|
588
|
+
eventData[param.name] = evaluateExpr(mergedContext, param.expr, x.event, x.self);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
target = scxmlAction.targetexpr ? evaluateExpr(mergedContext, scxmlAction.targetexpr, x.event, x.self) : scxmlAction.target;
|
|
592
|
+
const isInternalTarget = target === '#_internal';
|
|
593
|
+
delay = scxmlAction.delayexpr ? delayToMs(evaluateExpr(mergedContext, scxmlAction.delayexpr, x.event, x.self)) : isInternalTarget ? undefined : scxmlAction.delay;
|
|
594
|
+
} catch (err) {
|
|
595
|
+
raiseErrorExecution(state, 'send', err);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
const isInternalTarget = target === '#_internal';
|
|
599
|
+
const isParentTarget = target === '#_parent';
|
|
600
|
+
|
|
601
|
+
// Validate target. SCXML targets must be '#_internal', '#_parent',
|
|
602
|
+
// or '#_<id>'. A bare string without the '#_' prefix is invalid and
|
|
603
|
+
// raises error.execution.
|
|
604
|
+
if (typeof target === 'string' && target.length > 0 && !target.startsWith('#_')) {
|
|
605
|
+
raiseErrorExecution(state, 'send', new Error(`Invalid send target: ${target}`));
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
// Attach send id so _event.sendid can be read in expressions.
|
|
609
|
+
if (scxmlAction.id !== undefined) {
|
|
610
|
+
eventData._scxmlSendId = scxmlAction.id;
|
|
611
|
+
}
|
|
612
|
+
// Resolve target at runtime: parent, child, or self
|
|
613
|
+
if (isParentTarget && x.parent) {
|
|
614
|
+
// Send to parent via sendTo; pass delay if present
|
|
615
|
+
enq.sendTo(x.parent, eventData, delay !== undefined ? {
|
|
616
|
+
delay
|
|
617
|
+
} : undefined);
|
|
618
|
+
} else if (typeof target === 'string' && target.startsWith('#_') && !isParentTarget && !isInternalTarget) {
|
|
619
|
+
// #_<invokeId> → try to send to child actor, fall back to self-raise
|
|
620
|
+
const childId = target.slice(2); // strip '#_'
|
|
621
|
+
const childRef = x.children?.[childId];
|
|
622
|
+
if (childRef) {
|
|
623
|
+
enq.sendTo(childRef, eventData);
|
|
624
|
+
} else {
|
|
625
|
+
// Not a known child (e.g. #_scxml_sessionid) → self-raise
|
|
626
|
+
if (delay !== undefined) {
|
|
627
|
+
eventData._scxmlExternal = true;
|
|
628
|
+
}
|
|
629
|
+
enq.raise(eventData, {
|
|
630
|
+
id: scxmlAction.id,
|
|
631
|
+
delay
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
} else {
|
|
635
|
+
// Self-send or no special target: raise as external event
|
|
636
|
+
if (delay !== undefined) {
|
|
637
|
+
eventData._scxmlExternal = true;
|
|
638
|
+
}
|
|
639
|
+
enq.raise(eventData, {
|
|
640
|
+
id: scxmlAction.id,
|
|
641
|
+
delay
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
} else if (action.type === 'scxml.cancel') {
|
|
645
|
+
const scxmlAction = action;
|
|
646
|
+
const mergedContext = {
|
|
647
|
+
...x.context,
|
|
648
|
+
...context
|
|
649
|
+
};
|
|
650
|
+
try {
|
|
651
|
+
const sendId = evaluateExpr(mergedContext, scxmlAction.sendidexpr, x.event, x.self);
|
|
652
|
+
if (sendId) {
|
|
653
|
+
enq.cancel(sendId);
|
|
654
|
+
}
|
|
655
|
+
} catch {
|
|
656
|
+
// ignore evaluation errors
|
|
657
|
+
}
|
|
658
|
+
} else if (action.type === 'scxml.script') {
|
|
659
|
+
const scxmlAction = action;
|
|
660
|
+
const mergedContext = {
|
|
661
|
+
...x.context,
|
|
662
|
+
...context
|
|
663
|
+
};
|
|
664
|
+
try {
|
|
665
|
+
const updatedContext = executeScript(mergedContext, scxmlAction.code);
|
|
666
|
+
context ??= {};
|
|
667
|
+
Object.assign(context, updatedContext);
|
|
668
|
+
} catch (err) {
|
|
669
|
+
raiseErrorExecution(state, 'script', err);
|
|
670
|
+
}
|
|
671
|
+
} else if (action.type === 'scxml.foreach') {
|
|
672
|
+
const scxmlAction = action;
|
|
673
|
+
const mergedContext = {
|
|
674
|
+
...x.context,
|
|
675
|
+
...context
|
|
676
|
+
};
|
|
677
|
+
// SCXML: `item` (and `index` if present) must be valid datamodel
|
|
678
|
+
// locations — i.e. legal identifiers. Reject things like 'continue'
|
|
679
|
+
// (string literal) or '7' (number).
|
|
680
|
+
const isLegalIdentifier = s => /^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(s);
|
|
681
|
+
if (!isLegalIdentifier(scxmlAction.item) || scxmlAction.index && !isLegalIdentifier(scxmlAction.index)) {
|
|
682
|
+
raiseErrorExecution(state, 'foreach', new Error('foreach item/index is not a legal location'));
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
let arr;
|
|
686
|
+
try {
|
|
687
|
+
arr = evaluateExpr(mergedContext, scxmlAction.array, x.event, x.self);
|
|
688
|
+
} catch (err) {
|
|
689
|
+
raiseErrorExecution(state, 'foreach', err);
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
if (!Array.isArray(arr)) {
|
|
693
|
+
raiseErrorExecution(state, 'foreach', new Error('foreach array is not iterable'));
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
context ??= {};
|
|
697
|
+
for (let i = 0; i < arr.length; i++) {
|
|
698
|
+
context[scxmlAction.item] = arr[i];
|
|
699
|
+
if (scxmlAction.index) {
|
|
700
|
+
context[scxmlAction.index] = i;
|
|
701
|
+
}
|
|
702
|
+
const iterX = {
|
|
703
|
+
...x,
|
|
704
|
+
context: {
|
|
705
|
+
...x.context,
|
|
706
|
+
...context
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
const iterResult = executeActions(scxmlAction.actions, iterX, enq, state);
|
|
710
|
+
if (iterResult.context) {
|
|
711
|
+
Object.assign(context, iterResult.context);
|
|
712
|
+
}
|
|
713
|
+
if (state.errored) break;
|
|
714
|
+
}
|
|
715
|
+
} else if (action.type === 'scxml.block') {
|
|
716
|
+
const scxmlAction = action;
|
|
717
|
+
const blockX = {
|
|
718
|
+
...x,
|
|
719
|
+
context: {
|
|
720
|
+
...x.context,
|
|
721
|
+
...context
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
// Block has its own ExecState — errors don't propagate to parent.
|
|
725
|
+
const blockResult = executeActions(scxmlAction.actions, blockX, enq);
|
|
726
|
+
if (blockResult.context) {
|
|
727
|
+
context ??= {};
|
|
728
|
+
for (const key of Object.keys(blockResult.context)) {
|
|
729
|
+
if (blockResult.context[key] !== x.context[key]) {
|
|
730
|
+
context[key] = blockResult.context[key];
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
} else if (action.type === 'scxml.if') {
|
|
735
|
+
const scxmlAction = action;
|
|
736
|
+
const mergedContext = {
|
|
737
|
+
...x.context,
|
|
738
|
+
...context
|
|
739
|
+
};
|
|
740
|
+
for (const branch of scxmlAction.branches) {
|
|
741
|
+
let condResult;
|
|
742
|
+
if (branch.cond) {
|
|
743
|
+
try {
|
|
744
|
+
condResult = !!evaluateExpr(mergedContext, branch.cond, x.event, x.self);
|
|
745
|
+
} catch (err) {
|
|
746
|
+
raiseErrorExecution(state, 'if', err);
|
|
747
|
+
condResult = false;
|
|
748
|
+
}
|
|
749
|
+
} else {
|
|
750
|
+
condResult = true;
|
|
751
|
+
}
|
|
752
|
+
if (condResult) {
|
|
753
|
+
if (branch.actions.length) {
|
|
754
|
+
const branchX = {
|
|
755
|
+
...x,
|
|
756
|
+
context: mergedContext
|
|
757
|
+
};
|
|
758
|
+
const branchResult = executeActions(branch.actions, branchX, enq, state);
|
|
759
|
+
if (branchResult.context) {
|
|
760
|
+
context ??= {};
|
|
761
|
+
for (const key of Object.keys(branchResult.context)) {
|
|
762
|
+
if (branchResult.context[key] !== x.context[key]) {
|
|
763
|
+
context[key] = branchResult.context[key];
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
} else {
|
|
772
|
+
enq(x.actions[action.type], action.params);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
context: context ? {
|
|
777
|
+
...x.context,
|
|
778
|
+
...context
|
|
779
|
+
} : undefined,
|
|
780
|
+
errored: state.errored
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
function iterActions(actions) {
|
|
784
|
+
return (x, enq) => executeActions(actions, x, enq);
|
|
785
|
+
}
|
|
786
|
+
function getTransitionConfig(transition) {
|
|
787
|
+
const transitions = Array.isArray(transition) ? transition : [transition];
|
|
788
|
+
|
|
789
|
+
// Return an array of transition configs. Each SCXML transition becomes
|
|
790
|
+
// a separate XState transition with its own guard and optional .to.
|
|
791
|
+
// This ensures guards are evaluated by XState's evaluateCandidate (once,
|
|
792
|
+
// with pre-exit context) and NOT re-evaluated in computeEntrySet.
|
|
793
|
+
return transitions.map(t => {
|
|
794
|
+
const target = Array.isArray(t.target) ? t.target[0] : t.target;
|
|
795
|
+
const targetConfig = t.target;
|
|
796
|
+
const guard = resolveGuardConfig(t.guard);
|
|
797
|
+
|
|
798
|
+
// No guard and no actions: simple static config
|
|
799
|
+
if (!guard && !t.actions?.length) {
|
|
800
|
+
return {
|
|
801
|
+
target: targetConfig,
|
|
802
|
+
description: t.description,
|
|
803
|
+
reenter: t.reenter,
|
|
804
|
+
meta: t.meta,
|
|
805
|
+
input: t.input
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// Guard but no actions: static config with guard
|
|
810
|
+
if (guard && !t.actions?.length) {
|
|
811
|
+
return {
|
|
812
|
+
target: targetConfig,
|
|
813
|
+
guard,
|
|
814
|
+
description: t.description,
|
|
815
|
+
reenter: t.reenter,
|
|
816
|
+
meta: t.meta,
|
|
817
|
+
input: t.input
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// Targetless transitions: execute actions directly in .to AND track for
|
|
822
|
+
// parallel re-execution. For non-parallel, .to result is used directly.
|
|
823
|
+
// For parallel (entries exist), first entry re-executes all in document order.
|
|
824
|
+
if (!target) {
|
|
825
|
+
return {
|
|
826
|
+
guard,
|
|
827
|
+
description: t.description,
|
|
828
|
+
reenter: t.reenter,
|
|
829
|
+
meta: t.meta,
|
|
830
|
+
input: t.input,
|
|
831
|
+
to: (x, enq) => {
|
|
832
|
+
if (t.actions?.length) {
|
|
833
|
+
// Track for parallel re-execution (dedup by reference)
|
|
834
|
+
if (!allTransitionActions.includes(t.actions)) {
|
|
835
|
+
allTransitionActions.push(t.actions);
|
|
836
|
+
}
|
|
837
|
+
// Save pre-transition context for parallel override
|
|
838
|
+
contextBeforeTargetless ??= x.context;
|
|
839
|
+
// Execute immediately (fallback for non-parallel case)
|
|
840
|
+
const result = executeActions(t.actions, x, enq);
|
|
841
|
+
if (result.context) {
|
|
842
|
+
return {
|
|
843
|
+
context: result.context
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return {};
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Has target + actions: use guard (for XState evaluation) + .to (for pending actions).
|
|
853
|
+
// The .to function does NOT re-check the guard — XState's evaluateCandidate
|
|
854
|
+
// already validated it. The .to just stores actions for entry to execute.
|
|
855
|
+
// Map by target state ID so parallel transitions each get their own actions.
|
|
856
|
+
return {
|
|
857
|
+
guard,
|
|
858
|
+
description: t.description,
|
|
859
|
+
reenter: t.reenter,
|
|
860
|
+
meta: t.meta,
|
|
861
|
+
input: t.input,
|
|
862
|
+
to: (_x, _enq) => {
|
|
863
|
+
if (t.actions?.length) {
|
|
864
|
+
const targetId = target.replace(/^#/, '');
|
|
865
|
+
pendingTransitionActionsMap[targetId] = t.actions;
|
|
866
|
+
// Track for parallel re-execution (dedup by reference)
|
|
867
|
+
if (!allTransitionActions.includes(t.actions)) {
|
|
868
|
+
allTransitionActions.push(t.actions);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return {
|
|
872
|
+
target: targetConfig,
|
|
873
|
+
reenter: t.reenter
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
const rootNodeConfig = iterNode(json);
|
|
880
|
+
const contextConfig = json.context ? {
|
|
881
|
+
context: json.context
|
|
882
|
+
} : {};
|
|
883
|
+
_scxmlMachineName = json.id || '';
|
|
884
|
+
_scxmlSessionId = 'session_' + Math.random().toString(36).slice(2);
|
|
885
|
+
const machine = createMachine({
|
|
886
|
+
...rootNodeConfig,
|
|
887
|
+
...contextConfig,
|
|
888
|
+
version: json.version
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
// Register SCXML guard implementations
|
|
892
|
+
const providedGuards = {
|
|
893
|
+
'scxml.cond': ({
|
|
894
|
+
context,
|
|
895
|
+
event,
|
|
896
|
+
self
|
|
897
|
+
}, params) => {
|
|
898
|
+
const expr = params?.expr;
|
|
899
|
+
if (!expr) return true;
|
|
900
|
+
try {
|
|
901
|
+
return !!evaluateExpr(context, expr, event, self);
|
|
902
|
+
} catch (err) {
|
|
903
|
+
// Per SCXML spec, a cond that fails to evaluate is treated as false
|
|
904
|
+
// AND raises error.execution. We can't enqueue from a guard, so
|
|
905
|
+
// queue it for the next entry to drain.
|
|
906
|
+
const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
|
|
907
|
+
pendingPlatformErrors.push({
|
|
908
|
+
tagname: 'cond',
|
|
909
|
+
message,
|
|
910
|
+
line: NaN,
|
|
911
|
+
column: NaN,
|
|
912
|
+
reason: message
|
|
913
|
+
});
|
|
914
|
+
return false;
|
|
915
|
+
}
|
|
916
|
+
},
|
|
917
|
+
'xstate.stateIn': (args, params) => {
|
|
918
|
+
const stateId = params?.stateId;
|
|
919
|
+
if (!stateId) return false;
|
|
920
|
+
const normalizedId = stateId.replace(/^#/, '');
|
|
921
|
+
const snapshot = args._snapshot;
|
|
922
|
+
if (snapshot?._nodes) {
|
|
923
|
+
return snapshot._nodes.some(node => node.id === normalizedId);
|
|
924
|
+
}
|
|
925
|
+
return false;
|
|
926
|
+
},
|
|
927
|
+
'xstate.not': (args, params) => {
|
|
928
|
+
const inner = params?.guard;
|
|
929
|
+
const innerImpl = inner && args.guards?.[inner.type];
|
|
930
|
+
if (!innerImpl) {
|
|
931
|
+
throw new Error(`Guard '${inner?.type}' referenced by 'xstate.not' is not implemented.`);
|
|
932
|
+
}
|
|
933
|
+
return !innerImpl(args, inner.params);
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
const provided = machine.provide({
|
|
937
|
+
actions: resolvedImplementations.actions,
|
|
938
|
+
actorSources: resolvedImplementations.actorSources,
|
|
939
|
+
guards: {
|
|
940
|
+
...providedGuards,
|
|
941
|
+
...resolvedImplementations.guards
|
|
942
|
+
},
|
|
943
|
+
delays: resolvedImplementations.delays
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// Keep the original JSON so `serializeMachine(machine)`
|
|
947
|
+
// round-trip losslessly.
|
|
948
|
+
provided._json = json;
|
|
949
|
+
return provided;
|
|
950
|
+
}
|
|
951
|
+
function isBuiltInActionJSON(action) {
|
|
952
|
+
return action.type.startsWith('@xstate.');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* Machine-definition serialization.
|
|
957
|
+
*
|
|
958
|
+
* `machineConfigToJSON` converts a machine config into a JSON-safe structure
|
|
959
|
+
* (the `MachineJSON` shape accepted by `createMachineFromConfig`). The boundary
|
|
960
|
+
* between serializable structure and runtime implementations is explicit:
|
|
961
|
+
* functions are represented as code expressions, while actor logic, runtime
|
|
962
|
+
* schemas, and other non-code runtime values are replaced with an `{
|
|
963
|
+
* "$unserializable": <kind> }` marker rather than silently dropped.
|
|
964
|
+
*
|
|
965
|
+
* A machine definition is fully portable iff its JSON contains no
|
|
966
|
+
* `$unserializable` markers; reviving a definition that has markers requires
|
|
967
|
+
* re-providing those implementations (e.g. via `machine.provide(...)` or the
|
|
968
|
+
* `actions`/`guards`/`actorSources` maps on `createMachineFromConfig`
|
|
969
|
+
* revival).
|
|
970
|
+
*/
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Returns the JSON-serializable definition of a machine.
|
|
974
|
+
*
|
|
975
|
+
* Inline functions are represented as `{ "@type": "code", lang: "ts", expr }`.
|
|
976
|
+
* Actor logic and runtime schemas appear as `{ "$unserializable": ... }`
|
|
977
|
+
* markers. A machine created via `createMachineFromConfig` returns its original
|
|
978
|
+
* JSON config (lossless round-trip):
|
|
979
|
+
*
|
|
980
|
+
* ```ts
|
|
981
|
+
* import { serializeMachine, createMachineFromConfig } from 'xstate';
|
|
982
|
+
*
|
|
983
|
+
* const json = serializeMachine(machine);
|
|
984
|
+
* const revived = createMachineFromConfig(
|
|
985
|
+
* JSON.parse(JSON.stringify(json))
|
|
986
|
+
* );
|
|
987
|
+
* ```
|
|
988
|
+
*/
|
|
989
|
+
function serializeMachine(machine) {
|
|
990
|
+
return machine._json ?? machineConfigToJSON(machine.config);
|
|
991
|
+
}
|
|
992
|
+
function marker(kind, id) {
|
|
993
|
+
const m = {
|
|
994
|
+
$unserializable: kind
|
|
995
|
+
};
|
|
996
|
+
if (id) {
|
|
997
|
+
m.id = id;
|
|
998
|
+
}
|
|
999
|
+
return m;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
1003
|
+
function codeExpression(fn) {
|
|
1004
|
+
return {
|
|
1005
|
+
'@type': 'code',
|
|
1006
|
+
lang: 'ts',
|
|
1007
|
+
expr: fn.toString()
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function isActorLogic(value) {
|
|
1011
|
+
return !!value && typeof value === 'object' && typeof value.transition === 'function' && typeof value.getInitialSnapshot === 'function';
|
|
1012
|
+
}
|
|
1013
|
+
function isRuntimeSchema(value) {
|
|
1014
|
+
return !!value && typeof value === 'object' && '~standard' in value;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/** JSON-safe deep copy of a plain value; functions become code expressions. */
|
|
1018
|
+
function valueToJSON(value) {
|
|
1019
|
+
if (typeof value === 'function') {
|
|
1020
|
+
return codeExpression(value);
|
|
1021
|
+
}
|
|
1022
|
+
if (value === null || typeof value !== 'object') {
|
|
1023
|
+
return typeof value === 'bigint' || typeof value === 'symbol' ? marker('value') : value;
|
|
1024
|
+
}
|
|
1025
|
+
if (isActorLogic(value)) {
|
|
1026
|
+
return marker('actor', value.id);
|
|
1027
|
+
}
|
|
1028
|
+
if (isRuntimeSchema(value)) {
|
|
1029
|
+
return marker('schema');
|
|
1030
|
+
}
|
|
1031
|
+
if (Array.isArray(value)) {
|
|
1032
|
+
return value.map(valueToJSON);
|
|
1033
|
+
}
|
|
1034
|
+
if (value.constructor !== Object && value.constructor !== undefined) {
|
|
1035
|
+
// Class instances (actor logic, schemas, dates, ...) are not portable.
|
|
1036
|
+
return marker('value');
|
|
1037
|
+
}
|
|
1038
|
+
const result = {};
|
|
1039
|
+
for (const key of Object.keys(value)) {
|
|
1040
|
+
const v = value[key];
|
|
1041
|
+
if (v !== undefined) {
|
|
1042
|
+
result[key] = valueToJSON(v);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
return result;
|
|
1046
|
+
}
|
|
1047
|
+
function invokeToJSON(invoke) {
|
|
1048
|
+
if (Array.isArray(invoke)) {
|
|
1049
|
+
return invoke.map(invokeToJSON);
|
|
1050
|
+
}
|
|
1051
|
+
const def = invoke;
|
|
1052
|
+
const result = {};
|
|
1053
|
+
for (const key of Object.keys(def)) {
|
|
1054
|
+
const value = def[key];
|
|
1055
|
+
if (value === undefined) {
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
result[key] = key === 'src' && typeof value !== 'string' ?
|
|
1059
|
+
// Actor logic keeps its dedicated marker kind so revival knows the
|
|
1060
|
+
// contract is an actor, not a plain function.
|
|
1061
|
+
marker('actor', value.id) : valueToJSON(value);
|
|
1062
|
+
}
|
|
1063
|
+
return result;
|
|
1064
|
+
}
|
|
1065
|
+
function implementationsToJSON(map, kind) {
|
|
1066
|
+
if (!map) {
|
|
1067
|
+
return undefined;
|
|
1068
|
+
}
|
|
1069
|
+
// Keys are preserved — they are the contract a revived machine must
|
|
1070
|
+
// fulfill via provide() — while values become markers (or stay, for
|
|
1071
|
+
// JSON-safe values like numeric delays).
|
|
1072
|
+
const result = {};
|
|
1073
|
+
for (const key of Object.keys(map)) {
|
|
1074
|
+
const value = map[key];
|
|
1075
|
+
if (kind === 'schema') {
|
|
1076
|
+
result[key] = marker('schema', key);
|
|
1077
|
+
} else if (typeof value === 'function') {
|
|
1078
|
+
result[key] = codeExpression(value);
|
|
1079
|
+
} else if (kind === 'actor' && value && typeof value === 'object') {
|
|
1080
|
+
result[key] = marker('actor', key);
|
|
1081
|
+
} else {
|
|
1082
|
+
result[key] = valueToJSON(value);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
return result;
|
|
1086
|
+
}
|
|
1087
|
+
function stateNodeConfigToJSON(config) {
|
|
1088
|
+
const result = {};
|
|
1089
|
+
for (const key of Object.keys(config)) {
|
|
1090
|
+
if (key === 'states' || key === 'invoke') {
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
const value = config[key];
|
|
1094
|
+
if (value !== undefined) {
|
|
1095
|
+
result[key] = valueToJSON(value);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
if (config.invoke !== undefined) {
|
|
1099
|
+
result.invoke = invokeToJSON(config.invoke);
|
|
1100
|
+
}
|
|
1101
|
+
if (config.states) {
|
|
1102
|
+
const states = {};
|
|
1103
|
+
for (const key of Object.keys(config.states)) {
|
|
1104
|
+
states[key] = stateNodeConfigToJSON(config.states[key]);
|
|
1105
|
+
}
|
|
1106
|
+
result.states = states;
|
|
1107
|
+
}
|
|
1108
|
+
return result;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Converts a machine config (as passed to `createMachine`) to its JSON-safe
|
|
1113
|
+
* definition. See module docs for the `$unserializable` marker contract.
|
|
1114
|
+
*/
|
|
1115
|
+
function machineConfigToJSON(config) {
|
|
1116
|
+
const result = stateNodeConfigToJSON(config);
|
|
1117
|
+
if (config.internalEvents !== undefined) {
|
|
1118
|
+
result.internalEvents = valueToJSON(config.internalEvents);
|
|
1119
|
+
}
|
|
1120
|
+
if (config.schemas) {
|
|
1121
|
+
const schemas = {};
|
|
1122
|
+
for (const key of Object.keys(config.schemas)) {
|
|
1123
|
+
const value = config.schemas[key];
|
|
1124
|
+
if (value && typeof value === 'object' && !('~standard' in value)) {
|
|
1125
|
+
// Map-form schemas (events/emitted): preserve event-type keys.
|
|
1126
|
+
schemas[key] = implementationsToJSON(value, 'schema');
|
|
1127
|
+
} else {
|
|
1128
|
+
schemas[key] = marker('schema', key);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
result.schemas = schemas;
|
|
1132
|
+
}
|
|
1133
|
+
for (const key of ['actions', 'guards', 'actorSources', 'delays']) {
|
|
1134
|
+
if (config[key]) {
|
|
1135
|
+
result[key] = implementationsToJSON(config[key], key === 'actorSources' ? 'actor' : 'function');
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return result;
|
|
88
1139
|
}
|
|
89
1140
|
|
|
90
1141
|
/**
|
|
@@ -116,7 +1167,7 @@ function mapState(snapshot, mapper) {
|
|
|
116
1167
|
return mapper;
|
|
117
1168
|
};
|
|
118
1169
|
const visited = new Set();
|
|
119
|
-
for (const atomicNode of snapshot._nodes.filter(
|
|
1170
|
+
for (const atomicNode of snapshot._nodes.filter(dist_xstateActors.isAtomicStateNode)) {
|
|
120
1171
|
let current = atomicNode;
|
|
121
1172
|
while (current && !visited.has(current)) {
|
|
122
1173
|
visited.add(current);
|
|
@@ -133,11 +1184,245 @@ function mapState(snapshot, mapper) {
|
|
|
133
1184
|
return results;
|
|
134
1185
|
}
|
|
135
1186
|
|
|
1187
|
+
/** The Standard Schema interface. */
|
|
1188
|
+
|
|
1189
|
+
/** A type-only Standard Schema produced by {@link types}. */
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Declares schema types for inference only — no runtime validation.
|
|
1193
|
+
*
|
|
1194
|
+
* Use in a machine's `schemas` when you want TypeScript types without pulling
|
|
1195
|
+
* in a schema library like Zod. The returned value is a valid Standard Schema
|
|
1196
|
+
* whose validation is the identity function, so it carries types but never
|
|
1197
|
+
* rejects input.
|
|
1198
|
+
*
|
|
1199
|
+
* @example
|
|
1200
|
+
*
|
|
1201
|
+
* ```ts
|
|
1202
|
+
* import { createMachine, types } from 'xstate';
|
|
1203
|
+
*
|
|
1204
|
+
* const machine = createMachine({
|
|
1205
|
+
* schemas: {
|
|
1206
|
+
* context: types<{ count: number }>(),
|
|
1207
|
+
* events: {
|
|
1208
|
+
* inc: types<{ by: number }>(),
|
|
1209
|
+
* reset: types<{}>()
|
|
1210
|
+
* }
|
|
1211
|
+
* },
|
|
1212
|
+
* context: { count: 0 }
|
|
1213
|
+
* // ...
|
|
1214
|
+
* });
|
|
1215
|
+
* ```
|
|
1216
|
+
*/
|
|
1217
|
+
function types() {
|
|
1218
|
+
return {
|
|
1219
|
+
'~standard': {
|
|
1220
|
+
version: 1,
|
|
1221
|
+
vendor: 'xstate.types',
|
|
1222
|
+
validate: value => ({
|
|
1223
|
+
value: value
|
|
1224
|
+
})
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/** Returns true if the value is a type-only schema created by {@link types}. */
|
|
1230
|
+
function isTypeSchema(value) {
|
|
1231
|
+
return !!value && typeof value === 'object' && '~standard' in value && value['~standard'].vendor === 'xstate.types';
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
1235
|
+
|
|
1236
|
+
/** State schema with optional schemas.input and nested states */
|
|
1237
|
+
|
|
1238
|
+
/** Extracts input type from a state schema */
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Converts SetupStateSchema to StateSchema with input types included. This
|
|
1242
|
+
* allows getInputs() to be strongly typed.
|
|
1243
|
+
*/
|
|
1244
|
+
|
|
1245
|
+
/** Converts the root setup states config to a StateSchema. */
|
|
1246
|
+
|
|
1247
|
+
/** Machine config with typed state input */
|
|
1248
|
+
|
|
1249
|
+
/** States config type that provides typed input for known states */
|
|
1250
|
+
|
|
1251
|
+
/** State node config that recursively applies typed input for nested states */
|
|
1252
|
+
|
|
1253
|
+
/** Initial transition with typed input based on target state */
|
|
1254
|
+
|
|
1255
|
+
/** Return type of setup() */
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* Sets up a state machine with state input schemas and other configuration.
|
|
1259
|
+
*
|
|
1260
|
+
* @example
|
|
1261
|
+
*
|
|
1262
|
+
* ```ts
|
|
1263
|
+
* import { setup } from 'xstate';
|
|
1264
|
+
* import z from 'zod';
|
|
1265
|
+
*
|
|
1266
|
+
* const s = setup({
|
|
1267
|
+
* states: {
|
|
1268
|
+
* loading: {
|
|
1269
|
+
* schemas: {
|
|
1270
|
+
* input: z.object({
|
|
1271
|
+
* userId: z.string()
|
|
1272
|
+
* })
|
|
1273
|
+
* }
|
|
1274
|
+
* }
|
|
1275
|
+
* }
|
|
1276
|
+
* });
|
|
1277
|
+
*
|
|
1278
|
+
* const machine = s.createMachine({
|
|
1279
|
+
* initial: {
|
|
1280
|
+
* target: 'loading',
|
|
1281
|
+
* input: { userId: '123' }
|
|
1282
|
+
* },
|
|
1283
|
+
* states: {
|
|
1284
|
+
* loading: {
|
|
1285
|
+
* entry: ({ input }) => {
|
|
1286
|
+
* console.log(input.userId);
|
|
1287
|
+
* }
|
|
1288
|
+
* }
|
|
1289
|
+
* }
|
|
1290
|
+
* });
|
|
1291
|
+
* ```
|
|
1292
|
+
*/
|
|
1293
|
+
|
|
1294
|
+
function setup(config = {}) {
|
|
1295
|
+
const {
|
|
1296
|
+
states = {},
|
|
1297
|
+
schemas,
|
|
1298
|
+
actions,
|
|
1299
|
+
actorSources,
|
|
1300
|
+
guards,
|
|
1301
|
+
delays
|
|
1302
|
+
} = config;
|
|
1303
|
+
return {
|
|
1304
|
+
extend(extension) {
|
|
1305
|
+
return setup(mergeSetupConfigs(config, extension));
|
|
1306
|
+
},
|
|
1307
|
+
createMachine(machineConfig) {
|
|
1308
|
+
const configSchemas = machineConfig.schemas;
|
|
1309
|
+
const mergedSchemas = mergeSchemas(configSchemas, schemas);
|
|
1310
|
+
const mergedActions = mergeMaps(actions, machineConfig.actions);
|
|
1311
|
+
const mergedActorSources = mergeMaps(actorSources, machineConfig.actorSources);
|
|
1312
|
+
const mergedGuards = mergeMaps(guards, machineConfig.guards);
|
|
1313
|
+
const mergedDelays = mergeMaps(delays, machineConfig.delays);
|
|
1314
|
+
return new StateMachine.StateMachine({
|
|
1315
|
+
...machineConfig,
|
|
1316
|
+
...(mergedSchemas ? {
|
|
1317
|
+
schemas: mergedSchemas
|
|
1318
|
+
} : undefined),
|
|
1319
|
+
...(mergedActions ? {
|
|
1320
|
+
actions: mergedActions
|
|
1321
|
+
} : undefined),
|
|
1322
|
+
...(mergedActorSources ? {
|
|
1323
|
+
actorSources: mergedActorSources
|
|
1324
|
+
} : undefined),
|
|
1325
|
+
...(mergedGuards ? {
|
|
1326
|
+
guards: mergedGuards
|
|
1327
|
+
} : undefined),
|
|
1328
|
+
...(mergedDelays ? {
|
|
1329
|
+
delays: mergedDelays
|
|
1330
|
+
} : undefined)
|
|
1331
|
+
});
|
|
1332
|
+
},
|
|
1333
|
+
createStateConfig(stateConfig) {
|
|
1334
|
+
return stateConfig;
|
|
1335
|
+
},
|
|
1336
|
+
states
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
function createSystem(_config = {}) {
|
|
1340
|
+
const runtimeRef = {};
|
|
1341
|
+
const pendingObservers = [];
|
|
1342
|
+
const flushObservers = () => {
|
|
1343
|
+
const runtime = runtimeRef.current;
|
|
1344
|
+
if (!runtime) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
for (const entry of pendingObservers) {
|
|
1348
|
+
if (entry.active && !entry.subscription) {
|
|
1349
|
+
entry.subscription = runtime.inspect(entry.observer);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
return {
|
|
1354
|
+
createActor(logic, options) {
|
|
1355
|
+
const actor = dist_xstateActors.createActor(logic, {
|
|
1356
|
+
...options,
|
|
1357
|
+
_systemRef: runtimeRef
|
|
1358
|
+
});
|
|
1359
|
+
flushObservers();
|
|
1360
|
+
return actor;
|
|
1361
|
+
},
|
|
1362
|
+
get(key) {
|
|
1363
|
+
return runtimeRef.current?.get(key);
|
|
1364
|
+
},
|
|
1365
|
+
getAll() {
|
|
1366
|
+
return runtimeRef.current?.getAll() ?? {};
|
|
1367
|
+
},
|
|
1368
|
+
inspect(observer) {
|
|
1369
|
+
const runtime = runtimeRef.current;
|
|
1370
|
+
if (runtime) {
|
|
1371
|
+
return runtime.inspect(observer);
|
|
1372
|
+
}
|
|
1373
|
+
const entry = {
|
|
1374
|
+
observer: observer,
|
|
1375
|
+
active: true
|
|
1376
|
+
};
|
|
1377
|
+
pendingObservers.push(entry);
|
|
1378
|
+
return {
|
|
1379
|
+
unsubscribe() {
|
|
1380
|
+
entry.active = false;
|
|
1381
|
+
entry.subscription?.unsubscribe();
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
},
|
|
1385
|
+
setup(config) {
|
|
1386
|
+
return config ? setup(config) : setup();
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
function mergeMaps(left, right) {
|
|
1391
|
+
return left || right ? {
|
|
1392
|
+
...left,
|
|
1393
|
+
...right
|
|
1394
|
+
} : undefined;
|
|
1395
|
+
}
|
|
1396
|
+
function mergeSchemas(left, right) {
|
|
1397
|
+
if (!left && !right) {
|
|
1398
|
+
return undefined;
|
|
1399
|
+
}
|
|
1400
|
+
return {
|
|
1401
|
+
...left,
|
|
1402
|
+
...right,
|
|
1403
|
+
events: mergeMaps(left?.events, right?.events),
|
|
1404
|
+
emitted: mergeMaps(left?.emitted, right?.emitted),
|
|
1405
|
+
children: mergeMaps(left?.children, right?.children)
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
function mergeSetupConfigs(base, extension) {
|
|
1409
|
+
return {
|
|
1410
|
+
...base,
|
|
1411
|
+
...extension,
|
|
1412
|
+
schemas: mergeSchemas(base.schemas, extension.schemas),
|
|
1413
|
+
states: mergeMaps(base.states, extension.states),
|
|
1414
|
+
actions: mergeMaps(base.actions, extension.actions),
|
|
1415
|
+
actorSources: mergeMaps(base.actorSources, extension.actorSources),
|
|
1416
|
+
guards: mergeMaps(base.guards, extension.guards),
|
|
1417
|
+
delays: mergeMaps(base.delays, extension.delays)
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
|
|
136
1421
|
/** @internal */
|
|
137
1422
|
function createInertActorScope(actorLogic) {
|
|
138
|
-
const self =
|
|
1423
|
+
const self = dist_xstateActors.createActor(actorLogic);
|
|
139
1424
|
const inertActorScope = {
|
|
140
|
-
self,
|
|
1425
|
+
self: self,
|
|
141
1426
|
defer: () => {},
|
|
142
1427
|
id: '',
|
|
143
1428
|
logger: () => {},
|
|
@@ -153,7 +1438,7 @@ function createInertActorScope(actorLogic) {
|
|
|
153
1438
|
/** @deprecated Use `initialTransition(…)` instead. */
|
|
154
1439
|
function getInitialSnapshot(actorLogic, ...[input]) {
|
|
155
1440
|
const actorScope = createInertActorScope(actorLogic);
|
|
156
|
-
return actorLogic.
|
|
1441
|
+
return actorLogic.initialTransition(input, actorScope)[0];
|
|
157
1442
|
}
|
|
158
1443
|
|
|
159
1444
|
/**
|
|
@@ -192,64 +1477,8 @@ function getInitialSnapshot(actorLogic, ...[input]) {
|
|
|
192
1477
|
function getNextSnapshot(actorLogic, snapshot, event) {
|
|
193
1478
|
const inertActorScope = createInertActorScope(actorLogic);
|
|
194
1479
|
inertActorScope.self._snapshot = snapshot;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// at the moment we allow extra actors - ones that are not specified by `children`
|
|
199
|
-
// this could be reconsidered in the future
|
|
200
|
-
|
|
201
|
-
// used to keep only StateSchema relevant keys
|
|
202
|
-
// this helps with type serialization as it makes the inferred type much shorter when dealing with huge configs
|
|
203
|
-
|
|
204
|
-
// Extract { [invokeId]: src } mappings from a machine config's invoke entries.
|
|
205
|
-
// This allows createMachine to infer TChildrenMap from the invoke config
|
|
206
|
-
// when types.children is not explicitly provided.
|
|
207
|
-
|
|
208
|
-
function setup({
|
|
209
|
-
schemas,
|
|
210
|
-
actors,
|
|
211
|
-
actions,
|
|
212
|
-
guards,
|
|
213
|
-
delays
|
|
214
|
-
}) {
|
|
215
|
-
return {
|
|
216
|
-
assign: assign.assign,
|
|
217
|
-
sendTo: log.sendTo,
|
|
218
|
-
raise: dist_xstateGuards.raise,
|
|
219
|
-
log: log.log,
|
|
220
|
-
cancel: dist_xstateGuards.cancel,
|
|
221
|
-
stopChild: dist_xstateGuards.stopChild,
|
|
222
|
-
enqueueActions: log.enqueueActions,
|
|
223
|
-
emit: log.emit,
|
|
224
|
-
spawnChild: dist_xstateGuards.spawnChild,
|
|
225
|
-
createStateConfig: config => config,
|
|
226
|
-
createAction: fn => fn,
|
|
227
|
-
createMachine: config => createMachine({
|
|
228
|
-
...config,
|
|
229
|
-
schemas
|
|
230
|
-
}, {
|
|
231
|
-
actors,
|
|
232
|
-
actions,
|
|
233
|
-
guards,
|
|
234
|
-
delays
|
|
235
|
-
}),
|
|
236
|
-
extend: extended => setup({
|
|
237
|
-
schemas,
|
|
238
|
-
actors,
|
|
239
|
-
actions: {
|
|
240
|
-
...actions,
|
|
241
|
-
...extended.actions
|
|
242
|
-
},
|
|
243
|
-
guards: {
|
|
244
|
-
...guards,
|
|
245
|
-
...extended.guards
|
|
246
|
-
},
|
|
247
|
-
delays: {
|
|
248
|
-
...delays,
|
|
249
|
-
...extended.delays
|
|
250
|
-
}
|
|
251
|
-
})
|
|
252
|
-
};
|
|
1480
|
+
const transitionResult = actorLogic.transition(snapshot, event, inertActorScope);
|
|
1481
|
+
return Array.isArray(transitionResult) ? transitionResult[0] : transitionResult;
|
|
253
1482
|
}
|
|
254
1483
|
|
|
255
1484
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
@@ -314,6 +1543,11 @@ class SimulatedClock {
|
|
|
314
1543
|
}
|
|
315
1544
|
}
|
|
316
1545
|
this._flushing = false;
|
|
1546
|
+
// Check if new timeouts were added during the last iteration
|
|
1547
|
+
if (this._flushingInvalidated) {
|
|
1548
|
+
this._flushingInvalidated = false;
|
|
1549
|
+
this.flushTimeouts();
|
|
1550
|
+
}
|
|
317
1551
|
}
|
|
318
1552
|
increment(ms) {
|
|
319
1553
|
this._now += ms;
|
|
@@ -355,6 +1589,138 @@ function toPromise(actor) {
|
|
|
355
1589
|
});
|
|
356
1590
|
}
|
|
357
1591
|
|
|
1592
|
+
// this is needed to make JSDoc `@link` work properly
|
|
1593
|
+
|
|
1594
|
+
/**
|
|
1595
|
+
* @remarks
|
|
1596
|
+
* `T | unknown` reduces to `unknown` and that can be problematic when it comes
|
|
1597
|
+
* to contextual typing. It especially is a problem when the union has a
|
|
1598
|
+
* function member, like here:
|
|
1599
|
+
*
|
|
1600
|
+
* ```ts
|
|
1601
|
+
* declare function test(
|
|
1602
|
+
* cbOrVal: ((arg: number) => unknown) | unknown
|
|
1603
|
+
* ): void;
|
|
1604
|
+
* test((arg) => {}); // oops, implicit any
|
|
1605
|
+
* ```
|
|
1606
|
+
*
|
|
1607
|
+
* This type can be used to avoid this problem. This union represents the same
|
|
1608
|
+
* value space as `unknown`.
|
|
1609
|
+
*/
|
|
1610
|
+
|
|
1611
|
+
// https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379091887
|
|
1612
|
+
|
|
1613
|
+
// @TODO: we can't use native `NoInfer` as we need those:
|
|
1614
|
+
// https://github.com/microsoft/TypeScript/pull/61092
|
|
1615
|
+
// https://github.com/microsoft/TypeScript/pull/61077
|
|
1616
|
+
// but even with those fixes native NoInfer still doesn't work - further issues have to be reproduced and fixed
|
|
1617
|
+
|
|
1618
|
+
/** @deprecated Use the built-in `NoInfer` type instead */
|
|
1619
|
+
|
|
1620
|
+
/** The full definition of an event, with a string `type`. */
|
|
1621
|
+
|
|
1622
|
+
/**
|
|
1623
|
+
* The string or object representing the state value relative to the parent
|
|
1624
|
+
* state node.
|
|
1625
|
+
*
|
|
1626
|
+
* @remarks
|
|
1627
|
+
* - For a child atomic state node, this is a string, e.g., `"pending"`.
|
|
1628
|
+
* - For complex state nodes, this is an object, e.g., `{ success:
|
|
1629
|
+
* "someChildState" }`.
|
|
1630
|
+
*/
|
|
1631
|
+
|
|
1632
|
+
// Accept any StateNode instance regardless of generic parameters
|
|
1633
|
+
// Using a union type to handle variance issues with machine.resolveState
|
|
1634
|
+
|
|
1635
|
+
let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
|
|
1636
|
+
SpecialTargets["Internal"] = "#_internal";
|
|
1637
|
+
return SpecialTargets;
|
|
1638
|
+
}({});
|
|
1639
|
+
|
|
1640
|
+
/**
|
|
1641
|
+
* A pending effect (delayed event/transition that has not fired yet) captured
|
|
1642
|
+
* in a persisted snapshot — a serialized built-in action descriptor plus its
|
|
1643
|
+
* runtime progress, with enough information to restore it under any strategy.
|
|
1644
|
+
*/
|
|
1645
|
+
|
|
1646
|
+
/**
|
|
1647
|
+
* How pending effects (timers) from a persisted snapshot are restored on
|
|
1648
|
+
* `actor.start()`:
|
|
1649
|
+
*
|
|
1650
|
+
* - `'resume'` (default) — the clock was "frozen" while persisted: a 5-minute
|
|
1651
|
+
* timer persisted with 1 minute elapsed fires after 4 more minutes.
|
|
1652
|
+
* - `'restart'` — timers start over with their full delay.
|
|
1653
|
+
* - `'absolute'` — timers honor the original wall-clock expiry (`startedAt +
|
|
1654
|
+
* delay`); already-expired timers fire immediately.
|
|
1655
|
+
* - A custom function receiving the pending effect and returning the remaining
|
|
1656
|
+
* delay in ms.
|
|
1657
|
+
*/
|
|
1658
|
+
|
|
1659
|
+
/** @deprecated Use `AnyActor` instead. */
|
|
1660
|
+
|
|
1661
|
+
// Based on RxJS types
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* A consumer-facing actor handle.
|
|
1665
|
+
*
|
|
1666
|
+
* `ActorRef` describes the contract a consumer needs: which events can be sent
|
|
1667
|
+
* to the actor, which snapshot it publishes for observation, and which emitted
|
|
1668
|
+
* events can be listened to. It intentionally does not expose lifecycle control
|
|
1669
|
+
* or runtime internals. A concrete `Actor` satisfies this interface, so APIs
|
|
1670
|
+
* should accept `ActorRef` whenever they only need to send events, read
|
|
1671
|
+
* snapshots, or listen to emitted events.
|
|
1672
|
+
*/
|
|
1673
|
+
|
|
1674
|
+
/**
|
|
1675
|
+
* Runtime-only actor capabilities.
|
|
1676
|
+
*
|
|
1677
|
+
* These members are needed by the interpreter, scheduler, inspection, and child
|
|
1678
|
+
* management code. Public consumer APIs should prefer `ActorRef` unless they
|
|
1679
|
+
* genuinely need lifecycle control such as starting, stopping, or accessing
|
|
1680
|
+
* system-owned runtime state.
|
|
1681
|
+
*/
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* A concrete actor instance type.
|
|
1685
|
+
*
|
|
1686
|
+
* `ActorInstance` combines the consumer `ActorRef` contract with runtime
|
|
1687
|
+
* lifecycle capabilities. Values returned by `createActor(...)` and
|
|
1688
|
+
* `spawn(...)` naturally satisfy narrower `ActorRef` contracts.
|
|
1689
|
+
*/
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* The actor's own full self handle.
|
|
1693
|
+
*
|
|
1694
|
+
* Internals and action/guard implementations receive this shape because `self`
|
|
1695
|
+
* can participate in runtime-owned behavior while still being usable wherever
|
|
1696
|
+
* an `ActorRef` is expected.
|
|
1697
|
+
*/
|
|
1698
|
+
|
|
1699
|
+
// TODO: in v6, this should only accept AnyActorLogic, like ActorRefFromLogic
|
|
1700
|
+
|
|
1701
|
+
/** The concrete actor instance type produced from actor logic. */
|
|
1702
|
+
|
|
1703
|
+
// TODO: in v6, this should only accept AnyActorLogic, like ActorRefFromLogic
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* Represents logic which can be used by an actor.
|
|
1707
|
+
*
|
|
1708
|
+
* @template TSnapshot - The type of the snapshot.
|
|
1709
|
+
* @template TEvent - The type of the event object.
|
|
1710
|
+
* @template TInput - The type of the input.
|
|
1711
|
+
* @template TSystem - The type of the actor system.
|
|
1712
|
+
*/
|
|
1713
|
+
|
|
1714
|
+
// Actors that don't have literal string IDs — these are the only ones
|
|
1715
|
+
// that should appear in the index signature fallback, since actors with
|
|
1716
|
+
// literal IDs are already covered by ToConcreteChildren.
|
|
1717
|
+
|
|
1718
|
+
/** Maps state IDs to their input types based on the StateSchema. */
|
|
1719
|
+
|
|
1720
|
+
/** @deprecated */
|
|
1721
|
+
|
|
1722
|
+
/** Mappers for subscribeTo - maps lifecycle events to machine events */
|
|
1723
|
+
|
|
358
1724
|
/**
|
|
359
1725
|
* Given actor `logic`, a `snapshot`, and an `event`, returns a tuple of the
|
|
360
1726
|
* `nextSnapshot` and `actions` to execute.
|
|
@@ -362,13 +1728,9 @@ function toPromise(actor) {
|
|
|
362
1728
|
* This is a pure function that does not execute `actions`.
|
|
363
1729
|
*/
|
|
364
1730
|
function transition(logic, snapshot, event) {
|
|
365
|
-
const executableActions = [];
|
|
366
1731
|
const actorScope = createInertActorScope(logic);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
};
|
|
370
|
-
const nextSnapshot = logic.transition(snapshot, event, actorScope);
|
|
371
|
-
return [nextSnapshot, executableActions];
|
|
1732
|
+
const [nextSnapshot, effects] = logic.transition(snapshot, event, actorScope);
|
|
1733
|
+
return [nextSnapshot, effects];
|
|
372
1734
|
}
|
|
373
1735
|
|
|
374
1736
|
/**
|
|
@@ -379,12 +1741,8 @@ function transition(logic, snapshot, event) {
|
|
|
379
1741
|
* This is a pure function that does not execute `actions`.
|
|
380
1742
|
*/
|
|
381
1743
|
function initialTransition(logic, ...[input]) {
|
|
382
|
-
const executableActions = [];
|
|
383
1744
|
const actorScope = createInertActorScope(logic);
|
|
384
|
-
|
|
385
|
-
executableActions.push(action);
|
|
386
|
-
};
|
|
387
|
-
const nextSnapshot = logic.getInitialSnapshot(actorScope, input);
|
|
1745
|
+
const [nextSnapshot, executableActions] = logic.initialTransition(input, actorScope);
|
|
388
1746
|
return [nextSnapshot, executableActions];
|
|
389
1747
|
}
|
|
390
1748
|
|
|
@@ -398,7 +1756,7 @@ function getMicrosteps(machine, snapshot, event) {
|
|
|
398
1756
|
const actorScope = createInertActorScope(machine);
|
|
399
1757
|
const {
|
|
400
1758
|
microsteps
|
|
401
|
-
} =
|
|
1759
|
+
} = dist_xstateActors.macrostep(snapshot, event, actorScope, []);
|
|
402
1760
|
return microsteps;
|
|
403
1761
|
}
|
|
404
1762
|
|
|
@@ -411,13 +1769,13 @@ function getMicrosteps(machine, snapshot, event) {
|
|
|
411
1769
|
*/
|
|
412
1770
|
function getInitialMicrosteps(machine, ...[input]) {
|
|
413
1771
|
const actorScope = createInertActorScope(machine);
|
|
414
|
-
const initEvent =
|
|
1772
|
+
const initEvent = dist_xstateActors.createInitEvent(input);
|
|
415
1773
|
const internalQueue = [];
|
|
416
|
-
const preInitialSnapshot = machine._getPreInitialState(actorScope, initEvent
|
|
417
|
-
const first =
|
|
1774
|
+
const preInitialSnapshot = machine._getPreInitialState(actorScope, initEvent);
|
|
1775
|
+
const first = dist_xstateActors.initialMicrostep(machine.root, preInitialSnapshot, actorScope, initEvent, internalQueue);
|
|
418
1776
|
const {
|
|
419
1777
|
microsteps
|
|
420
|
-
} =
|
|
1778
|
+
} = dist_xstateActors.macrostep(first[0], initEvent, actorScope, internalQueue);
|
|
421
1779
|
return [first, ...microsteps];
|
|
422
1780
|
}
|
|
423
1781
|
|
|
@@ -447,7 +1805,7 @@ function getInitialMicrosteps(machine, ...[input]) {
|
|
|
447
1805
|
*/
|
|
448
1806
|
function getNextTransitions(state) {
|
|
449
1807
|
const potentialTransitions = [];
|
|
450
|
-
const atomicStates = state._nodes.filter(
|
|
1808
|
+
const atomicStates = state._nodes.filter(dist_xstateActors.isAtomicStateNode);
|
|
451
1809
|
const visited = new Set();
|
|
452
1810
|
|
|
453
1811
|
// Collect all transitions from atomic states and their ancestors
|
|
@@ -455,7 +1813,7 @@ function getNextTransitions(state) {
|
|
|
455
1813
|
for (const stateNode of atomicStates) {
|
|
456
1814
|
// For each atomic state, process the state itself first, then its ancestors
|
|
457
1815
|
// This ensures child state transitions come before parent state transitions
|
|
458
|
-
for (const s of [stateNode].concat(
|
|
1816
|
+
for (const s of [stateNode].concat(dist_xstateActors.getProperAncestors(stateNode, undefined))) {
|
|
459
1817
|
if (visited.has(s.id)) {
|
|
460
1818
|
continue;
|
|
461
1819
|
}
|
|
@@ -464,7 +1822,7 @@ function getNextTransitions(state) {
|
|
|
464
1822
|
// Get all transitions for each event type
|
|
465
1823
|
// Include ALL transitions, even if the same event type appears in multiple state nodes
|
|
466
1824
|
// This is important for guarded transitions - all are "potential" regardless of guard evaluation
|
|
467
|
-
for (const [, transitions] of s.transitions) {
|
|
1825
|
+
for (const [, transitions] of s.transitions.entries()) {
|
|
468
1826
|
potentialTransitions.push(...transitions);
|
|
469
1827
|
}
|
|
470
1828
|
|
|
@@ -578,51 +1936,48 @@ function waitFor(actorRef, predicate, options) {
|
|
|
578
1936
|
});
|
|
579
1937
|
}
|
|
580
1938
|
|
|
1939
|
+
exports.Actor = dist_xstateActors.Actor;
|
|
1940
|
+
exports.TimeoutError = dist_xstateActors.TimeoutError;
|
|
1941
|
+
exports.__unsafe_getAllOwnEventDescriptors = dist_xstateActors.getAllOwnEventDescriptors;
|
|
1942
|
+
exports.checkStateIn = dist_xstateActors.checkStateIn;
|
|
1943
|
+
exports.createActor = dist_xstateActors.createActor;
|
|
1944
|
+
exports.createAsyncLogic = dist_xstateActors.createAsyncLogic;
|
|
1945
|
+
exports.createCallbackLogic = dist_xstateActors.createCallbackLogic;
|
|
581
1946
|
exports.createEmptyActor = dist_xstateActors.createEmptyActor;
|
|
582
|
-
exports.
|
|
583
|
-
exports.
|
|
584
|
-
exports.
|
|
585
|
-
exports.
|
|
586
|
-
exports.
|
|
587
|
-
exports.
|
|
588
|
-
exports.
|
|
589
|
-
exports.
|
|
590
|
-
exports.
|
|
591
|
-
exports.
|
|
592
|
-
exports.
|
|
593
|
-
exports.
|
|
594
|
-
exports.
|
|
595
|
-
exports.matchesState = dist_xstateGuards.matchesState;
|
|
596
|
-
exports.not = dist_xstateGuards.not;
|
|
597
|
-
exports.or = dist_xstateGuards.or;
|
|
598
|
-
exports.pathToStateValue = dist_xstateGuards.pathToStateValue;
|
|
599
|
-
exports.raise = dist_xstateGuards.raise;
|
|
600
|
-
exports.spawnChild = dist_xstateGuards.spawnChild;
|
|
601
|
-
exports.stateIn = dist_xstateGuards.stateIn;
|
|
602
|
-
exports.stop = dist_xstateGuards.stop;
|
|
603
|
-
exports.stopChild = dist_xstateGuards.stopChild;
|
|
604
|
-
exports.toObserver = dist_xstateGuards.toObserver;
|
|
1947
|
+
exports.createEventObservableLogic = dist_xstateActors.createEventObservableLogic;
|
|
1948
|
+
exports.createListenerLogic = dist_xstateActors.createListenerLogic;
|
|
1949
|
+
exports.createLogic = dist_xstateActors.createLogic;
|
|
1950
|
+
exports.createObservableLogic = dist_xstateActors.createObservableLogic;
|
|
1951
|
+
exports.createSubscriptionLogic = dist_xstateActors.createSubscriptionLogic;
|
|
1952
|
+
exports.getStateNodes = dist_xstateActors.getStateNodes;
|
|
1953
|
+
exports.isBuiltInExecutableAction = dist_xstateActors.isBuiltInExecutableAction;
|
|
1954
|
+
exports.isMachineSnapshot = dist_xstateActors.isMachineSnapshot;
|
|
1955
|
+
exports.listenerLogic = dist_xstateActors.listenerLogic;
|
|
1956
|
+
exports.matchesState = dist_xstateActors.matchesState;
|
|
1957
|
+
exports.pathToStateValue = dist_xstateActors.pathToStateValue;
|
|
1958
|
+
exports.subscriptionLogic = dist_xstateActors.subscriptionLogic;
|
|
1959
|
+
exports.toObserver = dist_xstateActors.toObserver;
|
|
605
1960
|
exports.StateMachine = StateMachine.StateMachine;
|
|
606
1961
|
exports.StateNode = StateMachine.StateNode;
|
|
607
|
-
exports.assign = assign.assign;
|
|
608
|
-
exports.SpecialTargets = log.SpecialTargets;
|
|
609
|
-
exports.emit = log.emit;
|
|
610
|
-
exports.enqueueActions = log.enqueueActions;
|
|
611
|
-
exports.forwardTo = log.forwardTo;
|
|
612
|
-
exports.log = log.log;
|
|
613
|
-
exports.sendParent = log.sendParent;
|
|
614
|
-
exports.sendTo = log.sendTo;
|
|
615
1962
|
exports.SimulatedClock = SimulatedClock;
|
|
1963
|
+
exports.SpecialTargets = SpecialTargets;
|
|
616
1964
|
exports.assertEvent = assertEvent;
|
|
617
1965
|
exports.createMachine = createMachine;
|
|
1966
|
+
exports.createMachineFromConfig = createMachineFromConfig;
|
|
1967
|
+
exports.createStateConfig = createStateConfig;
|
|
1968
|
+
exports.createSystem = createSystem;
|
|
618
1969
|
exports.getInitialMicrosteps = getInitialMicrosteps;
|
|
619
1970
|
exports.getInitialSnapshot = getInitialSnapshot;
|
|
620
1971
|
exports.getMicrosteps = getMicrosteps;
|
|
621
1972
|
exports.getNextSnapshot = getNextSnapshot;
|
|
622
1973
|
exports.getNextTransitions = getNextTransitions;
|
|
623
1974
|
exports.initialTransition = initialTransition;
|
|
1975
|
+
exports.isTypeSchema = isTypeSchema;
|
|
1976
|
+
exports.machineConfigToJSON = machineConfigToJSON;
|
|
624
1977
|
exports.mapState = mapState;
|
|
1978
|
+
exports.serializeMachine = serializeMachine;
|
|
625
1979
|
exports.setup = setup;
|
|
626
1980
|
exports.toPromise = toPromise;
|
|
627
1981
|
exports.transition = transition;
|
|
1982
|
+
exports.types = types;
|
|
628
1983
|
exports.waitFor = waitFor;
|