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