import { __assign, __spreadArray, __read, __values } from './_virtual/_tslib.js'; import { SpecialTargets, ActionTypes } from './types.js'; 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'; import * as actionTypes from './actionTypes.js'; export { actionTypes }; import { toSCXMLEvent, isString, isFunction, toEventObject, getEventType, updateContext, flatten, isArray, toArray, toGuard, evaluateGuard, warn } from './utils.js'; import { IS_PRODUCTION } from './environment.js'; var initEvent = /*#__PURE__*/toSCXMLEvent({ type: init }); function getActionFunction(actionType, actionFunctionMap) { return actionFunctionMap ? actionFunctionMap[actionType] || undefined : undefined; } function toActionObject(action, actionFunctionMap) { var actionObject; if (isString(action) || typeof action === 'number') { var exec = getActionFunction(action, actionFunctionMap); if (isFunction(exec)) { actionObject = { type: action, exec: exec }; } else if (exec) { actionObject = exec; } else { actionObject = { type: action, exec: undefined }; } } else if (isFunction(action)) { actionObject = { // Convert action to string if unnamed type: action.name || action.toString(), exec: action }; } else { var exec = getActionFunction(action.type, actionFunctionMap); if (isFunction(exec)) { actionObject = __assign(__assign({}, action), { exec: exec }); } else if (exec) { var actionType = exec.type || action.type; actionObject = __assign(__assign(__assign({}, exec), action), { type: actionType }); } else { actionObject = action; } } return actionObject; } var toActionObjects = function (action, actionFunctionMap) { if (!action) { return []; } var actions = isArray(action) ? action : [action]; return actions.map(function (subAction) { return toActionObject(subAction, actionFunctionMap); }); }; function toActivityDefinition(action) { var actionObject = toActionObject(action); return __assign(__assign({ id: isString(action) ? action : actionObject.id }, actionObject), { type: actionObject.type }); } /** * Raises an event. This places the event in the internal event queue, so that * the event is immediately consumed by the machine in the current step. * * @param eventType The event to raise. */ function raise(event, options) { return { type: raise$1, event: typeof event === 'function' ? event : toEventObject(event), delay: options ? options.delay : undefined, id: options === null || options === void 0 ? void 0 : options.id }; } function resolveRaise(action, ctx, _event, delaysMap) { var meta = { _event: _event }; var resolvedEvent = toSCXMLEvent(isFunction(action.event) ? action.event(ctx, _event.data, meta) : action.event); var resolvedDelay; if (isString(action.delay)) { var configDelay = delaysMap && delaysMap[action.delay]; resolvedDelay = isFunction(configDelay) ? configDelay(ctx, _event.data, meta) : configDelay; } else { resolvedDelay = isFunction(action.delay) ? action.delay(ctx, _event.data, meta) : action.delay; } return __assign(__assign({}, action), { type: raise$1, _event: resolvedEvent, delay: resolvedDelay }); } /** * Sends an event. This returns an action that will be read by an interpreter to * send the event in the next step, after the current step is finished executing. * * @deprecated Use the `sendTo(...)` action creator instead. * * @param event The event to send. * @param options Options to pass into the send event: * - `id` - The unique send event identifier (used with `cancel()`). * - `delay` - The number of milliseconds to delay the sending of the event. * - `to` - The target of this event (by default, the machine the event was sent from). */ function send(event, options) { return { to: options ? options.to : undefined, type: send$1, event: isFunction(event) ? event : toEventObject(event), delay: options ? options.delay : undefined, // TODO: don't auto-generate IDs here like that // there is too big chance of the ID collision id: options && options.id !== undefined ? options.id : isFunction(event) ? event.name : getEventType(event) }; } function resolveSend(action, ctx, _event, delaysMap) { var meta = { _event: _event }; // TODO: helper function for resolving Expr var resolvedEvent = toSCXMLEvent(isFunction(action.event) ? action.event(ctx, _event.data, meta) : action.event); var resolvedDelay; if (isString(action.delay)) { var configDelay = delaysMap && delaysMap[action.delay]; resolvedDelay = isFunction(configDelay) ? configDelay(ctx, _event.data, meta) : configDelay; } else { resolvedDelay = isFunction(action.delay) ? action.delay(ctx, _event.data, meta) : action.delay; } var resolvedTarget = isFunction(action.to) ? action.to(ctx, _event.data, meta) : action.to; return __assign(__assign({}, action), { to: resolvedTarget, _event: resolvedEvent, event: resolvedEvent.data, delay: resolvedDelay }); } /** * Sends an event to this machine's parent. * * @param event The event to send to the parent machine. * @param options Options to pass into the send event. */ function sendParent(event, options) { return send(event, __assign(__assign({}, options), { to: SpecialTargets.Parent })); } /** * Sends an event to an actor. * * @param actor The `ActorRef` to send the event to. * @param event The event to send, or an expression that evaluates to the event to send * @param options Send action options * @returns An XState send action object */ function sendTo(actor, event, options) { return send(event, __assign(__assign({}, options), { to: actor })); } /** * Sends an update event to this machine's parent. */ function sendUpdate() { return sendParent(update); } /** * Sends an event back to the sender of the original event. * * @param event The event to send back to the sender * @param options Options to pass into the send event */ function respond(event, options) { return send(event, __assign(__assign({}, options), { to: function (_, __, _a) { var _event = _a._event; return _event.origin; // TODO: handle when _event.origin is undefined } })); } var defaultLogExpr = function (context, event) { return { context: context, event: event }; }; /** * * @param expr The expression function to evaluate which will be logged. * Takes in 2 arguments: * - `ctx` - the current state context * - `event` - the event that caused this action to be executed. * @param label The label to give to the logged expression. */ function log(expr, label) { if (expr === void 0) { expr = defaultLogExpr; } return { type: log$1, label: label, expr: expr }; } var resolveLog = function (action, ctx, _event) { return __assign(__assign({}, action), { value: isString(action.expr) ? action.expr : action.expr(ctx, _event.data, { _event: _event }) }); }; /** * Cancels an in-flight `send(...)` action. A canceled sent action will not * be executed, nor will its event be sent, unless it has already been sent * (e.g., if `cancel(...)` is called after the `send(...)` action's `delay`). * * @param sendId The `id` of the `send(...)` action to cancel. */ var cancel = function (sendId) { return { type: cancel$1, sendId: sendId }; }; /** * Starts an activity. * * @param activity The activity to start. */ function start(activity) { var activityDef = toActivityDefinition(activity); return { type: ActionTypes.Start, activity: activityDef, exec: undefined }; } /** * Stops an activity. * * @param actorRef The activity to stop. */ function stop(actorRef) { var activity = isFunction(actorRef) ? actorRef : toActivityDefinition(actorRef); return { type: ActionTypes.Stop, activity: activity, exec: undefined }; } function resolveStop(action, context, _event) { var actorRefOrString = isFunction(action.activity) ? action.activity(context, _event.data) : action.activity; var resolvedActorRef = typeof actorRefOrString === 'string' ? { id: actorRefOrString } : actorRefOrString; var actionObject = { type: ActionTypes.Stop, activity: resolvedActorRef }; return actionObject; } /** * Updates the current context of the machine. * * @param assignment An object that represents the partial context to update. */ var assign = function (assignment) { return { type: assign$1, assignment: assignment }; }; function isActionObject(action) { return typeof action === 'object' && 'type' in action; } /** * Returns an event type that represents an implicit event that * is sent after the specified `delay`. * * @param delayRef The delay in milliseconds * @param id The state node ID where this event is handled */ function after(delayRef, id) { var idSuffix = id ? "#".concat(id) : ''; return "".concat(ActionTypes.After, "(").concat(delayRef, ")").concat(idSuffix); } /** * Returns an event that represents that a final state node * has been reached in the parent state node. * * @param id The final state node's parent state node `id` * @param data The data to pass into the event */ function done(id, data) { var type = "".concat(ActionTypes.DoneState, ".").concat(id); var eventObject = { type: type, data: data }; eventObject.toString = function () { return type; }; return eventObject; } /** * Returns an event that represents that an invoked service has terminated. * * An invoked service is terminated when it has reached a top-level final state node, * but not when it is canceled. * * @param id The final state node ID * @param data The data to pass into the event */ function doneInvoke(id, data) { var type = "".concat(ActionTypes.DoneInvoke, ".").concat(id); var eventObject = { type: type, data: data }; eventObject.toString = function () { return type; }; return eventObject; } function error(id, data) { var type = "".concat(ActionTypes.ErrorPlatform, ".").concat(id); var eventObject = { type: type, data: data }; eventObject.toString = function () { return type; }; return eventObject; } function pure(getActions) { return { type: ActionTypes.Pure, get: getActions }; } /** * Forwards (sends) an event to a specified service. * * @param target The target service to forward the event to. * @param options Options to pass into the send action creator. */ function forwardTo(target, options) { if (!IS_PRODUCTION && (!target || typeof target === 'function')) { var originalTarget_1 = target; target = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var resolvedTarget = typeof originalTarget_1 === 'function' ? originalTarget_1.apply(void 0, __spreadArray([], __read(args), false)) : originalTarget_1; if (!resolvedTarget) { throw new Error("Attempted to forward event to undefined actor. This risks an infinite loop in the sender."); } return resolvedTarget; }; } return send(function (_, event) { return event; }, __assign(__assign({}, options), { to: target })); } /** * Escalates an error by sending it as an event to this machine's parent. * * @param errorData The error data to send, or the expression function that * takes in the `context`, `event`, and `meta`, and returns the error data to send. * @param options Options to pass into the send action creator. */ function escalate(errorData, options) { return sendParent(function (context, event, meta) { return { type: error$1, data: isFunction(errorData) ? errorData(context, event, meta) : errorData }; }, __assign(__assign({}, options), { to: SpecialTargets.Parent })); } function choose(conds) { return { type: ActionTypes.Choose, conds: conds }; } var pluckAssigns = function (actionBlocks) { var e_1, _a; var assignActions = []; try { for (var actionBlocks_1 = __values(actionBlocks), actionBlocks_1_1 = actionBlocks_1.next(); !actionBlocks_1_1.done; actionBlocks_1_1 = actionBlocks_1.next()) { var block = actionBlocks_1_1.value; var i = 0; while (i < block.actions.length) { if (block.actions[i].type === assign$1) { assignActions.push(block.actions[i]); block.actions.splice(i, 1); continue; } i++; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (actionBlocks_1_1 && !actionBlocks_1_1.done && (_a = actionBlocks_1.return)) _a.call(actionBlocks_1); } finally { if (e_1) throw e_1.error; } } return assignActions; }; function resolveActions(machine, currentState, currentContext, _event, actionBlocks, predictableExec, preserveActionOrder) { if (preserveActionOrder === void 0) { preserveActionOrder = false; } var assignActions = preserveActionOrder ? [] : pluckAssigns(actionBlocks); var updatedContext = assignActions.length ? updateContext(currentContext, _event, assignActions, currentState) : currentContext; var preservedContexts = preserveActionOrder ? [currentContext] : undefined; var deferredToBlockEnd = []; function handleAction(blockType, actionObject) { var _a; switch (actionObject.type) { case raise$1: { var raisedAction = resolveRaise(actionObject, updatedContext, _event, machine.options.delays); if (predictableExec && typeof raisedAction.delay === 'number') { predictableExec(raisedAction, updatedContext, _event); } return raisedAction; } case send$1: var sendAction = resolveSend(actionObject, updatedContext, _event, machine.options.delays); // TODO: fix ActionTypes.Init if (!IS_PRODUCTION) { var configuredDelay = actionObject.delay; // warn after resolving as we can create better contextual message here warn(!isString(configuredDelay) || typeof sendAction.delay === 'number', // tslint:disable-next-line:max-line-length "No delay reference for delay expression '".concat(configuredDelay, "' was found on machine '").concat(machine.id, "'")); } if (predictableExec && sendAction.to !== SpecialTargets.Internal) { if (blockType === 'entry') { deferredToBlockEnd.push(sendAction); } else { predictableExec(sendAction, updatedContext, _event); } } return sendAction; case log$1: { var resolved = resolveLog(actionObject, updatedContext, _event); predictableExec === null || predictableExec === void 0 ? void 0 : predictableExec(resolved, updatedContext, _event); return resolved; } case choose$1: { var chooseAction = actionObject; var matchedActions = (_a = chooseAction.conds.find(function (condition) { var guard = toGuard(condition.cond, machine.options.guards); return !guard || evaluateGuard(machine, guard, updatedContext, _event, !predictableExec ? currentState : undefined); })) === null || _a === void 0 ? void 0 : _a.actions; if (!matchedActions) { return []; } var _b = __read(resolveActions(machine, currentState, updatedContext, _event, [{ type: blockType, actions: toActionObjects(toArray(matchedActions), machine.options.actions) }], predictableExec, preserveActionOrder), 2), resolvedActionsFromChoose = _b[0], resolvedContextFromChoose = _b[1]; updatedContext = resolvedContextFromChoose; preservedContexts === null || preservedContexts === void 0 ? void 0 : preservedContexts.push(updatedContext); return resolvedActionsFromChoose; } case pure$1: { var matchedActions = actionObject.get(updatedContext, _event.data); if (!matchedActions) { return []; } var _c = __read(resolveActions(machine, currentState, updatedContext, _event, [{ type: blockType, actions: toActionObjects(toArray(matchedActions), machine.options.actions) }], predictableExec, preserveActionOrder), 2), resolvedActionsFromPure = _c[0], resolvedContext = _c[1]; updatedContext = resolvedContext; preservedContexts === null || preservedContexts === void 0 ? void 0 : preservedContexts.push(updatedContext); return resolvedActionsFromPure; } case stop$1: { var resolved = resolveStop(actionObject, updatedContext, _event); predictableExec === null || predictableExec === void 0 ? void 0 : predictableExec(resolved, currentContext, _event); return resolved; } case assign$1: { updatedContext = updateContext(updatedContext, _event, [actionObject], !predictableExec ? currentState : undefined); preservedContexts === null || preservedContexts === void 0 ? void 0 : preservedContexts.push(updatedContext); break; } default: var resolvedActionObject = toActionObject(actionObject, machine.options.actions); var exec_1 = resolvedActionObject.exec; if (predictableExec) { predictableExec(resolvedActionObject, updatedContext, _event); } else if (exec_1 && preservedContexts) { var contextIndex_1 = preservedContexts.length - 1; var wrapped = __assign(__assign({}, resolvedActionObject), { exec: function (_ctx) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } exec_1.apply(void 0, __spreadArray([preservedContexts[contextIndex_1]], __read(args), false)); } }); resolvedActionObject = wrapped; } return resolvedActionObject; } } function processBlock(block) { var e_2, _a; var resolvedActions = []; try { for (var _b = __values(block.actions), _c = _b.next(); !_c.done; _c = _b.next()) { var action = _c.value; var resolved = handleAction(block.type, action); if (resolved) { resolvedActions = resolvedActions.concat(resolved); } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } deferredToBlockEnd.forEach(function (action) { predictableExec(action, updatedContext, _event); }); deferredToBlockEnd.length = 0; return resolvedActions; } var resolvedActions = flatten(actionBlocks.map(processBlock)); return [resolvedActions, updatedContext]; } 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 };