xstate 5.0.0-beta.42 → 5.0.0-beta.44
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 -3
- package/actions/dist/xstate-actions.development.cjs.js +2 -3
- package/actions/dist/xstate-actions.development.esm.js +2 -3
- package/actions/dist/xstate-actions.esm.js +2 -3
- 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 +50 -6
- package/actors/dist/xstate-actors.development.cjs.js +50 -6
- package/actors/dist/xstate-actors.development.esm.js +45 -1
- package/actors/dist/xstate-actors.esm.js +45 -1
- package/actors/dist/xstate-actors.umd.min.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/declarations/src/State.d.ts +8 -12
- package/dist/declarations/src/actions/spawn.d.ts +11 -16
- package/dist/declarations/src/actors/promise.d.ts +53 -0
- package/dist/declarations/src/guards.d.ts +2 -2
- package/dist/declarations/src/index.d.ts +1 -1
- package/dist/declarations/src/spawn.d.ts +9 -13
- package/dist/declarations/src/stateUtils.d.ts +4 -4
- package/dist/declarations/src/types.d.ts +56 -22
- package/dist/declarations/src/utils.d.ts +2 -10
- package/dist/{raise-6b64c553.cjs.js → raise-348cc74e.development.esm.js} +1007 -116
- package/dist/{raise-51ae36e5.development.esm.js → raise-5854eaca.esm.js} +925 -101
- package/dist/{raise-8f482ce9.development.cjs.js → raise-ed700d14.development.cjs.js} +986 -87
- package/dist/{raise-d2084327.esm.js → raise-fb6f017b.cjs.js} +972 -54
- package/dist/{send-cc8f864e.development.cjs.js → send-00466e37.development.cjs.js} +14 -17
- package/dist/{send-85b562d8.cjs.js → send-53e5693c.cjs.js} +14 -17
- package/dist/{send-7a350091.development.esm.js → send-a0193bdb.development.esm.js} +7 -10
- package/dist/{send-4e732fa5.esm.js → send-b7b4befa.esm.js} +7 -10
- package/dist/xstate.cjs.js +25 -25
- package/dist/xstate.cjs.mjs +1 -0
- package/dist/xstate.development.cjs.js +25 -25
- package/dist/xstate.development.cjs.mjs +1 -0
- package/dist/xstate.development.esm.js +5 -7
- package/dist/xstate.esm.js +5 -7
- 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 -2
- package/guards/dist/xstate-guards.development.cjs.js +1 -2
- package/guards/dist/xstate-guards.development.esm.js +1 -2
- package/guards/dist/xstate-guards.esm.js +1 -2
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/interpreter-23e4041c.development.cjs.js +0 -905
- package/dist/interpreter-3d0c0ff2.esm.js +0 -864
- package/dist/interpreter-b6bdd134.cjs.js +0 -894
- package/dist/interpreter-f2620ea7.development.esm.js +0 -875
|
@@ -1,4 +1,855 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { devToolsAdapter } from '../dev/dist/xstate-dev.esm.js';
|
|
2
|
+
|
|
3
|
+
class Mailbox {
|
|
4
|
+
constructor(_process) {
|
|
5
|
+
this._process = _process;
|
|
6
|
+
this._active = false;
|
|
7
|
+
this._current = null;
|
|
8
|
+
this._last = null;
|
|
9
|
+
}
|
|
10
|
+
start() {
|
|
11
|
+
this._active = true;
|
|
12
|
+
this.flush();
|
|
13
|
+
}
|
|
14
|
+
clear() {
|
|
15
|
+
// we can't set _current to null because we might be currently processing
|
|
16
|
+
// and enqueue following clear shouldnt start processing the enqueued item immediately
|
|
17
|
+
if (this._current) {
|
|
18
|
+
this._current.next = null;
|
|
19
|
+
this._last = this._current;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
enqueue(event) {
|
|
23
|
+
const enqueued = {
|
|
24
|
+
value: event,
|
|
25
|
+
next: null
|
|
26
|
+
};
|
|
27
|
+
if (this._current) {
|
|
28
|
+
this._last.next = enqueued;
|
|
29
|
+
this._last = enqueued;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this._current = enqueued;
|
|
33
|
+
this._last = enqueued;
|
|
34
|
+
if (this._active) {
|
|
35
|
+
this.flush();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
flush() {
|
|
39
|
+
while (this._current) {
|
|
40
|
+
// atm the given _process is responsible for implementing proper try/catch handling
|
|
41
|
+
// we assume here that this won't throw in a way that can affect this mailbox
|
|
42
|
+
const consumed = this._current;
|
|
43
|
+
this._process(consumed.value);
|
|
44
|
+
this._current = consumed.next;
|
|
45
|
+
}
|
|
46
|
+
this._last = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const STATE_DELIMITER = '.';
|
|
51
|
+
const TARGETLESS_KEY = '';
|
|
52
|
+
const NULL_EVENT = '';
|
|
53
|
+
const STATE_IDENTIFIER = '#';
|
|
54
|
+
const WILDCARD = '*';
|
|
55
|
+
const XSTATE_INIT = 'xstate.init';
|
|
56
|
+
const XSTATE_ERROR = 'xstate.error';
|
|
57
|
+
const XSTATE_STOP = 'xstate.stop';
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns an event that represents an implicit event that
|
|
61
|
+
* is sent after the specified `delay`.
|
|
62
|
+
*
|
|
63
|
+
* @param delayRef The delay in milliseconds
|
|
64
|
+
* @param id The state node ID where this event is handled
|
|
65
|
+
*/
|
|
66
|
+
function createAfterEvent(delayRef, id) {
|
|
67
|
+
const idSuffix = id ? `#${id}` : '';
|
|
68
|
+
return {
|
|
69
|
+
type: `xstate.after(${delayRef})${idSuffix}`
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns an event that represents that a final state node
|
|
75
|
+
* has been reached in the parent state node.
|
|
76
|
+
*
|
|
77
|
+
* @param id The final state node's parent state node `id`
|
|
78
|
+
* @param output The data to pass into the event
|
|
79
|
+
*/
|
|
80
|
+
function createDoneStateEvent(id, output) {
|
|
81
|
+
return {
|
|
82
|
+
type: `xstate.done.state.${id}`,
|
|
83
|
+
output
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Returns an event that represents that an invoked service has terminated.
|
|
89
|
+
*
|
|
90
|
+
* An invoked service is terminated when it has reached a top-level final state node,
|
|
91
|
+
* but not when it is canceled.
|
|
92
|
+
*
|
|
93
|
+
* @param invokeId The invoked service ID
|
|
94
|
+
* @param output The data to pass into the event
|
|
95
|
+
*/
|
|
96
|
+
function createDoneActorEvent(invokeId, output) {
|
|
97
|
+
return {
|
|
98
|
+
type: `xstate.done.actor.${invokeId}`,
|
|
99
|
+
output
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function createErrorActorEvent(id, data) {
|
|
103
|
+
return {
|
|
104
|
+
type: `xstate.error.actor.${id}`,
|
|
105
|
+
data
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function createInitEvent(input) {
|
|
109
|
+
return {
|
|
110
|
+
type: XSTATE_INIT,
|
|
111
|
+
input
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* This function makes sure that unhandled errors are thrown in a separate macrotask.
|
|
117
|
+
* It allows those errors to be detected by global error handlers and reported to bug tracking services
|
|
118
|
+
* without interrupting our own stack of execution.
|
|
119
|
+
*
|
|
120
|
+
* @param err error to be thrown
|
|
121
|
+
*/
|
|
122
|
+
function reportUnhandledError(err) {
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
throw err;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
129
|
+
|
|
130
|
+
let idCounter = 0;
|
|
131
|
+
function createSystem(rootActor) {
|
|
132
|
+
const children = new Map();
|
|
133
|
+
const keyedActors = new Map();
|
|
134
|
+
const reverseKeyedActors = new WeakMap();
|
|
135
|
+
const observers = new Set();
|
|
136
|
+
const system = {
|
|
137
|
+
_bookId: () => `x:${idCounter++}`,
|
|
138
|
+
_register: (sessionId, actorRef) => {
|
|
139
|
+
children.set(sessionId, actorRef);
|
|
140
|
+
return sessionId;
|
|
141
|
+
},
|
|
142
|
+
_unregister: actorRef => {
|
|
143
|
+
children.delete(actorRef.sessionId);
|
|
144
|
+
const systemId = reverseKeyedActors.get(actorRef);
|
|
145
|
+
if (systemId !== undefined) {
|
|
146
|
+
keyedActors.delete(systemId);
|
|
147
|
+
reverseKeyedActors.delete(actorRef);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
get: systemId => {
|
|
151
|
+
return keyedActors.get(systemId);
|
|
152
|
+
},
|
|
153
|
+
_set: (systemId, actorRef) => {
|
|
154
|
+
const existing = keyedActors.get(systemId);
|
|
155
|
+
if (existing && existing !== actorRef) {
|
|
156
|
+
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
157
|
+
}
|
|
158
|
+
keyedActors.set(systemId, actorRef);
|
|
159
|
+
reverseKeyedActors.set(actorRef, systemId);
|
|
160
|
+
},
|
|
161
|
+
inspect: observer => {
|
|
162
|
+
observers.add(observer);
|
|
163
|
+
},
|
|
164
|
+
_sendInspectionEvent: event => {
|
|
165
|
+
const resolvedInspectionEvent = {
|
|
166
|
+
...event,
|
|
167
|
+
rootId: rootActor.sessionId
|
|
168
|
+
};
|
|
169
|
+
observers.forEach(observer => observer.next?.(resolvedInspectionEvent));
|
|
170
|
+
},
|
|
171
|
+
_relay: (source, target, event) => {
|
|
172
|
+
system._sendInspectionEvent({
|
|
173
|
+
type: '@xstate.event',
|
|
174
|
+
sourceRef: source,
|
|
175
|
+
actorRef: target,
|
|
176
|
+
event
|
|
177
|
+
});
|
|
178
|
+
target._send(event);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
return system;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function matchesState(parentStateId, childStateId) {
|
|
185
|
+
const parentStateValue = toStateValue(parentStateId);
|
|
186
|
+
const childStateValue = toStateValue(childStateId);
|
|
187
|
+
if (typeof childStateValue === 'string') {
|
|
188
|
+
if (typeof parentStateValue === 'string') {
|
|
189
|
+
return childStateValue === parentStateValue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Parent more specific than child
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (typeof parentStateValue === 'string') {
|
|
196
|
+
return parentStateValue in childStateValue;
|
|
197
|
+
}
|
|
198
|
+
return Object.keys(parentStateValue).every(key => {
|
|
199
|
+
if (!(key in childStateValue)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return matchesState(parentStateValue[key], childStateValue[key]);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function toStatePath(stateId) {
|
|
206
|
+
try {
|
|
207
|
+
if (isArray(stateId)) {
|
|
208
|
+
return stateId;
|
|
209
|
+
}
|
|
210
|
+
return stateId.split(STATE_DELIMITER);
|
|
211
|
+
} catch (e) {
|
|
212
|
+
throw new Error(`'${stateId}' is not a valid state path.`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function toStateValue(stateValue) {
|
|
216
|
+
if (isMachineSnapshot(stateValue)) {
|
|
217
|
+
return stateValue.value;
|
|
218
|
+
}
|
|
219
|
+
if (typeof stateValue !== 'string') {
|
|
220
|
+
return stateValue;
|
|
221
|
+
}
|
|
222
|
+
const statePath = toStatePath(stateValue);
|
|
223
|
+
return pathToStateValue(statePath);
|
|
224
|
+
}
|
|
225
|
+
function pathToStateValue(statePath) {
|
|
226
|
+
if (statePath.length === 1) {
|
|
227
|
+
return statePath[0];
|
|
228
|
+
}
|
|
229
|
+
const value = {};
|
|
230
|
+
let marker = value;
|
|
231
|
+
for (let i = 0; i < statePath.length - 1; i++) {
|
|
232
|
+
if (i === statePath.length - 2) {
|
|
233
|
+
marker[statePath[i]] = statePath[i + 1];
|
|
234
|
+
} else {
|
|
235
|
+
const previous = marker;
|
|
236
|
+
marker = {};
|
|
237
|
+
previous[statePath[i]] = marker;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
function mapValues(collection, iteratee) {
|
|
243
|
+
const result = {};
|
|
244
|
+
const collectionKeys = Object.keys(collection);
|
|
245
|
+
for (let i = 0; i < collectionKeys.length; i++) {
|
|
246
|
+
const key = collectionKeys[i];
|
|
247
|
+
result[key] = iteratee(collection[key], key, collection, i);
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
function flatten(array) {
|
|
252
|
+
return [].concat(...array);
|
|
253
|
+
}
|
|
254
|
+
function toArrayStrict(value) {
|
|
255
|
+
if (isArray(value)) {
|
|
256
|
+
return value;
|
|
257
|
+
}
|
|
258
|
+
return [value];
|
|
259
|
+
}
|
|
260
|
+
function toArray(value) {
|
|
261
|
+
if (value === undefined) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
return toArrayStrict(value);
|
|
265
|
+
}
|
|
266
|
+
function resolveOutput(mapper, context, event, self) {
|
|
267
|
+
if (typeof mapper === 'function') {
|
|
268
|
+
return mapper({
|
|
269
|
+
context,
|
|
270
|
+
event,
|
|
271
|
+
self
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return mapper;
|
|
275
|
+
}
|
|
276
|
+
function isArray(value) {
|
|
277
|
+
return Array.isArray(value);
|
|
278
|
+
}
|
|
279
|
+
function isErrorActorEvent(event) {
|
|
280
|
+
return event.type.startsWith('xstate.error.actor');
|
|
281
|
+
}
|
|
282
|
+
function toTransitionConfigArray(configLike) {
|
|
283
|
+
return toArrayStrict(configLike).map(transitionLike => {
|
|
284
|
+
if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
|
|
285
|
+
return {
|
|
286
|
+
target: transitionLike
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return transitionLike;
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
function normalizeTarget(target) {
|
|
293
|
+
if (target === undefined || target === TARGETLESS_KEY) {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
return toArray(target);
|
|
297
|
+
}
|
|
298
|
+
function toObserver(nextHandler, errorHandler, completionHandler) {
|
|
299
|
+
const isObserver = typeof nextHandler === 'object';
|
|
300
|
+
const self = isObserver ? nextHandler : undefined;
|
|
301
|
+
return {
|
|
302
|
+
next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),
|
|
303
|
+
error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),
|
|
304
|
+
complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self)
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function createInvokeId(stateNodeId, index) {
|
|
308
|
+
return `${stateNodeId}[${index}]`;
|
|
309
|
+
}
|
|
310
|
+
function resolveReferencedActor(machine, src) {
|
|
311
|
+
if (src.startsWith('xstate#')) {
|
|
312
|
+
const [, indexStr] = src.match(/\[(\d+)\]$/);
|
|
313
|
+
const node = machine.getStateNodeById(src.slice(7, -(indexStr.length + 2)));
|
|
314
|
+
const invokeConfig = node.config.invoke;
|
|
315
|
+
return (Array.isArray(invokeConfig) ? invokeConfig[indexStr] : invokeConfig).src;
|
|
316
|
+
}
|
|
317
|
+
return machine.implementations.actors[src];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const $$ACTOR_TYPE = 1;
|
|
321
|
+
// those values are currently used by @xstate/react directly so it's important to keep the assigned values in sync
|
|
322
|
+
let ProcessingStatus = /*#__PURE__*/function (ProcessingStatus) {
|
|
323
|
+
ProcessingStatus[ProcessingStatus["NotStarted"] = 0] = "NotStarted";
|
|
324
|
+
ProcessingStatus[ProcessingStatus["Running"] = 1] = "Running";
|
|
325
|
+
ProcessingStatus[ProcessingStatus["Stopped"] = 2] = "Stopped";
|
|
326
|
+
return ProcessingStatus;
|
|
327
|
+
}({});
|
|
328
|
+
const defaultOptions = {
|
|
329
|
+
clock: {
|
|
330
|
+
setTimeout: (fn, ms) => {
|
|
331
|
+
return setTimeout(fn, ms);
|
|
332
|
+
},
|
|
333
|
+
clearTimeout: id => {
|
|
334
|
+
return clearTimeout(id);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
logger: console.log.bind(console),
|
|
338
|
+
devTools: false
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* An Actor is a running process that can receive events, send events and change its behavior based on the events it receives, which can cause effects outside of the actor. When you run a state machine, it becomes an actor.
|
|
343
|
+
*/
|
|
344
|
+
class Actor {
|
|
345
|
+
/**
|
|
346
|
+
* The current internal state of the actor.
|
|
347
|
+
*/
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* The unique identifier for this actor relative to its parent.
|
|
355
|
+
*/
|
|
356
|
+
|
|
357
|
+
/** @internal */
|
|
358
|
+
|
|
359
|
+
// Actor Ref
|
|
360
|
+
|
|
361
|
+
// TODO: add typings for system
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* The globally unique process ID for this invocation.
|
|
365
|
+
*/
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* The system to which this actor belongs.
|
|
369
|
+
*/
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Creates a new actor instance for the given logic with the provided options, if any.
|
|
373
|
+
*
|
|
374
|
+
* @param logic The logic to create an actor from
|
|
375
|
+
* @param options Actor options
|
|
376
|
+
*/
|
|
377
|
+
constructor(logic, options) {
|
|
378
|
+
this.logic = logic;
|
|
379
|
+
this._state = void 0;
|
|
380
|
+
this.clock = void 0;
|
|
381
|
+
this.options = void 0;
|
|
382
|
+
this.id = void 0;
|
|
383
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
384
|
+
this.delayedEventsMap = {};
|
|
385
|
+
this.observers = new Set();
|
|
386
|
+
this.logger = void 0;
|
|
387
|
+
this._processingStatus = ProcessingStatus.NotStarted;
|
|
388
|
+
this._parent = void 0;
|
|
389
|
+
this.ref = void 0;
|
|
390
|
+
this._actorScope = void 0;
|
|
391
|
+
this._systemId = void 0;
|
|
392
|
+
this.sessionId = void 0;
|
|
393
|
+
this.system = void 0;
|
|
394
|
+
this._doneEvent = void 0;
|
|
395
|
+
this.src = void 0;
|
|
396
|
+
this._deferred = [];
|
|
397
|
+
const resolvedOptions = {
|
|
398
|
+
...defaultOptions,
|
|
399
|
+
...options
|
|
400
|
+
};
|
|
401
|
+
const {
|
|
402
|
+
clock,
|
|
403
|
+
logger,
|
|
404
|
+
parent,
|
|
405
|
+
id,
|
|
406
|
+
systemId,
|
|
407
|
+
inspect
|
|
408
|
+
} = resolvedOptions;
|
|
409
|
+
this.system = parent?.system ?? createSystem(this);
|
|
410
|
+
if (inspect && !parent) {
|
|
411
|
+
// Always inspect at the system-level
|
|
412
|
+
this.system.inspect(toObserver(inspect));
|
|
413
|
+
}
|
|
414
|
+
this.sessionId = this.system._bookId();
|
|
415
|
+
this.id = id ?? this.sessionId;
|
|
416
|
+
this.logger = logger;
|
|
417
|
+
this.clock = clock;
|
|
418
|
+
this._parent = parent;
|
|
419
|
+
this.options = resolvedOptions;
|
|
420
|
+
this.src = resolvedOptions.src ?? logic;
|
|
421
|
+
this.ref = this;
|
|
422
|
+
this._actorScope = {
|
|
423
|
+
self: this,
|
|
424
|
+
id: this.id,
|
|
425
|
+
sessionId: this.sessionId,
|
|
426
|
+
logger: this.logger,
|
|
427
|
+
defer: fn => {
|
|
428
|
+
this._deferred.push(fn);
|
|
429
|
+
},
|
|
430
|
+
system: this.system,
|
|
431
|
+
stopChild: child => {
|
|
432
|
+
if (child._parent !== this) {
|
|
433
|
+
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
434
|
+
}
|
|
435
|
+
child._stop();
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// Ensure that the send method is bound to this Actor instance
|
|
440
|
+
// if destructured
|
|
441
|
+
this.send = this.send.bind(this);
|
|
442
|
+
this.system._sendInspectionEvent({
|
|
443
|
+
type: '@xstate.actor',
|
|
444
|
+
actorRef: this
|
|
445
|
+
});
|
|
446
|
+
if (systemId) {
|
|
447
|
+
this._systemId = systemId;
|
|
448
|
+
this.system._set(systemId, this);
|
|
449
|
+
}
|
|
450
|
+
this._initState(options?.state);
|
|
451
|
+
if (systemId && this._state.status !== 'active') {
|
|
452
|
+
this.system._unregister(this);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
_initState(persistedState) {
|
|
456
|
+
this._state = persistedState ? this.logic.restoreState ? this.logic.restoreState(persistedState, this._actorScope) : persistedState : this.logic.getInitialState(this._actorScope, this.options?.input);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// array of functions to defer
|
|
460
|
+
|
|
461
|
+
update(snapshot, event) {
|
|
462
|
+
// Update state
|
|
463
|
+
this._state = snapshot;
|
|
464
|
+
|
|
465
|
+
// Execute deferred effects
|
|
466
|
+
let deferredFn;
|
|
467
|
+
while (deferredFn = this._deferred.shift()) {
|
|
468
|
+
deferredFn();
|
|
469
|
+
}
|
|
470
|
+
for (const observer of this.observers) {
|
|
471
|
+
try {
|
|
472
|
+
observer.next?.(snapshot);
|
|
473
|
+
} catch (err) {
|
|
474
|
+
reportUnhandledError(err);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
switch (this._state.status) {
|
|
478
|
+
case 'done':
|
|
479
|
+
this._stopProcedure();
|
|
480
|
+
this._complete();
|
|
481
|
+
this._doneEvent = createDoneActorEvent(this.id, this._state.output);
|
|
482
|
+
if (this._parent) {
|
|
483
|
+
this.system._relay(this, this._parent, this._doneEvent);
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
case 'error':
|
|
487
|
+
this._stopProcedure();
|
|
488
|
+
this._error(this._state.error);
|
|
489
|
+
if (this._parent) {
|
|
490
|
+
this.system._relay(this, this._parent, createErrorActorEvent(this.id, this._state.error));
|
|
491
|
+
}
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
this.system._sendInspectionEvent({
|
|
495
|
+
type: '@xstate.snapshot',
|
|
496
|
+
actorRef: this,
|
|
497
|
+
event,
|
|
498
|
+
snapshot
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Subscribe an observer to an actor’s snapshot values.
|
|
504
|
+
*
|
|
505
|
+
* @remarks
|
|
506
|
+
* The observer will receive the actor’s snapshot value when it is emitted. The observer can be:
|
|
507
|
+
* - A plain function that receives the latest snapshot, or
|
|
508
|
+
* - An observer object whose `.next(snapshot)` method receives the latest snapshot
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```ts
|
|
512
|
+
* // Observer as a plain function
|
|
513
|
+
* const subscription = actor.subscribe((snapshot) => {
|
|
514
|
+
* console.log(snapshot);
|
|
515
|
+
* });
|
|
516
|
+
* ```
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* ```ts
|
|
520
|
+
* // Observer as an object
|
|
521
|
+
* const subscription = actor.subscribe({
|
|
522
|
+
* next(snapshot) {
|
|
523
|
+
* console.log(snapshot);
|
|
524
|
+
* },
|
|
525
|
+
* error(err) {
|
|
526
|
+
* // ...
|
|
527
|
+
* },
|
|
528
|
+
* complete() {
|
|
529
|
+
* // ...
|
|
530
|
+
* },
|
|
531
|
+
* });
|
|
532
|
+
* ```
|
|
533
|
+
*
|
|
534
|
+
* The return value of `actor.subscribe(observer)` is a subscription object that has an `.unsubscribe()` method. You can call `subscription.unsubscribe()` to unsubscribe the observer:
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```ts
|
|
538
|
+
* const subscription = actor.subscribe((snapshot) => {
|
|
539
|
+
* // ...
|
|
540
|
+
* });
|
|
541
|
+
*
|
|
542
|
+
* // Unsubscribe the observer
|
|
543
|
+
* subscription.unsubscribe();
|
|
544
|
+
* ```
|
|
545
|
+
*
|
|
546
|
+
* When the actor is stopped, all of its observers will automatically be unsubscribed.
|
|
547
|
+
*
|
|
548
|
+
* @param observer - Either a plain function that receives the latest snapshot, or an observer object whose `.next(snapshot)` method receives the latest snapshot
|
|
549
|
+
*/
|
|
550
|
+
|
|
551
|
+
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
552
|
+
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
553
|
+
if (this._processingStatus !== ProcessingStatus.Stopped) {
|
|
554
|
+
this.observers.add(observer);
|
|
555
|
+
} else {
|
|
556
|
+
try {
|
|
557
|
+
observer.complete?.();
|
|
558
|
+
} catch (err) {
|
|
559
|
+
reportUnhandledError(err);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return {
|
|
563
|
+
unsubscribe: () => {
|
|
564
|
+
this.observers.delete(observer);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Starts the Actor from the initial state
|
|
571
|
+
*/
|
|
572
|
+
start() {
|
|
573
|
+
if (this._processingStatus === ProcessingStatus.Running) {
|
|
574
|
+
// Do not restart the service if it is already started
|
|
575
|
+
return this;
|
|
576
|
+
}
|
|
577
|
+
this.system._register(this.sessionId, this);
|
|
578
|
+
if (this._systemId) {
|
|
579
|
+
this.system._set(this._systemId, this);
|
|
580
|
+
}
|
|
581
|
+
this._processingStatus = ProcessingStatus.Running;
|
|
582
|
+
|
|
583
|
+
// TODO: this isn't correct when rehydrating
|
|
584
|
+
const initEvent = createInitEvent(this.options.input);
|
|
585
|
+
this.system._sendInspectionEvent({
|
|
586
|
+
type: '@xstate.event',
|
|
587
|
+
sourceRef: this._parent,
|
|
588
|
+
actorRef: this,
|
|
589
|
+
event: initEvent
|
|
590
|
+
});
|
|
591
|
+
const status = this._state.status;
|
|
592
|
+
switch (status) {
|
|
593
|
+
case 'done':
|
|
594
|
+
// a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
|
|
595
|
+
// we still need to complete observers, flush deferreds etc
|
|
596
|
+
this.update(this._state, initEvent);
|
|
597
|
+
// fallthrough
|
|
598
|
+
case 'error':
|
|
599
|
+
// TODO: rethink cleanup of observers, mailbox, etc
|
|
600
|
+
return this;
|
|
601
|
+
}
|
|
602
|
+
if (this.logic.start) {
|
|
603
|
+
try {
|
|
604
|
+
this.logic.start(this._state, this._actorScope);
|
|
605
|
+
} catch (err) {
|
|
606
|
+
this._stopProcedure();
|
|
607
|
+
this._error(err);
|
|
608
|
+
this._parent?.send(createErrorActorEvent(this.id, err));
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// TODO: this notifies all subscribers but usually this is redundant
|
|
614
|
+
// there is no real change happening here
|
|
615
|
+
// we need to rethink if this needs to be refactored
|
|
616
|
+
this.update(this._state, initEvent);
|
|
617
|
+
if (this.options.devTools) {
|
|
618
|
+
this.attachDevTools();
|
|
619
|
+
}
|
|
620
|
+
this.mailbox.start();
|
|
621
|
+
return this;
|
|
622
|
+
}
|
|
623
|
+
_process(event) {
|
|
624
|
+
// TODO: reexamine what happens when an action (or a guard or smth) throws
|
|
625
|
+
let nextState;
|
|
626
|
+
let caughtError;
|
|
627
|
+
try {
|
|
628
|
+
nextState = this.logic.transition(this._state, event, this._actorScope);
|
|
629
|
+
} catch (err) {
|
|
630
|
+
// we wrap it in a box so we can rethrow it later even if falsy value gets caught here
|
|
631
|
+
caughtError = {
|
|
632
|
+
err
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
if (caughtError) {
|
|
636
|
+
const {
|
|
637
|
+
err
|
|
638
|
+
} = caughtError;
|
|
639
|
+
this._stopProcedure();
|
|
640
|
+
this._error(err);
|
|
641
|
+
this._parent?.send(createErrorActorEvent(this.id, err));
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
this.update(nextState, event);
|
|
645
|
+
if (event.type === XSTATE_STOP) {
|
|
646
|
+
this._stopProcedure();
|
|
647
|
+
this._complete();
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
_stop() {
|
|
651
|
+
if (this._processingStatus === ProcessingStatus.Stopped) {
|
|
652
|
+
return this;
|
|
653
|
+
}
|
|
654
|
+
this.mailbox.clear();
|
|
655
|
+
if (this._processingStatus === ProcessingStatus.NotStarted) {
|
|
656
|
+
this._processingStatus = ProcessingStatus.Stopped;
|
|
657
|
+
return this;
|
|
658
|
+
}
|
|
659
|
+
this.mailbox.enqueue({
|
|
660
|
+
type: XSTATE_STOP
|
|
661
|
+
});
|
|
662
|
+
return this;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Stops the Actor and unsubscribe all listeners.
|
|
667
|
+
*/
|
|
668
|
+
stop() {
|
|
669
|
+
if (this._parent) {
|
|
670
|
+
throw new Error('A non-root actor cannot be stopped directly.');
|
|
671
|
+
}
|
|
672
|
+
return this._stop();
|
|
673
|
+
}
|
|
674
|
+
_complete() {
|
|
675
|
+
for (const observer of this.observers) {
|
|
676
|
+
try {
|
|
677
|
+
observer.complete?.();
|
|
678
|
+
} catch (err) {
|
|
679
|
+
reportUnhandledError(err);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
this.observers.clear();
|
|
683
|
+
}
|
|
684
|
+
_error(err) {
|
|
685
|
+
if (!this.observers.size) {
|
|
686
|
+
if (!this._parent) {
|
|
687
|
+
reportUnhandledError(err);
|
|
688
|
+
}
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
let reportError = false;
|
|
692
|
+
for (const observer of this.observers) {
|
|
693
|
+
const errorListener = observer.error;
|
|
694
|
+
reportError ||= !errorListener;
|
|
695
|
+
try {
|
|
696
|
+
errorListener?.(err);
|
|
697
|
+
} catch (err2) {
|
|
698
|
+
reportUnhandledError(err2);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
this.observers.clear();
|
|
702
|
+
if (reportError) {
|
|
703
|
+
reportUnhandledError(err);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
_stopProcedure() {
|
|
707
|
+
if (this._processingStatus !== ProcessingStatus.Running) {
|
|
708
|
+
// Actor already stopped; do nothing
|
|
709
|
+
return this;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Cancel all delayed events
|
|
713
|
+
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
714
|
+
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// TODO: mailbox.reset
|
|
718
|
+
this.mailbox.clear();
|
|
719
|
+
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
720
|
+
// events sent *after* stop signal must be queued
|
|
721
|
+
// it seems like this should be the common behavior for all of our consumers
|
|
722
|
+
// so perhaps this should be unified somehow for all of them
|
|
723
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
724
|
+
this._processingStatus = ProcessingStatus.Stopped;
|
|
725
|
+
this.system._unregister(this);
|
|
726
|
+
return this;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @internal
|
|
731
|
+
*/
|
|
732
|
+
_send(event) {
|
|
733
|
+
if (this._processingStatus === ProcessingStatus.Stopped) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
this.mailbox.enqueue(event);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Sends an event to the running Actor to trigger a transition.
|
|
741
|
+
*
|
|
742
|
+
* @param event The event to send
|
|
743
|
+
*/
|
|
744
|
+
send(event) {
|
|
745
|
+
this.system._relay(undefined, this, event);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* TODO: figure out a way to do this within the machine
|
|
750
|
+
* @internal
|
|
751
|
+
*/
|
|
752
|
+
delaySend(params) {
|
|
753
|
+
const {
|
|
754
|
+
event,
|
|
755
|
+
id,
|
|
756
|
+
delay
|
|
757
|
+
} = params;
|
|
758
|
+
const timerId = this.clock.setTimeout(() => {
|
|
759
|
+
this.system._relay(this, params.to ?? this, event);
|
|
760
|
+
}, delay);
|
|
761
|
+
|
|
762
|
+
// TODO: consider the rehydration story here
|
|
763
|
+
if (id) {
|
|
764
|
+
this.delayedEventsMap[id] = timerId;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* TODO: figure out a way to do this within the machine
|
|
770
|
+
* @internal
|
|
771
|
+
*/
|
|
772
|
+
cancel(sendId) {
|
|
773
|
+
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
774
|
+
delete this.delayedEventsMap[sendId];
|
|
775
|
+
}
|
|
776
|
+
attachDevTools() {
|
|
777
|
+
const {
|
|
778
|
+
devTools
|
|
779
|
+
} = this.options;
|
|
780
|
+
if (devTools) {
|
|
781
|
+
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
|
|
782
|
+
resolvedDevToolsAdapter(this);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
toJSON() {
|
|
786
|
+
return {
|
|
787
|
+
xstate$$type: $$ACTOR_TYPE,
|
|
788
|
+
id: this.id
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Obtain the internal state of the actor, which can be persisted.
|
|
794
|
+
*
|
|
795
|
+
* @remarks
|
|
796
|
+
* The internal state can be persisted from any actor, not only machines.
|
|
797
|
+
*
|
|
798
|
+
* Note that the persisted state is not the same as the snapshot from {@link Actor.getSnapshot}. Persisted state represents the internal state of the actor, while snapshots represent the actor's last emitted value.
|
|
799
|
+
*
|
|
800
|
+
* Can be restored with {@link ActorOptions.state}
|
|
801
|
+
*
|
|
802
|
+
* @see https://stately.ai/docs/persistence
|
|
803
|
+
*/
|
|
804
|
+
|
|
805
|
+
getPersistedState(options) {
|
|
806
|
+
return this.logic.getPersistedState(this._state, options);
|
|
807
|
+
}
|
|
808
|
+
[symbolObservable]() {
|
|
809
|
+
return this;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Read an actor’s snapshot synchronously.
|
|
814
|
+
*
|
|
815
|
+
* @remarks
|
|
816
|
+
* The snapshot represent an actor's last emitted value.
|
|
817
|
+
*
|
|
818
|
+
* When an actor receives an event, its internal state may change.
|
|
819
|
+
* An actor may emit a snapshot when a state transition occurs.
|
|
820
|
+
*
|
|
821
|
+
* Note that some actors, such as callback actors generated with `fromCallback`, will not emit snapshots.
|
|
822
|
+
*
|
|
823
|
+
* @see {@link Actor.subscribe} to subscribe to an actor’s snapshot values.
|
|
824
|
+
* @see {@link Actor.getPersistedState} to persist the internal state of an actor (which is more than just a snapshot).
|
|
825
|
+
*/
|
|
826
|
+
getSnapshot() {
|
|
827
|
+
return this._state;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Creates a new `ActorRef` instance for the given machine with the provided options, if any.
|
|
833
|
+
*
|
|
834
|
+
* @param machine The machine to create an actor from
|
|
835
|
+
* @param options `ActorRef` options
|
|
836
|
+
*/
|
|
837
|
+
|
|
838
|
+
function createActor(logic, options) {
|
|
839
|
+
const interpreter = new Actor(logic, options);
|
|
840
|
+
return interpreter;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
845
|
+
*
|
|
846
|
+
* @deprecated Use `createActor` instead
|
|
847
|
+
*/
|
|
848
|
+
const interpret = createActor;
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* @deprecated Use `Actor` instead.
|
|
852
|
+
*/
|
|
2
853
|
|
|
3
854
|
const cache = new WeakMap();
|
|
4
855
|
function memo(object, key, fn) {
|
|
@@ -32,9 +883,6 @@ function executeCancel(actorScope, resolvedSendId) {
|
|
|
32
883
|
*/
|
|
33
884
|
function cancel(sendId) {
|
|
34
885
|
function cancel(args, params) {
|
|
35
|
-
{
|
|
36
|
-
throw new Error(`This isn't supposed to be called`);
|
|
37
|
-
}
|
|
38
886
|
}
|
|
39
887
|
cancel.type = 'xstate.cancel';
|
|
40
888
|
cancel.sendId = sendId;
|
|
@@ -50,25 +898,20 @@ function resolveSpawn(actorScope, state, actionArgs, _actionParams, {
|
|
|
50
898
|
input,
|
|
51
899
|
syncSnapshot
|
|
52
900
|
}) {
|
|
53
|
-
const
|
|
54
|
-
src,
|
|
55
|
-
input: undefined
|
|
56
|
-
};
|
|
901
|
+
const logic = typeof src === 'string' ? resolveReferencedActor(state.machine, src) : src;
|
|
57
902
|
const resolvedId = typeof id === 'function' ? id(actionArgs) : id;
|
|
58
903
|
let actorRef;
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
const configuredInput = input || referenced.input;
|
|
62
|
-
actorRef = createActor(referenced.src, {
|
|
904
|
+
if (logic) {
|
|
905
|
+
actorRef = createActor(logic, {
|
|
63
906
|
id: resolvedId,
|
|
64
907
|
src,
|
|
65
908
|
parent: actorScope?.self,
|
|
66
909
|
systemId,
|
|
67
|
-
input: typeof
|
|
910
|
+
input: typeof input === 'function' ? input({
|
|
68
911
|
context: state.context,
|
|
69
912
|
event: actionArgs.event,
|
|
70
913
|
self: actorScope?.self
|
|
71
|
-
}) :
|
|
914
|
+
}) : input
|
|
72
915
|
});
|
|
73
916
|
if (syncSnapshot) {
|
|
74
917
|
actorRef.subscribe({
|
|
@@ -84,9 +927,6 @@ function resolveSpawn(actorScope, state, actionArgs, _actionParams, {
|
|
|
84
927
|
});
|
|
85
928
|
}
|
|
86
929
|
}
|
|
87
|
-
if (!actorRef) {
|
|
88
|
-
console.warn(`Actor type '${src}' not found in machine '${actorScope.id}'.`);
|
|
89
|
-
}
|
|
90
930
|
return [cloneMachineSnapshot(state, {
|
|
91
931
|
children: {
|
|
92
932
|
...state.children,
|
|
@@ -123,9 +963,6 @@ function spawn(...[src, {
|
|
|
123
963
|
syncSnapshot = false
|
|
124
964
|
} = {}]) {
|
|
125
965
|
function spawn(args, params) {
|
|
126
|
-
{
|
|
127
|
-
throw new Error(`This isn't supposed to be called`);
|
|
128
|
-
}
|
|
129
966
|
}
|
|
130
967
|
spawn.type = 'xstate.spawn';
|
|
131
968
|
spawn.id = id;
|
|
@@ -185,9 +1022,6 @@ function executeStop(actorScope, actorRef) {
|
|
|
185
1022
|
*/
|
|
186
1023
|
function stop(actorRef) {
|
|
187
1024
|
function stop(args, params) {
|
|
188
|
-
{
|
|
189
|
-
throw new Error(`This isn't supposed to be called`);
|
|
190
|
-
}
|
|
191
1025
|
}
|
|
192
1026
|
stop.type = 'xstate.stop';
|
|
193
1027
|
stop.actorRef = actorRef;
|
|
@@ -207,9 +1041,7 @@ function checkStateIn(state, _, {
|
|
|
207
1041
|
}
|
|
208
1042
|
function stateIn(stateValue) {
|
|
209
1043
|
function stateIn(args, params) {
|
|
210
|
-
|
|
211
|
-
throw new Error(`This isn't supposed to be called`);
|
|
212
|
-
}
|
|
1044
|
+
return false;
|
|
213
1045
|
}
|
|
214
1046
|
stateIn.check = checkStateIn;
|
|
215
1047
|
stateIn.stateValue = stateValue;
|
|
@@ -225,9 +1057,7 @@ function checkNot(state, {
|
|
|
225
1057
|
}
|
|
226
1058
|
function not(guard) {
|
|
227
1059
|
function not(args, params) {
|
|
228
|
-
|
|
229
|
-
throw new Error(`This isn't supposed to be called`);
|
|
230
|
-
}
|
|
1060
|
+
return false;
|
|
231
1061
|
}
|
|
232
1062
|
not.check = checkNot;
|
|
233
1063
|
not.guards = [guard];
|
|
@@ -243,9 +1073,7 @@ function checkAnd(state, {
|
|
|
243
1073
|
}
|
|
244
1074
|
function and(guards) {
|
|
245
1075
|
function and(args, params) {
|
|
246
|
-
|
|
247
|
-
throw new Error(`This isn't supposed to be called`);
|
|
248
|
-
}
|
|
1076
|
+
return false;
|
|
249
1077
|
}
|
|
250
1078
|
and.check = checkAnd;
|
|
251
1079
|
and.guards = guards;
|
|
@@ -261,9 +1089,7 @@ function checkOr(state, {
|
|
|
261
1089
|
}
|
|
262
1090
|
function or(guards) {
|
|
263
1091
|
function or(args, params) {
|
|
264
|
-
|
|
265
|
-
throw new Error(`This isn't supposed to be called`);
|
|
266
|
-
}
|
|
1092
|
+
return false;
|
|
267
1093
|
}
|
|
268
1094
|
or.check = checkOr;
|
|
269
1095
|
or.guards = guards;
|
|
@@ -418,9 +1244,6 @@ function getCandidates(stateNode, receivedEventType) {
|
|
|
418
1244
|
if (!descriptor.endsWith('.*')) {
|
|
419
1245
|
return false;
|
|
420
1246
|
}
|
|
421
|
-
if (/.*\*.+/.test(descriptor)) {
|
|
422
|
-
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.`);
|
|
423
|
-
}
|
|
424
1247
|
const partialEventTokens = descriptor.split('.');
|
|
425
1248
|
const eventTokens = receivedEventType.split('.');
|
|
426
1249
|
for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
|
|
@@ -428,9 +1251,6 @@ function getCandidates(stateNode, receivedEventType) {
|
|
|
428
1251
|
const eventToken = eventTokens[tokenIndex];
|
|
429
1252
|
if (partialEventToken === '*') {
|
|
430
1253
|
const isLastToken = tokenIndex === partialEventTokens.length - 1;
|
|
431
|
-
if (!isLastToken) {
|
|
432
|
-
console.warn(`Infix wildcards in transition events are not allowed. Check the "${descriptor}" transition.`);
|
|
433
|
-
}
|
|
434
1254
|
return isLastToken;
|
|
435
1255
|
}
|
|
436
1256
|
if (partialEventToken !== eventToken) {
|
|
@@ -488,11 +1308,6 @@ function formatTransition(stateNode, descriptor, transitionConfig) {
|
|
|
488
1308
|
const normalizedTarget = normalizeTarget(transitionConfig.target);
|
|
489
1309
|
const reenter = transitionConfig.reenter ?? false;
|
|
490
1310
|
const target = resolveTarget(stateNode, normalizedTarget);
|
|
491
|
-
|
|
492
|
-
// TODO: should this be part of a lint rule instead?
|
|
493
|
-
if (transitionConfig.cond) {
|
|
494
|
-
throw new Error(`State "${stateNode.id}" has declared \`cond\` for one of its transitions. This property has been renamed to \`guard\`. Please update your code.`);
|
|
495
|
-
}
|
|
496
1311
|
const transition = {
|
|
497
1312
|
...transitionConfig,
|
|
498
1313
|
actions: toArray(transitionConfig.actions),
|
|
@@ -1168,9 +1983,6 @@ function resolveActionsAndContext(currentState, event, actorScope, actions, inte
|
|
|
1168
1983
|
return nextState;
|
|
1169
1984
|
}
|
|
1170
1985
|
function macrostep(state, event, actorScope, internalQueue = []) {
|
|
1171
|
-
if (event.type === WILDCARD) {
|
|
1172
|
-
throw new Error(`An event cannot have the wildcard type ('${WILDCARD}')`);
|
|
1173
|
-
}
|
|
1174
1986
|
let nextState = state;
|
|
1175
1987
|
const states = [];
|
|
1176
1988
|
|
|
@@ -1255,8 +2067,53 @@ function resolveStateValue(rootNode, stateValue) {
|
|
|
1255
2067
|
return getStateValue(rootNode, [...configuration]);
|
|
1256
2068
|
}
|
|
1257
2069
|
|
|
1258
|
-
function
|
|
2070
|
+
function isMachineSnapshot(value) {
|
|
2071
|
+
return !!value && typeof value === 'object' && 'machine' in value && 'value' in value;
|
|
2072
|
+
}
|
|
2073
|
+
const machineSnapshotMatches = function matches(testValue) {
|
|
2074
|
+
return matchesState(testValue, this.value);
|
|
2075
|
+
};
|
|
2076
|
+
const machineSnapshotHasTag = function hasTag(tag) {
|
|
2077
|
+
return this.tags.has(tag);
|
|
2078
|
+
};
|
|
2079
|
+
const machineSnapshotCan = function can(event) {
|
|
2080
|
+
const transitionData = this.machine.getTransitionData(this, event);
|
|
2081
|
+
return !!transitionData?.length &&
|
|
2082
|
+
// Check that at least one transition is not forbidden
|
|
2083
|
+
transitionData.some(t => t.target !== undefined || t.actions.length);
|
|
2084
|
+
};
|
|
2085
|
+
const machineSnapshotToJSON = function toJSON() {
|
|
2086
|
+
const {
|
|
2087
|
+
configuration,
|
|
2088
|
+
tags,
|
|
2089
|
+
machine,
|
|
2090
|
+
nextEvents,
|
|
2091
|
+
toJSON,
|
|
2092
|
+
can,
|
|
2093
|
+
hasTag,
|
|
2094
|
+
matches,
|
|
2095
|
+
...jsonValues
|
|
2096
|
+
} = this;
|
|
1259
2097
|
return {
|
|
2098
|
+
...jsonValues,
|
|
2099
|
+
tags: Array.from(tags)
|
|
2100
|
+
};
|
|
2101
|
+
};
|
|
2102
|
+
const machineSnapshotNextEvents = function nextEvents() {
|
|
2103
|
+
return memo(this, 'nextEvents', () => {
|
|
2104
|
+
return [...new Set(flatten([...this.configuration.map(sn => sn.ownEvents)]))];
|
|
2105
|
+
});
|
|
2106
|
+
};
|
|
2107
|
+
const machineSnapshotMeta = function nextEvents() {
|
|
2108
|
+
return this.configuration.reduce((acc, stateNode) => {
|
|
2109
|
+
if (stateNode.meta !== undefined) {
|
|
2110
|
+
acc[stateNode.id] = stateNode.meta;
|
|
2111
|
+
}
|
|
2112
|
+
return acc;
|
|
2113
|
+
}, {});
|
|
2114
|
+
};
|
|
2115
|
+
function createMachineSnapshot(config, machine) {
|
|
2116
|
+
const snapshot = {
|
|
1260
2117
|
status: config.status,
|
|
1261
2118
|
output: config.output,
|
|
1262
2119
|
error: config.error,
|
|
@@ -1267,52 +2124,25 @@ function createMachineSnapshot(config, machine) {
|
|
|
1267
2124
|
tags: new Set(flatten(config.configuration.map(sn => sn.tags))),
|
|
1268
2125
|
children: config.children,
|
|
1269
2126
|
historyValue: config.historyValue || {},
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
return !!transitionData?.length &&
|
|
1282
|
-
// Check that at least one transition is not forbidden
|
|
1283
|
-
transitionData.some(t => t.target !== undefined || t.actions.length);
|
|
1284
|
-
},
|
|
1285
|
-
get nextEvents() {
|
|
1286
|
-
return memo(this, 'nextEvents', () => {
|
|
1287
|
-
return [...new Set(flatten([...this.configuration.map(sn => sn.ownEvents)]))];
|
|
1288
|
-
});
|
|
1289
|
-
},
|
|
1290
|
-
get meta() {
|
|
1291
|
-
return this.configuration.reduce((acc, stateNode) => {
|
|
1292
|
-
if (stateNode.meta !== undefined) {
|
|
1293
|
-
acc[stateNode.id] = stateNode.meta;
|
|
1294
|
-
}
|
|
1295
|
-
return acc;
|
|
1296
|
-
}, {});
|
|
2127
|
+
// this one is generic in the target and it's hard to create a matching non-generic source signature
|
|
2128
|
+
matches: machineSnapshotMatches,
|
|
2129
|
+
hasTag: machineSnapshotHasTag,
|
|
2130
|
+
can: machineSnapshotCan,
|
|
2131
|
+
toJSON: machineSnapshotToJSON
|
|
2132
|
+
};
|
|
2133
|
+
Object.defineProperties(snapshot, {
|
|
2134
|
+
nextEvents: {
|
|
2135
|
+
get: machineSnapshotNextEvents,
|
|
2136
|
+
configurable: true,
|
|
2137
|
+
enumerable: true
|
|
1297
2138
|
},
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
machine,
|
|
1303
|
-
nextEvents,
|
|
1304
|
-
toJSON,
|
|
1305
|
-
can,
|
|
1306
|
-
hasTag,
|
|
1307
|
-
matches,
|
|
1308
|
-
...jsonValues
|
|
1309
|
-
} = this;
|
|
1310
|
-
return {
|
|
1311
|
-
...jsonValues,
|
|
1312
|
-
tags: Array.from(tags)
|
|
1313
|
-
};
|
|
2139
|
+
meta: {
|
|
2140
|
+
get: machineSnapshotMeta,
|
|
2141
|
+
configurable: true,
|
|
2142
|
+
enumerable: true
|
|
1314
2143
|
}
|
|
1315
|
-
};
|
|
2144
|
+
});
|
|
2145
|
+
return snapshot;
|
|
1316
2146
|
}
|
|
1317
2147
|
function cloneMachineSnapshot(state, config = {}) {
|
|
1318
2148
|
return createMachineSnapshot(
|
|
@@ -1339,9 +2169,6 @@ function getPersistedState(state, options) {
|
|
|
1339
2169
|
const childrenJson = {};
|
|
1340
2170
|
for (const id in children) {
|
|
1341
2171
|
const child = children[id];
|
|
1342
|
-
if (typeof child.src !== 'string' && (!options || !('__unsafeAllowInlineActors' in options))) {
|
|
1343
|
-
throw new Error('An inline child actor cannot be persisted.');
|
|
1344
|
-
}
|
|
1345
2172
|
childrenJson[id] = {
|
|
1346
2173
|
state: child.getPersistedState(options),
|
|
1347
2174
|
src: child.src,
|
|
@@ -1424,9 +2251,6 @@ function executeRaise(actorScope, params) {
|
|
|
1424
2251
|
*/
|
|
1425
2252
|
function raise(eventOrExpr, options) {
|
|
1426
2253
|
function raise(args, params) {
|
|
1427
|
-
{
|
|
1428
|
-
throw new Error(`This isn't supposed to be called`);
|
|
1429
|
-
}
|
|
1430
2254
|
}
|
|
1431
2255
|
raise.type = 'xstate.raise';
|
|
1432
2256
|
raise.event = eventOrExpr;
|
|
@@ -1437,4 +2261,4 @@ function raise(eventOrExpr, options) {
|
|
|
1437
2261
|
return raise;
|
|
1438
2262
|
}
|
|
1439
2263
|
|
|
1440
|
-
export {
|
|
2264
|
+
export { $$ACTOR_TYPE as $, getPersistedState as A, resolveReferencedActor as B, createActor as C, Actor as D, interpret as E, isMachineSnapshot as F, matchesState as G, pathToStateValue as H, toObserver as I, and as J, not as K, or as L, stateIn as M, NULL_EVENT as N, cancel as O, raise as P, stop as Q, spawn as R, STATE_DELIMITER as S, ProcessingStatus as T, createErrorActorEvent as U, XSTATE_ERROR as V, XSTATE_STOP as X, toTransitionConfigArray as a, formatTransition as b, memo as c, createInvokeId as d, evaluateGuard as e, formatTransitions as f, getDelayedTransitions as g, formatInitialTransition as h, getCandidates as i, getConfiguration as j, getStateNodes as k, createMachineSnapshot as l, mapValues as m, isInFinalState as n, isErrorActorEvent as o, cloneMachineSnapshot as p, macrostep as q, resolveStateValue as r, transitionNode as s, toArray as t, resolveActionsAndContext as u, createInitEvent as v, microstep as w, getInitialStateNodes as x, isStateId as y, getStateNodeByPath as z };
|