All files traversalUtils.ts

100% Statements 45/45
92.31% Branches 24/26
100% Functions 16/16
100% Lines 44/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93  3x   3x 44x   44x 58x 30x 58x 69x 58x   11x   11x 4x           11x       44x 29x 33x   33x 4x           33x       44x   44x 159x 7x   44x 7x 20x 15x 15x     5x           44x 30x 7x       44x     3x 94x 127x     94x 127x     122x         94x     3x 85x 44x   41x    
import { StateNode } from 'xstate';
import { toStatePaths, pathToStateValue } from 'xstate/lib/utils';
 
export const getTransitionsFromNode = (node: StateNode): string[] => {
  const transitions = new Set<string>();
 
  if (node.parent) {
    Object.keys(node.parent.states).forEach((key) => transitions.add(key));
    Object.values(node.parent.states).forEach((siblingNode) => {
      getMatchesStates(siblingNode).forEach((key) => {
        if (key === siblingNode.path.join('.')) {
          return;
        }
        let relativeKey = key;
 
        if ((node.parent?.path.length || 0) > 0) {
          relativeKey = relativeKey.replace(
            new RegExp(`^${(node.parent as StateNode).path.join('.')}\.`),
            '',
          );
        }
 
        transitions.add(relativeKey);
      });
    });
  }
  Object.values(node.states).map((childNode) => {
    getMatchesStates(childNode).map((key) => {
      let relativeKey = key;
 
      if ((childNode.parent?.path.length || 0) > 0) {
        relativeKey = relativeKey.replace(
          new RegExp(`^${(childNode.parent as StateNode).path.join('.')}\.`),
          '',
        );
      }
 
      transitions.add(`.${relativeKey}`);
    });
  });
 
  const rootNode = getRootNode(node);
 
  const nodesWithId = rootNode.stateIds
    .filter((id) => !/(\.|\(machine\))/.test(id))
    .map((id) => rootNode.getStateNodeById(id));
 
  nodesWithId.forEach((idNode) => {
    getMatchesStates(idNode).forEach((match) => {
      if (idNode.id === rootNode.id) {
        transitions.add(`#${idNode.id}.${match}`);
        return;
      }
 
      transitions.add(
        match.replace(new RegExp(`^${idNode.path.join('.')}`), `#${idNode.id}`),
      );
    });
  });
 
  toStatePaths(pathToStateValue(node.path)).forEach((path) => {
    if (path.length > 1) {
      transitions.delete(path.join('.'));
    }
  });
 
  return Array.from(transitions);
};
 
export const getMatchesStates = (machine: StateNode) => {
  const allStateNodes = machine.stateIds.map((id) =>
    machine.getStateNodeById(id),
  );
 
  const states = allStateNodes.reduce((arr: string[], node) => {
    return [
      ...arr,
      ...toStatePaths(pathToStateValue(node.path)).map((path) =>
        path.join('.'),
      ),
    ];
  }, [] as string[]);
 
  return states;
};
 
export const getRootNode = (node: StateNode): StateNode => {
  if (!node.parent) {
    return node;
  }
  return getRootNode(node.parent);
};