@@ -432,7 +432,7 @@ class MergingOpAssembler {
432432 * @returns {Generator<Op, number> } The done value indicates how much the sequence of operations
433433 * changes the length of the document (in characters).
434434 */
435- const canonicalizeOps = function * ( ops , finalize ) {
435+ exports . canonicalizeOps = function * ( ops , finalize ) {
436436 let minusOps = [ ] ;
437437 let plusOps = [ ] ;
438438 let keepOps = [ ] ;
@@ -519,6 +519,8 @@ const opsFromText = function* (opcode, text, attribs = '', pool = null) {
519519 * - strips final "="
520520 * - ignores 0-length changes
521521 * - reorders consecutive + and - (which MergingOpAssembler doesn't do)
522+ *
523+ * @deprecated Use `canonicalizeOps` with `serializeOps` instead.
522524 */
523525class SmartOpAssembler {
524526 constructor ( ) {
@@ -533,7 +535,7 @@ class SmartOpAssembler {
533535
534536 _serialize ( finalize ) {
535537 this . _serialized = exports . serializeOps ( ( function * ( ) {
536- this . _lengthChange = yield * canonicalizeOps ( this . _ops , finalize ) ;
538+ this . _lengthChange = yield * exports . canonicalizeOps ( this . _ops , finalize ) ;
537539 } ) . call ( this ) ) ;
538540 }
539541
@@ -586,54 +588,58 @@ exports.checkRep = (cs) => {
586588 const unpacked = exports . unpack ( cs ) ;
587589 const oldLen = unpacked . oldLen ;
588590 const newLen = unpacked . newLen ;
589- const ops = unpacked . ops ;
590591 let charBank = unpacked . charBank ;
591592
592- const assem = new SmartOpAssembler ( ) ;
593593 let oldPos = 0 ;
594594 let calcNewLen = 0 ;
595- for ( const o of exports . deserializeOps ( ops ) ) {
596- switch ( o . opcode ) {
597- case '=' :
598- oldPos += o . chars ;
599- calcNewLen += o . chars ;
600- break ;
601- case '-' :
602- oldPos += o . chars ;
603- assert ( oldPos <= oldLen , `${ oldPos } > ${ oldLen } in ${ cs } ` ) ;
604- break ;
605- case '+' :
606- {
607- assert ( charBank . length >= o . chars , 'Invalid changeset: not enough chars in charBank' ) ;
608- const chars = charBank . slice ( 0 , o . chars ) ;
609- const nlines = ( chars . match ( / \n / g) || [ ] ) . length ;
610- assert ( nlines === o . lines ,
611- 'Invalid changeset: number of newlines in insert op does not match the charBank' ) ;
612- assert ( o . lines === 0 || chars . endsWith ( '\n' ) ,
613- 'Invalid changeset: multiline insert op does not end with a newline' ) ;
614- charBank = charBank . slice ( o . chars ) ;
615- calcNewLen += o . chars ;
616- assert ( calcNewLen <= newLen , `${ calcNewLen } > ${ newLen } in ${ cs } ` ) ;
617- break ;
595+ const ops = ( function * ( ) {
596+ for ( const o of exports . deserializeOps ( unpacked . ops ) ) {
597+ switch ( o . opcode ) {
598+ case '=' :
599+ oldPos += o . chars ;
600+ calcNewLen += o . chars ;
601+ break ;
602+ case '-' :
603+ oldPos += o . chars ;
604+ assert ( oldPos <= oldLen , `${ oldPos } > ${ oldLen } in ${ cs } ` ) ;
605+ break ;
606+ case '+' : {
607+ assert ( charBank . length >= o . chars , 'Invalid changeset: not enough chars in charBank' ) ;
608+ const chars = charBank . slice ( 0 , o . chars ) ;
609+ const nlines = ( chars . match ( / \n / g) || [ ] ) . length ;
610+ assert ( nlines === o . lines ,
611+ 'Invalid changeset: number of newlines in insert op does not match the charBank' ) ;
612+ assert ( o . lines === 0 || chars . endsWith ( '\n' ) ,
613+ 'Invalid changeset: multiline insert op does not end with a newline' ) ;
614+ charBank = charBank . slice ( o . chars ) ;
615+ calcNewLen += o . chars ;
616+ assert ( calcNewLen <= newLen , `${ calcNewLen } > ${ newLen } in ${ cs } ` ) ;
617+ break ;
618+ }
619+ default :
620+ assert ( false , `Invalid changeset: Unknown opcode: ${ JSON . stringify ( o . opcode ) } ` ) ;
618621 }
619- default :
620- assert ( false , `Invalid changeset: Unknown opcode: ${ JSON . stringify ( o . opcode ) } ` ) ;
622+ yield o ;
621623 }
622- assem . append ( o ) ;
623- }
624+ } ) ( ) ;
625+ const serializedOps = exports . serializeOps ( exports . canonicalizeOps ( ops , true ) ) ;
624626 calcNewLen += oldLen - oldPos ;
625627 assert ( calcNewLen === newLen , 'Invalid changeset: claimed length does not match actual length' ) ;
626628 assert ( charBank === '' , 'Invalid changeset: excess characters in the charBank' ) ;
627- assem . endDocument ( ) ;
628- const normalized = exports . pack ( oldLen , calcNewLen , assem . toString ( ) , unpacked . charBank ) ;
629+ const normalized = exports . pack ( oldLen , calcNewLen , serializedOps , unpacked . charBank ) ;
629630 assert ( normalized === cs , 'Invalid changeset: not in canonical form' ) ;
630631 return cs ;
631632} ;
632633
633634/**
635+ * @deprecated Use `canonicalizeOps` with `serializeOps` instead.
634636 * @returns {SmartOpAssembler }
635637 */
636- exports . smartOpAssembler = ( ) => new SmartOpAssembler ( ) ;
638+ exports . smartOpAssembler = ( ) => {
639+ padutils . warnDeprecated (
640+ 'Changeset.smartOpAssembler() is deprecated; use Changeset.canonicalizeOps() instead' ) ;
641+ return new SmartOpAssembler ( ) ;
642+ } ;
637643
638644/**
639645 * @deprecated Use `squashOps` with `serializeOps` instead.
@@ -1082,22 +1088,22 @@ class TextLinesMutator {
10821088 * @returns {string } the integrated changeset
10831089 */
10841090const applyZip = ( in1 , in2 , func ) => {
1085- const ops1 = exports . deserializeOps ( in1 ) ;
1086- const ops2 = exports . deserializeOps ( in2 ) ;
1087- let next1 = ops1 . next ( ) ;
1088- let next2 = ops2 . next ( ) ;
1089- const assem = new SmartOpAssembler ( ) ;
1090- while ( ! next1 . done || ! next2 . done ) {
1091- if ( ! next1 . done && ! next1 . value . opcode ) next1 = ops1 . next ( ) ;
1092- if ( ! next2 . done && ! next2 . value . opcode ) next2 = ops2 . next ( ) ;
1093- if ( next1 . value == null ) next1 . value = new Op ( ) ;
1094- if ( next2 . value == null ) next2 . value = new Op ( ) ;
1095- if ( ! next1 . value . opcode && ! next2 . value . opcode ) break ;
1096- const opOut = func ( next1 . value , next2 . value ) ;
1097- if ( opOut && opOut . opcode ) assem . append ( opOut ) ;
1098- }
1099- assem . endDocument ( ) ;
1100- return assem . toString ( ) ;
1091+ const ops = ( function * ( ) {
1092+ const ops1 = exports . deserializeOps ( in1 ) ;
1093+ const ops2 = exports . deserializeOps ( in2 ) ;
1094+ let next1 = ops1 . next ( ) ;
1095+ let next2 = ops2 . next ( ) ;
1096+ while ( ! next1 . done || ! next2 . done ) {
1097+ if ( ! next1 . done && ! next1 . value . opcode ) next1 = ops1 . next ( ) ;
1098+ if ( ! next2 . done && ! next2 . value . opcode ) next2 = ops2 . next ( ) ;
1099+ if ( next1 . value == null ) next1 . value = new Op ( ) ;
1100+ if ( next2 . value == null ) next2 . value = new Op ( ) ;
1101+ if ( ! next1 . value . opcode && ! next2 . value . opcode ) break ;
1102+ const opOut = func ( next1 . value , next2 . value ) ;
1103+ if ( opOut && opOut . opcode ) yield opOut ;
1104+ }
1105+ } ) ( ) ;
1106+ return exports . serializeOps ( exports . canonicalizeOps ( ops , true ) ) ;
11011107} ;
11021108
11031109/**
@@ -1540,15 +1546,13 @@ exports.makeSplice = (orig, start, ndel, ins, attribs, pool) => {
15401546 if ( start > orig . length ) start = orig . length ;
15411547 if ( ndel > orig . length - start ) ndel = orig . length - start ;
15421548 const deleted = orig . substring ( start , start + ndel ) ;
1543- const assem = new SmartOpAssembler ( ) ;
15441549 const ops = ( function * ( ) {
15451550 yield * opsFromText ( '=' , orig . substring ( 0 , start ) ) ;
15461551 yield * opsFromText ( '-' , deleted ) ;
15471552 yield * opsFromText ( '+' , ins , attribs , pool ) ;
15481553 } ) ( ) ;
1549- for ( const op of ops ) assem . append ( op ) ;
1550- assem . endDocument ( ) ;
1551- return exports . pack ( orig . length , orig . length + ins . length - ndel , assem . toString ( ) , ins ) ;
1554+ const serializedOps = exports . serializeOps ( exports . canonicalizeOps ( ops , true ) ) ;
1555+ return exports . pack ( orig . length , orig . length + ins . length - ndel , serializedOps , ins ) ;
15521556} ;
15531557
15541558/**
@@ -1670,11 +1674,8 @@ exports.moveOpsToNewPool = (cs, oldPool, newPool) => {
16701674 * @param {string } text - text to insert
16711675 * @returns {string }
16721676 */
1673- exports . makeAttribution = ( text ) => {
1674- const assem = new SmartOpAssembler ( ) ;
1675- for ( const op of opsFromText ( '+' , text ) ) assem . append ( op ) ;
1676- return assem . toString ( ) ;
1677- } ;
1677+ exports . makeAttribution =
1678+ ( text ) => exports . serializeOps ( exports . canonicalizeOps ( opsFromText ( '+' , text ) , false ) ) ;
16781679
16791680/**
16801681 * Iterates over attributes in exports, attribution string, or attribs property of an op and runs
@@ -1928,8 +1929,7 @@ exports.attribsAttributeValue = (attribs, key, pool) => {
19281929 * @returns {Builder }
19291930 */
19301931exports . builder = ( oldLen ) => {
1931- const assem = new SmartOpAssembler ( ) ;
1932- const o = new Op ( ) ;
1932+ const ops = [ ] ;
19331933 const charBank = exports . stringAssembler ( ) ;
19341934
19351935 const self = {
@@ -1944,12 +1944,12 @@ exports.builder = (oldLen) => {
19441944 * @returns {Builder } this
19451945 */
19461946 keep : ( N , L , attribs , pool ) => {
1947- o . opcode = '=' ;
1947+ const o = new Op ( '=' ) ;
19481948 o . attribs = typeof attribs === 'string'
19491949 ? attribs : new AttributeMap ( pool ) . update ( attribs || [ ] ) . toString ( ) ;
19501950 o . chars = N ;
19511951 o . lines = ( L || 0 ) ;
1952- assem . append ( o ) ;
1952+ ops . push ( o ) ;
19531953 return self ;
19541954 } ,
19551955
@@ -1962,7 +1962,7 @@ exports.builder = (oldLen) => {
19621962 * @returns {Builder } this
19631963 */
19641964 keepText : ( text , attribs , pool ) => {
1965- for ( const op of opsFromText ( '=' , text , attribs , pool ) ) assem . append ( op ) ;
1965+ ops . push ( ... opsFromText ( '=' , text , attribs , pool ) ) ;
19661966 return self ;
19671967 } ,
19681968
@@ -1975,7 +1975,7 @@ exports.builder = (oldLen) => {
19751975 * @returns {Builder } this
19761976 */
19771977 insert : ( text , attribs , pool ) => {
1978- for ( const op of opsFromText ( '+' , text , attribs , pool ) ) assem . append ( op ) ;
1978+ ops . push ( ... opsFromText ( '+' , text , attribs , pool ) ) ;
19791979 charBank . append ( text ) ;
19801980 return self ;
19811981 } ,
@@ -1987,18 +1987,22 @@ exports.builder = (oldLen) => {
19871987 * @returns {Builder } this
19881988 */
19891989 remove : ( N , L ) => {
1990- o . opcode = '-' ;
1990+ const o = new Op ( '-' ) ;
19911991 o . attribs = '' ;
19921992 o . chars = N ;
19931993 o . lines = ( L || 0 ) ;
1994- assem . append ( o ) ;
1994+ ops . push ( o ) ;
19951995 return self ;
19961996 } ,
19971997
19981998 toString : ( ) => {
1999- assem . endDocument ( ) ;
2000- const newLen = oldLen + assem . getLengthChange ( ) ;
2001- return exports . pack ( oldLen , newLen , assem . toString ( ) , charBank . toString ( ) ) ;
1999+ /** @type {number } */
2000+ let lengthChange ;
2001+ const serializedOps = exports . serializeOps ( ( function * ( ) {
2002+ lengthChange = yield * exports . canonicalizeOps ( ops , true ) ;
2003+ } ) ( ) ) ;
2004+ const newLen = oldLen + lengthChange ;
2005+ return exports . pack ( oldLen , newLen , serializedOps , charBank . toString ( ) ) ;
20022006 } ,
20032007 } ;
20042008
@@ -2033,11 +2037,11 @@ exports.makeAttribsString = (opcode, attribs, pool) => {
20332037exports . subattribution = ( astr , start , optEnd ) => {
20342038 const attOps = exports . deserializeOps ( astr ) ;
20352039 let attOpsNext = attOps . next ( ) ;
2036- const assem = new SmartOpAssembler ( ) ;
20372040 let attOp = new Op ( ) ;
2038- const csOp = new Op ( ) ;
2041+ const csOp = new Op ( '-' ) ;
2042+ csOp . chars = start ;
20392043
2040- const doCsOp = ( ) => {
2044+ const doCsOp = function * ( ) {
20412045 if ( ! csOp . chars ) return ;
20422046 while ( csOp . opcode && ( attOp . opcode || ! attOpsNext . done ) ) {
20432047 if ( ! attOp . opcode ) {
@@ -2049,30 +2053,25 @@ exports.subattribution = (astr, start, optEnd) => {
20492053 csOp . lines ++ ;
20502054 }
20512055 const opOut = slicerZipperFunc ( attOp , csOp , null ) ;
2052- if ( opOut . opcode ) assem . append ( opOut ) ;
2056+ if ( opOut . opcode ) yield opOut ;
20532057 }
20542058 } ;
20552059
2056- csOp . opcode = '-' ;
2057- csOp . chars = start ;
2058-
2059- doCsOp ( ) ;
2060-
2061- if ( optEnd === undefined ) {
2062- if ( attOp . opcode ) {
2063- assem . append ( attOp ) ;
2064- }
2065- while ( ! attOpsNext . done ) {
2066- assem . append ( attOpsNext . value ) ;
2067- attOpsNext = attOps . next ( ) ;
2060+ const ops = ( function * ( ) {
2061+ yield * doCsOp ( ) ;
2062+ if ( optEnd === undefined ) {
2063+ if ( attOp . opcode ) yield attOp ;
2064+ while ( ! attOpsNext . done ) {
2065+ yield attOpsNext . value ;
2066+ attOpsNext = attOps . next ( ) ;
2067+ }
2068+ } else {
2069+ csOp . opcode = '=' ;
2070+ csOp . chars = optEnd - start ;
2071+ yield * doCsOp ( ) ;
20682072 }
2069- } else {
2070- csOp . opcode = '=' ;
2071- csOp . chars = optEnd - start ;
2072- doCsOp ( ) ;
2073- }
2074-
2075- return assem . toString ( ) ;
2073+ } ) ( ) ;
2074+ return exports . serializeOps ( exports . canonicalizeOps ( ops , false ) ) ;
20762075} ;
20772076
20782077exports . inverse = ( cs , lines , alines , pool ) => {
0 commit comments