xstate 3.3.2 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xstate",
3
- "version": "3.3.2",
3
+ "version": "3.3.3",
4
4
  "description": "Simple JavaScript Finite State Machines and Statecharts",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -36,11 +36,11 @@
36
36
  "@types/node": "^8.9.4",
37
37
  "chai": "^4.1.2",
38
38
  "mocha": "^3.5.3",
39
- "prettier": "^1.7.0",
39
+ "prettier": "^1.13.5",
40
40
  "scxml-test-framework": "^1.0.2",
41
41
  "ts-node": "^3.3.0",
42
42
  "tslint": "^5.7.0",
43
- "typescript": "^2.8.3",
43
+ "typescript": "^2.9.2",
44
44
  "webpack": "^3.5.6",
45
45
  "xml-js": "^1.6.2"
46
46
  },
package/src/State.ts CHANGED
@@ -3,7 +3,8 @@ import {
3
3
  ActivityMap,
4
4
  EventObject,
5
5
  Action,
6
- StateInterface
6
+ StateInterface,
7
+ HistoryValue
7
8
  } from './types';
8
9
  import { STATE_DELIMITER, EMPTY_ACTIVITY_MAP } from './constants';
9
10
 
@@ -22,6 +23,7 @@ export class State implements StateInterface {
22
23
  }
