diff --git a/src/api/converter.ts b/src/api/converter.ts index ca7a21c8f..9f273a76d 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -52,6 +52,7 @@ import { RGATreeSplitNode, RGATreeSplitNodeID, RGATreeSplitPos, + StyleOperation as MarkOperation, } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split'; import { CRDTText, CRDTTextValue } from '@yorkie-js-sdk/src/document/crdt/text'; import { @@ -83,6 +84,8 @@ import { TreePos as PbTreePos, TreeNodeID as PbTreeNodeID, ValueType as PbValueType, + MarkOps as PbMarkOps, + MarkOp as PbMarkOp, } from '@yorkie-js-sdk/src/api/yorkie/v1/resources_pb'; import { IncreaseOperation } from '@yorkie-js-sdk/src/document/operation/increase_operation'; import { @@ -128,6 +131,33 @@ function toPresenceChange( return pbPresenceChange; } +/** + * `toMarkOps` converts the given model to Protobuf format. + */ +function toMarkOps(markOps: Set): PbMarkOps { + const pbMarkOps = new PbMarkOps(); + const pbMarkOpsList: Array = []; + for (const markOp of markOps) { + pbMarkOpsList.push(toMarkOp(markOp)); + } + pbMarkOps.setOperationsList(pbMarkOpsList); + return pbMarkOps; +} + +/** + * `toMarkOp` converts the given model to Protobuf format. + */ +function toMarkOp(markOp: MarkOperation): PbMarkOp { + const pbMarkOp = new PbMarkOp(); + pbMarkOp.setFromboundary(toTextNodeBoundary(markOp.fromBoundary)); + pbMarkOp.setToboundary(toTextNodeBoundary(markOp.toBoundary)); + const pbAttributes = pbMarkOp.getAttributesMap(); + for (const [key, value] of Object.entries(markOp.attributes)) { + pbAttributes.set(key, value); + } + return pbMarkOp; +} + /** * `toCheckpoint` converts the given model to Protobuf format. */ @@ -539,7 +569,6 @@ function toTextNodes( rgaTreeSplit: RGATreeSplit, ): Array { const pbTextNodes = []; - let currentAttr = new Map(); for (const textNode of rgaTreeSplit) { const pbTextNode = new PbTextNode(); @@ -548,23 +577,6 @@ function toTextNodes( pbTextNode.setRemovedAt(toTimeTicket(textNode.getRemovedAt())); const pbNodeAttrsMap = pbTextNode.getAttributesMap(); - - const beforeAnchor = textNode.getStyleOpsBefore(); - const afterAnchor = textNode.getStyleOpsAfter(); - if (beforeAnchor) { - currentAttr = rgaTreeSplit.getAttrsFromAnchor(beforeAnchor); - } - if (!textNode.isRemoved()) { - for (const [key, value] of currentAttr.entries()) { - const pbNodeAttr = new PbNodeAttr(); - pbNodeAttr.setValue(value); - pbNodeAttrsMap.set(key, pbNodeAttr); - } - } - if (afterAnchor) { - currentAttr = rgaTreeSplit.getAttrsFromAnchor(afterAnchor); - } - const attrs = textNode.getValue().getAttrs(); for (const attr of attrs) { const pbNodeAttr = new PbNodeAttr(); @@ -573,6 +585,14 @@ function toTextNodes( pbNodeAttrsMap.set(attr.getKey(), pbNodeAttr); } + const styleOpsBefore = textNode.getStyleOpsBefore(); + if (styleOpsBefore) { + pbTextNode.setMarkopsbefore(toMarkOps(styleOpsBefore)); + } + const styleOpsAfter = textNode.getStyleOpsAfter(); + if (styleOpsAfter) { + pbTextNode.setMarkopsafter(toMarkOps(styleOpsAfter)); + } pbTextNodes.push(pbTextNode); } @@ -985,6 +1005,22 @@ function fromTextNodeID(pbTextNodeID: PbTextNodeID): RGATreeSplitNodeID { ); } +/** + * `fromMarkOp` converts the given Protobuf format to model format. + */ +function fromMarkOp(pbMarkOp: PbMarkOp): MarkOperation { + const attributes: Record = {}; + pbMarkOp.getAttributesMap().forEach((value, key) => { + attributes[key as string] = value; + }); + + return { + fromBoundary: fromTextNodeBoundary(pbMarkOp.getFromboundary()!), + toBoundary: fromTextNodeBoundary(pbMarkOp.getToboundary()!), + attributes, + }; +} + /** * `fromTextNode` converts the given Protobuf format to model format. */ @@ -998,10 +1034,30 @@ function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode { ); }); - const textNode = RGATreeSplitNode.create( - fromTextNodeID(pbTextNode.getId()!), - textValue, - ); + let styleOpsBefore: Set | undefined; + const markOpsBefore = pbTextNode.getMarkopsbefore()?.getOperationsList(); + if (markOpsBefore) { + styleOpsBefore = new Set(); + for (const op of markOpsBefore) { + styleOpsBefore.add(fromMarkOp(op)); + } + } + + let styleOpsAfter: Set | undefined; + const markOpsAfter = pbTextNode.getMarkopsafter()?.getOperationsList(); + if (markOpsAfter) { + styleOpsAfter = new Set(); + for (const op of markOpsAfter) { + styleOpsAfter.add(fromMarkOp(op)); + } + } + + const textNode = RGATreeSplitNode.create({ + id: fromTextNodeID(pbTextNode.getId()!), + value: textValue, + styleOpsBefore, + styleOpsAfter, + }); textNode.remove(fromTimeTicket(pbTextNode.getRemovedAt())); return textNode; } diff --git a/src/api/yorkie/v1/resources.proto b/src/api/yorkie/v1/resources.proto index 65a1d2010..27fc676f5 100644 --- a/src/api/yorkie/v1/resources.proto +++ b/src/api/yorkie/v1/resources.proto @@ -231,6 +231,8 @@ message TextNode { TimeTicket removed_at = 3; TextNodeID ins_prev_id = 4; map attributes = 5; + MarkOps mark_ops_before = 6; + MarkOps mark_ops_After = 7; } message TextNodeID { @@ -238,6 +240,16 @@ message TextNodeID { int32 offset = 2; } +message MarkOps { + repeated MarkOp operations = 1; +} + +message MarkOp { + TextNodeBoundary from_boundary = 1; + TextNodeBoundary to_boundary = 2; + map attributes = 3; +} + message TreeNode { TreeNodeID id = 1; string type = 2; diff --git a/src/api/yorkie/v1/resources_pb.d.ts b/src/api/yorkie/v1/resources_pb.d.ts index 83f60acb0..7d6a9c838 100644 --- a/src/api/yorkie/v1/resources_pb.d.ts +++ b/src/api/yorkie/v1/resources_pb.d.ts @@ -1084,6 +1084,16 @@ export class TextNode extends jspb.Message { getAttributesMap(): jspb.Map; clearAttributesMap(): TextNode; + getMarkopsbefore(): MarkOps | undefined; + setMarkopsbefore(value?: MarkOps): TextNode; + hasMarkopsbefore(): boolean; + clearMarkopsbefore(): TextNode; + + getMarkopsafter(): MarkOps | undefined; + setMarkopsafter(value?: MarkOps): TextNode; + hasMarkopsafter(): boolean; + clearMarkopsafter(): TextNode; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): TextNode.AsObject; static toObject(includeInstance: boolean, msg: TextNode): TextNode.AsObject; @@ -1099,6 +1109,8 @@ export namespace TextNode { removedAt?: TimeTicket.AsObject, insPrevId?: TextNodeID.AsObject, attributesMap: Array<[string, NodeAttr.AsObject]>, + markopsbefore?: MarkOps.AsObject, + markopsafter?: MarkOps.AsObject, } } @@ -1126,6 +1138,56 @@ export namespace TextNodeID { } } +export class MarkOps extends jspb.Message { + getOperationsList(): Array; + setOperationsList(value: Array): MarkOps; + clearOperationsList(): MarkOps; + addOperations(value?: MarkOp, index?: number): MarkOp; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): MarkOps.AsObject; + static toObject(includeInstance: boolean, msg: MarkOps): MarkOps.AsObject; + static serializeBinaryToWriter(message: MarkOps, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): MarkOps; + static deserializeBinaryFromReader(message: MarkOps, reader: jspb.BinaryReader): MarkOps; +} + +export namespace MarkOps { + export type AsObject = { + operationsList: Array, + } +} + +export class MarkOp extends jspb.Message { + getFromboundary(): TextNodeBoundary | undefined; + setFromboundary(value?: TextNodeBoundary): MarkOp; + hasFromboundary(): boolean; + clearFromboundary(): MarkOp; + + getToboundary(): TextNodeBoundary | undefined; + setToboundary(value?: TextNodeBoundary): MarkOp; + hasToboundary(): boolean; + clearToboundary(): MarkOp; + + getAttributesMap(): jspb.Map; + clearAttributesMap(): MarkOp; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): MarkOp.AsObject; + static toObject(includeInstance: boolean, msg: MarkOp): MarkOp.AsObject; + static serializeBinaryToWriter(message: MarkOp, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): MarkOp; + static deserializeBinaryFromReader(message: MarkOp, reader: jspb.BinaryReader): MarkOp; +} + +export namespace MarkOp { + export type AsObject = { + fromboundary?: TextNodeBoundary.AsObject, + toboundary?: TextNodeBoundary.AsObject, + attributesMap: Array<[string, string]>, + } +} + export class TreeNode extends jspb.Message { getId(): TreeNodeID | undefined; setId(value?: TreeNodeID): TreeNode; diff --git a/src/api/yorkie/v1/resources_pb.js b/src/api/yorkie/v1/resources_pb.js index 01c1823a6..7f4d98917 100644 --- a/src/api/yorkie/v1/resources_pb.js +++ b/src/api/yorkie/v1/resources_pb.js @@ -36,6 +36,8 @@ goog.exportSymbol('proto.yorkie.v1.JSONElement.Primitive', null, global); goog.exportSymbol('proto.yorkie.v1.JSONElement.Text', null, global); goog.exportSymbol('proto.yorkie.v1.JSONElement.Tree', null, global); goog.exportSymbol('proto.yorkie.v1.JSONElementSimple', null, global); +goog.exportSymbol('proto.yorkie.v1.MarkOp', null, global); +goog.exportSymbol('proto.yorkie.v1.MarkOps', null, global); goog.exportSymbol('proto.yorkie.v1.NodeAttr', null, global); goog.exportSymbol('proto.yorkie.v1.Operation', null, global); goog.exportSymbol('proto.yorkie.v1.Operation.Add', null, global); @@ -657,6 +659,48 @@ if (goog.DEBUG && !COMPILED) { */ proto.yorkie.v1.TextNodeID.displayName = 'proto.yorkie.v1.TextNodeID'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.yorkie.v1.MarkOps = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.MarkOps.repeatedFields_, null); +}; +goog.inherits(proto.yorkie.v1.MarkOps, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.yorkie.v1.MarkOps.displayName = 'proto.yorkie.v1.MarkOps'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.yorkie.v1.MarkOp = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.yorkie.v1.MarkOp, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.yorkie.v1.MarkOp.displayName = 'proto.yorkie.v1.MarkOp'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -9237,7 +9281,9 @@ proto.yorkie.v1.TextNode.toObject = function(includeInstance, msg) { value: jspb.Message.getFieldWithDefault(msg, 2, ""), removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), insPrevId: (f = msg.getInsPrevId()) && proto.yorkie.v1.TextNodeID.toObject(includeInstance, f), - attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, proto.yorkie.v1.NodeAttr.toObject) : [] + attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, proto.yorkie.v1.NodeAttr.toObject) : [], + markopsbefore: (f = msg.getMarkopsbefore()) && proto.yorkie.v1.MarkOps.toObject(includeInstance, f), + markopsafter: (f = msg.getMarkopsafter()) && proto.yorkie.v1.MarkOps.toObject(includeInstance, f) }; if (includeInstance) { @@ -9299,6 +9345,16 @@ proto.yorkie.v1.TextNode.deserializeBinaryFromReader = function(msg, reader) { jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.NodeAttr.deserializeBinaryFromReader, "", new proto.yorkie.v1.NodeAttr()); }); break; + case 6: + var value = new proto.yorkie.v1.MarkOps; + reader.readMessage(value,proto.yorkie.v1.MarkOps.deserializeBinaryFromReader); + msg.setMarkopsbefore(value); + break; + case 7: + var value = new proto.yorkie.v1.MarkOps; + reader.readMessage(value,proto.yorkie.v1.MarkOps.deserializeBinaryFromReader); + msg.setMarkopsafter(value); + break; default: reader.skipField(); break; @@ -9363,6 +9419,22 @@ proto.yorkie.v1.TextNode.serializeBinaryToWriter = function(message, writer) { if (f && f.getLength() > 0) { f.serializeBinary(5, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.NodeAttr.serializeBinaryToWriter); } + f = message.getMarkopsbefore(); + if (f != null) { + writer.writeMessage( + 6, + f, + proto.yorkie.v1.MarkOps.serializeBinaryToWriter + ); + } + f = message.getMarkopsafter(); + if (f != null) { + writer.writeMessage( + 7, + f, + proto.yorkie.v1.MarkOps.serializeBinaryToWriter + ); + } }; @@ -9517,6 +9589,80 @@ proto.yorkie.v1.TextNode.prototype.clearAttributesMap = function() { return this;}; +/** + * optional MarkOps markOpsBefore = 6; + * @return {?proto.yorkie.v1.MarkOps} + */ +proto.yorkie.v1.TextNode.prototype.getMarkopsbefore = function() { + return /** @type{?proto.yorkie.v1.MarkOps} */ ( + jspb.Message.getWrapperField(this, proto.yorkie.v1.MarkOps, 6)); +}; + + +/** + * @param {?proto.yorkie.v1.MarkOps|undefined} value + * @return {!proto.yorkie.v1.TextNode} returns this +*/ +proto.yorkie.v1.TextNode.prototype.setMarkopsbefore = function(value) { + return jspb.Message.setWrapperField(this, 6, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.yorkie.v1.TextNode} returns this + */ +proto.yorkie.v1.TextNode.prototype.clearMarkopsbefore = function() { + return this.setMarkopsbefore(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.yorkie.v1.TextNode.prototype.hasMarkopsbefore = function() { + return jspb.Message.getField(this, 6) != null; +}; + + +/** + * optional MarkOps markOpsAfter = 7; + * @return {?proto.yorkie.v1.MarkOps} + */ +proto.yorkie.v1.TextNode.prototype.getMarkopsafter = function() { + return /** @type{?proto.yorkie.v1.MarkOps} */ ( + jspb.Message.getWrapperField(this, proto.yorkie.v1.MarkOps, 7)); +}; + + +/** + * @param {?proto.yorkie.v1.MarkOps|undefined} value + * @return {!proto.yorkie.v1.TextNode} returns this +*/ +proto.yorkie.v1.TextNode.prototype.setMarkopsafter = function(value) { + return jspb.Message.setWrapperField(this, 7, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.yorkie.v1.TextNode} returns this + */ +proto.yorkie.v1.TextNode.prototype.clearMarkopsafter = function() { + return this.setMarkopsafter(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.yorkie.v1.TextNode.prototype.hasMarkopsafter = function() { + return jspb.Message.getField(this, 7) != null; +}; + + @@ -9699,6 +9845,401 @@ proto.yorkie.v1.TextNodeID.prototype.setOffset = function(value) { +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.yorkie.v1.MarkOps.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.yorkie.v1.MarkOps.prototype.toObject = function(opt_includeInstance) { + return proto.yorkie.v1.MarkOps.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.yorkie.v1.MarkOps} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.MarkOps.toObject = function(includeInstance, msg) { + var f, obj = { + operationsList: jspb.Message.toObjectList(msg.getOperationsList(), + proto.yorkie.v1.MarkOp.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.yorkie.v1.MarkOps} + */ +proto.yorkie.v1.MarkOps.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.yorkie.v1.MarkOps; + return proto.yorkie.v1.MarkOps.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.yorkie.v1.MarkOps} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.yorkie.v1.MarkOps} + */ +proto.yorkie.v1.MarkOps.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.yorkie.v1.MarkOp; + reader.readMessage(value,proto.yorkie.v1.MarkOp.deserializeBinaryFromReader); + msg.addOperations(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.yorkie.v1.MarkOps.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.yorkie.v1.MarkOps.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.yorkie.v1.MarkOps} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.MarkOps.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getOperationsList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.yorkie.v1.MarkOp.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated MarkOp operations = 1; + * @return {!Array} + */ +proto.yorkie.v1.MarkOps.prototype.getOperationsList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.MarkOp, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.yorkie.v1.MarkOps} returns this +*/ +proto.yorkie.v1.MarkOps.prototype.setOperationsList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.yorkie.v1.MarkOp=} opt_value + * @param {number=} opt_index + * @return {!proto.yorkie.v1.MarkOp} + */ +proto.yorkie.v1.MarkOps.prototype.addOperations = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.yorkie.v1.MarkOp, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.yorkie.v1.MarkOps} returns this + */ +proto.yorkie.v1.MarkOps.prototype.clearOperationsList = function() { + return this.setOperationsList([]); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.yorkie.v1.MarkOp.prototype.toObject = function(opt_includeInstance) { + return proto.yorkie.v1.MarkOp.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.yorkie.v1.MarkOp} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.MarkOp.toObject = function(includeInstance, msg) { + var f, obj = { + fromboundary: (f = msg.getFromboundary()) && proto.yorkie.v1.TextNodeBoundary.toObject(includeInstance, f), + toboundary: (f = msg.getToboundary()) && proto.yorkie.v1.TextNodeBoundary.toObject(includeInstance, f), + attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, undefined) : [] + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.yorkie.v1.MarkOp} + */ +proto.yorkie.v1.MarkOp.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.yorkie.v1.MarkOp; + return proto.yorkie.v1.MarkOp.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.yorkie.v1.MarkOp} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.yorkie.v1.MarkOp} + */ +proto.yorkie.v1.MarkOp.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.yorkie.v1.TextNodeBoundary; + reader.readMessage(value,proto.yorkie.v1.TextNodeBoundary.deserializeBinaryFromReader); + msg.setFromboundary(value); + break; + case 2: + var value = new proto.yorkie.v1.TextNodeBoundary; + reader.readMessage(value,proto.yorkie.v1.TextNodeBoundary.deserializeBinaryFromReader); + msg.setToboundary(value); + break; + case 3: + var value = msg.getAttributesMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); + }); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.yorkie.v1.MarkOp.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.yorkie.v1.MarkOp.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.yorkie.v1.MarkOp} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.MarkOp.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getFromboundary(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.yorkie.v1.TextNodeBoundary.serializeBinaryToWriter + ); + } + f = message.getToboundary(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.yorkie.v1.TextNodeBoundary.serializeBinaryToWriter + ); + } + f = message.getAttributesMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(3, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); + } +}; + + +/** + * optional TextNodeBoundary fromBoundary = 1; + * @return {?proto.yorkie.v1.TextNodeBoundary} + */ +proto.yorkie.v1.MarkOp.prototype.getFromboundary = function() { + return /** @type{?proto.yorkie.v1.TextNodeBoundary} */ ( + jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodeBoundary, 1)); +}; + + +/** + * @param {?proto.yorkie.v1.TextNodeBoundary|undefined} value + * @return {!proto.yorkie.v1.MarkOp} returns this +*/ +proto.yorkie.v1.MarkOp.prototype.setFromboundary = function(value) { + return jspb.Message.setWrapperField(this, 1, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.yorkie.v1.MarkOp} returns this + */ +proto.yorkie.v1.MarkOp.prototype.clearFromboundary = function() { + return this.setFromboundary(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.yorkie.v1.MarkOp.prototype.hasFromboundary = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional TextNodeBoundary toBoundary = 2; + * @return {?proto.yorkie.v1.TextNodeBoundary} + */ +proto.yorkie.v1.MarkOp.prototype.getToboundary = function() { + return /** @type{?proto.yorkie.v1.TextNodeBoundary} */ ( + jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodeBoundary, 2)); +}; + + +/** + * @param {?proto.yorkie.v1.TextNodeBoundary|undefined} value + * @return {!proto.yorkie.v1.MarkOp} returns this +*/ +proto.yorkie.v1.MarkOp.prototype.setToboundary = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.yorkie.v1.MarkOp} returns this + */ +proto.yorkie.v1.MarkOp.prototype.clearToboundary = function() { + return this.setToboundary(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.yorkie.v1.MarkOp.prototype.hasToboundary = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * map attributes = 3; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} + */ +proto.yorkie.v1.MarkOp.prototype.getAttributesMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 3, opt_noLazyCreate, + null)); +}; + + +/** + * Clears values from the map. The map will be non-null. + * @return {!proto.yorkie.v1.MarkOp} returns this + */ +proto.yorkie.v1.MarkOp.prototype.clearAttributesMap = function() { + this.getAttributesMap().clear(); + return this;}; + + + if (jspb.Message.GENERATE_TO_OBJECT) { diff --git a/src/api/yorkie/v1/yorkie_grpc_web_pb.js b/src/api/yorkie/v1/yorkie_grpc_web_pb.js index ff8f94ad1..2eef83bd0 100644 --- a/src/api/yorkie/v1/yorkie_grpc_web_pb.js +++ b/src/api/yorkie/v1/yorkie_grpc_web_pb.js @@ -4,11 +4,7 @@ * @public */ -// Code generated by protoc-gen-grpc-web. DO NOT EDIT. -// versions: -// protoc-gen-grpc-web v1.4.2 -// protoc v3.20.3 -// source: yorkie/v1/yorkie.proto +// GENERATED CODE -- DO NOT EDIT! /* eslint-disable */ @@ -46,7 +42,7 @@ proto.yorkie.v1.YorkieServiceClient = /** * @private @const {string} The hostname */ - this.hostname_ = hostname.replace(/\/+$/, ''); + this.hostname_ = hostname; }; @@ -72,7 +68,7 @@ proto.yorkie.v1.YorkieServicePromiseClient = /** * @private @const {string} The hostname */ - this.hostname_ = hostname.replace(/\/+$/, ''); + this.hostname_ = hostname; }; diff --git a/src/document/crdt/rga_tree_split.ts b/src/document/crdt/rga_tree_split.ts index 7c4291e21..120f3880d 100644 --- a/src/document/crdt/rga_tree_split.ts +++ b/src/document/crdt/rga_tree_split.ts @@ -322,20 +322,41 @@ export class RGATreeSplitNode< private styleOpsBefore?: Set; private styleOpsAfter?: Set; - constructor(id: RGATreeSplitNodeID, value?: T, removedAt?: TimeTicket) { + constructor({ + id, + value, + removedAt, + styleOpsBefore, + styleOpsAfter, + }: { + id: RGATreeSplitNodeID; + value?: T; + removedAt?: TimeTicket; + styleOpsBefore?: Set; + styleOpsAfter?: Set; + }) { super(value!); this.id = id; this.removedAt = removedAt; + this.styleOpsBefore = styleOpsBefore; + this.styleOpsAfter = styleOpsAfter; } /** * `create` creates a instance of RGATreeSplitNode. */ - public static create( - id: RGATreeSplitNodeID, - value?: T, - ): RGATreeSplitNode { - return new RGATreeSplitNode(id, value); + public static create({ + id, + value, + styleOpsBefore, + styleOpsAfter, + }: { + id: RGATreeSplitNodeID; + value?: T; + styleOpsBefore?: Set; + styleOpsAfter?: Set; + }): RGATreeSplitNode { + return new RGATreeSplitNode({ id, value, styleOpsBefore, styleOpsAfter }); } /** @@ -523,11 +544,11 @@ export class RGATreeSplitNode< * `split` creates a new split node of the given offset. */ public split(offset: number): RGATreeSplitNode { - return new RGATreeSplitNode( - this.id.split(offset), - this.splitValue(offset), - this.removedAt, - ); + return new RGATreeSplitNode({ + id: this.id.split(offset), + value: this.splitValue(offset), + removedAt: this.removedAt, + }); } /** @@ -571,7 +592,11 @@ export class RGATreeSplitNode< * `deepcopy` returns a new instance of this RGATreeSplitNode without structural info. */ public deepcopy(): RGATreeSplitNode { - return new RGATreeSplitNode(this.id, this.value, this.removedAt); + return new RGATreeSplitNode({ + id: this.id, + value: this.value, + removedAt: this.removedAt, + }); } /** @@ -603,7 +628,7 @@ export class RGATreeSplit { private removedNodeMap: Map>; constructor() { - this.head = RGATreeSplitNode.create(InitialRGATreeSplitNodeID); + this.head = RGATreeSplitNode.create({ id: InitialRGATreeSplitNodeID }); this.treeByIndex = new SplayTree(); this.treeByID = new LLRBTree(RGATreeSplitNode.createComparator()); this.removedNodeMap = new Map(); @@ -655,7 +680,10 @@ export class RGATreeSplit { const inserted = this.insertAfter( fromLeft, - RGATreeSplitNode.create(RGATreeSplitNodeID.of(editedAt, 0), value), + RGATreeSplitNode.create({ + id: RGATreeSplitNodeID.of(editedAt, 0), + value, + }), ); if (changes.length && changes[changes.length - 1].from === idx) { diff --git a/test/integration/snapshot_test.ts b/test/integration/snapshot_test.ts index dbadfe091..09516ef93 100644 --- a/test/integration/snapshot_test.ts +++ b/test/integration/snapshot_test.ts @@ -58,7 +58,8 @@ describe('Snapshot', function () { }, this.test!.title); }); - // TODO(MoonGyu1): Remove skip after addressing logic of Text.setStyle + // TODO(MoonGyu1): Remove skip after applying mark + // when creating a snapshot in the Go SDK. it.skip('should handle snapshot for text with attributes', async function () { await withTwoClientsAndDocuments<{ k1: Text }>(async (c1, d1, c2, d2) => { d1.update((root) => {