Skip to content

Commit de86bd3

Browse files
committed
Changeset: Avoid unnecessary StringAssembler class
1 parent 9a35f16 commit de86bd3

File tree

5 files changed

+56
-87
lines changed

5 files changed

+56
-87
lines changed

src/node/utils/ExportHtml.js

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const getHTMLFromAtext = async (pad, atext, authorColors) => {
124124
// becomes
125125
// <b>Just bold <i>Bold and italics</i></b> <i>Just italics</i>
126126
const taker = Changeset.stringIterator(text);
127-
const assem = Changeset.stringAssembler();
127+
let assem = '';
128128
const openTags = [];
129129

130130
const getSpanClassFor = (i) => {
@@ -160,31 +160,15 @@ const getHTMLFromAtext = async (pad, atext, authorColors) => {
160160
const emitOpenTag = (i) => {
161161
openTags.unshift(i);
162162
const spanClass = getSpanClassFor(i);
163-
164-
if (spanClass) {
165-
assem.append('<span class="');
166-
assem.append(spanClass);
167-
assem.append('">');
168-
} else {
169-
assem.append('<');
170-
assem.append(tags[i]);
171-
assem.append('>');
172-
}
163+
assem += spanClass ? `<span class="${spanClass}">` : `<${tags[i]}>`;
173164
};
174165

175166
// this closes an open tag and removes its reference from openTags
176167
const emitCloseTag = (i) => {
177168
openTags.shift();
178169
const spanClass = getSpanClassFor(i);
179170
const spanWithData = isSpanWithData(i);
180-
181-
if (spanClass || spanWithData) {
182-
assem.append('</span>');
183-
} else {
184-
assem.append('</');
185-
assem.append(tags[i]);
186-
assem.append('>');
187-
}
171+
assem += spanClass || spanWithData ? '</span>' : `</${tags[i]}>`;
188172
};
189173

190174
const urls = padutils.findURLs(text);
@@ -245,7 +229,7 @@ const getHTMLFromAtext = async (pad, atext, authorColors) => {
245229
// from but they break the abiword parser and are completly useless
246230
s = s.replace(String.fromCharCode(12), '');
247231

248-
assem.append(_encodeWhitespace(Security.escapeHTML(s)));
232+
assem += _encodeWhitespace(Security.escapeHTML(s));
249233
} // end iteration over spans in line
250234

251235
// close all the tags that are open after the last op
@@ -268,14 +252,14 @@ const getHTMLFromAtext = async (pad, atext, authorColors) => {
268252
// https://html.spec.whatwg.org/multipage/links.html#link-type-noopener
269253
// https://mathiasbynens.github.io/rel-noopener/
270254
// https://github.com/ether/etherpad-lite/pull/3636
271-
assem.append(`<a href="${Security.escapeHTMLAttribute(url)}" rel="noreferrer noopener">`);
255+
assem += `<a href="${Security.escapeHTMLAttribute(url)}" rel="noreferrer noopener">`;
272256
processNextChars(urlLength);
273-
assem.append('</a>');
257+
assem += '</a>';
274258
});
275259
}
276260
processNextChars(text.length - idx);
277261

278-
return _processSpaces(assem.toString());
262+
return _processSpaces(assem);
279263
};
280264
// end getLineHTML
281265
const pieces = [css];

