1471 lines
63 KiB
JavaScript
1471 lines
63 KiB
JavaScript
"use strict";
|
|
var __assign = (this && this.__assign) || function () {
|
|
__assign = Object.assign || function(t) {
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
s = arguments[i];
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
t[p] = s[p];
|
|
}
|
|
return t;
|
|
};
|
|
return __assign.apply(this, arguments);
|
|
};
|
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
var t = {};
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
t[p] = s[p];
|
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
|
|
t[p[i]] = s[p[i]];
|
|
return t;
|
|
};
|
|
var __read = (this && this.__read) || function (o, n) {
|
|
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
if (!m) return o;
|
|
var i = m.call(o), r, ar = [], e;
|
|
try {
|
|
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
}
|
|
catch (error) { e = { error: error }; }
|
|
finally {
|
|
try {
|
|
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
}
|
|
finally { if (e) throw e.error; }
|
|
}
|
|
return ar;
|
|
};
|
|
var __spread = (this && this.__spread) || function () {
|
|
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
|
|
return ar;
|
|
};
|
|
var __values = (this && this.__values) || function (o) {
|
|
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
|
|
if (m) return m.call(o);
|
|
return {
|
|
next: function () {
|
|
if (o && i >= o.length) o = void 0;
|
|
return { value: o && o[i++], done: !o };
|
|
}
|
|
};
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var utils_1 = require("./utils");
|
|
var types_1 = require("./types");
|
|
var utils_2 = require("./utils");
|
|
var State_1 = require("./State");
|
|
var actionTypes = require("./actionTypes");
|
|
var actions_1 = require("./actions");
|
|
var StateTree_1 = require("./StateTree");
|
|
var environment_1 = require("./environment");
|
|
var constants_1 = require("./constants");
|
|
var stateUtils_1 = require("./stateUtils");
|
|
var STATE_DELIMITER = '.';
|
|
var NULL_EVENT = '';
|
|
var STATE_IDENTIFIER = '#';
|
|
var TARGETLESS_KEY = '';
|
|
var EMPTY_OBJECT = {};
|
|
var isStateId = function (str) { return str[0] === STATE_IDENTIFIER; };
|
|
var createDefaultOptions = function () { return ({
|
|
actions: {},
|
|
guards: {},
|
|
services: {},
|
|
activities: {},
|
|
delays: {},
|
|
updater: utils_1.updateContext
|
|
}); };
|
|
var StateNode = /** @class */ (function () {
|
|
function StateNode(_config, options,
|
|
/**
|
|
* The initial extended state
|
|
*/
|
|
context) {
|
|
var _this = this;
|
|
this.context = context;
|
|
this.__xstatenode = true;
|
|
this.__cache = {
|
|
events: undefined,
|
|
relativeValue: new Map(),
|
|
initialStateValue: undefined,
|
|
initialState: undefined,
|
|
transitions: undefined
|
|
};
|
|
this.idMap = {};
|
|
var parent = _config.parent, config = __rest(_config, ["parent"]);
|
|
this.config = config;
|
|
this.parent = parent;
|
|
this.options = __assign({}, createDefaultOptions(), options);
|
|
this.key = _config.key || _config.id || '(machine)';
|
|
this.machine = this.parent ? this.parent.machine : this;
|
|
this.path = this.parent ? this.parent.path.concat(this.key) : [];
|
|
this.delimiter =
|
|
_config.delimiter ||
|
|
(this.parent ? this.parent.delimiter : STATE_DELIMITER);
|
|
this.id =
|
|
_config.id ||
|
|
(this.machine
|
|
? __spread([this.machine.key], this.path).join(this.delimiter)
|
|
: this.key);
|
|
this.version = this.parent
|
|
? this.parent.version
|
|
: _config.version;
|
|
this.type =
|
|
_config.type ||
|
|
(_config.parallel
|
|
? 'parallel'
|
|
: _config.states && utils_1.keys(_config.states).length
|
|
? 'compound'
|
|
: _config.history
|
|
? 'history'
|
|
: 'atomic');
|
|
if (!environment_1.IS_PRODUCTION) {
|
|
utils_1.warn(!('parallel' in _config), "The \"parallel\" property is deprecated and will be removed in version 4.1. " + (_config.parallel
|
|
? "Replace with `type: 'parallel'`"
|
|
: "Use `type: '" + this.type + "'`") + " in the config for state node '" + this.id + "' instead.");
|
|
}
|
|
this.initial = _config.initial;
|
|
this.order = _config.order || -1;
|
|
this.states = (_config.states
|
|
? utils_1.mapValues(_config.states, function (stateConfig, key, _, i) {
|
|
var _a;
|
|
var stateNode = new StateNode(__assign({}, stateConfig, { key: key, order: stateConfig.order === undefined ? i : stateConfig.order, parent: _this }));
|
|
Object.assign(_this.idMap, __assign((_a = {}, _a[stateNode.id] = stateNode, _a), stateNode.idMap));
|
|
return stateNode;
|
|
})
|
|
: EMPTY_OBJECT);
|
|
// History config
|
|
this.history =
|
|
_config.history === true ? 'shallow' : _config.history || false;
|
|
this._transient = !!(_config.on && _config.on[NULL_EVENT]);
|
|
this.strict = !!_config.strict;
|
|
// TODO: deprecate (entry)
|
|
this.onEntry = utils_1.toArray(_config.entry || _config.onEntry).map(function (action) {
|
|
return actions_1.toActionObject(action);
|
|
});
|
|
// TODO: deprecate (exit)
|
|
this.onExit = utils_1.toArray(_config.exit || _config.onExit).map(function (action) {
|
|
return actions_1.toActionObject(action);
|
|
});
|
|
this.meta = _config.meta;
|
|
this.data =
|
|
this.type === 'final'
|
|
? _config.data
|
|
: undefined;
|
|
this.invoke = utils_1.toArray(_config.invoke).map(function (invokeConfig, i) {
|
|
var _a, _b;
|
|
if (utils_1.isMachine(invokeConfig)) {
|
|
(_this.parent || _this).options.services = __assign((_a = {}, _a[invokeConfig.id] = invokeConfig, _a), (_this.parent || _this).options.services);
|
|
return {
|
|
type: actionTypes.invoke,
|
|
src: invokeConfig.id,
|
|
id: invokeConfig.id
|
|
};
|
|
}
|
|
else if (typeof invokeConfig.src !== 'string') {
|
|
var invokeSrc = _this.id + ":invocation[" + i + "]"; // TODO: util function
|
|
_this.machine.options.services = __assign((_b = {}, _b[invokeSrc] = invokeConfig.src, _b), _this.machine.options.services);
|
|
return __assign({ type: actionTypes.invoke, id: invokeSrc }, invokeConfig, { src: invokeSrc });
|
|
}
|
|
else {
|
|
return __assign({}, invokeConfig, { type: actionTypes.invoke, id: invokeConfig.id || invokeConfig.src, src: invokeConfig.src });
|
|
}
|
|
});
|
|
this.activities = utils_1.toArray(_config.activities)
|
|
.concat(this.invoke)
|
|
.map(function (activity) { return actions_1.toActivityDefinition(activity); });
|
|
this.after = this.getDelayedTransitions();
|
|
}
|
|
/**
|
|
* Clones this state machine with custom options and context.
|
|
*
|
|
* @param options Options (actions, guards, activities, services) to recursively merge with the existing options.
|
|
* @param context Custom context (will override predefined context)
|
|
*/
|
|
StateNode.prototype.withConfig = function (options, context) {
|
|
if (context === void 0) { context = this.context; }
|
|
var _a = this.options, actions = _a.actions, activities = _a.activities, guards = _a.guards, services = _a.services, delays = _a.delays;
|
|
return new StateNode(this.config, {
|
|
actions: __assign({}, actions, options.actions),
|
|
activities: __assign({}, activities, options.activities),
|
|
guards: __assign({}, guards, options.guards),
|
|
services: __assign({}, services, options.services),
|
|
delays: __assign({}, delays, options.delays)
|
|
}, context);
|
|
};
|
|
/**
|
|
* Clones this state machine with custom context.
|
|
*
|
|
* @param context Custom context (will override predefined context, not recursive)
|
|
*/
|
|
StateNode.prototype.withContext = function (context) {
|
|
return new StateNode(this.config, this.options, context);
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "definition", {
|
|
/**
|
|
* The well-structured state node definition.
|
|
*/
|
|
get: function () {
|
|
return {
|
|
id: this.id,
|
|
key: this.key,
|
|
version: this.version,
|
|
type: this.type,
|
|
initial: this.initial,
|
|
history: this.history,
|
|
states: utils_1.mapValues(this.states, function (state) { return state.definition; }),
|
|
on: this.on,
|
|
onEntry: this.onEntry,
|
|
onExit: this.onExit,
|
|
activities: this.activities || [],
|
|
meta: this.meta,
|
|
order: this.order || -1,
|
|
data: this.data,
|
|
invoke: this.invoke
|
|
};
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateNode.prototype.toJSON = function () {
|
|
return this.definition;
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "on", {
|
|
/**
|
|
* The mapping of events to transitions.
|
|
*/
|
|
get: function () {
|
|
return (this.__cache.transitions ||
|
|
((this.__cache.transitions = this.formatTransitions()),
|
|
this.__cache.transitions));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateNode.prototype, "transitions", {
|
|
/**
|
|
* All the transitions that can be taken from this state node.
|
|
*/
|
|
get: function () {
|
|
var _this = this;
|
|
return utils_1.flatten(utils_1.keys(this.on).map(function (event) { return _this.on[event]; }));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
/**
|
|
* All delayed transitions from the config.
|
|
*/
|
|
StateNode.prototype.getDelayedTransitions = function () {
|
|
var _this = this;
|
|
if (this.after) {
|
|
return this.after;
|
|
}
|
|
var afterConfig = this.config.after;
|
|
var guards = this.machine.options.guards;
|
|
if (!afterConfig) {
|
|
return [];
|
|
}
|
|
if (utils_1.isArray(afterConfig)) {
|
|
return afterConfig.map(function (delayedTransition, i) {
|
|
var delay = delayedTransition.delay, target = delayedTransition.target;
|
|
var delayRef;
|
|
if (utils_1.isFunction(delay)) {
|
|
delayRef = _this.id + ":delay[" + i + "]";
|
|
_this.options.delays[delayRef] = delay; // TODO: util function
|
|
}
|
|
else {
|
|
delayRef = delay;
|
|
}
|
|
var event = actions_1.after(delayRef, _this.id);
|
|
_this.onEntry.push(actions_1.send(event, { delay: delay }));
|
|
_this.onExit.push(actions_1.cancel(event));
|
|
return __assign({ event: event }, delayedTransition, { source: _this, target: target === undefined ? undefined : utils_1.toArray(target), cond: utils_1.toGuard(delayedTransition.cond, guards), actions: utils_1.toArray(delayedTransition.actions).map(function (action) {
|
|
return actions_1.toActionObject(action);
|
|
}) });
|
|
});
|
|
}
|
|
var allDelayedTransitions = utils_1.flatten(utils_1.keys(afterConfig).map(function (delayKey) {
|
|
var delayedTransition = afterConfig[delayKey];
|
|
var delay = isNaN(+delayKey) ? delayKey : +delayKey;
|
|
var event = actions_1.after(delay, _this.id);
|
|
_this.onEntry.push(actions_1.send(event, { delay: delay }));
|
|
_this.onExit.push(actions_1.cancel(event));
|
|
if (utils_1.isString(delayedTransition)) {
|
|
return [
|
|
{
|
|
source: _this,
|
|
target: [delayedTransition],
|
|
delay: delay,
|
|
event: event,
|
|
actions: []
|
|
}
|
|
];
|
|
}
|
|
var delayedTransitions = utils_1.toArray(delayedTransition);
|
|
return delayedTransitions.map(function (transition) { return (__assign({ event: event,
|
|
delay: delay }, transition, { source: _this, target: transition.target === undefined
|
|
? transition.target
|
|
: utils_1.toArray(transition.target), cond: utils_1.toGuard(transition.cond, guards), actions: utils_1.toArray(transition.actions).map(function (action) {
|
|
return actions_1.toActionObject(action);
|
|
}) })); });
|
|
}));
|
|
allDelayedTransitions.sort(function (a, b) {
|
|
return utils_1.isString(a) || utils_1.isString(b) ? 0 : +a.delay - +b.delay;
|
|
});
|
|
return allDelayedTransitions;
|
|
};
|
|
/**
|
|
* Returns the state nodes represented by the current state value.
|
|
*
|
|
* @param state The state value or State instance
|
|
*/
|
|
StateNode.prototype.getStateNodes = function (state) {
|
|
var _this = this;
|
|
var _a;
|
|
if (!state) {
|
|
return [];
|
|
}
|
|
var stateValue = state instanceof State_1.State
|
|
? state.value
|
|
: utils_1.toStateValue(state, this.delimiter);
|
|
if (utils_1.isString(stateValue)) {
|
|
var initialStateValue = this.getStateNode(stateValue).initial;
|
|
return initialStateValue !== undefined
|
|
? this.getStateNodes((_a = {}, _a[stateValue] = initialStateValue, _a))
|
|
: [this.states[stateValue]];
|
|
}
|
|
var subStateKeys = utils_1.keys(stateValue);
|
|
var subStateNodes = subStateKeys.map(function (subStateKey) { return _this.getStateNode(subStateKey); });
|
|
return subStateNodes.concat(subStateKeys.reduce(function (allSubStateNodes, subStateKey) {
|
|
var subStateNode = _this.getStateNode(subStateKey).getStateNodes(stateValue[subStateKey]);
|
|
return allSubStateNodes.concat(subStateNode);
|
|
}, []));
|
|
};
|
|
/**
|
|
* Returns `true` if this state node explicitly handles the given event.
|
|
*
|
|
* @param event The event in question
|
|
*/
|
|
StateNode.prototype.handles = function (event) {
|
|
var eventType = utils_1.getEventType(event);
|
|
return this.events.indexOf(eventType) !== -1;
|
|
};
|
|
/**
|
|
* Resolves the given `state` to a new `State` instance relative to this machine.
|
|
*
|
|
* This ensures that `.events` and `.nextEvents` represent the correct values.
|
|
*
|
|
* @param state The state to resolve
|
|
*/
|
|
StateNode.prototype.resolveState = function (state) {
|
|
return new State_1.State(__assign({}, state, { value: this.resolve(state.value), tree: this.getStateTree(state.value) }));
|
|
};
|
|
StateNode.prototype.transitionLeafNode = function (stateValue, state, eventObject) {
|
|
var stateNode = this.getStateNode(stateValue);
|
|
var next = stateNode.next(state, eventObject);
|
|
if (!next.tree) {
|
|
var _a = this.next(state, eventObject), actions = _a.actions, tree = _a.tree, transitions = _a.transitions, configuration = _a.configuration;
|
|
return {
|
|
tree: tree,
|
|
transitions: transitions,
|
|
configuration: configuration,
|
|
source: state,
|
|
actions: actions
|
|
};
|
|
}
|
|
return next;
|
|
};
|
|
StateNode.prototype.transitionCompoundNode = function (stateValue, state, eventObject) {
|
|
var subStateKeys = utils_1.keys(stateValue);
|
|
var stateNode = this.getStateNode(subStateKeys[0]);
|
|
var next = stateNode._transition(stateValue[subStateKeys[0]], state, eventObject);
|
|
if (!next.tree) {
|
|
var _a = this.next(state, eventObject), actions = _a.actions, tree = _a.tree, transitions = _a.transitions, configuration = _a.configuration;
|
|
return {
|
|
tree: tree,
|
|
transitions: transitions,
|
|
configuration: configuration,
|
|
source: state,
|
|
actions: actions
|
|
};
|
|
}
|
|
return next;
|
|
};
|
|
StateNode.prototype.transitionParallelNode = function (stateValue, state, eventObject) {
|
|
var e_1, _a;
|
|
var noTransitionKeys = [];
|
|
var transitionMap = {};
|
|
try {
|
|
for (var _b = __values(utils_1.keys(stateValue)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var subStateKey = _c.value;
|
|
var subStateValue = stateValue[subStateKey];
|
|
if (!subStateValue) {
|
|
continue;
|
|
}
|
|
var subStateNode = this.getStateNode(subStateKey);
|
|
var next = subStateNode._transition(subStateValue, state, eventObject);
|
|
if (!next.tree) {
|
|
noTransitionKeys.push(subStateKey);
|
|
}
|
|
transitionMap[subStateKey] = next;
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
var stateTransitions = utils_1.keys(transitionMap).map(function (key) { return transitionMap[key]; });
|
|
var enabledTransitions = utils_1.flatten(stateTransitions.map(function (st) { return st.transitions; }));
|
|
var willTransition = stateTransitions.some(function (transition) { return transition.tree !== undefined; });
|
|
if (!willTransition) {
|
|
var _d = this.next(state, eventObject), actions = _d.actions, tree = _d.tree, transitions = _d.transitions, _configuration = _d.configuration;
|
|
return {
|
|
tree: tree,
|
|
transitions: transitions,
|
|
configuration: _configuration,
|
|
source: state,
|
|
actions: actions
|
|
};
|
|
}
|
|
var targetNodes = utils_1.flatten(stateTransitions.map(function (st) { return st.configuration; }));
|
|
var prevNodes = this.getStateNodes(stateValue);
|
|
// console.log(targetNodes.map(t => t.id));
|
|
// console.log([...getConfiguration(prevNodes, targetNodes)].map(c => c.id));
|
|
var stateValueFromConfiguration = stateUtils_1.getValue(this.machine, stateUtils_1.getConfiguration(prevNodes, targetNodes));
|
|
// console.log(sv);
|
|
var combinedTree = new StateTree_1.StateTree(this.machine, stateValueFromConfiguration);
|
|
// const allTrees = keys(transitionMap)
|
|
// .map(key => transitionMap[key].tree)
|
|
// .filter(t => t !== undefined) as StateTree[];
|
|
// const combinedTree = allTrees.reduce((acc, t) => {
|
|
// return acc.combine(t);
|
|
// });
|
|
var allPaths = combinedTree.paths;
|
|
var configuration = utils_1.flatten(utils_1.keys(transitionMap).map(function (key) { return transitionMap[key].configuration; }));
|
|
// External transition that escapes orthogonal region
|
|
if (allPaths.length === 1 &&
|
|
!utils_2.matchesState(utils_1.toStateValue(this.path, this.delimiter), combinedTree.value)) {
|
|
return {
|
|
tree: combinedTree,
|
|
transitions: enabledTransitions,
|
|
configuration: configuration,
|
|
source: state,
|
|
actions: utils_1.flatten(utils_1.keys(transitionMap).map(function (key) {
|
|
return transitionMap[key].actions;
|
|
}))
|
|
};
|
|
}
|
|
// const allResolvedTrees = keys(transitionMap).map(key => {
|
|
// const { tree } = transitionMap[key];
|
|
// if (tree) {
|
|
// return tree;
|
|
// }
|
|
// const subValue = path(this.path)(state.value)[key];
|
|
// return new StateTree(this.getStateNode(key), subValue).absolute;
|
|
// });
|
|
// const finalCombinedTree = allResolvedTrees.reduce((acc, t) => {
|
|
// return acc.combine(t);
|
|
// });
|
|
return {
|
|
tree: combinedTree,
|
|
transitions: enabledTransitions,
|
|
configuration: configuration,
|
|
source: state,
|
|
actions: utils_1.flatten(utils_1.keys(transitionMap).map(function (key) {
|
|
return transitionMap[key].actions;
|
|
}))
|
|
};
|
|
};
|
|
StateNode.prototype._transition = function (stateValue, state, event) {
|
|
// leaf node
|
|
if (utils_1.isString(stateValue)) {
|
|
return this.transitionLeafNode(stateValue, state, event);
|
|
}
|
|
// hierarchical node
|
|
if (utils_1.keys(stateValue).length === 1) {
|
|
return this.transitionCompoundNode(stateValue, state, event);
|
|
}
|
|
// orthogonal node
|
|
return this.transitionParallelNode(stateValue, state, event);
|
|
};
|
|
StateNode.prototype.next = function (state, eventObject) {
|
|
var _this = this;
|
|
var e_2, _a;
|
|
var eventType = eventObject.type;
|
|
var candidates = this.on[eventType];
|
|
if (!candidates || !candidates.length) {
|
|
return {
|
|
tree: undefined,
|
|
transitions: [],
|
|
configuration: [],
|
|
source: state,
|
|
actions: []
|
|
};
|
|
}
|
|
var actions = this._transient
|
|
? [{ type: actionTypes.nullEvent }]
|
|
: [];
|
|
var nextStateStrings = [];
|
|
var selectedTransition;
|
|
try {
|
|
for (var candidates_1 = __values(candidates), candidates_1_1 = candidates_1.next(); !candidates_1_1.done; candidates_1_1 = candidates_1.next()) {
|
|
var candidate = candidates_1_1.value;
|
|
var cond = candidate.cond, stateIn = candidate.in;
|
|
var resolvedContext = state.context;
|
|
var isInState = stateIn
|
|
? utils_1.isString(stateIn) && isStateId(stateIn)
|
|
? // Check if in state by ID
|
|
state.matches(utils_1.toStateValue(this.getStateNodeById(stateIn).path, this.delimiter))
|
|
: // Check if in state by relative grandparent
|
|
utils_2.matchesState(utils_1.toStateValue(stateIn, this.delimiter), utils_1.path(this.path.slice(0, -2))(state.value))
|
|
: true;
|
|
var guardPassed = false;
|
|
try {
|
|
guardPassed =
|
|
!cond ||
|
|
this.evaluateGuard(cond, resolvedContext, eventObject, state);
|
|
}
|
|
catch (err) {
|
|
throw new Error("Unable to evaluate guard '" + (cond.name ||
|
|
cond
|
|
.type) + "' in transition for event '" + eventType + "' in state node '" + this.id + "':\n" + err.message);
|
|
}
|
|
if (guardPassed && isInState) {
|
|
if (candidate.target !== undefined) {
|
|
nextStateStrings = candidate.target;
|
|
}
|
|
actions.push.apply(actions, __spread(utils_1.toArray(candidate.actions)));
|
|
selectedTransition = candidate;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
if (!nextStateStrings.length) {
|
|
return {
|
|
tree: selectedTransition && state.value // targetless transition
|
|
? new StateTree_1.StateTree(this, utils_1.path(this.path)(state.value)).absolute
|
|
: undefined,
|
|
transitions: [selectedTransition],
|
|
configuration: selectedTransition && state.value ? [this] : [],
|
|
source: state,
|
|
actions: actions
|
|
};
|
|
}
|
|
var nextStateNodes = utils_1.flatten(nextStateStrings.map(function (str) {
|
|
if (str instanceof StateNode) {
|
|
return str; // TODO: fix anys
|
|
}
|
|
return _this.getRelativeStateNodes(str, state.historyValue);
|
|
}));
|
|
var isInternal = !!selectedTransition.internal;
|
|
var reentryNodes = isInternal
|
|
? []
|
|
: utils_1.flatten(nextStateNodes.map(function (n) { return _this.nodesFromChild(n); }));
|
|
var trees = nextStateNodes.map(function (stateNode) { return stateNode.tree; });
|
|
var combinedTree = trees.reduce(function (acc, t) {
|
|
return acc.combine(t);
|
|
});
|
|
reentryNodes.forEach(function (reentryNode) {
|
|
return combinedTree.addReentryNode(reentryNode);
|
|
});
|
|
return {
|
|
tree: combinedTree,
|
|
transitions: [selectedTransition],
|
|
configuration: nextStateNodes,
|
|
source: state,
|
|
actions: actions
|
|
};
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "tree", {
|
|
/**
|
|
* The state tree represented by this state node.
|
|
*/
|
|
get: function () {
|
|
var stateValue = utils_1.toStateValue(this.path, this.delimiter);
|
|
return new StateTree_1.StateTree(this.machine, stateValue);
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateNode.prototype.nodesFromChild = function (childStateNode) {
|
|
if (childStateNode.escapes(this)) {
|
|
return [];
|
|
}
|
|
var nodes = [];
|
|
var marker = childStateNode;
|
|
while (marker && marker !== this) {
|
|
nodes.push(marker);
|
|
marker = marker.parent;
|
|
}
|
|
nodes.push(this); // inclusive
|
|
return nodes;
|
|
};
|
|
StateNode.prototype.getStateTree = function (stateValue) {
|
|
return new StateTree_1.StateTree(this, stateValue);
|
|
};
|
|
/**
|
|
* Whether the given state node "escapes" this state node. If the `stateNode` is equal to or the parent of
|
|
* this state node, it does not escape.
|
|
*/
|
|
StateNode.prototype.escapes = function (stateNode) {
|
|
if (this === stateNode) {
|
|
return false;
|
|
}
|
|
var parent = this.parent;
|
|
while (parent) {
|
|
if (parent === stateNode) {
|
|
return false;
|
|
}
|
|
parent = parent.parent;
|
|
}
|
|
return true;
|
|
};
|
|
StateNode.prototype.evaluateGuard = function (guard, context, eventObject, state) {
|
|
var condFn;
|
|
var guards = this.machine.options.guards;
|
|
var guardMeta = {
|
|
state: state,
|
|
cond: guard
|
|
};
|
|
// TODO: do not hardcode!
|
|
if (guard.type === constants_1.DEFAULT_GUARD_TYPE) {
|
|
return guard.predicate(context, eventObject, guardMeta);
|
|
}
|
|
if (!guards[guard.type]) {
|
|
throw new Error("Guard '" + guard.type + "' is not implemented on machine '" + this.machine.id + "'.");
|
|
}
|
|
condFn = guards[guard.type];
|
|
return condFn(context, eventObject, guardMeta);
|
|
};
|
|
StateNode.prototype.getActions = function (transition, prevState) {
|
|
var entryExitStates = transition.tree
|
|
? transition.tree.resolved.getEntryExitStates(prevState ? this.getStateTree(prevState.value) : undefined)
|
|
: { entry: [], exit: [] };
|
|
var doneEvents = transition.tree
|
|
? transition.tree.getDoneEvents(new Set(entryExitStates.entry))
|
|
: [];
|
|
if (!transition.source) {
|
|
entryExitStates.exit = [];
|
|
// Ensure that root StateNode (machine) is entered
|
|
entryExitStates.entry.unshift(this);
|
|
}
|
|
var entryStates = new Set(entryExitStates.entry);
|
|
var exitStates = new Set(entryExitStates.exit);
|
|
var _a = __read([
|
|
utils_1.flatten(Array.from(entryStates).map(function (stateNode) {
|
|
return __spread(stateNode.activities.map(function (activity) { return actions_1.start(activity); }), stateNode.onEntry);
|
|
})).concat(doneEvents.map(actions_1.raise)),
|
|
utils_1.flatten(Array.from(exitStates).map(function (stateNode) { return __spread(stateNode.onExit, stateNode.activities.map(function (activity) { return actions_1.stop(activity); })); }))
|
|
], 2), entryActions = _a[0], exitActions = _a[1];
|
|
var actions = actions_1.toActionObjects(exitActions.concat(transition.actions).concat(entryActions), this.machine.options.actions);
|
|
return actions;
|
|
};
|
|
/**
|
|
* Determines the next state given the current `state` and sent `event`.
|
|
*
|
|
* @param state The current State instance or state value
|
|
* @param event The event that was sent at the current state
|
|
* @param context The current context (extended state) of the current state
|
|
*/
|
|
StateNode.prototype.transition = function (state, event, context) {
|
|
var currentState;
|
|
if (state instanceof State_1.State) {
|
|
currentState =
|
|
context === undefined
|
|
? state
|
|
: this.resolveState(State_1.State.from(state, context));
|
|
}
|
|
else {
|
|
var resolvedStateValue = utils_1.isString(state)
|
|
? this.resolve(utils_1.pathToStateValue(this.getResolvedPath(state)))
|
|
: this.resolve(state);
|
|
var resolvedContext = context ? context : this.machine.context;
|
|
currentState = this.resolveState(State_1.State.from(resolvedStateValue, resolvedContext));
|
|
}
|
|
var eventObject = actions_1.toEventObject(event);
|
|
var eventType = eventObject.type;
|
|
if (this.strict) {
|
|
if (this.events.indexOf(eventType) === -1 && !utils_1.isBuiltInEvent(eventType)) {
|
|
throw new Error("Machine '" + this.id + "' does not accept event '" + eventType + "'");
|
|
}
|
|
}
|
|
var stateTransition = this._transition(currentState.value, currentState, eventObject);
|
|
if (stateTransition.tree) {
|
|
stateTransition.tree = stateTransition.tree.resolved;
|
|
}
|
|
// const prevConfig = this.machine.getStateNodes(currentState.value);
|
|
// const cv = getValue(
|
|
// this.machine,
|
|
// getConfiguration(prevConfig, stateTransition.configuration)
|
|
// );
|
|
// if (stateTransition.tree) {
|
|
// const eq = stateValuesEqual(cv, stateTransition.tree.value);
|
|
// console.log(eq);
|
|
// }
|
|
// if (!eq) {
|
|
// console.log('prevConfig', prevConfig.map(c => c.id));
|
|
// console.log('config', [...stateTransition.configuration].map(c => c.id));
|
|
// console.log(cv, stateTransition.tree!.value);
|
|
// }
|
|
return this.resolveTransition(stateTransition, currentState, eventObject);
|
|
};
|
|
StateNode.prototype.resolveTransition = function (stateTransition, currentState, _eventObject) {
|
|
var _this = this;
|
|
var e_3, _a, _b;
|
|
var resolvedStateValue = stateTransition.tree
|
|
? stateTransition.tree.value
|
|
: undefined;
|
|
var historyValue = currentState
|
|
? currentState.historyValue
|
|
? currentState.historyValue
|
|
: stateTransition.source
|
|
? this.machine.historyValue(currentState.value)
|
|
: undefined
|
|
: undefined;
|
|
var currentContext = currentState
|
|
? currentState.context
|
|
: stateTransition.context || this.machine.context;
|
|
var eventObject = _eventObject || { type: types_1.ActionTypes.Init };
|
|
if (!environment_1.IS_PRODUCTION && stateTransition.tree) {
|
|
try {
|
|
this.ensureValidPaths(stateTransition.tree.paths); // TODO: ensure code coverage for this
|
|
}
|
|
catch (e) {
|
|
throw new Error("Event '" + (eventObject ? eventObject.type : 'none') + "' leads to an invalid configuration: " + e.message);
|
|
}
|
|
}
|
|
var actions = this.getActions(stateTransition, currentState);
|
|
var activities = currentState ? __assign({}, currentState.activities) : {};
|
|
try {
|
|
for (var actions_2 = __values(actions), actions_2_1 = actions_2.next(); !actions_2_1.done; actions_2_1 = actions_2.next()) {
|
|
var action = actions_2_1.value;
|
|
if (action.type === actionTypes.start) {
|
|
activities[action.activity.type] = action;
|
|
}
|
|
else if (action.type === actionTypes.stop) {
|
|
activities[action.activity.type] = false;
|
|
}
|
|
}
|
|
}
|
|
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
finally {
|
|
try {
|
|
if (actions_2_1 && !actions_2_1.done && (_a = actions_2.return)) _a.call(actions_2);
|
|
}
|
|
finally { if (e_3) throw e_3.error; }
|
|
}
|
|
var _c = __read(utils_1.partition(actions, function (action) {
|
|
return action.type === actionTypes.raise ||
|
|
action.type === actionTypes.nullEvent;
|
|
}), 2), raisedEvents = _c[0], otherActions = _c[1];
|
|
var _d = __read(utils_1.partition(otherActions, function (action) {
|
|
return action.type === actionTypes.assign;
|
|
}), 2), assignActions = _d[0], nonEventActions = _d[1];
|
|
var updatedContext = assignActions.length
|
|
? this.options.updater(currentContext, eventObject, assignActions)
|
|
: currentContext;
|
|
var resolvedActions = utils_1.flatten(nonEventActions.map(function (actionObject) {
|
|
if (actionObject.type === actionTypes.send) {
|
|
var sendAction = actions_1.resolveSend(actionObject, updatedContext, eventObject || { type: types_1.ActionTypes.Init }); // TODO: fix ActionTypes.Init
|
|
if (utils_1.isString(sendAction.delay)) {
|
|
if (!_this.machine.options.delays ||
|
|
_this.machine.options.delays[sendAction.delay] === undefined) {
|
|
if (!environment_1.IS_PRODUCTION) {
|
|
utils_1.warn(false,
|
|
// tslint:disable-next-line:max-line-length
|
|
"No delay reference for delay expression '" + sendAction.delay + "' was found on machine '" + _this.machine.id + "'");
|
|
}
|
|
// Do not send anything
|
|
return sendAction;
|
|
}
|
|
var delayExpr = _this.machine.options.delays[sendAction.delay];
|
|
sendAction.delay =
|
|
typeof delayExpr === 'number'
|
|
? delayExpr
|
|
: delayExpr(updatedContext, eventObject || { type: types_1.ActionTypes.Init });
|
|
}
|
|
return sendAction;
|
|
}
|
|
if (actionObject.type === types_1.ActionTypes.Pure) {
|
|
return (actionObject.get(updatedContext, eventObject) || []);
|
|
}
|
|
return actions_1.toActionObject(actionObject, _this.options.actions);
|
|
}));
|
|
var stateNodes = resolvedStateValue
|
|
? this.getStateNodes(resolvedStateValue)
|
|
: [];
|
|
var isTransient = stateNodes.some(function (stateNode) { return stateNode._transient; });
|
|
if (isTransient) {
|
|
raisedEvents.push({ type: actionTypes.nullEvent });
|
|
}
|
|
var meta = __spread([this], stateNodes).reduce(function (acc, stateNode) {
|
|
if (stateNode.meta !== undefined) {
|
|
acc[stateNode.id] = stateNode.meta;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
var nextState = new State_1.State({
|
|
value: resolvedStateValue || currentState.value,
|
|
context: updatedContext,
|
|
event: eventObject || actions_1.initEvent,
|
|
historyValue: resolvedStateValue
|
|
? historyValue
|
|
? utils_1.updateHistoryValue(historyValue, resolvedStateValue)
|
|
: undefined
|
|
: currentState
|
|
? currentState.historyValue
|
|
: undefined,
|
|
history: !resolvedStateValue || stateTransition.source
|
|
? currentState
|
|
: undefined,
|
|
actions: resolvedStateValue ? resolvedActions : [],
|
|
activities: resolvedStateValue
|
|
? activities
|
|
: currentState
|
|
? currentState.activities
|
|
: {},
|
|
meta: resolvedStateValue
|
|
? meta
|
|
: currentState
|
|
? currentState.meta
|
|
: undefined,
|
|
events: resolvedStateValue ? raisedEvents : [],
|
|
tree: resolvedStateValue
|
|
? stateTransition.tree
|
|
: currentState
|
|
? currentState.tree
|
|
: undefined
|
|
});
|
|
nextState.changed =
|
|
eventObject.type === actionTypes.update || !!assignActions.length;
|
|
// Dispose of penultimate histories to prevent memory leaks
|
|
var history = nextState.history;
|
|
if (history) {
|
|
delete history.history;
|
|
}
|
|
if (!resolvedStateValue) {
|
|
return nextState;
|
|
}
|
|
var maybeNextState = nextState;
|
|
while (raisedEvents.length) {
|
|
var currentActions = maybeNextState.actions;
|
|
var raisedEvent = raisedEvents.shift();
|
|
maybeNextState = this.transition(maybeNextState, raisedEvent.type === actionTypes.nullEvent
|
|
? NULL_EVENT
|
|
: raisedEvent.event, maybeNextState.context);
|
|
// Save original event to state
|
|
maybeNextState.event = eventObject;
|
|
(_b = maybeNextState.actions).unshift.apply(_b, __spread(currentActions));
|
|
}
|
|
// Detect if state changed
|
|
var changed = maybeNextState.changed ||
|
|
(history
|
|
? !!maybeNextState.actions.length ||
|
|
!!assignActions.length ||
|
|
typeof history.value !== typeof maybeNextState.value ||
|
|
!State_1.stateValuesEqual(maybeNextState.value, history.value)
|
|
: undefined);
|
|
maybeNextState.changed = changed;
|
|
// Preserve original history after raised events
|
|
maybeNextState.historyValue = nextState.historyValue;
|
|
maybeNextState.history = history;
|
|
return maybeNextState;
|
|
};
|
|
StateNode.prototype.ensureValidPaths = function (paths) {
|
|
var _this = this;
|
|
var e_4, _a;
|
|
if (!environment_1.IS_PRODUCTION) {
|
|
var visitedParents = new Map();
|
|
var stateNodes = utils_1.flatten(paths.map(function (_path) { return _this.getRelativeStateNodes(_path); }));
|
|
try {
|
|
outer: for (var stateNodes_1 = __values(stateNodes), stateNodes_1_1 = stateNodes_1.next(); !stateNodes_1_1.done; stateNodes_1_1 = stateNodes_1.next()) {
|
|
var stateNode = stateNodes_1_1.value;
|
|
var marker = stateNode;
|
|
while (marker.parent) {
|
|
if (visitedParents.has(marker.parent)) {
|
|
if (marker.parent.type === 'parallel') {
|
|
continue outer;
|
|
}
|
|
throw new Error("State node '" + stateNode.id + "' shares parent '" + marker.parent.id + "' with state node '" + visitedParents
|
|
.get(marker.parent)
|
|
.map(function (a) { return a.id; }) + "'");
|
|
}
|
|
if (!visitedParents.get(marker.parent)) {
|
|
visitedParents.set(marker.parent, [stateNode]);
|
|
}
|
|
else {
|
|
visitedParents.get(marker.parent).push(stateNode);
|
|
}
|
|
marker = marker.parent;
|
|
}
|
|
}
|
|
}
|
|
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
finally {
|
|
try {
|
|
if (stateNodes_1_1 && !stateNodes_1_1.done && (_a = stateNodes_1.return)) _a.call(stateNodes_1);
|
|
}
|
|
finally { if (e_4) throw e_4.error; }
|
|
}
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
};
|
|
/**
|
|
* Returns the child state node from its relative `stateKey`, or throws.
|
|
*/
|
|
StateNode.prototype.getStateNode = function (stateKey) {
|
|
if (isStateId(stateKey)) {
|
|
return this.machine.getStateNodeById(stateKey);
|
|
}
|
|
if (!this.states) {
|
|
throw new Error("Unable to retrieve child state '" + stateKey + "' from '" + this.id + "'; no child states exist.");
|
|
}
|
|
var result = this.states[stateKey];
|
|
if (!result) {
|
|
throw new Error("Child state '" + stateKey + "' does not exist on '" + this.id + "'");
|
|
}
|
|
return result;
|
|
};
|
|
/**
|
|
* Returns the state node with the given `stateId`, or throws.
|
|
*
|
|
* @param stateId The state ID. The prefix "#" is removed.
|
|
*/
|
|
StateNode.prototype.getStateNodeById = function (stateId) {
|
|
var resolvedStateId = isStateId(stateId)
|
|
? stateId.slice(STATE_IDENTIFIER.length)
|
|
: stateId;
|
|
if (resolvedStateId === this.id) {
|
|
return this;
|
|
}
|
|
var stateNode = this.machine.idMap[resolvedStateId];
|
|
if (!stateNode) {
|
|
throw new Error("Child state node '#" + resolvedStateId + "' does not exist on machine '" + this.id + "'");
|
|
}
|
|
return stateNode;
|
|
};
|
|
/**
|
|
* Returns the relative state node from the given `statePath`, or throws.
|
|
*
|
|
* @param statePath The string or string array relative path to the state node.
|
|
*/
|
|
StateNode.prototype.getStateNodeByPath = function (statePath) {
|
|
if (typeof statePath === 'string' && isStateId(statePath)) {
|
|
try {
|
|
return this.getStateNodeById(statePath.slice(1));
|
|
}
|
|
catch (e) {
|
|
// try individual paths
|
|
// throw e;
|
|
}
|
|
}
|
|
var arrayStatePath = utils_1.toStatePath(statePath, this.delimiter).slice();
|
|
var currentStateNode = this;
|
|
while (arrayStatePath.length) {
|
|
var key = arrayStatePath.shift();
|
|
if (!key.length) {
|
|
break;
|
|
}
|
|
currentStateNode = currentStateNode.getStateNode(key);
|
|
}
|
|
return currentStateNode;
|
|
};
|
|
/**
|
|
* Resolves a partial state value with its full representation in this machine.
|
|
*
|
|
* @param stateValue The partial state value to resolve.
|
|
*/
|
|
StateNode.prototype.resolve = function (stateValue) {
|
|
var _this = this;
|
|
var _a;
|
|
if (!stateValue) {
|
|
return this.initialStateValue || EMPTY_OBJECT; // TODO: type-specific properties
|
|
}
|
|
switch (this.type) {
|
|
case 'parallel':
|
|
return utils_1.mapValues(this.initialStateValue, function (subStateValue, subStateKey) {
|
|
return subStateValue
|
|
? _this.getStateNode(subStateKey).resolve(stateValue[subStateKey] || subStateValue)
|
|
: EMPTY_OBJECT;
|
|
});
|
|
case 'compound':
|
|
if (utils_1.isString(stateValue)) {
|
|
var subStateNode = this.getStateNode(stateValue);
|
|
if (subStateNode.type === 'parallel' ||
|
|
subStateNode.type === 'compound') {
|
|
return _a = {}, _a[stateValue] = subStateNode.initialStateValue, _a;
|
|
}
|
|
return stateValue;
|
|
}
|
|
if (!utils_1.keys(stateValue).length) {
|
|
return this.initialStateValue || {};
|
|
}
|
|
return utils_1.mapValues(stateValue, function (subStateValue, subStateKey) {
|
|
return subStateValue
|
|
? _this.getStateNode(subStateKey).resolve(subStateValue)
|
|
: EMPTY_OBJECT;
|
|
});
|
|
default:
|
|
return stateValue || EMPTY_OBJECT;
|
|
}
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "resolvedStateValue", {
|
|
get: function () {
|
|
var _a, _b;
|
|
var key = this.key;
|
|
if (this.type === 'parallel') {
|
|
return _a = {},
|
|
_a[key] = utils_1.mapFilterValues(this.states, function (stateNode) { return stateNode.resolvedStateValue[stateNode.key]; }, function (stateNode) { return !(stateNode.type === 'history'); }),
|
|
_a;
|
|
}
|
|
if (this.initial === undefined) {
|
|
// If leaf node, value is just the state node's key
|
|
return key;
|
|
}
|
|
if (!this.states[this.initial]) {
|
|
throw new Error("Initial state '" + this.initial + "' not found on '" + key + "'");
|
|
}
|
|
return _b = {},
|
|
_b[key] = this.states[this.initial].resolvedStateValue,
|
|
_b;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateNode.prototype.getResolvedPath = function (stateIdentifier) {
|
|
if (isStateId(stateIdentifier)) {
|
|
var stateNode = this.machine.idMap[stateIdentifier.slice(STATE_IDENTIFIER.length)];
|
|
if (!stateNode) {
|
|
throw new Error("Unable to find state node '" + stateIdentifier + "'");
|
|
}
|
|
return stateNode.path;
|
|
}
|
|
return utils_1.toStatePath(stateIdentifier, this.delimiter);
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "initialStateValue", {
|
|
get: function () {
|
|
if (this.__cache.initialStateValue) {
|
|
return this.__cache.initialStateValue;
|
|
}
|
|
var initialStateValue = (this.type === 'parallel'
|
|
? utils_1.mapFilterValues(this.states, function (state) { return state.initialStateValue || EMPTY_OBJECT; }, function (stateNode) { return !(stateNode.type === 'history'); })
|
|
: utils_1.isString(this.resolvedStateValue)
|
|
? undefined
|
|
: this.resolvedStateValue[this.key]);
|
|
this.__cache.initialStateValue = initialStateValue;
|
|
return this.__cache.initialStateValue;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateNode.prototype.getInitialState = function (stateValue, context) {
|
|
if (context === void 0) { context = this.machine.context; }
|
|
var tree = this.getStateTree(stateValue);
|
|
var configuration = this.getStateNodes(stateValue);
|
|
configuration.forEach(function (stateNode) {
|
|
tree.addReentryNode(stateNode);
|
|
});
|
|
return this.resolveTransition({
|
|
tree: tree,
|
|
configuration: configuration,
|
|
transitions: [],
|
|
source: undefined,
|
|
actions: [],
|
|
context: context
|
|
});
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "initialState", {
|
|
/**
|
|
* The initial State instance, which includes all actions to be executed from
|
|
* entering the initial state.
|
|
*/
|
|
get: function () {
|
|
if (this.__cache.initialState) {
|
|
return this.__cache.initialState;
|
|
}
|
|
var initialStateValue = this.initialStateValue;
|
|
if (!initialStateValue) {
|
|
throw new Error("Cannot retrieve initial state from simple state '" + this.id + "'.");
|
|
}
|
|
this.__cache.initialState = this.getInitialState(initialStateValue);
|
|
return this.__cache.initialState;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateNode.prototype, "target", {
|
|
/**
|
|
* The target state value of the history state node, if it exists. This represents the
|
|
* default state value to transition to if no history value exists yet.
|
|
*/
|
|
get: function () {
|
|
var target;
|
|
if (this.type === 'history') {
|
|
var historyConfig = this.config;
|
|
if (historyConfig.target && utils_1.isString(historyConfig.target)) {
|
|
target = isStateId(historyConfig.target)
|
|
? utils_1.pathToStateValue(this.machine
|
|
.getStateNodeById(historyConfig.target)
|
|
.path.slice(this.path.length - 1))
|
|
: historyConfig.target;
|
|
}
|
|
else {
|
|
target = historyConfig.target;
|
|
}
|
|
}
|
|
return target;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateNode.prototype.getStates = function (stateValue) {
|
|
var e_5, _a;
|
|
if (utils_1.isString(stateValue)) {
|
|
return [this.states[stateValue]];
|
|
}
|
|
var stateNodes = [];
|
|
try {
|
|
for (var _b = __values(utils_1.keys(stateValue)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var key = _c.value;
|
|
stateNodes.push.apply(stateNodes, __spread(this.states[key].getStates(stateValue[key])));
|
|
}
|
|
}
|
|
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_5) throw e_5.error; }
|
|
}
|
|
return stateNodes;
|
|
};
|
|
/**
|
|
* Returns the leaf nodes from a state path relative to this state node.
|
|
*
|
|
* @param relativeStateId The relative state path to retrieve the state nodes
|
|
* @param history The previous state to retrieve history
|
|
* @param resolve Whether state nodes should resolve to initial child state nodes
|
|
*/
|
|
StateNode.prototype.getRelativeStateNodes = function (relativeStateId, historyValue, resolve) {
|
|
if (resolve === void 0) { resolve = true; }
|
|
if (utils_1.isString(relativeStateId) && isStateId(relativeStateId)) {
|
|
var unresolvedStateNode = this.getStateNodeById(relativeStateId);
|
|
return resolve
|
|
? unresolvedStateNode.type === 'history'
|
|
? unresolvedStateNode.resolveHistory(historyValue)
|
|
: unresolvedStateNode.initialStateNodes
|
|
: [unresolvedStateNode];
|
|
}
|
|
var statePath = utils_1.toStatePath(relativeStateId, this.delimiter);
|
|
var rootStateNode = this.parent || this;
|
|
var unresolvedStateNodes = rootStateNode.getFromRelativePath(statePath, historyValue);
|
|
if (!resolve) {
|
|
return unresolvedStateNodes;
|
|
}
|
|
return utils_1.flatten(unresolvedStateNodes.map(function (stateNode) { return stateNode.initialStateNodes; }));
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "initialStateNodes", {
|
|
get: function () {
|
|
var _this = this;
|
|
if (this.type === 'atomic' || this.type === 'final') {
|
|
return [this];
|
|
}
|
|
// Case when state node is compound but no initial state is defined
|
|
if (this.type === 'compound' && !this.initial) {
|
|
if (!environment_1.IS_PRODUCTION) {
|
|
utils_1.warn(false, "Compound state node '" + this.id + "' has no initial state.");
|
|
}
|
|
return [this];
|
|
}
|
|
var initialStateNodePaths = utils_1.toStatePaths(this.initialStateValue);
|
|
return utils_1.flatten(initialStateNodePaths.map(function (initialPath) {
|
|
return _this.getFromRelativePath(initialPath);
|
|
}));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
/**
|
|
* Retrieves state nodes from a relative path to this state node.
|
|
*
|
|
* @param relativePath The relative path from this state node
|
|
* @param historyValue
|
|
*/
|
|
StateNode.prototype.getFromRelativePath = function (relativePath, historyValue) {
|
|
if (!relativePath.length) {
|
|
return [this];
|
|
}
|
|
var _a = __read(relativePath), stateKey = _a[0], childStatePath = _a.slice(1);
|
|
if (!this.states) {
|
|
throw new Error("Cannot retrieve subPath '" + stateKey + "' from node with no states");
|
|
}
|
|
var childStateNode = this.getStateNode(stateKey);
|
|
if (childStateNode.type === 'history') {
|
|
return childStateNode.resolveHistory(historyValue);
|
|
}
|
|
if (!this.states[stateKey]) {
|
|
throw new Error("Child state '" + stateKey + "' does not exist on '" + this.id + "'");
|
|
}
|
|
return this.states[stateKey].getFromRelativePath(childStatePath, historyValue);
|
|
};
|
|
StateNode.prototype.historyValue = function (relativeStateValue) {
|
|
if (!utils_1.keys(this.states).length) {
|
|
return undefined;
|
|
}
|
|
return {
|
|
current: relativeStateValue || this.initialStateValue,
|
|
states: utils_1.mapFilterValues(this.states, function (stateNode, key) {
|
|
if (!relativeStateValue) {
|
|
return stateNode.historyValue();
|
|
}
|
|
var subStateValue = utils_1.isString(relativeStateValue)
|
|
? undefined
|
|
: relativeStateValue[key];
|
|
return stateNode.historyValue(subStateValue || stateNode.initialStateValue);
|
|
}, function (stateNode) { return !stateNode.history; })
|
|
};
|
|
};
|
|
/**
|
|
* Resolves to the historical value(s) of the parent state node,
|
|
* represented by state nodes.
|
|
*
|
|
* @param historyValue
|
|
*/
|
|
StateNode.prototype.resolveHistory = function (historyValue) {
|
|
var _this = this;
|
|
if (this.type !== 'history') {
|
|
return [this];
|
|
}
|
|
var parent = this.parent;
|
|
if (!historyValue) {
|
|
return this.target
|
|
? utils_1.flatten(utils_1.toStatePaths(this.target).map(function (relativeChildPath) {
|
|
return parent.getFromRelativePath(relativeChildPath);
|
|
}))
|
|
: parent.initialStateNodes;
|
|
}
|
|
var subHistoryValue = utils_1.nestedPath(parent.path, 'states')(historyValue).current;
|
|
if (utils_1.isString(subHistoryValue)) {
|
|
return [parent.getStateNode(subHistoryValue)];
|
|
}
|
|
return utils_1.flatten(utils_1.toStatePaths(subHistoryValue).map(function (subStatePath) {
|
|
return _this.history === 'deep'
|
|
? parent.getFromRelativePath(subStatePath)
|
|
: [parent.states[subStatePath[0]]];
|
|
}));
|
|
};
|
|
Object.defineProperty(StateNode.prototype, "stateIds", {
|
|
/**
|
|
* All the state node IDs of this state node and its descendant state nodes.
|
|
*/
|
|
get: function () {
|
|
var _this = this;
|
|
var childStateIds = utils_1.flatten(utils_1.keys(this.states).map(function (stateKey) {
|
|
return _this.states[stateKey].stateIds;
|
|
}));
|
|
return [this.id].concat(childStateIds);
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateNode.prototype, "events", {
|
|
/**
|
|
* All the event types accepted by this state node and its descendants.
|
|
*/
|
|
get: function () {
|
|
var e_6, _a, e_7, _b;
|
|
if (this.__cache.events) {
|
|
return this.__cache.events;
|
|
}
|
|
var states = this.states;
|
|
var events = new Set(this.ownEvents);
|
|
if (states) {
|
|
try {
|
|
for (var _c = __values(utils_1.keys(states)), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
var stateId = _d.value;
|
|
var state = states[stateId];
|
|
if (state.states) {
|
|
try {
|
|
for (var _e = __values(state.events), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
var event_1 = _f.value;
|
|
events.add("" + event_1);
|
|
}
|
|
}
|
|
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
finally {
|
|
try {
|
|
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
|
}
|
|
finally { if (e_7) throw e_7.error; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
finally {
|
|
try {
|
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
}
|
|
finally { if (e_6) throw e_6.error; }
|
|
}
|
|
}
|
|
return (this.__cache.events = Array.from(events));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateNode.prototype, "ownEvents", {
|
|
/**
|
|
* All the events that have transitions directly from this state node.
|
|
*
|
|
* Excludes any inert events.
|
|
*/
|
|
get: function () {
|
|
var _this = this;
|
|
var events = new Set(utils_1.keys(this.on).filter(function (key) {
|
|
var transitions = _this.on[key];
|
|
return transitions.some(function (transition) {
|
|
return !(!transition.target &&
|
|
!transition.actions.length &&
|
|
transition.internal);
|
|
});
|
|
}));
|
|
return Array.from(events);
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateNode.prototype.formatTransition = function (target, transitionConfig, event) {
|
|
var _this = this;
|
|
var internal = transitionConfig ? transitionConfig.internal : undefined;
|
|
var targets = utils_1.toArray(target);
|
|
var guards = this.machine.options.guards;
|
|
// Format targets to their full string path
|
|
var formattedTargets = targets.map(function (_target) {
|
|
if (!utils_1.isString(_target)) {
|
|
return "#" + _target.id;
|
|
}
|
|
var isInternalTarget = _target[0] === _this.delimiter;
|
|
internal = internal === undefined ? isInternalTarget : internal;
|
|
// If internal target is defined on machine,
|
|
// do not include machine key on target
|
|
if (isInternalTarget && !_this.parent) {
|
|
return "#" + _this.getStateNodeByPath(_target.slice(1)).id;
|
|
}
|
|
var resolvedTarget = isInternalTarget
|
|
? _this.key + _target
|
|
: "" + _target;
|
|
if (_this.parent) {
|
|
try {
|
|
var targetStateNode = _this.parent.getStateNodeByPath(resolvedTarget);
|
|
return "#" + targetStateNode.id;
|
|
}
|
|
catch (err) {
|
|
throw new Error("Invalid transition for state node '" + _this.id + "' on event '" + event + "':\n" + err.message);
|
|
}
|
|
}
|
|
else {
|
|
return "#" + _this.getStateNodeByPath(resolvedTarget).id;
|
|
}
|
|
});
|
|
if (transitionConfig === undefined) {
|
|
return {
|
|
target: target === undefined ? undefined : formattedTargets,
|
|
source: this,
|
|
actions: [],
|
|
internal: target === undefined || internal,
|
|
event: event
|
|
};
|
|
}
|
|
// Check if there is no target (targetless)
|
|
// An undefined transition signals that the state node should not transition from that event.
|
|
var isTargetless = target === undefined || target === TARGETLESS_KEY;
|
|
return __assign({}, transitionConfig, { actions: actions_1.toActionObjects(utils_1.toArray(transitionConfig.actions)), cond: utils_1.toGuard(transitionConfig.cond, guards), target: isTargetless ? undefined : formattedTargets, source: this, internal: (isTargetless && internal === undefined) || internal, event: event });
|
|
};
|
|
StateNode.prototype.formatTransitions = function () {
|
|
var _this = this;
|
|
var _a, e_8, _b;
|
|
var onConfig = this.config.on || EMPTY_OBJECT;
|
|
var doneConfig = this.config.onDone
|
|
? (_a = {},
|
|
_a["" + actions_1.done(this.id)] = this.config.onDone,
|
|
_a) : undefined;
|
|
var invokeConfig = this.invoke.reduce(function (acc, invokeDef) {
|
|
if (invokeDef.onDone) {
|
|
acc[actions_1.doneInvoke(invokeDef.id)] = invokeDef.onDone;
|
|
}
|
|
if (invokeDef.onError) {
|
|
acc[actions_1.error(invokeDef.id)] = invokeDef.onError;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
var delayedTransitions = this.after;
|
|
var formattedTransitions = utils_1.mapValues(__assign({}, onConfig, doneConfig, invokeConfig), function (value, event) {
|
|
var e_9, _a;
|
|
if (value === undefined) {
|
|
return [{ target: undefined, event: event, actions: [], internal: true }];
|
|
}
|
|
if (utils_1.isArray(value)) {
|
|
return value.map(function (targetTransitionConfig) {
|
|
return _this.formatTransition(targetTransitionConfig.target, targetTransitionConfig, event);
|
|
});
|
|
}
|
|
if (utils_1.isString(value) || utils_1.isMachine(value)) {
|
|
return [_this.formatTransition([value], undefined, event)];
|
|
}
|
|
if (!environment_1.IS_PRODUCTION) {
|
|
try {
|
|
for (var _b = __values(utils_1.keys(value)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
var key = _c.value;
|
|
if (['target', 'actions', 'internal', 'in', 'cond', 'event'].indexOf(key) === -1) {
|
|
throw new Error(
|
|
// tslint:disable-next-line:max-line-length
|
|
"State object mapping of transitions is deprecated. Check the config for event '" + event + "' on state '" + _this.id + "'.");
|
|
}
|
|
}
|
|
}
|
|
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
finally {
|
|
try {
|
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
}
|
|
finally { if (e_9) throw e_9.error; }
|
|
}
|
|
}
|
|
return [
|
|
_this.formatTransition(value.target, value, event)
|
|
];
|
|
});
|
|
try {
|
|
for (var delayedTransitions_1 = __values(delayedTransitions), delayedTransitions_1_1 = delayedTransitions_1.next(); !delayedTransitions_1_1.done; delayedTransitions_1_1 = delayedTransitions_1.next()) {
|
|
var delayedTransition = delayedTransitions_1_1.value;
|
|
formattedTransitions[delayedTransition.event] =
|
|
formattedTransitions[delayedTransition.event] || [];
|
|
formattedTransitions[delayedTransition.event].push(delayedTransition);
|
|
}
|
|
}
|
|
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
finally {
|
|
try {
|
|
if (delayedTransitions_1_1 && !delayedTransitions_1_1.done && (_b = delayedTransitions_1.return)) _b.call(delayedTransitions_1);
|
|
}
|
|
finally { if (e_8) throw e_8.error; }
|
|
}
|
|
return formattedTransitions;
|
|
};
|
|
return StateNode;
|
|
}());
|
|
exports.StateNode = StateNode;
|
|
//# sourceMappingURL=StateNode.js.map
|