actions.js 19 KB

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