Skip to content

Commit 4e5bd5e

Browse files
committed
Changeset: Migrate from mergingOpAssembler() to squashOps()
1 parent 763e92c commit 4e5bd5e

File tree

4 files changed

+59
-53
lines changed

4 files changed

+59
-53
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
generator function. Also, the unused start index parameter has been
4646
removed, as has the unused `lastIndex()` method on the returned object.
4747
* `opAssembler()`: Deprecated in favor of the new `serializeOps()` function.
48+
* `mergingOpAssembler()`: Deprecated in favor of the new `squashOps()`
49+
generator function (combined with `serializeOps()`).
4850
* `smartOpAssembler()`: The returned object's `appendOpWithText()` method is
4951
deprecated without a replacement available to plugins (if you need one,
5052
let us know and we can make the private `opsFromText()` function public).

src/static/js/Changeset.js

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ class OpAssembler {
356356
* @yields {Op} The squashed operations.
357357
* @returns {Generator<Op>}
358358
*/
359-
const squashOps = function* (ops, finalize) {
359+
exports.squashOps = function* (ops, finalize) {
360360
let prevOp = new Op();
361361
// If we get, for example, insertions [xxx\n,yyy], those don't merge, but if we get
362362
// [xxx\n,yyy,zzz\n], that merges to [xxx\nyyyzzz\n]. This variable stores the length of yyy and
@@ -415,7 +415,7 @@ class MergingOpAssembler {
415415
}
416416

417417
_serialize(finalize) {
418-
this._serialized = exports.serializeOps(squashOps(this._ops, finalize));
418+
this._serialized = exports.serializeOps(exports.squashOps(this._ops, finalize));
419419
}
420420

421421
clear() {
@@ -458,14 +458,14 @@ const canonicalizeOps = function* (ops, finalize) {
458458
let lengthChange = 0;
459459

460460
const flushPlusMinus = function* () {
461-
yield* squashOps(minusOps, false);
461+
yield* exports.squashOps(minusOps, false);
462462
minusOps = [];
463-
yield* squashOps(plusOps, false);
463+
yield* exports.squashOps(plusOps, false);
464464
plusOps = [];
465465
};
466466

467467
const flushKeeps = function* (finalize) {
468-
yield* squashOps(keepOps, finalize);
468+
yield* exports.squashOps(keepOps, finalize);
469469
keepOps = [];
470470
};
471471

@@ -646,9 +646,13 @@ exports.checkRep = (cs) => {
646646
exports.smartOpAssembler = () => new SmartOpAssembler();
647647

648648
/**
649+
* @deprecated Use `squashOps` with `serializeOps` instead.
649650
* @returns {MergingOpAssembler}
650651
*/
651-
exports.mergingOpAssembler = () => new MergingOpAssembler();
652+
exports.mergingOpAssembler = () => {
653+
warnDeprecated('Changeset.mergingOpAssembler() is deprecated; use Changeset.squashOps() instead');
654+
return new MergingOpAssembler();
655+
};
652656

653657
/**
654658
* @deprecated Use `serializeOps` instead.
@@ -1384,16 +1388,16 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
13841388
lineOpsNext = lineOps.next();
13851389
return op;
13861390
};
1387-
let lineAssem = null;
1391+
let lineOps = null;
13881392

13891393
const outputMutOp = (op) => {
1390-
if (!lineAssem) lineAssem = new MergingOpAssembler();
1391-
lineAssem.append(op);
1394+
if (lineOps == null) lineOps = [];
1395+
lineOps.push(op);
13921396
if (op.lines <= 0) return;
13931397
assert(op.lines === 1, `Can't have op.lines of ${op.lines} in attribution lines`);
13941398
// ship it to the mut
1395-
mut.insert(lineAssem.toString(), 1);
1396-
lineAssem = null;
1399+
mut.insert(exports.serializeOps(exports.squashOps(lineOps, false)), 1);
1400+
lineOps = null;
13971401
};
13981402

13991403
let csOp = new Op();
@@ -1403,10 +1407,10 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
14031407
csOp = csOpsNext.value;
14041408
csOpsNext = csOps.next();
14051409
}
1406-
if (!csOp.opcode && !attOp.opcode && !lineAssem && !lineOpsHasNext()) {
1410+
if (!csOp.opcode && !attOp.opcode && lineOps == null && !lineOpsHasNext()) {
14071411
break; // done
14081412
} else if (csOp.opcode === '=' && csOp.lines > 0 && !csOp.attribs && !attOp.opcode &&
1409-
!lineAssem && !lineOpsHasNext()) {
1413+
lineOps == null && !lineOpsHasNext()) {
14101414
// skip multiple lines; this is what makes small changes not order of the document size
14111415
mut.skipLines(csOp.lines);
14121416
csOp.opcode = '';
@@ -1430,7 +1434,7 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
14301434
}
14311435
}
14321436

1433-
assert(!lineAssem, `line assembler not finished:${cs}`);
1437+
assert(lineOps == null, `line assembler not finished: ${cs}`);
14341438
mut.close();
14351439
};
14361440

@@ -1441,23 +1445,22 @@ exports.mutateAttributionLines = (cs, lines, pool) => {
14411445
* @returns {string} joined Attribution lines
14421446
*/
14431447
exports.joinAttributionLines = (theAlines) => {
1444-
const assem = new MergingOpAssembler();
1445-
for (const aline of theAlines) {
1446-
for (const op of exports.deserializeOps(aline)) assem.append(op);
1447-
}
1448-
return assem.toString();
1448+
const ops = (function* () {
1449+
for (const aline of theAlines) yield* exports.deserializeOps(aline);
1450+
})();
1451+
return exports.serializeOps(exports.squashOps(ops, false));
14491452
};
14501453

14511454
exports.splitAttributionLines = (attrOps, text) => {
1452-
const assem = new MergingOpAssembler();
1455+
let ops = [];
14531456
const lines = [];
14541457
let pos = 0;
14551458

14561459
const appendOp = (op) => {
1457-
assem.append(op);
1460+
ops.push(op);
14581461
if (op.lines > 0) {
1459-
lines.push(assem.toString());
1460-
assem.clear();
1462+
lines.push(exports.serializeOps(exports.squashOps(ops, false)));
1463+
ops = [];
14611464
}
14621465
pos += op.chars;
14631466
};

src/static/js/changesettracker.js

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -153,27 +153,27 @@ const makeChangesetTracker = (scheduler, apool, aceCallbacksProvider) => {
153153

154154
// Replace all added 'author' attribs with the value of the current user
155155
const cs = Changeset.unpack(userChangeset);
156-
const assem = Changeset.mergingOpAssembler();
157-
158-
for (const op of Changeset.deserializeOps(cs.ops)) {
159-
if (op.opcode === '+') {
160-
let newAttrs = '';
161-
162-
op.attribs.split('*').forEach((attrNum) => {
163-
if (!attrNum) return;
164-
const attr = apool.getAttrib(parseInt(attrNum, 36));
165-
if (!attr) return;
166-
if ('author' === attr[0]) {
167-
// replace that author with the current one
168-
newAttrs += `*${authorAttr}`;
169-
} else { newAttrs += `*${attrNum}`; } // overtake all other attribs as is
170-
});
171-
op.attribs = newAttrs;
156+
const ops = (function* () {
157+
for (const op of Changeset.deserializeOps(cs.ops)) {
158+
if (op.opcode === '+') {
159+
let newAttrs = '';
160+
161+
op.attribs.split('*').forEach((attrNum) => {
162+
if (!attrNum) return;
163+
const attr = apool.getAttrib(parseInt(attrNum, 36));
164+
if (!attr) return;
165+
if ('author' === attr[0]) {
166+
// replace that author with the current one
167+
newAttrs += `*${authorAttr}`;
168+
} else { newAttrs += `*${attrNum}`; } // overtake all other attribs as is
169+
});
170+
op.attribs = newAttrs;
171+
}
172+
yield op;
172173
}
173-
assem.append(op);
174-
}
175-
assem.endDocument();
176-
userChangeset = Changeset.pack(cs.oldLen, cs.newLen, assem.toString(), cs.charBank);
174+
})();
175+
const serializedOps = Changeset.serializeOps(Changeset.squashOps(ops, true));
176+
userChangeset = Changeset.pack(cs.oldLen, cs.newLen, serializedOps, cs.charBank);
177177
Changeset.checkRep(userChangeset);
178178
}
179179
if (Changeset.isIdentity(userChangeset)) toSubmit = null;

src/tests/frontend/specs/easysync.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -646,16 +646,17 @@ describe('easysync', function () {
646646

647647
const testSplitJoinAttributionLines = (randomSeed) => {
648648
const stringToOps = (str) => {
649-
const assem = Changeset.mergingOpAssembler();
650-
const o = new Changeset.Op('+');
651-
o.chars = 1;
652-
for (let i = 0; i < str.length; i++) {
653-
const c = str.charAt(i);
654-
o.lines = (c === '\n' ? 1 : 0);
655-
o.attribs = (c === 'a' || c === 'b' ? `*${c}` : '');
656-
assem.append(o);
657-
}
658-
return assem.toString();
649+
const ops = (function* () {
650+
for (let i = 0; i < str.length; i++) {
651+
const c = str.charAt(i);
652+
const o = new Changeset.Op('+');
653+
o.chars = 1;
654+
o.lines = (c === '\n' ? 1 : 0);
655+
o.attribs = (c === 'a' || c === 'b' ? `*${c}` : '');
656+
yield o;
657+
}
658+
})();
659+
return Changeset.serializeOps(Changeset.squashOps(ops, false));
659660
};
660661

661662
it(`testSplitJoinAttributionLines#${randomSeed}`, async function () {

0 commit comments

Comments
 (0)