'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _tslib = require('./_virtual/_tslib.js'); var types = require('./types.js'); var actionTypes = require('./actionTypes.js'); var utils = require('./utils.js'); var environment = require('./environment.js'); var initEvent = /*#__PURE__*/utils.toSCXMLEvent({ type: actionTypes.init }); function getActionFunction(actionType, actionFunctionMap) { return actionFunctionMap ? actionFunctionMap[actionType] || undefined : undefined; } function toActionObject(action, actionFunctionMap) { var actionObject; if (utils.isString(action) || typeof action === 'number') { var exec = getActionFunction(action, actionFunctionMap); if (utils.isFunction(exec)) { actionObject = { type: action, exec: exec }; } else if (exec) { actionObject = exec; } else { actionObject = { type: action, exec: undefined }; } } else if (utils.isFunction(action)) { actionObject = { // Convert action to string if unnamed type: action.name || action.toString(), exec: action }; } else { var exec = getActionFunction(action.type, actionFunctionMap); if (utils.isFunction(exec)) { actionObject = _tslib.__assign(_tslib.__assign({}, action), { exec: exec }); } else if (exec) { var actionType = exec.type || action.type; actionObject = _tslib.__assign(_tslib.__assign(_tslib.__assign({}, exec), action), { type: actionType }); } else { actionObject = action; } } return actionObject; } var toActionObjects = function (action, actionFunctionMap) { if (!action) { return []; } var actions = utils.isArray(action) ? action : [action]; return actions.map(function (subAction) { return toActionObject(subAction, actionFunctionMap); }); }; function toActivityDefinition(action) { var actionObject = toActionObject(action); return _tslib.__assign(_tslib.__assign({ id: utils.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: actionTypes.raise, event: typeof event === 'function' ? event : utils.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 = utils.toSCXMLEvent(utils.isFunction(action.event) ? action.event(ctx, _event.data, meta) : action.event); var resolvedDelay; if (utils.isString(action.delay)) { var configDelay = delaysMap && delaysMap[action.delay]; resolvedDelay = utils.isFunction(configDelay) ? configDelay(ctx, _event.data, meta) : configDelay; } else { resolvedDelay = utils.isFunction(action.delay) ? action.delay(ctx, _event.data, meta) : action.delay; } return _tslib.__assign(_tslib.__assign({}, action), { type: actionTypes.raise, _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: actionTypes.send, event: utils.isFunction(event) ? event : utils.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 : utils.isFunction(event) ? event.name : utils.getEventType(event) }; } function resolveSend(action, ctx, _event, delaysMap) { var meta = { _event: _event }; // TODO: helper function for resolving Expr var resolvedEvent = utils.toSCXMLEvent(utils.isFunction(action.event) ? action.event(ctx, _event.data, meta) : action.event); var resolvedDelay; if (utils.isString(action.delay)) { var configDelay = delaysMap && delaysMap[action.delay]; resolvedDelay = utils.isFunction(configDelay) ? configDelay(ctx, _event.data, meta) : configDelay; } else { resolvedDelay = utils.isFunction(action.delay) ? action.delay(ctx, _event.data, meta) : action.delay; } var resolvedTarget = utils.isFunction(action.to) ? action.to(ctx, _event.data, meta) : action.to; return _tslib.__assign(_tslib.__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, _tslib.__assign(_tslib.__assign({}, options), { to: types.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, _tslib.__assign(_tslib.__assign({}, options), { to: actor })); } /** * Sends an update event to this machine's parent. */ function sendUpdate() { return sendParent(actionTypes.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, _tslib.__assign(_tslib.__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: actionTypes.log, label: label, expr: expr }; } var resolveLog = function (action, ctx, _event) { return _tslib.__assign(_tslib.__assign({}, action), { value: utils.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: actionTypes.cancel, sendId: sendId }; }; /** * Starts an activity. * * @param activity The activity to start. */ function start(activity) { var activityDef = toActivityDefinition(activity); return { type: types.ActionTypes.Start, activity: activityDef, exec: undefined }; } /** * Stops an activity. * * @param actorRef The activity to stop. */ function stop(actorRef) { var activity = utils.isFunction(actorRef) ? actorRef : toActivityDefinition(actorRef); return { type: types.ActionTypes.Stop, activity: activity, exec: undefined }; } function resolveStop(action, context, _event) { var actorRefOrString = utils.isFunction(action.activity) ? action.activity(context, _event.data) : action.activity; var resolvedActorRef = typeof actorRefOrString === 'string' ? { id: actorRefOrString } : actorRefOrString; var actionObject = { type: types.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: actionTypes.assign, 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(types.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(types.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(types.ActionTypes.DoneInvoke, ".").concat(id); var eventObject = { type: type, data: data }; eventObject.toString = function () { return type; }; return eventObject; } function error(id, data) { var type = "".concat(types.ActionTypes.ErrorPlatform, ".").concat(id); var eventObject = { type: type, data: data }; eventObject.toString = function () { return type; }; return eventObject; } function pure(getActions) { return { type: types.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 (!environment.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, _tslib.__spreadArray([], _tslib.__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; }, _tslib.__assign(_tslib.__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: actionTypes.error, data: utils.isFunction(errorData) ? errorData(context, event, meta) : errorData }; }, _tslib.__assign(_tslib.__assign({}, options), { to: types.SpecialTargets.Parent })); } function choose(conds) { return { type: types.ActionTypes.Choose, conds: conds }; } var pluckAssigns = function (actionBlocks) { var e_1, _a; var assignActions = []; try { for (var actionBlocks_1 = _tslib.__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 === actionTypes.assign) { 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 ? utils.updateContext(currentContext, _event, assignActions, currentState) : currentContext; var preservedContexts = preserveActionOrder ? [currentContext] : undefined; var deferredToBlockEnd = []; function handleAction(blockType, actionObject) { var _a; switch (actionObject.type) { case actionTypes.raise: { var raisedAction = resolveRaise(actionObject, updatedContext, _event, machine.options.delays); if (predictableExec && typeof raisedAction.delay === 'number') { predictableExec(raisedAction, updatedContext, _event); } return raisedAction; } case actionTypes.send: var sendAction = resolveSend(actionObject, updatedContext, _event, machine.options.delays); // TODO: fix ActionTypes.Init if (!environment.IS_PRODUCTION) { var configuredDelay = actionObject.delay; // warn after resolving as we can create better contextual message here utils.warn(!utils.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 !== types.SpecialTargets.Internal) { if (blockType === 'entry') { deferredToBlockEnd.push(sendAction); } else { predictableExec(sendAction, updatedContext, _event); } } return sendAction; case actionTypes.log: { var resolved = resolveLog(actionObject, updatedContext, _event); predictableExec === null || predictableExec === void 0 ? void 0 : predictableExec(resolved, updatedContext, _event); return resolved; } case actionTypes.choose: { var chooseAction = actionObject; var matchedActions = (_a = chooseAction.conds.find(function (condition) { var guard = utils.toGuard(condition.cond, machine.options.guards); return !guard || utils.evaluateGuard(machine, guard, updatedContext, _event, !predictableExec ? currentState : undefined); })) === null || _a === void 0 ? void 0 : _a.actions; if (!matchedActions) { return []; } var _b = _tslib.__read(resolveActions(machine, currentState, updatedContext, _event, [{ type: blockType, actions: toActionObjects(utils.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 actionTypes.pure: { var matchedActions = actionObject.get(updatedContext, _event.data); if (!matchedActions) { return []; } var _c = _tslib.__read(resolveActions(machine, currentState, updatedContext, _event, [{ type: blockType, actions: toActionObjects(utils.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 actionTypes.stop: { var resolved = resolveStop(actionObject, updatedContext, _event); predictableExec === null || predictableExec === void 0 ? void 0 : predictableExec(resolved, currentContext, _event); return resolved; } case actionTypes.assign: { updatedContext = utils.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 = _tslib.__assign(_tslib.__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, _tslib.__spreadArray([preservedContexts[contextIndex_1]], _tslib.__read(args), false)); } }); resolvedActionObject = wrapped; } return resolvedActionObject; } } function processBlock(block) { var e_2, _a; var resolvedActions = []; try { for (var _b = _tslib.__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 = utils.flatten(actionBlocks.map(processBlock)); return [resolvedActions, updatedContext]; } exports.actionTypes = actionTypes; exports.after = after; exports.assign = assign; exports.cancel = cancel; exports.choose = choose; exports.done = done; exports.doneInvoke = doneInvoke; exports.error = error; exports.escalate = escalate; exports.forwardTo = forwardTo; exports.getActionFunction = getActionFunction; exports.initEvent = initEvent; exports.isActionObject = isActionObject; exports.log = log; exports.pure = pure; exports.raise = raise; exports.resolveActions = resolveActions; exports.resolveLog = resolveLog; exports.resolveRaise = resolveRaise; exports.resolveSend = resolveSend; exports.resolveStop = resolveStop; exports.respond = respond; exports.send = send; exports.sendParent = sendParent; exports.sendTo = sendTo; exports.sendUpdate = sendUpdate; exports.start = start; exports.stop = stop; exports.toActionObject = toActionObject; exports.toActionObjects = toActionObjects; exports.toActivityDefinition = toActivityDefinition;