@@ -424,15 +424,93 @@ const opsFromText = function* (opcode, text, attribs = '', pool = null) {
424424 * - strips final "="
425425 * - ignores 0-length changes
426426 * - reorders consecutive + and - (which MergingOpAssembler doesn't do)
427- *
428- * @typedef {object } SmartOpAssembler
429- * @property {Function } append -
430- * @property {Function } appendOpWithText -
431- * @property {Function } clear -
432- * @property {Function } endDocument -
433- * @property {Function } getLengthChange -
434- * @property {Function } toString -
435427 */
428+ class SmartOpAssembler {
429+ constructor ( ) {
430+ this . _minusAssem = new MergingOpAssembler ( ) ;
431+ this . _plusAssem = new MergingOpAssembler ( ) ;
432+ this . _keepAssem = new MergingOpAssembler ( ) ;
433+ this . _assem = exports . stringAssembler ( ) ;
434+ this . _lastOpcode = '' ;
435+ this . _lengthChange = 0 ;
436+ }
437+
438+ clear ( ) {
439+ this . _minusAssem . clear ( ) ;
440+ this . _plusAssem . clear ( ) ;
441+ this . _keepAssem . clear ( ) ;
442+ this . _assem . clear ( ) ;
443+ this . _lengthChange = 0 ;
444+ }
445+
446+ _flushKeeps ( ) {
447+ this . _assem . append ( this . _keepAssem . toString ( ) ) ;
448+ this . _keepAssem . clear ( ) ;
449+ }
450+
451+ _flushPlusMinus ( ) {
452+ this . _assem . append ( this . _minusAssem . toString ( ) ) ;
453+ this . _minusAssem . clear ( ) ;
454+ this . _assem . append ( this . _plusAssem . toString ( ) ) ;
455+ this . _plusAssem . clear ( ) ;
456+ }
457+
458+ append ( op ) {
459+ if ( ! op . opcode ) return ;
460+ if ( ! op . chars ) return ;
461+
462+ if ( op . opcode === '-' ) {
463+ if ( this . _lastOpcode === '=' ) {
464+ this . _flushKeeps ( ) ;
465+ }
466+ this . _minusAssem . append ( op ) ;
467+ this . _lengthChange -= op . chars ;
468+ } else if ( op . opcode === '+' ) {
469+ if ( this . _lastOpcode === '=' ) {
470+ this . _flushKeeps ( ) ;
471+ }
472+ this . _plusAssem . append ( op ) ;
473+ this . _lengthChange += op . chars ;
474+ } else if ( op . opcode === '=' ) {
475+ if ( this . _lastOpcode !== '=' ) {
476+ this . _flushPlusMinus ( ) ;
477+ }
478+ this . _keepAssem . append ( op ) ;
479+ }
480+ this . _lastOpcode = op . opcode ;
481+ }
482+
483+ /**
484+ * Generates operations from the given text and attributes.
485+ *
486+ * @deprecated Use `opsFromText` instead.
487+ * @param {('-'|'+'|'=') } opcode - The operator to use.
488+ * @param {string } text - The text to remove/add/keep.
489+ * @param {(string|Iterable<Attribute>) } attribs - The attributes to apply to the operations.
490+ * @param {?AttributePool } pool - Attribute pool. Only required if `attribs` is an iterable of
491+ * attribute key, value pairs.
492+ */
493+ appendOpWithText ( opcode , text , attribs , pool ) {
494+ padutils . warnWithStack (
495+ 'Changeset.SmartOpAssembler.prototype.appendOpWithText() is deprecated; ' +
496+ 'use opsFromText() instead.' ) ;
497+ for ( const op of opsFromText ( opcode , text , attribs , pool ) ) this . append ( op ) ;
498+ }
499+
500+ toString ( ) {
501+ this . _flushPlusMinus ( ) ;
502+ this . _flushKeeps ( ) ;
503+ return this . _assem . toString ( ) ;
504+ }
505+
506+ endDocument ( ) {
507+ this . _keepAssem . endDocument ( ) ;
508+ }
509+
510+ getLengthChange ( ) {
511+ return this . _lengthChange ;
512+ }
513+ }
436514
437515/**
438516 * Used to check if a Changeset is valid. This function does not check things that require access to
@@ -448,7 +526,7 @@ exports.checkRep = (cs) => {
448526 const ops = unpacked . ops ;
449527 let charBank = unpacked . charBank ;
450528
451- const assem = exports . smartOpAssembler ( ) ;
529+ const assem = new SmartOpAssembler ( ) ;
452530 let oldPos = 0 ;
453531 let calcNewLen = 0 ;
454532 for ( const o of exports . deserializeOps ( ops ) ) {
@@ -492,96 +570,7 @@ exports.checkRep = (cs) => {
492570/**
493571 * @returns {SmartOpAssembler }
494572 */
495- exports . smartOpAssembler = ( ) => {
496- const minusAssem = new MergingOpAssembler ( ) ;
497- const plusAssem = new MergingOpAssembler ( ) ;
498- const keepAssem = new MergingOpAssembler ( ) ;
499- const assem = exports . stringAssembler ( ) ;
500- let lastOpcode = '' ;
501- let lengthChange = 0 ;
502-
503- const flushKeeps = ( ) => {
504- assem . append ( keepAssem . toString ( ) ) ;
505- keepAssem . clear ( ) ;
506- } ;
507-
508- const flushPlusMinus = ( ) => {
509- assem . append ( minusAssem . toString ( ) ) ;
510- minusAssem . clear ( ) ;
511- assem . append ( plusAssem . toString ( ) ) ;
512- plusAssem . clear ( ) ;
513- } ;
514-
515- const append = ( op ) => {
516- if ( ! op . opcode ) return ;
517- if ( ! op . chars ) return ;
518-
519- if ( op . opcode === '-' ) {
520- if ( lastOpcode === '=' ) {
521- flushKeeps ( ) ;
522- }
523- minusAssem . append ( op ) ;
524- lengthChange -= op . chars ;
525- } else if ( op . opcode === '+' ) {
526- if ( lastOpcode === '=' ) {
527- flushKeeps ( ) ;
528- }
529- plusAssem . append ( op ) ;
530- lengthChange += op . chars ;
531- } else if ( op . opcode === '=' ) {
532- if ( lastOpcode !== '=' ) {
533- flushPlusMinus ( ) ;
534- }
535- keepAssem . append ( op ) ;
536- }
537- lastOpcode = op . opcode ;
538- } ;
539-
540- /**
541- * Generates operations from the given text and attributes.
542- *
543- * @deprecated Use `opsFromText` instead.
544- * @param {('-'|'+'|'=') } opcode - The operator to use.
545- * @param {string } text - The text to remove/add/keep.
546- * @param {(string|Iterable<Attribute>) } attribs - The attributes to apply to the operations.
547- * @param {?AttributePool } pool - Attribute pool. Only required if `attribs` is an iterable of
548- * attribute key, value pairs.
549- */
550- const appendOpWithText = ( opcode , text , attribs , pool ) => {
551- padutils . warnWithStack ( 'Changeset.smartOpAssembler().appendOpWithText() is deprecated; ' +
552- 'use opsFromText() instead.' ) ;
553- for ( const op of opsFromText ( opcode , text , attribs , pool ) ) append ( op ) ;
554- } ;
555-
556- const toString = ( ) => {
557- flushPlusMinus ( ) ;
558- flushKeeps ( ) ;
559- return assem . toString ( ) ;
560- } ;
561-
562- const clear = ( ) => {
563- minusAssem . clear ( ) ;
564- plusAssem . clear ( ) ;
565- keepAssem . clear ( ) ;
566- assem . clear ( ) ;
567- lengthChange = 0 ;
568- } ;
569-
570- const endDocument = ( ) => {
571- keepAssem . endDocument ( ) ;
572- } ;
573-
574- const getLengthChange = ( ) => lengthChange ;
575-
576- return {
577- append,
578- toString,
579- clear,
580- endDocument,
581- appendOpWithText,
582- getLengthChange,
583- } ;
584- } ;
573+ exports . smartOpAssembler = ( ) => new SmartOpAssembler ( ) ;
585574
586575/**
587576 * @returns {MergingOpAssembler }
@@ -1023,7 +1012,7 @@ const applyZip = (in1, in2, func) => {
10231012 const ops2 = exports . deserializeOps ( in2 ) ;
10241013 let next1 = ops1 . next ( ) ;
10251014 let next2 = ops2 . next ( ) ;
1026- const assem = exports . smartOpAssembler ( ) ;
1015+ const assem = new SmartOpAssembler ( ) ;
10271016 while ( ! next1 . done || ! next2 . done ) {
10281017 if ( ! next1 . done && ! next1 . value . opcode ) next1 = ops1 . next ( ) ;
10291018 if ( ! next2 . done && ! next2 . value . opcode ) next2 = ops2 . next ( ) ;
@@ -1484,7 +1473,7 @@ exports.makeSplice = (oldFullText, spliceStart, numRemoved, newText, optNewTextA
14841473 const oldText = oldFullText . substring ( spliceStart , spliceStart + numRemoved ) ;
14851474 const newLen = oldLen + newText . length - oldText . length ;
14861475
1487- const assem = exports . smartOpAssembler ( ) ;
1476+ const assem = new SmartOpAssembler ( ) ;
14881477 const ops = ( function * ( ) {
14891478 yield * opsFromText ( '=' , oldFullText . substring ( 0 , spliceStart ) ) ;
14901479 yield * opsFromText ( '-' , oldText ) ;
@@ -1615,7 +1604,7 @@ exports.moveOpsToNewPool = (cs, oldPool, newPool) => {
16151604 * @returns {string }
16161605 */
16171606exports . makeAttribution = ( text ) => {
1618- const assem = exports . smartOpAssembler ( ) ;
1607+ const assem = new SmartOpAssembler ( ) ;
16191608 for ( const op of opsFromText ( '+' , text ) ) assem . append ( op ) ;
16201609 return assem . toString ( ) ;
16211610} ;
@@ -1871,7 +1860,7 @@ exports.attribsAttributeValue = (attribs, key, pool) => {
18711860 * @returns {Builder }
18721861 */
18731862exports . builder = ( oldLen ) => {
1874- const assem = exports . smartOpAssembler ( ) ;
1863+ const assem = new SmartOpAssembler ( ) ;
18751864 const o = new Op ( ) ;
18761865 const charBank = exports . stringAssembler ( ) ;
18771866
@@ -1976,7 +1965,7 @@ exports.makeAttribsString = (opcode, attribs, pool) => {
19761965exports . subattribution = ( astr , start , optEnd ) => {
19771966 const attOps = exports . deserializeOps ( astr ) ;
19781967 let attOpsNext = attOps . next ( ) ;
1979- const assem = exports . smartOpAssembler ( ) ;
1968+ const assem = new SmartOpAssembler ( ) ;
19801969 let attOp = new Op ( ) ;
19811970 const csOp = new Op ( ) ;
19821971
0 commit comments