xstate 5.0.0-beta.15 → 5.0.0-beta.17
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/actions/dist/xstate-actions.cjs.js +2 -7
- package/actions/dist/xstate-actions.cjs.mjs +2 -7
- package/actions/dist/xstate-actions.development.cjs.js +2 -7
- package/actions/dist/xstate-actions.development.esm.js +1 -1
- package/actions/dist/xstate-actions.esm.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js.map +1 -1
- package/actors/dist/xstate-actors.cjs.js +1 -1
- package/actors/dist/xstate-actors.development.cjs.js +1 -1
- package/actors/dist/xstate-actors.development.esm.js +1 -1
- package/actors/dist/xstate-actors.esm.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/{actions-98f362b9.development.esm.js → actions-13190b25.development.esm.js} +1335 -1537
- package/dist/{actions-d71ac253.development.cjs.js → actions-40bd643f.development.cjs.js} +1336 -1546
- package/dist/{actions-6884fae8.esm.js → actions-4d6514d2.esm.js} +1310 -1539
- package/dist/{actions-81cc7f2b.cjs.js → actions-5fb9f10d.cjs.js} +1311 -1548
- package/dist/declarations/src/State.d.ts +1 -1
- package/dist/declarations/src/StateMachine.d.ts +2 -4
- package/dist/declarations/src/StateNode.d.ts +4 -4
- package/dist/declarations/src/actions/assign.d.ts +11 -2
- package/dist/declarations/src/actions/cancel.d.ts +14 -3
- package/dist/declarations/src/actions/choose.d.ts +11 -3
- package/dist/declarations/src/actions/log.d.ts +22 -3
- package/dist/declarations/src/actions/pure.d.ts +17 -3
- package/dist/declarations/src/actions/raise.d.ts +5 -2
- package/dist/declarations/src/actions/send.d.ts +64 -22
- package/dist/declarations/src/actions/stop.d.ts +14 -2
- package/dist/declarations/src/actions.d.ts +5 -11
- package/dist/declarations/src/constantPrefixes.d.ts +6 -0
- package/dist/declarations/src/interpreter.d.ts +8 -3
- package/dist/declarations/src/stateUtils.d.ts +4 -8
- package/dist/declarations/src/types.d.ts +38 -223
- package/dist/declarations/src/utils.d.ts +1 -6
- package/dist/xstate.cjs.js +61 -52
- package/dist/xstate.cjs.mjs +1 -1
- package/dist/xstate.development.cjs.js +61 -52
- package/dist/xstate.development.esm.js +61 -52
- package/dist/xstate.esm.js +61 -52
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/guards/dist/xstate-guards.cjs.js +1 -1
- package/guards/dist/xstate-guards.development.cjs.js +1 -1
- package/guards/dist/xstate-guards.development.esm.js +1 -1
- package/guards/dist/xstate-guards.esm.js +1 -1
- package/guards/dist/xstate-guards.umd.min.js +1 -1
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/actions/dynamicAction.ts +0 -42
- package/dist/declarations/src/actionTypes.d.ts +0 -16
- package/dist/declarations/src/constants.d.ts +0 -5
|
@@ -15,12 +15,6 @@ import { devToolsAdapter } from '../dev/dist/xstate-dev.esm.js';
|
|
|
15
15
|
|
|
16
16
|
// TODO: narrow this to logic from machine
|
|
17
17
|
|
|
18
|
-
// TODO: fix last param
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Extracts action objects that have no extra properties.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
18
|
/**
|
|
25
19
|
* The string or object representing the state value relative to the parent state node.
|
|
26
20
|
*
|
|
@@ -32,25 +26,15 @@ import { devToolsAdapter } from '../dev/dist/xstate-dev.esm.js';
|
|
|
32
26
|
|
|
33
27
|
// TODO: possibly refactor this somehow, use even a simpler type, and maybe even make `machine.options` private or something
|
|
34
28
|
|
|
35
|
-
let
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ActionTypes["Log"] = "xstate.log";
|
|
45
|
-
ActionTypes["Init"] = "xstate.init";
|
|
46
|
-
ActionTypes["Invoke"] = "xstate.invoke";
|
|
47
|
-
ActionTypes["ErrorExecution"] = "error.execution";
|
|
48
|
-
ActionTypes["ErrorCommunication"] = "error.communication";
|
|
49
|
-
ActionTypes["ErrorPlatform"] = "error.platform";
|
|
50
|
-
ActionTypes["ErrorCustom"] = "xstate.error";
|
|
51
|
-
ActionTypes["Pure"] = "xstate.pure";
|
|
52
|
-
ActionTypes["Choose"] = "xstate.choose";
|
|
53
|
-
return ActionTypes;
|
|
29
|
+
let ConstantPrefix = /*#__PURE__*/function (ConstantPrefix) {
|
|
30
|
+
ConstantPrefix["After"] = "xstate.after";
|
|
31
|
+
ConstantPrefix["DoneState"] = "done.state";
|
|
32
|
+
ConstantPrefix["DoneInvoke"] = "done.invoke";
|
|
33
|
+
ConstantPrefix["ErrorExecution"] = "error.execution";
|
|
34
|
+
ConstantPrefix["ErrorCommunication"] = "error.communication";
|
|
35
|
+
ConstantPrefix["ErrorPlatform"] = "error.platform";
|
|
36
|
+
ConstantPrefix["ErrorCustom"] = "xstate.error";
|
|
37
|
+
return ConstantPrefix;
|
|
54
38
|
}({});
|
|
55
39
|
let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
|
|
56
40
|
SpecialTargets["Parent"] = "#_parent";
|
|
@@ -58,40 +42,19 @@ let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
|
|
|
58
42
|
return SpecialTargets;
|
|
59
43
|
}({});
|
|
60
44
|
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const doneState = ActionTypes.DoneState;
|
|
69
|
-
const log$1 = ActionTypes.Log;
|
|
70
|
-
const init = ActionTypes.Init;
|
|
71
|
-
const invoke$1 = ActionTypes.Invoke;
|
|
72
|
-
const errorExecution = ActionTypes.ErrorExecution;
|
|
73
|
-
const errorPlatform = ActionTypes.ErrorPlatform;
|
|
74
|
-
const error$1 = ActionTypes.ErrorCustom;
|
|
75
|
-
const choose$1 = ActionTypes.Choose;
|
|
76
|
-
const pure$1 = ActionTypes.Pure;
|
|
77
|
-
|
|
78
|
-
var actionTypes = /*#__PURE__*/Object.freeze({
|
|
45
|
+
const after$1 = ConstantPrefix.After;
|
|
46
|
+
const doneState = ConstantPrefix.DoneState;
|
|
47
|
+
const errorExecution = ConstantPrefix.ErrorExecution;
|
|
48
|
+
const errorPlatform = ConstantPrefix.ErrorPlatform;
|
|
49
|
+
const error$1 = ConstantPrefix.ErrorCustom;
|
|
50
|
+
|
|
51
|
+
var constantPrefixes = /*#__PURE__*/Object.freeze({
|
|
79
52
|
__proto__: null,
|
|
80
|
-
stop: stop$1,
|
|
81
|
-
raise: raise$1,
|
|
82
|
-
send: send$1,
|
|
83
|
-
cancel: cancel$1,
|
|
84
|
-
assign: assign$1,
|
|
85
53
|
after: after$1,
|
|
86
54
|
doneState: doneState,
|
|
87
|
-
log: log$1,
|
|
88
|
-
init: init,
|
|
89
|
-
invoke: invoke$1,
|
|
90
55
|
errorExecution: errorExecution,
|
|
91
56
|
errorPlatform: errorPlatform,
|
|
92
|
-
error: error$1
|
|
93
|
-
choose: choose$1,
|
|
94
|
-
pure: pure$1
|
|
57
|
+
error: error$1
|
|
95
58
|
});
|
|
96
59
|
|
|
97
60
|
const STATE_DELIMITER = '.';
|
|
@@ -99,311 +62,90 @@ const TARGETLESS_KEY = '';
|
|
|
99
62
|
const NULL_EVENT = '';
|
|
100
63
|
const STATE_IDENTIFIER = '#';
|
|
101
64
|
const WILDCARD = '*';
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
function isStateLike(state) {
|
|
135
|
-
return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state;
|
|
136
|
-
}
|
|
137
|
-
function toStateValue(stateValue) {
|
|
138
|
-
if (isStateLike(stateValue)) {
|
|
139
|
-
return stateValue.value;
|
|
140
|
-
}
|
|
141
|
-
if (isArray(stateValue)) {
|
|
142
|
-
return pathToStateValue(stateValue);
|
|
143
|
-
}
|
|
144
|
-
if (typeof stateValue !== 'string') {
|
|
145
|
-
return stateValue;
|
|
146
|
-
}
|
|
147
|
-
const statePath = toStatePath(stateValue);
|
|
148
|
-
return pathToStateValue(statePath);
|
|
149
|
-
}
|
|
150
|
-
function pathToStateValue(statePath) {
|
|
151
|
-
if (statePath.length === 1) {
|
|
152
|
-
return statePath[0];
|
|
153
|
-
}
|
|
154
|
-
const value = {};
|
|
155
|
-
let marker = value;
|
|
156
|
-
for (let i = 0; i < statePath.length - 1; i++) {
|
|
157
|
-
if (i === statePath.length - 2) {
|
|
158
|
-
marker[statePath[i]] = statePath[i + 1];
|
|
65
|
+
const INIT_TYPE = 'xstate.init';
|
|
66
|
+
|
|
67
|
+
function resolve$8(actorContext, state, args, {
|
|
68
|
+
to,
|
|
69
|
+
event: eventOrExpr,
|
|
70
|
+
id,
|
|
71
|
+
delay
|
|
72
|
+
}) {
|
|
73
|
+
const delaysMap = state.machine.implementations.delays;
|
|
74
|
+
if (typeof eventOrExpr === 'string') {
|
|
75
|
+
throw new Error(`Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`);
|
|
76
|
+
}
|
|
77
|
+
const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
|
|
78
|
+
let resolvedDelay;
|
|
79
|
+
if (typeof delay === 'string') {
|
|
80
|
+
const configDelay = delaysMap && delaysMap[delay];
|
|
81
|
+
resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
|
|
82
|
+
} else {
|
|
83
|
+
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
84
|
+
}
|
|
85
|
+
const resolvedTarget = typeof to === 'function' ? to(args) : to;
|
|
86
|
+
let targetActorRef;
|
|
87
|
+
if (typeof resolvedTarget === 'string') {
|
|
88
|
+
if (resolvedTarget === SpecialTargets.Parent) {
|
|
89
|
+
targetActorRef = actorContext?.self._parent;
|
|
90
|
+
} else if (resolvedTarget === SpecialTargets.Internal) {
|
|
91
|
+
targetActorRef = actorContext?.self;
|
|
92
|
+
} else if (resolvedTarget.startsWith('#_')) {
|
|
93
|
+
// SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor
|
|
94
|
+
// #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session.
|
|
95
|
+
targetActorRef = state.children[resolvedTarget.slice(2)];
|
|
159
96
|
} else {
|
|
160
|
-
|
|
161
|
-
marker = {};
|
|
162
|
-
previous[statePath[i]] = marker;
|
|
97
|
+
targetActorRef = state.children[resolvedTarget];
|
|
163
98
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
function mapValues(collection, iteratee) {
|
|
168
|
-
const result = {};
|
|
169
|
-
const collectionKeys = Object.keys(collection);
|
|
170
|
-
for (let i = 0; i < collectionKeys.length; i++) {
|
|
171
|
-
const key = collectionKeys[i];
|
|
172
|
-
result[key] = iteratee(collection[key], key, collection, i);
|
|
173
|
-
}
|
|
174
|
-
return result;
|
|
175
|
-
}
|
|
176
|
-
function flatten(array) {
|
|
177
|
-
return [].concat(...array);
|
|
178
|
-
}
|
|
179
|
-
function toArrayStrict(value) {
|
|
180
|
-
if (isArray(value)) {
|
|
181
|
-
return value;
|
|
182
|
-
}
|
|
183
|
-
return [value];
|
|
184
|
-
}
|
|
185
|
-
function toArray(value) {
|
|
186
|
-
if (value === undefined) {
|
|
187
|
-
return [];
|
|
188
|
-
}
|
|
189
|
-
return toArrayStrict(value);
|
|
190
|
-
}
|
|
191
|
-
function mapContext(mapper, context, event) {
|
|
192
|
-
if (isFunction(mapper)) {
|
|
193
|
-
return mapper({
|
|
194
|
-
context,
|
|
195
|
-
event
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
const result = {};
|
|
199
|
-
const args = {
|
|
200
|
-
context,
|
|
201
|
-
event
|
|
202
|
-
};
|
|
203
|
-
for (const key of Object.keys(mapper)) {
|
|
204
|
-
const subMapper = mapper[key];
|
|
205
|
-
if (isFunction(subMapper)) {
|
|
206
|
-
result[key] = subMapper(args);
|
|
207
|
-
} else {
|
|
208
|
-
result[key] = subMapper;
|
|
99
|
+
if (!targetActorRef) {
|
|
100
|
+
throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${state.machine.id}'.`);
|
|
209
101
|
}
|
|
102
|
+
} else {
|
|
103
|
+
targetActorRef = resolvedTarget || actorContext?.self;
|
|
210
104
|
}
|
|
211
|
-
return
|
|
105
|
+
return [state, {
|
|
106
|
+
to: targetActorRef,
|
|
107
|
+
event: resolvedEvent,
|
|
108
|
+
id,
|
|
109
|
+
delay: resolvedDelay
|
|
110
|
+
}];
|
|
212
111
|
}
|
|
213
|
-
function
|
|
214
|
-
if (
|
|
215
|
-
|
|
112
|
+
function execute$5(actorContext, params) {
|
|
113
|
+
if (typeof params.delay === 'number') {
|
|
114
|
+
actorContext.self.delaySend(params);
|
|
115
|
+
return;
|
|
216
116
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// tslint:disable-next-line:ban-types
|
|
228
|
-
function isFunction(value) {
|
|
229
|
-
return typeof value === 'function';
|
|
230
|
-
}
|
|
231
|
-
function isString(value) {
|
|
232
|
-
return typeof value === 'string';
|
|
233
|
-
}
|
|
234
|
-
function isErrorEvent(event) {
|
|
235
|
-
return typeof event.type === 'string' && (event.type === errorExecution || event.type.startsWith(errorPlatform));
|
|
236
|
-
}
|
|
237
|
-
function toTransitionConfigArray(event, configLike) {
|
|
238
|
-
const transitions = toArrayStrict(configLike).map(transitionLike => {
|
|
239
|
-
if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
|
|
240
|
-
return {
|
|
241
|
-
target: transitionLike,
|
|
242
|
-
event
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
return {
|
|
246
|
-
...transitionLike,
|
|
247
|
-
event
|
|
248
|
-
};
|
|
117
|
+
const {
|
|
118
|
+
to,
|
|
119
|
+
event
|
|
120
|
+
} = params;
|
|
121
|
+
actorContext.defer(() => {
|
|
122
|
+
to.send(event.type === error$1 ? {
|
|
123
|
+
type: `${error(actorContext.self.id)}`,
|
|
124
|
+
data: event.data
|
|
125
|
+
} : event);
|
|
249
126
|
});
|
|
250
|
-
return transitions;
|
|
251
|
-
}
|
|
252
|
-
function normalizeTarget(target) {
|
|
253
|
-
if (target === undefined || target === TARGETLESS_KEY) {
|
|
254
|
-
return undefined;
|
|
255
|
-
}
|
|
256
|
-
return toArray(target);
|
|
257
|
-
}
|
|
258
|
-
function toInvokeConfig(invocable, id) {
|
|
259
|
-
if (typeof invocable === 'object') {
|
|
260
|
-
if ('src' in invocable) {
|
|
261
|
-
return invocable;
|
|
262
|
-
}
|
|
263
|
-
if ('transition' in invocable) {
|
|
264
|
-
return {
|
|
265
|
-
id,
|
|
266
|
-
src: invocable
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return {
|
|
271
|
-
id,
|
|
272
|
-
src: invocable
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
function toObserver(nextHandler, errorHandler, completionHandler) {
|
|
276
|
-
const noop = () => {};
|
|
277
|
-
const isObserver = typeof nextHandler === 'object';
|
|
278
|
-
const self = isObserver ? nextHandler : null;
|
|
279
|
-
return {
|
|
280
|
-
next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
|
|
281
|
-
error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
|
|
282
|
-
complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
function createInvokeId(stateNodeId, index) {
|
|
286
|
-
return `${stateNodeId}:invocation[${index}]`;
|
|
287
|
-
}
|
|
288
|
-
function resolveReferencedActor(referenced) {
|
|
289
|
-
return referenced ? 'transition' in referenced ? {
|
|
290
|
-
src: referenced,
|
|
291
|
-
input: undefined
|
|
292
|
-
} : referenced : undefined;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function createDynamicAction(action, resolve) {
|
|
296
|
-
return {
|
|
297
|
-
type: action.type,
|
|
298
|
-
params: action.params,
|
|
299
|
-
resolve
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
function isDynamicAction(action) {
|
|
303
|
-
return typeof action === 'object' && action !== null && 'resolve' in action;
|
|
304
127
|
}
|
|
305
128
|
|
|
306
129
|
/**
|
|
307
|
-
* Sends an event
|
|
308
|
-
* send the event in the next step, after the current step is finished executing.
|
|
309
|
-
*
|
|
310
|
-
* @deprecated Use the `sendTo(...)` action creator instead.
|
|
130
|
+
* Sends an event to an actor.
|
|
311
131
|
*
|
|
312
|
-
* @param
|
|
313
|
-
* @param
|
|
132
|
+
* @param actor The `ActorRef` to send the event to.
|
|
133
|
+
* @param event The event to send, or an expression that evaluates to the event to send
|
|
134
|
+
* @param options Send action options
|
|
314
135
|
* - `id` - The unique send event identifier (used with `cancel()`).
|
|
315
136
|
* - `delay` - The number of milliseconds to delay the sending of the event.
|
|
316
|
-
* - `to` - The target of this event (by default, the machine the event was sent from).
|
|
317
137
|
*/
|
|
318
|
-
function
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
state
|
|
330
|
-
}) => {
|
|
331
|
-
const params = {
|
|
332
|
-
to: options ? options.to : undefined,
|
|
333
|
-
delay: options ? options.delay : undefined,
|
|
334
|
-
event: eventOrExpr,
|
|
335
|
-
// TODO: don't auto-generate IDs here like that
|
|
336
|
-
// there is too big chance of the ID collision
|
|
337
|
-
id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
|
|
338
|
-
};
|
|
339
|
-
const args = {
|
|
340
|
-
context: state.context,
|
|
341
|
-
event,
|
|
342
|
-
self: actorContext?.self ?? null,
|
|
343
|
-
system: actorContext?.system
|
|
344
|
-
};
|
|
345
|
-
const delaysMap = state.machine.implementations.delays;
|
|
346
|
-
|
|
347
|
-
// TODO: helper function for resolving Expr
|
|
348
|
-
if (typeof eventOrExpr === 'string') {
|
|
349
|
-
throw new Error(`Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`);
|
|
350
|
-
}
|
|
351
|
-
const resolvedEvent = isFunction(eventOrExpr) ? eventOrExpr(args) : eventOrExpr;
|
|
352
|
-
let resolvedDelay;
|
|
353
|
-
if (isString(params.delay)) {
|
|
354
|
-
const configDelay = delaysMap && delaysMap[params.delay];
|
|
355
|
-
resolvedDelay = isFunction(configDelay) ? configDelay(args) : configDelay;
|
|
356
|
-
} else {
|
|
357
|
-
resolvedDelay = isFunction(params.delay) ? params.delay(args) : params.delay;
|
|
358
|
-
}
|
|
359
|
-
const resolvedTarget = isFunction(params.to) ? params.to(args) : params.to;
|
|
360
|
-
let targetActorRef;
|
|
361
|
-
if (typeof resolvedTarget === 'string') {
|
|
362
|
-
if (resolvedTarget === SpecialTargets.Parent) {
|
|
363
|
-
targetActorRef = actorContext?.self._parent;
|
|
364
|
-
} else if (resolvedTarget === SpecialTargets.Internal) {
|
|
365
|
-
targetActorRef = actorContext?.self;
|
|
366
|
-
} else if (resolvedTarget.startsWith('#_')) {
|
|
367
|
-
// SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor
|
|
368
|
-
// #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session.
|
|
369
|
-
targetActorRef = state.children[resolvedTarget.slice(2)];
|
|
370
|
-
} else {
|
|
371
|
-
targetActorRef = state.children[resolvedTarget];
|
|
372
|
-
}
|
|
373
|
-
if (!targetActorRef) {
|
|
374
|
-
throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${state.machine.id}'.`);
|
|
375
|
-
}
|
|
376
|
-
} else {
|
|
377
|
-
targetActorRef = resolvedTarget || actorContext?.self;
|
|
378
|
-
}
|
|
379
|
-
const resolvedAction = {
|
|
380
|
-
type: send$1,
|
|
381
|
-
params: {
|
|
382
|
-
...params,
|
|
383
|
-
to: targetActorRef,
|
|
384
|
-
event: resolvedEvent,
|
|
385
|
-
delay: resolvedDelay,
|
|
386
|
-
internal: resolvedTarget === SpecialTargets.Internal
|
|
387
|
-
},
|
|
388
|
-
execute: actorCtx => {
|
|
389
|
-
const sendAction = resolvedAction;
|
|
390
|
-
if (typeof sendAction.params.delay === 'number') {
|
|
391
|
-
actorCtx.self.delaySend(sendAction);
|
|
392
|
-
return;
|
|
393
|
-
} else {
|
|
394
|
-
const target = sendAction.params.to;
|
|
395
|
-
const sentEvent = sendAction.params.event;
|
|
396
|
-
actorCtx.defer(() => {
|
|
397
|
-
target.send(sentEvent.type === error$1 ? {
|
|
398
|
-
type: `${error(actorCtx.self.id)}`,
|
|
399
|
-
data: sentEvent.data
|
|
400
|
-
} : sendAction.params.event);
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
return [state, resolvedAction];
|
|
406
|
-
});
|
|
138
|
+
function sendTo(to, eventOrExpr, options) {
|
|
139
|
+
function sendTo(_) {
|
|
140
|
+
}
|
|
141
|
+
sendTo.type = 'xstate.sendTo';
|
|
142
|
+
sendTo.to = to;
|
|
143
|
+
sendTo.event = eventOrExpr;
|
|
144
|
+
sendTo.id = options?.id;
|
|
145
|
+
sendTo.delay = options?.delay;
|
|
146
|
+
sendTo.resolve = resolve$8;
|
|
147
|
+
sendTo.execute = execute$5;
|
|
148
|
+
return sendTo;
|
|
407
149
|
}
|
|
408
150
|
|
|
409
151
|
/**
|
|
@@ -413,12 +155,8 @@ function send(eventOrExpr, options) {
|
|
|
413
155
|
* @param options Options to pass into the send event.
|
|
414
156
|
*/
|
|
415
157
|
function sendParent(event, options) {
|
|
416
|
-
return
|
|
417
|
-
...options,
|
|
418
|
-
to: SpecialTargets.Parent
|
|
419
|
-
});
|
|
158
|
+
return sendTo(SpecialTargets.Parent, event, options);
|
|
420
159
|
}
|
|
421
|
-
|
|
422
160
|
/**
|
|
423
161
|
* Forwards (sends) an event to a specified service.
|
|
424
162
|
*
|
|
@@ -426,12 +164,9 @@ function sendParent(event, options) {
|
|
|
426
164
|
* @param options Options to pass into the send action creator.
|
|
427
165
|
*/
|
|
428
166
|
function forwardTo(target, options) {
|
|
429
|
-
return
|
|
167
|
+
return sendTo(target, ({
|
|
430
168
|
event
|
|
431
|
-
}) => event,
|
|
432
|
-
...options,
|
|
433
|
-
to: target
|
|
434
|
-
});
|
|
169
|
+
}) => event, options);
|
|
435
170
|
}
|
|
436
171
|
|
|
437
172
|
/**
|
|
@@ -445,27 +180,9 @@ function escalate(errorData, options) {
|
|
|
445
180
|
return sendParent(arg => {
|
|
446
181
|
return {
|
|
447
182
|
type: error$1,
|
|
448
|
-
data:
|
|
183
|
+
data: typeof errorData === 'function' ? errorData(arg) : errorData
|
|
449
184
|
};
|
|
450
|
-
},
|
|
451
|
-
...options,
|
|
452
|
-
to: SpecialTargets.Parent
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Sends an event to an actor.
|
|
458
|
-
*
|
|
459
|
-
* @param actor The `ActorRef` to send the event to.
|
|
460
|
-
* @param event The event to send, or an expression that evaluates to the event to send
|
|
461
|
-
* @param options Send action options
|
|
462
|
-
* @returns An XState send action object
|
|
463
|
-
*/
|
|
464
|
-
function sendTo(actor, event, options) {
|
|
465
|
-
return send(event, {
|
|
466
|
-
...options,
|
|
467
|
-
to: actor
|
|
468
|
-
});
|
|
185
|
+
}, options);
|
|
469
186
|
}
|
|
470
187
|
|
|
471
188
|
const cache = new WeakMap();
|
|
@@ -482,6 +199,16 @@ function memo(object, key, fn) {
|
|
|
482
199
|
return memoizedData[key];
|
|
483
200
|
}
|
|
484
201
|
|
|
202
|
+
function resolve$7(_, state, actionArgs, {
|
|
203
|
+
sendId
|
|
204
|
+
}) {
|
|
205
|
+
const resolvedSendId = typeof sendId === 'function' ? sendId(actionArgs) : sendId;
|
|
206
|
+
return [state, resolvedSendId];
|
|
207
|
+
}
|
|
208
|
+
function execute$4(actorContext, resolvedSendId) {
|
|
209
|
+
actorContext.self.cancel(resolvedSendId);
|
|
210
|
+
}
|
|
211
|
+
|
|
485
212
|
/**
|
|
486
213
|
* Cancels an in-flight `send(...)` action. A canceled sent action will not
|
|
487
214
|
* be executed, nor will its event be sent, unless it has already been sent
|
|
@@ -489,38 +216,16 @@ function memo(object, key, fn) {
|
|
|
489
216
|
*
|
|
490
217
|
* @param sendId The `id` of the `send(...)` action to cancel.
|
|
491
218
|
*/
|
|
492
|
-
|
|
493
219
|
function cancel(sendId) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
actorContext
|
|
502
|
-
}) => {
|
|
503
|
-
const resolvedSendId = isFunction(sendId) ? sendId({
|
|
504
|
-
context: state.context,
|
|
505
|
-
event,
|
|
506
|
-
self: actorContext?.self ?? {},
|
|
507
|
-
system: actorContext?.system
|
|
508
|
-
}) : sendId;
|
|
509
|
-
return [state, {
|
|
510
|
-
type: 'xstate.cancel',
|
|
511
|
-
params: {
|
|
512
|
-
sendId: resolvedSendId
|
|
513
|
-
},
|
|
514
|
-
execute: actorCtx => {
|
|
515
|
-
const interpreter = actorCtx.self;
|
|
516
|
-
interpreter.cancel(resolvedSendId);
|
|
517
|
-
}
|
|
518
|
-
}];
|
|
519
|
-
});
|
|
220
|
+
function cancel(_) {
|
|
221
|
+
}
|
|
222
|
+
cancel.type = 'xstate.cancel';
|
|
223
|
+
cancel.sendId = sendId;
|
|
224
|
+
cancel.resolve = resolve$7;
|
|
225
|
+
cancel.execute = execute$4;
|
|
226
|
+
return cancel;
|
|
520
227
|
}
|
|
521
228
|
|
|
522
|
-
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
523
|
-
|
|
524
229
|
class Mailbox {
|
|
525
230
|
constructor(_process) {
|
|
526
231
|
this._process = _process;
|
|
@@ -588,526 +293,150 @@ class Mailbox {
|
|
|
588
293
|
}
|
|
589
294
|
}
|
|
590
295
|
|
|
591
|
-
function
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
reverseKeyedActors.delete(actorRef);
|
|
608
|
-
}
|
|
296
|
+
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Returns actor logic from a transition function and its initial state.
|
|
300
|
+
*
|
|
301
|
+
* A transition function is a function that takes the current state and an event and returns the next state.
|
|
302
|
+
*
|
|
303
|
+
* @param transition The transition function that returns the next state given the current state and event.
|
|
304
|
+
* @param initialState The initial state of the transition function.
|
|
305
|
+
* @returns Actor logic
|
|
306
|
+
*/
|
|
307
|
+
function fromTransition(transition, initialState) {
|
|
308
|
+
const logic = {
|
|
309
|
+
config: transition,
|
|
310
|
+
transition: (state, event, actorContext) => {
|
|
311
|
+
return transition(state, event, actorContext);
|
|
609
312
|
},
|
|
610
|
-
|
|
611
|
-
return
|
|
313
|
+
getInitialState: (_, input) => {
|
|
314
|
+
return typeof initialState === 'function' ? initialState({
|
|
315
|
+
input
|
|
316
|
+
}) : initialState;
|
|
612
317
|
},
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
617
|
-
}
|
|
618
|
-
keyedActors.set(systemId, actorRef);
|
|
619
|
-
reverseKeyedActors.set(actorRef, systemId);
|
|
620
|
-
}
|
|
318
|
+
getSnapshot: state => state,
|
|
319
|
+
getPersistedState: state => state,
|
|
320
|
+
restoreState: state => state
|
|
621
321
|
};
|
|
622
|
-
return
|
|
322
|
+
return logic;
|
|
623
323
|
}
|
|
624
324
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
325
|
+
const resolveEventType = '$$xstate.resolve';
|
|
326
|
+
const rejectEventType = '$$xstate.reject';
|
|
327
|
+
function fromPromise(
|
|
328
|
+
// TODO: add types
|
|
329
|
+
promiseCreator) {
|
|
330
|
+
// TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
|
|
331
|
+
const logic = {
|
|
332
|
+
config: promiseCreator,
|
|
333
|
+
transition: (state, event) => {
|
|
334
|
+
if (state.status !== 'active') {
|
|
335
|
+
return state;
|
|
336
|
+
}
|
|
337
|
+
switch (event.type) {
|
|
338
|
+
case resolveEventType:
|
|
339
|
+
return {
|
|
340
|
+
...state,
|
|
341
|
+
status: 'done',
|
|
342
|
+
data: event.data,
|
|
343
|
+
input: undefined
|
|
344
|
+
};
|
|
345
|
+
case rejectEventType:
|
|
346
|
+
return {
|
|
347
|
+
...state,
|
|
348
|
+
status: 'error',
|
|
349
|
+
data: event.data,
|
|
350
|
+
input: undefined
|
|
351
|
+
};
|
|
352
|
+
case stopSignalType:
|
|
353
|
+
return {
|
|
354
|
+
...state,
|
|
355
|
+
status: 'canceled',
|
|
356
|
+
input: undefined
|
|
357
|
+
};
|
|
358
|
+
default:
|
|
359
|
+
return state;
|
|
360
|
+
}
|
|
636
361
|
},
|
|
637
|
-
|
|
638
|
-
return clearTimeout(id);
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
logger: console.log.bind(console),
|
|
642
|
-
devTools: false
|
|
643
|
-
};
|
|
644
|
-
class Interpreter {
|
|
645
|
-
/**
|
|
646
|
-
* The current state of the interpreted logic.
|
|
647
|
-
*/
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
|
|
651
|
-
*/
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* The unique identifier for this actor relative to its parent.
|
|
655
|
-
*/
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* Whether the service is started.
|
|
659
|
-
*/
|
|
660
|
-
|
|
661
|
-
// Actor Ref
|
|
662
|
-
|
|
663
|
-
// TODO: add typings for system
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* The globally unique process ID for this invocation.
|
|
667
|
-
*/
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
|
|
671
|
-
*
|
|
672
|
-
* @param logic The logic to be interpreted
|
|
673
|
-
* @param options Interpreter options
|
|
674
|
-
*/
|
|
675
|
-
constructor(logic, options) {
|
|
676
|
-
this.logic = logic;
|
|
677
|
-
this._state = void 0;
|
|
678
|
-
this.clock = void 0;
|
|
679
|
-
this.options = void 0;
|
|
680
|
-
this.id = void 0;
|
|
681
|
-
this.mailbox = new Mailbox(this._process.bind(this));
|
|
682
|
-
this.delayedEventsMap = {};
|
|
683
|
-
this.observers = new Set();
|
|
684
|
-
this.logger = void 0;
|
|
685
|
-
this.status = ActorStatus.NotStarted;
|
|
686
|
-
this._parent = void 0;
|
|
687
|
-
this.ref = void 0;
|
|
688
|
-
this._actorContext = void 0;
|
|
689
|
-
this._systemId = void 0;
|
|
690
|
-
this.sessionId = void 0;
|
|
691
|
-
this.system = void 0;
|
|
692
|
-
this._doneEvent = void 0;
|
|
693
|
-
this.src = void 0;
|
|
694
|
-
this._deferred = [];
|
|
695
|
-
const resolvedOptions = {
|
|
696
|
-
...defaultOptions,
|
|
697
|
-
...options
|
|
698
|
-
};
|
|
699
|
-
const {
|
|
700
|
-
clock,
|
|
701
|
-
logger,
|
|
702
|
-
parent,
|
|
703
|
-
id,
|
|
704
|
-
systemId
|
|
705
|
-
} = resolvedOptions;
|
|
706
|
-
const self = this;
|
|
707
|
-
this.system = parent?.system ?? createSystem();
|
|
708
|
-
if (systemId) {
|
|
709
|
-
this._systemId = systemId;
|
|
710
|
-
this.system._set(systemId, this);
|
|
711
|
-
}
|
|
712
|
-
this.sessionId = this.system._bookId();
|
|
713
|
-
this.id = id ?? this.sessionId;
|
|
714
|
-
this.logger = logger;
|
|
715
|
-
this.clock = clock;
|
|
716
|
-
this._parent = parent;
|
|
717
|
-
this.options = resolvedOptions;
|
|
718
|
-
this.src = resolvedOptions.src;
|
|
719
|
-
this.ref = this;
|
|
720
|
-
this._actorContext = {
|
|
362
|
+
start: (state, {
|
|
721
363
|
self,
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
system: this.system,
|
|
729
|
-
stopChild: child => {
|
|
730
|
-
if (child._parent !== this) {
|
|
731
|
-
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
732
|
-
}
|
|
733
|
-
child._stop();
|
|
364
|
+
system
|
|
365
|
+
}) => {
|
|
366
|
+
// TODO: determine how to allow customizing this so that promises
|
|
367
|
+
// can be restarted if necessary
|
|
368
|
+
if (state.status !== 'active') {
|
|
369
|
+
return;
|
|
734
370
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
371
|
+
const resolvedPromise = Promise.resolve(promiseCreator({
|
|
372
|
+
input: state.input,
|
|
373
|
+
system
|
|
374
|
+
}));
|
|
375
|
+
resolvedPromise.then(response => {
|
|
376
|
+
// TODO: remove this condition once dead letter queue lands
|
|
377
|
+
if (self._state.status !== 'active') {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
self.send({
|
|
381
|
+
type: resolveEventType,
|
|
382
|
+
data: response
|
|
383
|
+
});
|
|
384
|
+
}, errorData => {
|
|
385
|
+
// TODO: remove this condition once dead letter queue lands
|
|
386
|
+
if (self._state.status !== 'active') {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
self.send({
|
|
390
|
+
type: rejectEventType,
|
|
391
|
+
data: errorData
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
},
|
|
395
|
+
getInitialState: (_, input) => {
|
|
396
|
+
return {
|
|
397
|
+
status: 'active',
|
|
398
|
+
data: undefined,
|
|
399
|
+
input
|
|
400
|
+
};
|
|
401
|
+
},
|
|
402
|
+
getSnapshot: state => state.data,
|
|
403
|
+
getStatus: state => state,
|
|
404
|
+
getPersistedState: state => state,
|
|
405
|
+
restoreState: state => state
|
|
406
|
+
};
|
|
407
|
+
return logic;
|
|
408
|
+
}
|
|
747
409
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
410
|
+
// TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
|
|
411
|
+
function fromObservable(observableCreator) {
|
|
412
|
+
const nextEventType = '$$xstate.next';
|
|
413
|
+
const errorEventType = '$$xstate.error';
|
|
414
|
+
const completeEventType = '$$xstate.complete';
|
|
752
415
|
|
|
753
|
-
|
|
754
|
-
let deferredFn;
|
|
755
|
-
while (deferredFn = this._deferred.shift()) {
|
|
756
|
-
deferredFn();
|
|
757
|
-
}
|
|
758
|
-
for (const observer of this.observers) {
|
|
759
|
-
observer.next?.(snapshot);
|
|
760
|
-
}
|
|
761
|
-
const status = this.logic.getStatus?.(state);
|
|
762
|
-
switch (status?.status) {
|
|
763
|
-
case 'done':
|
|
764
|
-
this._stopProcedure();
|
|
765
|
-
this._doneEvent = doneInvoke(this.id, status.data);
|
|
766
|
-
this._parent?.send(this._doneEvent);
|
|
767
|
-
this._complete();
|
|
768
|
-
break;
|
|
769
|
-
case 'error':
|
|
770
|
-
this._stopProcedure();
|
|
771
|
-
this._parent?.send(error(this.id, status.data));
|
|
772
|
-
this._error(status.data);
|
|
773
|
-
break;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
777
|
-
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
778
|
-
this.observers.add(observer);
|
|
779
|
-
if (this.status === ActorStatus.Stopped) {
|
|
780
|
-
observer.complete?.();
|
|
781
|
-
this.observers.delete(observer);
|
|
782
|
-
}
|
|
783
|
-
return {
|
|
784
|
-
unsubscribe: () => {
|
|
785
|
-
this.observers.delete(observer);
|
|
786
|
-
}
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Starts the interpreter from the initial state
|
|
792
|
-
*/
|
|
793
|
-
start() {
|
|
794
|
-
if (this.status === ActorStatus.Running) {
|
|
795
|
-
// Do not restart the service if it is already started
|
|
796
|
-
return this;
|
|
797
|
-
}
|
|
798
|
-
this.system._register(this.sessionId, this);
|
|
799
|
-
if (this._systemId) {
|
|
800
|
-
this.system._set(this._systemId, this);
|
|
801
|
-
}
|
|
802
|
-
this.status = ActorStatus.Running;
|
|
803
|
-
if (this.logic.start) {
|
|
804
|
-
this.logic.start(this._state, this._actorContext);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
// TODO: this notifies all subscribers but usually this is redundant
|
|
808
|
-
// there is no real change happening here
|
|
809
|
-
// we need to rethink if this needs to be refactored
|
|
810
|
-
this.update(this._state);
|
|
811
|
-
if (this.options.devTools) {
|
|
812
|
-
this.attachDevTools();
|
|
813
|
-
}
|
|
814
|
-
this.mailbox.start();
|
|
815
|
-
return this;
|
|
816
|
-
}
|
|
817
|
-
_process(event) {
|
|
818
|
-
try {
|
|
819
|
-
const nextState = this.logic.transition(this._state, event, this._actorContext);
|
|
820
|
-
this.update(nextState);
|
|
821
|
-
if (event.type === stopSignalType) {
|
|
822
|
-
this._stopProcedure();
|
|
823
|
-
this._complete();
|
|
824
|
-
}
|
|
825
|
-
} catch (err) {
|
|
826
|
-
// TODO: properly handle errors
|
|
827
|
-
if (this.observers.size > 0) {
|
|
828
|
-
this.observers.forEach(observer => {
|
|
829
|
-
observer.error?.(err);
|
|
830
|
-
});
|
|
831
|
-
this.stop();
|
|
832
|
-
} else {
|
|
833
|
-
throw err;
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
_stop() {
|
|
838
|
-
if (this.status === ActorStatus.Stopped) {
|
|
839
|
-
return this;
|
|
840
|
-
}
|
|
841
|
-
this.mailbox.clear();
|
|
842
|
-
if (this.status === ActorStatus.NotStarted) {
|
|
843
|
-
this.status = ActorStatus.Stopped;
|
|
844
|
-
return this;
|
|
845
|
-
}
|
|
846
|
-
this.mailbox.enqueue({
|
|
847
|
-
type: stopSignalType
|
|
848
|
-
});
|
|
849
|
-
return this;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
/**
|
|
853
|
-
* Stops the interpreter and unsubscribe all listeners.
|
|
854
|
-
*/
|
|
855
|
-
stop() {
|
|
856
|
-
if (this._parent) {
|
|
857
|
-
throw new Error('A non-root actor cannot be stopped directly.');
|
|
858
|
-
}
|
|
859
|
-
return this._stop();
|
|
860
|
-
}
|
|
861
|
-
_complete() {
|
|
862
|
-
for (const observer of this.observers) {
|
|
863
|
-
observer.complete?.();
|
|
864
|
-
}
|
|
865
|
-
this.observers.clear();
|
|
866
|
-
}
|
|
867
|
-
_error(data) {
|
|
868
|
-
for (const observer of this.observers) {
|
|
869
|
-
observer.error?.(data);
|
|
870
|
-
}
|
|
871
|
-
this.observers.clear();
|
|
872
|
-
}
|
|
873
|
-
_stopProcedure() {
|
|
874
|
-
if (this.status !== ActorStatus.Running) {
|
|
875
|
-
// Interpreter already stopped; do nothing
|
|
876
|
-
return this;
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// Cancel all delayed events
|
|
880
|
-
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
881
|
-
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// TODO: mailbox.reset
|
|
885
|
-
this.mailbox.clear();
|
|
886
|
-
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
887
|
-
// events sent *after* stop signal must be queued
|
|
888
|
-
// it seems like this should be the common behavior for all of our consumers
|
|
889
|
-
// so perhaps this should be unified somehow for all of them
|
|
890
|
-
this.mailbox = new Mailbox(this._process.bind(this));
|
|
891
|
-
this.status = ActorStatus.Stopped;
|
|
892
|
-
this.system._unregister(this);
|
|
893
|
-
return this;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
/**
|
|
897
|
-
* Sends an event to the running interpreter to trigger a transition.
|
|
898
|
-
*
|
|
899
|
-
* @param event The event to send
|
|
900
|
-
*/
|
|
901
|
-
send(event) {
|
|
902
|
-
if (typeof event === 'string') {
|
|
903
|
-
throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
|
|
904
|
-
}
|
|
905
|
-
if (this.status === ActorStatus.Stopped) {
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
|
|
909
|
-
throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
|
|
910
|
-
// tslint:disable-next-line:max-line-length
|
|
911
|
-
}". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
|
|
912
|
-
}
|
|
913
|
-
this.mailbox.enqueue(event);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// TODO: make private (and figure out a way to do this within the machine)
|
|
917
|
-
delaySend(sendAction) {
|
|
918
|
-
this.delayedEventsMap[sendAction.params.id] = this.clock.setTimeout(() => {
|
|
919
|
-
if ('to' in sendAction.params && sendAction.params.to) {
|
|
920
|
-
sendAction.params.to.send(sendAction.params.event);
|
|
921
|
-
} else {
|
|
922
|
-
this.send(sendAction.params.event);
|
|
923
|
-
}
|
|
924
|
-
}, sendAction.params.delay);
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
// TODO: make private (and figure out a way to do this within the machine)
|
|
928
|
-
cancel(sendId) {
|
|
929
|
-
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
930
|
-
delete this.delayedEventsMap[sendId];
|
|
931
|
-
}
|
|
932
|
-
attachDevTools() {
|
|
933
|
-
const {
|
|
934
|
-
devTools
|
|
935
|
-
} = this.options;
|
|
936
|
-
if (devTools) {
|
|
937
|
-
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
|
|
938
|
-
resolvedDevToolsAdapter(this);
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
toJSON() {
|
|
942
|
-
return {
|
|
943
|
-
id: this.id
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
getPersistedState() {
|
|
947
|
-
return this.logic.getPersistedState?.(this._state);
|
|
948
|
-
}
|
|
949
|
-
[symbolObservable]() {
|
|
950
|
-
return this;
|
|
951
|
-
}
|
|
952
|
-
getSnapshot() {
|
|
953
|
-
return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
/**
|
|
958
|
-
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
959
|
-
*
|
|
960
|
-
* @param machine The machine to interpret
|
|
961
|
-
* @param options Interpreter options
|
|
962
|
-
*/
|
|
963
|
-
|
|
964
|
-
function interpret(logic, options) {
|
|
965
|
-
const interpreter = new Interpreter(logic, options);
|
|
966
|
-
return interpreter;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
/**
|
|
970
|
-
* Returns actor logic from a transition function and its initial state.
|
|
971
|
-
*
|
|
972
|
-
* A transition function is a function that takes the current state and an event and returns the next state.
|
|
973
|
-
*
|
|
974
|
-
* @param transition The transition function that returns the next state given the current state and event.
|
|
975
|
-
* @param initialState The initial state of the transition function.
|
|
976
|
-
* @returns Actor logic
|
|
977
|
-
*/
|
|
978
|
-
function fromTransition(transition, initialState) {
|
|
979
|
-
const logic = {
|
|
980
|
-
config: transition,
|
|
981
|
-
transition: (state, event, actorContext) => {
|
|
982
|
-
return transition(state, event, actorContext);
|
|
983
|
-
},
|
|
984
|
-
getInitialState: (_, input) => {
|
|
985
|
-
return typeof initialState === 'function' ? initialState({
|
|
986
|
-
input
|
|
987
|
-
}) : initialState;
|
|
988
|
-
},
|
|
989
|
-
getSnapshot: state => state,
|
|
990
|
-
getPersistedState: state => state,
|
|
991
|
-
restoreState: state => state
|
|
992
|
-
};
|
|
993
|
-
return logic;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
const resolveEventType = '$$xstate.resolve';
|
|
997
|
-
const rejectEventType = '$$xstate.reject';
|
|
998
|
-
function fromPromise(
|
|
999
|
-
// TODO: add types
|
|
1000
|
-
promiseCreator) {
|
|
1001
|
-
// TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
|
|
416
|
+
// TODO: add event types
|
|
1002
417
|
const logic = {
|
|
1003
|
-
config:
|
|
1004
|
-
transition: (state, event
|
|
418
|
+
config: observableCreator,
|
|
419
|
+
transition: (state, event, {
|
|
420
|
+
self,
|
|
421
|
+
id,
|
|
422
|
+
defer
|
|
423
|
+
}) => {
|
|
1005
424
|
if (state.status !== 'active') {
|
|
1006
425
|
return state;
|
|
1007
426
|
}
|
|
1008
427
|
switch (event.type) {
|
|
1009
|
-
case
|
|
428
|
+
case nextEventType:
|
|
429
|
+
// match the exact timing of events sent by machines
|
|
430
|
+
// send actions are not executed immediately
|
|
431
|
+
defer(() => {
|
|
432
|
+
self._parent?.send({
|
|
433
|
+
type: `xstate.snapshot.${id}`,
|
|
434
|
+
data: event.data
|
|
435
|
+
});
|
|
436
|
+
});
|
|
1010
437
|
return {
|
|
1011
438
|
...state,
|
|
1012
|
-
|
|
1013
|
-
data: event.data,
|
|
1014
|
-
input: undefined
|
|
1015
|
-
};
|
|
1016
|
-
case rejectEventType:
|
|
1017
|
-
return {
|
|
1018
|
-
...state,
|
|
1019
|
-
status: 'error',
|
|
1020
|
-
data: event.data,
|
|
1021
|
-
input: undefined
|
|
1022
|
-
};
|
|
1023
|
-
case stopSignalType:
|
|
1024
|
-
return {
|
|
1025
|
-
...state,
|
|
1026
|
-
status: 'canceled',
|
|
1027
|
-
input: undefined
|
|
1028
|
-
};
|
|
1029
|
-
default:
|
|
1030
|
-
return state;
|
|
1031
|
-
}
|
|
1032
|
-
},
|
|
1033
|
-
start: (state, {
|
|
1034
|
-
self,
|
|
1035
|
-
system
|
|
1036
|
-
}) => {
|
|
1037
|
-
// TODO: determine how to allow customizing this so that promises
|
|
1038
|
-
// can be restarted if necessary
|
|
1039
|
-
if (state.status !== 'active') {
|
|
1040
|
-
return;
|
|
1041
|
-
}
|
|
1042
|
-
const resolvedPromise = Promise.resolve(promiseCreator({
|
|
1043
|
-
input: state.input,
|
|
1044
|
-
system
|
|
1045
|
-
}));
|
|
1046
|
-
resolvedPromise.then(response => {
|
|
1047
|
-
// TODO: remove this condition once dead letter queue lands
|
|
1048
|
-
if (self._state.status !== 'active') {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
self.send({
|
|
1052
|
-
type: resolveEventType,
|
|
1053
|
-
data: response
|
|
1054
|
-
});
|
|
1055
|
-
}, errorData => {
|
|
1056
|
-
// TODO: remove this condition once dead letter queue lands
|
|
1057
|
-
if (self._state.status !== 'active') {
|
|
1058
|
-
return;
|
|
1059
|
-
}
|
|
1060
|
-
self.send({
|
|
1061
|
-
type: rejectEventType,
|
|
1062
|
-
data: errorData
|
|
1063
|
-
});
|
|
1064
|
-
});
|
|
1065
|
-
},
|
|
1066
|
-
getInitialState: (_, input) => {
|
|
1067
|
-
return {
|
|
1068
|
-
status: 'active',
|
|
1069
|
-
data: undefined,
|
|
1070
|
-
input
|
|
1071
|
-
};
|
|
1072
|
-
},
|
|
1073
|
-
getSnapshot: state => state.data,
|
|
1074
|
-
getStatus: state => state,
|
|
1075
|
-
getPersistedState: state => state,
|
|
1076
|
-
restoreState: state => state
|
|
1077
|
-
};
|
|
1078
|
-
return logic;
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
// TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
|
|
1082
|
-
function fromObservable(observableCreator) {
|
|
1083
|
-
const nextEventType = '$$xstate.next';
|
|
1084
|
-
const errorEventType = '$$xstate.error';
|
|
1085
|
-
const completeEventType = '$$xstate.complete';
|
|
1086
|
-
|
|
1087
|
-
// TODO: add event types
|
|
1088
|
-
const logic = {
|
|
1089
|
-
config: observableCreator,
|
|
1090
|
-
transition: (state, event, {
|
|
1091
|
-
self,
|
|
1092
|
-
id,
|
|
1093
|
-
defer
|
|
1094
|
-
}) => {
|
|
1095
|
-
if (state.status !== 'active') {
|
|
1096
|
-
return state;
|
|
1097
|
-
}
|
|
1098
|
-
switch (event.type) {
|
|
1099
|
-
case nextEventType:
|
|
1100
|
-
// match the exact timing of events sent by machines
|
|
1101
|
-
// send actions are not executed immediately
|
|
1102
|
-
defer(() => {
|
|
1103
|
-
self._parent?.send({
|
|
1104
|
-
type: `xstate.snapshot.${id}`,
|
|
1105
|
-
data: event.data
|
|
1106
|
-
});
|
|
1107
|
-
});
|
|
1108
|
-
return {
|
|
1109
|
-
...state,
|
|
1110
|
-
data: event.data
|
|
439
|
+
data: event.data
|
|
1111
440
|
};
|
|
1112
441
|
case errorEventType:
|
|
1113
442
|
return {
|
|
@@ -1297,205 +626,759 @@ function fromEventObservable(lazyObservable) {
|
|
|
1297
626
|
return logic;
|
|
1298
627
|
}
|
|
1299
628
|
|
|
1300
|
-
function
|
|
1301
|
-
const
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
629
|
+
function matchesState(parentStateId, childStateId) {
|
|
630
|
+
const parentStateValue = toStateValue(parentStateId);
|
|
631
|
+
const childStateValue = toStateValue(childStateId);
|
|
632
|
+
if (typeof childStateValue === 'string') {
|
|
633
|
+
if (typeof parentStateValue === 'string') {
|
|
634
|
+
return childStateValue === parentStateValue;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Parent more specific than child
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
if (typeof parentStateValue === 'string') {
|
|
641
|
+
return parentStateValue in childStateValue;
|
|
642
|
+
}
|
|
643
|
+
return Object.keys(parentStateValue).every(key => {
|
|
644
|
+
if (!(key in childStateValue)) {
|
|
645
|
+
return false;
|
|
646
|
+
}
|
|
647
|
+
return matchesState(parentStateValue[key], childStateValue[key]);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
function toStatePath(stateId) {
|
|
651
|
+
try {
|
|
652
|
+
if (isArray(stateId)) {
|
|
653
|
+
return stateId;
|
|
654
|
+
}
|
|
655
|
+
return stateId.toString().split(STATE_DELIMITER);
|
|
656
|
+
} catch (e) {
|
|
657
|
+
throw new Error(`'${stateId}' is not a valid state path.`);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
function isStateLike(state) {
|
|
661
|
+
return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state;
|
|
662
|
+
}
|
|
663
|
+
function toStateValue(stateValue) {
|
|
664
|
+
if (isStateLike(stateValue)) {
|
|
665
|
+
return stateValue.value;
|
|
666
|
+
}
|
|
667
|
+
if (isArray(stateValue)) {
|
|
668
|
+
return pathToStateValue(stateValue);
|
|
669
|
+
}
|
|
670
|
+
if (typeof stateValue !== 'string') {
|
|
671
|
+
return stateValue;
|
|
672
|
+
}
|
|
673
|
+
const statePath = toStatePath(stateValue);
|
|
674
|
+
return pathToStateValue(statePath);
|
|
675
|
+
}
|
|
676
|
+
function pathToStateValue(statePath) {
|
|
677
|
+
if (statePath.length === 1) {
|
|
678
|
+
return statePath[0];
|
|
679
|
+
}
|
|
680
|
+
const value = {};
|
|
681
|
+
let marker = value;
|
|
682
|
+
for (let i = 0; i < statePath.length - 1; i++) {
|
|
683
|
+
if (i === statePath.length - 2) {
|
|
684
|
+
marker[statePath[i]] = statePath[i + 1];
|
|
685
|
+
} else {
|
|
686
|
+
const previous = marker;
|
|
687
|
+
marker = {};
|
|
688
|
+
previous[statePath[i]] = marker;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return value;
|
|
692
|
+
}
|
|
693
|
+
function mapValues(collection, iteratee) {
|
|
694
|
+
const result = {};
|
|
695
|
+
const collectionKeys = Object.keys(collection);
|
|
696
|
+
for (let i = 0; i < collectionKeys.length; i++) {
|
|
697
|
+
const key = collectionKeys[i];
|
|
698
|
+
result[key] = iteratee(collection[key], key, collection, i);
|
|
699
|
+
}
|
|
700
|
+
return result;
|
|
701
|
+
}
|
|
702
|
+
function flatten(array) {
|
|
703
|
+
return [].concat(...array);
|
|
704
|
+
}
|
|
705
|
+
function toArrayStrict(value) {
|
|
706
|
+
if (isArray(value)) {
|
|
707
|
+
return value;
|
|
708
|
+
}
|
|
709
|
+
return [value];
|
|
710
|
+
}
|
|
711
|
+
function toArray(value) {
|
|
712
|
+
if (value === undefined) {
|
|
713
|
+
return [];
|
|
714
|
+
}
|
|
715
|
+
return toArrayStrict(value);
|
|
716
|
+
}
|
|
717
|
+
function mapContext(mapper, context, event) {
|
|
718
|
+
if (typeof mapper === 'function') {
|
|
719
|
+
return mapper({
|
|
720
|
+
context,
|
|
721
|
+
event
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
const result = {};
|
|
725
|
+
const args = {
|
|
726
|
+
context,
|
|
727
|
+
event
|
|
728
|
+
};
|
|
729
|
+
for (const key of Object.keys(mapper)) {
|
|
730
|
+
const subMapper = mapper[key];
|
|
731
|
+
if (typeof subMapper === 'function') {
|
|
732
|
+
result[key] = subMapper(args);
|
|
733
|
+
} else {
|
|
734
|
+
result[key] = subMapper;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return result;
|
|
738
|
+
}
|
|
739
|
+
function isPromiseLike(value) {
|
|
740
|
+
if (value instanceof Promise) {
|
|
741
|
+
return true;
|
|
742
|
+
}
|
|
743
|
+
// Check if shape matches the Promise/A+ specification for a "thenable".
|
|
744
|
+
if (value !== null && (typeof value === 'function' || typeof value === 'object') && typeof value.then === 'function') {
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
function isArray(value) {
|
|
750
|
+
return Array.isArray(value);
|
|
751
|
+
}
|
|
752
|
+
function isErrorEvent(event) {
|
|
753
|
+
return typeof event.type === 'string' && (event.type === errorExecution || event.type.startsWith(errorPlatform));
|
|
754
|
+
}
|
|
755
|
+
function toTransitionConfigArray(configLike) {
|
|
756
|
+
return toArrayStrict(configLike).map(transitionLike => {
|
|
757
|
+
if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
|
|
758
|
+
return {
|
|
759
|
+
target: transitionLike
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return transitionLike;
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
function normalizeTarget(target) {
|
|
766
|
+
if (target === undefined || target === TARGETLESS_KEY) {
|
|
767
|
+
return undefined;
|
|
768
|
+
}
|
|
769
|
+
return toArray(target);
|
|
770
|
+
}
|
|
771
|
+
function toInvokeConfig(invocable, id) {
|
|
772
|
+
if (typeof invocable === 'object') {
|
|
773
|
+
if ('src' in invocable) {
|
|
774
|
+
return invocable;
|
|
775
|
+
}
|
|
776
|
+
if ('transition' in invocable) {
|
|
777
|
+
return {
|
|
778
|
+
id,
|
|
779
|
+
src: invocable
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
id,
|
|
785
|
+
src: invocable
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
function toObserver(nextHandler, errorHandler, completionHandler) {
|
|
789
|
+
const noop = () => {};
|
|
790
|
+
const isObserver = typeof nextHandler === 'object';
|
|
791
|
+
const self = isObserver ? nextHandler : null;
|
|
792
|
+
return {
|
|
793
|
+
next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
|
|
794
|
+
error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
|
|
795
|
+
complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function createInvokeId(stateNodeId, index) {
|
|
799
|
+
return `${stateNodeId}:invocation[${index}]`;
|
|
800
|
+
}
|
|
801
|
+
function resolveReferencedActor(referenced) {
|
|
802
|
+
return referenced ? 'transition' in referenced ? {
|
|
803
|
+
src: referenced,
|
|
804
|
+
input: undefined
|
|
805
|
+
} : referenced : undefined;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
function fromCallback(invokeCallback) {
|
|
809
|
+
const logic = {
|
|
810
|
+
config: invokeCallback,
|
|
811
|
+
start: (_state, {
|
|
812
|
+
self
|
|
813
|
+
}) => {
|
|
814
|
+
self.send({
|
|
815
|
+
type: startSignalType
|
|
816
|
+
});
|
|
817
|
+
},
|
|
818
|
+
transition: (state, event, {
|
|
819
|
+
self,
|
|
820
|
+
id,
|
|
821
|
+
system
|
|
822
|
+
}) => {
|
|
823
|
+
if (event.type === startSignalType) {
|
|
824
|
+
const sender = eventForParent => {
|
|
825
|
+
if (state.canceled) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
self._parent?.send(eventForParent);
|
|
829
|
+
};
|
|
830
|
+
const receiver = newListener => {
|
|
831
|
+
state.receivers.add(newListener);
|
|
832
|
+
};
|
|
833
|
+
state.dispose = invokeCallback(sender, receiver, {
|
|
834
|
+
input: state.input,
|
|
835
|
+
system
|
|
836
|
+
});
|
|
837
|
+
if (isPromiseLike(state.dispose)) {
|
|
838
|
+
state.dispose.then(resolved => {
|
|
839
|
+
self._parent?.send(doneInvoke(id, resolved));
|
|
840
|
+
state.canceled = true;
|
|
841
|
+
}, errorData => {
|
|
842
|
+
state.canceled = true;
|
|
843
|
+
self._parent?.send(error(id, errorData));
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
return state;
|
|
847
|
+
}
|
|
848
|
+
if (event.type === stopSignalType) {
|
|
849
|
+
state.canceled = true;
|
|
850
|
+
if (typeof state.dispose === 'function') {
|
|
851
|
+
state.dispose();
|
|
852
|
+
}
|
|
853
|
+
return state;
|
|
854
|
+
}
|
|
855
|
+
if (isSignal(event)) {
|
|
856
|
+
// TODO: unrecognized signal
|
|
857
|
+
return state;
|
|
858
|
+
}
|
|
859
|
+
state.receivers.forEach(receiver => receiver(event));
|
|
860
|
+
return state;
|
|
861
|
+
},
|
|
862
|
+
getInitialState: (_, input) => {
|
|
863
|
+
return {
|
|
864
|
+
canceled: false,
|
|
865
|
+
receivers: new Set(),
|
|
866
|
+
dispose: undefined,
|
|
867
|
+
input
|
|
868
|
+
};
|
|
869
|
+
},
|
|
870
|
+
getSnapshot: () => undefined,
|
|
871
|
+
getPersistedState: ({
|
|
872
|
+
input
|
|
873
|
+
}) => input
|
|
874
|
+
};
|
|
875
|
+
return logic;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const startSignalType = 'xstate.init';
|
|
879
|
+
const stopSignalType = 'xstate.stop';
|
|
880
|
+
const startSignal = {
|
|
881
|
+
type: 'xstate.init'
|
|
882
|
+
};
|
|
883
|
+
const stopSignal = {
|
|
884
|
+
type: 'xstate.stop'
|
|
885
|
+
};
|
|
886
|
+
/**
|
|
887
|
+
* An object that expresses the actor logic in reaction to received events,
|
|
888
|
+
* as well as an optionally emitted stream of values.
|
|
889
|
+
*
|
|
890
|
+
* @template TReceived The received event
|
|
891
|
+
* @template TSnapshot The emitted value
|
|
892
|
+
*/
|
|
893
|
+
|
|
894
|
+
function isSignal(event) {
|
|
895
|
+
return event.type === startSignalType || event.type === stopSignalType;
|
|
896
|
+
}
|
|
897
|
+
function isActorRef(item) {
|
|
898
|
+
return !!item && typeof item === 'object' && typeof item.send === 'function';
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// TODO: refactor the return type, this could be written in a better way
|
|
902
|
+
// but it's best to avoid unneccessary breaking changes now
|
|
903
|
+
// @deprecated use `interpret(actorLogic)` instead
|
|
904
|
+
function toActorRef(actorRefLike) {
|
|
905
|
+
return {
|
|
906
|
+
subscribe: () => ({
|
|
907
|
+
unsubscribe: () => void 0
|
|
908
|
+
}),
|
|
909
|
+
id: 'anonymous',
|
|
910
|
+
sessionId: '',
|
|
911
|
+
getSnapshot: () => undefined,
|
|
912
|
+
[symbolObservable]: function () {
|
|
913
|
+
return this;
|
|
914
|
+
},
|
|
915
|
+
status: ActorStatus.Running,
|
|
916
|
+
stop: () => void 0,
|
|
917
|
+
...actorRefLike
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
const emptyLogic = fromTransition(_ => undefined, undefined);
|
|
921
|
+
function createEmptyActor() {
|
|
922
|
+
return interpret(emptyLogic);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function createSystem() {
|
|
926
|
+
let sessionIdCounter = 0;
|
|
927
|
+
const children = new Map();
|
|
928
|
+
const keyedActors = new Map();
|
|
929
|
+
const reverseKeyedActors = new WeakMap();
|
|
930
|
+
const system = {
|
|
931
|
+
_bookId: () => `x:${sessionIdCounter++}`,
|
|
932
|
+
_register: (sessionId, actorRef) => {
|
|
933
|
+
children.set(sessionId, actorRef);
|
|
934
|
+
return sessionId;
|
|
935
|
+
},
|
|
936
|
+
_unregister: actorRef => {
|
|
937
|
+
children.delete(actorRef.sessionId);
|
|
938
|
+
const systemId = reverseKeyedActors.get(actorRef);
|
|
939
|
+
if (systemId !== undefined) {
|
|
940
|
+
keyedActors.delete(systemId);
|
|
941
|
+
reverseKeyedActors.delete(actorRef);
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
get: systemId => {
|
|
945
|
+
return keyedActors.get(systemId);
|
|
946
|
+
},
|
|
947
|
+
_set: (systemId, actorRef) => {
|
|
948
|
+
const existing = keyedActors.get(systemId);
|
|
949
|
+
if (existing && existing !== actorRef) {
|
|
950
|
+
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
951
|
+
}
|
|
952
|
+
keyedActors.set(systemId, actorRef);
|
|
953
|
+
reverseKeyedActors.set(actorRef, systemId);
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
return system;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
let ActorStatus = /*#__PURE__*/function (ActorStatus) {
|
|
960
|
+
ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
|
|
961
|
+
ActorStatus[ActorStatus["Running"] = 1] = "Running";
|
|
962
|
+
ActorStatus[ActorStatus["Stopped"] = 2] = "Stopped";
|
|
963
|
+
return ActorStatus;
|
|
964
|
+
}({});
|
|
965
|
+
const defaultOptions = {
|
|
966
|
+
deferEvents: true,
|
|
967
|
+
clock: {
|
|
968
|
+
setTimeout: (fn, ms) => {
|
|
969
|
+
return setTimeout(fn, ms);
|
|
970
|
+
},
|
|
971
|
+
clearTimeout: id => {
|
|
972
|
+
return clearTimeout(id);
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
logger: console.log.bind(console),
|
|
976
|
+
devTools: false
|
|
977
|
+
};
|
|
978
|
+
class Interpreter {
|
|
979
|
+
/**
|
|
980
|
+
* The current state of the interpreted logic.
|
|
981
|
+
*/
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
|
|
985
|
+
*/
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* The unique identifier for this actor relative to its parent.
|
|
989
|
+
*/
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Whether the service is started.
|
|
993
|
+
*/
|
|
994
|
+
|
|
995
|
+
// Actor Ref
|
|
996
|
+
|
|
997
|
+
// TODO: add typings for system
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* The globally unique process ID for this invocation.
|
|
1001
|
+
*/
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
|
|
1005
|
+
*
|
|
1006
|
+
* @param logic The logic to be interpreted
|
|
1007
|
+
* @param options Interpreter options
|
|
1008
|
+
*/
|
|
1009
|
+
constructor(logic, options) {
|
|
1010
|
+
this.logic = logic;
|
|
1011
|
+
this._state = void 0;
|
|
1012
|
+
this.clock = void 0;
|
|
1013
|
+
this.options = void 0;
|
|
1014
|
+
this.id = void 0;
|
|
1015
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
1016
|
+
this.delayedEventsMap = {};
|
|
1017
|
+
this.observers = new Set();
|
|
1018
|
+
this.logger = void 0;
|
|
1019
|
+
this.status = ActorStatus.NotStarted;
|
|
1020
|
+
this._parent = void 0;
|
|
1021
|
+
this.ref = void 0;
|
|
1022
|
+
this._actorContext = void 0;
|
|
1023
|
+
this._systemId = void 0;
|
|
1024
|
+
this.sessionId = void 0;
|
|
1025
|
+
this.system = void 0;
|
|
1026
|
+
this._doneEvent = void 0;
|
|
1027
|
+
this.src = void 0;
|
|
1028
|
+
this._deferred = [];
|
|
1029
|
+
const resolvedOptions = {
|
|
1030
|
+
...defaultOptions,
|
|
1031
|
+
...options
|
|
1032
|
+
};
|
|
1033
|
+
const {
|
|
1034
|
+
clock,
|
|
1035
|
+
logger,
|
|
1036
|
+
parent,
|
|
1037
|
+
id,
|
|
1038
|
+
systemId
|
|
1039
|
+
} = resolvedOptions;
|
|
1040
|
+
const self = this;
|
|
1041
|
+
this.system = parent?.system ?? createSystem();
|
|
1042
|
+
if (systemId) {
|
|
1043
|
+
this._systemId = systemId;
|
|
1044
|
+
this.system._set(systemId, this);
|
|
1045
|
+
}
|
|
1046
|
+
this.sessionId = this.system._bookId();
|
|
1047
|
+
this.id = id ?? this.sessionId;
|
|
1048
|
+
this.logger = logger;
|
|
1049
|
+
this.clock = clock;
|
|
1050
|
+
this._parent = parent;
|
|
1051
|
+
this.options = resolvedOptions;
|
|
1052
|
+
this.src = resolvedOptions.src;
|
|
1053
|
+
this.ref = this;
|
|
1054
|
+
this._actorContext = {
|
|
1055
|
+
self,
|
|
1056
|
+
id: this.id,
|
|
1057
|
+
sessionId: this.sessionId,
|
|
1058
|
+
logger: this.logger,
|
|
1059
|
+
defer: fn => {
|
|
1060
|
+
this._deferred.push(fn);
|
|
1061
|
+
},
|
|
1062
|
+
system: this.system,
|
|
1063
|
+
stopChild: child => {
|
|
1064
|
+
if (child._parent !== this) {
|
|
1065
|
+
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
1066
|
+
}
|
|
1067
|
+
child._stop();
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
// Ensure that the send method is bound to this interpreter instance
|
|
1072
|
+
// if destructured
|
|
1073
|
+
this.send = this.send.bind(this);
|
|
1074
|
+
this._initState();
|
|
1075
|
+
}
|
|
1076
|
+
_initState() {
|
|
1077
|
+
this._state = this.options.state ? this.logic.restoreState ? this.logic.restoreState(this.options.state, this._actorContext) : this.options.state : this.logic.getInitialState(this._actorContext, this.options?.input);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// array of functions to defer
|
|
1081
|
+
|
|
1082
|
+
update(state) {
|
|
1083
|
+
// Update state
|
|
1084
|
+
this._state = state;
|
|
1085
|
+
const snapshot = this.getSnapshot();
|
|
1086
|
+
|
|
1087
|
+
// Execute deferred effects
|
|
1088
|
+
let deferredFn;
|
|
1089
|
+
while (deferredFn = this._deferred.shift()) {
|
|
1090
|
+
deferredFn();
|
|
1091
|
+
}
|
|
1092
|
+
for (const observer of this.observers) {
|
|
1093
|
+
observer.next?.(snapshot);
|
|
1094
|
+
}
|
|
1095
|
+
const status = this.logic.getStatus?.(state);
|
|
1096
|
+
switch (status?.status) {
|
|
1097
|
+
case 'done':
|
|
1098
|
+
this._stopProcedure();
|
|
1099
|
+
this._doneEvent = doneInvoke(this.id, status.data);
|
|
1100
|
+
this._parent?.send(this._doneEvent);
|
|
1101
|
+
this._complete();
|
|
1102
|
+
break;
|
|
1103
|
+
case 'error':
|
|
1104
|
+
this._stopProcedure();
|
|
1105
|
+
this._parent?.send(error(this.id, status.data));
|
|
1106
|
+
this._error(status.data);
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
1111
|
+
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
1112
|
+
this.observers.add(observer);
|
|
1113
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1114
|
+
observer.complete?.();
|
|
1115
|
+
this.observers.delete(observer);
|
|
1116
|
+
}
|
|
1117
|
+
return {
|
|
1118
|
+
unsubscribe: () => {
|
|
1119
|
+
this.observers.delete(observer);
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/**
|
|
1125
|
+
* Starts the interpreter from the initial state
|
|
1126
|
+
*/
|
|
1127
|
+
start() {
|
|
1128
|
+
if (this.status === ActorStatus.Running) {
|
|
1129
|
+
// Do not restart the service if it is already started
|
|
1130
|
+
return this;
|
|
1131
|
+
}
|
|
1132
|
+
this.system._register(this.sessionId, this);
|
|
1133
|
+
if (this._systemId) {
|
|
1134
|
+
this.system._set(this._systemId, this);
|
|
1135
|
+
}
|
|
1136
|
+
this.status = ActorStatus.Running;
|
|
1137
|
+
if (this.logic.start) {
|
|
1138
|
+
this.logic.start(this._state, this._actorContext);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// TODO: this notifies all subscribers but usually this is redundant
|
|
1142
|
+
// there is no real change happening here
|
|
1143
|
+
// we need to rethink if this needs to be refactored
|
|
1144
|
+
this.update(this._state);
|
|
1145
|
+
if (this.options.devTools) {
|
|
1146
|
+
this.attachDevTools();
|
|
1147
|
+
}
|
|
1148
|
+
this.mailbox.start();
|
|
1149
|
+
return this;
|
|
1150
|
+
}
|
|
1151
|
+
_process(event) {
|
|
1152
|
+
try {
|
|
1153
|
+
const nextState = this.logic.transition(this._state, event, this._actorContext);
|
|
1154
|
+
this.update(nextState);
|
|
1155
|
+
if (event.type === stopSignalType) {
|
|
1156
|
+
this._stopProcedure();
|
|
1157
|
+
this._complete();
|
|
1158
|
+
}
|
|
1159
|
+
} catch (err) {
|
|
1160
|
+
// TODO: properly handle errors
|
|
1161
|
+
if (this.observers.size > 0) {
|
|
1162
|
+
this.observers.forEach(observer => {
|
|
1163
|
+
observer.error?.(err);
|
|
1164
|
+
});
|
|
1165
|
+
this.stop();
|
|
1166
|
+
} else {
|
|
1167
|
+
throw err;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
_stop() {
|
|
1172
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1173
|
+
return this;
|
|
1174
|
+
}
|
|
1175
|
+
this.mailbox.clear();
|
|
1176
|
+
if (this.status === ActorStatus.NotStarted) {
|
|
1177
|
+
this.status = ActorStatus.Stopped;
|
|
1178
|
+
return this;
|
|
1179
|
+
}
|
|
1180
|
+
this.mailbox.enqueue({
|
|
1181
|
+
type: stopSignalType
|
|
1182
|
+
});
|
|
1183
|
+
return this;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* Stops the interpreter and unsubscribe all listeners.
|
|
1188
|
+
*/
|
|
1189
|
+
stop() {
|
|
1190
|
+
if (this._parent) {
|
|
1191
|
+
throw new Error('A non-root actor cannot be stopped directly.');
|
|
1192
|
+
}
|
|
1193
|
+
return this._stop();
|
|
1194
|
+
}
|
|
1195
|
+
_complete() {
|
|
1196
|
+
for (const observer of this.observers) {
|
|
1197
|
+
observer.complete?.();
|
|
1198
|
+
}
|
|
1199
|
+
this.observers.clear();
|
|
1200
|
+
}
|
|
1201
|
+
_error(data) {
|
|
1202
|
+
for (const observer of this.observers) {
|
|
1203
|
+
observer.error?.(data);
|
|
1204
|
+
}
|
|
1205
|
+
this.observers.clear();
|
|
1206
|
+
}
|
|
1207
|
+
_stopProcedure() {
|
|
1208
|
+
if (this.status !== ActorStatus.Running) {
|
|
1209
|
+
// Interpreter already stopped; do nothing
|
|
1210
|
+
return this;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// Cancel all delayed events
|
|
1214
|
+
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
1215
|
+
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// TODO: mailbox.reset
|
|
1219
|
+
this.mailbox.clear();
|
|
1220
|
+
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
1221
|
+
// events sent *after* stop signal must be queued
|
|
1222
|
+
// it seems like this should be the common behavior for all of our consumers
|
|
1223
|
+
// so perhaps this should be unified somehow for all of them
|
|
1224
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
1225
|
+
this.status = ActorStatus.Stopped;
|
|
1226
|
+
this.system._unregister(this);
|
|
1227
|
+
return this;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Sends an event to the running interpreter to trigger a transition.
|
|
1232
|
+
*
|
|
1233
|
+
* @param event The event to send
|
|
1234
|
+
*/
|
|
1235
|
+
send(event) {
|
|
1236
|
+
if (typeof event === 'string') {
|
|
1237
|
+
throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
|
|
1238
|
+
}
|
|
1239
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
|
|
1243
|
+
throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
|
|
1244
|
+
// tslint:disable-next-line:max-line-length
|
|
1245
|
+
}". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
|
|
1246
|
+
}
|
|
1247
|
+
this.mailbox.enqueue(event);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// TODO: make private (and figure out a way to do this within the machine)
|
|
1251
|
+
delaySend({
|
|
1252
|
+
event,
|
|
1253
|
+
id,
|
|
1254
|
+
delay,
|
|
1255
|
+
to
|
|
1256
|
+
}) {
|
|
1257
|
+
const timerId = this.clock.setTimeout(() => {
|
|
1258
|
+
if (to) {
|
|
1259
|
+
to.send(event);
|
|
1260
|
+
} else {
|
|
1261
|
+
this.send(event);
|
|
1262
|
+
}
|
|
1263
|
+
}, delay);
|
|
1264
|
+
|
|
1265
|
+
// TODO: consider the rehydration story here
|
|
1266
|
+
if (id) {
|
|
1267
|
+
this.delayedEventsMap[id] = timerId;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// TODO: make private (and figure out a way to do this within the machine)
|
|
1272
|
+
cancel(sendId) {
|
|
1273
|
+
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
1274
|
+
delete this.delayedEventsMap[sendId];
|
|
1275
|
+
}
|
|
1276
|
+
attachDevTools() {
|
|
1277
|
+
const {
|
|
1278
|
+
devTools
|
|
1279
|
+
} = this.options;
|
|
1280
|
+
if (devTools) {
|
|
1281
|
+
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
|
|
1282
|
+
resolvedDevToolsAdapter(this);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
toJSON() {
|
|
1286
|
+
return {
|
|
1287
|
+
id: this.id
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
getPersistedState() {
|
|
1291
|
+
return this.logic.getPersistedState?.(this._state);
|
|
1292
|
+
}
|
|
1293
|
+
[symbolObservable]() {
|
|
1294
|
+
return this;
|
|
1295
|
+
}
|
|
1296
|
+
getSnapshot() {
|
|
1297
|
+
return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1369
1300
|
|
|
1370
|
-
const startSignalType = 'xstate.init';
|
|
1371
|
-
const stopSignalType = 'xstate.stop';
|
|
1372
|
-
const startSignal = {
|
|
1373
|
-
type: 'xstate.init'
|
|
1374
|
-
};
|
|
1375
|
-
const stopSignal = {
|
|
1376
|
-
type: 'xstate.stop'
|
|
1377
|
-
};
|
|
1378
1301
|
/**
|
|
1379
|
-
*
|
|
1380
|
-
* as well as an optionally emitted stream of values.
|
|
1302
|
+
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
1381
1303
|
*
|
|
1382
|
-
* @
|
|
1383
|
-
* @
|
|
1304
|
+
* @param machine The machine to interpret
|
|
1305
|
+
* @param options Interpreter options
|
|
1384
1306
|
*/
|
|
1385
1307
|
|
|
1386
|
-
function
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
function isActorRef(item) {
|
|
1390
|
-
return !!item && typeof item === 'object' && typeof item.send === 'function';
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
// TODO: refactor the return type, this could be written in a better way
|
|
1394
|
-
// but it's best to avoid unneccessary breaking changes now
|
|
1395
|
-
// @deprecated use `interpret(actorLogic)` instead
|
|
1396
|
-
function toActorRef(actorRefLike) {
|
|
1397
|
-
return {
|
|
1398
|
-
subscribe: () => ({
|
|
1399
|
-
unsubscribe: () => void 0
|
|
1400
|
-
}),
|
|
1401
|
-
id: 'anonymous',
|
|
1402
|
-
sessionId: '',
|
|
1403
|
-
getSnapshot: () => undefined,
|
|
1404
|
-
[symbolObservable]: function () {
|
|
1405
|
-
return this;
|
|
1406
|
-
},
|
|
1407
|
-
status: ActorStatus.Running,
|
|
1408
|
-
stop: () => void 0,
|
|
1409
|
-
...actorRefLike
|
|
1410
|
-
};
|
|
1411
|
-
}
|
|
1412
|
-
const emptyLogic = fromTransition(_ => undefined, undefined);
|
|
1413
|
-
function createEmptyActor() {
|
|
1414
|
-
return interpret(emptyLogic);
|
|
1308
|
+
function interpret(logic, options) {
|
|
1309
|
+
const interpreter = new Interpreter(logic, options);
|
|
1310
|
+
return interpreter;
|
|
1415
1311
|
}
|
|
1416
1312
|
|
|
1417
|
-
function
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1313
|
+
function resolve$6(actorContext, state, actionArgs, {
|
|
1314
|
+
id,
|
|
1315
|
+
systemId,
|
|
1316
|
+
src,
|
|
1317
|
+
input
|
|
1318
|
+
}) {
|
|
1319
|
+
const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
|
|
1320
|
+
let actorRef;
|
|
1321
|
+
if (referenced) {
|
|
1322
|
+
// TODO: inline `input: undefined` should win over the referenced one
|
|
1323
|
+
const configuredInput = input || referenced.input;
|
|
1324
|
+
actorRef = interpret(referenced.src, {
|
|
1427
1325
|
id,
|
|
1428
|
-
src
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
ref: src
|
|
1437
|
-
}
|
|
1438
|
-
};
|
|
1439
|
-
} else {
|
|
1440
|
-
const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
|
|
1441
|
-
if (!referenced) {
|
|
1442
|
-
resolvedInvokeAction = {
|
|
1443
|
-
type,
|
|
1444
|
-
params: invokeDef
|
|
1445
|
-
};
|
|
1446
|
-
} else {
|
|
1447
|
-
const input = 'input' in invokeDef ? invokeDef.input : referenced.input;
|
|
1448
|
-
const ref = interpret(referenced.src, {
|
|
1449
|
-
id,
|
|
1450
|
-
src,
|
|
1451
|
-
parent: actorContext?.self,
|
|
1452
|
-
systemId: invokeDef.systemId,
|
|
1453
|
-
input: typeof input === 'function' ? input({
|
|
1454
|
-
context: state.context,
|
|
1455
|
-
event,
|
|
1456
|
-
self: actorContext?.self
|
|
1457
|
-
}) : input
|
|
1458
|
-
});
|
|
1459
|
-
resolvedInvokeAction = {
|
|
1460
|
-
type,
|
|
1461
|
-
params: {
|
|
1462
|
-
...invokeDef,
|
|
1463
|
-
ref
|
|
1464
|
-
}
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
const actorRef = resolvedInvokeAction.params.ref;
|
|
1469
|
-
const invokedState = cloneState(state, {
|
|
1470
|
-
children: {
|
|
1471
|
-
...state.children,
|
|
1472
|
-
[id]: actorRef
|
|
1473
|
-
}
|
|
1326
|
+
src,
|
|
1327
|
+
parent: actorContext?.self,
|
|
1328
|
+
systemId,
|
|
1329
|
+
input: typeof configuredInput === 'function' ? configuredInput({
|
|
1330
|
+
context: state.context,
|
|
1331
|
+
event: actionArgs.event,
|
|
1332
|
+
self: actorContext?.self
|
|
1333
|
+
}) : configuredInput
|
|
1474
1334
|
});
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1335
|
+
}
|
|
1336
|
+
return [cloneState(state, {
|
|
1337
|
+
children: {
|
|
1338
|
+
...state.children,
|
|
1339
|
+
[id]: actorRef
|
|
1340
|
+
}
|
|
1341
|
+
}), {
|
|
1342
|
+
id,
|
|
1343
|
+
actorRef
|
|
1344
|
+
}];
|
|
1345
|
+
}
|
|
1346
|
+
function execute$3(actorContext, {
|
|
1347
|
+
id,
|
|
1348
|
+
actorRef
|
|
1349
|
+
}) {
|
|
1350
|
+
if (!actorRef) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
actorContext.defer(() => {
|
|
1354
|
+
if (actorRef.status === ActorStatus.Stopped) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
try {
|
|
1358
|
+
actorRef.start?.();
|
|
1359
|
+
} catch (err) {
|
|
1360
|
+
actorContext.self.send(error(id, err));
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1497
1363
|
});
|
|
1498
1364
|
}
|
|
1365
|
+
function invoke({
|
|
1366
|
+
id,
|
|
1367
|
+
systemId,
|
|
1368
|
+
src,
|
|
1369
|
+
input
|
|
1370
|
+
}) {
|
|
1371
|
+
function invoke(_) {
|
|
1372
|
+
}
|
|
1373
|
+
invoke.type = 'xstate.invoke';
|
|
1374
|
+
invoke.id = id;
|
|
1375
|
+
invoke.systemId = systemId;
|
|
1376
|
+
invoke.src = src;
|
|
1377
|
+
invoke.input = input;
|
|
1378
|
+
invoke.resolve = resolve$6;
|
|
1379
|
+
invoke.execute = execute$3;
|
|
1380
|
+
return invoke;
|
|
1381
|
+
}
|
|
1499
1382
|
|
|
1500
1383
|
function stateIn(stateValue) {
|
|
1501
1384
|
return {
|
|
@@ -1506,7 +1389,7 @@ function stateIn(stateValue) {
|
|
|
1506
1389
|
predicate: ({
|
|
1507
1390
|
state
|
|
1508
1391
|
}) => {
|
|
1509
|
-
if (
|
|
1392
|
+
if (typeof stateValue === 'string' && isStateId(stateValue)) {
|
|
1510
1393
|
return state.configuration.some(sn => sn.id === stateValue.slice(1));
|
|
1511
1394
|
}
|
|
1512
1395
|
return state.matches(stateValue);
|
|
@@ -1590,9 +1473,9 @@ function evaluateGuard(guard, context, event, state) {
|
|
|
1590
1473
|
function toGuardDefinition(guardConfig, getPredicate) {
|
|
1591
1474
|
// TODO: check for cycles and consider a refactor to more lazily evaluated guards
|
|
1592
1475
|
// TODO: resolve this more recursively: https://github.com/statelyai/xstate/pull/4064#discussion_r1229915724
|
|
1593
|
-
if (
|
|
1476
|
+
if (typeof guardConfig === 'string') {
|
|
1594
1477
|
const predicateOrDef = getPredicate?.(guardConfig);
|
|
1595
|
-
if (
|
|
1478
|
+
if (typeof predicateOrDef === 'function') {
|
|
1596
1479
|
return {
|
|
1597
1480
|
type: guardConfig,
|
|
1598
1481
|
predicate: predicateOrDef,
|
|
@@ -1611,7 +1494,7 @@ function toGuardDefinition(guardConfig, getPredicate) {
|
|
|
1611
1494
|
};
|
|
1612
1495
|
}
|
|
1613
1496
|
}
|
|
1614
|
-
if (
|
|
1497
|
+
if (typeof guardConfig === 'function') {
|
|
1615
1498
|
return {
|
|
1616
1499
|
type: guardConfig.name,
|
|
1617
1500
|
predicate: guardConfig,
|
|
@@ -1622,7 +1505,7 @@ function toGuardDefinition(guardConfig, getPredicate) {
|
|
|
1622
1505
|
};
|
|
1623
1506
|
}
|
|
1624
1507
|
const predicateOrDef = getPredicate?.(guardConfig.type);
|
|
1625
|
-
if (
|
|
1508
|
+
if (typeof predicateOrDef === 'function') {
|
|
1626
1509
|
return {
|
|
1627
1510
|
type: guardConfig.type,
|
|
1628
1511
|
params: guardConfig.params || guardConfig,
|
|
@@ -1749,24 +1632,16 @@ function isInFinalState(configuration, stateNode = configuration[0].machine.root
|
|
|
1749
1632
|
}
|
|
1750
1633
|
const isStateId = str => str[0] === STATE_IDENTIFIER;
|
|
1751
1634
|
function getCandidates(stateNode, receivedEventType) {
|
|
1752
|
-
const candidates = stateNode.transitions.filter(
|
|
1753
|
-
|
|
1754
|
-
eventType
|
|
1755
|
-
} = transition;
|
|
1756
|
-
// First, check the trivial case: event names are exactly equal
|
|
1757
|
-
if (eventType === receivedEventType) {
|
|
1758
|
-
return true;
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
// Then, check if transition is a wildcard transition,
|
|
1635
|
+
const candidates = stateNode.transitions.get(receivedEventType) || [...stateNode.transitions.keys()].filter(descriptor => {
|
|
1636
|
+
// check if transition is a wildcard transition,
|
|
1762
1637
|
// which matches any non-transient events
|
|
1763
|
-
if (
|
|
1638
|
+
if (descriptor === WILDCARD) {
|
|
1764
1639
|
return true;
|
|
1765
1640
|
}
|
|
1766
|
-
if (!
|
|
1641
|
+
if (!descriptor.endsWith('.*')) {
|
|
1767
1642
|
return false;
|
|
1768
1643
|
}
|
|
1769
|
-
const partialEventTokens =
|
|
1644
|
+
const partialEventTokens = descriptor.split('.');
|
|
1770
1645
|
const eventTokens = receivedEventType.split('.');
|
|
1771
1646
|
for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
|
|
1772
1647
|
const partialEventToken = partialEventTokens[tokenIndex];
|
|
@@ -1780,7 +1655,7 @@ function getCandidates(stateNode, receivedEventType) {
|
|
|
1780
1655
|
}
|
|
1781
1656
|
}
|
|
1782
1657
|
return true;
|
|
1783
|
-
});
|
|
1658
|
+
}).sort((a, b) => b.length - a.length).flatMap(key => stateNode.transitions.get(key));
|
|
1784
1659
|
return candidates;
|
|
1785
1660
|
}
|
|
1786
1661
|
|
|
@@ -1793,11 +1668,12 @@ function getDelayedTransitions(stateNode) {
|
|
|
1793
1668
|
return [];
|
|
1794
1669
|
}
|
|
1795
1670
|
const mutateEntryExit = (delay, i) => {
|
|
1796
|
-
const delayRef =
|
|
1671
|
+
const delayRef = typeof delay === 'function' ? `${stateNode.id}:delay[${i}]` : delay;
|
|
1797
1672
|
const eventType = after(delayRef, stateNode.id);
|
|
1798
1673
|
stateNode.entry.push(raise({
|
|
1799
1674
|
type: eventType
|
|
1800
1675
|
}, {
|
|
1676
|
+
id: eventType,
|
|
1801
1677
|
delay
|
|
1802
1678
|
}));
|
|
1803
1679
|
stateNode.exit.push(cancel(eventType));
|
|
@@ -1811,7 +1687,7 @@ function getDelayedTransitions(stateNode) {
|
|
|
1811
1687
|
};
|
|
1812
1688
|
}) : Object.keys(afterConfig).flatMap((delay, i) => {
|
|
1813
1689
|
const configTransition = afterConfig[delay];
|
|
1814
|
-
const resolvedTransition =
|
|
1690
|
+
const resolvedTransition = typeof configTransition === 'string' ? {
|
|
1815
1691
|
target: configTransition
|
|
1816
1692
|
} : configTransition;
|
|
1817
1693
|
const resolvedDelay = !isNaN(+delay) ? +delay : delay;
|
|
@@ -1827,12 +1703,12 @@ function getDelayedTransitions(stateNode) {
|
|
|
1827
1703
|
delay
|
|
1828
1704
|
} = delayedTransition;
|
|
1829
1705
|
return {
|
|
1830
|
-
...formatTransition(stateNode, delayedTransition),
|
|
1706
|
+
...formatTransition(stateNode, delayedTransition.event, delayedTransition),
|
|
1831
1707
|
delay
|
|
1832
1708
|
};
|
|
1833
1709
|
});
|
|
1834
1710
|
}
|
|
1835
|
-
function formatTransition(stateNode, transitionConfig) {
|
|
1711
|
+
function formatTransition(stateNode, descriptor, transitionConfig) {
|
|
1836
1712
|
const normalizedTarget = normalizeTarget(transitionConfig.target);
|
|
1837
1713
|
const reenter = transitionConfig.reenter ?? false;
|
|
1838
1714
|
const {
|
|
@@ -1841,12 +1717,12 @@ function formatTransition(stateNode, transitionConfig) {
|
|
|
1841
1717
|
const target = resolveTarget(stateNode, normalizedTarget);
|
|
1842
1718
|
const transition = {
|
|
1843
1719
|
...transitionConfig,
|
|
1844
|
-
actions:
|
|
1720
|
+
actions: toArray(transitionConfig.actions),
|
|
1845
1721
|
guard: transitionConfig.guard ? toGuardDefinition(transitionConfig.guard, guardType => guards[guardType]) : undefined,
|
|
1846
1722
|
target,
|
|
1847
1723
|
source: stateNode,
|
|
1848
1724
|
reenter,
|
|
1849
|
-
eventType:
|
|
1725
|
+
eventType: descriptor,
|
|
1850
1726
|
toJSON: () => ({
|
|
1851
1727
|
...transition,
|
|
1852
1728
|
source: `#${stateNode.id}`,
|
|
@@ -1856,52 +1732,50 @@ function formatTransition(stateNode, transitionConfig) {
|
|
|
1856
1732
|
return transition;
|
|
1857
1733
|
}
|
|
1858
1734
|
function formatTransitions(stateNode) {
|
|
1859
|
-
const
|
|
1860
|
-
if (
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
const {
|
|
1864
|
-
[WILDCARD]: wildcardConfigs = [],
|
|
1865
|
-
...namedTransitionConfigs
|
|
1866
|
-
} = stateNode.config.on;
|
|
1867
|
-
for (const eventType of Object.keys(namedTransitionConfigs)) {
|
|
1868
|
-
if (eventType === NULL_EVENT) {
|
|
1735
|
+
const transitions = new Map();
|
|
1736
|
+
if (stateNode.config.on) {
|
|
1737
|
+
for (const descriptor of Object.keys(stateNode.config.on)) {
|
|
1738
|
+
if (descriptor === NULL_EVENT) {
|
|
1869
1739
|
throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.');
|
|
1870
1740
|
}
|
|
1871
|
-
const
|
|
1872
|
-
|
|
1873
|
-
// TODO: add dev-mode validation for unreachable transitions
|
|
1741
|
+
const transitionsConfig = stateNode.config.on[descriptor];
|
|
1742
|
+
transitions.set(descriptor, toTransitionConfigArray(transitionsConfig).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1874
1743
|
}
|
|
1875
|
-
|
|
1876
|
-
transitionConfigs.push(...toTransitionConfigArray(WILDCARD, wildcardConfigs));
|
|
1877
1744
|
}
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1745
|
+
if (stateNode.config.onDone) {
|
|
1746
|
+
const descriptor = String(done(stateNode.id));
|
|
1747
|
+
transitions.set(descriptor, toTransitionConfigArray(stateNode.config.onDone).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1748
|
+
}
|
|
1749
|
+
for (const invokeDef of stateNode.invoke) {
|
|
1881
1750
|
if (invokeDef.onDone) {
|
|
1882
|
-
|
|
1751
|
+
const descriptor = `done.invoke.${invokeDef.id}`;
|
|
1752
|
+
transitions.set(descriptor, toTransitionConfigArray(invokeDef.onDone).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1883
1753
|
}
|
|
1884
1754
|
if (invokeDef.onError) {
|
|
1885
|
-
|
|
1755
|
+
const descriptor = `error.platform.${invokeDef.id}`;
|
|
1756
|
+
transitions.set(descriptor, toTransitionConfigArray(invokeDef.onError).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1886
1757
|
}
|
|
1887
1758
|
if (invokeDef.onSnapshot) {
|
|
1888
|
-
|
|
1759
|
+
const descriptor = `xstate.snapshot.${invokeDef.id}`;
|
|
1760
|
+
transitions.set(descriptor, toTransitionConfigArray(invokeDef.onSnapshot).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1889
1761
|
}
|
|
1890
|
-
return settleTransitions;
|
|
1891
|
-
});
|
|
1892
|
-
const delayedTransitions = stateNode.after;
|
|
1893
|
-
const formattedTransitions = [...doneConfig, ...invokeConfig, ...transitionConfigs].flatMap(transitionConfig => toArray(transitionConfig).map(transition => formatTransition(stateNode, transition)));
|
|
1894
|
-
for (const delayedTransition of delayedTransitions) {
|
|
1895
|
-
formattedTransitions.push(delayedTransition);
|
|
1896
1762
|
}
|
|
1897
|
-
|
|
1763
|
+
for (const delayedTransition of stateNode.after) {
|
|
1764
|
+
let existing = transitions.get(delayedTransition.eventType);
|
|
1765
|
+
if (!existing) {
|
|
1766
|
+
existing = [];
|
|
1767
|
+
transitions.set(delayedTransition.eventType, existing);
|
|
1768
|
+
}
|
|
1769
|
+
existing.push(delayedTransition);
|
|
1770
|
+
}
|
|
1771
|
+
return transitions;
|
|
1898
1772
|
}
|
|
1899
1773
|
function formatInitialTransition(stateNode, _target) {
|
|
1900
|
-
if (
|
|
1774
|
+
if (typeof _target === 'string' || isArray(_target)) {
|
|
1901
1775
|
const targets = toArray(_target).map(t => {
|
|
1902
1776
|
// Resolve state string keys (which represent children)
|
|
1903
1777
|
// to their state node
|
|
1904
|
-
const descStateNode =
|
|
1778
|
+
const descStateNode = typeof t === 'string' ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
|
|
1905
1779
|
if (!descStateNode) {
|
|
1906
1780
|
throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
|
|
1907
1781
|
}
|
|
@@ -1925,15 +1799,14 @@ function formatInitialTransition(stateNode, _target) {
|
|
|
1925
1799
|
};
|
|
1926
1800
|
return transition;
|
|
1927
1801
|
}
|
|
1928
|
-
return formatTransition(stateNode, {
|
|
1802
|
+
return formatTransition(stateNode, '__INITIAL__', {
|
|
1929
1803
|
target: toArray(_target.target).map(t => {
|
|
1930
|
-
if (
|
|
1804
|
+
if (typeof t === 'string') {
|
|
1931
1805
|
return isStateId(t) ? t : `${STATE_DELIMITER}${t}`;
|
|
1932
1806
|
}
|
|
1933
1807
|
return t;
|
|
1934
1808
|
}),
|
|
1935
|
-
actions: _target.actions
|
|
1936
|
-
event: null
|
|
1809
|
+
actions: _target.actions
|
|
1937
1810
|
});
|
|
1938
1811
|
}
|
|
1939
1812
|
function resolveTarget(stateNode, targets) {
|
|
@@ -1942,7 +1815,7 @@ function resolveTarget(stateNode, targets) {
|
|
|
1942
1815
|
return undefined;
|
|
1943
1816
|
}
|
|
1944
1817
|
return targets.map(target => {
|
|
1945
|
-
if (
|
|
1818
|
+
if (typeof target !== 'string') {
|
|
1946
1819
|
return target;
|
|
1947
1820
|
}
|
|
1948
1821
|
if (isStateId(target)) {
|
|
@@ -2050,7 +1923,7 @@ function getStateNodeByPath(stateNode, statePath) {
|
|
|
2050
1923
|
*/
|
|
2051
1924
|
function getStateNodes(stateNode, state) {
|
|
2052
1925
|
const stateValue = state instanceof State ? state.value : toStateValue(state);
|
|
2053
|
-
if (
|
|
1926
|
+
if (typeof stateValue === 'string') {
|
|
2054
1927
|
return [stateNode, stateNode.states[stateValue]];
|
|
2055
1928
|
}
|
|
2056
1929
|
const childStateKeys = Object.keys(stateValue);
|
|
@@ -2101,7 +1974,7 @@ function transitionParallelNode(stateNode, stateValue, state, event) {
|
|
|
2101
1974
|
}
|
|
2102
1975
|
function transitionNode(stateNode, stateValue, state, event) {
|
|
2103
1976
|
// leaf node
|
|
2104
|
-
if (
|
|
1977
|
+
if (typeof stateValue === 'string') {
|
|
2105
1978
|
return transitionAtomicNode(stateNode, stateValue, state, event);
|
|
2106
1979
|
}
|
|
2107
1980
|
|
|
@@ -2435,44 +2308,55 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
|
|
|
2435
2308
|
const {
|
|
2436
2309
|
machine
|
|
2437
2310
|
} = currentState;
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2311
|
+
// TODO: this `cloneState` is really just a hack to prevent infinite loops
|
|
2312
|
+
// we need to take another look at how internal queue is managed
|
|
2313
|
+
let intermediateState = cloneState(currentState, {
|
|
2314
|
+
_internalQueue: []
|
|
2315
|
+
});
|
|
2316
|
+
for (const action of actions) {
|
|
2317
|
+
const resolved = typeof action === 'function' ? action : machine.implementations.actions[typeof action === 'string' ? action : action.type];
|
|
2318
|
+
if (!resolved) {
|
|
2319
|
+
continue;
|
|
2445
2320
|
}
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
})
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2321
|
+
const args = {
|
|
2322
|
+
context: intermediateState.context,
|
|
2323
|
+
event,
|
|
2324
|
+
self: actorCtx?.self,
|
|
2325
|
+
system: actorCtx?.system,
|
|
2326
|
+
// TODO: figure out story for `action` and inline actions
|
|
2327
|
+
// what those ones should receive?
|
|
2328
|
+
//
|
|
2329
|
+
// entry: ({ action }) => {}
|
|
2330
|
+
// exit: assign(({ action }) => {})
|
|
2331
|
+
action: typeof action === 'string' ? {
|
|
2332
|
+
type: action
|
|
2333
|
+
} : action
|
|
2334
|
+
};
|
|
2335
|
+
if (!('resolve' in resolved)) {
|
|
2336
|
+
if (actorCtx?.self.status === ActorStatus.Running) {
|
|
2337
|
+
resolved(args);
|
|
2338
|
+
} else {
|
|
2339
|
+
actorCtx?.defer(() => resolved(args));
|
|
2459
2340
|
}
|
|
2341
|
+
continue;
|
|
2342
|
+
}
|
|
2343
|
+
const builtinAction = resolved;
|
|
2344
|
+
const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, args, resolved // this holds all params
|
|
2345
|
+
);
|
|
2460
2346
|
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2347
|
+
intermediateState = nextState;
|
|
2348
|
+
if ('execute' in resolved) {
|
|
2349
|
+
if (actorCtx?.self.status === ActorStatus.Running) {
|
|
2350
|
+
builtinAction.execute(actorCtx, params);
|
|
2351
|
+
} else {
|
|
2352
|
+
actorCtx?.defer(builtinAction.execute.bind(null, actorCtx, params));
|
|
2464
2353
|
}
|
|
2465
|
-
toActionObjects(matchedActions).forEach(resolveAction);
|
|
2466
|
-
return;
|
|
2467
2354
|
}
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
resolveAction(actionObject);
|
|
2355
|
+
if (actions) {
|
|
2356
|
+
intermediateState = resolveActionsAndContext(actions, event, intermediateState, actorCtx);
|
|
2357
|
+
}
|
|
2472
2358
|
}
|
|
2473
|
-
return
|
|
2474
|
-
_internalQueue: raiseActions.map(a => a.params.event)
|
|
2475
|
-
});
|
|
2359
|
+
return intermediateState;
|
|
2476
2360
|
}
|
|
2477
2361
|
function macrostep(state, event, actorCtx) {
|
|
2478
2362
|
let nextState = state;
|
|
@@ -2491,7 +2375,7 @@ function macrostep(state, event, actorCtx) {
|
|
|
2491
2375
|
|
|
2492
2376
|
// Assume the state is at rest (no raised events)
|
|
2493
2377
|
// Determine the next state based on the next microstep
|
|
2494
|
-
if (nextEvent.type !==
|
|
2378
|
+
if (nextEvent.type !== INIT_TYPE) {
|
|
2495
2379
|
const transitions = selectTransitions(nextEvent, nextState);
|
|
2496
2380
|
nextState = microstep(transitions, state, actorCtx, nextEvent, false);
|
|
2497
2381
|
states.push(nextState);
|
|
@@ -2657,7 +2541,7 @@ class State {
|
|
|
2657
2541
|
* @param delimiter The character(s) that separate each subpath in the string state node path.
|
|
2658
2542
|
*/
|
|
2659
2543
|
toStrings(stateValue = this.value) {
|
|
2660
|
-
if (
|
|
2544
|
+
if (typeof stateValue === 'string') {
|
|
2661
2545
|
return [stateValue];
|
|
2662
2546
|
}
|
|
2663
2547
|
const valueKeys = Object.keys(stateValue);
|
|
@@ -2752,6 +2636,36 @@ function getPersistedState(state) {
|
|
|
2752
2636
|
};
|
|
2753
2637
|
}
|
|
2754
2638
|
|
|
2639
|
+
function resolve$5(_, state, args, {
|
|
2640
|
+
actorRef
|
|
2641
|
+
}) {
|
|
2642
|
+
const actorRefOrString = typeof actorRef === 'function' ? actorRef(args) : actorRef;
|
|
2643
|
+
const resolvedActorRef = typeof actorRefOrString === 'string' ? state.children[actorRefOrString] : actorRefOrString;
|
|
2644
|
+
let children = state.children;
|
|
2645
|
+
if (resolvedActorRef) {
|
|
2646
|
+
children = {
|
|
2647
|
+
...children
|
|
2648
|
+
};
|
|
2649
|
+
delete children[resolvedActorRef.id];
|
|
2650
|
+
}
|
|
2651
|
+
return [cloneState(state, {
|
|
2652
|
+
children
|
|
2653
|
+
}), resolvedActorRef];
|
|
2654
|
+
}
|
|
2655
|
+
function execute$2(actorContext, actorRef) {
|
|
2656
|
+
if (!actorRef) {
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2659
|
+
if (actorRef.status !== ActorStatus.Running) {
|
|
2660
|
+
actorContext.stopChild(actorRef);
|
|
2661
|
+
return;
|
|
2662
|
+
}
|
|
2663
|
+
// TODO: recheck why this one has to be deferred
|
|
2664
|
+
actorContext.defer(() => {
|
|
2665
|
+
actorContext.stopChild(actorRef);
|
|
2666
|
+
});
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2755
2669
|
/**
|
|
2756
2670
|
* Stops an actor.
|
|
2757
2671
|
*
|
|
@@ -2759,58 +2673,37 @@ function getPersistedState(state) {
|
|
|
2759
2673
|
*/
|
|
2760
2674
|
|
|
2761
2675
|
function stop(actorRef) {
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
if (!actorRef) {
|
|
2792
|
-
return;
|
|
2793
|
-
}
|
|
2794
|
-
if (actorRef.status !== ActorStatus.Running) {
|
|
2795
|
-
actorCtx.stopChild(actorRef);
|
|
2796
|
-
return;
|
|
2797
|
-
}
|
|
2798
|
-
actorCtx.defer(() => {
|
|
2799
|
-
actorCtx.stopChild(actorRef);
|
|
2800
|
-
});
|
|
2801
|
-
}
|
|
2802
|
-
}];
|
|
2803
|
-
});
|
|
2676
|
+
function stop(_) {
|
|
2677
|
+
}
|
|
2678
|
+
stop.type = 'xstate.stop';
|
|
2679
|
+
stop.actorRef = actorRef;
|
|
2680
|
+
stop.resolve = resolve$5;
|
|
2681
|
+
stop.execute = execute$2;
|
|
2682
|
+
return stop;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
function resolve$4(_, state, actionArgs, {
|
|
2686
|
+
value,
|
|
2687
|
+
label
|
|
2688
|
+
}) {
|
|
2689
|
+
return [state, {
|
|
2690
|
+
value: typeof value === 'function' ? value(actionArgs) : value,
|
|
2691
|
+
label
|
|
2692
|
+
}];
|
|
2693
|
+
}
|
|
2694
|
+
function execute$1({
|
|
2695
|
+
logger
|
|
2696
|
+
}, {
|
|
2697
|
+
value,
|
|
2698
|
+
label
|
|
2699
|
+
}) {
|
|
2700
|
+
if (label) {
|
|
2701
|
+
logger(label, value);
|
|
2702
|
+
} else {
|
|
2703
|
+
logger(value);
|
|
2704
|
+
}
|
|
2804
2705
|
}
|
|
2805
2706
|
|
|
2806
|
-
const defaultLogExpr = ({
|
|
2807
|
-
context,
|
|
2808
|
-
event
|
|
2809
|
-
}) => ({
|
|
2810
|
-
context,
|
|
2811
|
-
event
|
|
2812
|
-
});
|
|
2813
|
-
|
|
2814
2707
|
/**
|
|
2815
2708
|
*
|
|
2816
2709
|
* @param expr The expression function to evaluate which will be logged.
|
|
@@ -2819,94 +2712,111 @@ const defaultLogExpr = ({
|
|
|
2819
2712
|
* - `event` - the event that caused this action to be executed.
|
|
2820
2713
|
* @param label The label to give to the logged expression.
|
|
2821
2714
|
*/
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
value: resolvedValue
|
|
2845
|
-
},
|
|
2846
|
-
execute: actorCtx => {
|
|
2847
|
-
if (label) {
|
|
2848
|
-
actorCtx.logger?.(label, resolvedValue);
|
|
2849
|
-
} else {
|
|
2850
|
-
actorCtx.logger?.(resolvedValue);
|
|
2851
|
-
}
|
|
2852
|
-
}
|
|
2853
|
-
}];
|
|
2854
|
-
});
|
|
2855
|
-
}
|
|
2856
|
-
|
|
2857
|
-
function createSpawner(self, machine, context, event, mutCapturedActions) {
|
|
2858
|
-
return (src, options = {}) => {
|
|
2715
|
+
function log(value = ({
|
|
2716
|
+
context,
|
|
2717
|
+
event
|
|
2718
|
+
}) => ({
|
|
2719
|
+
context,
|
|
2720
|
+
event
|
|
2721
|
+
}), label) {
|
|
2722
|
+
function log(_) {
|
|
2723
|
+
}
|
|
2724
|
+
log.type = 'xstate.log';
|
|
2725
|
+
log.value = value;
|
|
2726
|
+
log.label = label;
|
|
2727
|
+
log.resolve = resolve$4;
|
|
2728
|
+
log.execute = execute$1;
|
|
2729
|
+
return log;
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
function createSpawner(actorContext, {
|
|
2733
|
+
machine,
|
|
2734
|
+
context
|
|
2735
|
+
}, event, spawnedChildren) {
|
|
2736
|
+
const spawn = (src, options = {}) => {
|
|
2859
2737
|
const {
|
|
2860
2738
|
systemId
|
|
2861
2739
|
} = options;
|
|
2862
|
-
if (
|
|
2740
|
+
if (typeof src === 'string') {
|
|
2863
2741
|
const referenced = resolveReferencedActor(machine.implementations.actors[src]);
|
|
2864
|
-
if (referenced) {
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
// TODO: this should also receive `src`
|
|
2868
|
-
const actorRef = interpret(referenced.src, {
|
|
2869
|
-
id: options.id,
|
|
2870
|
-
parent: self,
|
|
2871
|
-
input: typeof input === 'function' ? input({
|
|
2872
|
-
context,
|
|
2873
|
-
event,
|
|
2874
|
-
self
|
|
2875
|
-
}) : input
|
|
2876
|
-
});
|
|
2877
|
-
mutCapturedActions.push(invoke({
|
|
2878
|
-
id: actorRef.id,
|
|
2879
|
-
// @ts-ignore TODO: fix types
|
|
2880
|
-
src: actorRef,
|
|
2881
|
-
// TODO
|
|
2882
|
-
ref: actorRef,
|
|
2883
|
-
meta: undefined,
|
|
2884
|
-
input,
|
|
2885
|
-
systemId
|
|
2886
|
-
}));
|
|
2887
|
-
return actorRef; // TODO: fix types
|
|
2742
|
+
if (!referenced) {
|
|
2743
|
+
throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
|
|
2888
2744
|
}
|
|
2745
|
+
const input = 'input' in options ? options.input : referenced.input;
|
|
2889
2746
|
|
|
2890
|
-
|
|
2747
|
+
// TODO: this should also receive `src`
|
|
2748
|
+
const actor = interpret(referenced.src, {
|
|
2749
|
+
id: options.id,
|
|
2750
|
+
parent: actorContext.self,
|
|
2751
|
+
input: typeof input === 'function' ? input({
|
|
2752
|
+
context,
|
|
2753
|
+
event,
|
|
2754
|
+
self: actorContext.self
|
|
2755
|
+
}) : input,
|
|
2756
|
+
systemId
|
|
2757
|
+
});
|
|
2758
|
+
spawnedChildren[actor.id] = actor;
|
|
2759
|
+
return actor;
|
|
2891
2760
|
} else {
|
|
2892
2761
|
// TODO: this should also receive `src`
|
|
2893
|
-
|
|
2762
|
+
return interpret(src, {
|
|
2894
2763
|
id: options.id,
|
|
2895
|
-
parent: self,
|
|
2764
|
+
parent: actorContext.self,
|
|
2896
2765
|
input: options.input,
|
|
2897
2766
|
systemId
|
|
2898
2767
|
});
|
|
2899
|
-
mutCapturedActions.push(invoke({
|
|
2900
|
-
// @ts-ignore TODO: fix types
|
|
2901
|
-
src: actorRef,
|
|
2902
|
-
ref: actorRef,
|
|
2903
|
-
id: actorRef.id,
|
|
2904
|
-
meta: undefined,
|
|
2905
|
-
input: options.input
|
|
2906
|
-
}));
|
|
2907
|
-
return actorRef; // TODO: fix types
|
|
2908
2768
|
}
|
|
2909
2769
|
};
|
|
2770
|
+
return (src, options) => {
|
|
2771
|
+
const actorRef = spawn(src, options);
|
|
2772
|
+
spawnedChildren[actorRef.id] = actorRef;
|
|
2773
|
+
actorContext.defer(() => {
|
|
2774
|
+
if (actorRef.status === ActorStatus.Stopped) {
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
try {
|
|
2778
|
+
actorRef.start?.();
|
|
2779
|
+
} catch (err) {
|
|
2780
|
+
actorContext.self.send(error(actorRef.id, err));
|
|
2781
|
+
return;
|
|
2782
|
+
}
|
|
2783
|
+
});
|
|
2784
|
+
return actorRef;
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
function resolve$3(actorContext, state, actionArgs, {
|
|
2789
|
+
assignment
|
|
2790
|
+
}) {
|
|
2791
|
+
if (!state.context) {
|
|
2792
|
+
throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
|
|
2793
|
+
}
|
|
2794
|
+
const spawnedChildren = {};
|
|
2795
|
+
const assignArgs = {
|
|
2796
|
+
context: state.context,
|
|
2797
|
+
event: actionArgs.event,
|
|
2798
|
+
action: actionArgs.action,
|
|
2799
|
+
spawn: createSpawner(actorContext, state, actionArgs.event, spawnedChildren),
|
|
2800
|
+
self: actorContext?.self,
|
|
2801
|
+
system: actorContext?.system
|
|
2802
|
+
};
|
|
2803
|
+
let partialUpdate = {};
|
|
2804
|
+
if (typeof assignment === 'function') {
|
|
2805
|
+
partialUpdate = assignment(assignArgs);
|
|
2806
|
+
} else {
|
|
2807
|
+
for (const key of Object.keys(assignment)) {
|
|
2808
|
+
const propAssignment = assignment[key];
|
|
2809
|
+
partialUpdate[key] = typeof propAssignment === 'function' ? propAssignment(assignArgs) : propAssignment;
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
const updatedContext = Object.assign({}, state.context, partialUpdate);
|
|
2813
|
+
return [cloneState(state, {
|
|
2814
|
+
context: updatedContext,
|
|
2815
|
+
children: Object.keys(spawnedChildren).length ? {
|
|
2816
|
+
...state.children,
|
|
2817
|
+
...spawnedChildren
|
|
2818
|
+
} : state.children
|
|
2819
|
+
})];
|
|
2910
2820
|
}
|
|
2911
2821
|
|
|
2912
2822
|
/**
|
|
@@ -2915,48 +2825,44 @@ function createSpawner(self, machine, context, event, mutCapturedActions) {
|
|
|
2915
2825
|
* @param assignment An object that represents the partial context to update.
|
|
2916
2826
|
*/
|
|
2917
2827
|
function assign(assignment) {
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
actions: capturedActions
|
|
2957
|
-
}
|
|
2958
|
-
}];
|
|
2959
|
-
});
|
|
2828
|
+
function assign(_) {
|
|
2829
|
+
}
|
|
2830
|
+
assign.type = 'xstate.assign';
|
|
2831
|
+
assign.assignment = assignment;
|
|
2832
|
+
assign.resolve = resolve$3;
|
|
2833
|
+
return assign;
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
function resolve$2(_, state, args, {
|
|
2837
|
+
event: eventOrExpr,
|
|
2838
|
+
id,
|
|
2839
|
+
delay
|
|
2840
|
+
}) {
|
|
2841
|
+
const delaysMap = state.machine.implementations.delays;
|
|
2842
|
+
if (typeof eventOrExpr === 'string') {
|
|
2843
|
+
throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
|
|
2844
|
+
}
|
|
2845
|
+
const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
|
|
2846
|
+
let resolvedDelay;
|
|
2847
|
+
if (typeof delay === 'string') {
|
|
2848
|
+
const configDelay = delaysMap && delaysMap[delay];
|
|
2849
|
+
resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
|
|
2850
|
+
} else {
|
|
2851
|
+
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
2852
|
+
}
|
|
2853
|
+
return [typeof resolvedDelay !== 'number' ? cloneState(state, {
|
|
2854
|
+
_internalQueue: state._internalQueue.concat(resolvedEvent)
|
|
2855
|
+
}) : state, {
|
|
2856
|
+
event: resolvedEvent,
|
|
2857
|
+
id,
|
|
2858
|
+
delay: resolvedDelay
|
|
2859
|
+
}];
|
|
2860
|
+
}
|
|
2861
|
+
function execute(actorContext, params) {
|
|
2862
|
+
if (typeof params.delay === 'number') {
|
|
2863
|
+
actorContext.self.delaySend(params);
|
|
2864
|
+
return;
|
|
2865
|
+
}
|
|
2960
2866
|
}
|
|
2961
2867
|
|
|
2962
2868
|
/**
|
|
@@ -2967,186 +2873,51 @@ function assign(assignment) {
|
|
|
2967
2873
|
*/
|
|
2968
2874
|
|
|
2969
2875
|
function raise(eventOrExpr, options) {
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
const resolvedAction = {
|
|
3007
|
-
type: raise$1,
|
|
3008
|
-
params: {
|
|
3009
|
-
...params,
|
|
3010
|
-
event: resolvedEvent,
|
|
3011
|
-
delay: resolvedDelay
|
|
3012
|
-
},
|
|
3013
|
-
execute: actorCtx => {
|
|
3014
|
-
if (typeof resolvedAction.params.delay === 'number') {
|
|
3015
|
-
actorCtx.self.delaySend(resolvedAction);
|
|
3016
|
-
return;
|
|
3017
|
-
}
|
|
3018
|
-
}
|
|
3019
|
-
};
|
|
3020
|
-
return [state, resolvedAction];
|
|
3021
|
-
});
|
|
2876
|
+
function raise(_) {
|
|
2877
|
+
}
|
|
2878
|
+
raise.type = 'xstate.raise';
|
|
2879
|
+
raise.event = eventOrExpr;
|
|
2880
|
+
raise.id = options?.id;
|
|
2881
|
+
raise.delay = options?.delay;
|
|
2882
|
+
raise.resolve = resolve$2;
|
|
2883
|
+
raise.execute = execute;
|
|
2884
|
+
return raise;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
function resolve$1(_, state, actionArgs, {
|
|
2888
|
+
branches
|
|
2889
|
+
}) {
|
|
2890
|
+
const matchedActions = branches.find(condition => {
|
|
2891
|
+
const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.implementations.guards[guardType]);
|
|
2892
|
+
return !guard || evaluateGuard(guard, state.context, actionArgs.event, state);
|
|
2893
|
+
})?.actions;
|
|
2894
|
+
return [state, undefined, toArray(matchedActions)];
|
|
2895
|
+
}
|
|
2896
|
+
function choose(branches) {
|
|
2897
|
+
function choose(_) {
|
|
2898
|
+
}
|
|
2899
|
+
choose.type = 'xstate.choose';
|
|
2900
|
+
choose.branches = branches;
|
|
2901
|
+
choose.resolve = resolve$1;
|
|
2902
|
+
return choose;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
function resolve(_, state, args, {
|
|
2906
|
+
get
|
|
2907
|
+
}) {
|
|
2908
|
+
return [state, undefined, toArray(get({
|
|
2909
|
+
context: state.context,
|
|
2910
|
+
event: args.event
|
|
2911
|
+
}))];
|
|
3022
2912
|
}
|
|
3023
|
-
|
|
3024
|
-
function choose(guards) {
|
|
3025
|
-
return createDynamicAction({
|
|
3026
|
-
type: choose$1,
|
|
3027
|
-
params: {
|
|
3028
|
-
guards
|
|
3029
|
-
}
|
|
3030
|
-
}, (event, {
|
|
3031
|
-
state
|
|
3032
|
-
}) => {
|
|
3033
|
-
const matchedActions = guards.find(condition => {
|
|
3034
|
-
const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.implementations.guards[guardType]);
|
|
3035
|
-
return !guard || evaluateGuard(guard, state.context, event, state);
|
|
3036
|
-
})?.actions;
|
|
3037
|
-
return [state, {
|
|
3038
|
-
type: choose$1,
|
|
3039
|
-
params: {
|
|
3040
|
-
actions: toActionObjects(matchedActions)
|
|
3041
|
-
}
|
|
3042
|
-
}];
|
|
3043
|
-
});
|
|
3044
|
-
}
|
|
3045
|
-
|
|
3046
2913
|
function pure(getActions) {
|
|
3047
|
-
|
|
3048
|
-
type: pure$1,
|
|
3049
|
-
params: {
|
|
3050
|
-
get: getActions
|
|
3051
|
-
}
|
|
3052
|
-
}, (event, {
|
|
3053
|
-
state
|
|
3054
|
-
}) => {
|
|
3055
|
-
return [state, {
|
|
3056
|
-
type: pure$1,
|
|
3057
|
-
params: {
|
|
3058
|
-
actions: toArray(toActionObjects(getActions({
|
|
3059
|
-
context: state.context,
|
|
3060
|
-
event
|
|
3061
|
-
}))) ?? []
|
|
3062
|
-
}
|
|
3063
|
-
}];
|
|
3064
|
-
});
|
|
3065
|
-
}
|
|
3066
|
-
|
|
3067
|
-
const initEvent = {
|
|
3068
|
-
type: init
|
|
3069
|
-
};
|
|
3070
|
-
function resolveActionObject(actionObject, actionFunctionMap) {
|
|
3071
|
-
if (isDynamicAction(actionObject)) {
|
|
3072
|
-
return actionObject;
|
|
3073
|
-
}
|
|
3074
|
-
const dereferencedAction = actionFunctionMap[actionObject.type];
|
|
3075
|
-
if (typeof dereferencedAction === 'function') {
|
|
3076
|
-
return createDynamicAction({
|
|
3077
|
-
type: 'xstate.function',
|
|
3078
|
-
params: actionObject.params ?? {}
|
|
3079
|
-
}, (event, {
|
|
3080
|
-
state
|
|
3081
|
-
}) => {
|
|
3082
|
-
const a = {
|
|
3083
|
-
type: actionObject.type,
|
|
3084
|
-
params: actionObject.params,
|
|
3085
|
-
execute: actorCtx => {
|
|
3086
|
-
return dereferencedAction({
|
|
3087
|
-
context: state.context,
|
|
3088
|
-
event,
|
|
3089
|
-
action: a,
|
|
3090
|
-
system: actorCtx.system,
|
|
3091
|
-
self: actorCtx.self
|
|
3092
|
-
});
|
|
3093
|
-
}
|
|
3094
|
-
};
|
|
3095
|
-
return [state, a];
|
|
3096
|
-
});
|
|
3097
|
-
} else if (dereferencedAction) {
|
|
3098
|
-
return dereferencedAction;
|
|
3099
|
-
} else {
|
|
3100
|
-
return actionObject;
|
|
3101
|
-
}
|
|
3102
|
-
}
|
|
3103
|
-
function toActionObject(action) {
|
|
3104
|
-
if (isDynamicAction(action)) {
|
|
3105
|
-
return action;
|
|
2914
|
+
function pure(_) {
|
|
3106
2915
|
}
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
};
|
|
3112
|
-
}
|
|
3113
|
-
if (typeof action === 'function') {
|
|
3114
|
-
const type = 'xstate.function';
|
|
3115
|
-
return createDynamicAction({
|
|
3116
|
-
type,
|
|
3117
|
-
params: {}
|
|
3118
|
-
}, (event, {
|
|
3119
|
-
state
|
|
3120
|
-
}) => {
|
|
3121
|
-
const actionObject = {
|
|
3122
|
-
type,
|
|
3123
|
-
params: {
|
|
3124
|
-
function: action
|
|
3125
|
-
},
|
|
3126
|
-
execute: actorCtx => {
|
|
3127
|
-
return action({
|
|
3128
|
-
context: state.context,
|
|
3129
|
-
event: event,
|
|
3130
|
-
action: actionObject,
|
|
3131
|
-
self: actorCtx.self,
|
|
3132
|
-
system: actorCtx.system
|
|
3133
|
-
});
|
|
3134
|
-
}
|
|
3135
|
-
};
|
|
3136
|
-
return [state, actionObject];
|
|
3137
|
-
});
|
|
3138
|
-
}
|
|
3139
|
-
|
|
3140
|
-
// action is already a BaseActionObject
|
|
3141
|
-
return action;
|
|
2916
|
+
pure.type = 'xstate.pure';
|
|
2917
|
+
pure.get = getActions;
|
|
2918
|
+
pure.resolve = resolve;
|
|
2919
|
+
return pure;
|
|
3142
2920
|
}
|
|
3143
|
-
const toActionObjects = action => {
|
|
3144
|
-
if (!action) {
|
|
3145
|
-
return [];
|
|
3146
|
-
}
|
|
3147
|
-
const actions = isArray(action) ? action : [action];
|
|
3148
|
-
return actions.map(toActionObject);
|
|
3149
|
-
};
|
|
3150
2921
|
|
|
3151
2922
|
/**
|
|
3152
2923
|
* Returns an event type that represents an implicit event that
|
|
@@ -3157,7 +2928,7 @@ const toActionObjects = action => {
|
|
|
3157
2928
|
*/
|
|
3158
2929
|
function after(delayRef, id) {
|
|
3159
2930
|
const idSuffix = id ? `#${id}` : '';
|
|
3160
|
-
return `${
|
|
2931
|
+
return `${ConstantPrefix.After}(${delayRef})${idSuffix}`;
|
|
3161
2932
|
}
|
|
3162
2933
|
|
|
3163
2934
|
/**
|
|
@@ -3168,7 +2939,7 @@ function after(delayRef, id) {
|
|
|
3168
2939
|
* @param output The data to pass into the event
|
|
3169
2940
|
*/
|
|
3170
2941
|
function done(id, output) {
|
|
3171
|
-
const type = `${
|
|
2942
|
+
const type = `${ConstantPrefix.DoneState}.${id}`;
|
|
3172
2943
|
const eventObject = {
|
|
3173
2944
|
type,
|
|
3174
2945
|
output
|
|
@@ -3187,7 +2958,7 @@ function done(id, output) {
|
|
|
3187
2958
|
* @param output The data to pass into the event
|
|
3188
2959
|
*/
|
|
3189
2960
|
function doneInvoke(invokeId, output) {
|
|
3190
|
-
const type = `${
|
|
2961
|
+
const type = `${ConstantPrefix.DoneInvoke}.${invokeId}`;
|
|
3191
2962
|
const eventObject = {
|
|
3192
2963
|
type,
|
|
3193
2964
|
output
|
|
@@ -3196,7 +2967,7 @@ function doneInvoke(invokeId, output) {
|
|
|
3196
2967
|
return eventObject;
|
|
3197
2968
|
}
|
|
3198
2969
|
function error(id, data) {
|
|
3199
|
-
const type = `${
|
|
2970
|
+
const type = `${ConstantPrefix.ErrorPlatform}.${id}`;
|
|
3200
2971
|
const eventObject = {
|
|
3201
2972
|
type,
|
|
3202
2973
|
data
|
|
@@ -3206,9 +2977,9 @@ function error(id, data) {
|
|
|
3206
2977
|
}
|
|
3207
2978
|
function createInitEvent(input) {
|
|
3208
2979
|
return {
|
|
3209
|
-
type:
|
|
2980
|
+
type: INIT_TYPE,
|
|
3210
2981
|
input
|
|
3211
2982
|
};
|
|
3212
2983
|
}
|
|
3213
2984
|
|
|
3214
|
-
export {
|
|
2985
|
+
export { fromEventObservable as $, isAtomicStateNode as A, error as B, isStateId as C, getStateNodeByPath as D, getPersistedState as E, resolveReferencedActor as F, interpret as G, matchesState as H, sendTo as I, sendParent as J, forwardTo as K, Interpreter as L, ActorStatus as M, NULL_EVENT as N, doneInvoke as O, cancel as P, choose as Q, log as R, STATE_DELIMITER as S, pure as T, raise as U, stop as V, pathToStateValue as W, toObserver as X, fromPromise as Y, fromObservable as Z, fromCallback as _, toTransitionConfigArray as a, fromTransition as a0, stateIn as a1, not as a2, and as a3, or as a4, ConstantPrefix as a5, SpecialTargets as a6, startSignalType as a7, stopSignalType as a8, startSignal as a9, stopSignal as aa, isSignal as ab, isActorRef as ac, toActorRef as ad, createEmptyActor as ae, toGuardDefinition as af, constantPrefixes as ag, after as ah, done as ai, escalate as aj, formatTransition as b, memo as c, flatten as d, evaluateGuard as e, formatTransitions as f, createInvokeId as g, getDelayedTransitions as h, formatInitialTransition as i, getCandidates as j, toInvokeConfig as k, getConfiguration as l, mapValues as m, getStateNodes as n, isInFinalState as o, State as p, isErrorEvent as q, resolveStateValue as r, macrostep as s, toArray as t, transitionNode as u, getInitialConfiguration as v, resolveActionsAndContext as w, assign as x, createInitEvent as y, microstep as z };
|