@@ -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 . warnWithStack (
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/**
@@ -1546,15 +1552,13 @@ exports.makeSplice = (oldFullText, spliceStart, numRemoved, newText, optNewTextA
15461552 const oldText = oldFullText . substring ( spliceStart , spliceStart + numRemoved ) ;
15471553 const newLen = oldLen + newText . length - oldText . length ;
15481554
1549- const assem = new SmartOpAssembler ( ) ;
15501555 const ops = ( function * ( ) {
15511556 yield * opsFromText ( '=' , oldFullText . substring ( 0 , spliceStart ) ) ;
15521557 yield * opsFromText ( '-' , oldText ) ;
15531558 yield * opsFromText ( '+' , newText , optNewTextAPairs , pool ) ;
15541559 } ) ( ) ;
1555- for ( const op of ops ) assem . append ( op ) ;
1556- assem . endDocument ( ) ;
1557- return exports . pack ( oldLen , newLen , assem . toString ( ) , newText ) ;
1560+ const serializedOps = exports . serializeOps ( exports . canonicalizeOps ( ops , true ) ) ;
1561+ return exports . pack ( oldLen , newLen , serializedOps , newText ) ;
15581562} ;
15591563
15601564/**
@@ -1676,11 +1680,8 @@ exports.moveOpsToNewPool = (cs, oldPool, newPool) => {
16761680 * @param {string } text - text to insert
16771681 * @returns {string }
16781682 */
1679- exports . makeAttribution = ( text ) => {
1680- const assem = new SmartOpAssembler ( ) ;
1681- for ( const op of opsFromText ( '+' , text ) ) assem . append ( op ) ;
1682- return assem . toString ( ) ;
1683- } ;
1683+ exports . makeAttribution =
1684+ ( text ) => exports . serializeOps ( exports . canonicalizeOps ( opsFromText ( '+' , text ) , false ) ) ;
16841685
16851686/**
16861687 * Iterates over attributes in exports, attribution string, or attribs property of an op and runs
@@ -1933,8 +1934,7 @@ exports.attribsAttributeValue = (attribs, key, pool) => {
19331934 * @returns {Builder }
19341935 */
19351936exports . builder = ( oldLen ) => {
1936- const assem = new SmartOpAssembler ( ) ;
1937- const o = new Op ( ) ;
1937+ const ops = [ ] ;
19381938 const charBank = exports . stringAssembler ( ) ;
19391939
19401940 const self = {
@@ -1949,12 +1949,12 @@ exports.builder = (oldLen) => {
19491949 * @returns {Builder } this
19501950 */
19511951 keep : ( N , L , attribs , pool ) => {
1952- o . opcode = '=' ;
1952+ const o = new Op ( '=' ) ;
19531953 o . attribs = typeof attribs === 'string'
19541954 ? attribs : new AttributeMap ( pool ) . update ( attribs || [ ] ) . toString ( ) ;
19551955 o . chars = N ;
19561956 o . lines = ( L || 0 ) ;
1957- assem . append ( o ) ;
1957+ ops . push ( o ) ;
19581958 return self ;
19591959 } ,
19601960
@@ -1967,7 +1967,7 @@ exports.builder = (oldLen) => {
19671967 * @returns {Builder } this
19681968 */
19691969 keepText : ( text , attribs , pool ) => {
1970- for ( const op of opsFromText ( '=' , text , attribs , pool ) ) assem . append ( op ) ;
1970+ ops . push ( ... opsFromText ( '=' , text , attribs , pool ) ) ;
19711971 return self ;
19721972 } ,
19731973
@@ -1980,7 +1980,7 @@ exports.builder = (oldLen) => {
19801980 * @returns {Builder } this
19811981 */
19821982 insert : ( text , attribs , pool ) => {
1983- for ( const op of opsFromText ( '+' , text , attribs , pool ) ) assem . append ( op ) ;
1983+ ops . push ( ... opsFromText ( '+' , text , attribs , pool ) ) ;
19841984 charBank . append ( text ) ;
19851985 return self ;
19861986 } ,
@@ -1992,18 +1992,22 @@ exports.builder = (oldLen) => {
19921992 * @returns {Builder } this
19931993 */
19941994 remove : ( N , L ) => {
1995- o . opcode = '-' ;
1995+ const o = new Op ( '-' ) ;
19961996 o . attribs = '' ;
19971997 o . chars = N ;
19981998 o . lines = ( L || 0 ) ;
1999- assem . append ( o ) ;
1999+ ops . push ( o ) ;
20002000 return self ;
20012001 } ,
20022002
20032003 toString : ( ) => {
2004- assem . endDocument ( ) ;
2005- const newLen = oldLen + assem . getLengthChange ( ) ;
2006- return exports . pack ( oldLen , newLen , assem . toString ( ) , charBank . toString ( ) ) ;
2004+ /** @type {number } */
2005+ let lengthChange ;
2006+ const serializedOps = exports . serializeOps ( ( function * ( ) {
2007+ lengthChange = yield * exports . canonicalizeOps ( ops , true ) ;
2008+ } ) ( ) ) ;
2009+ const newLen = oldLen + lengthChange ;
2010+ return exports . pack ( oldLen , newLen , serializedOps , charBank . toString ( ) ) ;
20072011 } ,
20082012 } ;
20092013
@@ -2038,11 +2042,11 @@ exports.makeAttribsString = (opcode, attribs, pool) => {
20382042exports . subattribution = ( astr , start , optEnd ) => {
20392043 const attOps = exports . deserializeOps ( astr ) ;
20402044 let attOpsNext = attOps . next ( ) ;
2041- const assem = new SmartOpAssembler ( ) ;
20422045 let attOp = new Op ( ) ;
2043- const csOp = new Op ( ) ;
2046+ const csOp = new Op ( '-' ) ;
2047+ csOp . chars = start ;
20442048
2045- const doCsOp = ( ) => {
2049+ const doCsOp = function * ( ) {
20462050 if ( ! csOp . chars ) return ;
20472051 while ( csOp . opcode && ( attOp . opcode || ! attOpsNext . done ) ) {
20482052 if ( ! attOp . opcode ) {
@@ -2054,30 +2058,25 @@ exports.subattribution = (astr, start, optEnd) => {
20542058 csOp . lines ++ ;
20552059 }
20562060 const opOut = slicerZipperFunc ( attOp , csOp , null ) ;
2057- if ( opOut . opcode ) assem . append ( opOut ) ;
2061+ if ( opOut . opcode ) yield opOut ;
20582062 }
20592063 } ;
20602064
2061- csOp . opcode = '-' ;
2062- csOp . chars = start ;
2063-
2064- doCsOp ( ) ;
2065-
2066- if ( optEnd === undefined ) {
2067- if ( attOp . opcode ) {
2068- assem . append ( attOp ) ;
2069- }
2070- while ( ! attOpsNext . done ) {
2071- assem . append ( attOpsNext . value ) ;
2072- attOpsNext = attOps . next ( ) ;
2065+ const ops = ( function * ( ) {
2066+ yield * doCsOp ( ) ;
2067+ if ( optEnd === undefined ) {
2068+ if ( attOp . opcode ) yield attOp ;
2069+ while ( ! attOpsNext . done ) {
2070+ yield attOpsNext . value ;
2071+ attOpsNext = attOps . next ( ) ;
2072+ }
2073+ } else {
2074+ csOp . opcode = '=' ;
2075+ csOp . chars = optEnd - start ;
2076+ yield * doCsOp ( ) ;
20732077 }
2074- } else {
2075- csOp . opcode = '=' ;
2076- csOp . chars = optEnd - start ;
2077- doCsOp ( ) ;
2078- }
2079-
2080- return assem . toString ( ) ;
2078+ } ) ( ) ;
2079+ return exports . serializeOps ( exports . canonicalizeOps ( ops , false ) ) ;
20812080} ;
20822081
20832082exports . inverse = ( cs , lines , alines , pool ) => {
0 commit comments