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