xstate 3.2.1 → 3.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +15 -13
- package/README.md +37 -9
- package/dist/xstate.js +1 -1
- package/dist/xstate.utils.js +1 -1
- package/es/Machine.d.ts +2 -2
- package/es/Machine.js +2 -2
- package/es/State.d.ts +8 -7
- package/es/State.js +3 -2
- package/es/StateNode.d.ts +50 -13
- package/es/StateNode.js +617 -412
- package/es/graph.d.ts +9 -6
- package/es/graph.js +31 -24
- package/es/patterns.js +1 -1
- package/es/scxml.d.ts +2 -1
- package/es/scxml.js +33 -10
- package/es/types.d.ts +38 -7
- package/es/utils.d.ts +14 -1
- package/es/utils.js +33 -5
- package/lib/Machine.d.ts +2 -2
- package/lib/Machine.js +2 -2
- package/lib/State.d.ts +8 -7
- package/lib/State.js +3 -2
- package/lib/StateNode.d.ts +50 -13
- package/lib/StateNode.js +616 -411
- package/lib/graph.d.ts +9 -6
- package/lib/graph.js +30 -22
- package/lib/patterns.js +1 -1
- package/lib/scxml.d.ts +2 -1
- package/lib/scxml.js +33 -10
- package/lib/types.d.ts +38 -7
- package/lib/utils.d.ts +14 -1
- package/lib/utils.js +35 -5
- package/package.json +3 -3
- package/src/Machine.ts +5 -3
- package/src/State.ts +10 -2
- package/src/StateNode.ts +966 -590
- package/src/graph.ts +60 -31
- package/src/scxml.ts +80 -49
- package/src/types.ts +48 -7
- package/src/utils.ts +52 -7
- package/test/actions.test.ts +24 -1
- package/test/activities.test.ts +165 -0
- package/test/deep.test.ts +14 -16
- package/test/deterministic.test.ts +26 -5
- package/test/examples/6.17.test.ts +64 -0
- package/test/fixtures/id.ts +1 -1
- package/test/graph.test.ts +39 -16
- package/test/guards.test.ts +172 -15
- package/test/history.test.ts +193 -58
- package/test/invalid.test.ts +48 -0
- package/test/multiple.test.ts +12 -18
- package/test/parallel.test.ts +472 -1
- package/test/scxml.test.ts +13 -4
- package/test/stateIn.test.ts +1 -1
- package/test/transient.test.ts +183 -1
package/lib/StateNode.js
CHANGED
|
@@ -17,65 +17,15 @@ var HISTORY_KEY = '$history';
|
|
|
17
17
|
var NULL_EVENT = '';
|
|
18
18
|
var STATE_IDENTIFIER = '#';
|
|
19
19
|
var isStateId = function (str) { return str[0] === STATE_IDENTIFIER; };
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
onExit: [],
|
|
23
|
-
actions: []
|
|
24
|
-
});
|
|
25
|
-
/**
|
|
26
|
-
* Given a StateNode, walk up the parent chain until we find an
|
|
27
|
-
* orthogonal region of a parallel state, or the top level machine
|
|
28
|
-
* itself
|
|
29
|
-
*/
|
|
30
|
-
var regionOf = function (node) {
|
|
31
|
-
// If we reach the top of the state machine, we're a "region".
|
|
32
|
-
// If our parent is a parallel state, we're a region.
|
|
33
|
-
while (node.parent && !node.parent.parallel) {
|
|
34
|
-
node = node.parent;
|
|
35
|
-
}
|
|
36
|
-
return node;
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Ensure that the passed in StateNode instance belongs to a region
|
|
40
|
-
* that previously had not been used, or that matches the existing
|
|
41
|
-
* StateNode for the orthogonal regions. This function is used to
|
|
42
|
-
* verify that a transition that has multiple targets ends doesn't try
|
|
43
|
-
* to target several states in the same orthogonal region. The passed
|
|
44
|
-
* state is added to the regions data structure using the state's
|
|
45
|
-
* _region_ (see regionOf), and the region's parent. If there is
|
|
46
|
-
* already an object in the structure which is not already the state
|
|
47
|
-
* in question, an Error is thrown, otherwise the state is added to
|
|
48
|
-
* the structure, and the _region_ is returned.
|
|
49
|
-
*
|
|
50
|
-
* @param sourceState the state in which the event was triggered (used
|
|
51
|
-
* to report error messages)
|
|
52
|
-
* @param event the event that triggered the transition (used to
|
|
53
|
-
* report error messages)
|
|
54
|
-
* @param regions A data structure that retains the current set of
|
|
55
|
-
* orthogonal regions (their IDs), grouped by their parallel state
|
|
56
|
-
* (their IDs), with the values being the chosen states
|
|
57
|
-
* @param state A state to add to the structure if possible.
|
|
58
|
-
* @returns The region of the state, in order for the caller to repeat the process for the parent.
|
|
59
|
-
* @throws Error if the region found already exists in the regions
|
|
60
|
-
*/
|
|
61
|
-
var ensureTargetStateIsInCorrectRegion = function (sourceState, event, regions, stateToCheck) {
|
|
62
|
-
var region = regionOf(stateToCheck);
|
|
63
|
-
var parent = region.parent;
|
|
64
|
-
var parentId = parent ? parent.id : ''; // '' == machine
|
|
65
|
-
regions[parentId] = regions[parentId] || {};
|
|
66
|
-
if (regions[parentId][region.id] &&
|
|
67
|
-
regions[parentId][region.id] !== stateToCheck) {
|
|
68
|
-
throw new Error("Event '" + event + "' on state '" + sourceState.id + "' leads to an invalid configuration: " +
|
|
69
|
-
("Two or more states in the orthogonal region '" + region.id + "'."));
|
|
70
|
-
}
|
|
71
|
-
// Keep track of which state was chosen in a particular region.
|
|
72
|
-
regions[parentId][region.id] = stateToCheck;
|
|
73
|
-
return region;
|
|
20
|
+
var defaultOptions = {
|
|
21
|
+
guards: {}
|
|
74
22
|
};
|
|
75
23
|
var StateNode = /** @class */ (function () {
|
|
76
|
-
function StateNode(config) {
|
|
24
|
+
function StateNode(config, options) {
|
|
25
|
+
if (options === void 0) { options = defaultOptions; }
|
|
77
26
|
var _this = this;
|
|
78
27
|
this.config = config;
|
|
28
|
+
this.options = options;
|
|
79
29
|
this.__cache = {
|
|
80
30
|
events: undefined,
|
|
81
31
|
relativeValue: new Map(),
|
|
@@ -98,25 +48,31 @@ var StateNode = /** @class */ (function () {
|
|
|
98
48
|
this.parallel = !!config.parallel;
|
|
99
49
|
this.states = (config.states
|
|
100
50
|
? utils_1.mapValues(config.states, function (stateConfig, key) {
|
|
51
|
+
var _a;
|
|
101
52
|
var stateNode = new StateNode(__assign({}, stateConfig, { key: key, parent: _this }));
|
|
102
53
|
Object.assign(_this.idMap, __assign((_a = {}, _a[stateNode.id] = stateNode, _a), stateNode.idMap));
|
|
103
54
|
return stateNode;
|
|
104
|
-
var _a;
|
|
105
55
|
})
|
|
106
56
|
: {});
|
|
57
|
+
// History config
|
|
58
|
+
this.history =
|
|
59
|
+
config.history === true ? 'shallow' : config.history || false;
|
|
107
60
|
this.on = config.on ? this.formatTransitions(config.on) : {};
|
|
61
|
+
this.transient = !!this.on[NULL_EVENT];
|
|
108
62
|
this.strict = !!config.strict;
|
|
109
63
|
this.onEntry = config.onEntry
|
|
110
64
|
? [].concat(config.onEntry)
|
|
111
|
-
:
|
|
112
|
-
this.onExit = config.onExit
|
|
113
|
-
? [].concat(config.onExit)
|
|
114
|
-
: undefined;
|
|
65
|
+
: [];
|
|
66
|
+
this.onExit = config.onExit ? [].concat(config.onExit) : [];
|
|
115
67
|
this.data = config.data;
|
|
116
68
|
this.activities = config.activities;
|
|
117
69
|
}
|
|
118
70
|
StateNode.prototype.getStateNodes = function (state) {
|
|
119
71
|
var _this = this;
|
|
72
|
+
var _a;
|
|
73
|
+
if (!state) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
120
76
|
var stateValue = state instanceof State_1.State
|
|
121
77
|
? state.value
|
|
122
78
|
: utils_1.toStateValue(state, this.delimiter);
|
|
@@ -134,86 +90,406 @@ var StateNode = /** @class */ (function () {
|
|
|
134
90
|
var subStateNode = _this.getStateNode(subStateKey).getStateNodes(stateValue[subStateKey]);
|
|
135
91
|
return allSubStateNodes.concat(subStateNode);
|
|
136
92
|
}, []));
|
|
137
|
-
var _a;
|
|
138
93
|
};
|
|
139
94
|
StateNode.prototype.handles = function (event) {
|
|
140
95
|
var eventType = utils_1.getEventType(event);
|
|
141
96
|
return this.events.indexOf(eventType) !== -1;
|
|
142
97
|
};
|
|
98
|
+
StateNode.prototype._transitionLeafNode = function (stateValue, state, event, extendedState) {
|
|
99
|
+
var stateNode = this.getStateNode(stateValue);
|
|
100
|
+
var next = stateNode._next(state, event, extendedState);
|
|
101
|
+
if (!next.value) {
|
|
102
|
+
var _a = this._next(state, event, extendedState), value = _a.value, entryExitStates = _a.entryExitStates, actions = _a.actions, paths = _a.paths;
|
|
103
|
+
return {
|
|
104
|
+
value: value,
|
|
105
|
+
entryExitStates: {
|
|
106
|
+
entry: entryExitStates ? entryExitStates.entry : new Set(),
|
|
107
|
+
exit: new Set([
|
|
108
|
+
stateNode
|
|
109
|
+
].concat((entryExitStates
|
|
110
|
+
? Array.from(entryExitStates.exit)
|
|
111
|
+
: [])))
|
|
112
|
+
},
|
|
113
|
+
actions: actions,
|
|
114
|
+
paths: paths
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return next;
|
|
118
|
+
};
|
|
119
|
+
StateNode.prototype._transitionHierarchicalNode = function (stateValue, state, event, extendedState) {
|
|
120
|
+
var subStateKeys = Object.keys(stateValue);
|
|
121
|
+
var stateNode = this.getStateNode(subStateKeys[0]);
|
|
122
|
+
var next = stateNode._transition(stateValue[subStateKeys[0]], state, event, extendedState);
|
|
123
|
+
if (!next.value) {
|
|
124
|
+
var _a = this._next(state, event, extendedState), value = _a.value, entryExitStates = _a.entryExitStates, actions = _a.actions, paths = _a.paths;
|
|
125
|
+
return {
|
|
126
|
+
value: value,
|
|
127
|
+
entryExitStates: {
|
|
128
|
+
entry: entryExitStates ? entryExitStates.entry : new Set(),
|
|
129
|
+
exit: new Set((next.entryExitStates
|
|
130
|
+
? Array.from(next.entryExitStates.exit)
|
|
131
|
+
: []).concat([
|
|
132
|
+
stateNode
|
|
133
|
+
], (entryExitStates
|
|
134
|
+
? Array.from(entryExitStates.exit)
|
|
135
|
+
: [])))
|
|
136
|
+
},
|
|
137
|
+
actions: actions,
|
|
138
|
+
paths: paths
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return next;
|
|
142
|
+
};
|
|
143
|
+
StateNode.prototype._transitionOrthogonalNode = function (stateValue, state, event, extendedState) {
|
|
144
|
+
var _this = this;
|
|
145
|
+
var noTransitionKeys = [];
|
|
146
|
+
var transitionMap = {};
|
|
147
|
+
Object.keys(stateValue).forEach(function (subStateKey) {
|
|
148
|
+
var subStateValue = stateValue[subStateKey];
|
|
149
|
+
if (!subStateValue) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
var next = _this.getStateNode(subStateKey)._transition(subStateValue, state, event, extendedState);
|
|
153
|
+
if (!next.value) {
|
|
154
|
+
noTransitionKeys.push(subStateKey);
|
|
155
|
+
}
|
|
156
|
+
transitionMap[subStateKey] = next;
|
|
157
|
+
});
|
|
158
|
+
var willTransition = Object.keys(transitionMap).some(function (key) { return transitionMap[key].value !== undefined; });
|
|
159
|
+
if (!willTransition) {
|
|
160
|
+
var _a = this._next(state, event, extendedState), value = _a.value, entryExitStates = _a.entryExitStates, actions = _a.actions, paths = _a.paths;
|
|
161
|
+
return {
|
|
162
|
+
value: value,
|
|
163
|
+
entryExitStates: {
|
|
164
|
+
entry: entryExitStates ? entryExitStates.entry : new Set(),
|
|
165
|
+
exit: new Set(Object.keys(this.states).map(function (key) { return _this.states[key]; }).concat((entryExitStates ? Array.from(entryExitStates.exit) : [])))
|
|
166
|
+
},
|
|
167
|
+
actions: actions,
|
|
168
|
+
paths: paths
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
var allPaths = utils_1.flatMap(Object.keys(transitionMap).map(function (key) { return transitionMap[key].paths; }));
|
|
172
|
+
// External transition that escapes orthogonal region
|
|
173
|
+
if (allPaths.length === 1 &&
|
|
174
|
+
!matchesState_1.matchesState(utils_1.pathToStateValue(this.path), utils_1.pathToStateValue(allPaths[0]))) {
|
|
175
|
+
return {
|
|
176
|
+
value: this.machine.resolve(utils_1.pathsToStateValue(allPaths)),
|
|
177
|
+
entryExitStates: Object.keys(transitionMap)
|
|
178
|
+
.map(function (key) { return transitionMap[key].entryExitStates; })
|
|
179
|
+
.reduce(function (allEntryExitStates, entryExitStates) {
|
|
180
|
+
var _a = entryExitStates, entry = _a.entry, exit = _a.exit;
|
|
181
|
+
return {
|
|
182
|
+
entry: new Set(Array.from(allEntryExitStates.entry).concat(Array.from(entry))),
|
|
183
|
+
exit: new Set(Array.from(allEntryExitStates.exit).concat(Array.from(exit)))
|
|
184
|
+
};
|
|
185
|
+
}, { entry: new Set(), exit: new Set() }),
|
|
186
|
+
actions: utils_1.flatMap(Object.keys(transitionMap).map(function (key) {
|
|
187
|
+
return transitionMap[key].actions;
|
|
188
|
+
})),
|
|
189
|
+
paths: allPaths
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
var allResolvedPaths = utils_1.flatMap(Object.keys(transitionMap).map(function (key) {
|
|
193
|
+
var transition = transitionMap[key];
|
|
194
|
+
var value = transition.value || state.value;
|
|
195
|
+
return utils_1.toStatePaths(utils_1.path(_this.path)(value)[key]).map(function (statePath) {
|
|
196
|
+
return _this.path.concat(key, statePath);
|
|
197
|
+
});
|
|
198
|
+
}));
|
|
199
|
+
var nextStateValue = this.machine.resolve(utils_1.pathsToStateValue(allResolvedPaths));
|
|
200
|
+
return {
|
|
201
|
+
value: nextStateValue,
|
|
202
|
+
entryExitStates: Object.keys(transitionMap).reduce(function (allEntryExitStates, key) {
|
|
203
|
+
var _a = transitionMap[key], subStateValue = _a.value, entryExitStates = _a.entryExitStates;
|
|
204
|
+
// If the event was not handled (no subStateValue),
|
|
205
|
+
// machine should still be in state without reentry/exit.
|
|
206
|
+
if (!subStateValue || !entryExitStates) {
|
|
207
|
+
return allEntryExitStates;
|
|
208
|
+
}
|
|
209
|
+
var entry = entryExitStates.entry, exit = entryExitStates.exit;
|
|
210
|
+
return {
|
|
211
|
+
entry: new Set(Array.from(allEntryExitStates.entry).concat(Array.from(entry))),
|
|
212
|
+
exit: new Set(Array.from(allEntryExitStates.exit).concat(Array.from(exit)))
|
|
213
|
+
};
|
|
214
|
+
}, { entry: new Set(), exit: new Set() }),
|
|
215
|
+
actions: utils_1.flatMap(Object.keys(transitionMap).map(function (key) {
|
|
216
|
+
return transitionMap[key].actions;
|
|
217
|
+
})),
|
|
218
|
+
paths: utils_1.toStatePaths(nextStateValue)
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
StateNode.prototype._transition = function (stateValue, state, event, extendedState) {
|
|
222
|
+
// leaf node
|
|
223
|
+
if (typeof stateValue === 'string') {
|
|
224
|
+
return this._transitionLeafNode(stateValue, state, event, extendedState);
|
|
225
|
+
}
|
|
226
|
+
// hierarchical node
|
|
227
|
+
if (Object.keys(stateValue).length === 1) {
|
|
228
|
+
return this._transitionHierarchicalNode(stateValue, state, event, extendedState);
|
|
229
|
+
}
|
|
230
|
+
// orthogonal node
|
|
231
|
+
return this._transitionOrthogonalNode(stateValue, state, event, extendedState);
|
|
232
|
+
};
|
|
233
|
+
StateNode.prototype._next = function (state, event, extendedState) {
|
|
234
|
+
var _this = this;
|
|
235
|
+
var eventType = utils_1.getEventType(event);
|
|
236
|
+
var candidates = this.on[eventType];
|
|
237
|
+
var actions = this.transient
|
|
238
|
+
? [{ type: actions_1.actionTypes.null }]
|
|
239
|
+
: [];
|
|
240
|
+
if (!candidates || !candidates.length) {
|
|
241
|
+
return {
|
|
242
|
+
value: undefined,
|
|
243
|
+
entryExitStates: undefined,
|
|
244
|
+
actions: actions,
|
|
245
|
+
paths: []
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
var nextStateStrings = [];
|
|
249
|
+
var selectedTransition;
|
|
250
|
+
for (var _i = 0, candidates_1 = candidates; _i < candidates_1.length; _i++) {
|
|
251
|
+
var candidate = candidates_1[_i];
|
|
252
|
+
var _a = candidate, cond = _a.cond, stateIn = _a.in
|
|
253
|
+
// actions: transitionActions
|
|
254
|
+
;
|
|
255
|
+
var extendedStateObject = extendedState || {};
|
|
256
|
+
var eventObject = actions_1.toEventObject(event);
|
|
257
|
+
var isInState = stateIn
|
|
258
|
+
? matchesState_1.matchesState(utils_1.toStateValue(stateIn, this.delimiter), utils_1.path(this.path.slice(0, -2))(state.value))
|
|
259
|
+
: true;
|
|
260
|
+
if ((!cond ||
|
|
261
|
+
this._evaluateCond(cond, extendedStateObject, eventObject, state.value)) &&
|
|
262
|
+
(!stateIn || isInState)) {
|
|
263
|
+
nextStateStrings = Array.isArray(candidate.target)
|
|
264
|
+
? candidate.target
|
|
265
|
+
: [candidate.target];
|
|
266
|
+
actions.push.apply(actions, (candidate.actions ? candidate.actions : [])); // TODO: fixme;
|
|
267
|
+
selectedTransition = candidate;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (nextStateStrings.length === 0) {
|
|
272
|
+
return {
|
|
273
|
+
value: undefined,
|
|
274
|
+
entryExitStates: undefined,
|
|
275
|
+
actions: actions,
|
|
276
|
+
paths: []
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
var nextStateNodes = utils_1.flatMap(nextStateStrings.map(function (str) {
|
|
280
|
+
return _this.getRelativeStateNodes(str, state.historyValue);
|
|
281
|
+
}));
|
|
282
|
+
var nextStatePaths = nextStateNodes.map(function (stateNode) { return stateNode.path; });
|
|
283
|
+
var entryExitStates = nextStateNodes.reduce(function (allEntryExitStates, nextStateNode) {
|
|
284
|
+
var _a = _this._getEntryExitStates(nextStateNode, !!selectedTransition.internal), entry = _a.entry, exit = _a.exit;
|
|
285
|
+
return {
|
|
286
|
+
entry: new Set(Array.from(allEntryExitStates.entry).concat(Array.from(entry))),
|
|
287
|
+
exit: new Set(Array.from(allEntryExitStates.exit).concat(Array.from(exit)))
|
|
288
|
+
};
|
|
289
|
+
}, { entry: new Set(), exit: new Set() });
|
|
290
|
+
return {
|
|
291
|
+
value: this.machine.resolve(utils_1.pathsToStateValue(utils_1.flatMap(nextStateStrings.map(function (str) {
|
|
292
|
+
return _this.getRelativeStateNodes(str, state.historyValue).map(function (s) { return s.path; });
|
|
293
|
+
})))),
|
|
294
|
+
entryExitStates: entryExitStates,
|
|
295
|
+
actions: actions,
|
|
296
|
+
paths: nextStatePaths
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
StateNode.prototype._getEntryExitStates = function (nextStateNode, internal) {
|
|
300
|
+
var entryExitStates = {
|
|
301
|
+
entry: [],
|
|
302
|
+
exit: []
|
|
303
|
+
};
|
|
304
|
+
var fromPath = this.path;
|
|
305
|
+
var toPath = nextStateNode.path;
|
|
306
|
+
var parent = this.machine;
|
|
307
|
+
for (var i = 0; i < Math.min(fromPath.length, toPath.length); i++) {
|
|
308
|
+
var fromPathSegment = fromPath[i];
|
|
309
|
+
var toPathSegment = toPath[i];
|
|
310
|
+
if (fromPathSegment === toPathSegment) {
|
|
311
|
+
parent = parent.getStateNode(fromPathSegment);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
var commonAncestorPath = parent.path;
|
|
318
|
+
var marker = parent;
|
|
319
|
+
for (var _i = 0, _a = fromPath.slice(commonAncestorPath.length); _i < _a.length; _i++) {
|
|
320
|
+
var segment = _a[_i];
|
|
321
|
+
marker = marker.getStateNode(segment);
|
|
322
|
+
entryExitStates.exit.unshift(marker);
|
|
323
|
+
}
|
|
324
|
+
// Child node
|
|
325
|
+
if (parent === this) {
|
|
326
|
+
if (!internal) {
|
|
327
|
+
entryExitStates.exit.push(this);
|
|
328
|
+
entryExitStates.entry.push(this);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
marker = parent;
|
|
332
|
+
for (var _b = 0, _c = toPath.slice(commonAncestorPath.length); _b < _c.length; _b++) {
|
|
333
|
+
var segment = _c[_b];
|
|
334
|
+
marker = marker.getStateNode(segment);
|
|
335
|
+
entryExitStates.entry.push(marker);
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
entry: new Set(entryExitStates.entry),
|
|
339
|
+
exit: new Set(entryExitStates.exit)
|
|
340
|
+
};
|
|
341
|
+
};
|
|
342
|
+
StateNode.prototype._evaluateCond = function (condition, extendedState, eventObject, interimState) {
|
|
343
|
+
var condFn;
|
|
344
|
+
if (typeof condition === 'string') {
|
|
345
|
+
if (!this.machine.options.guards[condition]) {
|
|
346
|
+
throw new Error("String condition '" + condition + "' is not defined on machine '" + this.machine.id + "'");
|
|
347
|
+
}
|
|
348
|
+
condFn = this.machine.options.guards[condition];
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
condFn = condition;
|
|
352
|
+
}
|
|
353
|
+
return condFn(extendedState, eventObject, interimState);
|
|
354
|
+
};
|
|
355
|
+
StateNode.prototype._getActions = function (transition) {
|
|
356
|
+
var entryExitActions = {
|
|
357
|
+
entry: transition.entryExitStates
|
|
358
|
+
? utils_1.flatMap(Array.from(transition.entryExitStates.entry).map(function (n) { return n.onEntry.concat((n.activities
|
|
359
|
+
? n.activities.map(function (activity) { return actions_1.start(activity); })
|
|
360
|
+
: [])); }))
|
|
361
|
+
: [],
|
|
362
|
+
exit: transition.entryExitStates
|
|
363
|
+
? utils_1.flatMap(Array.from(transition.entryExitStates.exit).map(function (n) { return n.onExit.concat((n.activities
|
|
364
|
+
? n.activities.map(function (activity) { return actions_1.stop(activity); })
|
|
365
|
+
: [])); }))
|
|
366
|
+
: []
|
|
367
|
+
};
|
|
368
|
+
var actions = (entryExitActions.exit || [])
|
|
369
|
+
.concat(transition.actions || [])
|
|
370
|
+
.concat(entryExitActions.entry || []);
|
|
371
|
+
return actions;
|
|
372
|
+
};
|
|
373
|
+
StateNode.prototype._getActivities = function (state, transition) {
|
|
374
|
+
if (!transition.entryExitStates) {
|
|
375
|
+
return {};
|
|
376
|
+
}
|
|
377
|
+
var activityMap = __assign({}, state.activities);
|
|
378
|
+
Array.from(transition.entryExitStates.exit).forEach(function (stateNode) {
|
|
379
|
+
if (!stateNode.activities) {
|
|
380
|
+
return; // TODO: fixme
|
|
381
|
+
}
|
|
382
|
+
stateNode.activities.forEach(function (activity) {
|
|
383
|
+
activityMap[utils_1.getActionType(activity)] = false;
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
Array.from(transition.entryExitStates.entry).forEach(function (stateNode) {
|
|
387
|
+
if (!stateNode.activities) {
|
|
388
|
+
return; // TODO: fixme
|
|
389
|
+
}
|
|
390
|
+
stateNode.activities.forEach(function (activity) {
|
|
391
|
+
activityMap[utils_1.getActionType(activity)] = true;
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
return activityMap;
|
|
395
|
+
};
|
|
143
396
|
StateNode.prototype.transition = function (state, event, extendedState) {
|
|
397
|
+
var _a;
|
|
144
398
|
var resolvedStateValue = typeof state === 'string'
|
|
145
399
|
? this.resolve(utils_1.pathToStateValue(this.getResolvedPath(state)))
|
|
146
|
-
: state instanceof State_1.State
|
|
400
|
+
: state instanceof State_1.State
|
|
401
|
+
? state
|
|
402
|
+
: this.resolve(state);
|
|
403
|
+
var eventType = utils_1.getEventType(event);
|
|
147
404
|
if (this.strict) {
|
|
148
|
-
var eventType = utils_1.getEventType(event);
|
|
149
405
|
if (this.events.indexOf(eventType) === -1) {
|
|
150
406
|
throw new Error("Machine '" + this.id + "' does not accept event '" + eventType + "'");
|
|
151
407
|
}
|
|
152
408
|
}
|
|
153
409
|
var currentState = State_1.State.from(resolvedStateValue);
|
|
154
|
-
var
|
|
155
|
-
|
|
410
|
+
var historyValue = resolvedStateValue instanceof State_1.State
|
|
411
|
+
? resolvedStateValue.historyValue
|
|
412
|
+
? resolvedStateValue.historyValue
|
|
413
|
+
: this.machine.historyValue(resolvedStateValue.value)
|
|
414
|
+
: this.machine.historyValue(resolvedStateValue);
|
|
415
|
+
var stateTransition = this._transition(currentState.value, currentState, event, extendedState);
|
|
416
|
+
try {
|
|
417
|
+
this.ensureValidPaths(stateTransition.paths);
|
|
418
|
+
}
|
|
419
|
+
catch (e) {
|
|
420
|
+
throw new Error("Event '" + eventType + "' leads to an invalid configuration: " + e.message);
|
|
421
|
+
}
|
|
422
|
+
var actions = this._getActions(stateTransition);
|
|
423
|
+
var activities = this._getActivities(currentState, stateTransition);
|
|
424
|
+
var raisedEvents = actions.filter(function (action) {
|
|
425
|
+
return typeof action === 'object' &&
|
|
426
|
+
(action.type === actions_1.actionTypes.raise || action.type === actions_1.actionTypes.null);
|
|
427
|
+
});
|
|
428
|
+
var nonEventActions = actions.filter(function (action) {
|
|
429
|
+
return typeof action !== 'object' ||
|
|
430
|
+
(action.type !== actions_1.actionTypes.raise && action.type !== actions_1.actionTypes.null);
|
|
431
|
+
});
|
|
432
|
+
var stateNodes = stateTransition.value
|
|
433
|
+
? this.getStateNodes(stateTransition.value)
|
|
434
|
+
: [];
|
|
435
|
+
var isTransient = stateNodes.some(function (stateNode) { return stateNode.transient; });
|
|
436
|
+
if (isTransient) {
|
|
437
|
+
raisedEvents.push({ type: actions_1.actionTypes.null });
|
|
438
|
+
}
|
|
439
|
+
var data = {};
|
|
440
|
+
stateNodes.forEach(function (stateNode) {
|
|
441
|
+
data[stateNode.id] = stateNode.data;
|
|
442
|
+
});
|
|
443
|
+
var nextState = stateTransition.value
|
|
444
|
+
? new State_1.State(stateTransition.value, StateNode.updateHistoryValue(historyValue, stateTransition.value), currentState, nonEventActions, activities, data, raisedEvents)
|
|
445
|
+
: undefined;
|
|
156
446
|
if (!nextState) {
|
|
447
|
+
// Unchanged state should be returned with no actions
|
|
157
448
|
return State_1.State.inert(currentState);
|
|
158
449
|
}
|
|
450
|
+
// Dispose of previous histories to prevent memory leaks
|
|
451
|
+
delete currentState.history;
|
|
159
452
|
var maybeNextState = nextState;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
var raisedEvent = raisedEvents
|
|
163
|
-
|
|
164
|
-
(_a =
|
|
165
|
-
return nextState;
|
|
166
|
-
}
|
|
167
|
-
if (stateTransition.events.length) {
|
|
168
|
-
var raised = stateTransition.events[0].type === actions_1.actionTypes.raise
|
|
169
|
-
? stateTransition.events[0].event
|
|
170
|
-
: undefined;
|
|
171
|
-
var nullEvent = stateTransition.events[0].type === actions_1.actionTypes.null;
|
|
172
|
-
if (raised || nullEvent) {
|
|
173
|
-
maybeNextState = this.transition(nextState, nullEvent ? NULL_EVENT : raised, extendedState);
|
|
174
|
-
(_b = maybeNextState.actions).unshift.apply(_b, nextState.actions);
|
|
175
|
-
return maybeNextState;
|
|
176
|
-
}
|
|
453
|
+
while (raisedEvents.length) {
|
|
454
|
+
var currentActions = maybeNextState.actions;
|
|
455
|
+
var raisedEvent = raisedEvents.shift();
|
|
456
|
+
maybeNextState = this.transition(maybeNextState, raisedEvent.type === actions_1.actionTypes.null ? NULL_EVENT : raisedEvent.event, extendedState);
|
|
457
|
+
(_a = maybeNextState.actions).unshift.apply(_a, currentActions);
|
|
177
458
|
}
|
|
178
|
-
return
|
|
179
|
-
var _a, _b;
|
|
459
|
+
return maybeNextState;
|
|
180
460
|
};
|
|
181
|
-
StateNode.prototype.
|
|
182
|
-
var
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (stateNode.data !== undefined) {
|
|
205
|
-
data[stateNode.id] = stateNode.data;
|
|
461
|
+
StateNode.prototype.ensureValidPaths = function (paths) {
|
|
462
|
+
var _this = this;
|
|
463
|
+
var visitedParents = new Map();
|
|
464
|
+
var stateNodes = utils_1.flatMap(paths.map(function (_path) { return _this.getRelativeStateNodes(_path); }));
|
|
465
|
+
outer: for (var _i = 0, stateNodes_1 = stateNodes; _i < stateNodes_1.length; _i++) {
|
|
466
|
+
var stateNode = stateNodes_1[_i];
|
|
467
|
+
var marker = stateNode;
|
|
468
|
+
while (marker.parent) {
|
|
469
|
+
if (visitedParents.has(marker.parent)) {
|
|
470
|
+
if (marker.parent.parallel) {
|
|
471
|
+
continue outer;
|
|
472
|
+
}
|
|
473
|
+
throw new Error("State node '" + stateNode.id + "' shares parent '" + marker.parent.id + "' with state node '" + visitedParents
|
|
474
|
+
.get(marker.parent)
|
|
475
|
+
.map(function (a) { return a.id; }) + "'");
|
|
476
|
+
}
|
|
477
|
+
if (!visitedParents.get(marker.parent)) {
|
|
478
|
+
visitedParents.set(marker.parent, [stateNode]);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
visitedParents.get(marker.parent).push(stateNode);
|
|
482
|
+
}
|
|
483
|
+
marker = marker.parent;
|
|
206
484
|
}
|
|
207
|
-
|
|
208
|
-
}, {}), events);
|
|
485
|
+
}
|
|
209
486
|
};
|
|
210
487
|
StateNode.prototype.getStateNode = function (stateKey) {
|
|
211
488
|
if (isStateId(stateKey)) {
|
|
212
489
|
return this.machine.getStateNodeById(stateKey);
|
|
213
490
|
}
|
|
214
491
|
if (!this.states) {
|
|
215
|
-
throw new Error("Unable to retrieve child state '" + stateKey + "' from '" + this
|
|
216
|
-
.id + "'; no child states exist.");
|
|
492
|
+
throw new Error("Unable to retrieve child state '" + stateKey + "' from '" + this.id + "'; no child states exist.");
|
|
217
493
|
}
|
|
218
494
|
var result = this.states[stateKey];
|
|
219
495
|
if (!result) {
|
|
@@ -225,14 +501,24 @@ var StateNode = /** @class */ (function () {
|
|
|
225
501
|
var resolvedStateId = isStateId(stateId)
|
|
226
502
|
? stateId.slice(STATE_IDENTIFIER.length)
|
|
227
503
|
: stateId;
|
|
228
|
-
var stateNode = this.idMap[resolvedStateId];
|
|
504
|
+
var stateNode = this.machine.idMap[resolvedStateId];
|
|
229
505
|
if (!stateNode) {
|
|
230
506
|
throw new Error("Substate '#" + resolvedStateId + "' does not exist on '" + this.id + "'");
|
|
231
507
|
}
|
|
232
508
|
return stateNode;
|
|
233
509
|
};
|
|
510
|
+
StateNode.prototype.getStateNodeByPath = function (statePath) {
|
|
511
|
+
var arrayStatePath = utils_1.toStatePath(statePath, this.delimiter);
|
|
512
|
+
var currentStateNode = this;
|
|
513
|
+
while (arrayStatePath.length) {
|
|
514
|
+
var key = arrayStatePath.shift();
|
|
515
|
+
currentStateNode = currentStateNode.getStateNode(key);
|
|
516
|
+
}
|
|
517
|
+
return currentStateNode;
|
|
518
|
+
};
|
|
234
519
|
StateNode.prototype.resolve = function (stateValue) {
|
|
235
520
|
var _this = this;
|
|
521
|
+
var _a;
|
|
236
522
|
if (typeof stateValue === 'string') {
|
|
237
523
|
var subStateNode = this.getStateNode(stateValue);
|
|
238
524
|
return subStateNode.initial
|
|
@@ -240,290 +526,24 @@ var StateNode = /** @class */ (function () {
|
|
|
240
526
|
}
|
|
241
527
|
if (this.parallel) {
|
|
242
528
|
return utils_1.mapValues(this.initialStateValue, function (subStateValue, subStateKey) {
|
|
243
|
-
return
|
|
529
|
+
return subStateValue
|
|
530
|
+
? _this.getStateNode(subStateKey).resolve(stateValue[subStateKey] || subStateValue)
|
|
531
|
+
: {};
|
|
244
532
|
});
|
|
245
533
|
}
|
|
246
534
|
return utils_1.mapValues(stateValue, function (subStateValue, subStateKey) {
|
|
247
|
-
return
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
};
|
|
251
|
-
StateNode.prototype.transitionStateValue = function (state, event, fullState, extendedState) {
|
|
252
|
-
var _this = this;
|
|
253
|
-
var history = state.history;
|
|
254
|
-
var stateValue = state.value;
|
|
255
|
-
if (typeof stateValue === 'string') {
|
|
256
|
-
var subStateNode = this.getStateNode(stateValue);
|
|
257
|
-
var result = subStateNode.next(event, fullState, history ? history.value : undefined, extendedState);
|
|
258
|
-
// If a machine substate returns no potential transitions,
|
|
259
|
-
// check on the machine itself.
|
|
260
|
-
if (!result.statePaths.length && !this.parent) {
|
|
261
|
-
return this.next(event, fullState, history ? history.value : undefined, extendedState);
|
|
262
|
-
}
|
|
263
|
-
return result;
|
|
264
|
-
}
|
|
265
|
-
// Potential transition tuples from parent state nodes
|
|
266
|
-
var potentialStateTransitions = [];
|
|
267
|
-
var willTransition = false;
|
|
268
|
-
var nextStateTransitionMap = utils_1.mapValues(stateValue, function (subStateValue, subStateKey) {
|
|
269
|
-
var subStateNode = _this.getStateNode(subStateKey);
|
|
270
|
-
var subHistory = history ? history.value[subStateKey] : undefined;
|
|
271
|
-
var subState = new State_1.State(subStateValue, subHistory ? State_1.State.from(subHistory) : undefined);
|
|
272
|
-
var subStateTransition = subStateNode.transitionStateValue(subState, event, fullState, extendedState);
|
|
273
|
-
if (!subStateTransition.statePaths.length) {
|
|
274
|
-
potentialStateTransitions.push(subStateNode.next(event, fullState, history ? history.value : undefined, extendedState));
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
willTransition = true;
|
|
278
|
-
}
|
|
279
|
-
return subStateTransition;
|
|
280
|
-
});
|
|
281
|
-
if (!willTransition) {
|
|
282
|
-
if (this.parallel) {
|
|
283
|
-
if (potentialStateTransitions.length) {
|
|
284
|
-
// Select the first potential state transition to take
|
|
285
|
-
return potentialStateTransitions[0];
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
statePaths: [],
|
|
289
|
-
actions: emptyActions,
|
|
290
|
-
activities: undefined,
|
|
291
|
-
events: []
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
var subStateKey = Object.keys(nextStateTransitionMap)[0];
|
|
295
|
-
// try with parent
|
|
296
|
-
var _a = this.getStateNode(subStateKey).next(event, fullState, history ? history.value : undefined, extendedState), parentStatePaths = _a.statePaths, parentNextActions = _a.actions, parentActivities = _a.activities;
|
|
297
|
-
var nextActions = nextStateTransitionMap[subStateKey].actions;
|
|
298
|
-
var activities = nextStateTransitionMap[subStateKey].activities;
|
|
299
|
-
var allActivities = __assign({}, activities, parentActivities);
|
|
300
|
-
var allActions = parentNextActions
|
|
301
|
-
? nextActions
|
|
302
|
-
? {
|
|
303
|
-
onEntry: nextActions.onEntry.concat(parentNextActions.onEntry),
|
|
304
|
-
actions: nextActions.actions.concat(parentNextActions.actions),
|
|
305
|
-
onExit: nextActions.onExit.concat(parentNextActions.onExit)
|
|
306
|
-
}
|
|
307
|
-
: parentNextActions
|
|
308
|
-
: nextActions;
|
|
309
|
-
return {
|
|
310
|
-
statePaths: parentStatePaths,
|
|
311
|
-
actions: allActions,
|
|
312
|
-
activities: allActivities,
|
|
313
|
-
events: []
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
if (this.parallel) {
|
|
317
|
-
nextStateTransitionMap = __assign({}, utils_1.mapValues(this.initialState.value, function (subStateValue, key) {
|
|
318
|
-
var subStateTransition = nextStateTransitionMap[key];
|
|
319
|
-
return {
|
|
320
|
-
statePaths: subStateTransition && subStateTransition.statePaths.length
|
|
321
|
-
? subStateTransition.statePaths
|
|
322
|
-
: utils_1.toStatePaths(stateValue[key] || subStateValue).map(function (subPath) { return _this.getStateNode(key).path.concat(subPath); }),
|
|
323
|
-
actions: subStateTransition && subStateTransition.actions
|
|
324
|
-
? subStateTransition.actions
|
|
325
|
-
: {
|
|
326
|
-
onEntry: [],
|
|
327
|
-
onExit: [],
|
|
328
|
-
actions: []
|
|
329
|
-
},
|
|
330
|
-
activities: undefined,
|
|
331
|
-
events: []
|
|
332
|
-
};
|
|
333
|
-
}));
|
|
334
|
-
}
|
|
335
|
-
var finalActions = {
|
|
336
|
-
onEntry: [],
|
|
337
|
-
actions: [],
|
|
338
|
-
onExit: []
|
|
339
|
-
};
|
|
340
|
-
var finalActivities = {};
|
|
341
|
-
utils_1.mapValues(nextStateTransitionMap, function (subStateTransition) {
|
|
342
|
-
var
|
|
343
|
-
// statePaths: nextSubStatePaths,
|
|
344
|
-
nextSubActions = subStateTransition.actions, nextSubActivities = subStateTransition.activities;
|
|
345
|
-
if (nextSubActions) {
|
|
346
|
-
if (nextSubActions.onEntry) {
|
|
347
|
-
(_a = finalActions.onEntry).push.apply(_a, nextSubActions.onEntry);
|
|
348
|
-
}
|
|
349
|
-
if (nextSubActions.actions) {
|
|
350
|
-
(_b = finalActions.actions).push.apply(_b, nextSubActions.actions);
|
|
351
|
-
}
|
|
352
|
-
if (nextSubActions.onExit) {
|
|
353
|
-
(_c = finalActions.onExit).push.apply(_c, nextSubActions.onExit);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (nextSubActivities) {
|
|
357
|
-
Object.assign(finalActivities, nextSubActivities);
|
|
358
|
-
}
|
|
359
|
-
var _a, _b, _c;
|
|
360
|
-
});
|
|
361
|
-
return {
|
|
362
|
-
statePaths: Object.keys(nextStateTransitionMap)
|
|
363
|
-
.map(function (stateKey) { return nextStateTransitionMap[stateKey].statePaths; })
|
|
364
|
-
.reduce(function (a, b) { return a.concat(b); }, []),
|
|
365
|
-
actions: finalActions,
|
|
366
|
-
activities: finalActivities,
|
|
367
|
-
events: []
|
|
368
|
-
};
|
|
369
|
-
};
|
|
370
|
-
StateNode.prototype.next = function (event, fullState, history, extendedState) {
|
|
371
|
-
var _this = this;
|
|
372
|
-
var eventType = utils_1.getEventType(event);
|
|
373
|
-
var actionMap = { onEntry: [], onExit: [], actions: [] };
|
|
374
|
-
var activityMap = {};
|
|
375
|
-
var candidates = this.on[eventType];
|
|
376
|
-
if (this.onExit) {
|
|
377
|
-
actionMap.onExit = this.onExit;
|
|
378
|
-
}
|
|
379
|
-
if (this.activities) {
|
|
380
|
-
this.activities.forEach(function (activity) {
|
|
381
|
-
activityMap[utils_1.getEventType(activity)] = false;
|
|
382
|
-
actionMap.onExit = actionMap.onExit.concat(actions_1.stop(activity));
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
if (!candidates) {
|
|
386
|
-
return {
|
|
387
|
-
statePaths: [],
|
|
388
|
-
actions: actionMap,
|
|
389
|
-
activities: activityMap,
|
|
390
|
-
events: []
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
var nextStateStrings = [];
|
|
394
|
-
for (var _i = 0, candidates_1 = candidates; _i < candidates_1.length; _i++) {
|
|
395
|
-
var candidate = candidates_1[_i];
|
|
396
|
-
var _a = candidate, cond = _a.cond, stateIn = _a.in, transitionActions = _a.actions;
|
|
397
|
-
var extendedStateObject = extendedState || {};
|
|
398
|
-
var eventObject = actions_1.toEventObject(event);
|
|
399
|
-
var isInState = stateIn
|
|
400
|
-
? matchesState_1.matchesState(utils_1.toStateValue(stateIn, this.delimiter), utils_1.path(this.path.slice(0, -2))(fullState.value))
|
|
401
|
-
: true;
|
|
402
|
-
if ((!cond || cond(extendedStateObject, eventObject)) &&
|
|
403
|
-
(!stateIn || isInState)) {
|
|
404
|
-
nextStateStrings = Array.isArray(candidate.target)
|
|
405
|
-
? candidate.target
|
|
406
|
-
: [candidate.target];
|
|
407
|
-
if (transitionActions) {
|
|
408
|
-
actionMap.actions = actionMap.actions.concat(transitionActions);
|
|
409
|
-
}
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
if (nextStateStrings.length === 0) {
|
|
414
|
-
return {
|
|
415
|
-
statePaths: [],
|
|
416
|
-
actions: actionMap,
|
|
417
|
-
activities: activityMap,
|
|
418
|
-
events: []
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
var finalPaths = [];
|
|
422
|
-
var raisedEvents = [];
|
|
423
|
-
var usedRegions = {};
|
|
424
|
-
nextStateStrings.forEach(function (nextStateString) {
|
|
425
|
-
var nextStatePath = _this.getResolvedPath(nextStateString);
|
|
426
|
-
var currentState = isStateId(nextStateString)
|
|
427
|
-
? _this.machine
|
|
428
|
-
: _this.parent;
|
|
429
|
-
var currentHistory = history;
|
|
430
|
-
var currentPath = _this.key;
|
|
431
|
-
nextStatePath.forEach(function (subPath) {
|
|
432
|
-
if (subPath === '') {
|
|
433
|
-
actionMap.onExit = [];
|
|
434
|
-
currentState = _this;
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
if (!currentState || !currentState.states) {
|
|
438
|
-
throw new Error("Unable to read '" + subPath + "' from '" + _this.id + "'");
|
|
439
|
-
}
|
|
440
|
-
if (subPath === HISTORY_KEY) {
|
|
441
|
-
if (!Object.keys(currentState.states).length) {
|
|
442
|
-
subPath = '';
|
|
443
|
-
}
|
|
444
|
-
else if (currentHistory) {
|
|
445
|
-
subPath =
|
|
446
|
-
typeof currentHistory === 'object'
|
|
447
|
-
? Object.keys(currentHistory)[0]
|
|
448
|
-
: currentHistory;
|
|
449
|
-
}
|
|
450
|
-
else if (currentState.initial) {
|
|
451
|
-
subPath = currentState.initial;
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
throw new Error("Cannot read '" + HISTORY_KEY + "' from state '" + currentState.id + "': missing 'initial'");
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
try {
|
|
458
|
-
if (subPath !== '') {
|
|
459
|
-
currentState = currentState.getStateNode(subPath);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
catch (e) {
|
|
463
|
-
throw new Error("Event '" + event + "' on state '" + currentPath + "' leads to undefined state '" + nextStatePath.join(_this.delimiter) + "'.");
|
|
464
|
-
}
|
|
465
|
-
if (currentState.onEntry) {
|
|
466
|
-
actionMap.onEntry = actionMap.onEntry.concat(currentState.onEntry);
|
|
467
|
-
}
|
|
468
|
-
if (currentState.activities) {
|
|
469
|
-
currentState.activities.forEach(function (activity) {
|
|
470
|
-
activityMap[utils_1.getEventType(activity)] = true;
|
|
471
|
-
actionMap.onEntry = actionMap.onEntry.concat(actions_1.start(activity));
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
currentPath = subPath;
|
|
475
|
-
if (currentHistory) {
|
|
476
|
-
currentHistory = currentHistory[subPath];
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
if (!currentState) {
|
|
480
|
-
throw new Error('no state');
|
|
481
|
-
}
|
|
482
|
-
var region = ensureTargetStateIsInCorrectRegion(_this, event, usedRegions, currentState);
|
|
483
|
-
while (region.parent) {
|
|
484
|
-
region = ensureTargetStateIsInCorrectRegion(_this, event, usedRegions, region.parent);
|
|
485
|
-
}
|
|
486
|
-
var paths = [currentState.path];
|
|
487
|
-
if (currentState.initial || currentState.parallel) {
|
|
488
|
-
var initialState = currentState.initialState;
|
|
489
|
-
actionMap.onEntry = actionMap.onEntry.concat(initialState.actions);
|
|
490
|
-
paths = utils_1.toStatePaths(initialState.value).map(function (subPath) {
|
|
491
|
-
return currentState.path.concat(subPath);
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
finalPaths.push.apply(finalPaths, paths);
|
|
495
|
-
while (currentState.initial) {
|
|
496
|
-
if (!currentState || !currentState.states) {
|
|
497
|
-
throw new Error("Invalid initial state");
|
|
498
|
-
}
|
|
499
|
-
currentState = currentState.states[currentState.initial];
|
|
500
|
-
if (currentState.activities) {
|
|
501
|
-
currentState.activities.forEach(function (activity) {
|
|
502
|
-
activityMap[utils_1.getEventType(activity)] = true;
|
|
503
|
-
actionMap.onEntry = actionMap.onEntry.concat(actions_1.start(activity));
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
var myActions = (currentState.onEntry
|
|
508
|
-
? currentState.onEntry.filter(function (action) {
|
|
509
|
-
return typeof action === 'object' && action.type === actions_1.actionTypes.raise;
|
|
510
|
-
})
|
|
511
|
-
: []).concat(currentState.on[NULL_EVENT] ? { type: actions_1.actionTypes.null } : []);
|
|
512
|
-
myActions.forEach(function (action) { return raisedEvents.push(action); });
|
|
535
|
+
return subStateValue
|
|
536
|
+
? _this.getStateNode(subStateKey).resolve(subStateValue)
|
|
537
|
+
: {};
|
|
513
538
|
});
|
|
514
|
-
return {
|
|
515
|
-
statePaths: finalPaths,
|
|
516
|
-
actions: actionMap,
|
|
517
|
-
activities: activityMap,
|
|
518
|
-
events: raisedEvents
|
|
519
|
-
};
|
|
520
539
|
};
|
|
521
540
|
Object.defineProperty(StateNode.prototype, "resolvedStateValue", {
|
|
522
541
|
get: function () {
|
|
542
|
+
var _a, _b;
|
|
523
543
|
var key = this.key;
|
|
524
544
|
if (this.parallel) {
|
|
525
545
|
return _a = {},
|
|
526
|
-
_a[key] = utils_1.
|
|
546
|
+
_a[key] = utils_1.mapFilterValues(this.states, function (stateNode) { return stateNode.resolvedStateValue[stateNode.key]; }, function (stateNode) { return !stateNode.history; }),
|
|
527
547
|
_a;
|
|
528
548
|
}
|
|
529
549
|
if (!this.initial) {
|
|
@@ -533,7 +553,6 @@ var StateNode = /** @class */ (function () {
|
|
|
533
553
|
return _b = {},
|
|
534
554
|
_b[key] = this.states[this.initial].resolvedStateValue,
|
|
535
555
|
_b;
|
|
536
|
-
var _a, _b;
|
|
537
556
|
},
|
|
538
557
|
enumerable: true,
|
|
539
558
|
configurable: true
|
|
@@ -550,12 +569,14 @@ var StateNode = /** @class */ (function () {
|
|
|
550
569
|
};
|
|
551
570
|
Object.defineProperty(StateNode.prototype, "initialStateValue", {
|
|
552
571
|
get: function () {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
572
|
+
if (this.__cache.initialState) {
|
|
573
|
+
return this.__cache.initialState;
|
|
574
|
+
}
|
|
575
|
+
var initialStateValue = (this.parallel
|
|
576
|
+
? utils_1.mapFilterValues(this.states, function (state) { return state.initialStateValue || {}; }, function (stateNode) { return !stateNode.history; })
|
|
577
|
+
: typeof this.resolvedStateValue === 'string'
|
|
578
|
+
? undefined
|
|
579
|
+
: this.resolvedStateValue[this.key]);
|
|
559
580
|
this.__cache.initialState = initialStateValue;
|
|
560
581
|
return this.__cache.initialState;
|
|
561
582
|
},
|
|
@@ -564,6 +585,7 @@ var StateNode = /** @class */ (function () {
|
|
|
564
585
|
});
|
|
565
586
|
Object.defineProperty(StateNode.prototype, "initialState", {
|
|
566
587
|
get: function () {
|
|
588
|
+
var _a;
|
|
567
589
|
var initialStateValue = this.initialStateValue;
|
|
568
590
|
if (!initialStateValue) {
|
|
569
591
|
throw new Error("Cannot retrieve initial state from simple state '" + this.id + ".'");
|
|
@@ -581,7 +603,42 @@ var StateNode = /** @class */ (function () {
|
|
|
581
603
|
});
|
|
582
604
|
}
|
|
583
605
|
});
|
|
584
|
-
|
|
606
|
+
// TODO: deduplicate - DRY (from this.transition())
|
|
607
|
+
var raisedEvents = actions.filter(function (action) {
|
|
608
|
+
return typeof action === 'object' &&
|
|
609
|
+
(action.type === actions_1.actionTypes.raise || action.type === actions_1.actionTypes.null);
|
|
610
|
+
});
|
|
611
|
+
var initialState = new State_1.State(initialStateValue, undefined, undefined, actions, activityMap);
|
|
612
|
+
var maybeNextState = initialState;
|
|
613
|
+
while (raisedEvents.length) {
|
|
614
|
+
var currentActions = maybeNextState.actions;
|
|
615
|
+
var raisedEvent = raisedEvents.shift();
|
|
616
|
+
maybeNextState = this.transition(maybeNextState, raisedEvent.type === actions_1.actionTypes.null ? NULL_EVENT : raisedEvent.event, undefined // TODO: consider initial state given external state
|
|
617
|
+
);
|
|
618
|
+
(_a = maybeNextState.actions).unshift.apply(_a, currentActions);
|
|
619
|
+
}
|
|
620
|
+
return maybeNextState;
|
|
621
|
+
},
|
|
622
|
+
enumerable: true,
|
|
623
|
+
configurable: true
|
|
624
|
+
});
|
|
625
|
+
Object.defineProperty(StateNode.prototype, "target", {
|
|
626
|
+
get: function () {
|
|
627
|
+
var target;
|
|
628
|
+
if (this.history) {
|
|
629
|
+
var historyConfig = this.config;
|
|
630
|
+
if (historyConfig.target && typeof historyConfig.target === 'string') {
|
|
631
|
+
target = isStateId(historyConfig.target)
|
|
632
|
+
? utils_1.pathToStateValue(this.machine
|
|
633
|
+
.getStateNodeById(historyConfig.target)
|
|
634
|
+
.path.slice(this.path.length - 1))
|
|
635
|
+
: historyConfig.target;
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
target = historyConfig.target;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return target;
|
|
585
642
|
},
|
|
586
643
|
enumerable: true,
|
|
587
644
|
configurable: true
|
|
@@ -597,22 +654,151 @@ var StateNode = /** @class */ (function () {
|
|
|
597
654
|
});
|
|
598
655
|
return stateNodes;
|
|
599
656
|
};
|
|
600
|
-
|
|
657
|
+
/**
|
|
658
|
+
* Returns the leaf nodes from a state path relative to this state node.
|
|
659
|
+
*
|
|
660
|
+
* @param relativeStateId The relative state path to retrieve the state nodes
|
|
661
|
+
* @param history The previous state to retrieve history
|
|
662
|
+
* @param resolve Whether state nodes should resolve to initial child state nodes
|
|
663
|
+
*/
|
|
664
|
+
StateNode.prototype.getRelativeStateNodes = function (relativeStateId, historyValue, resolve) {
|
|
665
|
+
if (resolve === void 0) { resolve = true; }
|
|
601
666
|
if (typeof relativeStateId === 'string' && isStateId(relativeStateId)) {
|
|
602
|
-
|
|
667
|
+
var unresolvedStateNode = this.getStateNodeById(relativeStateId);
|
|
668
|
+
return resolve
|
|
669
|
+
? unresolvedStateNode.history
|
|
670
|
+
? unresolvedStateNode.resolveHistory(historyValue)
|
|
671
|
+
: unresolvedStateNode.initialStateNodes
|
|
672
|
+
: [unresolvedStateNode];
|
|
603
673
|
}
|
|
604
674
|
var statePath = utils_1.toStatePath(relativeStateId, this.delimiter);
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
675
|
+
var rootStateNode = this.parent || this;
|
|
676
|
+
var unresolvedStateNodes = rootStateNode.getFromRelativePath(statePath, historyValue);
|
|
677
|
+
if (!resolve) {
|
|
678
|
+
return unresolvedStateNodes;
|
|
679
|
+
}
|
|
680
|
+
return utils_1.flatMap(unresolvedStateNodes.map(function (stateNode) { return stateNode.initialStateNodes; }));
|
|
681
|
+
};
|
|
682
|
+
Object.defineProperty(StateNode.prototype, "initialStateNodes", {
|
|
683
|
+
get: function () {
|
|
684
|
+
var _this = this;
|
|
685
|
+
// todo - isLeafNode or something
|
|
686
|
+
if (!this.parallel && !this.initial) {
|
|
687
|
+
return [this];
|
|
688
|
+
}
|
|
689
|
+
var initialState = this.initialState;
|
|
690
|
+
var initialStateNodePaths = utils_1.toStatePaths(initialState.value);
|
|
691
|
+
return utils_1.flatMap(initialStateNodePaths.map(function (initialPath) {
|
|
692
|
+
return _this.getFromRelativePath(initialPath);
|
|
693
|
+
}));
|
|
694
|
+
},
|
|
695
|
+
enumerable: true,
|
|
696
|
+
configurable: true
|
|
697
|
+
});
|
|
698
|
+
/**
|
|
699
|
+
* Retrieves state nodes from a relative path to this state node.
|
|
700
|
+
*
|
|
701
|
+
* @param relativePath The relative path from this state node
|
|
702
|
+
* @param historyValue
|
|
703
|
+
*/
|
|
704
|
+
StateNode.prototype.getFromRelativePath = function (relativePath, historyValue) {
|
|
705
|
+
var _this = this;
|
|
706
|
+
if (!relativePath.length) {
|
|
707
|
+
return [this];
|
|
708
|
+
}
|
|
709
|
+
var x = relativePath[0], xs = relativePath.slice(1);
|
|
710
|
+
if (!this.states) {
|
|
711
|
+
throw new Error("Cannot retrieve subPath '" + x + "' from node with no states");
|
|
712
|
+
}
|
|
713
|
+
// TODO: remove (4.0)
|
|
714
|
+
if (x === HISTORY_KEY) {
|
|
715
|
+
if (!historyValue) {
|
|
716
|
+
return [this];
|
|
717
|
+
}
|
|
718
|
+
var subHistoryValue = utils_1.nestedPath(this.path, 'states')(historyValue).current;
|
|
719
|
+
if (typeof subHistoryValue === 'string') {
|
|
720
|
+
return this.states[subHistoryValue].getFromRelativePath(xs, historyValue);
|
|
721
|
+
}
|
|
722
|
+
return utils_1.flatMap(Object.keys(subHistoryValue).map(function (key) {
|
|
723
|
+
return _this.states[key].getFromRelativePath(xs, historyValue);
|
|
724
|
+
}));
|
|
725
|
+
}
|
|
726
|
+
var childStateNode = this.getStateNode(x);
|
|
727
|
+
if (childStateNode.history) {
|
|
728
|
+
return childStateNode.resolveHistory(historyValue);
|
|
729
|
+
}
|
|
730
|
+
if (!this.states[x]) {
|
|
731
|
+
throw new Error("Child state '" + x + "' does not exist on '" + this.id + "'");
|
|
732
|
+
}
|
|
733
|
+
return this.states[x].getFromRelativePath(xs, historyValue);
|
|
734
|
+
};
|
|
735
|
+
StateNode.updateHistoryValue = function (hist, stateValue) {
|
|
736
|
+
function update(_hist, _sv) {
|
|
737
|
+
return utils_1.mapValues(_hist.states, function (subHist, key) {
|
|
738
|
+
if (!subHist) {
|
|
739
|
+
return undefined;
|
|
740
|
+
}
|
|
741
|
+
var subStateValue = (typeof _sv === 'string' ? undefined : _sv[key]) ||
|
|
742
|
+
(subHist ? subHist.current : undefined);
|
|
743
|
+
if (!subStateValue) {
|
|
744
|
+
return undefined;
|
|
609
745
|
}
|
|
610
|
-
return
|
|
611
|
-
|
|
746
|
+
return {
|
|
747
|
+
current: subStateValue,
|
|
748
|
+
states: update(subHist, subStateValue)
|
|
749
|
+
};
|
|
750
|
+
});
|
|
612
751
|
}
|
|
613
|
-
|
|
614
|
-
|
|
752
|
+
return {
|
|
753
|
+
current: stateValue,
|
|
754
|
+
states: update(hist, stateValue)
|
|
755
|
+
};
|
|
756
|
+
};
|
|
757
|
+
StateNode.prototype.historyValue = function (relativeStateValue) {
|
|
758
|
+
if (!Object.keys(this.states).length) {
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
return {
|
|
762
|
+
current: relativeStateValue || this.initialStateValue,
|
|
763
|
+
states: utils_1.mapFilterValues(this.states, function (stateNode, key) {
|
|
764
|
+
if (!relativeStateValue) {
|
|
765
|
+
return stateNode.historyValue();
|
|
766
|
+
}
|
|
767
|
+
var subStateValue = typeof relativeStateValue === 'string'
|
|
768
|
+
? undefined
|
|
769
|
+
: relativeStateValue[key];
|
|
770
|
+
return stateNode.historyValue(subStateValue || stateNode.initialStateValue);
|
|
771
|
+
}, function (stateNode) { return !stateNode.history; })
|
|
772
|
+
};
|
|
773
|
+
};
|
|
774
|
+
/**
|
|
775
|
+
* Resolves to the historical value(s) of the parent state node,
|
|
776
|
+
* represented by state nodes.
|
|
777
|
+
*
|
|
778
|
+
* @param historyValue
|
|
779
|
+
*/
|
|
780
|
+
StateNode.prototype.resolveHistory = function (historyValue) {
|
|
781
|
+
var _this = this;
|
|
782
|
+
if (!this.history) {
|
|
783
|
+
return [this];
|
|
615
784
|
}
|
|
785
|
+
var parent = this.parent;
|
|
786
|
+
if (!historyValue) {
|
|
787
|
+
return this.target
|
|
788
|
+
? utils_1.flatMap(utils_1.toStatePaths(this.target).map(function (relativeChildPath) {
|
|
789
|
+
return parent.getFromRelativePath(relativeChildPath);
|
|
790
|
+
}))
|
|
791
|
+
: this.parent.initialStateNodes;
|
|
792
|
+
}
|
|
793
|
+
var subHistoryValue = utils_1.nestedPath(parent.path, 'states')(historyValue).current;
|
|
794
|
+
if (typeof subHistoryValue === 'string') {
|
|
795
|
+
return [parent.getStateNode(subHistoryValue)];
|
|
796
|
+
}
|
|
797
|
+
return utils_1.flatMap(utils_1.toStatePaths(subHistoryValue).map(function (subStatePath) {
|
|
798
|
+
return _this.history === 'deep'
|
|
799
|
+
? parent.getFromRelativePath(subStatePath)
|
|
800
|
+
: [parent.states[subStatePath[0]]];
|
|
801
|
+
}));
|
|
616
802
|
};
|
|
617
803
|
Object.defineProperty(StateNode.prototype, "events", {
|
|
618
804
|
get: function () {
|
|
@@ -637,26 +823,45 @@ var StateNode = /** @class */ (function () {
|
|
|
637
823
|
enumerable: true,
|
|
638
824
|
configurable: true
|
|
639
825
|
});
|
|
826
|
+
StateNode.prototype.formatTransition = function (targets, transitionConfig) {
|
|
827
|
+
var _this = this;
|
|
828
|
+
var internal = transitionConfig ? transitionConfig.internal : false;
|
|
829
|
+
// Format targets to their full string path
|
|
830
|
+
var formattedTargets = targets.map(function (target) {
|
|
831
|
+
var internalTarget = typeof target === 'string' && target[0] === _this.delimiter;
|
|
832
|
+
internal = internal || internalTarget;
|
|
833
|
+
// If internal target is defined on machine,
|
|
834
|
+
// do not include machine key on target
|
|
835
|
+
if (internalTarget && !_this.parent) {
|
|
836
|
+
return target.slice(1);
|
|
837
|
+
}
|
|
838
|
+
return internalTarget ? _this.key + target : target;
|
|
839
|
+
});
|
|
840
|
+
return __assign({}, transitionConfig, { target: formattedTargets, internal: internal });
|
|
841
|
+
};
|
|
640
842
|
StateNode.prototype.formatTransitions = function (onConfig) {
|
|
843
|
+
var _this = this;
|
|
641
844
|
return utils_1.mapValues(onConfig, function (value) {
|
|
642
845
|
if (value === undefined) {
|
|
643
846
|
return [];
|
|
644
847
|
}
|
|
645
848
|
if (Array.isArray(value)) {
|
|
646
|
-
return value
|
|
849
|
+
return value.map(function (targetTransitionConfig) {
|
|
850
|
+
return _this.formatTransition([].concat(targetTransitionConfig.target), targetTransitionConfig);
|
|
851
|
+
});
|
|
647
852
|
}
|
|
648
853
|
if (typeof value === 'string') {
|
|
649
|
-
return [
|
|
854
|
+
return [_this.formatTransition([value])];
|
|
650
855
|
}
|
|
651
856
|
return Object.keys(value).map(function (target) {
|
|
652
|
-
return
|
|
857
|
+
return _this.formatTransition([target], value[target]);
|
|
653
858
|
});
|
|
654
859
|
});
|
|
655
860
|
};
|
|
656
861
|
return StateNode;
|
|
657
862
|
}());
|
|
658
863
|
exports.StateNode = StateNode;
|
|
659
|
-
function Machine(config) {
|
|
660
|
-
return new StateNode(config);
|
|
864
|
+
function Machine(config, options) {
|
|
865
|
+
return new StateNode(config, options);
|
|
661
866
|
}
|
|
662
867
|
exports.Machine = Machine;
|