23
24
  return new State(
24
25
  stateValue.value,
26
+ stateValue.historyValue,
25
27
  stateValue.history,
26
28
  [],
27
29
  stateValue.activities
@@ -33,6 +35,7 @@ export class State implements StateInterface {
33
35
 
34
36
  constructor(
35
37
  public value: StateValue,
38
+ public historyValue?: HistoryValue | undefined,
36
39
  public history?: State,
37
40
  public actions: Action[] = [],
38
41
  public activities: ActivityMap = EMPTY_ACTIVITY_MAP,
package/src/StateNode.ts CHANGED
@@ -9,7 +9,8 @@ import {
9
9
  pathToStateValue,
10
10
  getActionType,
11
11
  flatMap,
12
- mapFilterValues
12
+ mapFilterValues,
13
+ nestedPath
13
14
  } from './utils';
14
15
  import {
15
16
  Event,
@@ -20,7 +21,6 @@ import {
20
21
  StandardMachine,
21
22
  ParallelMachine,
22
23
  SimpleOrCompoundStateNodeConfig,
23
- MachineConfig,
24
24
  ParallelMachineConfig,
25
25
  EventType,
26
26
  StandardMachineConfig,
@@ -30,14 +30,15 @@ import {
30
30
  ConditionalTransitionConfig,
31
31
  EntryExitStates,
32
32
  TargetTransitionConfig,
33
- _StateTransition,
33
+ StateTransition,
34
34
  ActionObject,
35
35
  StateValueMap,
36
36
  MachineOptions,
37
37
  Condition,
38
38
  ConditionPredicate,
39
39
  EventObject,
40
- HistoryStateNodeConfig
40
+ HistoryStateNodeConfig,
41
+ HistoryValue
41
42
  } from './types';
42
43
  import { matchesState } from './matchesState';
43
44
  import { State } from './State';
@@ -48,16 +49,11 @@ const HISTORY_KEY = '$history';
48
49
  const NULL_EVENT = '';
49
50
  const STATE_IDENTIFIER = '#';
50
51
  const isStateId = (str: string) => str[0] === STATE_IDENTIFIER;
51
- // const emptyActions: ActionMap = Object.freeze({
52
- // onEntry: [],
53
- // onExit: [],
54
- // actions: []
55
- // });
56
52
  const defaultOptions: MachineOptions = {
57
53
  guards: {}
58
54
  };
59
55
 
60
- class StateNode implements StateNode {
56
+ class StateNode {
61
57
  public key: string;
62
58
  public id: string;
63
59
  public path: string[];
@@ -106,21 +102,21 @@ class StateNode implements StateNode {
106
102
  this.initial = config.initial;
107
103
  this.parallel = !!config.parallel;
108
104
  this.states = (config.states
109
- ? mapValues<
110
- SimpleOrCompoundStateNodeConfig,
111
- StateNode
112
- >(config.states, (stateConfig, key) => {
113
- const stateNode = new StateNode({
114
- ...stateConfig,
115
- key,
116
- parent: this
117
- });
118
- Object.assign(this.idMap, {
119
- [stateNode.id]: stateNode,
120
- ...stateNode.idMap
121
- });
122
- return stateNode;
123
- })
105
+ ? mapValues<SimpleOrCompoundStateNodeConfig, StateNode>(
106
+ config.states,
107
+ (stateConfig, key) => {
108
+ const stateNode = new StateNode({
109
+ ...stateConfig,
110
+ key,
111
+ parent: this
112
+ });
113
+ Object.assign(this.idMap, {
114
+ [stateNode.id]: stateNode,
115
+ ...stateNode.idMap
116
+ });
117
+ return stateNode;
118
+ }
119
+ )
124
120
  : {}) as Record<string, StateNode>;
125
121
 
126
122
  // History config
@@ -177,12 +173,12 @@ class StateNode implements StateNode {
177
173
 
178
174
  return this.events.indexOf(eventType) !== -1;
179
175
  }
180
- public _transitionLeafNode(
176
+ private _transitionLeafNode(
181
177
  stateValue: string,
182
178
  state: State,
183
179
  event: Event,
184
180
  extendedState?: any
185
- ): _StateTransition {
181
+ ): StateTransition {
186
182
  const stateNode = this.getStateNode(stateValue);
187
183
  const next = stateNode._next(state, event, extendedState);
188
184
 
@@ -201,7 +197,7 @@ class StateNode implements StateNode {
201
197
  stateNode,
202
198
  ...(entryExitStates
203
199
  ? Array.from(entryExitStates.exit)
204
- : [] as StateNode[])
200
+ : ([] as StateNode[]))
205
201
  ])
206
202
  },
207
203
  actions,
@@ -211,12 +207,12 @@ class StateNode implements StateNode {
211
207
 
212
208
  return next;
213
209
  }
214
- public _transitionHierarchicalNode(
210
+ private _transitionHierarchicalNode(
215
211
  stateValue: StateValueMap,
216
212
  state: State,
217
213
  event: Event,
218
214
  extendedState?: any
219
- ): _StateTransition {
215
+ ): StateTransition {
220
216
  const subStateKeys = Object.keys(stateValue);
221
217
 
222
218
  const stateNode = this.getStateNode(subStateKeys[0]);
@@ -245,7 +241,7 @@ class StateNode implements StateNode {
245
241
  stateNode,
246
242
  ...(entryExitStates
247
243
  ? Array.from(entryExitStates.exit)
248
- : [] as StateNode[])
244
+ : ([] as StateNode[]))
249
245
  ])
250
246
  },
251
247
  actions,
@@ -255,14 +251,15 @@ class StateNode implements StateNode {
255
251
 
256
252
  return next;
257
253
  }
258
- public _transitionOrthogonalNode(
254
+ private _transitionOrthogonalNode(
259
255
  stateValue: StateValueMap,
260
256
  state: State,
261
257
  event: Event,
262
258
  extendedState?: any
263
- ): _StateTransition {
259
+ ): StateTransition {
264
260
  const noTransitionKeys: string[] = [];
265
- const transitionMap: Record<string, _StateTransition> = {};
261
+ const transitionMap: Record<string, StateTransition> = {};
262
+
266
263
  Object.keys(stateValue).forEach(subStateKey => {
267
264
  const subStateValue = stateValue[subStateKey];
268
265
 
@@ -351,12 +348,11 @@ class StateNode implements StateNode {
351
348
  const allResolvedPaths = flatMap(
352
349
  Object.keys(transitionMap).map(key => {
353
350
  const transition = transitionMap[key];
354
- if (!transition.value) {
355
- return toStatePaths(
356
- path(this.path)(state.value)[key]
357
- ).map(statePath => this.path.concat(key, statePath));
358
- }
359
- return transition.paths;
351
+ const value = transition.value || state.value;
352
+
353
+ return toStatePaths(path(this.path)(value)[key]).map(statePath =>
354
+ this.path.concat(key, statePath)
355
+ );
360
356
  })
361
357
  );
362
358
 
@@ -404,7 +400,7 @@ class StateNode implements StateNode {
404
400
  state: State,
405
401
  event: Event,
406
402
  extendedState?: any
407
- ): _StateTransition {
403
+ ): StateTransition {
408
404
  // leaf node
409
405
  if (typeof stateValue === 'string') {
410
406
  return this._transitionLeafNode(stateValue, state, event, extendedState);
@@ -428,11 +424,11 @@ class StateNode implements StateNode {
428
424
  extendedState
429
425
  );
430
426
  }
431
- public _next(
427
+ private _next(
432
428
  state: State,
433
429
  event: Event,
434
430
  extendedState?: any
435
- ): _StateTransition {
431
+ ): StateTransition {
436
432
  const eventType = getEventType(event);
437
433
  const candidates = this.on[eventType];
438
434
  const actions: Action[] = this.transient
@@ -497,7 +493,7 @@ class StateNode implements StateNode {
497
493
 
498
494
  const nextStateNodes = flatMap(
499
495
  nextStateStrings.map(str =>
500
- this.getRelativeStateNodes(str, state.history)
496
+ this.getRelativeStateNodes(str, state.historyValue)
501
497
  )
502
498
  );
503
499
 
@@ -529,7 +525,9 @@ class StateNode implements StateNode {
529
525
  pathsToStateValue(
530
526
  flatMap(
531
527
  nextStateStrings.map(str =>
532
- this.getRelativeStateNodes(str, state.history).map(s => s.path)
528
+ this.getRelativeStateNodes(str, state.historyValue).map(
529
+ s => s.path
530
+ )
533
531
  )
534
532
  )
535
533
  )
@@ -539,7 +537,7 @@ class StateNode implements StateNode {
539
537
  paths: nextStatePaths
540
538
  };
541
539
  }
542
- public _getEntryExitStates(
540
+ private _getEntryExitStates(
543
541
  nextStateNode: StateNode,
544
542
  internal: boolean
545
543
  ): EntryExitStates {
@@ -602,8 +600,9 @@ class StateNode implements StateNode {
602
600
  if (typeof condition === 'string') {
603
601
  if (!this.machine.options.guards[condition]) {
604
602
  throw new Error(
605
- `String condition '${condition}' is not defined on machine '${this
606
- .machine.id}'`
603
+ `String condition '${condition}' is not defined on machine '${
604
+ this.machine.id
605
+ }'`
607
606
  );
608
607
  }
609
608
 
@@ -614,7 +613,7 @@ class StateNode implements StateNode {
614
613
 
615
614
  return condFn(extendedState, eventObject, interimState);
616
615
  }
617
- private _getActions(transition: _StateTransition): Action[] {
616
+ private _getActions(transition: StateTransition): Action[] {
618
617
  const entryExitActions = {
619
618
  entry: transition.entryExitStates
620
619
  ? flatMap(
@@ -646,7 +645,7 @@ class StateNode implements StateNode {
646
645
  }
647
646
  private _getActivities(
648
647
  state: State,
649
- transition: _StateTransition
648
+ transition: StateTransition
650
649
  ): ActivityMap {
651
650
  if (!transition.entryExitStates) {
652
651
  return {};
@@ -654,23 +653,23 @@ class StateNode implements StateNode {
654
653
 
655
654
  const activityMap = { ...state.activities };
656
655
 
657
- Array.from(transition.entryExitStates.entry).forEach(stateNode => {
656
+ Array.from(transition.entryExitStates.exit).forEach(stateNode => {
658
657
  if (!stateNode.activities) {
659
658
  return; // TODO: fixme
660
659
  }
661
660
 
662
661
  stateNode.activities.forEach(activity => {
663
- activityMap[getActionType(activity)] = true;
662
+ activityMap[getActionType(activity)] = false;
664
663
  });
665
664
  });
666
665
 
667
- Array.from(transition.entryExitStates.exit).forEach(stateNode => {
666
+ Array.from(transition.entryExitStates.entry).forEach(stateNode => {
668
667
  if (!stateNode.activities) {
669
668
  return; // TODO: fixme
670
669
  }
671
670
 
672
671
  stateNode.activities.forEach(activity => {
673
- activityMap[getActionType(activity)] = false;
672
+ activityMap[getActionType(activity)] = true;
674
673
  });
675
674
  });
676
675
 
@@ -684,7 +683,9 @@ class StateNode implements StateNode {
684
683
  const resolvedStateValue =
685
684
  typeof state === 'string'
686
685
  ? this.resolve(pathToStateValue(this.getResolvedPath(state)))
687
- : state instanceof State ? state : this.resolve(state);
686
+ : state instanceof State
687
+ ? state
688
+ : this.resolve(state);
688
689
 
689
690
  const eventType = getEventType(event);
690
691
 
@@ -698,6 +699,15 @@ class StateNode implements StateNode {
698
699
 
699
700
  const currentState = State.from(resolvedStateValue);
700
701
 
702
+ const historyValue =
703
+ resolvedStateValue instanceof State
704
+ ? resolvedStateValue.historyValue
705
+ ? resolvedStateValue.historyValue
706
+ : (this.machine.historyValue(
707
+ resolvedStateValue.value
708
+ ) as HistoryValue)
709
+ : (this.machine.historyValue(resolvedStateValue) as HistoryValue);
710
+
701
711
  const stateTransition = this._transition(
702
712
  currentState.value,
703
713
  currentState,
@@ -741,12 +751,10 @@ class StateNode implements StateNode {
741
751
  data[stateNode.id] = stateNode.data;
742
752
  });
743
753
 
744
- // Dispose of previous histories to prevent memory leaks
745
- delete currentState.history;
746
-
747
754
  const nextState = stateTransition.value
748
755
  ? new State(
749
756
  stateTransition.value,
757
+ StateNode.updateHistoryValue(historyValue, stateTransition.value),
750
758
  currentState,
751
759
  nonEventActions,
752
760
  activities,
@@ -760,6 +768,9 @@ class StateNode implements StateNode {
760
768
  return State.inert(currentState);
761
769
  }
762
770
 
771
+ // Dispose of previous histories to prevent memory leaks
772
+ delete currentState.history;
773
+
763
774
  let maybeNextState = nextState;
764
775
  while (raisedEvents.length) {
765
776
  const currentActions = maybeNextState.actions;
@@ -791,10 +802,11 @@ class StateNode implements StateNode {
791
802
  }
792
803
 
793
804
  throw new Error(
794
- `State node '${stateNode.id}' shares parent '${marker.parent
795
- .id}' with state node '${visitedParents.get(marker.parent)!.map(
796
- a => a.id
797
- )}'`
805
+ `State node '${stateNode.id}' shares parent '${
806
+ marker.parent.id
807
+ }' with state node '${visitedParents
808
+ .get(marker.parent)!
809
+ .map(a => a.id)}'`
798
810
  );
799
811
  }
800
812
 
@@ -815,8 +827,9 @@ class StateNode implements StateNode {
815
827
 
816
828
  if (!this.states) {
817
829
  throw new Error(
818
- `Unable to retrieve child state '${stateKey}' from '${this
819
- .id}'; no child states exist.`
830
+ `Unable to retrieve child state '${stateKey}' from '${
831
+ this.id
832
+ }'; no child states exist.`
820
833
  );
821
834
  }
822
835
 
@@ -843,6 +856,16 @@ class StateNode implements StateNode {
843
856
 
844
857
  return stateNode;
845
858
  }
859
+ public getStateNodeByPath(statePath: string | string[]): StateNode {
860
+ const arrayStatePath = toStatePath(statePath, this.delimiter);
861
+ let currentStateNode: StateNode = this;
862
+ while (arrayStatePath.length) {
863
+ const key = arrayStatePath.shift()!;
864
+ currentStateNode = currentStateNode.getStateNode(key);
865
+ }
866
+
867
+ return currentStateNode;
868
+ }
846
869
  private resolve(stateValue: StateValue): StateValue {
847
870
  if (typeof stateValue === 'string') {
848
871
  const subStateNode = this.getStateNode(stateValue);
@@ -951,7 +974,34 @@ class StateNode implements StateNode {
951
974
  }
952
975
  });
953
976
 
954
- return new State(initialStateValue, undefined, actions, activityMap);
977
+ // TODO: deduplicate - DRY (from this.transition())
978
+ const raisedEvents = actions.filter(
979
+ action =>
980
+ typeof action === 'object' &&
981
+ (action.type === actionTypes.raise || action.type === actionTypes.null)
982
+ ) as ActionObject[];
983
+
984
+ const initialState = new State(
985
+ initialStateValue,
986
+ undefined,
987
+ undefined,
988
+ actions,
989
+ activityMap
990
+ );
991
+
992
+ let maybeNextState = initialState;
993
+ while (raisedEvents.length) {
994
+ const currentActions = maybeNextState.actions;
995
+ const raisedEvent = raisedEvents.shift()!;
996
+ maybeNextState = this.transition(
997
+ maybeNextState,
998
+ raisedEvent.type === actionTypes.null ? NULL_EVENT : raisedEvent.event,
999
+ undefined // TODO: consider initial state given external state
1000
+ );
1001
+ maybeNextState.actions.unshift(...currentActions);
1002
+ }
1003
+
1004
+ return maybeNextState;
955
1005
  }
956
1006
  public get target(): StateValue | undefined {
957
1007
  let target;
@@ -995,10 +1045,9 @@ class StateNode implements StateNode {
995
1045
  */
996
1046
  public getRelativeStateNodes(
997
1047
  relativeStateId: string | string[],
998
- history?: State,
1048
+ historyValue?: HistoryValue,
999
1049
  resolve: boolean = true
1000
1050
  ): StateNode[] {
1001
- const historyValue = history ? history.value : undefined;
1002
1051
  if (typeof relativeStateId === 'string' && isStateId(relativeStateId)) {
1003
1052
  const unresolvedStateNode = this.getStateNodeById(relativeStateId);
1004
1053
 
@@ -1039,9 +1088,15 @@ class StateNode implements StateNode {
1039
1088
  )
1040
1089
  );
1041
1090
  }
1091
+ /**
1092
+ * Retrieves state nodes from a relative path to this state node.
1093
+ *
1094
+ * @param relativePath The relative path from this state node
1095
+ * @param historyValue
1096
+ */
1042
1097
  public getFromRelativePath(
1043
1098
  relativePath: string[],
1044
- historyValue?: StateValue
1099
+ historyValue?: HistoryValue
1045
1100
  ): StateNode[] {
1046
1101
  if (!relativePath.length) {
1047
1102
  return [this];
@@ -1060,7 +1115,10 @@ class StateNode implements StateNode {
1060
1115
  if (!historyValue) {
1061
1116
  return [this];
1062
1117
  }
1063
- const subHistoryValue = path(this.path)(historyValue);
1118
+
1119
+ const subHistoryValue = nestedPath<HistoryValue>(this.path, 'states')(
1120
+ historyValue
1121
+ ).current;
1064
1122
 
1065
1123
  if (typeof subHistoryValue === 'string') {
1066
1124
  return this.states[subHistoryValue].getFromRelativePath(
@@ -1070,7 +1128,7 @@ class StateNode implements StateNode {
1070
1128
  }
1071
1129
 
1072
1130
  return flatMap(
1073
- Object.keys(subHistoryValue).map(key => {
1131
+ Object.keys(subHistoryValue!).map(key => {
1074
1132
  return this.states[key].getFromRelativePath(xs, historyValue);
1075
1133
  })
1076
1134
  );
@@ -1088,7 +1146,73 @@ class StateNode implements StateNode {
1088
1146
 
1089
1147
  return this.states[x].getFromRelativePath(xs, historyValue);
1090
1148
  }
1091
- private resolveHistory(historyValue?: StateValue): StateNode[] {
1149
+ public static updateHistoryValue(
1150
+ hist: HistoryValue,
1151
+ stateValue: StateValue
1152
+ ): HistoryValue {
1153
+ function update(
1154
+ _hist: HistoryValue,
1155
+ _sv: StateValue
1156
+ ): Record<string, HistoryValue | undefined> {
1157
+ return mapValues(_hist.states, (subHist, key) => {
1158
+ if (!subHist) {
1159
+ return undefined;
1160
+ }
1161
+ const subStateValue =
1162
+ (typeof _sv === 'string' ? undefined : _sv[key]) ||
1163
+ (subHist ? subHist.current : undefined);
1164
+
1165
+ if (!subStateValue) {
1166
+ return undefined;
1167
+ }
1168
+
1169
+ return {
1170
+ current: subStateValue,
1171
+ states: update(subHist, subStateValue)
1172
+ };
1173
+ });
1174
+ }
1175
+ return {
1176
+ current: stateValue,
1177
+ states: update(hist, stateValue)
1178
+ };
1179
+ }
1180
+ public historyValue(
1181
+ relativeStateValue?: StateValue | undefined
1182
+ ): HistoryValue | undefined {
1183
+ if (!Object.keys(this.states).length) {
1184
+ return undefined;
1185
+ }
1186
+
1187
+ return {
1188
+ current: relativeStateValue || this.initialStateValue,
1189
+ states: mapFilterValues(
1190
+ this.states,
1191
+ (stateNode, key) => {
1192
+ if (!relativeStateValue) {
1193
+ return stateNode.historyValue();
1194
+ }
1195
+
1196
+ const subStateValue =
1197
+ typeof relativeStateValue === 'string'
1198
+ ? undefined
1199
+ : relativeStateValue[key];
1200
+
1201
+ return stateNode.historyValue(
1202
+ subStateValue || stateNode.initialStateValue
1203
+ );
1204
+ },
1205
+ stateNode => !stateNode.history
1206
+ )
1207
+ };
1208
+ }
1209
+ /**
1210
+ * Resolves to the historical value(s) of the parent state node,
1211
+ * represented by state nodes.
1212
+ *
1213
+ * @param historyValue
1214
+ */
1215
+ private resolveHistory(historyValue?: HistoryValue): StateNode[] {
1092
1216
  if (!this.history) {
1093
1217
  return [this];
1094
1218
  }
@@ -1099,25 +1223,27 @@ class StateNode implements StateNode {
1099
1223
  return this.target
1100
1224
  ? flatMap(
1101
1225
  toStatePaths(this.target).map(relativeChildPath =>
1102
- parent.getFromRelativePath(relativeChildPath, historyValue)
1226
+ parent.getFromRelativePath(relativeChildPath)
1103
1227
  )
1104
1228
  )
1105
1229
  : this.parent!.initialStateNodes;
1106
- } else {
1107
- const subHistoryValue = path(parent.path)(historyValue);
1230
+ }
1108
1231
 
1109
- if (typeof subHistoryValue === 'string') {
1110
- return [parent.getStateNode(subHistoryValue)];
1111
- }
1232
+ const subHistoryValue = nestedPath<HistoryValue>(parent.path, 'states')(
1233
+ historyValue
1234
+ ).current;
1112
1235
 
1113
- return flatMap(
1114
- toStatePaths(subHistoryValue).map(subStatePath => {
1115
- return this.history === 'deep'
1116
- ? parent.getFromRelativePath(subStatePath)
1117
- : [parent.states[subStatePath[0]]];
1118
- })
1119
- );
1236
+ if (typeof subHistoryValue === 'string') {
1237
+ return [parent.getStateNode(subHistoryValue)];
1120
1238
  }
1239
+
1240
+ return flatMap(
1241
+ toStatePaths(subHistoryValue!).map(subStatePath => {
1242
+ return this.history === 'deep'
1243
+ ? parent.getFromRelativePath(subStatePath)
1244
+ : [parent.states[subStatePath[0]]];
1245
+ })
1246
+ );
1121
1247
  }
1122
1248
  get events(): EventType[] {
1123
1249
  if (this.__cache.events) {
@@ -1194,11 +1320,17 @@ class StateNode implements StateNode {
1194
1320
  }
1195
1321
  }
1196
1322
 
1197
- export function Machine(
1198
- config: MachineConfig | ParallelMachineConfig,
1199
- options: MachineOptions
1200
- ): StandardMachine | ParallelMachine {
1201
- return new StateNode(config, options) as StandardMachine | ParallelMachine;
1323
+ export function Machine<
1324
+ T extends StandardMachineConfig | ParallelMachineConfig
1325
+ >(
1326
+ config: T,
1327
+ options?: MachineOptions
1328
+ ): T extends ParallelMachineConfig
1329
+ ? ParallelMachine
1330
+ : T extends StandardMachineConfig ? StandardMachine : never {
1331
+ return new StateNode(config, options) as T extends ParallelMachineConfig
1332
+ ? ParallelMachine
1333
+ : T extends StandardMachineConfig ? StandardMachine : never;
1202
1334
  }
1203
1335
 
1204
1336
  export { StateNode };
package/src/graph.ts CHANGED
@@ -16,20 +16,21 @@ const EMPTY_MAP = {};
16
16
 
17
17
  export function getNodes(node: StateNode): StateNode[] {
18
18
  const { states } = node;
19
- const nodes = Object.keys(
20
- states
21
- ).reduce((accNodes: StateNode[], stateKey) => {
22
- const subState = states[stateKey];
23
- const subNodes = getNodes(states[stateKey]);
24
-
25
- accNodes.push(subState, ...subNodes);
26
- return accNodes;
27
- }, []);
19
+ const nodes = Object.keys(states).reduce(
20
+ (accNodes: StateNode[], stateKey) => {
21
+ const subState = states[stateKey];
22
+ const subNodes = getNodes(states[stateKey]);
23
+
24
+ accNodes.push(subState, ...subNodes);
25
+ return accNodes;
26
+ },
27
+ []
28
+ );
28
29
 
29
30
  return nodes;
30
31
  }
31
32
 
32
- function getEventEdges(node: StateNode, event: string): Edge[] {
33
+ export function getEventEdges(node: StateNode, event: string): Edge[] {
33
34
  const transitions = node.on[event]!;
34
35
 
35
36
  return flatMap(
@@ -55,10 +56,11 @@ function getEventEdges(node: StateNode, event: string): Edge[] {
55
56
  );
56
57
  }
57
58
 
58
- export function getEdges(node: StateNode): Edge[] {
59
+ export function getEdges(node: StateNode, options?: { deep: boolean }): Edge[] {
60
+ const { deep = true } = options || {};
59
61
  const edges: Edge[] = [];
60
62
 
61
- if (node.states) {
63
+ if (node.states && deep) {
62
64
  Object.keys(node.states).forEach(stateKey => {
63
65
  edges.push(...getEdges(node.states[stateKey]));
64
66
  });