code: private void introduceMoveOperation() {
          for (int i = 0; i < diffs.size(); i++) {
              Diff diff1 = diffs.get(i);
  
              // if not remove OR add, move to next diff
              if (!(Operation.REMOVE == diff1.getOperation() ||
                      Operation.ADD == diff1.getOperation())) {
                  continue;
              }
  
              for (int j = i + 1; j < diffs.size(); j++) {
                  Diff diff2 = diffs.get(j);
                  if (!diff1.getValue().equals(diff2.getValue())) {
                      continue;
                  }
  
                  Diff moveDiff = null;
                  if (Operation.REMOVE == diff1.getOperation() &&
                          Operation.ADD == diff2.getOperation()) {
                      JsonPointer relativePath = computeRelativePath(diff2.getPath(), i + 1, j - 1, diffs);
                      moveDiff = new Diff(Operation.MOVE, diff1.getPath(), relativePath);
  
                  } else if (Operation.ADD == diff1.getOperation() &&
                          Operation.REMOVE == diff2.getOperation()) {
                      JsonPointer relativePath = computeRelativePath(diff2.getPath(), i, j - 1, diffs); // diff1's add should also be considered
                      moveDiff = new Diff(Operation.MOVE, relativePath, diff1.getPath());
                  }
                  if (moveDiff != null) {
                      diffs.remove(j);
                      diffs.set(i, moveDiff);
                      break;
                  }
              }
          }
      }
docs: This method merge 2 diffs ( remove then add, or vice versa ) with same value into one Move operation,
  all the core logic resides here only