json-joy
Version:
Collection of libraries for building collaborative editing apps.
84 lines (83 loc) • 3.15 kB
JavaScript
/**
* @description Operations for combining patches together, combining operations
* together, and cleaning up operations.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.compact = exports.combine = void 0;
const clock_1 = require("./clock");
const operations_1 = require("./operations");
/**
* Combines two or more patches together. The first patch is modified in place.
* Operations from the second patch are appended to the first patch as is
* (without cloning).
*
* The patches must have the same `sid`. The first patch must have lower logical
* time than the second patch, and the logical times must not overlap.
*
* @param patches The patches to combine.
*/
const combine = (patches) => {
const firstPatch = patches[0];
const firstPatchId = firstPatch.getId();
const patchesLength = patches.length;
for (let i = 1; i < patchesLength; i++) {
const currentPatch = patches[i];
const currentPatchId = currentPatch.getId();
if (!firstPatchId) {
if (!currentPatchId)
return;
firstPatch.ops = firstPatch.ops.concat(currentPatch.ops);
return;
}
if (!currentPatchId)
return;
if (!firstPatchId || !currentPatchId)
throw new Error('EMPTY_PATCH');
const sidA = firstPatchId.sid;
if (sidA !== currentPatchId.sid)
throw new Error('SID_MISMATCH');
const timeA = firstPatchId.time;
const nextTick = timeA + firstPatch.span();
const timeB = currentPatchId.time;
const timeDiff = timeB - nextTick;
if (timeDiff < 0)
throw new Error('TIMESTAMP_CONFLICT');
const needsNoop = timeDiff > 0;
if (needsNoop)
firstPatch.ops.push(new operations_1.NopOp(new clock_1.Timestamp(sidA, nextTick), timeDiff));
firstPatch.ops = firstPatch.ops.concat(currentPatch.ops);
}
};
exports.combine = combine;
/**
* Compacts operations within a patch. Combines consecutive string inserts.
* Mutates the operations in place. (Use `patch.clone()` to avoid mutating the
* original patch.)
*
* @param patch The patch to compact.
*/
const compact = (patch) => {
const ops = patch.ops;
const length = ops.length;
let lastOp = ops[0];
const newOps = [lastOp];
for (let i = 1; i < length; i++) {
const op = ops[i];
if (lastOp instanceof operations_1.InsStrOp && op instanceof operations_1.InsStrOp) {
const lastOpNextTick = lastOp.id.time + lastOp.span();
const isTimeConsecutive = lastOpNextTick === op.id.time;
const isInsertIntoSameString = (0, clock_1.equal)(lastOp.obj, op.obj);
const opRef = op.ref;
const isAppend = lastOpNextTick === opRef.time + 1 && lastOp.ref.sid === opRef.sid;
if (isTimeConsecutive && isInsertIntoSameString && isAppend) {
lastOp.data = lastOp.data + op.data;
continue;
}
}
newOps.push(op);
lastOp = op;
}
patch.ops = newOps;
};
exports.compact = compact;
;