All files / json-ot/types/ot-binary-irreversible compose.ts

100% Statements 54/54
100% Branches 23/23
100% Functions 1/1
100% Lines 46/46

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  3x                             3x 1006x 1006x 1006x 1006x 1006x 1006x 3026x 3026x 1975x 771x 771x 2098x 2098x 2098x 2098x 2098x 2098x 2098x 2098x 966x 966x   2098x     1204x 1204x 1204x 3709x 3709x 3709x 3709x 3709x 3709x 3709x 1850x 3709x 3709x 1809x 1809x   3709x     1051x 1051x     1006x 1058x 1006x 1006x    
import type {BinaryOp} from './types';
import {append, chunk, componentLength, isDeleteComponent, trim} from './util';
 
/**
 * Combine two operations into one, such that the changes produced by the
 * by the single operation are the same as if the two operations were applied
 * in sequence.
 *
 * ```
 * apply(str, combine(op1, op2)) === apply(apply(str, op1), op2)
 * ```
 *
 * @param op1 First operation.
 * @param op2 Second operation.
 * @returns A combined operation.
 */
export const compose = (op1: BinaryOp, op2: BinaryOp): BinaryOp => {
  const op3: BinaryOp = [];
  const len1 = op1.length;
  const len2 = op2.length;
  let off1 = 0;
  let i1 = 0;
  for (let i2 = 0; i2 < len2; i2++) {
    const comp2 = op2[i2];
    if (typeof comp2 === 'number') {
      if (comp2 > 0) {
        let length2 = comp2;
        while (length2 > 0) {
          const comp1 = op1[i1];
          const comp = i1 >= len1 ? length2 : chunk(comp1, off1, length2);
          const compLength = componentLength(comp);
          const isDelete = isDeleteComponent(comp);
          const length1 = componentLength(comp1 || comp);
          append(op3, comp);
          off1 += compLength;
          if (off1 >= length1) {
            i1++;
            off1 = 0;
          }
          if (!isDelete) length2 -= compLength;
        }
      } else {
        const length2 = -comp2;
        let off2 = 0;
        while (off2 < length2) {
          const remaining = length2 - off2;
          const comp1 = op1[i1];
          const comp = i1 >= len1 ? remaining : chunk(comp1, off1, remaining);
          const compLength = componentLength(comp);
          const isDelete = isDeleteComponent(comp);
          const length1 = componentLength(comp1 || comp);
          if (isDelete) append(op3, comp);
          else if (typeof comp === 'number') append(op3, -compLength);
          off1 += compLength;
          if (off1 >= length1) {
            i1++;
            off1 = 0;
          }
          if (!isDelete) off2 += compLength;
        }
      }
    } else if (comp2 instanceof Uint8Array) {
      append(op3, comp2);
    }
  }
  if (i1 < len1 && off1) append(op3, chunk(op1[i1++], off1, Number.POSITIVE_INFINITY));
  for (; i1 < len1; i1++) append(op3, op1[i1]);
  trim(op3);
  return op3;
};