Skip to content

Commit 7b76323

Browse files
committed
Changeset: Avoid unnecessary StringAssembler class
1 parent faa47c7 commit 7b76323

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
@@ -325,21 +325,21 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
325325

326326
const nextText = (numChars) => {
327327
let len = 0;
328-
const assem = Changeset.stringAssembler();
328+
let assem = '';
329329
const firstString = linesGet(curLine).substring(curChar);
330330
len += firstString.length;
331-
assem.append(firstString);
331+
assem += firstString;
332332

333333
let lineNum = curLine + 1;
334334

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

342-
return assem.toString().substring(0, numChars);
342+
return assem.substring(0, numChars);
343343
};
344344

345345
const cachedStrFunc = (func) => {

src/static/js/Changeset.js

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,10 @@ class StringAssembler {
738738
/**
739739
* @returns {StringAssembler}
740740
*/
741-
exports.stringAssembler = () => new StringAssembler();
741+
exports.stringAssembler = () => {
742+
warnDeprecated('Changeset.stringAssembler() is deprecated; build a string manually instead');
743+
return new StringAssembler();
744+
};
742745

743746
/**
744747
* @typedef {object} StringArrayLike
@@ -1167,7 +1170,7 @@ exports.applyToText = (cs, str) => {
11671170
assert(str.length === unpacked.oldLen, `mismatched apply: ${str.length} / ${unpacked.oldLen}`);
11681171
const bankIter = exports.stringIterator(unpacked.charBank);
11691172
const strIter = exports.stringIterator(str);
1170-
const assem = new StringAssembler();
1173+
let assem = '';
11711174
for (const op of exports.deserializeOps(unpacked.ops)) {
11721175
switch (op.opcode) {
11731176
case '+':
@@ -1176,7 +1179,7 @@ exports.applyToText = (cs, str) => {
11761179
if (op.lines !== bankIter.peek(op.chars).split('\n').length - 1) {
11771180
throw new Error(`newline count is wrong in op +; cs:${cs} and text:${str}`);
11781181
}
1179-
assem.append(bankIter.take(op.chars));
1182+
assem += bankIter.take(op.chars);
11801183
break;
11811184
case '-':
11821185
// op is - and op.lines 0: no newlines must be in the deleted string
@@ -1192,12 +1195,12 @@ exports.applyToText = (cs, str) => {
11921195
if (op.lines !== strIter.peek(op.chars).split('\n').length - 1) {
11931196
throw new Error(`newline count is wrong in op =; cs:${cs} and text:${str}`);
11941197
}
1195-
assem.append(strIter.take(op.chars));
1198+
assem += strIter.take(op.chars);
11961199
break;
11971200
}
11981201
}
1199-
assem.append(strIter.take(strIter.remaining()));
1200-
return assem.toString();
1202+
assem += strIter.take(strIter.remaining());
1203+
return assem;
12011204
};
12021205

12031206
/**
@@ -1281,12 +1284,11 @@ exports.composeAttributes = (att1, att2, resultIsMutation, pool) => {
12811284
}
12821285
return '';
12831286
});
1284-
const buf = new StringAssembler();
1287+
let buf = '';
12851288
for (const att of sortAttribs([...atts])) {
1286-
buf.append('*');
1287-
buf.append(exports.numToString(pool.putAttrib(att)));
1289+
buf += `*${exports.numToString(pool.putAttrib(att))}`;
12881290
}
1289-
return buf.toString();
1291+
return buf;
12901292
};
12911293

12921294
/**
@@ -1506,7 +1508,7 @@ exports.compose = (cs1, cs2, pool) => {
15061508
const len3 = unpacked2.newLen;
15071509
const bankIter1 = exports.stringIterator(unpacked1.charBank);
15081510
const bankIter2 = exports.stringIterator(unpacked2.charBank);
1509-
const bankAssem = new StringAssembler();
1511+
let bankAssem = '';
15101512

15111513
const newOps = applyZip(unpacked1.ops, unpacked2.ops, (op1, op2) => {
15121514
const op1code = op1.opcode;
@@ -1516,16 +1518,12 @@ exports.compose = (cs1, cs2, pool) => {
15161518
}
15171519
const opOut = slicerZipperFunc(op1, op2, pool);
15181520
if (opOut.opcode === '+') {
1519-
if (op2code === '+') {
1520-
bankAssem.append(bankIter2.take(opOut.chars));
1521-
} else {
1522-
bankAssem.append(bankIter1.take(opOut.chars));
1523-
}
1521+
bankAssem += (op2code === '+' ? bankIter2 : bankIter1).take(opOut.chars);
15241522
}
15251523
return opOut;
15261524
});
15271525

1528-
return exports.pack(len1, len3, newOps, bankAssem.toString());
1526+
return exports.pack(len1, len3, newOps, bankAssem);
15291527
};
15301528

15311529
/**
@@ -1938,7 +1936,7 @@ class Builder {
19381936
constructor(oldLen) {
19391937
this._oldLen = oldLen;
19401938
this._ops = [];
1941-
this._charBank = new StringAssembler();
1939+
this._charBank = '';
19421940
}
19431941

19441942
/**
@@ -1983,7 +1981,7 @@ class Builder {
19831981
*/
19841982
insert(text, attribs = '', pool = null) {
19851983
this._ops.push(...opsFromText('+', text, attribs, pool));
1986-
this._charBank.append(text);
1984+
this._charBank += text;
19871985
return this;
19881986
}
19891987

@@ -2015,7 +2013,7 @@ class Builder {
20152013
oldLen: this._oldLen,
20162014
newLen: this._oldLen + lengthChange,
20172015
ops: serializedOps,
2018-
charBank: this._charBank.toString(),
2016+
charBank: this._charBank,
20192017
};
20202018
}
20212019

@@ -2181,20 +2179,20 @@ exports.inverse = (cs, lines, alines, pool) => {
21812179

21822180
const nextText = (numChars) => {
21832181
let len = 0;
2184-
const assem = new StringAssembler();
2182+
let assem = '';
21852183
const firstString = linesGet(curLine).substring(curChar);
21862184
len += firstString.length;
2187-
assem.append(firstString);
2185+
assem += firstString;
21882186

21892187
let lineNum = curLine + 1;
21902188
while (len < numChars) {
21912189
const nextString = linesGet(lineNum);
21922190
len += nextString.length;
2193-
assem.append(nextString);
2191+
assem += nextString;
21942192
lineNum++;
21952193
}
21962194

2197-
return assem.toString().substring(0, numChars);
2195+
return assem.substring(0, numChars);
21982196
};
21992197

22002198
const cachedStrFunc = (func) => {
@@ -2407,12 +2405,9 @@ const followAttributes = (att1, att2, pool) => {
24072405
return '';
24082406
});
24092407
// we've only removed attributes, so they're already sorted
2410-
const buf = new StringAssembler();
2411-
for (const att of atts) {
2412-
buf.append('*');
2413-
buf.append(exports.numToString(pool.putAttrib(att)));
2414-
}
2415-
return buf.toString();
2408+
let buf = '';
2409+
for (const att of atts) buf += `*${exports.numToString(pool.putAttrib(att))}`;
2410+
return buf;
24162411
};
24172412

24182413
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)