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