385 lines
15 KiB
JavaScript
385 lines
15 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 __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 utils_2 = require("./utils");
|
|
var actions_1 = require("./actions");
|
|
var defaultStateTreeOptions = {
|
|
resolved: false
|
|
};
|
|
var StateTree = /** @class */ (function () {
|
|
function StateTree(stateNode, stateValue, options, parent) {
|
|
var _this = this;
|
|
var _a;
|
|
if (options === void 0) { options = defaultStateTreeOptions; }
|
|
this.stateNode = stateNode;
|
|
this.stateValue = stateValue;
|
|
this.parent = parent;
|
|
this.reentryNodes = new Set();
|
|
this.root = this.parent ? this.parent.root : this;
|
|
this.nodes = stateValue
|
|
? utils_1.isString(stateValue)
|
|
? (_a = {},
|
|
_a[stateValue] = new StateTree(stateNode.getStateNode(stateValue), undefined, undefined, this),
|
|
_a) : utils_1.mapValues(stateValue, function (subValue, key) {
|
|
return new StateTree(stateNode.getStateNode(key), subValue, undefined, _this);
|
|
})
|
|
: {};
|
|
var resolvedOptions = __assign({}, defaultStateTreeOptions, options);
|
|
this.isResolved = resolvedOptions.resolved;
|
|
}
|
|
Object.defineProperty(StateTree.prototype, "done", {
|
|
get: function () {
|
|
var _this = this;
|
|
switch (this.stateNode.type) {
|
|
case 'final':
|
|
return true;
|
|
case 'compound':
|
|
var childTree = this.nodes[utils_1.keys(this.nodes)[0]];
|
|
return childTree.stateNode.type === 'final';
|
|
case 'parallel':
|
|
return utils_1.keys(this.nodes).every(function (key) { return _this.nodes[key].done; });
|
|
default:
|
|
return false;
|
|
}
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateTree.prototype.getDoneData = function (context, event) {
|
|
if (!this.done) {
|
|
return undefined;
|
|
}
|
|
if (this.stateNode.type === 'compound') {
|
|
var childTree = this.nodes[utils_1.keys(this.nodes)[0]];
|
|
if (!childTree.stateNode.data) {
|
|
return undefined;
|
|
}
|
|
return utils_1.mapContext(childTree.stateNode.data, context, event);
|
|
}
|
|
return undefined;
|
|
};
|
|
Object.defineProperty(StateTree.prototype, "atomicNodes", {
|
|
get: function () {
|
|
var _this = this;
|
|
if (this.stateNode.type === 'atomic' || this.stateNode.type === 'final') {
|
|
return [this.stateNode];
|
|
}
|
|
return utils_1.flatten(utils_1.keys(this.value).map(function (key) {
|
|
return _this.value[key].atomicNodes;
|
|
}));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateTree.prototype.getDoneEvents = function (entryStateNodes) {
|
|
var _this = this;
|
|
// If no state nodes are being entered, no done events will be fired
|
|
if (!entryStateNodes || !entryStateNodes.size) {
|
|
return [];
|
|
}
|
|
if (entryStateNodes.has(this.stateNode) &&
|
|
this.stateNode.type === 'final') {
|
|
return [actions_1.done(this.stateNode.id, this.stateNode.data)];
|
|
}
|
|
var childDoneEvents = utils_1.flatten(utils_1.keys(this.nodes).map(function (key) {
|
|
return _this.nodes[key].getDoneEvents(entryStateNodes);
|
|
}));
|
|
if (this.stateNode.type === 'parallel') {
|
|
var allChildrenDone = utils_1.keys(this.nodes).every(function (key) { return _this.nodes[key].done; });
|
|
if (childDoneEvents && allChildrenDone) {
|
|
return childDoneEvents.concat(actions_1.done(this.stateNode.id));
|
|
}
|
|
else {
|
|
return childDoneEvents;
|
|
}
|
|
}
|
|
if (!this.done || !childDoneEvents.length) {
|
|
return childDoneEvents;
|
|
}
|
|
// TODO: handle merging strategy
|
|
// For compound state nodes with final child state, there should be only
|
|
// one done.state event (potentially with data).
|
|
var doneData = childDoneEvents.length === 1 ? childDoneEvents[0].data : undefined;
|
|
return childDoneEvents.concat(actions_1.done(this.stateNode.id, doneData));
|
|
};
|
|
Object.defineProperty(StateTree.prototype, "resolved", {
|
|
get: function () {
|
|
var newStateTree = new StateTree(this.stateNode, this.stateNode.resolve(this.value), {
|
|
resolved: true
|
|
});
|
|
newStateTree.reentryNodes = this.reentryNodes;
|
|
return newStateTree;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateTree.prototype, "paths", {
|
|
get: function () {
|
|
return utils_1.toStatePaths(this.value);
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateTree.prototype, "absolute", {
|
|
get: function () {
|
|
var _stateValue = this.stateValue;
|
|
var absoluteStateValue = {};
|
|
var marker = absoluteStateValue;
|
|
for (var i = 0; i < this.stateNode.path.length; i++) {
|
|
var key = this.stateNode.path[i];
|
|
if (i === this.stateNode.path.length - 1) {
|
|
marker[key] = _stateValue;
|
|
}
|
|
else {
|
|
marker[key] = {};
|
|
marker = marker[key];
|
|
}
|
|
}
|
|
var newStateTree = new StateTree(this.stateNode.machine, absoluteStateValue);
|
|
newStateTree.reentryNodes = this.reentryNodes;
|
|
return newStateTree;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
Object.defineProperty(StateTree.prototype, "nextEvents", {
|
|
get: function () {
|
|
var _this = this;
|
|
var ownEvents = this.stateNode.ownEvents;
|
|
var childEvents = utils_1.flatten(utils_1.keys(this.nodes).map(function (key) {
|
|
var subTree = _this.nodes[key];
|
|
return subTree.nextEvents;
|
|
}));
|
|
return __spread(new Set(childEvents.concat(ownEvents)));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateTree.prototype.clone = function () {
|
|
var newStateTree = new StateTree(this.stateNode, this.value, undefined, this.parent);
|
|
return newStateTree;
|
|
};
|
|
StateTree.prototype.combine = function (tree) {
|
|
var _a, e_1, _b;
|
|
if (tree.stateNode !== this.stateNode) {
|
|
throw new Error('Cannot combine distinct trees');
|
|
}
|
|
var newTree = this.clone();
|
|
tree.root.reentryNodes.forEach(function (reentryNode) {
|
|
newTree.root.addReentryNode(reentryNode);
|
|
});
|
|
if (this.stateNode.type === 'compound') {
|
|
// Only combine if no child state is defined
|
|
var newValue = void 0;
|
|
if (!utils_1.keys(this.nodes).length || !utils_1.keys(tree.nodes).length) {
|
|
newValue = Object.assign({}, this.nodes, tree.nodes);
|
|
newTree.nodes = newValue;
|
|
return newTree;
|
|
}
|
|
else {
|
|
var childKey = utils_1.keys(this.nodes)[0];
|
|
newValue = (_a = {},
|
|
_a[childKey] = this.nodes[childKey].combine(tree.nodes[childKey]),
|
|
_a);
|
|
newTree.nodes = newValue;
|
|
return newTree;
|
|
}
|
|
}
|
|
if (this.stateNode.type === 'parallel') {
|
|
var valueKeys = new Set(__spread(utils_1.keys(this.nodes), utils_1.keys(tree.nodes)));
|
|
var newValue = {};
|
|
try {
|
|
for (var valueKeys_1 = __values(valueKeys), valueKeys_1_1 = valueKeys_1.next(); !valueKeys_1_1.done; valueKeys_1_1 = valueKeys_1.next()) {
|
|
var key = valueKeys_1_1.value;
|
|
if (!this.nodes[key] || !tree.nodes[key]) {
|
|
newValue[key] = this.nodes[key] || tree.nodes[key];
|
|
}
|
|
else {
|
|
newValue[key] = this.nodes[key].combine(tree.nodes[key]);
|
|
}
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (valueKeys_1_1 && !valueKeys_1_1.done && (_b = valueKeys_1.return)) _b.call(valueKeys_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
newTree.nodes = newValue;
|
|
return newTree;
|
|
}
|
|
// nothing to do
|
|
return this;
|
|
};
|
|
Object.defineProperty(StateTree.prototype, "value", {
|
|
get: function () {
|
|
if (this.stateNode.type === 'atomic' || this.stateNode.type === 'final') {
|
|
return {};
|
|
}
|
|
if (this.stateNode.type === 'parallel') {
|
|
return utils_1.mapValues(this.nodes, function (st) {
|
|
return st.value;
|
|
});
|
|
}
|
|
if (this.stateNode.type === 'compound') {
|
|
if (utils_1.keys(this.nodes).length === 0) {
|
|
return {};
|
|
}
|
|
var childStateNode = this.nodes[utils_1.keys(this.nodes)[0]].stateNode;
|
|
if (childStateNode.type === 'atomic' || childStateNode.type === 'final') {
|
|
return childStateNode.key;
|
|
}
|
|
return utils_1.mapValues(this.nodes, function (st) {
|
|
return st.value;
|
|
});
|
|
}
|
|
return {};
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
StateTree.prototype.matches = function (parentValue) {
|
|
return utils_2.matchesState(parentValue, this.value);
|
|
};
|
|
StateTree.prototype.getEntryExitStates = function (prevTree) {
|
|
var _this = this;
|
|
var e_2, _a;
|
|
var externalNodes = this.root.reentryNodes;
|
|
if (!prevTree) {
|
|
// Initial state
|
|
return {
|
|
exit: [],
|
|
entry: __spread(externalNodes)
|
|
};
|
|
}
|
|
if (prevTree.stateNode !== this.stateNode) {
|
|
throw new Error('Cannot compare distinct trees');
|
|
}
|
|
switch (this.stateNode.type) {
|
|
case 'compound':
|
|
var compoundResult = {
|
|
exit: [],
|
|
entry: []
|
|
};
|
|
var currentChildKey = utils_1.keys(this.nodes)[0];
|
|
var prevChildKey = utils_1.keys(prevTree.nodes)[0];
|
|
if (currentChildKey !== prevChildKey) {
|
|
compoundResult.exit = prevTree.nodes[prevChildKey].getExitStates();
|
|
compoundResult.entry = this.nodes[currentChildKey].getEntryStates();
|
|
}
|
|
else {
|
|
compoundResult = this.nodes[currentChildKey].getEntryExitStates(prevTree.nodes[prevChildKey]);
|
|
}
|
|
if (externalNodes && externalNodes.has(this.stateNode)) {
|
|
compoundResult.exit.push(this.stateNode);
|
|
compoundResult.entry.unshift(this.stateNode);
|
|
}
|
|
return compoundResult;
|
|
case 'parallel':
|
|
var all = utils_1.keys(this.nodes).map(function (key) {
|
|
return _this.nodes[key].getEntryExitStates(prevTree.nodes[key]);
|
|
});
|
|
var parallelResult = {
|
|
exit: [],
|
|
entry: []
|
|
};
|
|
try {
|
|
for (var all_1 = __values(all), all_1_1 = all_1.next(); !all_1_1.done; all_1_1 = all_1.next()) {
|
|
var ees = all_1_1.value;
|
|
parallelResult.exit = __spread(parallelResult.exit, ees.exit);
|
|
parallelResult.entry = __spread(parallelResult.entry, ees.entry);
|
|
}
|
|
}
|
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
finally {
|
|
try {
|
|
if (all_1_1 && !all_1_1.done && (_a = all_1.return)) _a.call(all_1);
|
|
}
|
|
finally { if (e_2) throw e_2.error; }
|
|
}
|
|
if (externalNodes && externalNodes.has(this.stateNode)) {
|
|
parallelResult.exit.push(this.stateNode);
|
|
parallelResult.entry.unshift(this.stateNode);
|
|
}
|
|
return parallelResult;
|
|
case 'atomic':
|
|
default:
|
|
if (externalNodes && externalNodes.has(this.stateNode)) {
|
|
return {
|
|
exit: [this.stateNode],
|
|
entry: [this.stateNode]
|
|
};
|
|
}
|
|
return {
|
|
exit: [],
|
|
entry: []
|
|
};
|
|
}
|
|
};
|
|
StateTree.prototype.getEntryStates = function () {
|
|
var _this = this;
|
|
if (!this.nodes) {
|
|
return [this.stateNode];
|
|
}
|
|
return [this.stateNode].concat(utils_1.flatten(utils_1.keys(this.nodes).map(function (key) {
|
|
return _this.nodes[key].getEntryStates();
|
|
})));
|
|
};
|
|
StateTree.prototype.getExitStates = function () {
|
|
var _this = this;
|
|
if (!this.nodes) {
|
|
return [this.stateNode];
|
|
}
|
|
return utils_1.flatten(utils_1.keys(this.nodes).map(function (key) {
|
|
return _this.nodes[key].getExitStates();
|
|
})).concat(this.stateNode);
|
|
};
|
|
StateTree.prototype.addReentryNode = function (reentryNode) {
|
|
this.root.reentryNodes.add(reentryNode);
|
|
};
|
|
return StateTree;
|
|
}());
|
|
exports.StateTree = StateTree;
|
|
//# sourceMappingURL=StateTree.js.map
|