All files / src redo.ts

100% Statements 27/27
87.5% Branches 14/16
100% Functions 4/4
100% Lines 27/27
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 94 95 96 97 98 99 1005x                           5x           14x 14x 14x             14x                         31x   14x   14x 17x   7x     10x 10x     10x   10x 10x     31x                 14x   14x   22x           22x   22x         14x 14x 14x 14x         14x      
import {
  getConfig,
  pipeActions,
  setConfig,
  updateCanUndoRedo
} from "./utils-undo-redo";
 
/**
 * The Redo function - commits the latest undone mutation to the store,
 * and pushes it to the done stack
 *
 * @module store/plugins/undoRedo:redo
 * @function
 */
export default ({
  paths,
  store
}: {
  paths: UndoRedoOptions[];
  store: any;
}) => async (namespace: string) => {
  const config = getConfig(paths)(namespace);
  Eif (Object.keys(config).length) {
    /**
     * @var {Array} undone - The updated undone stack
     * @var {Array} commits - The list of mutations to be redone
     * NB: The reduceRight operation is used to identify the mutation(s) from the
     * top of the undone stack to be redone
     */
    const { undone, commits } = config.undone.reduceRight(
      (
        {
          commits,
          undone,
          proceed
        }: {
          commits: Array<Mutation> | [];
          undone: Array<Mutation> | [];
          proceed: boolean;
        },
        m: Mutation
      ) => {
        if (!commits.length) {
          // The "topmost" mutation
          commits = [m];
          // Do not find more mutations if the mutations does not belong to a group
          proceed = !!m.payload.actionGroup;
        } else if (!proceed) {
          // The mutation(s) to redo have been identified
          undone = [m, ...undone];
        } else {
          // Find mutations belonging to the same actionGroup
          const lastCommit = commits[commits.length - 1];
          const { actionGroup } = lastCommit.payload;
          // Stop finding more mutations if the current mutation belongs to
          // another actionGroup, or does not have an actionGroup
          proceed =
            m.payload.actionGroup && m.payload.actionGroup === actionGroup;
          commits = [...(proceed ? [m] : []), ...commits];
          undone = [...(proceed ? [] : [m]), ...undone];
        }
 
        return { commits, undone, proceed };
      },
      {
        commits: [],
        undone: [],
        proceed: true
      }
    );
 
    config.newMutation = false;
    // NB: The array of redoCallbacks and respective action payloads
    const redoCallbacks = commits.map(async ({ type, payload }: Mutation) => {
      // NB: Commit each mutation in the redo stack
      store.commit(
        type,
        Array.isArray(payload) ? [...payload] : payload.constructor(payload)
      );
 
      // Check if there is an redo callback action
      const { redoCallback } = payload;
      // NB: The object containing the redoCallback action and payload
      return {
        action: redoCallback ? `${namespace}${redoCallback}` : "",
        payload
      };
    });
    await pipeActions(store)(await Promise.all(redoCallbacks));
    config.done = [...config.done, ...commits];
    config.newMutation = true;
    setConfig(paths)(namespace, {
      ...config,
      undone
    });
 
    updateCanUndoRedo({ paths, store })(namespace);
  }
};