@@ -438,15 +438,92 @@ const opsFromText = function* (opcode, text, attribs = '', pool = null) {
438438 * - strips final "="
439439 * - ignores 0-length changes
440440 * - reorders consecutive + and - (which MergingOpAssembler doesn't do)
441- *
442- * @typedef {object } SmartOpAssembler
443- * @property {Function } append -
444- * @property {Function } appendOpWithText -
445- * @property {Function } clear -
446- * @property {Function } endDocument -
447- * @property {Function } getLengthChange -
448- * @property {Function } toString -
449441 */
442+ class SmartOpAssembler {
443+ constructor ( ) {
444+ this . _minusAssem = new MergingOpAssembler ( ) ;
445+ this . _plusAssem = new MergingOpAssembler ( ) ;
446+ this . _keepAssem = new MergingOpAssembler ( ) ;
447+ this . _assem = exports . stringAssembler ( ) ;
448+ this . _lastOpcode = '' ;
449+ this . _lengthChange = 0 ;
450+ }
451+
452+ _flushKeeps ( ) {
453+ this . _assem . append ( this . _keepAssem . toString ( ) ) ;
454+ this . _keepAssem . clear ( ) ;
455+ }
456+
457+ _flushPlusMinus ( ) {
458+ this . _assem . append ( this . _minusAssem . toString ( ) ) ;
459+ this . _minusAssem . clear ( ) ;
460+ this . _assem . append ( this . _plusAssem . toString ( ) ) ;
461+ this . _plusAssem . clear ( ) ;
462+ }
463+
464+ append ( op ) {
465+ if ( ! op . opcode ) return ;
466+ if ( ! op . chars ) return ;
467+
468+ if ( op . opcode === '-' ) {
469+ if ( this . _lastOpcode === '=' ) {
470+ this . _flushKeeps ( ) ;
471+ }
472+ this . _minusAssem . append ( op ) ;
473+ this . _lengthChange -= op . chars ;
474+ } else if ( op . opcode === '+' ) {
475+ if ( this . _lastOpcode === '=' ) {
476+ this . _flushKeeps ( ) ;
477+ }
478+ this . _plusAssem . append ( op ) ;
479+ this . _lengthChange += op . chars ;
480+ } else if ( op . opcode === '=' ) {
481+ if ( this . _lastOpcode !== '=' ) {
482+ this . _flushPlusMinus ( ) ;
483+ }
484+ this . _keepAssem . append ( op ) ;
485+ }
486+ this . _lastOpcode = op . opcode ;
487+ }
488+
489+ /**
490+ * Generates operations from the given text and attributes.
491+ *
492+ * @deprecated Use `opsFromText` instead.
493+ * @param {('-'|'+'|'=') } opcode - The operator to use.
494+ * @param {string } text - The text to remove/add/keep.
495+ * @param {(string|Attribute[]) } attribs - The attributes to apply to the operations. See
496+ * `makeAttribsString`.
497+ * @param {?AttributePool } pool - See `makeAttribsString`.
498+ */
499+ appendOpWithText ( opcode , text , attribs , pool ) {
500+ warnDeprecated ( 'Changeset.SmartOpAssembler.prototype.appendOpWithText() is deprecated; ' +
501+ 'use opsFromText() instead.' ) ;
502+ for ( const op of opsFromText ( opcode , text , attribs , pool ) ) this . append ( op ) ;
503+ }
504+
505+ toString ( ) {
506+ this . _flushPlusMinus ( ) ;
507+ this . _flushKeeps ( ) ;
508+ return this . _assem . toString ( ) ;
509+ }
510+
511+ clear ( ) {
512+ this . _minusAssem . clear ( ) ;
513+ this . _plusAssem . clear ( ) ;
514+ this . _keepAssem . clear ( ) ;
515+ this . _assem . clear ( ) ;
516+ this . _lengthChange = 0 ;
517+ }
518+
519+ endDocument ( ) {
520+ this . _keepAssem . endDocument ( ) ;
521+ }
522+
523+ getLengthChange ( ) {
524+ return this . _lengthChange ;
525+ }
526+ }
450527
451528/**
452529 * Used to check if a Changeset is valid. This function does not check things that require access to
@@ -462,7 +539,7 @@ exports.checkRep = (cs) => {
462539 const ops = unpacked . ops ;
463540 let charBank = unpacked . charBank ;
464541
465- const assem = exports . smartOpAssembler ( ) ;
542+ const assem = new SmartOpAssembler ( ) ;
466543 let oldPos = 0 ;
467544 let calcNewLen = 0 ;
468545 let numInserted = 0 ;
@@ -503,96 +580,7 @@ exports.checkRep = (cs) => {
503580/**
504581 * @returns {SmartOpAssembler }
505582 */
506- exports . smartOpAssembler = ( ) => {
507- const minusAssem = new MergingOpAssembler ( ) ;
508- const plusAssem = new MergingOpAssembler ( ) ;
509- const keepAssem = new MergingOpAssembler ( ) ;
510- const assem = exports . stringAssembler ( ) ;
511- let lastOpcode = '' ;
512- let lengthChange = 0 ;
513-
514- const flushKeeps = ( ) => {
515- assem . append ( keepAssem . toString ( ) ) ;
516- keepAssem . clear ( ) ;
517- } ;
518-
519- const flushPlusMinus = ( ) => {
520- assem . append ( minusAssem . toString ( ) ) ;
521- minusAssem . clear ( ) ;
522- assem . append ( plusAssem . toString ( ) ) ;
523- plusAssem . clear ( ) ;
524- } ;
525-
526- const append = ( op ) => {
527- if ( ! op . opcode ) return ;
528- if ( ! op . chars ) return ;
529-
530- if ( op . opcode === '-' ) {
531- if ( lastOpcode === '=' ) {
532- flushKeeps ( ) ;
533- }
534- minusAssem . append ( op ) ;
535- lengthChange -= op . chars ;
536- } else if ( op . opcode === '+' ) {
537- if ( lastOpcode === '=' ) {
538- flushKeeps ( ) ;
539- }
540- plusAssem . append ( op ) ;
541- lengthChange += op . chars ;
542- } else if ( op . opcode === '=' ) {
543- if ( lastOpcode !== '=' ) {
544- flushPlusMinus ( ) ;
545- }
546- keepAssem . append ( op ) ;
547- }
548- lastOpcode = op . opcode ;
549- } ;
550-
551- /**
552- * Generates operations from the given text and attributes.
553- *
554- * @deprecated Use `opsFromText` instead.
555- * @param {('-'|'+'|'=') } opcode - The operator to use.
556- * @param {string } text - The text to remove/add/keep.
557- * @param {(string|Attribute[]) } attribs - The attributes to apply to the operations. See
558- * `makeAttribsString`.
559- * @param {?AttributePool } pool - See `makeAttribsString`.
560- */
561- const appendOpWithText = ( opcode , text , attribs , pool ) => {
562- warnDeprecated ( 'Changeset.smartOpAssembler().appendOpWithText() is deprecated; ' +
563- 'use opsFromText() instead.' ) ;
564- for ( const op of opsFromText ( opcode , text , attribs , pool ) ) append ( op ) ;
565- } ;
566-
567- const toString = ( ) => {
568- flushPlusMinus ( ) ;
569- flushKeeps ( ) ;
570- return assem . toString ( ) ;
571- } ;
572-
573- const clear = ( ) => {
574- minusAssem . clear ( ) ;
575- plusAssem . clear ( ) ;
576- keepAssem . clear ( ) ;
577- assem . clear ( ) ;
578- lengthChange = 0 ;
579- } ;
580-
581- const endDocument = ( ) => {
582- keepAssem . endDocument ( ) ;
583- } ;
584-
585- const getLengthChange = ( ) => lengthChange ;
586-
587- return {
588- append,
589- toString,
590- clear,
591- endDocument,
592- appendOpWithText,
593- getLengthChange,
594- } ;
595- } ;
583+ exports . smartOpAssembler = ( ) => new SmartOpAssembler ( ) ;
596584
597585/**
598586 * @returns {MergingOpAssembler }
@@ -1034,7 +1022,7 @@ const applyZip = (in1, in2, func) => {
10341022 const ops2 = exports . deserializeOps ( in2 ) ;
10351023 let next1 = ops1 . next ( ) ;
10361024 let next2 = ops2 . next ( ) ;
1037- const assem = exports . smartOpAssembler ( ) ;
1025+ const assem = new SmartOpAssembler ( ) ;
10381026 while ( ! next1 . done || ! next2 . done ) {
10391027 if ( ! next1 . done && ! next1 . value . opcode ) next1 = ops1 . next ( ) ;
10401028 if ( ! next2 . done && ! next2 . value . opcode ) next2 = ops2 . next ( ) ;
@@ -1526,7 +1514,7 @@ exports.makeSplice = (oldFullText, spliceStart, numRemoved, newText, optNewTextA
15261514 const oldText = oldFullText . substring ( spliceStart , spliceStart + numRemoved ) ;
15271515 const newLen = oldLen + newText . length - oldText . length ;
15281516
1529- const assem = exports . smartOpAssembler ( ) ;
1517+ const assem = new SmartOpAssembler ( ) ;
15301518 const ops = ( function * ( ) {
15311519 yield * opsFromText ( '=' , oldFullText . substring ( 0 , spliceStart ) ) ;
15321520 yield * opsFromText ( '-' , oldText ) ;
@@ -1657,7 +1645,7 @@ exports.moveOpsToNewPool = (cs, oldPool, newPool) => {
16571645 * @returns {string }
16581646 */
16591647exports . makeAttribution = ( text ) => {
1660- const assem = exports . smartOpAssembler ( ) ;
1648+ const assem = new SmartOpAssembler ( ) ;
16611649 for ( const op of opsFromText ( '+' , text ) ) assem . append ( op ) ;
16621650 return assem . toString ( ) ;
16631651} ;
@@ -1897,7 +1885,7 @@ exports.attribsAttributeValue = (attribs, key, pool) => {
18971885 * @returns {Builder }
18981886 */
18991887exports . builder = ( oldLen ) => {
1900- const assem = exports . smartOpAssembler ( ) ;
1888+ const assem = new SmartOpAssembler ( ) ;
19011889 const o = new Op ( ) ;
19021890 const charBank = exports . stringAssembler ( ) ;
19031891
@@ -2000,7 +1988,7 @@ exports.makeAttribsString = (opcode, attribs, pool) => {
20001988exports . subattribution = ( astr , start , optEnd ) => {
20011989 const attOps = exports . deserializeOps ( astr ) ;
20021990 let attOpsNext = attOps . next ( ) ;
2003- const assem = exports . smartOpAssembler ( ) ;
1991+ const assem = new SmartOpAssembler ( ) ;
20041992 let attOp = new Op ( ) ;
20051993 const csOp = new Op ( ) ;
20061994
0 commit comments