UNPKG

19.8 kBJavaScriptView Raw
1import { __assign, __spreadArray, __read, __values } from './_virtual/_tslib.js';
2import { SpecialTargets, ActionTypes } from './types.js';
3import { init, raise as raise$1, send as send$1, update, log as log$1, cancel as cancel$1, assign as assign$1, error as error$1, stop as stop$1, pure as pure$1, choose as choose$1 } from './actionTypes.js';
4import * as actionTypes from './actionTypes.js';
5export { actionTypes };
6import { toSCXMLEvent, isString, isFunction, toEventObject, getEventType, updateContext, flatten, isArray, toArray, toGuard, evaluateGuard, warn } from './utils.js';
7import { IS_PRODUCTION } from './environment.js';
8
9var initEvent = /*#__PURE__*/toSCXMLEvent({
10 type: init
11});
12function getActionFunction(actionType, actionFunctionMap) {
13 return actionFunctionMap ? actionFunctionMap[actionType] || undefined : undefined;
14}
15function toActionObject(action, actionFunctionMap) {
16 var actionObject;
17
18 if (isString(action) || typeof action === 'number') {
19 var exec = getActionFunction(action, actionFunctionMap);
20
21 if (isFunction(exec)) {
22 actionObject = {
23 type: action,
24 exec: exec
25 };
26 } else if (exec) {
27 actionObject = exec;
28 } else {
29 actionObject = {
30 type: action,
31 exec: undefined
32 };
33 }
34 } else if (isFunction(action)) {
35 actionObject = {
36 // Convert action to string if unnamed
37 type: action.name || action.toString(),
38 exec: action
39 };
40 } else {
41 var exec = getActionFunction(action.type, actionFunctionMap);
42
43 if (isFunction(exec)) {
44 actionObject = __assign(__assign({}, action), {
45 exec: exec
46 });
47 } else if (exec) {
48 var actionType = exec.type || action.type;
49 actionObject = __assign(__assign(__assign({}, exec), action), {
50 type: actionType
51 });
52 } else {
53 actionObject = action;
54 }
55 }
56
57 return actionObject;
58}
59var toActionObjects = function (action, actionFunctionMap) {
60 if (!action) {
61 return [];
62 }
63
64 var actions = isArray(action) ? action : [action];
65 return actions.map(function (subAction) {
66 return toActionObject(subAction, actionFunctionMap);
67 });
68};
69function toActivityDefinition(action) {
70 var actionObject = toActionObject(action);
71 return __assign(__assign({
72 id: isString(action) ? action : actionObject.id
73 }, actionObject), {
74 type: actionObject.type
75 });
76}
77/**
78 * Raises an event. This places the event in the internal event queue, so that
79 * the event is immediately consumed by the machine in the current step.
80 *
81 * @param eventType The event to raise.
82 */
83
84function raise(event, options) {
85 return {
86 type: raise$1,
87 event: typeof event === 'function' ? event : toEventObject(event),
88 delay: options ? options.delay : undefined,
89 id: options === null || options === void 0 ? void 0 : options.id
90 };
91}
92function resolveRaise(action, ctx, _event, delaysMap) {
93 var meta = {
94 _event: _event
95 };
96 var resolvedEvent = toSCXMLEvent(isFunction(action.event) ? action.event(ctx, _event.data, meta) : action.event);
97 var resolvedDelay;
98
99 if (isString(action.delay)) {
100 var configDelay = delaysMap && delaysMap[action.delay];
101 resolvedDelay = isFunction(configDelay) ? configDelay(ctx, _event.data, meta) : configDelay;
102 } else {
103 resolvedDelay = isFunction(action.delay) ? action.delay(ctx, _event.data, meta) : action.delay;
104 }
105
106 return __assign(__assign({}, action), {
107 type: raise$1,
108 _event: resolvedEvent,
109 delay: resolvedDelay
110 });
111}
112/**
113 * Sends an event. This returns an action that will be read by an interpreter to
114 * send the event in the next step, after the current step is finished executing.
115 *
116 * @deprecated Use the `sendTo(...)` action creator instead.
117 *
118 * @param event The event to send.
119 * @param options Options to pass into the send event:
120 * - `id` - The unique send event identifier (used with `cancel()`).
121 * - `delay` - The number of milliseconds to delay the sending of the event.
122 * - `to` - The target of this event (by default, the machine the event was sent from).
123 */
124
125function send(event, options) {
126 return {
127 to: options ? options.to : undefined,
128 type: send$1,
129 event: isFunction(event) ? event : toEventObject(event),
130 delay: options ? options.delay : undefined,
131 // TODO: don't auto-generate IDs here like that
132 // there is too big chance of the ID collision
133 id: options && options.id !== undefined ? options.id : isFunction(event) ? event.name : getEventType(event)
134 };
135}
136function resolveSend(action, ctx, _event, delaysMap) {
137 var meta = {
138 _event: _event
139 }; // TODO: helper function for resolving Expr
140
141 var resolvedEvent = toSCXMLEvent(isFunction(action.event) ? action.event(ctx, _event.data, meta) : action.event);
142 var resolvedDelay;
143
144 if (isString(action.delay)) {
145 var configDelay = delaysMap && delaysMap[action.delay];
146 resolvedDelay = isFunction(configDelay) ? configDelay(ctx, _event.data, meta) : configDelay;
147 } else {
148 resolvedDelay = isFunction(action.delay) ? action.delay(ctx, _event.data, meta) : action.delay;
149 }
150
151 var resolvedTarget = isFunction(action.to) ? action.to(ctx, _event.data, meta) : action.to;
152 return __assign(__assign({}, action), {
153 to: resolvedTarget,
154 _event: resolvedEvent,
155 event: resolvedEvent.data,
156 delay: resolvedDelay
157 });
158}
159/**
160 * Sends an event to this machine's parent.
161 *
162 * @param event The event to send to the parent machine.
163 * @param options Options to pass into the send event.
164 */
165
166function sendParent(event, options) {
167 return send(event, __assign(__assign({}, options), {
168 to: SpecialTargets.Parent
169 }));
170}
171/**
172 * Sends an event to an actor.
173 *
174 * @param actor The `ActorRef` to send the event to.
175 * @param event The event to send, or an expression that evaluates to the event to send
176 * @param options Send action options
177 * @returns An XState send action object
178 */
179
180function sendTo(actor, event, options) {
181 return send(event, __assign(__assign({}, options), {
182 to: actor
183 }));
184}
185/**
186 * Sends an update event to this machine's parent.
187 */
188
189function sendUpdate() {
190 return sendParent(update);
191}
192/**
193 * Sends an event back to the sender of the original event.
194 *
195 * @param event The event to send back to the sender
196 * @param options Options to pass into the send event
197 */
198
199function respond(event, options) {
200 return send(event, __assign(__assign({}, options), {
201 to: function (_, __, _a) {
202 var _event = _a._event;
203 return _event.origin; // TODO: handle when _event.origin is undefined
204 }
205 }));
206}
207
208var defaultLogExpr = function (context, event) {
209 return {
210 context: context,
211 event: event
212 };
213};
214/**
215 *
216 * @param expr The expression function to evaluate which will be logged.
217 * Takes in 2 arguments:
218 * - `ctx` - the current state context
219 * - `event` - the event that caused this action to be executed.
220 * @param label The label to give to the logged expression.
221 */
222
223
224function log(expr, label) {
225 if (expr === void 0) {
226 expr = defaultLogExpr;
227 }
228
229 return {
230 type: log$1,
231 label: label,
232 expr: expr
233 };
234}
235var resolveLog = function (action, ctx, _event) {
236 return __assign(__assign({}, action), {
237 value: isString(action.expr) ? action.expr : action.expr(ctx, _event.data, {
238 _event: _event
239 })
240 });
241};
242/**
243 * Cancels an in-flight `send(...)` action. A canceled sent action will not
244 * be executed, nor will its event be sent, unless it has already been sent
245 * (e.g., if `cancel(...)` is called after the `send(...)` action's `delay`).
246 *
247 * @param sendId The `id` of the `send(...)` action to cancel.
248 */
249
250var cancel = function (sendId) {
251 return {
252 type: cancel$1,
253 sendId: sendId
254 };
255};
256/**
257 * Starts an activity.
258 *
259 * @param activity The activity to start.
260 */
261
262function start(activity) {
263 var activityDef = toActivityDefinition(activity);
264 return {
265 type: ActionTypes.Start,
266 activity: activityDef,
267 exec: undefined
268 };
269}
270/**
271 * Stops an activity.
272 *
273 * @param actorRef The activity to stop.
274 */
275
276function stop(actorRef) {
277 var activity = isFunction(actorRef) ? actorRef : toActivityDefinition(actorRef);
278 return {
279 type: ActionTypes.Stop,
280 activity: activity,
281 exec: undefined
282 };
283}
284function resolveStop(action, context, _event) {
285 var actorRefOrString = isFunction(action.activity) ? action.activity(context, _event.data) : action.activity;
286 var resolvedActorRef = typeof actorRefOrString === 'string' ? {
287 id: actorRefOrString
288 } : actorRefOrString;
289 var actionObject = {
290 type: ActionTypes.Stop,
291 activity: resolvedActorRef
292 };
293 return actionObject;
294}
295/**
296 * Updates the current context of the machine.
297 *
298 * @param assignment An object that represents the partial context to update.
299 */
300
301var assign = function (assignment) {
302 return {
303 type: assign$1,
304 assignment: assignment
305 };
306};
307function isActionObject(action) {
308 return typeof action === 'object' && 'type' in action;
309}
310/**
311 * Returns an event type that represents an implicit event that
312 * is sent after the specified `delay`.
313 *
314 * @param delayRef The delay in milliseconds
315 * @param id The state node ID where this event is handled
316 */
317
318function after(delayRef, id) {
319 var idSuffix = id ? "#".concat(id) : '';
320 return "".concat(ActionTypes.After, "(").concat(delayRef, ")").concat(idSuffix);
321}
322/**
323 * Returns an event that represents that a final state node
324 * has been reached in the parent state node.
325 *
326 * @param id The final state node's parent state node `id`
327 * @param data The data to pass into the event
328 */
329
330function done(id, data) {
331 var type = "".concat(ActionTypes.DoneState, ".").concat(id);
332 var eventObject = {
333 type: type,
334 data: data
335 };
336
337 eventObject.toString = function () {
338 return type;
339 };
340
341 return eventObject;
342}
343/**
344 * Returns an event that represents that an invoked service has terminated.
345 *
346 * An invoked service is terminated when it has reached a top-level final state node,
347 * but not when it is canceled.
348 *
349 * @param id The final state node ID
350 * @param data The data to pass into the event
351 */
352
353function doneInvoke(id, data) {
354 var type = "".concat(ActionTypes.DoneInvoke, ".").concat(id);
355 var eventObject = {
356 type: type,
357 data: data
358 };
359
360 eventObject.toString = function () {
361 return type;
362 };
363
364 return eventObject;
365}
366function error(id, data) {
367 var type = "".concat(ActionTypes.ErrorPlatform, ".").concat(id);
368 var eventObject = {
369 type: type,
370 data: data
371 };
372
373 eventObject.toString = function () {
374 return type;
375 };
376
377 return eventObject;
378}
379function pure(getActions) {
380 return {
381 type: ActionTypes.Pure,
382 get: getActions
383 };
384}
385/**
386 * Forwards (sends) an event to a specified service.
387 *
388 * @param target The target service to forward the event to.
389 * @param options Options to pass into the send action creator.
390 */
391
392function forwardTo(target, options) {
393 if (!IS_PRODUCTION && (!target || typeof target === 'function')) {
394 var originalTarget_1 = target;
395
396 target = function () {
397 var args = [];
398
399 for (var _i = 0; _i < arguments.length; _i++) {
400 args[_i] = arguments[_i];
401 }
402
403 var resolvedTarget = typeof originalTarget_1 === 'function' ? originalTarget_1.apply(void 0, __spreadArray([], __read(args), false)) : originalTarget_1;
404
405 if (!resolvedTarget) {
406 throw new Error("Attempted to forward event to undefined actor. This risks an infinite loop in the sender.");
407 }
408
409 return resolvedTarget;
410 };
411 }
412
413 return send(function (_, event) {
414 return event;
415 }, __assign(__assign({}, options), {
416 to: target
417 }));
418}
419/**
420 * Escalates an error by sending it as an event to this machine's parent.
421 *
422 * @param errorData The error data to send, or the expression function that
423 * takes in the `context`, `event`, and `meta`, and returns the error data to send.
424 * @param options Options to pass into the send action creator.
425 */
426
427function escalate(errorData, options) {
428 return sendParent(function (context, event, meta) {
429 return {
430 type: error$1,
431 data: isFunction(errorData) ? errorData(context, event, meta) : errorData
432 };
433 }, __assign(__assign({}, options), {
434 to: SpecialTargets.Parent
435 }));
436}
437function choose(conds) {
438 return {
439 type: ActionTypes.Choose,
440 conds: conds
441 };
442}
443
444var pluckAssigns = function (actionBlocks) {
445 var e_1, _a;
446
447 var assignActions = [];
448
449 try {
450 for (var actionBlocks_1 = __values(actionBlocks), actionBlocks_1_1 = actionBlocks_1.next(); !actionBlocks_1_1.done; actionBlocks_1_1 = actionBlocks_1.next()) {
451 var block = actionBlocks_1_1.value;
452 var i = 0;
453
454 while (i < block.actions.length) {
455 if (block.actions[i].type === assign$1) {
456 assignActions.push(block.actions[i]);
457 block.actions.splice(i, 1);
458 continue;
459 }
460
461 i++;
462 }
463 }
464 } catch (e_1_1) {
465 e_1 = {
466 error: e_1_1
467 };
468 } finally {
469 try {
470 if (actionBlocks_1_1 && !actionBlocks_1_1.done && (_a = actionBlocks_1.return)) _a.call(actionBlocks_1);
471 } finally {
472 if (e_1) throw e_1.error;
473 }
474 }
475
476 return assignActions;
477};
478
479function resolveActions(machine, currentState, currentContext, _event, actionBlocks, predictableExec, preserveActionOrder) {
480 if (preserveActionOrder === void 0) {
481 preserveActionOrder = false;
482 }
483
484 var assignActions = preserveActionOrder ? [] : pluckAssigns(actionBlocks);
485 var updatedContext = assignActions.length ? updateContext(currentContext, _event, assignActions, currentState) : currentContext;
486 var preservedContexts = preserveActionOrder ? [currentContext] : undefined;
487 var deferredToBlockEnd = [];
488
489 function handleAction(blockType, actionObject) {
490 var _a;
491
492 switch (actionObject.type) {
493 case raise$1:
494 {
495 var raisedAction = resolveRaise(actionObject, updatedContext, _event, machine.options.delays);
496
497 if (predictableExec && typeof raisedAction.delay === 'number') {
498 predictableExec(raisedAction, updatedContext, _event);
499 }
500
501 return raisedAction;
502 }
503
504 case send$1:
505 var sendAction = resolveSend(actionObject, updatedContext, _event, machine.options.delays); // TODO: fix ActionTypes.Init
506
507 if (!IS_PRODUCTION) {
508 var configuredDelay = actionObject.delay; // warn after resolving as we can create better contextual message here
509
510 warn(!isString(configuredDelay) || typeof sendAction.delay === 'number', // tslint:disable-next-line:max-line-length
511 "No delay reference for delay expression '".concat(configuredDelay, "' was found on machine '").concat(machine.id, "'"));
512 }
513
514 if (predictableExec && sendAction.to !== SpecialTargets.Internal) {
515 if (blockType === 'entry') {
516 deferredToBlockEnd.push(sendAction);
517 } else {
518 predictableExec(sendAction, updatedContext, _event);
519 }
520 }
521
522 return sendAction;
523
524 case log$1:
525 {
526 var resolved = resolveLog(actionObject, updatedContext, _event);
527 predictableExec === null || predictableExec === void 0 ? void 0 : predictableExec(resolved, updatedContext, _event);
528 return resolved;
529 }
530
531 case choose$1:
532 {
533 var chooseAction = actionObject;
534 var matchedActions = (_a = chooseAction.conds.find(function (condition) {
535 var guard = toGuard(condition.cond, machine.options.guards);
536 return !guard || evaluateGuard(machine, guard, updatedContext, _event, !predictableExec ? currentState : undefined);
537 })) === null || _a === void 0 ? void 0 : _a.actions;
538
539 if (!matchedActions) {
540 return [];
541 }
542
543 var _b = __read(resolveActions(machine, currentState, updatedContext, _event, [{
544 type: blockType,
545 actions: toActionObjects(toArray(matchedActions), machine.options.actions)
546 }], predictableExec, preserveActionOrder), 2),
547 resolvedActionsFromChoose = _b[0],
548 resolvedContextFromChoose = _b[1];
549
550 updatedContext = resolvedContextFromChoose;
551 preservedContexts === null || preservedContexts === void 0 ? void 0 : preservedContexts.push(updatedContext);
552 return resolvedActionsFromChoose;
553 }
554
555 case pure$1:
556 {
557 var matchedActions = actionObject.get(updatedContext, _event.data);
558
559 if (!matchedActions) {
560 return [];
561 }
562
563 var _c = __read(resolveActions(machine, currentState, updatedContext, _event, [{
564 type: blockType,
565 actions: toActionObjects(toArray(matchedActions), machine.options.actions)
566 }], predictableExec, preserveActionOrder), 2),
567 resolvedActionsFromPure = _c[0],
568 resolvedContext = _c[1];
569
570 updatedContext = resolvedContext;
571 preservedContexts === null || preservedContexts === void 0 ? void 0 : preservedContexts.push(updatedContext);
572 return resolvedActionsFromPure;
573 }
574
575 case stop$1:
576 {
577 var resolved = resolveStop(actionObject, updatedContext, _event);
578 predictableExec === null || predictableExec === void 0 ? void 0 : predictableExec(resolved, currentContext, _event);
579 return resolved;
580 }
581
582 case assign$1:
583 {
584 updatedContext = updateContext(updatedContext, _event, [actionObject], !predictableExec ? currentState : undefined);
585 preservedContexts === null || preservedContexts === void 0 ? void 0 : preservedContexts.push(updatedContext);
586 break;
587 }
588
589 default:
590 var resolvedActionObject = toActionObject(actionObject, machine.options.actions);
591 var exec_1 = resolvedActionObject.exec;
592
593 if (predictableExec) {
594 predictableExec(resolvedActionObject, updatedContext, _event);
595 } else if (exec_1 && preservedContexts) {
596 var contextIndex_1 = preservedContexts.length - 1;
597
598 var wrapped = __assign(__assign({}, resolvedActionObject), {
599 exec: function (_ctx) {
600 var args = [];
601
602 for (var _i = 1; _i < arguments.length; _i++) {
603 args[_i - 1] = arguments[_i];
604 }
605
606 exec_1.apply(void 0, __spreadArray([preservedContexts[contextIndex_1]], __read(args), false));
607 }
608 });
609
610 resolvedActionObject = wrapped;
611 }
612
613 return resolvedActionObject;
614 }
615 }
616
617 function processBlock(block) {
618 var e_2, _a;
619
620 var resolvedActions = [];
621
622 try {
623 for (var _b = __values(block.actions), _c = _b.next(); !_c.done; _c = _b.next()) {
624 var action = _c.value;
625 var resolved = handleAction(block.type, action);
626
627 if (resolved) {
628 resolvedActions = resolvedActions.concat(resolved);
629 }
630 }
631 } catch (e_2_1) {
632 e_2 = {
633 error: e_2_1
634 };
635 } finally {
636 try {
637 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
638 } finally {
639 if (e_2) throw e_2.error;
640 }
641 }
642
643 deferredToBlockEnd.forEach(function (action) {
644 predictableExec(action, updatedContext, _event);
645 });
646 deferredToBlockEnd.length = 0;
647 return resolvedActions;
648 }
649
650 var resolvedActions = flatten(actionBlocks.map(processBlock));
651 return [resolvedActions, updatedContext];
652}
653
654export { after, assign, cancel, choose, done, doneInvoke, error, escalate, forwardTo, getActionFunction, initEvent, isActionObject, log, pure, raise, resolveActions, resolveLog, resolveRaise, resolveSend, resolveStop, respond, send, sendParent, sendTo, sendUpdate, start, stop, toActionObject, toActionObjects, toActivityDefinition };