@@ -52,6 +52,7 @@ import {
5252 RGATreeSplitNode ,
5353 RGATreeSplitNodeID ,
5454 RGATreeSplitPos ,
55+ StyleOperation as MarkOperation ,
5556} from '@yorkie-js-sdk/src/document/crdt/rga_tree_split' ;
5657import { CRDTText , CRDTTextValue } from '@yorkie-js-sdk/src/document/crdt/text' ;
5758import {
@@ -83,6 +84,8 @@ import {
8384 TreePos as PbTreePos ,
8485 TreeNodeID as PbTreeNodeID ,
8586 ValueType as PbValueType ,
87+ MarkOps as PbMarkOps ,
88+ MarkOp as PbMarkOp ,
8689} from '@yorkie-js-sdk/src/api/yorkie/v1/resources_pb' ;
8790import { IncreaseOperation } from '@yorkie-js-sdk/src/document/operation/increase_operation' ;
8891import {
@@ -128,6 +131,33 @@ function toPresenceChange(
128131 return pbPresenceChange ;
129132}
130133
134+ /**
135+ * `toMarkOps` converts the given model to Protobuf format.
136+ */
137+ function toMarkOps ( markOps : Set < MarkOperation > ) : PbMarkOps {
138+ const pbMarkOps = new PbMarkOps ( ) ;
139+ const pbMarkOpsList : Array < PbMarkOp > = [ ] ;
140+ for ( const markOp of markOps ) {
141+ pbMarkOpsList . push ( toMarkOp ( markOp ) ) ;
142+ }
143+ pbMarkOps . setOperationsList ( pbMarkOpsList ) ;
144+ return pbMarkOps ;
145+ }
146+
147+ /**
148+ * `toMarkOp` converts the given model to Protobuf format.
149+ */
150+ function toMarkOp ( markOp : MarkOperation ) : PbMarkOp {
151+ const pbMarkOp = new PbMarkOp ( ) ;
152+ pbMarkOp . setFromboundary ( toTextNodeBoundary ( markOp . fromBoundary ) ) ;
153+ pbMarkOp . setToboundary ( toTextNodeBoundary ( markOp . toBoundary ) ) ;
154+ const pbAttributes = pbMarkOp . getAttributesMap ( ) ;
155+ for ( const [ key , value ] of Object . entries ( markOp . attributes ) ) {
156+ pbAttributes . set ( key , value ) ;
157+ }
158+ return pbMarkOp ;
159+ }
160+
131161/**
132162 * `toCheckpoint` converts the given model to Protobuf format.
133163 */
@@ -539,7 +569,6 @@ function toTextNodes(
539569 rgaTreeSplit : RGATreeSplit < CRDTTextValue > ,
540570) : Array < PbTextNode > {
541571 const pbTextNodes = [ ] ;
542- let currentAttr = new Map < string , string > ( ) ;
543572
544573 for ( const textNode of rgaTreeSplit ) {
545574 const pbTextNode = new PbTextNode ( ) ;
@@ -548,23 +577,6 @@ function toTextNodes(
548577 pbTextNode . setRemovedAt ( toTimeTicket ( textNode . getRemovedAt ( ) ) ) ;
549578
550579 const pbNodeAttrsMap = pbTextNode . getAttributesMap ( ) ;
551-
552- const beforeAnchor = textNode . getStyleOpsBefore ( ) ;
553- const afterAnchor = textNode . getStyleOpsAfter ( ) ;
554- if ( beforeAnchor ) {
555- currentAttr = rgaTreeSplit . getAttrsFromAnchor ( beforeAnchor ) ;
556- }
557- if ( ! textNode . isRemoved ( ) ) {
558- for ( const [ key , value ] of currentAttr . entries ( ) ) {
559- const pbNodeAttr = new PbNodeAttr ( ) ;
560- pbNodeAttr . setValue ( value ) ;
561- pbNodeAttrsMap . set ( key , pbNodeAttr ) ;
562- }
563- }
564- if ( afterAnchor ) {
565- currentAttr = rgaTreeSplit . getAttrsFromAnchor ( afterAnchor ) ;
566- }
567-
568580 const attrs = textNode . getValue ( ) . getAttrs ( ) ;
569581 for ( const attr of attrs ) {
570582 const pbNodeAttr = new PbNodeAttr ( ) ;
@@ -573,6 +585,14 @@ function toTextNodes(
573585 pbNodeAttrsMap . set ( attr . getKey ( ) , pbNodeAttr ) ;
574586 }
575587
588+ const styleOpsBefore = textNode . getStyleOpsBefore ( ) ;
589+ if ( styleOpsBefore ) {
590+ pbTextNode . setMarkopsbefore ( toMarkOps ( styleOpsBefore ) ) ;
591+ }
592+ const styleOpsAfter = textNode . getStyleOpsAfter ( ) ;
593+ if ( styleOpsAfter ) {
594+ pbTextNode . setMarkopsafter ( toMarkOps ( styleOpsAfter ) ) ;
595+ }
576596 pbTextNodes . push ( pbTextNode ) ;
577597 }
578598
@@ -985,6 +1005,22 @@ function fromTextNodeID(pbTextNodeID: PbTextNodeID): RGATreeSplitNodeID {
9851005 ) ;
9861006}
9871007
1008+ /**
1009+ * `fromMarkOp` converts the given Protobuf format to model format.
1010+ */
1011+ function fromMarkOp ( pbMarkOp : PbMarkOp ) : MarkOperation {
1012+ const attributes : Record < string , string > = { } ;
1013+ pbMarkOp . getAttributesMap ( ) . forEach ( ( value , key ) => {
1014+ attributes [ key as string ] = value ;
1015+ } ) ;
1016+
1017+ return {
1018+ fromBoundary : fromTextNodeBoundary ( pbMarkOp . getFromboundary ( ) ! ) ,
1019+ toBoundary : fromTextNodeBoundary ( pbMarkOp . getToboundary ( ) ! ) ,
1020+ attributes,
1021+ } ;
1022+ }
1023+
9881024/**
9891025 * `fromTextNode` converts the given Protobuf format to model format.
9901026 */
@@ -998,10 +1034,30 @@ function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode<CRDTTextValue> {
9981034 ) ;
9991035 } ) ;
10001036
1001- const textNode = RGATreeSplitNode . create (
1002- fromTextNodeID ( pbTextNode . getId ( ) ! ) ,
1003- textValue ,
1004- ) ;
1037+ let styleOpsBefore : Set < MarkOperation > | undefined ;
1038+ const markOpsBefore = pbTextNode . getMarkopsbefore ( ) ?. getOperationsList ( ) ;
1039+ if ( markOpsBefore ) {
1040+ styleOpsBefore = new Set ( ) ;
1041+ for ( const op of markOpsBefore ) {
1042+ styleOpsBefore . add ( fromMarkOp ( op ) ) ;
1043+ }
1044+ }
1045+
1046+ let styleOpsAfter : Set < MarkOperation > | undefined ;
1047+ const markOpsAfter = pbTextNode . getMarkopsafter ( ) ?. getOperationsList ( ) ;
1048+ if ( markOpsAfter ) {
1049+ styleOpsAfter = new Set ( ) ;
1050+ for ( const op of markOpsAfter ) {
1051+ styleOpsAfter . add ( fromMarkOp ( op ) ) ;
1052+ }
1053+ }
1054+
1055+ const textNode = RGATreeSplitNode . create ( {
1056+ id : fromTextNodeID ( pbTextNode . getId ( ) ! ) ,
1057+ value : textValue ,
1058+ styleOpsBefore,
1059+ styleOpsAfter,
1060+ } ) ;
10051061 textNode . remove ( fromTimeTicket ( pbTextNode . getRemovedAt ( ) ) ) ;
10061062 return textNode ;
10071063}
0 commit comments