src/node/utils/ExportTxt.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const getTXTFromAtext = (pad, atext, authorColors) => {
6666
// becomes
6767
// <b>Just bold <i>Bold and italics</i></b> <i>Just italics</i>
6868
const taker = Changeset.stringIterator(text);
69-
const assem = Changeset.stringAssembler();
69+
let assem = '';
7070

7171
let idx = 0;
7272

@@ -160,7 +160,7 @@ const getTXTFromAtext = (pad, atext, authorColors) => {
160160
// plugins from being able to display * at the beginning of a line
161161
// s = s.replace("*", ""); // Then remove it
162162

163-
assem.append(s);
163+
assem += s;
164164
} // end iteration over spans in line
165165

166166
const tags2close = [];
@@ -174,7 +174,7 @@ const getTXTFromAtext = (pad, atext, authorColors) => {
174174
// end processNextChars
175175

176176
processNextChars(text.length - idx);
177-
return (assem.toString());
177+
return assem;
178178
};
179179
// end getLineHTML
180180

src/node/utils/padDiff.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,21 +326,21 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
326326

327327
const nextText = (numChars) => {
328328
let len = 0;
329-
const assem = Changeset.stringAssembler();
329+
let assem = '';
330330
const firstString = linesGet(curLine).substring(curChar);
331331
len += firstString.length;
332-
assem.append(firstString);
332+
assem += firstString;
333333

334334
let lineNum = curLine + 1;
335335

336336
while (len < numChars) {
337337
const nextString = linesGet(lineNum);
338338
len += nextString.length;
339-
assem.append(nextString);
339+
assem += nextString;
340340
lineNum++;
341341
}
342342

343-
return assem.toString().substring(0, numChars);
343+
return assem.substring(0, numChars);
344344
};
345345

346346
const cachedStrFunc = (func) => {

src/static/js/Changeset.js

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,10 @@ class StringAssembler {
730730
/**
731731
* @returns {StringAssembler}
732732
*/
733-
exports.stringAssembler = () => new StringAssembler();
733+
exports.stringAssembler = () => {
734+
warnDeprecated('Changeset.stringAssembler() is deprecated; build a string manually instead');
735+
return new StringAssembler();
736+
};
734737

735738
/**
736739
* Class to iterate and modify texts which have several lines. It is used for applying Changesets on
@@ -1142,7 +1145,7 @@ exports.applyToText = (cs, str) => {
11421145
assert(str.length === unpacked.oldLen, 'mismatched apply: ', str.length, ' / ', unpacked.oldLen);
11431146
const bankIter = exports.stringIterator(unpacked.charBank);
11441147
const strIter = exports.stringIterator(str);
1145-
const assem = new StringAssembler();
1148+
let assem = '';
11461149
for (const op of new exports.OpIter(unpacked.ops)) {
11471150
switch (op.opcode) {
11481151
case '+':
@@ -1151,7 +1154,7 @@ exports.applyToText = (cs, str) => {
11511154
if (op.lines !== bankIter.peek(op.chars).split('\n').length - 1) {
11521155
throw new Error(`newline count is wrong in op +; cs:${cs} and text:${str}`);
11531156
}
1154-
assem.append(bankIter.take(op.chars));
1157+
assem += bankIter.take(op.chars);
11551158
break;
11561159
case '-':
11571160
// op is - and op.lines 0: no newlines must be in the deleted string
@@ -1167,12 +1170,12 @@ exports.applyToText = (cs, str) => {
11671170
if (op.lines !== strIter.peek(op.chars).split('\n').length - 1) {
11681171
throw new Error(`newline count is wrong in op =; cs:${cs} and text:${str}`);
11691172
}
1170-
assem.append(strIter.take(op.chars));
1173+
assem += strIter.take(op.chars);
11711174
break;
11721175
}
11731176
}
1174-
assem.append(strIter.take(strIter.remaining()));
1175-
return assem.toString();
1177+
assem += strIter.take(strIter.remaining());
1178+
return assem;
11761179
};
11771180

11781181
/**
@@ -1247,12 +1250,11 @@ exports.composeAttributes = (att1, att2, resultIsMutation, pool) => {
12471250
}
12481251
return '';
12491252
});
1250-
const buf = new StringAssembler();
1253+
let buf = '';
12511254
for (const att of [...atts].sort((a, b) => (a[0] > b[0]) - (a[0] < b[0]))) {
1252-
buf.append('*');
1253-
buf.append(exports.numToString(pool.putAttrib(att)));
1255+
buf += `*${exports.numToString(pool.putAttrib(att))}`;
12541256
}
1255-
return buf.toString();
1257+
return buf;
12561258
};
12571259

12581260
/**
@@ -1468,7 +1470,7 @@ exports.compose = (cs1, cs2, pool) => {
14681470
const len3 = unpacked2.newLen;
14691471
const bankIter1 = exports.stringIterator(unpacked1.charBank);
14701472
const bankIter2 = exports.stringIterator(unpacked2.charBank);
1471-
const bankAssem = new StringAssembler();
1473+
let bankAssem = '';
14721474

14731475
const newOps = applyZip(unpacked1.ops, unpacked2.ops, (op1, op2) => {
14741476
const op1code = op1.opcode;
@@ -1478,16 +1480,12 @@ exports.compose = (cs1, cs2, pool) => {
14781480
}
14791481
const opOut = slicerZipperFunc(op1, op2, pool);
14801482
if (opOut.opcode === '+') {
1481-
if (op2code === '+') {
1482-
bankAssem.append(bankIter2.take(opOut.chars));
1483-
} else {
1484-
bankAssem.append(bankIter1.take(opOut.chars));
1485-
}
1483+
bankAssem += (op2code === '+' ? bankIter2 : bankIter1).take(opOut.chars);
14861484
}
14871485
return opOut;
14881486
});
14891487

1490-
return exports.pack(len1, len3, newOps, bankAssem.toString());
1488+
return exports.pack(len1, len3, newOps, bankAssem);
14911489
};
14921490

14931491
/**
@@ -1902,7 +1900,7 @@ exports.Builder = class {
19021900
constructor(oldLen) {
19031901
this._oldLen = oldLen;
19041902
this._ops = [];
1905-
this._charBank = new StringAssembler();
1903+
this._charBank = '';
19061904
}
19071905

19081906
/**
@@ -1925,7 +1923,7 @@ exports.Builder = class {
19251923

19261924
insert(text, attribs, pool) {
19271925
this._ops.push(...opsFromText('+', text, attribs, pool));
1928-
this._charBank.append(text);
1926+
this._charBank += text;
19291927
return this;
19301928
}
19311929

@@ -1944,7 +1942,7 @@ exports.Builder = class {
19441942
lengthChange = yield* exports.canonicalizeOps(this._ops, true);
19451943
}).call(this));
19461944
const newLen = this._oldLen + lengthChange;
1947-
return exports.pack(this._oldLen, newLen, serializedOps, this._charBank.toString());
1945+
return exports.pack(this._oldLen, newLen, serializedOps, this._charBank);
19481946
}
19491947
};
19501948

@@ -2103,20 +2101,20 @@ exports.inverse = (cs, lines, alines, pool) => {
21032101

21042102
const nextText = (numChars) => {
21052103
let len = 0;
2106-
const assem = new StringAssembler();
2104+
let assem = '';
21072105
const firstString = linesGet(curLine).substring(curChar);
21082106
len += firstString.length;
2109-
assem.append(firstString);
2107+
assem += firstString;
21102108

21112109
let lineNum = curLine + 1;
21122110
while (len < numChars) {
21132111
const nextString = linesGet(lineNum);
21142112
len += nextString.length;
2115-
assem.append(nextString);
2113+
assem += nextString;
21162114
lineNum++;
21172115
}
21182116

2119-
return assem.toString().substring(0, numChars);
2117+
return assem.substring(0, numChars);
21202118
};
21212119

21222120
const cachedStrFunc = (func) => {
@@ -2329,12 +2327,9 @@ const followAttributes = (att1, att2, pool) => {
23292327
return '';
23302328
});
23312329
// we've only removed attributes, so they're already sorted
2332-
const buf = new StringAssembler();
2333-
for (const att of atts) {
2334-
buf.append('*');
2335-
buf.append(exports.numToString(pool.putAttrib(att)));
2336-
}
2337-
return buf.toString();
2330+
let buf = '';
2331+
for (const att of atts) buf += `*${exports.numToString(pool.putAttrib(att))}`;
2332+
return buf;
23382333
};
23392334

23402335
exports.exportedForTestingOnly = {

src/tests/frontend/specs/easysync.js

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('easysync', function () {
5050
};
5151

5252
const mutationsToChangeset = (oldLen, arrayOfArrays) => {
53-
const bank = Changeset.stringAssembler();
53+
let bank = '';
5454
let oldPos = 0;
5555
let newLen = 0;
5656
const ops = (function* () {
@@ -69,7 +69,7 @@ describe('easysync', function () {
6969
oldPos += op.chars;
7070
} else if (a[0] === 'insert') {
7171
op.opcode = '+';
72-
bank.append(a[1]);
72+
bank += a[1];
7373
op.chars = a[1].length;
7474
op.lines = (a[2] || 0);
7575
newLen += op.chars;
@@ -79,7 +79,7 @@ describe('easysync', function () {
7979
})();
8080
const serializedOps = Changeset.serializeOps(Changeset.canonicalizeOps(ops, true));
8181
newLen += oldLen - oldPos;
82-
return Changeset.pack(oldLen, newLen, serializedOps, bank.toString());
82+
return Changeset.pack(oldLen, newLen, serializedOps, bank);
8383
};
8484

8585
const runMutationTest = (testId, origLines, muts, correct) => {
@@ -350,29 +350,19 @@ describe('easysync', function () {
350350
]);
351351

352352
const randomInlineString = (len) => {
353-
const assem = Changeset.stringAssembler();
354-
for (let i = 0; i < len; i++) {
355-
assem.append(String.fromCharCode(randInt(26) + 97));
356-
}
357-
return assem.toString();
353+
let assem = '';
354+
for (let i = 0; i < len; i++) assem += String.fromCharCode(randInt(26) + 97);
355+
return assem;
358356
};
359357

360358
const randomMultiline = (approxMaxLines, approxMaxCols) => {
361359
const numParts = randInt(approxMaxLines * 2) + 1;
362-
const txt = Changeset.stringAssembler();
363-
txt.append(randInt(2) ? '\n' : '');
360+
let txt = '';
361+
txt += randInt(2) ? '\n' : '';
364362
for (let i = 0; i < numParts; i++) {
365-
if ((i % 2) === 0) {
366-
if (randInt(10)) {
367-
txt.append(randomInlineString(randInt(approxMaxCols) + 1));
368-
} else {
369-
txt.append('\n');
370-
}
371-
} else {
372-
txt.append('\n');
373-
}
363+
txt += i % 2 === 0 && randInt(10) ? randomInlineString(randInt(approxMaxCols) + 1) : '\n';
374364
}
375-
return txt.toString();
365+
return txt;
376366
};
377367

378368
const randomStringOperation = (numCharsLeft) => {
@@ -494,9 +484,9 @@ describe('easysync', function () {
494484
};
495485

496486
const randomTestChangeset = (origText, withAttribs) => {
497-
const charBank = Changeset.stringAssembler();
487+
let charBank = '';
498488
let textLeft = origText; // always keep final newline
499-
const outTextAssem = Changeset.stringAssembler();
489+
let outTextAssem = '';
500490
const ops = [];
501491
const oldLen = origText.length;
502492

@@ -521,13 +511,13 @@ describe('easysync', function () {
521511
const o = randomStringOperation(textLeft.length);
522512
if (o.insert) {
523513
const txt = o.insert;
524-
charBank.append(txt);
525-
outTextAssem.append(txt);
514+
charBank += txt;
515+
outTextAssem += txt;
526516
appendMultilineOp('+', txt);
527517
} else if (o.skip) {
528518
const txt = textLeft.substring(0, o.skip);
529519
textLeft = textLeft.substring(o.skip);
530-
outTextAssem.append(txt);
520+
outTextAssem += txt;
531521
appendMultilineOp('=', txt);
532522
} else if (o.remove) {
533523
const txt = textLeft.substring(0, o.remove);
@@ -538,9 +528,9 @@ describe('easysync', function () {
538528

539529
while (textLeft.length > 1) doOp();
540530
for (let i = 0; i < 5; i++) doOp(); // do some more (only insertions will happen)
541-
const outText = `${outTextAssem.toString()}\n`;
531+
const outText = `${outTextAssem}\n`;
542532
const serializedOps = Changeset.serializeOps(Changeset.canonicalizeOps(ops, true));
543-
const cs = Changeset.pack(oldLen, outText.length, serializedOps, charBank.toString());
533+
const cs = Changeset.pack(oldLen, outText.length, serializedOps, charBank);
544534
Changeset.checkRep(cs);
545535
return [cs, outText];
546536
};

0 commit comments

Comments
 (0)