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.development.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.development.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,93 @@ 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
|
-
to: options ? options.to : undefined,
|
|
325
|
-
delay: options ? options.delay : undefined,
|
|
326
|
-
event: eventOrExpr,
|
|
327
|
-
id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
|
|
328
|
-
}
|
|
329
|
-
}, (event, {
|
|
330
|
-
actorContext,
|
|
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;
|
|
140
|
+
function sendTo(to, eventOrExpr, options) {
|
|
141
|
+
function sendTo(_) {
|
|
142
|
+
{
|
|
143
|
+
throw new Error(`This isn't supposed to be called`);
|
|
380
144
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
});
|
|
145
|
+
}
|
|
146
|
+
sendTo.type = 'xstate.sendTo';
|
|
147
|
+
sendTo.to = to;
|
|
148
|
+
sendTo.event = eventOrExpr;
|
|
149
|
+
sendTo.id = options?.id;
|
|
150
|
+
sendTo.delay = options?.delay;
|
|
151
|
+
sendTo.resolve = resolve$8;
|
|
152
|
+
sendTo.execute = execute$5;
|
|
153
|
+
return sendTo;
|
|
409
154
|
}
|
|
410
155
|
|
|
411
156
|
/**
|
|
@@ -415,12 +160,8 @@ function send(eventOrExpr, options) {
|
|
|
415
160
|
* @param options Options to pass into the send event.
|
|
416
161
|
*/
|
|
417
162
|
function sendParent(event, options) {
|
|
418
|
-
return
|
|
419
|
-
...options,
|
|
420
|
-
to: SpecialTargets.Parent
|
|
421
|
-
});
|
|
163
|
+
return sendTo(SpecialTargets.Parent, event, options);
|
|
422
164
|
}
|
|
423
|
-
|
|
424
165
|
/**
|
|
425
166
|
* Forwards (sends) an event to a specified service.
|
|
426
167
|
*
|
|
@@ -438,12 +179,9 @@ function forwardTo(target, options) {
|
|
|
438
179
|
return resolvedTarget;
|
|
439
180
|
};
|
|
440
181
|
}
|
|
441
|
-
return
|
|
182
|
+
return sendTo(target, ({
|
|
442
183
|
event
|
|
443
|
-
}) => event,
|
|
444
|
-
...options,
|
|
445
|
-
to: target
|
|
446
|
-
});
|
|
184
|
+
}) => event, options);
|
|
447
185
|
}
|
|
448
186
|
|
|
449
187
|
/**
|
|
@@ -457,27 +195,9 @@ function escalate(errorData, options) {
|
|
|
457
195
|
return sendParent(arg => {
|
|
458
196
|
return {
|
|
459
197
|
type: error$1,
|
|
460
|
-
data:
|
|
198
|
+
data: typeof errorData === 'function' ? errorData(arg) : errorData
|
|
461
199
|
};
|
|
462
|
-
},
|
|
463
|
-
...options,
|
|
464
|
-
to: SpecialTargets.Parent
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Sends an event to an actor.
|
|
470
|
-
*
|
|
471
|
-
* @param actor The `ActorRef` to send the event to.
|
|
472
|
-
* @param event The event to send, or an expression that evaluates to the event to send
|
|
473
|
-
* @param options Send action options
|
|
474
|
-
* @returns An XState send action object
|
|
475
|
-
*/
|
|
476
|
-
function sendTo(actor, event, options) {
|
|
477
|
-
return send(event, {
|
|
478
|
-
...options,
|
|
479
|
-
to: actor
|
|
480
|
-
});
|
|
200
|
+
}, options);
|
|
481
201
|
}
|
|
482
202
|
|
|
483
203
|
const cache = new WeakMap();
|
|
@@ -494,6 +214,16 @@ function memo(object, key, fn) {
|
|
|
494
214
|
return memoizedData[key];
|
|
495
215
|
}
|
|
496
216
|
|
|
217
|
+
function resolve$7(_, state, actionArgs, {
|
|
218
|
+
sendId
|
|
219
|
+
}) {
|
|
220
|
+
const resolvedSendId = typeof sendId === 'function' ? sendId(actionArgs) : sendId;
|
|
221
|
+
return [state, resolvedSendId];
|
|
222
|
+
}
|
|
223
|
+
function execute$4(actorContext, resolvedSendId) {
|
|
224
|
+
actorContext.self.cancel(resolvedSendId);
|
|
225
|
+
}
|
|
226
|
+
|
|
497
227
|
/**
|
|
498
228
|
* Cancels an in-flight `send(...)` action. A canceled sent action will not
|
|
499
229
|
* be executed, nor will its event be sent, unless it has already been sent
|
|
@@ -501,38 +231,19 @@ function memo(object, key, fn) {
|
|
|
501
231
|
*
|
|
502
232
|
* @param sendId The `id` of the `send(...)` action to cancel.
|
|
503
233
|
*/
|
|
504
|
-
|
|
505
234
|
function cancel(sendId) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
sendId
|
|
235
|
+
function cancel(_) {
|
|
236
|
+
{
|
|
237
|
+
throw new Error(`This isn't supposed to be called`);
|
|
510
238
|
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
event,
|
|
518
|
-
self: actorContext?.self ?? {},
|
|
519
|
-
system: actorContext?.system
|
|
520
|
-
}) : sendId;
|
|
521
|
-
return [state, {
|
|
522
|
-
type: 'xstate.cancel',
|
|
523
|
-
params: {
|
|
524
|
-
sendId: resolvedSendId
|
|
525
|
-
},
|
|
526
|
-
execute: actorCtx => {
|
|
527
|
-
const interpreter = actorCtx.self;
|
|
528
|
-
interpreter.cancel(resolvedSendId);
|
|
529
|
-
}
|
|
530
|
-
}];
|
|
531
|
-
});
|
|
239
|
+
}
|
|
240
|
+
cancel.type = 'xstate.cancel';
|
|
241
|
+
cancel.sendId = sendId;
|
|
242
|
+
cancel.resolve = resolve$7;
|
|
243
|
+
cancel.execute = execute$4;
|
|
244
|
+
return cancel;
|
|
532
245
|
}
|
|
533
246
|
|
|
534
|
-
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
535
|
-
|
|
536
247
|
class Mailbox {
|
|
537
248
|
constructor(_process) {
|
|
538
249
|
this._process = _process;
|
|
@@ -600,528 +311,147 @@ class Mailbox {
|
|
|
600
311
|
}
|
|
601
312
|
}
|
|
602
313
|
|
|
603
|
-
function
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
reverseKeyedActors.delete(actorRef);
|
|
620
|
-
}
|
|
314
|
+
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Returns actor logic from a transition function and its initial state.
|
|
318
|
+
*
|
|
319
|
+
* A transition function is a function that takes the current state and an event and returns the next state.
|
|
320
|
+
*
|
|
321
|
+
* @param transition The transition function that returns the next state given the current state and event.
|
|
322
|
+
* @param initialState The initial state of the transition function.
|
|
323
|
+
* @returns Actor logic
|
|
324
|
+
*/
|
|
325
|
+
function fromTransition(transition, initialState) {
|
|
326
|
+
const logic = {
|
|
327
|
+
config: transition,
|
|
328
|
+
transition: (state, event, actorContext) => {
|
|
329
|
+
return transition(state, event, actorContext);
|
|
621
330
|
},
|
|
622
|
-
|
|
623
|
-
return
|
|
331
|
+
getInitialState: (_, input) => {
|
|
332
|
+
return typeof initialState === 'function' ? initialState({
|
|
333
|
+
input
|
|
334
|
+
}) : initialState;
|
|
624
335
|
},
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
629
|
-
}
|
|
630
|
-
keyedActors.set(systemId, actorRef);
|
|
631
|
-
reverseKeyedActors.set(actorRef, systemId);
|
|
632
|
-
}
|
|
336
|
+
getSnapshot: state => state,
|
|
337
|
+
getPersistedState: state => state,
|
|
338
|
+
restoreState: state => state
|
|
633
339
|
};
|
|
634
|
-
return
|
|
340
|
+
return logic;
|
|
635
341
|
}
|
|
636
342
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
343
|
+
const resolveEventType = '$$xstate.resolve';
|
|
344
|
+
const rejectEventType = '$$xstate.reject';
|
|
345
|
+
function fromPromise(
|
|
346
|
+
// TODO: add types
|
|
347
|
+
promiseCreator) {
|
|
348
|
+
// TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
|
|
349
|
+
const logic = {
|
|
350
|
+
config: promiseCreator,
|
|
351
|
+
transition: (state, event) => {
|
|
352
|
+
if (state.status !== 'active') {
|
|
353
|
+
return state;
|
|
354
|
+
}
|
|
355
|
+
switch (event.type) {
|
|
356
|
+
case resolveEventType:
|
|
357
|
+
return {
|
|
358
|
+
...state,
|
|
359
|
+
status: 'done',
|
|
360
|
+
data: event.data,
|
|
361
|
+
input: undefined
|
|
362
|
+
};
|
|
363
|
+
case rejectEventType:
|
|
364
|
+
return {
|
|
365
|
+
...state,
|
|
366
|
+
status: 'error',
|
|
367
|
+
data: event.data,
|
|
368
|
+
input: undefined
|
|
369
|
+
};
|
|
370
|
+
case stopSignalType:
|
|
371
|
+
return {
|
|
372
|
+
...state,
|
|
373
|
+
status: 'canceled',
|
|
374
|
+
input: undefined
|
|
375
|
+
};
|
|
376
|
+
default:
|
|
377
|
+
return state;
|
|
378
|
+
}
|
|
648
379
|
},
|
|
649
|
-
|
|
650
|
-
return clearTimeout(id);
|
|
651
|
-
}
|
|
652
|
-
},
|
|
653
|
-
logger: console.log.bind(console),
|
|
654
|
-
devTools: false
|
|
655
|
-
};
|
|
656
|
-
class Interpreter {
|
|
657
|
-
/**
|
|
658
|
-
* The current state of the interpreted logic.
|
|
659
|
-
*/
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
|
|
663
|
-
*/
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* The unique identifier for this actor relative to its parent.
|
|
667
|
-
*/
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* Whether the service is started.
|
|
671
|
-
*/
|
|
672
|
-
|
|
673
|
-
// Actor Ref
|
|
674
|
-
|
|
675
|
-
// TODO: add typings for system
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* The globally unique process ID for this invocation.
|
|
679
|
-
*/
|
|
680
|
-
|
|
681
|
-
/**
|
|
682
|
-
* Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
|
|
683
|
-
*
|
|
684
|
-
* @param logic The logic to be interpreted
|
|
685
|
-
* @param options Interpreter options
|
|
686
|
-
*/
|
|
687
|
-
constructor(logic, options) {
|
|
688
|
-
this.logic = logic;
|
|
689
|
-
this._state = void 0;
|
|
690
|
-
this.clock = void 0;
|
|
691
|
-
this.options = void 0;
|
|
692
|
-
this.id = void 0;
|
|
693
|
-
this.mailbox = new Mailbox(this._process.bind(this));
|
|
694
|
-
this.delayedEventsMap = {};
|
|
695
|
-
this.observers = new Set();
|
|
696
|
-
this.logger = void 0;
|
|
697
|
-
this.status = ActorStatus.NotStarted;
|
|
698
|
-
this._parent = void 0;
|
|
699
|
-
this.ref = void 0;
|
|
700
|
-
this._actorContext = void 0;
|
|
701
|
-
this._systemId = void 0;
|
|
702
|
-
this.sessionId = void 0;
|
|
703
|
-
this.system = void 0;
|
|
704
|
-
this._doneEvent = void 0;
|
|
705
|
-
this.src = void 0;
|
|
706
|
-
this._deferred = [];
|
|
707
|
-
const resolvedOptions = {
|
|
708
|
-
...defaultOptions,
|
|
709
|
-
...options
|
|
710
|
-
};
|
|
711
|
-
const {
|
|
712
|
-
clock,
|
|
713
|
-
logger,
|
|
714
|
-
parent,
|
|
715
|
-
id,
|
|
716
|
-
systemId
|
|
717
|
-
} = resolvedOptions;
|
|
718
|
-
const self = this;
|
|
719
|
-
this.system = parent?.system ?? createSystem();
|
|
720
|
-
if (systemId) {
|
|
721
|
-
this._systemId = systemId;
|
|
722
|
-
this.system._set(systemId, this);
|
|
723
|
-
}
|
|
724
|
-
this.sessionId = this.system._bookId();
|
|
725
|
-
this.id = id ?? this.sessionId;
|
|
726
|
-
this.logger = logger;
|
|
727
|
-
this.clock = clock;
|
|
728
|
-
this._parent = parent;
|
|
729
|
-
this.options = resolvedOptions;
|
|
730
|
-
this.src = resolvedOptions.src;
|
|
731
|
-
this.ref = this;
|
|
732
|
-
this._actorContext = {
|
|
380
|
+
start: (state, {
|
|
733
381
|
self,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
system: this.system,
|
|
741
|
-
stopChild: child => {
|
|
742
|
-
if (child._parent !== this) {
|
|
743
|
-
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
744
|
-
}
|
|
745
|
-
child._stop();
|
|
382
|
+
system
|
|
383
|
+
}) => {
|
|
384
|
+
// TODO: determine how to allow customizing this so that promises
|
|
385
|
+
// can be restarted if necessary
|
|
386
|
+
if (state.status !== 'active') {
|
|
387
|
+
return;
|
|
746
388
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
389
|
+
const resolvedPromise = Promise.resolve(promiseCreator({
|
|
390
|
+
input: state.input,
|
|
391
|
+
system
|
|
392
|
+
}));
|
|
393
|
+
resolvedPromise.then(response => {
|
|
394
|
+
// TODO: remove this condition once dead letter queue lands
|
|
395
|
+
if (self._state.status !== 'active') {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
self.send({
|
|
399
|
+
type: resolveEventType,
|
|
400
|
+
data: response
|
|
401
|
+
});
|
|
402
|
+
}, errorData => {
|
|
403
|
+
// TODO: remove this condition once dead letter queue lands
|
|
404
|
+
if (self._state.status !== 'active') {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
self.send({
|
|
408
|
+
type: rejectEventType,
|
|
409
|
+
data: errorData
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
getInitialState: (_, input) => {
|
|
414
|
+
return {
|
|
415
|
+
status: 'active',
|
|
416
|
+
data: undefined,
|
|
417
|
+
input
|
|
418
|
+
};
|
|
419
|
+
},
|
|
420
|
+
getSnapshot: state => state.data,
|
|
421
|
+
getStatus: state => state,
|
|
422
|
+
getPersistedState: state => state,
|
|
423
|
+
restoreState: state => state
|
|
424
|
+
};
|
|
425
|
+
return logic;
|
|
426
|
+
}
|
|
759
427
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
428
|
+
// TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
|
|
429
|
+
function fromObservable(observableCreator) {
|
|
430
|
+
const nextEventType = '$$xstate.next';
|
|
431
|
+
const errorEventType = '$$xstate.error';
|
|
432
|
+
const completeEventType = '$$xstate.complete';
|
|
764
433
|
|
|
765
|
-
|
|
766
|
-
let deferredFn;
|
|
767
|
-
while (deferredFn = this._deferred.shift()) {
|
|
768
|
-
deferredFn();
|
|
769
|
-
}
|
|
770
|
-
for (const observer of this.observers) {
|
|
771
|
-
observer.next?.(snapshot);
|
|
772
|
-
}
|
|
773
|
-
const status = this.logic.getStatus?.(state);
|
|
774
|
-
switch (status?.status) {
|
|
775
|
-
case 'done':
|
|
776
|
-
this._stopProcedure();
|
|
777
|
-
this._doneEvent = doneInvoke(this.id, status.data);
|
|
778
|
-
this._parent?.send(this._doneEvent);
|
|
779
|
-
this._complete();
|
|
780
|
-
break;
|
|
781
|
-
case 'error':
|
|
782
|
-
this._stopProcedure();
|
|
783
|
-
this._parent?.send(error(this.id, status.data));
|
|
784
|
-
this._error(status.data);
|
|
785
|
-
break;
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
789
|
-
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
790
|
-
this.observers.add(observer);
|
|
791
|
-
if (this.status === ActorStatus.Stopped) {
|
|
792
|
-
observer.complete?.();
|
|
793
|
-
this.observers.delete(observer);
|
|
794
|
-
}
|
|
795
|
-
return {
|
|
796
|
-
unsubscribe: () => {
|
|
797
|
-
this.observers.delete(observer);
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
/**
|
|
803
|
-
* Starts the interpreter from the initial state
|
|
804
|
-
*/
|
|
805
|
-
start() {
|
|
806
|
-
if (this.status === ActorStatus.Running) {
|
|
807
|
-
// Do not restart the service if it is already started
|
|
808
|
-
return this;
|
|
809
|
-
}
|
|
810
|
-
this.system._register(this.sessionId, this);
|
|
811
|
-
if (this._systemId) {
|
|
812
|
-
this.system._set(this._systemId, this);
|
|
813
|
-
}
|
|
814
|
-
this.status = ActorStatus.Running;
|
|
815
|
-
if (this.logic.start) {
|
|
816
|
-
this.logic.start(this._state, this._actorContext);
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
// TODO: this notifies all subscribers but usually this is redundant
|
|
820
|
-
// there is no real change happening here
|
|
821
|
-
// we need to rethink if this needs to be refactored
|
|
822
|
-
this.update(this._state);
|
|
823
|
-
if (this.options.devTools) {
|
|
824
|
-
this.attachDevTools();
|
|
825
|
-
}
|
|
826
|
-
this.mailbox.start();
|
|
827
|
-
return this;
|
|
828
|
-
}
|
|
829
|
-
_process(event) {
|
|
830
|
-
try {
|
|
831
|
-
const nextState = this.logic.transition(this._state, event, this._actorContext);
|
|
832
|
-
this.update(nextState);
|
|
833
|
-
if (event.type === stopSignalType) {
|
|
834
|
-
this._stopProcedure();
|
|
835
|
-
this._complete();
|
|
836
|
-
}
|
|
837
|
-
} catch (err) {
|
|
838
|
-
// TODO: properly handle errors
|
|
839
|
-
if (this.observers.size > 0) {
|
|
840
|
-
this.observers.forEach(observer => {
|
|
841
|
-
observer.error?.(err);
|
|
842
|
-
});
|
|
843
|
-
this.stop();
|
|
844
|
-
} else {
|
|
845
|
-
throw err;
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
_stop() {
|
|
850
|
-
if (this.status === ActorStatus.Stopped) {
|
|
851
|
-
return this;
|
|
852
|
-
}
|
|
853
|
-
this.mailbox.clear();
|
|
854
|
-
if (this.status === ActorStatus.NotStarted) {
|
|
855
|
-
this.status = ActorStatus.Stopped;
|
|
856
|
-
return this;
|
|
857
|
-
}
|
|
858
|
-
this.mailbox.enqueue({
|
|
859
|
-
type: stopSignalType
|
|
860
|
-
});
|
|
861
|
-
return this;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
/**
|
|
865
|
-
* Stops the interpreter and unsubscribe all listeners.
|
|
866
|
-
*/
|
|
867
|
-
stop() {
|
|
868
|
-
if (this._parent) {
|
|
869
|
-
throw new Error('A non-root actor cannot be stopped directly.');
|
|
870
|
-
}
|
|
871
|
-
return this._stop();
|
|
872
|
-
}
|
|
873
|
-
_complete() {
|
|
874
|
-
for (const observer of this.observers) {
|
|
875
|
-
observer.complete?.();
|
|
876
|
-
}
|
|
877
|
-
this.observers.clear();
|
|
878
|
-
}
|
|
879
|
-
_error(data) {
|
|
880
|
-
for (const observer of this.observers) {
|
|
881
|
-
observer.error?.(data);
|
|
882
|
-
}
|
|
883
|
-
this.observers.clear();
|
|
884
|
-
}
|
|
885
|
-
_stopProcedure() {
|
|
886
|
-
if (this.status !== ActorStatus.Running) {
|
|
887
|
-
// Interpreter already stopped; do nothing
|
|
888
|
-
return this;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
// Cancel all delayed events
|
|
892
|
-
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
893
|
-
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// TODO: mailbox.reset
|
|
897
|
-
this.mailbox.clear();
|
|
898
|
-
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
899
|
-
// events sent *after* stop signal must be queued
|
|
900
|
-
// it seems like this should be the common behavior for all of our consumers
|
|
901
|
-
// so perhaps this should be unified somehow for all of them
|
|
902
|
-
this.mailbox = new Mailbox(this._process.bind(this));
|
|
903
|
-
this.status = ActorStatus.Stopped;
|
|
904
|
-
this.system._unregister(this);
|
|
905
|
-
return this;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
/**
|
|
909
|
-
* Sends an event to the running interpreter to trigger a transition.
|
|
910
|
-
*
|
|
911
|
-
* @param event The event to send
|
|
912
|
-
*/
|
|
913
|
-
send(event) {
|
|
914
|
-
if (typeof event === 'string') {
|
|
915
|
-
throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
|
|
916
|
-
}
|
|
917
|
-
if (this.status === ActorStatus.Stopped) {
|
|
918
|
-
// do nothing
|
|
919
|
-
{
|
|
920
|
-
const eventString = JSON.stringify(event);
|
|
921
|
-
console.warn(`Event "${event.type.toString()}" was sent to stopped actor "${this.id} (${this.sessionId})". This actor has already reached its final state, and will not transition.\nEvent: ${eventString}`);
|
|
922
|
-
}
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
|
|
926
|
-
throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
|
|
927
|
-
// tslint:disable-next-line:max-line-length
|
|
928
|
-
}". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
|
|
929
|
-
}
|
|
930
|
-
this.mailbox.enqueue(event);
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// TODO: make private (and figure out a way to do this within the machine)
|
|
934
|
-
delaySend(sendAction) {
|
|
935
|
-
this.delayedEventsMap[sendAction.params.id] = this.clock.setTimeout(() => {
|
|
936
|
-
if ('to' in sendAction.params && sendAction.params.to) {
|
|
937
|
-
sendAction.params.to.send(sendAction.params.event);
|
|
938
|
-
} else {
|
|
939
|
-
this.send(sendAction.params.event);
|
|
940
|
-
}
|
|
941
|
-
}, sendAction.params.delay);
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// TODO: make private (and figure out a way to do this within the machine)
|
|
945
|
-
cancel(sendId) {
|
|
946
|
-
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
947
|
-
delete this.delayedEventsMap[sendId];
|
|
948
|
-
}
|
|
949
|
-
attachDevTools() {
|
|
950
|
-
const {
|
|
951
|
-
devTools
|
|
952
|
-
} = this.options;
|
|
953
|
-
if (devTools) {
|
|
954
|
-
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : dev_dist_xstateDev.devToolsAdapter;
|
|
955
|
-
resolvedDevToolsAdapter(this);
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
toJSON() {
|
|
959
|
-
return {
|
|
960
|
-
id: this.id
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
getPersistedState() {
|
|
964
|
-
return this.logic.getPersistedState?.(this._state);
|
|
965
|
-
}
|
|
966
|
-
[symbolObservable]() {
|
|
967
|
-
return this;
|
|
968
|
-
}
|
|
969
|
-
getSnapshot() {
|
|
970
|
-
return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
/**
|
|
975
|
-
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
976
|
-
*
|
|
977
|
-
* @param machine The machine to interpret
|
|
978
|
-
* @param options Interpreter options
|
|
979
|
-
*/
|
|
980
|
-
|
|
981
|
-
function interpret(logic, options) {
|
|
982
|
-
const interpreter = new Interpreter(logic, options);
|
|
983
|
-
return interpreter;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
/**
|
|
987
|
-
* Returns actor logic from a transition function and its initial state.
|
|
988
|
-
*
|
|
989
|
-
* A transition function is a function that takes the current state and an event and returns the next state.
|
|
990
|
-
*
|
|
991
|
-
* @param transition The transition function that returns the next state given the current state and event.
|
|
992
|
-
* @param initialState The initial state of the transition function.
|
|
993
|
-
* @returns Actor logic
|
|
994
|
-
*/
|
|
995
|
-
function fromTransition(transition, initialState) {
|
|
996
|
-
const logic = {
|
|
997
|
-
config: transition,
|
|
998
|
-
transition: (state, event, actorContext) => {
|
|
999
|
-
return transition(state, event, actorContext);
|
|
1000
|
-
},
|
|
1001
|
-
getInitialState: (_, input) => {
|
|
1002
|
-
return typeof initialState === 'function' ? initialState({
|
|
1003
|
-
input
|
|
1004
|
-
}) : initialState;
|
|
1005
|
-
},
|
|
1006
|
-
getSnapshot: state => state,
|
|
1007
|
-
getPersistedState: state => state,
|
|
1008
|
-
restoreState: state => state
|
|
1009
|
-
};
|
|
1010
|
-
return logic;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
const resolveEventType = '$$xstate.resolve';
|
|
1014
|
-
const rejectEventType = '$$xstate.reject';
|
|
1015
|
-
function fromPromise(
|
|
1016
|
-
// TODO: add types
|
|
1017
|
-
promiseCreator) {
|
|
1018
|
-
// TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
|
|
434
|
+
// TODO: add event types
|
|
1019
435
|
const logic = {
|
|
1020
|
-
config:
|
|
1021
|
-
transition: (state, event
|
|
436
|
+
config: observableCreator,
|
|
437
|
+
transition: (state, event, {
|
|
438
|
+
self,
|
|
439
|
+
id,
|
|
440
|
+
defer
|
|
441
|
+
}) => {
|
|
1022
442
|
if (state.status !== 'active') {
|
|
1023
443
|
return state;
|
|
1024
444
|
}
|
|
1025
445
|
switch (event.type) {
|
|
1026
|
-
case
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
...state,
|
|
1036
|
-
status: 'error',
|
|
1037
|
-
data: event.data,
|
|
1038
|
-
input: undefined
|
|
1039
|
-
};
|
|
1040
|
-
case stopSignalType:
|
|
1041
|
-
return {
|
|
1042
|
-
...state,
|
|
1043
|
-
status: 'canceled',
|
|
1044
|
-
input: undefined
|
|
1045
|
-
};
|
|
1046
|
-
default:
|
|
1047
|
-
return state;
|
|
1048
|
-
}
|
|
1049
|
-
},
|
|
1050
|
-
start: (state, {
|
|
1051
|
-
self,
|
|
1052
|
-
system
|
|
1053
|
-
}) => {
|
|
1054
|
-
// TODO: determine how to allow customizing this so that promises
|
|
1055
|
-
// can be restarted if necessary
|
|
1056
|
-
if (state.status !== 'active') {
|
|
1057
|
-
return;
|
|
1058
|
-
}
|
|
1059
|
-
const resolvedPromise = Promise.resolve(promiseCreator({
|
|
1060
|
-
input: state.input,
|
|
1061
|
-
system
|
|
1062
|
-
}));
|
|
1063
|
-
resolvedPromise.then(response => {
|
|
1064
|
-
// TODO: remove this condition once dead letter queue lands
|
|
1065
|
-
if (self._state.status !== 'active') {
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
self.send({
|
|
1069
|
-
type: resolveEventType,
|
|
1070
|
-
data: response
|
|
1071
|
-
});
|
|
1072
|
-
}, errorData => {
|
|
1073
|
-
// TODO: remove this condition once dead letter queue lands
|
|
1074
|
-
if (self._state.status !== 'active') {
|
|
1075
|
-
return;
|
|
1076
|
-
}
|
|
1077
|
-
self.send({
|
|
1078
|
-
type: rejectEventType,
|
|
1079
|
-
data: errorData
|
|
1080
|
-
});
|
|
1081
|
-
});
|
|
1082
|
-
},
|
|
1083
|
-
getInitialState: (_, input) => {
|
|
1084
|
-
return {
|
|
1085
|
-
status: 'active',
|
|
1086
|
-
data: undefined,
|
|
1087
|
-
input
|
|
1088
|
-
};
|
|
1089
|
-
},
|
|
1090
|
-
getSnapshot: state => state.data,
|
|
1091
|
-
getStatus: state => state,
|
|
1092
|
-
getPersistedState: state => state,
|
|
1093
|
-
restoreState: state => state
|
|
1094
|
-
};
|
|
1095
|
-
return logic;
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
// TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
|
|
1099
|
-
function fromObservable(observableCreator) {
|
|
1100
|
-
const nextEventType = '$$xstate.next';
|
|
1101
|
-
const errorEventType = '$$xstate.error';
|
|
1102
|
-
const completeEventType = '$$xstate.complete';
|
|
1103
|
-
|
|
1104
|
-
// TODO: add event types
|
|
1105
|
-
const logic = {
|
|
1106
|
-
config: observableCreator,
|
|
1107
|
-
transition: (state, event, {
|
|
1108
|
-
self,
|
|
1109
|
-
id,
|
|
1110
|
-
defer
|
|
1111
|
-
}) => {
|
|
1112
|
-
if (state.status !== 'active') {
|
|
1113
|
-
return state;
|
|
1114
|
-
}
|
|
1115
|
-
switch (event.type) {
|
|
1116
|
-
case nextEventType:
|
|
1117
|
-
// match the exact timing of events sent by machines
|
|
1118
|
-
// send actions are not executed immediately
|
|
1119
|
-
defer(() => {
|
|
1120
|
-
self._parent?.send({
|
|
1121
|
-
type: `xstate.snapshot.${id}`,
|
|
1122
|
-
data: event.data
|
|
1123
|
-
});
|
|
1124
|
-
});
|
|
446
|
+
case nextEventType:
|
|
447
|
+
// match the exact timing of events sent by machines
|
|
448
|
+
// send actions are not executed immediately
|
|
449
|
+
defer(() => {
|
|
450
|
+
self._parent?.send({
|
|
451
|
+
type: `xstate.snapshot.${id}`,
|
|
452
|
+
data: event.data
|
|
453
|
+
});
|
|
454
|
+
});
|
|
1125
455
|
return {
|
|
1126
456
|
...state,
|
|
1127
457
|
data: event.data
|
|
@@ -1314,208 +644,770 @@ function fromEventObservable(lazyObservable) {
|
|
|
1314
644
|
return logic;
|
|
1315
645
|
}
|
|
1316
646
|
|
|
1317
|
-
function
|
|
1318
|
-
const
|
|
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
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
647
|
+
function matchesState(parentStateId, childStateId) {
|
|
648
|
+
const parentStateValue = toStateValue(parentStateId);
|
|
649
|
+
const childStateValue = toStateValue(childStateId);
|
|
650
|
+
if (typeof childStateValue === 'string') {
|
|
651
|
+
if (typeof parentStateValue === 'string') {
|
|
652
|
+
return childStateValue === parentStateValue;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Parent more specific than child
|
|
656
|
+
return false;
|
|
657
|
+
}
|
|
658
|
+
if (typeof parentStateValue === 'string') {
|
|
659
|
+
return parentStateValue in childStateValue;
|
|
660
|
+
}
|
|
661
|
+
return Object.keys(parentStateValue).every(key => {
|
|
662
|
+
if (!(key in childStateValue)) {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
return matchesState(parentStateValue[key], childStateValue[key]);
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
function toStatePath(stateId) {
|
|
669
|
+
try {
|
|
670
|
+
if (isArray(stateId)) {
|
|
671
|
+
return stateId;
|
|
672
|
+
}
|
|
673
|
+
return stateId.toString().split(STATE_DELIMITER);
|
|
674
|
+
} catch (e) {
|
|
675
|
+
throw new Error(`'${stateId}' is not a valid state path.`);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function isStateLike(state) {
|
|
679
|
+
return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state;
|
|
680
|
+
}
|
|
681
|
+
function toStateValue(stateValue) {
|
|
682
|
+
if (isStateLike(stateValue)) {
|
|
683
|
+
return stateValue.value;
|
|
684
|
+
}
|
|
685
|
+
if (isArray(stateValue)) {
|
|
686
|
+
return pathToStateValue(stateValue);
|
|
687
|
+
}
|
|
688
|
+
if (typeof stateValue !== 'string') {
|
|
689
|
+
return stateValue;
|
|
690
|
+
}
|
|
691
|
+
const statePath = toStatePath(stateValue);
|
|
692
|
+
return pathToStateValue(statePath);
|
|
693
|
+
}
|
|
694
|
+
function pathToStateValue(statePath) {
|
|
695
|
+
if (statePath.length === 1) {
|
|
696
|
+
return statePath[0];
|
|
697
|
+
}
|
|
698
|
+
const value = {};
|
|
699
|
+
let marker = value;
|
|
700
|
+
for (let i = 0; i < statePath.length - 1; i++) {
|
|
701
|
+
if (i === statePath.length - 2) {
|
|
702
|
+
marker[statePath[i]] = statePath[i + 1];
|
|
703
|
+
} else {
|
|
704
|
+
const previous = marker;
|
|
705
|
+
marker = {};
|
|
706
|
+
previous[statePath[i]] = marker;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return value;
|
|
710
|
+
}
|
|
711
|
+
function mapValues(collection, iteratee) {
|
|
712
|
+
const result = {};
|
|
713
|
+
const collectionKeys = Object.keys(collection);
|
|
714
|
+
for (let i = 0; i < collectionKeys.length; i++) {
|
|
715
|
+
const key = collectionKeys[i];
|
|
716
|
+
result[key] = iteratee(collection[key], key, collection, i);
|
|
717
|
+
}
|
|
718
|
+
return result;
|
|
719
|
+
}
|
|
720
|
+
function flatten(array) {
|
|
721
|
+
return [].concat(...array);
|
|
722
|
+
}
|
|
723
|
+
function toArrayStrict(value) {
|
|
724
|
+
if (isArray(value)) {
|
|
725
|
+
return value;
|
|
726
|
+
}
|
|
727
|
+
return [value];
|
|
728
|
+
}
|
|
729
|
+
function toArray(value) {
|
|
730
|
+
if (value === undefined) {
|
|
731
|
+
return [];
|
|
732
|
+
}
|
|
733
|
+
return toArrayStrict(value);
|
|
734
|
+
}
|
|
735
|
+
function mapContext(mapper, context, event) {
|
|
736
|
+
if (typeof mapper === 'function') {
|
|
737
|
+
return mapper({
|
|
738
|
+
context,
|
|
739
|
+
event
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
const result = {};
|
|
743
|
+
const args = {
|
|
744
|
+
context,
|
|
745
|
+
event
|
|
746
|
+
};
|
|
747
|
+
for (const key of Object.keys(mapper)) {
|
|
748
|
+
const subMapper = mapper[key];
|
|
749
|
+
if (typeof subMapper === 'function') {
|
|
750
|
+
result[key] = subMapper(args);
|
|
751
|
+
} else {
|
|
752
|
+
result[key] = subMapper;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return result;
|
|
756
|
+
}
|
|
757
|
+
function isPromiseLike(value) {
|
|
758
|
+
if (value instanceof Promise) {
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
// Check if shape matches the Promise/A+ specification for a "thenable".
|
|
762
|
+
if (value !== null && (typeof value === 'function' || typeof value === 'object') && typeof value.then === 'function') {
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
function isArray(value) {
|
|
768
|
+
return Array.isArray(value);
|
|
769
|
+
}
|
|
770
|
+
function isErrorEvent(event) {
|
|
771
|
+
return typeof event.type === 'string' && (event.type === errorExecution || event.type.startsWith(errorPlatform));
|
|
772
|
+
}
|
|
773
|
+
function toTransitionConfigArray(configLike) {
|
|
774
|
+
return toArrayStrict(configLike).map(transitionLike => {
|
|
775
|
+
if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
|
|
776
|
+
return {
|
|
777
|
+
target: transitionLike
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
return transitionLike;
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
function normalizeTarget(target) {
|
|
784
|
+
if (target === undefined || target === TARGETLESS_KEY) {
|
|
785
|
+
return undefined;
|
|
786
|
+
}
|
|
787
|
+
return toArray(target);
|
|
788
|
+
}
|
|
789
|
+
function toInvokeConfig(invocable, id) {
|
|
790
|
+
if (typeof invocable === 'object') {
|
|
791
|
+
if ('src' in invocable) {
|
|
792
|
+
return invocable;
|
|
793
|
+
}
|
|
794
|
+
if ('transition' in invocable) {
|
|
795
|
+
return {
|
|
796
|
+
id,
|
|
797
|
+
src: invocable
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return {
|
|
802
|
+
id,
|
|
803
|
+
src: invocable
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
function toObserver(nextHandler, errorHandler, completionHandler) {
|
|
807
|
+
const noop = () => {};
|
|
808
|
+
const isObserver = typeof nextHandler === 'object';
|
|
809
|
+
const self = isObserver ? nextHandler : null;
|
|
810
|
+
return {
|
|
811
|
+
next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
|
|
812
|
+
error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
|
|
813
|
+
complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function createInvokeId(stateNodeId, index) {
|
|
817
|
+
return `${stateNodeId}:invocation[${index}]`;
|
|
818
|
+
}
|
|
819
|
+
function resolveReferencedActor(referenced) {
|
|
820
|
+
return referenced ? 'transition' in referenced ? {
|
|
821
|
+
src: referenced,
|
|
822
|
+
input: undefined
|
|
823
|
+
} : referenced : undefined;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
function fromCallback(invokeCallback) {
|
|
827
|
+
const logic = {
|
|
828
|
+
config: invokeCallback,
|
|
829
|
+
start: (_state, {
|
|
830
|
+
self
|
|
831
|
+
}) => {
|
|
832
|
+
self.send({
|
|
833
|
+
type: startSignalType
|
|
834
|
+
});
|
|
835
|
+
},
|
|
836
|
+
transition: (state, event, {
|
|
837
|
+
self,
|
|
838
|
+
id,
|
|
839
|
+
system
|
|
840
|
+
}) => {
|
|
841
|
+
if (event.type === startSignalType) {
|
|
842
|
+
const sender = eventForParent => {
|
|
843
|
+
if (state.canceled) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
self._parent?.send(eventForParent);
|
|
847
|
+
};
|
|
848
|
+
const receiver = newListener => {
|
|
849
|
+
state.receivers.add(newListener);
|
|
850
|
+
};
|
|
851
|
+
state.dispose = invokeCallback(sender, receiver, {
|
|
852
|
+
input: state.input,
|
|
853
|
+
system
|
|
854
|
+
});
|
|
855
|
+
if (isPromiseLike(state.dispose)) {
|
|
856
|
+
state.dispose.then(resolved => {
|
|
857
|
+
self._parent?.send(doneInvoke(id, resolved));
|
|
858
|
+
state.canceled = true;
|
|
859
|
+
}, errorData => {
|
|
860
|
+
state.canceled = true;
|
|
861
|
+
self._parent?.send(error(id, errorData));
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
return state;
|
|
865
|
+
}
|
|
866
|
+
if (event.type === stopSignalType) {
|
|
867
|
+
state.canceled = true;
|
|
868
|
+
if (typeof state.dispose === 'function') {
|
|
869
|
+
state.dispose();
|
|
870
|
+
}
|
|
871
|
+
return state;
|
|
872
|
+
}
|
|
873
|
+
if (isSignal(event)) {
|
|
874
|
+
// TODO: unrecognized signal
|
|
875
|
+
return state;
|
|
876
|
+
}
|
|
877
|
+
state.receivers.forEach(receiver => receiver(event));
|
|
878
|
+
return state;
|
|
879
|
+
},
|
|
880
|
+
getInitialState: (_, input) => {
|
|
881
|
+
return {
|
|
882
|
+
canceled: false,
|
|
883
|
+
receivers: new Set(),
|
|
884
|
+
dispose: undefined,
|
|
885
|
+
input
|
|
886
|
+
};
|
|
887
|
+
},
|
|
888
|
+
getSnapshot: () => undefined,
|
|
889
|
+
getPersistedState: ({
|
|
890
|
+
input
|
|
891
|
+
}) => input
|
|
892
|
+
};
|
|
893
|
+
return logic;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
const startSignalType = 'xstate.init';
|
|
897
|
+
const stopSignalType = 'xstate.stop';
|
|
898
|
+
const startSignal = {
|
|
899
|
+
type: 'xstate.init'
|
|
900
|
+
};
|
|
901
|
+
const stopSignal = {
|
|
902
|
+
type: 'xstate.stop'
|
|
903
|
+
};
|
|
904
|
+
/**
|
|
905
|
+
* An object that expresses the actor logic in reaction to received events,
|
|
906
|
+
* as well as an optionally emitted stream of values.
|
|
907
|
+
*
|
|
908
|
+
* @template TReceived The received event
|
|
909
|
+
* @template TSnapshot The emitted value
|
|
910
|
+
*/
|
|
911
|
+
|
|
912
|
+
function isSignal(event) {
|
|
913
|
+
return event.type === startSignalType || event.type === stopSignalType;
|
|
914
|
+
}
|
|
915
|
+
function isActorRef(item) {
|
|
916
|
+
return !!item && typeof item === 'object' && typeof item.send === 'function';
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// TODO: refactor the return type, this could be written in a better way
|
|
920
|
+
// but it's best to avoid unneccessary breaking changes now
|
|
921
|
+
// @deprecated use `interpret(actorLogic)` instead
|
|
922
|
+
function toActorRef(actorRefLike) {
|
|
923
|
+
return {
|
|
924
|
+
subscribe: () => ({
|
|
925
|
+
unsubscribe: () => void 0
|
|
926
|
+
}),
|
|
927
|
+
id: 'anonymous',
|
|
928
|
+
sessionId: '',
|
|
929
|
+
getSnapshot: () => undefined,
|
|
930
|
+
[symbolObservable]: function () {
|
|
931
|
+
return this;
|
|
932
|
+
},
|
|
933
|
+
status: ActorStatus.Running,
|
|
934
|
+
stop: () => void 0,
|
|
935
|
+
...actorRefLike
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
const emptyLogic = fromTransition(_ => undefined, undefined);
|
|
939
|
+
function createEmptyActor() {
|
|
940
|
+
return interpret(emptyLogic);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
function createSystem() {
|
|
944
|
+
let sessionIdCounter = 0;
|
|
945
|
+
const children = new Map();
|
|
946
|
+
const keyedActors = new Map();
|
|
947
|
+
const reverseKeyedActors = new WeakMap();
|
|
948
|
+
const system = {
|
|
949
|
+
_bookId: () => `x:${sessionIdCounter++}`,
|
|
950
|
+
_register: (sessionId, actorRef) => {
|
|
951
|
+
children.set(sessionId, actorRef);
|
|
952
|
+
return sessionId;
|
|
953
|
+
},
|
|
954
|
+
_unregister: actorRef => {
|
|
955
|
+
children.delete(actorRef.sessionId);
|
|
956
|
+
const systemId = reverseKeyedActors.get(actorRef);
|
|
957
|
+
if (systemId !== undefined) {
|
|
958
|
+
keyedActors.delete(systemId);
|
|
959
|
+
reverseKeyedActors.delete(actorRef);
|
|
960
|
+
}
|
|
961
|
+
},
|
|
962
|
+
get: systemId => {
|
|
963
|
+
return keyedActors.get(systemId);
|
|
964
|
+
},
|
|
965
|
+
_set: (systemId, actorRef) => {
|
|
966
|
+
const existing = keyedActors.get(systemId);
|
|
967
|
+
if (existing && existing !== actorRef) {
|
|
968
|
+
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
969
|
+
}
|
|
970
|
+
keyedActors.set(systemId, actorRef);
|
|
971
|
+
reverseKeyedActors.set(actorRef, systemId);
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
return system;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
let ActorStatus = /*#__PURE__*/function (ActorStatus) {
|
|
978
|
+
ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
|
|
979
|
+
ActorStatus[ActorStatus["Running"] = 1] = "Running";
|
|
980
|
+
ActorStatus[ActorStatus["Stopped"] = 2] = "Stopped";
|
|
981
|
+
return ActorStatus;
|
|
982
|
+
}({});
|
|
983
|
+
const defaultOptions = {
|
|
984
|
+
deferEvents: true,
|
|
985
|
+
clock: {
|
|
986
|
+
setTimeout: (fn, ms) => {
|
|
987
|
+
return setTimeout(fn, ms);
|
|
988
|
+
},
|
|
989
|
+
clearTimeout: id => {
|
|
990
|
+
return clearTimeout(id);
|
|
991
|
+
}
|
|
992
|
+
},
|
|
993
|
+
logger: console.log.bind(console),
|
|
994
|
+
devTools: false
|
|
995
|
+
};
|
|
996
|
+
class Interpreter {
|
|
997
|
+
/**
|
|
998
|
+
* The current state of the interpreted logic.
|
|
999
|
+
*/
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
|
|
1003
|
+
*/
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* The unique identifier for this actor relative to its parent.
|
|
1007
|
+
*/
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* Whether the service is started.
|
|
1011
|
+
*/
|
|
1012
|
+
|
|
1013
|
+
// Actor Ref
|
|
1014
|
+
|
|
1015
|
+
// TODO: add typings for system
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* The globally unique process ID for this invocation.
|
|
1019
|
+
*/
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
|
|
1023
|
+
*
|
|
1024
|
+
* @param logic The logic to be interpreted
|
|
1025
|
+
* @param options Interpreter options
|
|
1026
|
+
*/
|
|
1027
|
+
constructor(logic, options) {
|
|
1028
|
+
this.logic = logic;
|
|
1029
|
+
this._state = void 0;
|
|
1030
|
+
this.clock = void 0;
|
|
1031
|
+
this.options = void 0;
|
|
1032
|
+
this.id = void 0;
|
|
1033
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
1034
|
+
this.delayedEventsMap = {};
|
|
1035
|
+
this.observers = new Set();
|
|
1036
|
+
this.logger = void 0;
|
|
1037
|
+
this.status = ActorStatus.NotStarted;
|
|
1038
|
+
this._parent = void 0;
|
|
1039
|
+
this.ref = void 0;
|
|
1040
|
+
this._actorContext = void 0;
|
|
1041
|
+
this._systemId = void 0;
|
|
1042
|
+
this.sessionId = void 0;
|
|
1043
|
+
this.system = void 0;
|
|
1044
|
+
this._doneEvent = void 0;
|
|
1045
|
+
this.src = void 0;
|
|
1046
|
+
this._deferred = [];
|
|
1047
|
+
const resolvedOptions = {
|
|
1048
|
+
...defaultOptions,
|
|
1049
|
+
...options
|
|
1050
|
+
};
|
|
1051
|
+
const {
|
|
1052
|
+
clock,
|
|
1053
|
+
logger,
|
|
1054
|
+
parent,
|
|
1055
|
+
id,
|
|
1056
|
+
systemId
|
|
1057
|
+
} = resolvedOptions;
|
|
1058
|
+
const self = this;
|
|
1059
|
+
this.system = parent?.system ?? createSystem();
|
|
1060
|
+
if (systemId) {
|
|
1061
|
+
this._systemId = systemId;
|
|
1062
|
+
this.system._set(systemId, this);
|
|
1063
|
+
}
|
|
1064
|
+
this.sessionId = this.system._bookId();
|
|
1065
|
+
this.id = id ?? this.sessionId;
|
|
1066
|
+
this.logger = logger;
|
|
1067
|
+
this.clock = clock;
|
|
1068
|
+
this._parent = parent;
|
|
1069
|
+
this.options = resolvedOptions;
|
|
1070
|
+
this.src = resolvedOptions.src;
|
|
1071
|
+
this.ref = this;
|
|
1072
|
+
this._actorContext = {
|
|
1073
|
+
self,
|
|
1074
|
+
id: this.id,
|
|
1075
|
+
sessionId: this.sessionId,
|
|
1076
|
+
logger: this.logger,
|
|
1077
|
+
defer: fn => {
|
|
1078
|
+
this._deferred.push(fn);
|
|
1079
|
+
},
|
|
1080
|
+
system: this.system,
|
|
1081
|
+
stopChild: child => {
|
|
1082
|
+
if (child._parent !== this) {
|
|
1083
|
+
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
1084
|
+
}
|
|
1085
|
+
child._stop();
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
// Ensure that the send method is bound to this interpreter instance
|
|
1090
|
+
// if destructured
|
|
1091
|
+
this.send = this.send.bind(this);
|
|
1092
|
+
this._initState();
|
|
1093
|
+
}
|
|
1094
|
+
_initState() {
|
|
1095
|
+
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);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// array of functions to defer
|
|
1099
|
+
|
|
1100
|
+
update(state) {
|
|
1101
|
+
// Update state
|
|
1102
|
+
this._state = state;
|
|
1103
|
+
const snapshot = this.getSnapshot();
|
|
1104
|
+
|
|
1105
|
+
// Execute deferred effects
|
|
1106
|
+
let deferredFn;
|
|
1107
|
+
while (deferredFn = this._deferred.shift()) {
|
|
1108
|
+
deferredFn();
|
|
1109
|
+
}
|
|
1110
|
+
for (const observer of this.observers) {
|
|
1111
|
+
observer.next?.(snapshot);
|
|
1112
|
+
}
|
|
1113
|
+
const status = this.logic.getStatus?.(state);
|
|
1114
|
+
switch (status?.status) {
|
|
1115
|
+
case 'done':
|
|
1116
|
+
this._stopProcedure();
|
|
1117
|
+
this._doneEvent = doneInvoke(this.id, status.data);
|
|
1118
|
+
this._parent?.send(this._doneEvent);
|
|
1119
|
+
this._complete();
|
|
1120
|
+
break;
|
|
1121
|
+
case 'error':
|
|
1122
|
+
this._stopProcedure();
|
|
1123
|
+
this._parent?.send(error(this.id, status.data));
|
|
1124
|
+
this._error(status.data);
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
1129
|
+
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
1130
|
+
this.observers.add(observer);
|
|
1131
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1132
|
+
observer.complete?.();
|
|
1133
|
+
this.observers.delete(observer);
|
|
1134
|
+
}
|
|
1135
|
+
return {
|
|
1136
|
+
unsubscribe: () => {
|
|
1137
|
+
this.observers.delete(observer);
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Starts the interpreter from the initial state
|
|
1144
|
+
*/
|
|
1145
|
+
start() {
|
|
1146
|
+
if (this.status === ActorStatus.Running) {
|
|
1147
|
+
// Do not restart the service if it is already started
|
|
1148
|
+
return this;
|
|
1149
|
+
}
|
|
1150
|
+
this.system._register(this.sessionId, this);
|
|
1151
|
+
if (this._systemId) {
|
|
1152
|
+
this.system._set(this._systemId, this);
|
|
1153
|
+
}
|
|
1154
|
+
this.status = ActorStatus.Running;
|
|
1155
|
+
if (this.logic.start) {
|
|
1156
|
+
this.logic.start(this._state, this._actorContext);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// TODO: this notifies all subscribers but usually this is redundant
|
|
1160
|
+
// there is no real change happening here
|
|
1161
|
+
// we need to rethink if this needs to be refactored
|
|
1162
|
+
this.update(this._state);
|
|
1163
|
+
if (this.options.devTools) {
|
|
1164
|
+
this.attachDevTools();
|
|
1165
|
+
}
|
|
1166
|
+
this.mailbox.start();
|
|
1167
|
+
return this;
|
|
1168
|
+
}
|
|
1169
|
+
_process(event) {
|
|
1170
|
+
try {
|
|
1171
|
+
const nextState = this.logic.transition(this._state, event, this._actorContext);
|
|
1172
|
+
this.update(nextState);
|
|
1173
|
+
if (event.type === stopSignalType) {
|
|
1174
|
+
this._stopProcedure();
|
|
1175
|
+
this._complete();
|
|
1176
|
+
}
|
|
1177
|
+
} catch (err) {
|
|
1178
|
+
// TODO: properly handle errors
|
|
1179
|
+
if (this.observers.size > 0) {
|
|
1180
|
+
this.observers.forEach(observer => {
|
|
1181
|
+
observer.error?.(err);
|
|
1182
|
+
});
|
|
1183
|
+
this.stop();
|
|
1184
|
+
} else {
|
|
1185
|
+
throw err;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
_stop() {
|
|
1190
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1191
|
+
return this;
|
|
1192
|
+
}
|
|
1193
|
+
this.mailbox.clear();
|
|
1194
|
+
if (this.status === ActorStatus.NotStarted) {
|
|
1195
|
+
this.status = ActorStatus.Stopped;
|
|
1196
|
+
return this;
|
|
1197
|
+
}
|
|
1198
|
+
this.mailbox.enqueue({
|
|
1199
|
+
type: stopSignalType
|
|
1200
|
+
});
|
|
1201
|
+
return this;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* Stops the interpreter and unsubscribe all listeners.
|
|
1206
|
+
*/
|
|
1207
|
+
stop() {
|
|
1208
|
+
if (this._parent) {
|
|
1209
|
+
throw new Error('A non-root actor cannot be stopped directly.');
|
|
1210
|
+
}
|
|
1211
|
+
return this._stop();
|
|
1212
|
+
}
|
|
1213
|
+
_complete() {
|
|
1214
|
+
for (const observer of this.observers) {
|
|
1215
|
+
observer.complete?.();
|
|
1216
|
+
}
|
|
1217
|
+
this.observers.clear();
|
|
1218
|
+
}
|
|
1219
|
+
_error(data) {
|
|
1220
|
+
for (const observer of this.observers) {
|
|
1221
|
+
observer.error?.(data);
|
|
1222
|
+
}
|
|
1223
|
+
this.observers.clear();
|
|
1224
|
+
}
|
|
1225
|
+
_stopProcedure() {
|
|
1226
|
+
if (this.status !== ActorStatus.Running) {
|
|
1227
|
+
// Interpreter already stopped; do nothing
|
|
1228
|
+
return this;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// Cancel all delayed events
|
|
1232
|
+
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
1233
|
+
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// TODO: mailbox.reset
|
|
1237
|
+
this.mailbox.clear();
|
|
1238
|
+
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
1239
|
+
// events sent *after* stop signal must be queued
|
|
1240
|
+
// it seems like this should be the common behavior for all of our consumers
|
|
1241
|
+
// so perhaps this should be unified somehow for all of them
|
|
1242
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
1243
|
+
this.status = ActorStatus.Stopped;
|
|
1244
|
+
this.system._unregister(this);
|
|
1245
|
+
return this;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* Sends an event to the running interpreter to trigger a transition.
|
|
1250
|
+
*
|
|
1251
|
+
* @param event The event to send
|
|
1252
|
+
*/
|
|
1253
|
+
send(event) {
|
|
1254
|
+
if (typeof event === 'string') {
|
|
1255
|
+
throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
|
|
1256
|
+
}
|
|
1257
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1258
|
+
// do nothing
|
|
1259
|
+
{
|
|
1260
|
+
const eventString = JSON.stringify(event);
|
|
1261
|
+
console.warn(`Event "${event.type.toString()}" was sent to stopped actor "${this.id} (${this.sessionId})". This actor has already reached its final state, and will not transition.\nEvent: ${eventString}`);
|
|
1262
|
+
}
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
|
|
1266
|
+
throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
|
|
1267
|
+
// tslint:disable-next-line:max-line-length
|
|
1268
|
+
}". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
|
|
1269
|
+
}
|
|
1270
|
+
this.mailbox.enqueue(event);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// TODO: make private (and figure out a way to do this within the machine)
|
|
1274
|
+
delaySend({
|
|
1275
|
+
event,
|
|
1276
|
+
id,
|
|
1277
|
+
delay,
|
|
1278
|
+
to
|
|
1279
|
+
}) {
|
|
1280
|
+
const timerId = this.clock.setTimeout(() => {
|
|
1281
|
+
if (to) {
|
|
1282
|
+
to.send(event);
|
|
1283
|
+
} else {
|
|
1284
|
+
this.send(event);
|
|
1285
|
+
}
|
|
1286
|
+
}, delay);
|
|
1287
|
+
|
|
1288
|
+
// TODO: consider the rehydration story here
|
|
1289
|
+
if (id) {
|
|
1290
|
+
this.delayedEventsMap[id] = timerId;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// TODO: make private (and figure out a way to do this within the machine)
|
|
1295
|
+
cancel(sendId) {
|
|
1296
|
+
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
1297
|
+
delete this.delayedEventsMap[sendId];
|
|
1298
|
+
}
|
|
1299
|
+
attachDevTools() {
|
|
1300
|
+
const {
|
|
1301
|
+
devTools
|
|
1302
|
+
} = this.options;
|
|
1303
|
+
if (devTools) {
|
|
1304
|
+
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : dev_dist_xstateDev.devToolsAdapter;
|
|
1305
|
+
resolvedDevToolsAdapter(this);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
toJSON() {
|
|
1309
|
+
return {
|
|
1310
|
+
id: this.id
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
getPersistedState() {
|
|
1314
|
+
return this.logic.getPersistedState?.(this._state);
|
|
1315
|
+
}
|
|
1316
|
+
[symbolObservable]() {
|
|
1317
|
+
return this;
|
|
1318
|
+
}
|
|
1319
|
+
getSnapshot() {
|
|
1320
|
+
return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
|
|
1321
|
+
}
|
|
1385
1322
|
}
|
|
1386
1323
|
|
|
1387
|
-
const startSignalType = 'xstate.init';
|
|
1388
|
-
const stopSignalType = 'xstate.stop';
|
|
1389
|
-
const startSignal = {
|
|
1390
|
-
type: 'xstate.init'
|
|
1391
|
-
};
|
|
1392
|
-
const stopSignal = {
|
|
1393
|
-
type: 'xstate.stop'
|
|
1394
|
-
};
|
|
1395
1324
|
/**
|
|
1396
|
-
*
|
|
1397
|
-
* as well as an optionally emitted stream of values.
|
|
1325
|
+
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
1398
1326
|
*
|
|
1399
|
-
* @
|
|
1400
|
-
* @
|
|
1327
|
+
* @param machine The machine to interpret
|
|
1328
|
+
* @param options Interpreter options
|
|
1401
1329
|
*/
|
|
1402
1330
|
|
|
1403
|
-
function
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
function isActorRef(item) {
|
|
1407
|
-
return !!item && typeof item === 'object' && typeof item.send === 'function';
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
// TODO: refactor the return type, this could be written in a better way
|
|
1411
|
-
// but it's best to avoid unneccessary breaking changes now
|
|
1412
|
-
// @deprecated use `interpret(actorLogic)` instead
|
|
1413
|
-
function toActorRef(actorRefLike) {
|
|
1414
|
-
return {
|
|
1415
|
-
subscribe: () => ({
|
|
1416
|
-
unsubscribe: () => void 0
|
|
1417
|
-
}),
|
|
1418
|
-
id: 'anonymous',
|
|
1419
|
-
sessionId: '',
|
|
1420
|
-
getSnapshot: () => undefined,
|
|
1421
|
-
[symbolObservable]: function () {
|
|
1422
|
-
return this;
|
|
1423
|
-
},
|
|
1424
|
-
status: ActorStatus.Running,
|
|
1425
|
-
stop: () => void 0,
|
|
1426
|
-
...actorRefLike
|
|
1427
|
-
};
|
|
1428
|
-
}
|
|
1429
|
-
const emptyLogic = fromTransition(_ => undefined, undefined);
|
|
1430
|
-
function createEmptyActor() {
|
|
1431
|
-
return interpret(emptyLogic);
|
|
1331
|
+
function interpret(logic, options) {
|
|
1332
|
+
const interpreter = new Interpreter(logic, options);
|
|
1333
|
+
return interpreter;
|
|
1432
1334
|
}
|
|
1433
1335
|
|
|
1434
|
-
function
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1336
|
+
function resolve$6(actorContext, state, actionArgs, {
|
|
1337
|
+
id,
|
|
1338
|
+
systemId,
|
|
1339
|
+
src,
|
|
1340
|
+
input
|
|
1341
|
+
}) {
|
|
1342
|
+
const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
|
|
1343
|
+
let actorRef;
|
|
1344
|
+
if (referenced) {
|
|
1345
|
+
// TODO: inline `input: undefined` should win over the referenced one
|
|
1346
|
+
const configuredInput = input || referenced.input;
|
|
1347
|
+
actorRef = interpret(referenced.src, {
|
|
1444
1348
|
id,
|
|
1445
|
-
src
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
ref: src
|
|
1454
|
-
}
|
|
1455
|
-
};
|
|
1456
|
-
} else {
|
|
1457
|
-
const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
|
|
1458
|
-
if (!referenced) {
|
|
1459
|
-
resolvedInvokeAction = {
|
|
1460
|
-
type,
|
|
1461
|
-
params: invokeDef
|
|
1462
|
-
};
|
|
1463
|
-
} else {
|
|
1464
|
-
const input = 'input' in invokeDef ? invokeDef.input : referenced.input;
|
|
1465
|
-
const ref = interpret(referenced.src, {
|
|
1466
|
-
id,
|
|
1467
|
-
src,
|
|
1468
|
-
parent: actorContext?.self,
|
|
1469
|
-
systemId: invokeDef.systemId,
|
|
1470
|
-
input: typeof input === 'function' ? input({
|
|
1471
|
-
context: state.context,
|
|
1472
|
-
event,
|
|
1473
|
-
self: actorContext?.self
|
|
1474
|
-
}) : input
|
|
1475
|
-
});
|
|
1476
|
-
resolvedInvokeAction = {
|
|
1477
|
-
type,
|
|
1478
|
-
params: {
|
|
1479
|
-
...invokeDef,
|
|
1480
|
-
ref
|
|
1481
|
-
}
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
const actorRef = resolvedInvokeAction.params.ref;
|
|
1486
|
-
const invokedState = cloneState(state, {
|
|
1487
|
-
children: {
|
|
1488
|
-
...state.children,
|
|
1489
|
-
[id]: actorRef
|
|
1490
|
-
}
|
|
1349
|
+
src,
|
|
1350
|
+
parent: actorContext?.self,
|
|
1351
|
+
systemId,
|
|
1352
|
+
input: typeof configuredInput === 'function' ? configuredInput({
|
|
1353
|
+
context: state.context,
|
|
1354
|
+
event: actionArgs.event,
|
|
1355
|
+
self: actorContext?.self
|
|
1356
|
+
}) : configuredInput
|
|
1491
1357
|
});
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1358
|
+
}
|
|
1359
|
+
if (!actorRef) {
|
|
1360
|
+
console.warn(`Actor type '${src}' not found in machine '${actorContext.id}'.`);
|
|
1361
|
+
}
|
|
1362
|
+
return [cloneState(state, {
|
|
1363
|
+
children: {
|
|
1364
|
+
...state.children,
|
|
1365
|
+
[id]: actorRef
|
|
1366
|
+
}
|
|
1367
|
+
}), {
|
|
1368
|
+
id,
|
|
1369
|
+
actorRef
|
|
1370
|
+
}];
|
|
1371
|
+
}
|
|
1372
|
+
function execute$3(actorContext, {
|
|
1373
|
+
id,
|
|
1374
|
+
actorRef
|
|
1375
|
+
}) {
|
|
1376
|
+
if (!actorRef) {
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
actorContext.defer(() => {
|
|
1380
|
+
if (actorRef.status === ActorStatus.Stopped) {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
try {
|
|
1384
|
+
actorRef.start?.();
|
|
1385
|
+
} catch (err) {
|
|
1386
|
+
actorContext.self.send(error(id, err));
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1517
1389
|
});
|
|
1518
1390
|
}
|
|
1391
|
+
function invoke({
|
|
1392
|
+
id,
|
|
1393
|
+
systemId,
|
|
1394
|
+
src,
|
|
1395
|
+
input
|
|
1396
|
+
}) {
|
|
1397
|
+
function invoke(_) {
|
|
1398
|
+
{
|
|
1399
|
+
throw new Error(`This isn't supposed to be called`);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
invoke.type = 'xstate.invoke';
|
|
1403
|
+
invoke.id = id;
|
|
1404
|
+
invoke.systemId = systemId;
|
|
1405
|
+
invoke.src = src;
|
|
1406
|
+
invoke.input = input;
|
|
1407
|
+
invoke.resolve = resolve$6;
|
|
1408
|
+
invoke.execute = execute$3;
|
|
1409
|
+
return invoke;
|
|
1410
|
+
}
|
|
1519
1411
|
|
|
1520
1412
|
function stateIn(stateValue) {
|
|
1521
1413
|
return {
|
|
@@ -1526,7 +1418,7 @@ function stateIn(stateValue) {
|
|
|
1526
1418
|
predicate: ({
|
|
1527
1419
|
state
|
|
1528
1420
|
}) => {
|
|
1529
|
-
if (
|
|
1421
|
+
if (typeof stateValue === 'string' && isStateId(stateValue)) {
|
|
1530
1422
|
return state.configuration.some(sn => sn.id === stateValue.slice(1));
|
|
1531
1423
|
}
|
|
1532
1424
|
return state.matches(stateValue);
|
|
@@ -1610,9 +1502,9 @@ function evaluateGuard(guard, context, event, state) {
|
|
|
1610
1502
|
function toGuardDefinition(guardConfig, getPredicate) {
|
|
1611
1503
|
// TODO: check for cycles and consider a refactor to more lazily evaluated guards
|
|
1612
1504
|
// TODO: resolve this more recursively: https://github.com/statelyai/xstate/pull/4064#discussion_r1229915724
|
|
1613
|
-
if (
|
|
1505
|
+
if (typeof guardConfig === 'string') {
|
|
1614
1506
|
const predicateOrDef = getPredicate?.(guardConfig);
|
|
1615
|
-
if (
|
|
1507
|
+
if (typeof predicateOrDef === 'function') {
|
|
1616
1508
|
return {
|
|
1617
1509
|
type: guardConfig,
|
|
1618
1510
|
predicate: predicateOrDef,
|
|
@@ -1631,7 +1523,7 @@ function toGuardDefinition(guardConfig, getPredicate) {
|
|
|
1631
1523
|
};
|
|
1632
1524
|
}
|
|
1633
1525
|
}
|
|
1634
|
-
if (
|
|
1526
|
+
if (typeof guardConfig === 'function') {
|
|
1635
1527
|
return {
|
|
1636
1528
|
type: guardConfig.name,
|
|
1637
1529
|
predicate: guardConfig,
|
|
@@ -1642,7 +1534,7 @@ function toGuardDefinition(guardConfig, getPredicate) {
|
|
|
1642
1534
|
};
|
|
1643
1535
|
}
|
|
1644
1536
|
const predicateOrDef = getPredicate?.(guardConfig.type);
|
|
1645
|
-
if (
|
|
1537
|
+
if (typeof predicateOrDef === 'function') {
|
|
1646
1538
|
return {
|
|
1647
1539
|
type: guardConfig.type,
|
|
1648
1540
|
params: guardConfig.params || guardConfig,
|
|
@@ -1769,27 +1661,19 @@ function isInFinalState(configuration, stateNode = configuration[0].machine.root
|
|
|
1769
1661
|
}
|
|
1770
1662
|
const isStateId = str => str[0] === STATE_IDENTIFIER;
|
|
1771
1663
|
function getCandidates(stateNode, receivedEventType) {
|
|
1772
|
-
const candidates = stateNode.transitions.filter(
|
|
1773
|
-
|
|
1774
|
-
eventType
|
|
1775
|
-
} = transition;
|
|
1776
|
-
// First, check the trivial case: event names are exactly equal
|
|
1777
|
-
if (eventType === receivedEventType) {
|
|
1778
|
-
return true;
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
// Then, check if transition is a wildcard transition,
|
|
1664
|
+
const candidates = stateNode.transitions.get(receivedEventType) || [...stateNode.transitions.keys()].filter(descriptor => {
|
|
1665
|
+
// check if transition is a wildcard transition,
|
|
1782
1666
|
// which matches any non-transient events
|
|
1783
|
-
if (
|
|
1667
|
+
if (descriptor === WILDCARD) {
|
|
1784
1668
|
return true;
|
|
1785
1669
|
}
|
|
1786
|
-
if (!
|
|
1670
|
+
if (!descriptor.endsWith('.*')) {
|
|
1787
1671
|
return false;
|
|
1788
1672
|
}
|
|
1789
|
-
if (/.*\*.+/.test(
|
|
1790
|
-
console.warn(`Wildcards can only be the last token of an event descriptor (e.g., "event.*") or the entire event descriptor ("*"). Check the "${
|
|
1673
|
+
if (/.*\*.+/.test(descriptor)) {
|
|
1674
|
+
console.warn(`Wildcards can only be the last token of an event descriptor (e.g., "event.*") or the entire event descriptor ("*"). Check the "${descriptor}" event.`);
|
|
1791
1675
|
}
|
|
1792
|
-
const partialEventTokens =
|
|
1676
|
+
const partialEventTokens = descriptor.split('.');
|
|
1793
1677
|
const eventTokens = receivedEventType.split('.');
|
|
1794
1678
|
for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
|
|
1795
1679
|
const partialEventToken = partialEventTokens[tokenIndex];
|
|
@@ -1797,7 +1681,7 @@ function getCandidates(stateNode, receivedEventType) {
|
|
|
1797
1681
|
if (partialEventToken === '*') {
|
|
1798
1682
|
const isLastToken = tokenIndex === partialEventTokens.length - 1;
|
|
1799
1683
|
if (!isLastToken) {
|
|
1800
|
-
console.warn(`Infix wildcards in transition events are not allowed. Check the "${
|
|
1684
|
+
console.warn(`Infix wildcards in transition events are not allowed. Check the "${descriptor}" transition.`);
|
|
1801
1685
|
}
|
|
1802
1686
|
return isLastToken;
|
|
1803
1687
|
}
|
|
@@ -1806,7 +1690,7 @@ function getCandidates(stateNode, receivedEventType) {
|
|
|
1806
1690
|
}
|
|
1807
1691
|
}
|
|
1808
1692
|
return true;
|
|
1809
|
-
});
|
|
1693
|
+
}).sort((a, b) => b.length - a.length).flatMap(key => stateNode.transitions.get(key));
|
|
1810
1694
|
return candidates;
|
|
1811
1695
|
}
|
|
1812
1696
|
|
|
@@ -1819,11 +1703,12 @@ function getDelayedTransitions(stateNode) {
|
|
|
1819
1703
|
return [];
|
|
1820
1704
|
}
|
|
1821
1705
|
const mutateEntryExit = (delay, i) => {
|
|
1822
|
-
const delayRef =
|
|
1706
|
+
const delayRef = typeof delay === 'function' ? `${stateNode.id}:delay[${i}]` : delay;
|
|
1823
1707
|
const eventType = after(delayRef, stateNode.id);
|
|
1824
1708
|
stateNode.entry.push(raise({
|
|
1825
1709
|
type: eventType
|
|
1826
1710
|
}, {
|
|
1711
|
+
id: eventType,
|
|
1827
1712
|
delay
|
|
1828
1713
|
}));
|
|
1829
1714
|
stateNode.exit.push(cancel(eventType));
|
|
@@ -1837,7 +1722,7 @@ function getDelayedTransitions(stateNode) {
|
|
|
1837
1722
|
};
|
|
1838
1723
|
}) : Object.keys(afterConfig).flatMap((delay, i) => {
|
|
1839
1724
|
const configTransition = afterConfig[delay];
|
|
1840
|
-
const resolvedTransition =
|
|
1725
|
+
const resolvedTransition = typeof configTransition === 'string' ? {
|
|
1841
1726
|
target: configTransition
|
|
1842
1727
|
} : configTransition;
|
|
1843
1728
|
const resolvedDelay = !isNaN(+delay) ? +delay : delay;
|
|
@@ -1853,12 +1738,12 @@ function getDelayedTransitions(stateNode) {
|
|
|
1853
1738
|
delay
|
|
1854
1739
|
} = delayedTransition;
|
|
1855
1740
|
return {
|
|
1856
|
-
...formatTransition(stateNode, delayedTransition),
|
|
1741
|
+
...formatTransition(stateNode, delayedTransition.event, delayedTransition),
|
|
1857
1742
|
delay
|
|
1858
1743
|
};
|
|
1859
1744
|
});
|
|
1860
1745
|
}
|
|
1861
|
-
function formatTransition(stateNode, transitionConfig) {
|
|
1746
|
+
function formatTransition(stateNode, descriptor, transitionConfig) {
|
|
1862
1747
|
const normalizedTarget = normalizeTarget(transitionConfig.target);
|
|
1863
1748
|
const reenter = transitionConfig.reenter ?? false;
|
|
1864
1749
|
const {
|
|
@@ -1872,12 +1757,12 @@ function formatTransition(stateNode, transitionConfig) {
|
|
|
1872
1757
|
}
|
|
1873
1758
|
const transition = {
|
|
1874
1759
|
...transitionConfig,
|
|
1875
|
-
actions:
|
|
1760
|
+
actions: toArray(transitionConfig.actions),
|
|
1876
1761
|
guard: transitionConfig.guard ? toGuardDefinition(transitionConfig.guard, guardType => guards[guardType]) : undefined,
|
|
1877
1762
|
target,
|
|
1878
1763
|
source: stateNode,
|
|
1879
1764
|
reenter,
|
|
1880
|
-
eventType:
|
|
1765
|
+
eventType: descriptor,
|
|
1881
1766
|
toJSON: () => ({
|
|
1882
1767
|
...transition,
|
|
1883
1768
|
source: `#${stateNode.id}`,
|
|
@@ -1887,52 +1772,50 @@ function formatTransition(stateNode, transitionConfig) {
|
|
|
1887
1772
|
return transition;
|
|
1888
1773
|
}
|
|
1889
1774
|
function formatTransitions(stateNode) {
|
|
1890
|
-
const
|
|
1891
|
-
if (
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
const {
|
|
1895
|
-
[WILDCARD]: wildcardConfigs = [],
|
|
1896
|
-
...namedTransitionConfigs
|
|
1897
|
-
} = stateNode.config.on;
|
|
1898
|
-
for (const eventType of Object.keys(namedTransitionConfigs)) {
|
|
1899
|
-
if (eventType === NULL_EVENT) {
|
|
1775
|
+
const transitions = new Map();
|
|
1776
|
+
if (stateNode.config.on) {
|
|
1777
|
+
for (const descriptor of Object.keys(stateNode.config.on)) {
|
|
1778
|
+
if (descriptor === NULL_EVENT) {
|
|
1900
1779
|
throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.');
|
|
1901
1780
|
}
|
|
1902
|
-
const
|
|
1903
|
-
|
|
1904
|
-
// TODO: add dev-mode validation for unreachable transitions
|
|
1781
|
+
const transitionsConfig = stateNode.config.on[descriptor];
|
|
1782
|
+
transitions.set(descriptor, toTransitionConfigArray(transitionsConfig).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1905
1783
|
}
|
|
1906
|
-
|
|
1907
|
-
transitionConfigs.push(...toTransitionConfigArray(WILDCARD, wildcardConfigs));
|
|
1908
1784
|
}
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1785
|
+
if (stateNode.config.onDone) {
|
|
1786
|
+
const descriptor = String(done(stateNode.id));
|
|
1787
|
+
transitions.set(descriptor, toTransitionConfigArray(stateNode.config.onDone).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1788
|
+
}
|
|
1789
|
+
for (const invokeDef of stateNode.invoke) {
|
|
1912
1790
|
if (invokeDef.onDone) {
|
|
1913
|
-
|
|
1791
|
+
const descriptor = `done.invoke.${invokeDef.id}`;
|
|
1792
|
+
transitions.set(descriptor, toTransitionConfigArray(invokeDef.onDone).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1914
1793
|
}
|
|
1915
1794
|
if (invokeDef.onError) {
|
|
1916
|
-
|
|
1795
|
+
const descriptor = `error.platform.${invokeDef.id}`;
|
|
1796
|
+
transitions.set(descriptor, toTransitionConfigArray(invokeDef.onError).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1917
1797
|
}
|
|
1918
1798
|
if (invokeDef.onSnapshot) {
|
|
1919
|
-
|
|
1799
|
+
const descriptor = `xstate.snapshot.${invokeDef.id}`;
|
|
1800
|
+
transitions.set(descriptor, toTransitionConfigArray(invokeDef.onSnapshot).map(t => formatTransition(stateNode, descriptor, t)));
|
|
1920
1801
|
}
|
|
1921
|
-
return settleTransitions;
|
|
1922
|
-
});
|
|
1923
|
-
const delayedTransitions = stateNode.after;
|
|
1924
|
-
const formattedTransitions = [...doneConfig, ...invokeConfig, ...transitionConfigs].flatMap(transitionConfig => toArray(transitionConfig).map(transition => formatTransition(stateNode, transition)));
|
|
1925
|
-
for (const delayedTransition of delayedTransitions) {
|
|
1926
|
-
formattedTransitions.push(delayedTransition);
|
|
1927
1802
|
}
|
|
1928
|
-
|
|
1803
|
+
for (const delayedTransition of stateNode.after) {
|
|
1804
|
+
let existing = transitions.get(delayedTransition.eventType);
|
|
1805
|
+
if (!existing) {
|
|
1806
|
+
existing = [];
|
|
1807
|
+
transitions.set(delayedTransition.eventType, existing);
|
|
1808
|
+
}
|
|
1809
|
+
existing.push(delayedTransition);
|
|
1810
|
+
}
|
|
1811
|
+
return transitions;
|
|
1929
1812
|
}
|
|
1930
1813
|
function formatInitialTransition(stateNode, _target) {
|
|
1931
|
-
if (
|
|
1814
|
+
if (typeof _target === 'string' || isArray(_target)) {
|
|
1932
1815
|
const targets = toArray(_target).map(t => {
|
|
1933
1816
|
// Resolve state string keys (which represent children)
|
|
1934
1817
|
// to their state node
|
|
1935
|
-
const descStateNode =
|
|
1818
|
+
const descStateNode = typeof t === 'string' ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
|
|
1936
1819
|
if (!descStateNode) {
|
|
1937
1820
|
throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
|
|
1938
1821
|
}
|
|
@@ -1956,15 +1839,14 @@ function formatInitialTransition(stateNode, _target) {
|
|
|
1956
1839
|
};
|
|
1957
1840
|
return transition;
|
|
1958
1841
|
}
|
|
1959
|
-
return formatTransition(stateNode, {
|
|
1842
|
+
return formatTransition(stateNode, '__INITIAL__', {
|
|
1960
1843
|
target: toArray(_target.target).map(t => {
|
|
1961
|
-
if (
|
|
1844
|
+
if (typeof t === 'string') {
|
|
1962
1845
|
return isStateId(t) ? t : `${STATE_DELIMITER}${t}`;
|
|
1963
1846
|
}
|
|
1964
1847
|
return t;
|
|
1965
1848
|
}),
|
|
1966
|
-
actions: _target.actions
|
|
1967
|
-
event: null
|
|
1849
|
+
actions: _target.actions
|
|
1968
1850
|
});
|
|
1969
1851
|
}
|
|
1970
1852
|
function resolveTarget(stateNode, targets) {
|
|
@@ -1973,7 +1855,7 @@ function resolveTarget(stateNode, targets) {
|
|
|
1973
1855
|
return undefined;
|
|
1974
1856
|
}
|
|
1975
1857
|
return targets.map(target => {
|
|
1976
|
-
if (
|
|
1858
|
+
if (typeof target !== 'string') {
|
|
1977
1859
|
return target;
|
|
1978
1860
|
}
|
|
1979
1861
|
if (isStateId(target)) {
|
|
@@ -2081,7 +1963,7 @@ function getStateNodeByPath(stateNode, statePath) {
|
|
|
2081
1963
|
*/
|
|
2082
1964
|
function getStateNodes(stateNode, state) {
|
|
2083
1965
|
const stateValue = state instanceof State ? state.value : toStateValue(state);
|
|
2084
|
-
if (
|
|
1966
|
+
if (typeof stateValue === 'string') {
|
|
2085
1967
|
return [stateNode, stateNode.states[stateValue]];
|
|
2086
1968
|
}
|
|
2087
1969
|
const childStateKeys = Object.keys(stateValue);
|
|
@@ -2132,7 +2014,7 @@ function transitionParallelNode(stateNode, stateValue, state, event) {
|
|
|
2132
2014
|
}
|
|
2133
2015
|
function transitionNode(stateNode, stateValue, state, event) {
|
|
2134
2016
|
// leaf node
|
|
2135
|
-
if (
|
|
2017
|
+
if (typeof stateValue === 'string') {
|
|
2136
2018
|
return transitionAtomicNode(stateNode, stateValue, state, event);
|
|
2137
2019
|
}
|
|
2138
2020
|
|
|
@@ -2466,44 +2348,55 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
|
|
|
2466
2348
|
const {
|
|
2467
2349
|
machine
|
|
2468
2350
|
} = currentState;
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2351
|
+
// TODO: this `cloneState` is really just a hack to prevent infinite loops
|
|
2352
|
+
// we need to take another look at how internal queue is managed
|
|
2353
|
+
let intermediateState = cloneState(currentState, {
|
|
2354
|
+
_internalQueue: []
|
|
2355
|
+
});
|
|
2356
|
+
for (const action of actions) {
|
|
2357
|
+
const resolved = typeof action === 'function' ? action : machine.implementations.actions[typeof action === 'string' ? action : action.type];
|
|
2358
|
+
if (!resolved) {
|
|
2359
|
+
continue;
|
|
2476
2360
|
}
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
})
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2361
|
+
const args = {
|
|
2362
|
+
context: intermediateState.context,
|
|
2363
|
+
event,
|
|
2364
|
+
self: actorCtx?.self,
|
|
2365
|
+
system: actorCtx?.system,
|
|
2366
|
+
// TODO: figure out story for `action` and inline actions
|
|
2367
|
+
// what those ones should receive?
|
|
2368
|
+
//
|
|
2369
|
+
// entry: ({ action }) => {}
|
|
2370
|
+
// exit: assign(({ action }) => {})
|
|
2371
|
+
action: typeof action === 'string' ? {
|
|
2372
|
+
type: action
|
|
2373
|
+
} : action
|
|
2374
|
+
};
|
|
2375
|
+
if (!('resolve' in resolved)) {
|
|
2376
|
+
if (actorCtx?.self.status === ActorStatus.Running) {
|
|
2377
|
+
resolved(args);
|
|
2378
|
+
} else {
|
|
2379
|
+
actorCtx?.defer(() => resolved(args));
|
|
2490
2380
|
}
|
|
2381
|
+
continue;
|
|
2382
|
+
}
|
|
2383
|
+
const builtinAction = resolved;
|
|
2384
|
+
const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, args, resolved // this holds all params
|
|
2385
|
+
);
|
|
2491
2386
|
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2387
|
+
intermediateState = nextState;
|
|
2388
|
+
if ('execute' in resolved) {
|
|
2389
|
+
if (actorCtx?.self.status === ActorStatus.Running) {
|
|
2390
|
+
builtinAction.execute(actorCtx, params);
|
|
2391
|
+
} else {
|
|
2392
|
+
actorCtx?.defer(builtinAction.execute.bind(null, actorCtx, params));
|
|
2495
2393
|
}
|
|
2496
|
-
toActionObjects(matchedActions).forEach(resolveAction);
|
|
2497
|
-
return;
|
|
2498
2394
|
}
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
resolveAction(actionObject);
|
|
2395
|
+
if (actions) {
|
|
2396
|
+
intermediateState = resolveActionsAndContext(actions, event, intermediateState, actorCtx);
|
|
2397
|
+
}
|
|
2503
2398
|
}
|
|
2504
|
-
return
|
|
2505
|
-
_internalQueue: raiseActions.map(a => a.params.event)
|
|
2506
|
-
});
|
|
2399
|
+
return intermediateState;
|
|
2507
2400
|
}
|
|
2508
2401
|
function macrostep(state, event, actorCtx) {
|
|
2509
2402
|
if (event.type === WILDCARD) {
|
|
@@ -2525,7 +2418,7 @@ function macrostep(state, event, actorCtx) {
|
|
|
2525
2418
|
|
|
2526
2419
|
// Assume the state is at rest (no raised events)
|
|
2527
2420
|
// Determine the next state based on the next microstep
|
|
2528
|
-
if (nextEvent.type !==
|
|
2421
|
+
if (nextEvent.type !== INIT_TYPE) {
|
|
2529
2422
|
const transitions = selectTransitions(nextEvent, nextState);
|
|
2530
2423
|
nextState = microstep(transitions, state, actorCtx, nextEvent, false);
|
|
2531
2424
|
states.push(nextState);
|
|
@@ -2691,7 +2584,7 @@ class State {
|
|
|
2691
2584
|
* @param delimiter The character(s) that separate each subpath in the string state node path.
|
|
2692
2585
|
*/
|
|
2693
2586
|
toStrings(stateValue = this.value) {
|
|
2694
|
-
if (
|
|
2587
|
+
if (typeof stateValue === 'string') {
|
|
2695
2588
|
return [stateValue];
|
|
2696
2589
|
}
|
|
2697
2590
|
const valueKeys = Object.keys(stateValue);
|
|
@@ -2789,6 +2682,36 @@ function getPersistedState(state) {
|
|
|
2789
2682
|
};
|
|
2790
2683
|
}
|
|
2791
2684
|
|
|
2685
|
+
function resolve$5(_, state, args, {
|
|
2686
|
+
actorRef
|
|
2687
|
+
}) {
|
|
2688
|
+
const actorRefOrString = typeof actorRef === 'function' ? actorRef(args) : actorRef;
|
|
2689
|
+
const resolvedActorRef = typeof actorRefOrString === 'string' ? state.children[actorRefOrString] : actorRefOrString;
|
|
2690
|
+
let children = state.children;
|
|
2691
|
+
if (resolvedActorRef) {
|
|
2692
|
+
children = {
|
|
2693
|
+
...children
|
|
2694
|
+
};
|
|
2695
|
+
delete children[resolvedActorRef.id];
|
|
2696
|
+
}
|
|
2697
|
+
return [cloneState(state, {
|
|
2698
|
+
children
|
|
2699
|
+
}), resolvedActorRef];
|
|
2700
|
+
}
|
|
2701
|
+
function execute$2(actorContext, actorRef) {
|
|
2702
|
+
if (!actorRef) {
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
if (actorRef.status !== ActorStatus.Running) {
|
|
2706
|
+
actorContext.stopChild(actorRef);
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
// TODO: recheck why this one has to be deferred
|
|
2710
|
+
actorContext.defer(() => {
|
|
2711
|
+
actorContext.stopChild(actorRef);
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2792
2715
|
/**
|
|
2793
2716
|
* Stops an actor.
|
|
2794
2717
|
*
|
|
@@ -2796,58 +2719,40 @@ function getPersistedState(state) {
|
|
|
2796
2719
|
*/
|
|
2797
2720
|
|
|
2798
2721
|
function stop(actorRef) {
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
if (actorRef.status !== ActorStatus.Running) {
|
|
2832
|
-
actorCtx.stopChild(actorRef);
|
|
2833
|
-
return;
|
|
2834
|
-
}
|
|
2835
|
-
actorCtx.defer(() => {
|
|
2836
|
-
actorCtx.stopChild(actorRef);
|
|
2837
|
-
});
|
|
2838
|
-
}
|
|
2839
|
-
}];
|
|
2840
|
-
});
|
|
2722
|
+
function stop(_) {
|
|
2723
|
+
{
|
|
2724
|
+
throw new Error(`This isn't supposed to be called`);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
stop.type = 'xstate.stop';
|
|
2728
|
+
stop.actorRef = actorRef;
|
|
2729
|
+
stop.resolve = resolve$5;
|
|
2730
|
+
stop.execute = execute$2;
|
|
2731
|
+
return stop;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
function resolve$4(_, state, actionArgs, {
|
|
2735
|
+
value,
|
|
2736
|
+
label
|
|
2737
|
+
}) {
|
|
2738
|
+
return [state, {
|
|
2739
|
+
value: typeof value === 'function' ? value(actionArgs) : value,
|
|
2740
|
+
label
|
|
2741
|
+
}];
|
|
2742
|
+
}
|
|
2743
|
+
function execute$1({
|
|
2744
|
+
logger
|
|
2745
|
+
}, {
|
|
2746
|
+
value,
|
|
2747
|
+
label
|
|
2748
|
+
}) {
|
|
2749
|
+
if (label) {
|
|
2750
|
+
logger(label, value);
|
|
2751
|
+
} else {
|
|
2752
|
+
logger(value);
|
|
2753
|
+
}
|
|
2841
2754
|
}
|
|
2842
2755
|
|
|
2843
|
-
const defaultLogExpr = ({
|
|
2844
|
-
context,
|
|
2845
|
-
event
|
|
2846
|
-
}) => ({
|
|
2847
|
-
context,
|
|
2848
|
-
event
|
|
2849
|
-
});
|
|
2850
|
-
|
|
2851
2756
|
/**
|
|
2852
2757
|
*
|
|
2853
2758
|
* @param expr The expression function to evaluate which will be logged.
|
|
@@ -2856,94 +2761,114 @@ const defaultLogExpr = ({
|
|
|
2856
2761
|
* - `event` - the event that caused this action to be executed.
|
|
2857
2762
|
* @param label The label to give to the logged expression.
|
|
2858
2763
|
*/
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2764
|
+
function log(value = ({
|
|
2765
|
+
context,
|
|
2766
|
+
event
|
|
2767
|
+
}) => ({
|
|
2768
|
+
context,
|
|
2769
|
+
event
|
|
2770
|
+
}), label) {
|
|
2771
|
+
function log(_) {
|
|
2772
|
+
{
|
|
2773
|
+
throw new Error(`This isn't supposed to be called`);
|
|
2866
2774
|
}
|
|
2867
|
-
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
self: actorContext?.self ?? {},
|
|
2875
|
-
system: actorContext?.system
|
|
2876
|
-
}) : expr;
|
|
2877
|
-
return [state, {
|
|
2878
|
-
type: 'xstate.log',
|
|
2879
|
-
params: {
|
|
2880
|
-
label,
|
|
2881
|
-
value: resolvedValue
|
|
2882
|
-
},
|
|
2883
|
-
execute: actorCtx => {
|
|
2884
|
-
if (label) {
|
|
2885
|
-
actorCtx.logger?.(label, resolvedValue);
|
|
2886
|
-
} else {
|
|
2887
|
-
actorCtx.logger?.(resolvedValue);
|
|
2888
|
-
}
|
|
2889
|
-
}
|
|
2890
|
-
}];
|
|
2891
|
-
});
|
|
2775
|
+
}
|
|
2776
|
+
log.type = 'xstate.log';
|
|
2777
|
+
log.value = value;
|
|
2778
|
+
log.label = label;
|
|
2779
|
+
log.resolve = resolve$4;
|
|
2780
|
+
log.execute = execute$1;
|
|
2781
|
+
return log;
|
|
2892
2782
|
}
|
|
2893
2783
|
|
|
2894
|
-
function createSpawner(
|
|
2895
|
-
|
|
2784
|
+
function createSpawner(actorContext, {
|
|
2785
|
+
machine,
|
|
2786
|
+
context
|
|
2787
|
+
}, event, spawnedChildren) {
|
|
2788
|
+
const spawn = (src, options = {}) => {
|
|
2896
2789
|
const {
|
|
2897
2790
|
systemId
|
|
2898
2791
|
} = options;
|
|
2899
|
-
if (
|
|
2792
|
+
if (typeof src === 'string') {
|
|
2900
2793
|
const referenced = resolveReferencedActor(machine.implementations.actors[src]);
|
|
2901
|
-
if (referenced) {
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
// TODO: this should also receive `src`
|
|
2905
|
-
const actorRef = interpret(referenced.src, {
|
|
2906
|
-
id: options.id,
|
|
2907
|
-
parent: self,
|
|
2908
|
-
input: typeof input === 'function' ? input({
|
|
2909
|
-
context,
|
|
2910
|
-
event,
|
|
2911
|
-
self
|
|
2912
|
-
}) : input
|
|
2913
|
-
});
|
|
2914
|
-
mutCapturedActions.push(invoke({
|
|
2915
|
-
id: actorRef.id,
|
|
2916
|
-
// @ts-ignore TODO: fix types
|
|
2917
|
-
src: actorRef,
|
|
2918
|
-
// TODO
|
|
2919
|
-
ref: actorRef,
|
|
2920
|
-
meta: undefined,
|
|
2921
|
-
input,
|
|
2922
|
-
systemId
|
|
2923
|
-
}));
|
|
2924
|
-
return actorRef; // TODO: fix types
|
|
2794
|
+
if (!referenced) {
|
|
2795
|
+
throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
|
|
2925
2796
|
}
|
|
2797
|
+
const input = 'input' in options ? options.input : referenced.input;
|
|
2926
2798
|
|
|
2927
|
-
|
|
2799
|
+
// TODO: this should also receive `src`
|
|
2800
|
+
const actor = interpret(referenced.src, {
|
|
2801
|
+
id: options.id,
|
|
2802
|
+
parent: actorContext.self,
|
|
2803
|
+
input: typeof input === 'function' ? input({
|
|
2804
|
+
context,
|
|
2805
|
+
event,
|
|
2806
|
+
self: actorContext.self
|
|
2807
|
+
}) : input,
|
|
2808
|
+
systemId
|
|
2809
|
+
});
|
|
2810
|
+
spawnedChildren[actor.id] = actor;
|
|
2811
|
+
return actor;
|
|
2928
2812
|
} else {
|
|
2929
2813
|
// TODO: this should also receive `src`
|
|
2930
|
-
|
|
2814
|
+
return interpret(src, {
|
|
2931
2815
|
id: options.id,
|
|
2932
|
-
parent: self,
|
|
2816
|
+
parent: actorContext.self,
|
|
2933
2817
|
input: options.input,
|
|
2934
2818
|
systemId
|
|
2935
2819
|
});
|
|
2936
|
-
mutCapturedActions.push(invoke({
|
|
2937
|
-
// @ts-ignore TODO: fix types
|
|
2938
|
-
src: actorRef,
|
|
2939
|
-
ref: actorRef,
|
|
2940
|
-
id: actorRef.id,
|
|
2941
|
-
meta: undefined,
|
|
2942
|
-
input: options.input
|
|
2943
|
-
}));
|
|
2944
|
-
return actorRef; // TODO: fix types
|
|
2945
2820
|
}
|
|
2946
2821
|
};
|
|
2822
|
+
return (src, options) => {
|
|
2823
|
+
const actorRef = spawn(src, options);
|
|
2824
|
+
spawnedChildren[actorRef.id] = actorRef;
|
|
2825
|
+
actorContext.defer(() => {
|
|
2826
|
+
if (actorRef.status === ActorStatus.Stopped) {
|
|
2827
|
+
return;
|
|
2828
|
+
}
|
|
2829
|
+
try {
|
|
2830
|
+
actorRef.start?.();
|
|
2831
|
+
} catch (err) {
|
|
2832
|
+
actorContext.self.send(error(actorRef.id, err));
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
return actorRef;
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
function resolve$3(actorContext, state, actionArgs, {
|
|
2841
|
+
assignment
|
|
2842
|
+
}) {
|
|
2843
|
+
if (!state.context) {
|
|
2844
|
+
throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
|
|
2845
|
+
}
|
|
2846
|
+
const spawnedChildren = {};
|
|
2847
|
+
const assignArgs = {
|
|
2848
|
+
context: state.context,
|
|
2849
|
+
event: actionArgs.event,
|
|
2850
|
+
action: actionArgs.action,
|
|
2851
|
+
spawn: createSpawner(actorContext, state, actionArgs.event, spawnedChildren),
|
|
2852
|
+
self: actorContext?.self,
|
|
2853
|
+
system: actorContext?.system
|
|
2854
|
+
};
|
|
2855
|
+
let partialUpdate = {};
|
|
2856
|
+
if (typeof assignment === 'function') {
|
|
2857
|
+
partialUpdate = assignment(assignArgs);
|
|
2858
|
+
} else {
|
|
2859
|
+
for (const key of Object.keys(assignment)) {
|
|
2860
|
+
const propAssignment = assignment[key];
|
|
2861
|
+
partialUpdate[key] = typeof propAssignment === 'function' ? propAssignment(assignArgs) : propAssignment;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
const updatedContext = Object.assign({}, state.context, partialUpdate);
|
|
2865
|
+
return [cloneState(state, {
|
|
2866
|
+
context: updatedContext,
|
|
2867
|
+
children: Object.keys(spawnedChildren).length ? {
|
|
2868
|
+
...state.children,
|
|
2869
|
+
...spawnedChildren
|
|
2870
|
+
} : state.children
|
|
2871
|
+
})];
|
|
2947
2872
|
}
|
|
2948
2873
|
|
|
2949
2874
|
/**
|
|
@@ -2952,48 +2877,47 @@ function createSpawner(self, machine, context, event, mutCapturedActions) {
|
|
|
2952
2877
|
* @param assignment An object that represents the partial context to update.
|
|
2953
2878
|
*/
|
|
2954
2879
|
function assign(assignment) {
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
});
|
|
2880
|
+
function assign(_) {
|
|
2881
|
+
{
|
|
2882
|
+
throw new Error(`This isn't supposed to be called`);
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
assign.type = 'xstate.assign';
|
|
2886
|
+
assign.assignment = assignment;
|
|
2887
|
+
assign.resolve = resolve$3;
|
|
2888
|
+
return assign;
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
function resolve$2(_, state, args, {
|
|
2892
|
+
event: eventOrExpr,
|
|
2893
|
+
id,
|
|
2894
|
+
delay
|
|
2895
|
+
}) {
|
|
2896
|
+
const delaysMap = state.machine.implementations.delays;
|
|
2897
|
+
if (typeof eventOrExpr === 'string') {
|
|
2898
|
+
throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
|
|
2899
|
+
}
|
|
2900
|
+
const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args) : eventOrExpr;
|
|
2901
|
+
let resolvedDelay;
|
|
2902
|
+
if (typeof delay === 'string') {
|
|
2903
|
+
const configDelay = delaysMap && delaysMap[delay];
|
|
2904
|
+
resolvedDelay = typeof configDelay === 'function' ? configDelay(args) : configDelay;
|
|
2905
|
+
} else {
|
|
2906
|
+
resolvedDelay = typeof delay === 'function' ? delay(args) : delay;
|
|
2907
|
+
}
|
|
2908
|
+
return [typeof resolvedDelay !== 'number' ? cloneState(state, {
|
|
2909
|
+
_internalQueue: state._internalQueue.concat(resolvedEvent)
|
|
2910
|
+
}) : state, {
|
|
2911
|
+
event: resolvedEvent,
|
|
2912
|
+
id,
|
|
2913
|
+
delay: resolvedDelay
|
|
2914
|
+
}];
|
|
2915
|
+
}
|
|
2916
|
+
function execute(actorContext, params) {
|
|
2917
|
+
if (typeof params.delay === 'number') {
|
|
2918
|
+
actorContext.self.delaySend(params);
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2997
2921
|
}
|
|
2998
2922
|
|
|
2999
2923
|
/**
|
|
@@ -3004,186 +2928,60 @@ function assign(assignment) {
|
|
|
3004
2928
|
*/
|
|
3005
2929
|
|
|
3006
2930
|
function raise(eventOrExpr, options) {
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
delay: options ? options.delay : undefined,
|
|
3011
|
-
event: eventOrExpr,
|
|
3012
|
-
id: options && options.id !== undefined ? options.id : typeof eventOrExpr === 'function' ? eventOrExpr.name : eventOrExpr.type
|
|
3013
|
-
}
|
|
3014
|
-
}, (event, {
|
|
3015
|
-
state,
|
|
3016
|
-
actorContext
|
|
3017
|
-
}) => {
|
|
3018
|
-
const params = {
|
|
3019
|
-
delay: options ? options.delay : undefined,
|
|
3020
|
-
event: eventOrExpr,
|
|
3021
|
-
id: options && options.id !== undefined ? options.id : typeof eventOrExpr === 'function' ? eventOrExpr.name : eventOrExpr.type
|
|
3022
|
-
};
|
|
3023
|
-
const args = {
|
|
3024
|
-
context: state.context,
|
|
3025
|
-
event,
|
|
3026
|
-
self: actorContext?.self ?? {},
|
|
3027
|
-
system: actorContext?.system
|
|
3028
|
-
};
|
|
3029
|
-
const delaysMap = state.machine.implementations.delays;
|
|
3030
|
-
|
|
3031
|
-
// TODO: helper function for resolving Expr
|
|
3032
|
-
if (typeof eventOrExpr === 'string') {
|
|
3033
|
-
throw new Error(`Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`);
|
|
2931
|
+
function raise(_) {
|
|
2932
|
+
{
|
|
2933
|
+
throw new Error(`This isn't supposed to be called`);
|
|
3034
2934
|
}
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
const resolvedAction = {
|
|
3044
|
-
type: raise$1,
|
|
3045
|
-
params: {
|
|
3046
|
-
...params,
|
|
3047
|
-
event: resolvedEvent,
|
|
3048
|
-
delay: resolvedDelay
|
|
3049
|
-
},
|
|
3050
|
-
execute: actorCtx => {
|
|
3051
|
-
if (typeof resolvedAction.params.delay === 'number') {
|
|
3052
|
-
actorCtx.self.delaySend(resolvedAction);
|
|
3053
|
-
return;
|
|
3054
|
-
}
|
|
3055
|
-
}
|
|
3056
|
-
};
|
|
3057
|
-
return [state, resolvedAction];
|
|
3058
|
-
});
|
|
2935
|
+
}
|
|
2936
|
+
raise.type = 'xstate.raise';
|
|
2937
|
+
raise.event = eventOrExpr;
|
|
2938
|
+
raise.id = options?.id;
|
|
2939
|
+
raise.delay = options?.delay;
|
|
2940
|
+
raise.resolve = resolve$2;
|
|
2941
|
+
raise.execute = execute;
|
|
2942
|
+
return raise;
|
|
3059
2943
|
}
|
|
3060
2944
|
|
|
3061
|
-
function
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
}
|
|
3068
|
-
|
|
3069
|
-
}) => {
|
|
3070
|
-
const matchedActions = guards.find(condition => {
|
|
3071
|
-
const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.implementations.guards[guardType]);
|
|
3072
|
-
return !guard || evaluateGuard(guard, state.context, event, state);
|
|
3073
|
-
})?.actions;
|
|
3074
|
-
return [state, {
|
|
3075
|
-
type: choose$1,
|
|
3076
|
-
params: {
|
|
3077
|
-
actions: toActionObjects(matchedActions)
|
|
3078
|
-
}
|
|
3079
|
-
}];
|
|
3080
|
-
});
|
|
2945
|
+
function resolve$1(_, state, actionArgs, {
|
|
2946
|
+
branches
|
|
2947
|
+
}) {
|
|
2948
|
+
const matchedActions = branches.find(condition => {
|
|
2949
|
+
const guard = condition.guard && toGuardDefinition(condition.guard, guardType => state.machine.implementations.guards[guardType]);
|
|
2950
|
+
return !guard || evaluateGuard(guard, state.context, actionArgs.event, state);
|
|
2951
|
+
})?.actions;
|
|
2952
|
+
return [state, undefined, toArray(matchedActions)];
|
|
3081
2953
|
}
|
|
3082
|
-
|
|
3083
|
-
function
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
params: {
|
|
3087
|
-
get: getActions
|
|
2954
|
+
function choose(branches) {
|
|
2955
|
+
function choose(_) {
|
|
2956
|
+
{
|
|
2957
|
+
throw new Error(`This isn't supposed to be called`);
|
|
3088
2958
|
}
|
|
3089
|
-
}, (event, {
|
|
3090
|
-
state
|
|
3091
|
-
}) => {
|
|
3092
|
-
return [state, {
|
|
3093
|
-
type: pure$1,
|
|
3094
|
-
params: {
|
|
3095
|
-
actions: toArray(toActionObjects(getActions({
|
|
3096
|
-
context: state.context,
|
|
3097
|
-
event
|
|
3098
|
-
}))) ?? []
|
|
3099
|
-
}
|
|
3100
|
-
}];
|
|
3101
|
-
});
|
|
3102
|
-
}
|
|
3103
|
-
|
|
3104
|
-
const initEvent = {
|
|
3105
|
-
type: init
|
|
3106
|
-
};
|
|
3107
|
-
function resolveActionObject(actionObject, actionFunctionMap) {
|
|
3108
|
-
if (isDynamicAction(actionObject)) {
|
|
3109
|
-
return actionObject;
|
|
3110
|
-
}
|
|
3111
|
-
const dereferencedAction = actionFunctionMap[actionObject.type];
|
|
3112
|
-
if (typeof dereferencedAction === 'function') {
|
|
3113
|
-
return createDynamicAction({
|
|
3114
|
-
type: 'xstate.function',
|
|
3115
|
-
params: actionObject.params ?? {}
|
|
3116
|
-
}, (event, {
|
|
3117
|
-
state
|
|
3118
|
-
}) => {
|
|
3119
|
-
const a = {
|
|
3120
|
-
type: actionObject.type,
|
|
3121
|
-
params: actionObject.params,
|
|
3122
|
-
execute: actorCtx => {
|
|
3123
|
-
return dereferencedAction({
|
|
3124
|
-
context: state.context,
|
|
3125
|
-
event,
|
|
3126
|
-
action: a,
|
|
3127
|
-
system: actorCtx.system,
|
|
3128
|
-
self: actorCtx.self
|
|
3129
|
-
});
|
|
3130
|
-
}
|
|
3131
|
-
};
|
|
3132
|
-
return [state, a];
|
|
3133
|
-
});
|
|
3134
|
-
} else if (dereferencedAction) {
|
|
3135
|
-
return dereferencedAction;
|
|
3136
|
-
} else {
|
|
3137
|
-
return actionObject;
|
|
3138
2959
|
}
|
|
2960
|
+
choose.type = 'xstate.choose';
|
|
2961
|
+
choose.branches = branches;
|
|
2962
|
+
choose.resolve = resolve$1;
|
|
2963
|
+
return choose;
|
|
3139
2964
|
}
|
|
3140
|
-
function toActionObject(action) {
|
|
3141
|
-
if (isDynamicAction(action)) {
|
|
3142
|
-
return action;
|
|
3143
|
-
}
|
|
3144
|
-
if (typeof action === 'string') {
|
|
3145
|
-
return {
|
|
3146
|
-
type: action,
|
|
3147
|
-
params: {}
|
|
3148
|
-
};
|
|
3149
|
-
}
|
|
3150
|
-
if (typeof action === 'function') {
|
|
3151
|
-
const type = 'xstate.function';
|
|
3152
|
-
return createDynamicAction({
|
|
3153
|
-
type,
|
|
3154
|
-
params: {}
|
|
3155
|
-
}, (event, {
|
|
3156
|
-
state
|
|
3157
|
-
}) => {
|
|
3158
|
-
const actionObject = {
|
|
3159
|
-
type,
|
|
3160
|
-
params: {
|
|
3161
|
-
function: action
|
|
3162
|
-
},
|
|
3163
|
-
execute: actorCtx => {
|
|
3164
|
-
return action({
|
|
3165
|
-
context: state.context,
|
|
3166
|
-
event: event,
|
|
3167
|
-
action: actionObject,
|
|
3168
|
-
self: actorCtx.self,
|
|
3169
|
-
system: actorCtx.system
|
|
3170
|
-
});
|
|
3171
|
-
}
|
|
3172
|
-
};
|
|
3173
|
-
return [state, actionObject];
|
|
3174
|
-
});
|
|
3175
|
-
}
|
|
3176
2965
|
|
|
3177
|
-
|
|
3178
|
-
|
|
2966
|
+
function resolve(_, state, args, {
|
|
2967
|
+
get
|
|
2968
|
+
}) {
|
|
2969
|
+
return [state, undefined, toArray(get({
|
|
2970
|
+
context: state.context,
|
|
2971
|
+
event: args.event
|
|
2972
|
+
}))];
|
|
3179
2973
|
}
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
2974
|
+
function pure(getActions) {
|
|
2975
|
+
function pure(_) {
|
|
2976
|
+
{
|
|
2977
|
+
throw new Error(`This isn't supposed to be called`);
|
|
2978
|
+
}
|
|
3183
2979
|
}
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
2980
|
+
pure.type = 'xstate.pure';
|
|
2981
|
+
pure.get = getActions;
|
|
2982
|
+
pure.resolve = resolve;
|
|
2983
|
+
return pure;
|
|
2984
|
+
}
|
|
3187
2985
|
|
|
3188
2986
|
/**
|
|
3189
2987
|
* Returns an event type that represents an implicit event that
|
|
@@ -3194,7 +2992,7 @@ const toActionObjects = action => {
|
|
|
3194
2992
|
*/
|
|
3195
2993
|
function after(delayRef, id) {
|
|
3196
2994
|
const idSuffix = id ? `#${id}` : '';
|
|
3197
|
-
return `${
|
|
2995
|
+
return `${ConstantPrefix.After}(${delayRef})${idSuffix}`;
|
|
3198
2996
|
}
|
|
3199
2997
|
|
|
3200
2998
|
/**
|
|
@@ -3205,7 +3003,7 @@ function after(delayRef, id) {
|
|
|
3205
3003
|
* @param output The data to pass into the event
|
|
3206
3004
|
*/
|
|
3207
3005
|
function done(id, output) {
|
|
3208
|
-
const type = `${
|
|
3006
|
+
const type = `${ConstantPrefix.DoneState}.${id}`;
|
|
3209
3007
|
const eventObject = {
|
|
3210
3008
|
type,
|
|
3211
3009
|
output
|
|
@@ -3224,7 +3022,7 @@ function done(id, output) {
|
|
|
3224
3022
|
* @param output The data to pass into the event
|
|
3225
3023
|
*/
|
|
3226
3024
|
function doneInvoke(invokeId, output) {
|
|
3227
|
-
const type = `${
|
|
3025
|
+
const type = `${ConstantPrefix.DoneInvoke}.${invokeId}`;
|
|
3228
3026
|
const eventObject = {
|
|
3229
3027
|
type,
|
|
3230
3028
|
output
|
|
@@ -3233,7 +3031,7 @@ function doneInvoke(invokeId, output) {
|
|
|
3233
3031
|
return eventObject;
|
|
3234
3032
|
}
|
|
3235
3033
|
function error(id, data) {
|
|
3236
|
-
const type = `${
|
|
3034
|
+
const type = `${ConstantPrefix.ErrorPlatform}.${id}`;
|
|
3237
3035
|
const eventObject = {
|
|
3238
3036
|
type,
|
|
3239
3037
|
data
|
|
@@ -3243,28 +3041,27 @@ function error(id, data) {
|
|
|
3243
3041
|
}
|
|
3244
3042
|
function createInitEvent(input) {
|
|
3245
3043
|
return {
|
|
3246
|
-
type:
|
|
3044
|
+
type: INIT_TYPE,
|
|
3247
3045
|
input
|
|
3248
3046
|
};
|
|
3249
3047
|
}
|
|
3250
3048
|
|
|
3251
|
-
exports.ActionTypes = ActionTypes;
|
|
3252
3049
|
exports.ActorStatus = ActorStatus;
|
|
3050
|
+
exports.ConstantPrefix = ConstantPrefix;
|
|
3253
3051
|
exports.Interpreter = Interpreter;
|
|
3254
3052
|
exports.NULL_EVENT = NULL_EVENT;
|
|
3255
3053
|
exports.STATE_DELIMITER = STATE_DELIMITER;
|
|
3256
3054
|
exports.SpecialTargets = SpecialTargets;
|
|
3257
3055
|
exports.State = State;
|
|
3258
|
-
exports.actionTypes = actionTypes;
|
|
3259
3056
|
exports.after = after;
|
|
3260
3057
|
exports.and = and;
|
|
3261
3058
|
exports.assign = assign;
|
|
3262
3059
|
exports.cancel = cancel;
|
|
3263
3060
|
exports.choose = choose;
|
|
3061
|
+
exports.constantPrefixes = constantPrefixes;
|
|
3264
3062
|
exports.createEmptyActor = createEmptyActor;
|
|
3265
3063
|
exports.createInitEvent = createInitEvent;
|
|
3266
3064
|
exports.createInvokeId = createInvokeId;
|
|
3267
|
-
exports.createSpawner = createSpawner;
|
|
3268
3065
|
exports.done = done;
|
|
3269
3066
|
exports.doneInvoke = doneInvoke;
|
|
3270
3067
|
exports.error = error;
|
|
@@ -3287,16 +3084,13 @@ exports.getInitialConfiguration = getInitialConfiguration;
|
|
|
3287
3084
|
exports.getPersistedState = getPersistedState;
|
|
3288
3085
|
exports.getStateNodeByPath = getStateNodeByPath;
|
|
3289
3086
|
exports.getStateNodes = getStateNodes;
|
|
3290
|
-
exports.initEvent = initEvent;
|
|
3291
3087
|
exports.interpret = interpret;
|
|
3292
|
-
exports.invoke = invoke$1;
|
|
3293
3088
|
exports.isActorRef = isActorRef;
|
|
3294
3089
|
exports.isAtomicStateNode = isAtomicStateNode;
|
|
3295
3090
|
exports.isErrorEvent = isErrorEvent;
|
|
3296
3091
|
exports.isInFinalState = isInFinalState;
|
|
3297
3092
|
exports.isSignal = isSignal;
|
|
3298
3093
|
exports.isStateId = isStateId;
|
|
3299
|
-
exports.isString = isString;
|
|
3300
3094
|
exports.log = log;
|
|
3301
3095
|
exports.macrostep = macrostep;
|
|
3302
3096
|
exports.mapValues = mapValues;
|
|
@@ -3308,11 +3102,9 @@ exports.or = or;
|
|
|
3308
3102
|
exports.pathToStateValue = pathToStateValue;
|
|
3309
3103
|
exports.pure = pure;
|
|
3310
3104
|
exports.raise = raise;
|
|
3311
|
-
exports.resolveActionObject = resolveActionObject;
|
|
3312
3105
|
exports.resolveActionsAndContext = resolveActionsAndContext;
|
|
3313
3106
|
exports.resolveReferencedActor = resolveReferencedActor;
|
|
3314
3107
|
exports.resolveStateValue = resolveStateValue;
|
|
3315
|
-
exports.send = send;
|
|
3316
3108
|
exports.sendParent = sendParent;
|
|
3317
3109
|
exports.sendTo = sendTo;
|
|
3318
3110
|
exports.startSignal = startSignal;
|
|
@@ -3321,8 +3113,6 @@ exports.stateIn = stateIn;
|
|
|
3321
3113
|
exports.stop = stop;
|
|
3322
3114
|
exports.stopSignal = stopSignal;
|
|
3323
3115
|
exports.stopSignalType = stopSignalType;
|
|
3324
|
-
exports.toActionObject = toActionObject;
|
|
3325
|
-
exports.toActionObjects = toActionObjects;
|
|
3326
3116
|
exports.toActorRef = toActorRef;
|
|
3327
3117
|
exports.toArray = toArray;
|
|
3328
3118
|
exports.toGuardDefinition = toGuardDefinition;
|