Skip to content

Commit

Permalink
Implement Protocol Changes for Tree.RemoveStyle (yorkie-team#755)
Browse files Browse the repository at this point in the history
This commit reflects protocol changes for the Tree.RemoveStyle. Proto
file and converter were modified to reflect requirements related to
the Tree.RemoveStyle patch.
  • Loading branch information
raararaara authored Mar 14, 2024
1 parent ef0eb4a commit 2af8a0c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 17 deletions.
47 changes: 32 additions & 15 deletions src/api/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,15 @@ function toOperation(operation: Operation): PbOperation {
pbTreeStyleOperation.from = toTreePos(treeStyleOperation.getFromPos());
pbTreeStyleOperation.to = toTreePos(treeStyleOperation.getToPos());

const attributesMap = pbTreeStyleOperation.attributes;
const attributesToRemove = treeStyleOperation.getAttributesToRemove();
if (attributesToRemove.length > 0) {
pbTreeStyleOperation.attributesToRemove = attributesToRemove;
} else {
const attributesMap = pbTreeStyleOperation.attributes;

for (const [key, value] of treeStyleOperation.getAttributes()) {
attributesMap[key] = value;
for (const [key, value] of treeStyleOperation.getAttributes()) {
attributesMap[key] = value;
}
}
pbTreeStyleOperation.executedAt = toTimeTicket(
treeStyleOperation.getExecutedAt(),
Expand Down Expand Up @@ -1176,18 +1181,30 @@ function fromOperations(pbOperations: Array<PbOperation>): Array<Operation> {
const pbTreeStyleOperation = pbOperation.body.value;
const attributes = new Map();

Object.entries(pbTreeStyleOperation!.attributes).forEach(
([key, value]) => {
attributes.set(key, value);
},
);
operation = TreeStyleOperation.create(
fromTimeTicket(pbTreeStyleOperation!.parentCreatedAt)!,
fromTreePos(pbTreeStyleOperation!.from!),
fromTreePos(pbTreeStyleOperation!.to!),
attributes,
fromTimeTicket(pbTreeStyleOperation!.executedAt)!,
);
const attributesToRemove = pbTreeStyleOperation.attributesToRemove;
if (attributesToRemove.length > 0) {
operation = TreeStyleOperation.createTreeRemoveStyleOperation(
fromTimeTicket(pbTreeStyleOperation!.parentCreatedAt)!,
fromTreePos(pbTreeStyleOperation!.from!),
fromTreePos(pbTreeStyleOperation!.to!),
attributesToRemove,
fromTimeTicket(pbTreeStyleOperation!.executedAt)!,
);
} else {
Object.entries(pbTreeStyleOperation!.attributes).forEach(
([key, value]) => {
attributes.set(key, value);
},
);

operation = TreeStyleOperation.create(
fromTimeTicket(pbTreeStyleOperation!.parentCreatedAt)!,
fromTreePos(pbTreeStyleOperation!.from!),
fromTreePos(pbTreeStyleOperation!.to!),
attributes,
fromTimeTicket(pbTreeStyleOperation!.executedAt)!,
);
}
} else {
throw new YorkieError(Code.Unimplemented, `unimplemented operation`);
}
Expand Down
1 change: 1 addition & 0 deletions src/api/yorkie/v1/resources.proto
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ message Operation {
TreePos to = 3;
map<string, string> attributes = 4;
TimeTicket executed_at = 5;
repeated string attributes_to_remove = 6;
}

oneof body {
Expand Down
5 changes: 5 additions & 0 deletions src/api/yorkie/v1/resources_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,11 @@ export declare class Operation_TreeStyle extends Message<Operation_TreeStyle> {
*/
executedAt?: TimeTicket;

/**
* @generated from field: repeated string attributes_to_remove = 6;
*/
attributesToRemove: string[];

constructor(data?: PartialMessage<Operation_TreeStyle>);

static readonly runtime: typeof proto3;
Expand Down
1 change: 1 addition & 0 deletions src/api/yorkie/v1/resources_pb.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ const Operation_TreeStyle = proto3.makeMessageType(
{ no: 3, name: "to", kind: "message", T: TreePos },
{ no: 4, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} },
{ no: 5, name: "executed_at", kind: "message", T: TimeTicket },
{ no: 6, name: "attributes_to_remove", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
],
{localName: "Operation_TreeStyle"},
);
Expand Down
2 changes: 1 addition & 1 deletion src/document/operation/tree_style_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export class TreeStyleOperation extends Operation {
* `getAttributes` returns the attributes of Style.
*/
public getAttributes(): Map<string, string> {
return this.attributes!;
return this.attributes;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/util/index_tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ export class IndexTree<T extends IndexTreeNode<T>> {
path.push(sizeOfLeftSiblings + treePos.offset);
node = node.parent!;
} else if (node.hasTextChild()) {
// TODO(hackerwins): The function does not consider the situation
// TODO(hackerwins): The function does not consider the situation
// where Element and Text nodes are mixed in the Element's Children.
const sizeOfLeftSiblings = addSizeOfLeftSiblings(
node! as T,
Expand Down
36 changes: 36 additions & 0 deletions test/integration/tree_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,42 @@ describe('Tree.style', function () {
});
});

it('Can sync its content with remove style', async function ({ task }) {
await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => {
d1.update((root) => {
root.t = new Tree({
type: 'doc',
children: [
{
type: 'p',
children: [{ type: 'text', value: 'hello' }],
attributes: { italic: 'true' },
},
],
});
});
await c1.sync();
await c2.sync();
assert.equal(
d1.getRoot().t.toXML(),
/*html*/ `<doc><p italic="true">hello</p></doc>`,
);
assert.equal(
d2.getRoot().t.toXML(),
/*html*/ `<doc><p italic="true">hello</p></doc>`,
);

d1.update((root) => {
root.t.removeStyle(0, 1, ['italic']);
});
await c1.sync();
await c2.sync();

assert.equal(d1.getRoot().t.toXML(), /*html*/ `<doc><p>hello</p></doc>`);
assert.equal(d2.getRoot().t.toXML(), /*html*/ `<doc><p>hello</p></doc>`);
}, task.name);
});

it('Should return correct range path within doc.subscribe', async function ({
task,
}) {
Expand Down

0 comments on commit 2af8a0c

Please sign in to comment.