@yorkie-js/react 0.6.28 → 0.6.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/yorkie-js-react.es.js +1079 -1278
- package/dist/yorkie-js-react.es.js.map +1 -1
- package/dist/yorkie-js-react.js +1079 -1278
- package/dist/yorkie-js-react.js.map +1 -1
- package/package.json +2 -2
|
@@ -8663,8 +8663,7 @@ class CRDTObject extends CRDTContainer {
|
|
|
8663
8663
|
}
|
|
8664
8664
|
}
|
|
8665
8665
|
/**
|
|
8666
|
-
*
|
|
8667
|
-
* @internal
|
|
8666
|
+
* `[Symbol.iterator]` returns an iterator for the entries in this object.
|
|
8668
8667
|
*/
|
|
8669
8668
|
*[Symbol.iterator]() {
|
|
8670
8669
|
const keySet = /* @__PURE__ */ new Set();
|
|
@@ -10456,9 +10455,7 @@ class RGATreeList {
|
|
|
10456
10455
|
* `findNextBeforeExecutedAt` returns the node by the given createdAt and
|
|
10457
10456
|
* executedAt. It passes through nodes created after executedAt from the
|
|
10458
10457
|
* given node and returns the next node.
|
|
10459
|
-
* @
|
|
10460
|
-
* @param executedAt - executed time
|
|
10461
|
-
* @returns next node
|
|
10458
|
+
* @returns the next node of the given createdAt and executedAt
|
|
10462
10459
|
*/
|
|
10463
10460
|
findNextBeforeExecutedAt(createdAt, executedAt) {
|
|
10464
10461
|
let node = this.nodeMapByCreatedAt.get(createdAt.toIDString());
|
|
@@ -10794,8 +10791,7 @@ class CRDTArray extends CRDTContainer {
|
|
|
10794
10791
|
return this.elements.length;
|
|
10795
10792
|
}
|
|
10796
10793
|
/**
|
|
10797
|
-
*
|
|
10798
|
-
* @internal
|
|
10794
|
+
* `[Symbol.iterator]` returns an iterator for the elements in this array.
|
|
10799
10795
|
*/
|
|
10800
10796
|
*[Symbol.iterator]() {
|
|
10801
10797
|
for (const node of this.elements) {
|
|
@@ -11698,8 +11694,6 @@ class CRDTText extends CRDTElement {
|
|
|
11698
11694
|
}
|
|
11699
11695
|
/**
|
|
11700
11696
|
* `edit` edits the given range with the given value and attributes.
|
|
11701
|
-
*
|
|
11702
|
-
* @internal
|
|
11703
11697
|
*/
|
|
11704
11698
|
edit(range, content, editedAt, attributes, versionVector) {
|
|
11705
11699
|
const crdtTextValue = content ? CRDTTextValue.create(content) : void 0;
|
|
@@ -11736,7 +11730,6 @@ class CRDTText extends CRDTElement {
|
|
|
11736
11730
|
* @param range - range of RGATreeSplitNode
|
|
11737
11731
|
* @param attributes - style attributes
|
|
11738
11732
|
* @param editedAt - edited time
|
|
11739
|
-
* @internal
|
|
11740
11733
|
*/
|
|
11741
11734
|
setStyle(range, attributes, editedAt, versionVector) {
|
|
11742
11735
|
const diff = { data: 0, meta: 0 };
|
|
@@ -11890,8 +11883,6 @@ class CRDTText extends CRDTElement {
|
|
|
11890
11883
|
}
|
|
11891
11884
|
/**
|
|
11892
11885
|
* `getRGATreeSplit` returns rgaTreeSplit.
|
|
11893
|
-
*
|
|
11894
|
-
* @internal
|
|
11895
11886
|
*/
|
|
11896
11887
|
getRGATreeSplit() {
|
|
11897
11888
|
return this.rgaTreeSplit;
|
|
@@ -14004,8 +13995,6 @@ class CRDTTree extends CRDTElement {
|
|
|
14004
13995
|
}
|
|
14005
13996
|
/**
|
|
14006
13997
|
* `toJSForTest` returns value with meta data for testing.
|
|
14007
|
-
*
|
|
14008
|
-
* @internal
|
|
14009
13998
|
*/
|
|
14010
13999
|
toJSForTest() {
|
|
14011
14000
|
return {
|
|
@@ -14016,8 +14005,6 @@ class CRDTTree extends CRDTElement {
|
|
|
14016
14005
|
}
|
|
14017
14006
|
/**
|
|
14018
14007
|
* `toJSInfoForTest` returns detailed TreeNode information for use in Devtools.
|
|
14019
|
-
*
|
|
14020
|
-
* @internal
|
|
14021
14008
|
*/
|
|
14022
14009
|
toJSInfoForTest() {
|
|
14023
14010
|
const rootNode = this.indexTree.getRoot();
|
|
@@ -17571,11 +17558,11 @@ function uuid() {
|
|
|
17571
17558
|
class Attachment {
|
|
17572
17559
|
constructor(reconnectStreamDelay, doc, docID, syncMode, unsubscribeBroadcastEvent) {
|
|
17573
17560
|
// TODO(hackerwins): Consider to changing the modifiers of the following properties to private.
|
|
17574
|
-
__publicField(this, "reconnectStreamDelay");
|
|
17575
17561
|
__publicField(this, "doc");
|
|
17576
17562
|
__publicField(this, "docID");
|
|
17577
17563
|
__publicField(this, "syncMode");
|
|
17578
17564
|
__publicField(this, "remoteChangeEventReceived");
|
|
17565
|
+
__publicField(this, "reconnectStreamDelay");
|
|
17579
17566
|
__publicField(this, "cancelled");
|
|
17580
17567
|
__publicField(this, "watchStream");
|
|
17581
17568
|
__publicField(this, "watchLoopTimerID");
|
|
@@ -17649,156 +17636,6 @@ class Attachment {
|
|
|
17649
17636
|
this.watchLoopTimerID = void 0;
|
|
17650
17637
|
}
|
|
17651
17638
|
}
|
|
17652
|
-
function validateYorkieRuleset(data, ruleset) {
|
|
17653
|
-
const errors = [];
|
|
17654
|
-
for (const rule of ruleset) {
|
|
17655
|
-
const value = getValueByPath(data, rule.path);
|
|
17656
|
-
const result = validateValue(value, rule);
|
|
17657
|
-
if (!result.valid) {
|
|
17658
|
-
for (const error of result.errors || []) {
|
|
17659
|
-
errors.push(error);
|
|
17660
|
-
}
|
|
17661
|
-
}
|
|
17662
|
-
}
|
|
17663
|
-
return {
|
|
17664
|
-
valid: errors.length === 0,
|
|
17665
|
-
errors
|
|
17666
|
-
};
|
|
17667
|
-
}
|
|
17668
|
-
function getValueByPath(obj, path) {
|
|
17669
|
-
if (!path.startsWith("$")) {
|
|
17670
|
-
throw new Error(`Path must start with $, got ${path}`);
|
|
17671
|
-
}
|
|
17672
|
-
const keys = path.split(".");
|
|
17673
|
-
let current = obj;
|
|
17674
|
-
for (let i = 1; i < keys.length; i++) {
|
|
17675
|
-
const key = keys[i];
|
|
17676
|
-
if (!(current instanceof CRDTObject)) {
|
|
17677
|
-
return void 0;
|
|
17678
|
-
}
|
|
17679
|
-
current = current.get(key);
|
|
17680
|
-
}
|
|
17681
|
-
return current;
|
|
17682
|
-
}
|
|
17683
|
-
function validateValue(value, rule) {
|
|
17684
|
-
switch (rule.type) {
|
|
17685
|
-
case "string":
|
|
17686
|
-
case "boolean":
|
|
17687
|
-
case "integer":
|
|
17688
|
-
case "double":
|
|
17689
|
-
case "long":
|
|
17690
|
-
case "date":
|
|
17691
|
-
case "bytes":
|
|
17692
|
-
case "null":
|
|
17693
|
-
return validatePrimitiveValue(value, rule);
|
|
17694
|
-
case "object":
|
|
17695
|
-
if (!(value instanceof CRDTObject)) {
|
|
17696
|
-
return {
|
|
17697
|
-
valid: false,
|
|
17698
|
-
errors: [
|
|
17699
|
-
{
|
|
17700
|
-
path: rule.path,
|
|
17701
|
-
message: `expected object at path ${rule.path}`
|
|
17702
|
-
}
|
|
17703
|
-
]
|
|
17704
|
-
};
|
|
17705
|
-
}
|
|
17706
|
-
break;
|
|
17707
|
-
case "array":
|
|
17708
|
-
if (!(value instanceof CRDTArray)) {
|
|
17709
|
-
return {
|
|
17710
|
-
valid: false,
|
|
17711
|
-
errors: [
|
|
17712
|
-
{
|
|
17713
|
-
path: rule.path,
|
|
17714
|
-
message: `expected array at path ${rule.path}`
|
|
17715
|
-
}
|
|
17716
|
-
]
|
|
17717
|
-
};
|
|
17718
|
-
}
|
|
17719
|
-
break;
|
|
17720
|
-
case "yorkie.Text":
|
|
17721
|
-
if (!(value instanceof CRDTText)) {
|
|
17722
|
-
return {
|
|
17723
|
-
valid: false,
|
|
17724
|
-
errors: [
|
|
17725
|
-
{
|
|
17726
|
-
path: rule.path,
|
|
17727
|
-
message: `expected yorkie.Text at path ${rule.path}`
|
|
17728
|
-
}
|
|
17729
|
-
]
|
|
17730
|
-
};
|
|
17731
|
-
}
|
|
17732
|
-
break;
|
|
17733
|
-
case "yorkie.Tree":
|
|
17734
|
-
if (!(value instanceof CRDTTree)) {
|
|
17735
|
-
return {
|
|
17736
|
-
valid: false,
|
|
17737
|
-
errors: [
|
|
17738
|
-
{
|
|
17739
|
-
path: rule.path,
|
|
17740
|
-
message: `expected yorkie.Tree at path ${rule.path}`
|
|
17741
|
-
}
|
|
17742
|
-
]
|
|
17743
|
-
};
|
|
17744
|
-
}
|
|
17745
|
-
break;
|
|
17746
|
-
case "yorkie.Counter":
|
|
17747
|
-
if (!(value instanceof CRDTCounter)) {
|
|
17748
|
-
return {
|
|
17749
|
-
valid: false,
|
|
17750
|
-
errors: [
|
|
17751
|
-
{
|
|
17752
|
-
path: rule.path,
|
|
17753
|
-
message: `expected yorkie.Counter at path ${rule.path}`
|
|
17754
|
-
}
|
|
17755
|
-
]
|
|
17756
|
-
};
|
|
17757
|
-
}
|
|
17758
|
-
break;
|
|
17759
|
-
default:
|
|
17760
|
-
throw new Error(`Unknown rule type: ${rule.type}`);
|
|
17761
|
-
}
|
|
17762
|
-
return {
|
|
17763
|
-
valid: true
|
|
17764
|
-
};
|
|
17765
|
-
}
|
|
17766
|
-
function getPrimitiveType(type) {
|
|
17767
|
-
switch (type) {
|
|
17768
|
-
case "null":
|
|
17769
|
-
return PrimitiveType.Null;
|
|
17770
|
-
case "boolean":
|
|
17771
|
-
return PrimitiveType.Boolean;
|
|
17772
|
-
case "integer":
|
|
17773
|
-
return PrimitiveType.Integer;
|
|
17774
|
-
case "long":
|
|
17775
|
-
return PrimitiveType.Long;
|
|
17776
|
-
case "double":
|
|
17777
|
-
return PrimitiveType.Double;
|
|
17778
|
-
case "string":
|
|
17779
|
-
return PrimitiveType.String;
|
|
17780
|
-
case "bytes":
|
|
17781
|
-
return PrimitiveType.Bytes;
|
|
17782
|
-
case "date":
|
|
17783
|
-
return PrimitiveType.Date;
|
|
17784
|
-
default:
|
|
17785
|
-
throw new Error(`Unknown primitive type: ${type}`);
|
|
17786
|
-
}
|
|
17787
|
-
}
|
|
17788
|
-
function validatePrimitiveValue(value, rule) {
|
|
17789
|
-
if (value instanceof Primitive && value.getType() === getPrimitiveType(rule.type)) {
|
|
17790
|
-
return { valid: true };
|
|
17791
|
-
}
|
|
17792
|
-
return {
|
|
17793
|
-
valid: false,
|
|
17794
|
-
errors: [
|
|
17795
|
-
{
|
|
17796
|
-
path: rule.path,
|
|
17797
|
-
message: `expected ${rule.type} at path ${rule.path}`
|
|
17798
|
-
}
|
|
17799
|
-
]
|
|
17800
|
-
};
|
|
17801
|
-
}
|
|
17802
17639
|
const Noop = () => {
|
|
17803
17640
|
};
|
|
17804
17641
|
class ObserverProxy {
|
|
@@ -18073,332 +17910,66 @@ class ChangeContext {
|
|
|
18073
17910
|
this.root.acc(diff);
|
|
18074
17911
|
}
|
|
18075
17912
|
}
|
|
18076
|
-
|
|
18077
|
-
|
|
18078
|
-
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
|
|
18082
|
-
|
|
18083
|
-
|
|
18084
|
-
|
|
18085
|
-
|
|
18086
|
-
|
|
18087
|
-
|
|
18088
|
-
|
|
18089
|
-
|
|
18090
|
-
|
|
18091
|
-
|
|
18092
|
-
|
|
18093
|
-
|
|
18094
|
-
|
|
18095
|
-
|
|
18096
|
-
|
|
18097
|
-
|
|
18098
|
-
|
|
18099
|
-
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
|
|
18104
|
-
|
|
18105
|
-
|
|
18106
|
-
|
|
18107
|
-
|
|
18108
|
-
|
|
18109
|
-
|
|
18110
|
-
|
|
18111
|
-
|
|
18112
|
-
|
|
18113
|
-
|
|
18114
|
-
|
|
17913
|
+
function createJSONObject(context, target) {
|
|
17914
|
+
const objectProxy = new ObjectProxy(context);
|
|
17915
|
+
return new Proxy(target, objectProxy.getHandlers());
|
|
17916
|
+
}
|
|
17917
|
+
class ObjectProxy {
|
|
17918
|
+
constructor(context) {
|
|
17919
|
+
__publicField(this, "context");
|
|
17920
|
+
__publicField(this, "handlers");
|
|
17921
|
+
this.context = context;
|
|
17922
|
+
this.handlers = {
|
|
17923
|
+
set: (target, key, value) => {
|
|
17924
|
+
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
17925
|
+
logger.trivial(`obj[${key}]=${JSON.stringify(value)}`);
|
|
17926
|
+
}
|
|
17927
|
+
ObjectProxy.setInternal(context, target, key, value);
|
|
17928
|
+
return true;
|
|
17929
|
+
},
|
|
17930
|
+
get: (target, keyOrMethod) => {
|
|
17931
|
+
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
17932
|
+
logger.trivial(`obj[${keyOrMethod}]`);
|
|
17933
|
+
}
|
|
17934
|
+
if (keyOrMethod === "getID") {
|
|
17935
|
+
return () => {
|
|
17936
|
+
return target.getCreatedAt();
|
|
17937
|
+
};
|
|
17938
|
+
} else if (keyOrMethod === "toJSON" || keyOrMethod === "toString") {
|
|
17939
|
+
return () => {
|
|
17940
|
+
return target.toJSON();
|
|
17941
|
+
};
|
|
17942
|
+
} else if (keyOrMethod === "toJS") {
|
|
17943
|
+
return () => {
|
|
17944
|
+
return target.toJS();
|
|
17945
|
+
};
|
|
17946
|
+
} else if (keyOrMethod === "toJSForTest") {
|
|
17947
|
+
return () => {
|
|
17948
|
+
return target.toJSForTest();
|
|
17949
|
+
};
|
|
17950
|
+
}
|
|
17951
|
+
return toJSONElement(context, target.get(keyOrMethod));
|
|
17952
|
+
},
|
|
17953
|
+
ownKeys: (target) => {
|
|
17954
|
+
return target.getKeys();
|
|
17955
|
+
},
|
|
17956
|
+
getOwnPropertyDescriptor: () => {
|
|
17957
|
+
return {
|
|
17958
|
+
enumerable: true,
|
|
17959
|
+
configurable: true
|
|
17960
|
+
};
|
|
17961
|
+
},
|
|
17962
|
+
deleteProperty: (target, key) => {
|
|
17963
|
+
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
17964
|
+
logger.trivial(`obj[${key}]`);
|
|
18115
17965
|
}
|
|
17966
|
+
ObjectProxy.deleteInternal(context, target, key);
|
|
17967
|
+
return true;
|
|
18116
17968
|
}
|
|
18117
|
-
|
|
18118
|
-
});
|
|
17969
|
+
};
|
|
18119
17970
|
}
|
|
18120
17971
|
/**
|
|
18121
|
-
* `
|
|
18122
|
-
*/
|
|
18123
|
-
static create() {
|
|
18124
|
-
return new CRDTRoot(CRDTObject.create(InitialTimeTicket));
|
|
18125
|
-
}
|
|
18126
|
-
/**
|
|
18127
|
-
* `findByCreatedAt` returns the element of given creation time.
|
|
18128
|
-
*/
|
|
18129
|
-
findByCreatedAt(createdAt) {
|
|
18130
|
-
const pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
|
|
18131
|
-
if (!pair) {
|
|
18132
|
-
return;
|
|
18133
|
-
}
|
|
18134
|
-
return pair.element;
|
|
18135
|
-
}
|
|
18136
|
-
/**
|
|
18137
|
-
* `findElementPairByCreatedAt` returns the element and parent pair
|
|
18138
|
-
* of given creation time.
|
|
18139
|
-
*/
|
|
18140
|
-
findElementPairByCreatedAt(createdAt) {
|
|
18141
|
-
return this.elementPairMapByCreatedAt.get(createdAt.toIDString());
|
|
18142
|
-
}
|
|
18143
|
-
/**
|
|
18144
|
-
* `createSubPaths` creates an array of the sub paths for the given element.
|
|
18145
|
-
*/
|
|
18146
|
-
createSubPaths(createdAt) {
|
|
18147
|
-
let pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
|
|
18148
|
-
if (!pair) {
|
|
18149
|
-
return [];
|
|
18150
|
-
}
|
|
18151
|
-
const subPaths = [];
|
|
18152
|
-
while (pair.parent) {
|
|
18153
|
-
const createdAt2 = pair.element.getCreatedAt();
|
|
18154
|
-
const subPath = pair.parent.subPathOf(createdAt2);
|
|
18155
|
-
if (subPath === void 0) {
|
|
18156
|
-
throw new YorkieError(
|
|
18157
|
-
Code.ErrInvalidArgument,
|
|
18158
|
-
`cant find the given element: ${createdAt2.toIDString()}`
|
|
18159
|
-
);
|
|
18160
|
-
}
|
|
18161
|
-
subPaths.unshift(subPath);
|
|
18162
|
-
pair = this.elementPairMapByCreatedAt.get(
|
|
18163
|
-
pair.parent.getCreatedAt().toIDString()
|
|
18164
|
-
);
|
|
18165
|
-
}
|
|
18166
|
-
subPaths.unshift("$");
|
|
18167
|
-
return subPaths;
|
|
18168
|
-
}
|
|
18169
|
-
/**
|
|
18170
|
-
* `createPath` creates path of the given element.
|
|
18171
|
-
*/
|
|
18172
|
-
createPath(createdAt) {
|
|
18173
|
-
return this.createSubPaths(createdAt).join(".");
|
|
18174
|
-
}
|
|
18175
|
-
/**
|
|
18176
|
-
* `registerElement` registers the given element and its descendants to hash table.
|
|
18177
|
-
*/
|
|
18178
|
-
registerElement(element, parent) {
|
|
18179
|
-
this.elementPairMapByCreatedAt.set(element.getCreatedAt().toIDString(), {
|
|
18180
|
-
parent,
|
|
18181
|
-
element
|
|
18182
|
-
});
|
|
18183
|
-
addDataSizes(this.docSize.live, element.getDataSize());
|
|
18184
|
-
if (element instanceof CRDTContainer) {
|
|
18185
|
-
element.getDescendants((elem, par) => {
|
|
18186
|
-
this.elementPairMapByCreatedAt.set(elem.getCreatedAt().toIDString(), {
|
|
18187
|
-
parent: par,
|
|
18188
|
-
element: elem
|
|
18189
|
-
});
|
|
18190
|
-
addDataSizes(this.docSize.live, elem.getDataSize());
|
|
18191
|
-
return false;
|
|
18192
|
-
});
|
|
18193
|
-
}
|
|
18194
|
-
}
|
|
18195
|
-
/**
|
|
18196
|
-
* `deregisterElement` deregister the given element and its descendants from hash table.
|
|
18197
|
-
*/
|
|
18198
|
-
deregisterElement(element) {
|
|
18199
|
-
let count = 0;
|
|
18200
|
-
const deregisterElementInternal = (elem) => {
|
|
18201
|
-
const createdAt = elem.getCreatedAt().toIDString();
|
|
18202
|
-
subDataSize(this.docSize.gc, elem.getDataSize());
|
|
18203
|
-
this.elementPairMapByCreatedAt.delete(createdAt);
|
|
18204
|
-
this.gcElementSetByCreatedAt.delete(createdAt);
|
|
18205
|
-
count++;
|
|
18206
|
-
};
|
|
18207
|
-
deregisterElementInternal(element);
|
|
18208
|
-
if (element instanceof CRDTContainer) {
|
|
18209
|
-
element.getDescendants((e) => {
|
|
18210
|
-
deregisterElementInternal(e);
|
|
18211
|
-
return false;
|
|
18212
|
-
});
|
|
18213
|
-
}
|
|
18214
|
-
return count;
|
|
18215
|
-
}
|
|
18216
|
-
/**
|
|
18217
|
-
* `registerRemovedElement` registers the given element to the hash set.
|
|
18218
|
-
*/
|
|
18219
|
-
registerRemovedElement(element) {
|
|
18220
|
-
addDataSizes(this.docSize.gc, element.getDataSize());
|
|
18221
|
-
subDataSize(this.docSize.live, element.getDataSize());
|
|
18222
|
-
this.docSize.live.meta += TimeTicketSize;
|
|
18223
|
-
this.gcElementSetByCreatedAt.add(element.getCreatedAt().toIDString());
|
|
18224
|
-
}
|
|
18225
|
-
/**
|
|
18226
|
-
* `registerGCPair` registers the given pair to hash table.
|
|
18227
|
-
*/
|
|
18228
|
-
registerGCPair(pair) {
|
|
18229
|
-
const prev = this.gcPairMap.get(pair.child.toIDString());
|
|
18230
|
-
if (prev) {
|
|
18231
|
-
this.gcPairMap.delete(pair.child.toIDString());
|
|
18232
|
-
return;
|
|
18233
|
-
}
|
|
18234
|
-
this.gcPairMap.set(pair.child.toIDString(), pair);
|
|
18235
|
-
const size = this.gcPairMap.get(pair.child.toIDString()).child.getDataSize();
|
|
18236
|
-
addDataSizes(this.docSize.gc, size);
|
|
18237
|
-
subDataSize(this.docSize.live, size);
|
|
18238
|
-
if (!(pair.child instanceof RHTNode)) {
|
|
18239
|
-
this.docSize.live.meta += TimeTicketSize;
|
|
18240
|
-
}
|
|
18241
|
-
}
|
|
18242
|
-
/**
|
|
18243
|
-
* `getElementMapSize` returns the size of element map.
|
|
18244
|
-
*/
|
|
18245
|
-
getElementMapSize() {
|
|
18246
|
-
return this.elementPairMapByCreatedAt.size;
|
|
18247
|
-
}
|
|
18248
|
-
/**
|
|
18249
|
-
* `getGarbageElementSetSize()` returns the size of removed element set.
|
|
18250
|
-
*/
|
|
18251
|
-
getGarbageElementSetSize() {
|
|
18252
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18253
|
-
for (const createdAt of this.gcElementSetByCreatedAt) {
|
|
18254
|
-
seen.add(createdAt);
|
|
18255
|
-
const pair = this.elementPairMapByCreatedAt.get(createdAt);
|
|
18256
|
-
if (pair.element instanceof CRDTContainer) {
|
|
18257
|
-
pair.element.getDescendants((el) => {
|
|
18258
|
-
seen.add(el.getCreatedAt().toIDString());
|
|
18259
|
-
return false;
|
|
18260
|
-
});
|
|
18261
|
-
}
|
|
18262
|
-
}
|
|
18263
|
-
return seen.size;
|
|
18264
|
-
}
|
|
18265
|
-
/**
|
|
18266
|
-
* `getObject` returns root object.
|
|
18267
|
-
*/
|
|
18268
|
-
getObject() {
|
|
18269
|
-
return this.rootObject;
|
|
18270
|
-
}
|
|
18271
|
-
/**
|
|
18272
|
-
* `getGarbageLen` returns length of nodes which can be garbage collected.
|
|
18273
|
-
*/
|
|
18274
|
-
getGarbageLen() {
|
|
18275
|
-
return this.getGarbageElementSetSize() + this.gcPairMap.size;
|
|
18276
|
-
}
|
|
18277
|
-
/**
|
|
18278
|
-
* `getDocSize` returns the size of the document.
|
|
18279
|
-
*/
|
|
18280
|
-
getDocSize() {
|
|
18281
|
-
return this.docSize;
|
|
18282
|
-
}
|
|
18283
|
-
/**
|
|
18284
|
-
* `deepcopy` copies itself deeply.
|
|
18285
|
-
*/
|
|
18286
|
-
deepcopy() {
|
|
18287
|
-
return new CRDTRoot(this.rootObject.deepcopy());
|
|
18288
|
-
}
|
|
18289
|
-
/**
|
|
18290
|
-
* `garbageCollect` purges elements that were removed before the given time.
|
|
18291
|
-
*/
|
|
18292
|
-
garbageCollect(minSyncedVersionVector) {
|
|
18293
|
-
let count = 0;
|
|
18294
|
-
for (const createdAt of this.gcElementSetByCreatedAt) {
|
|
18295
|
-
const pair = this.elementPairMapByCreatedAt.get(createdAt);
|
|
18296
|
-
const removedAt = pair.element.getRemovedAt();
|
|
18297
|
-
if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
|
|
18298
|
-
pair.parent.purge(pair.element);
|
|
18299
|
-
count += this.deregisterElement(pair.element);
|
|
18300
|
-
}
|
|
18301
|
-
}
|
|
18302
|
-
for (const [, pair] of this.gcPairMap) {
|
|
18303
|
-
const removedAt = pair.child.getRemovedAt();
|
|
18304
|
-
if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
|
|
18305
|
-
pair.parent.purge(pair.child);
|
|
18306
|
-
this.gcPairMap.delete(pair.child.toIDString());
|
|
18307
|
-
count += 1;
|
|
18308
|
-
}
|
|
18309
|
-
}
|
|
18310
|
-
return count;
|
|
18311
|
-
}
|
|
18312
|
-
/**
|
|
18313
|
-
* `toJSON` returns the JSON encoding of this root object.
|
|
18314
|
-
*/
|
|
18315
|
-
toJSON() {
|
|
18316
|
-
return this.rootObject.toJSON();
|
|
18317
|
-
}
|
|
18318
|
-
/**
|
|
18319
|
-
* `toSortedJSON` returns the sorted JSON encoding of this root object.
|
|
18320
|
-
*/
|
|
18321
|
-
toSortedJSON() {
|
|
18322
|
-
return this.rootObject.toSortedJSON();
|
|
18323
|
-
}
|
|
18324
|
-
/**
|
|
18325
|
-
* `getStats` returns the current statistics of the root object.
|
|
18326
|
-
* This includes counts of various types of elements and structural information.
|
|
18327
|
-
*/
|
|
18328
|
-
getStats() {
|
|
18329
|
-
return {
|
|
18330
|
-
elements: this.getElementMapSize(),
|
|
18331
|
-
gcPairs: this.gcPairMap.size,
|
|
18332
|
-
gcElements: this.getGarbageElementSetSize()
|
|
18333
|
-
};
|
|
18334
|
-
}
|
|
18335
|
-
/**
|
|
18336
|
-
* `acc` accumulates the given DataSize to Live.
|
|
18337
|
-
*/
|
|
18338
|
-
acc(diff) {
|
|
18339
|
-
addDataSizes(this.docSize.live, diff);
|
|
18340
|
-
}
|
|
18341
|
-
}
|
|
18342
|
-
function createJSONObject(context, target) {
|
|
18343
|
-
const objectProxy = new ObjectProxy(context);
|
|
18344
|
-
return new Proxy(target, objectProxy.getHandlers());
|
|
18345
|
-
}
|
|
18346
|
-
class ObjectProxy {
|
|
18347
|
-
constructor(context) {
|
|
18348
|
-
__publicField(this, "context");
|
|
18349
|
-
__publicField(this, "handlers");
|
|
18350
|
-
this.context = context;
|
|
18351
|
-
this.handlers = {
|
|
18352
|
-
set: (target, key, value) => {
|
|
18353
|
-
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
18354
|
-
logger.trivial(`obj[${key}]=${JSON.stringify(value)}`);
|
|
18355
|
-
}
|
|
18356
|
-
ObjectProxy.setInternal(context, target, key, value);
|
|
18357
|
-
return true;
|
|
18358
|
-
},
|
|
18359
|
-
get: (target, keyOrMethod) => {
|
|
18360
|
-
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
18361
|
-
logger.trivial(`obj[${keyOrMethod}]`);
|
|
18362
|
-
}
|
|
18363
|
-
if (keyOrMethod === "getID") {
|
|
18364
|
-
return () => {
|
|
18365
|
-
return target.getCreatedAt();
|
|
18366
|
-
};
|
|
18367
|
-
} else if (keyOrMethod === "toJSON" || keyOrMethod === "toString") {
|
|
18368
|
-
return () => {
|
|
18369
|
-
return target.toJSON();
|
|
18370
|
-
};
|
|
18371
|
-
} else if (keyOrMethod === "toJS") {
|
|
18372
|
-
return () => {
|
|
18373
|
-
return target.toJS();
|
|
18374
|
-
};
|
|
18375
|
-
} else if (keyOrMethod === "toJSForTest") {
|
|
18376
|
-
return () => {
|
|
18377
|
-
return target.toJSForTest();
|
|
18378
|
-
};
|
|
18379
|
-
}
|
|
18380
|
-
return toJSONElement(context, target.get(keyOrMethod));
|
|
18381
|
-
},
|
|
18382
|
-
ownKeys: (target) => {
|
|
18383
|
-
return target.getKeys();
|
|
18384
|
-
},
|
|
18385
|
-
getOwnPropertyDescriptor: () => {
|
|
18386
|
-
return {
|
|
18387
|
-
enumerable: true,
|
|
18388
|
-
configurable: true
|
|
18389
|
-
};
|
|
18390
|
-
},
|
|
18391
|
-
deleteProperty: (target, key) => {
|
|
18392
|
-
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
18393
|
-
logger.trivial(`obj[${key}]`);
|
|
18394
|
-
}
|
|
18395
|
-
ObjectProxy.deleteInternal(context, target, key);
|
|
18396
|
-
return true;
|
|
18397
|
-
}
|
|
18398
|
-
};
|
|
18399
|
-
}
|
|
18400
|
-
/**
|
|
18401
|
-
* `setInternal` sets a new Object for the given key
|
|
17972
|
+
* `setInternal` sets a new Object for the given key
|
|
18402
17973
|
*/
|
|
18403
17974
|
static setInternal(context, target, key, value) {
|
|
18404
17975
|
if (key.includes(".")) {
|
|
@@ -19043,7 +18614,6 @@ class Text {
|
|
|
19043
18614
|
}
|
|
19044
18615
|
/**
|
|
19045
18616
|
* `initialize` initialize this text with context and internal text.
|
|
19046
|
-
* @internal
|
|
19047
18617
|
*/
|
|
19048
18618
|
initialize(context, text) {
|
|
19049
18619
|
this.context = context;
|
|
@@ -19253,7 +18823,6 @@ class Text {
|
|
|
19253
18823
|
}
|
|
19254
18824
|
/**
|
|
19255
18825
|
* `toJSForTest` returns value with meta data for testing.
|
|
19256
|
-
* @internal
|
|
19257
18826
|
*/
|
|
19258
18827
|
toJSForTest() {
|
|
19259
18828
|
if (!this.context || !this.text) {
|
|
@@ -19289,7 +18858,6 @@ class Counter {
|
|
|
19289
18858
|
}
|
|
19290
18859
|
/**
|
|
19291
18860
|
* `initialize` initialize this text with context and internal text.
|
|
19292
|
-
* @internal
|
|
19293
18861
|
*/
|
|
19294
18862
|
initialize(context, counter) {
|
|
19295
18863
|
this.valueType = counter.getValueType();
|
|
@@ -19305,7 +18873,6 @@ class Counter {
|
|
|
19305
18873
|
}
|
|
19306
18874
|
/**
|
|
19307
18875
|
* `getValue` returns the value of this counter;
|
|
19308
|
-
* @internal
|
|
19309
18876
|
*/
|
|
19310
18877
|
getValue() {
|
|
19311
18878
|
return this.value;
|
|
@@ -19341,7 +18908,6 @@ class Counter {
|
|
|
19341
18908
|
}
|
|
19342
18909
|
/**
|
|
19343
18910
|
* `toJSForTest` returns value with meta data for testing.
|
|
19344
|
-
* @internal
|
|
19345
18911
|
*/
|
|
19346
18912
|
toJSForTest() {
|
|
19347
18913
|
if (!this.context || !this.counter) {
|
|
@@ -19540,7 +19106,6 @@ class Tree {
|
|
|
19540
19106
|
}
|
|
19541
19107
|
/**
|
|
19542
19108
|
* `initialize` initialize this tree with context and internal tree.
|
|
19543
|
-
* @internal
|
|
19544
19109
|
*/
|
|
19545
19110
|
initialize(context, tree) {
|
|
19546
19111
|
this.context = context;
|
|
@@ -19552,593 +19117,857 @@ class Tree {
|
|
|
19552
19117
|
getID() {
|
|
19553
19118
|
return this.tree.getID();
|
|
19554
19119
|
}
|
|
19555
|
-
/**
|
|
19556
|
-
* `buildRoot` builds the root of this tree with the given initial root
|
|
19557
|
-
* which set by the user.
|
|
19558
|
-
*/
|
|
19559
|
-
buildRoot(context) {
|
|
19560
|
-
if (!this.initialRoot) {
|
|
19561
|
-
return CRDTTreeNode.create(
|
|
19562
|
-
CRDTTreeNodeID.of(context.issueTimeTicket(), 0),
|
|
19563
|
-
DefaultRootType
|
|
19120
|
+
/**
|
|
19121
|
+
* `buildRoot` builds the root of this tree with the given initial root
|
|
19122
|
+
* which set by the user.
|
|
19123
|
+
*/
|
|
19124
|
+
buildRoot(context) {
|
|
19125
|
+
if (!this.initialRoot) {
|
|
19126
|
+
return CRDTTreeNode.create(
|
|
19127
|
+
CRDTTreeNodeID.of(context.issueTimeTicket(), 0),
|
|
19128
|
+
DefaultRootType
|
|
19129
|
+
);
|
|
19130
|
+
}
|
|
19131
|
+
const root = CRDTTreeNode.create(
|
|
19132
|
+
CRDTTreeNodeID.of(context.issueTimeTicket(), 0),
|
|
19133
|
+
this.initialRoot.type
|
|
19134
|
+
);
|
|
19135
|
+
for (const child of this.initialRoot.children) {
|
|
19136
|
+
buildDescendants(child, root, context);
|
|
19137
|
+
}
|
|
19138
|
+
return root;
|
|
19139
|
+
}
|
|
19140
|
+
/**
|
|
19141
|
+
* `getSize` returns the size of this tree.
|
|
19142
|
+
*/
|
|
19143
|
+
getSize() {
|
|
19144
|
+
if (!this.context || !this.tree) {
|
|
19145
|
+
throw new YorkieError(
|
|
19146
|
+
Code.ErrNotInitialized,
|
|
19147
|
+
"Tree is not initialized yet"
|
|
19148
|
+
);
|
|
19149
|
+
}
|
|
19150
|
+
return this.tree.getSize();
|
|
19151
|
+
}
|
|
19152
|
+
/**
|
|
19153
|
+
* `getNodeSize` returns the node size of this tree.
|
|
19154
|
+
*/
|
|
19155
|
+
getNodeSize() {
|
|
19156
|
+
if (!this.context || !this.tree) {
|
|
19157
|
+
throw new YorkieError(
|
|
19158
|
+
Code.ErrNotInitialized,
|
|
19159
|
+
"Tree is not initialized yet"
|
|
19160
|
+
);
|
|
19161
|
+
}
|
|
19162
|
+
return this.tree.getNodeSize();
|
|
19163
|
+
}
|
|
19164
|
+
/**
|
|
19165
|
+
* `getIndexTree` returns the index tree of this tree.
|
|
19166
|
+
*/
|
|
19167
|
+
getIndexTree() {
|
|
19168
|
+
if (!this.context || !this.tree) {
|
|
19169
|
+
throw new YorkieError(
|
|
19170
|
+
Code.ErrNotInitialized,
|
|
19171
|
+
"Tree is not initialized yet"
|
|
19172
|
+
);
|
|
19173
|
+
}
|
|
19174
|
+
return this.tree.getIndexTree();
|
|
19175
|
+
}
|
|
19176
|
+
/**
|
|
19177
|
+
* `splitByPath` splits the tree by the given path.
|
|
19178
|
+
*/
|
|
19179
|
+
splitByPath(path) {
|
|
19180
|
+
if (!this.context || !this.tree) {
|
|
19181
|
+
throw new YorkieError(
|
|
19182
|
+
Code.ErrNotInitialized,
|
|
19183
|
+
"Tree is not initialized yet"
|
|
19184
|
+
);
|
|
19185
|
+
}
|
|
19186
|
+
if (!path.length) {
|
|
19187
|
+
throw new YorkieError(
|
|
19188
|
+
Code.ErrInvalidArgument,
|
|
19189
|
+
"path should not be empty"
|
|
19190
|
+
);
|
|
19191
|
+
}
|
|
19192
|
+
const treePos = this.tree.pathToTreePos(path);
|
|
19193
|
+
const commands = separateSplit(treePos, path);
|
|
19194
|
+
for (const command of commands) {
|
|
19195
|
+
const { fromPath, toPath, content } = command;
|
|
19196
|
+
const fromPos = this.tree.pathToPos(fromPath);
|
|
19197
|
+
const toPos = this.tree.pathToPos(toPath);
|
|
19198
|
+
this.editInternal(fromPos, toPos, content ? [content] : [], 0);
|
|
19199
|
+
}
|
|
19200
|
+
}
|
|
19201
|
+
/**
|
|
19202
|
+
* `mergeByPath` merges the tree by the given path.
|
|
19203
|
+
*/
|
|
19204
|
+
mergeByPath(path) {
|
|
19205
|
+
if (!this.context || !this.tree) {
|
|
19206
|
+
throw new YorkieError(
|
|
19207
|
+
Code.ErrNotInitialized,
|
|
19208
|
+
"Tree is not initialized yet"
|
|
19209
|
+
);
|
|
19210
|
+
}
|
|
19211
|
+
if (!path.length) {
|
|
19212
|
+
throw new YorkieError(
|
|
19213
|
+
Code.ErrInvalidArgument,
|
|
19214
|
+
"path should not be empty"
|
|
19215
|
+
);
|
|
19216
|
+
}
|
|
19217
|
+
const treePos = this.tree.pathToTreePos(path);
|
|
19218
|
+
if (treePos.node.isText) {
|
|
19219
|
+
throw new YorkieError(
|
|
19220
|
+
Code.ErrInvalidArgument,
|
|
19221
|
+
"text node cannot be merged"
|
|
19222
|
+
);
|
|
19223
|
+
}
|
|
19224
|
+
const commands = separateMerge(treePos, path);
|
|
19225
|
+
for (const command of commands) {
|
|
19226
|
+
const { fromPath, toPath, content } = command;
|
|
19227
|
+
const fromPos = this.tree.pathToPos(fromPath);
|
|
19228
|
+
const toPos = this.tree.pathToPos(toPath);
|
|
19229
|
+
this.editInternal(fromPos, toPos, content ?? [], 0);
|
|
19230
|
+
}
|
|
19231
|
+
}
|
|
19232
|
+
/**
|
|
19233
|
+
* `styleByPath` sets the attributes to the elements of the given path.
|
|
19234
|
+
*/
|
|
19235
|
+
styleByPath(path, attributes) {
|
|
19236
|
+
if (!this.context || !this.tree) {
|
|
19237
|
+
throw new YorkieError(
|
|
19238
|
+
Code.ErrNotInitialized,
|
|
19239
|
+
"Tree is not initialized yet"
|
|
19240
|
+
);
|
|
19241
|
+
}
|
|
19242
|
+
if (!path.length) {
|
|
19243
|
+
throw new YorkieError(
|
|
19244
|
+
Code.ErrInvalidArgument,
|
|
19245
|
+
"path should not be empty"
|
|
19246
|
+
);
|
|
19247
|
+
}
|
|
19248
|
+
const [fromPos, toPos] = this.tree.pathToPosRange(path);
|
|
19249
|
+
const ticket = this.context.issueTimeTicket();
|
|
19250
|
+
const attrs = attributes ? stringifyObjectValues(attributes) : void 0;
|
|
19251
|
+
const [pairs, , diff] = this.tree.style([fromPos, toPos], attrs, ticket);
|
|
19252
|
+
this.context.acc(diff);
|
|
19253
|
+
for (const pair of pairs) {
|
|
19254
|
+
this.context.registerGCPair(pair);
|
|
19255
|
+
}
|
|
19256
|
+
this.context.push(
|
|
19257
|
+
TreeStyleOperation.create(
|
|
19258
|
+
this.tree.getCreatedAt(),
|
|
19259
|
+
fromPos,
|
|
19260
|
+
toPos,
|
|
19261
|
+
attrs ? new Map(Object.entries(attrs)) : /* @__PURE__ */ new Map(),
|
|
19262
|
+
ticket
|
|
19263
|
+
)
|
|
19264
|
+
);
|
|
19265
|
+
}
|
|
19266
|
+
/**
|
|
19267
|
+
* `style` sets the attributes to the elements of the given range.
|
|
19268
|
+
*/
|
|
19269
|
+
style(fromIdx, toIdx, attributes) {
|
|
19270
|
+
if (!this.context || !this.tree) {
|
|
19271
|
+
throw new YorkieError(
|
|
19272
|
+
Code.ErrNotInitialized,
|
|
19273
|
+
"Tree is not initialized yet"
|
|
19274
|
+
);
|
|
19275
|
+
}
|
|
19276
|
+
if (fromIdx > toIdx) {
|
|
19277
|
+
throw new YorkieError(
|
|
19278
|
+
Code.ErrInvalidArgument,
|
|
19279
|
+
"from should be less than or equal to to"
|
|
19280
|
+
);
|
|
19281
|
+
}
|
|
19282
|
+
const fromPos = this.tree.findPos(fromIdx);
|
|
19283
|
+
const toPos = this.tree.findPos(toIdx);
|
|
19284
|
+
const ticket = this.context.issueTimeTicket();
|
|
19285
|
+
const attrs = attributes ? stringifyObjectValues(attributes) : void 0;
|
|
19286
|
+
const [pairs, , diff] = this.tree.style([fromPos, toPos], attrs, ticket);
|
|
19287
|
+
this.context.acc(diff);
|
|
19288
|
+
for (const pair of pairs) {
|
|
19289
|
+
this.context.registerGCPair(pair);
|
|
19290
|
+
}
|
|
19291
|
+
this.context.push(
|
|
19292
|
+
TreeStyleOperation.create(
|
|
19293
|
+
this.tree.getCreatedAt(),
|
|
19294
|
+
fromPos,
|
|
19295
|
+
toPos,
|
|
19296
|
+
attrs ? new Map(Object.entries(attrs)) : /* @__PURE__ */ new Map(),
|
|
19297
|
+
ticket
|
|
19298
|
+
)
|
|
19299
|
+
);
|
|
19300
|
+
}
|
|
19301
|
+
/**
|
|
19302
|
+
* `removeStyle` removes the attributes to the elements of the given range.
|
|
19303
|
+
*/
|
|
19304
|
+
removeStyle(fromIdx, toIdx, attributesToRemove) {
|
|
19305
|
+
if (!this.context || !this.tree) {
|
|
19306
|
+
throw new YorkieError(
|
|
19307
|
+
Code.ErrNotInitialized,
|
|
19308
|
+
"Tree is not initialized yet"
|
|
19309
|
+
);
|
|
19310
|
+
}
|
|
19311
|
+
if (fromIdx > toIdx) {
|
|
19312
|
+
throw new YorkieError(
|
|
19313
|
+
Code.ErrInvalidArgument,
|
|
19314
|
+
"from should be less than or equal to to"
|
|
19315
|
+
);
|
|
19316
|
+
}
|
|
19317
|
+
const fromPos = this.tree.findPos(fromIdx);
|
|
19318
|
+
const toPos = this.tree.findPos(toIdx);
|
|
19319
|
+
const ticket = this.context.issueTimeTicket();
|
|
19320
|
+
const [pairs, , diff] = this.tree.removeStyle(
|
|
19321
|
+
[fromPos, toPos],
|
|
19322
|
+
attributesToRemove,
|
|
19323
|
+
ticket
|
|
19324
|
+
);
|
|
19325
|
+
this.context.acc(diff);
|
|
19326
|
+
for (const pair of pairs) {
|
|
19327
|
+
this.context.registerGCPair(pair);
|
|
19328
|
+
}
|
|
19329
|
+
this.context.push(
|
|
19330
|
+
TreeStyleOperation.createTreeRemoveStyleOperation(
|
|
19331
|
+
this.tree.getCreatedAt(),
|
|
19332
|
+
fromPos,
|
|
19333
|
+
toPos,
|
|
19334
|
+
attributesToRemove,
|
|
19335
|
+
ticket
|
|
19336
|
+
)
|
|
19337
|
+
);
|
|
19338
|
+
}
|
|
19339
|
+
editInternal(fromPos, toPos, contents, splitLevel = 0) {
|
|
19340
|
+
var _a2;
|
|
19341
|
+
if (contents.length !== 0 && contents[0]) {
|
|
19342
|
+
validateTreeNodes(contents);
|
|
19343
|
+
if (contents[0].type !== DefaultTextType) {
|
|
19344
|
+
for (const content of contents) {
|
|
19345
|
+
const { children = [] } = content;
|
|
19346
|
+
validateTreeNodes(children);
|
|
19347
|
+
}
|
|
19348
|
+
}
|
|
19349
|
+
}
|
|
19350
|
+
const ticket = this.context.getLastTimeTicket();
|
|
19351
|
+
let crdtNodes = new Array();
|
|
19352
|
+
if (((_a2 = contents[0]) == null ? void 0 : _a2.type) === DefaultTextType) {
|
|
19353
|
+
let compVal = "";
|
|
19354
|
+
for (const content of contents) {
|
|
19355
|
+
const { value } = content;
|
|
19356
|
+
compVal += value;
|
|
19357
|
+
}
|
|
19358
|
+
crdtNodes.push(
|
|
19359
|
+
CRDTTreeNode.create(
|
|
19360
|
+
CRDTTreeNodeID.of(this.context.issueTimeTicket(), 0),
|
|
19361
|
+
DefaultTextType,
|
|
19362
|
+
compVal
|
|
19363
|
+
)
|
|
19564
19364
|
);
|
|
19365
|
+
} else {
|
|
19366
|
+
crdtNodes = contents.map((content) => content && createCRDTTreeNode(this.context, content)).filter((a) => a);
|
|
19565
19367
|
}
|
|
19566
|
-
const
|
|
19567
|
-
|
|
19568
|
-
|
|
19368
|
+
const [, pairs, diff] = this.tree.edit(
|
|
19369
|
+
[fromPos, toPos],
|
|
19370
|
+
crdtNodes.length ? crdtNodes.map((crdtNode) => crdtNode == null ? void 0 : crdtNode.deepcopy()) : void 0,
|
|
19371
|
+
splitLevel,
|
|
19372
|
+
ticket,
|
|
19373
|
+
() => this.context.issueTimeTicket()
|
|
19569
19374
|
);
|
|
19570
|
-
|
|
19571
|
-
|
|
19375
|
+
this.context.acc(diff);
|
|
19376
|
+
for (const pair of pairs) {
|
|
19377
|
+
this.context.registerGCPair(pair);
|
|
19572
19378
|
}
|
|
19573
|
-
|
|
19379
|
+
this.context.push(
|
|
19380
|
+
TreeEditOperation.create(
|
|
19381
|
+
this.tree.getCreatedAt(),
|
|
19382
|
+
fromPos,
|
|
19383
|
+
toPos,
|
|
19384
|
+
crdtNodes.length ? crdtNodes : void 0,
|
|
19385
|
+
splitLevel,
|
|
19386
|
+
ticket
|
|
19387
|
+
)
|
|
19388
|
+
);
|
|
19389
|
+
return true;
|
|
19574
19390
|
}
|
|
19575
19391
|
/**
|
|
19576
|
-
* `
|
|
19392
|
+
* `editByPath` edits this tree with the given node and path.
|
|
19577
19393
|
*/
|
|
19578
|
-
|
|
19394
|
+
editByPath(fromPath, toPath, content, splitLevel = 0) {
|
|
19579
19395
|
if (!this.context || !this.tree) {
|
|
19580
19396
|
throw new YorkieError(
|
|
19581
19397
|
Code.ErrNotInitialized,
|
|
19582
19398
|
"Tree is not initialized yet"
|
|
19583
19399
|
);
|
|
19584
19400
|
}
|
|
19585
|
-
|
|
19401
|
+
if (fromPath.length !== toPath.length) {
|
|
19402
|
+
throw new YorkieError(
|
|
19403
|
+
Code.ErrInvalidArgument,
|
|
19404
|
+
"path length should be equal"
|
|
19405
|
+
);
|
|
19406
|
+
}
|
|
19407
|
+
if (!fromPath.length || !toPath.length) {
|
|
19408
|
+
throw new YorkieError(
|
|
19409
|
+
Code.ErrInvalidArgument,
|
|
19410
|
+
"path should not be empty"
|
|
19411
|
+
);
|
|
19412
|
+
}
|
|
19413
|
+
const fromPos = this.tree.pathToPos(fromPath);
|
|
19414
|
+
const toPos = this.tree.pathToPos(toPath);
|
|
19415
|
+
return this.editInternal(
|
|
19416
|
+
fromPos,
|
|
19417
|
+
toPos,
|
|
19418
|
+
content ? [content] : [],
|
|
19419
|
+
splitLevel
|
|
19420
|
+
);
|
|
19586
19421
|
}
|
|
19587
19422
|
/**
|
|
19588
|
-
* `
|
|
19423
|
+
* `editBulkByPath` edits this tree with the given node and path.
|
|
19589
19424
|
*/
|
|
19590
|
-
|
|
19425
|
+
editBulkByPath(fromPath, toPath, contents, splitLevel = 0) {
|
|
19591
19426
|
if (!this.context || !this.tree) {
|
|
19592
19427
|
throw new YorkieError(
|
|
19593
19428
|
Code.ErrNotInitialized,
|
|
19594
19429
|
"Tree is not initialized yet"
|
|
19595
19430
|
);
|
|
19596
19431
|
}
|
|
19597
|
-
|
|
19432
|
+
if (fromPath.length !== toPath.length) {
|
|
19433
|
+
throw new YorkieError(
|
|
19434
|
+
Code.ErrInvalidArgument,
|
|
19435
|
+
"path length should be equal"
|
|
19436
|
+
);
|
|
19437
|
+
}
|
|
19438
|
+
if (!fromPath.length || !toPath.length) {
|
|
19439
|
+
throw new YorkieError(
|
|
19440
|
+
Code.ErrInvalidArgument,
|
|
19441
|
+
"path should not be empty"
|
|
19442
|
+
);
|
|
19443
|
+
}
|
|
19444
|
+
const fromPos = this.tree.pathToPos(fromPath);
|
|
19445
|
+
const toPos = this.tree.pathToPos(toPath);
|
|
19446
|
+
return this.editInternal(fromPos, toPos, contents, splitLevel);
|
|
19598
19447
|
}
|
|
19599
19448
|
/**
|
|
19600
|
-
* `
|
|
19449
|
+
* `edit` edits this tree with the given nodes.
|
|
19601
19450
|
*/
|
|
19602
|
-
|
|
19451
|
+
edit(fromIdx, toIdx, content, splitLevel = 0) {
|
|
19603
19452
|
if (!this.context || !this.tree) {
|
|
19604
19453
|
throw new YorkieError(
|
|
19605
19454
|
Code.ErrNotInitialized,
|
|
19606
19455
|
"Tree is not initialized yet"
|
|
19607
19456
|
);
|
|
19608
19457
|
}
|
|
19609
|
-
|
|
19458
|
+
if (fromIdx > toIdx) {
|
|
19459
|
+
throw new YorkieError(
|
|
19460
|
+
Code.ErrInvalidArgument,
|
|
19461
|
+
"from should be less than or equal to to"
|
|
19462
|
+
);
|
|
19463
|
+
}
|
|
19464
|
+
const fromPos = this.tree.findPos(fromIdx);
|
|
19465
|
+
const toPos = this.tree.findPos(toIdx);
|
|
19466
|
+
return this.editInternal(
|
|
19467
|
+
fromPos,
|
|
19468
|
+
toPos,
|
|
19469
|
+
content ? [content] : [],
|
|
19470
|
+
splitLevel
|
|
19471
|
+
);
|
|
19610
19472
|
}
|
|
19611
19473
|
/**
|
|
19612
|
-
* `
|
|
19474
|
+
* `editBulk` edits this tree with the given nodes.
|
|
19613
19475
|
*/
|
|
19614
|
-
|
|
19476
|
+
editBulk(fromIdx, toIdx, contents, splitLevel = 0) {
|
|
19615
19477
|
if (!this.context || !this.tree) {
|
|
19616
19478
|
throw new YorkieError(
|
|
19617
19479
|
Code.ErrNotInitialized,
|
|
19618
19480
|
"Tree is not initialized yet"
|
|
19619
19481
|
);
|
|
19620
19482
|
}
|
|
19621
|
-
if (
|
|
19483
|
+
if (fromIdx > toIdx) {
|
|
19622
19484
|
throw new YorkieError(
|
|
19623
19485
|
Code.ErrInvalidArgument,
|
|
19624
|
-
"
|
|
19486
|
+
"from should be less than or equal to to"
|
|
19625
19487
|
);
|
|
19626
19488
|
}
|
|
19627
|
-
const
|
|
19628
|
-
const
|
|
19629
|
-
|
|
19630
|
-
const { fromPath, toPath, content } = command;
|
|
19631
|
-
const fromPos = this.tree.pathToPos(fromPath);
|
|
19632
|
-
const toPos = this.tree.pathToPos(toPath);
|
|
19633
|
-
this.editInternal(fromPos, toPos, content ? [content] : [], 0);
|
|
19634
|
-
}
|
|
19489
|
+
const fromPos = this.tree.findPos(fromIdx);
|
|
19490
|
+
const toPos = this.tree.findPos(toIdx);
|
|
19491
|
+
return this.editInternal(fromPos, toPos, contents, splitLevel);
|
|
19635
19492
|
}
|
|
19636
19493
|
/**
|
|
19637
|
-
* `
|
|
19494
|
+
* `toXML` returns the XML string of this tree.
|
|
19638
19495
|
*/
|
|
19639
|
-
|
|
19496
|
+
toXML() {
|
|
19640
19497
|
if (!this.context || !this.tree) {
|
|
19641
19498
|
throw new YorkieError(
|
|
19642
19499
|
Code.ErrNotInitialized,
|
|
19643
19500
|
"Tree is not initialized yet"
|
|
19644
19501
|
);
|
|
19645
19502
|
}
|
|
19646
|
-
|
|
19503
|
+
return this.tree.toXML();
|
|
19504
|
+
}
|
|
19505
|
+
/**
|
|
19506
|
+
* `toJSON` returns the JSON string of this tree.
|
|
19507
|
+
*/
|
|
19508
|
+
toJSON() {
|
|
19509
|
+
if (!this.context || !this.tree) {
|
|
19647
19510
|
throw new YorkieError(
|
|
19648
|
-
Code.
|
|
19649
|
-
"
|
|
19511
|
+
Code.ErrNotInitialized,
|
|
19512
|
+
"Tree is not initialized yet"
|
|
19650
19513
|
);
|
|
19651
19514
|
}
|
|
19652
|
-
|
|
19653
|
-
|
|
19515
|
+
return this.tree.toJSON();
|
|
19516
|
+
}
|
|
19517
|
+
/**
|
|
19518
|
+
* `toJSForTest` returns value with meta data for testing.
|
|
19519
|
+
*/
|
|
19520
|
+
toJSForTest() {
|
|
19521
|
+
if (!this.context || !this.tree) {
|
|
19654
19522
|
throw new YorkieError(
|
|
19655
|
-
Code.
|
|
19656
|
-
"
|
|
19523
|
+
Code.ErrNotInitialized,
|
|
19524
|
+
"Tree is not initialized yet"
|
|
19657
19525
|
);
|
|
19658
19526
|
}
|
|
19659
|
-
|
|
19660
|
-
for (const command of commands) {
|
|
19661
|
-
const { fromPath, toPath, content } = command;
|
|
19662
|
-
const fromPos = this.tree.pathToPos(fromPath);
|
|
19663
|
-
const toPos = this.tree.pathToPos(toPath);
|
|
19664
|
-
this.editInternal(fromPos, toPos, content ?? [], 0);
|
|
19665
|
-
}
|
|
19527
|
+
return this.tree.toJSForTest();
|
|
19666
19528
|
}
|
|
19667
19529
|
/**
|
|
19668
|
-
* `
|
|
19530
|
+
* `toJSInfoForTest` returns detailed TreeNode information for use in Devtools.
|
|
19669
19531
|
*/
|
|
19670
|
-
|
|
19532
|
+
toJSInfoForTest() {
|
|
19671
19533
|
if (!this.context || !this.tree) {
|
|
19672
19534
|
throw new YorkieError(
|
|
19673
19535
|
Code.ErrNotInitialized,
|
|
19674
19536
|
"Tree is not initialized yet"
|
|
19675
19537
|
);
|
|
19676
19538
|
}
|
|
19677
|
-
|
|
19539
|
+
return this.tree.toJSInfoForTest();
|
|
19540
|
+
}
|
|
19541
|
+
/**
|
|
19542
|
+
* `getRootTreeNode` returns TreeNode of this tree.
|
|
19543
|
+
*/
|
|
19544
|
+
getRootTreeNode() {
|
|
19545
|
+
if (!this.context || !this.tree) {
|
|
19678
19546
|
throw new YorkieError(
|
|
19679
|
-
Code.
|
|
19680
|
-
"
|
|
19547
|
+
Code.ErrNotInitialized,
|
|
19548
|
+
"Tree is not initialized yet"
|
|
19681
19549
|
);
|
|
19682
19550
|
}
|
|
19683
|
-
|
|
19684
|
-
const ticket = this.context.issueTimeTicket();
|
|
19685
|
-
const attrs = attributes ? stringifyObjectValues(attributes) : void 0;
|
|
19686
|
-
const [pairs, , diff] = this.tree.style([fromPos, toPos], attrs, ticket);
|
|
19687
|
-
this.context.acc(diff);
|
|
19688
|
-
for (const pair of pairs) {
|
|
19689
|
-
this.context.registerGCPair(pair);
|
|
19690
|
-
}
|
|
19691
|
-
this.context.push(
|
|
19692
|
-
TreeStyleOperation.create(
|
|
19693
|
-
this.tree.getCreatedAt(),
|
|
19694
|
-
fromPos,
|
|
19695
|
-
toPos,
|
|
19696
|
-
attrs ? new Map(Object.entries(attrs)) : /* @__PURE__ */ new Map(),
|
|
19697
|
-
ticket
|
|
19698
|
-
)
|
|
19699
|
-
);
|
|
19551
|
+
return this.tree.getRootTreeNode();
|
|
19700
19552
|
}
|
|
19701
19553
|
/**
|
|
19702
|
-
* `
|
|
19554
|
+
* `indexToPath` returns the path of the given index.
|
|
19703
19555
|
*/
|
|
19704
|
-
|
|
19556
|
+
indexToPath(index) {
|
|
19705
19557
|
if (!this.context || !this.tree) {
|
|
19706
19558
|
throw new YorkieError(
|
|
19707
19559
|
Code.ErrNotInitialized,
|
|
19708
19560
|
"Tree is not initialized yet"
|
|
19709
19561
|
);
|
|
19710
19562
|
}
|
|
19711
|
-
|
|
19563
|
+
return this.tree.indexToPath(index);
|
|
19564
|
+
}
|
|
19565
|
+
/**
|
|
19566
|
+
* `pathToIndex` returns the index of given path.
|
|
19567
|
+
*/
|
|
19568
|
+
pathToIndex(path) {
|
|
19569
|
+
if (!this.context || !this.tree) {
|
|
19712
19570
|
throw new YorkieError(
|
|
19713
|
-
Code.
|
|
19714
|
-
"
|
|
19715
|
-
);
|
|
19716
|
-
}
|
|
19717
|
-
|
|
19718
|
-
const toPos = this.tree.findPos(toIdx);
|
|
19719
|
-
const ticket = this.context.issueTimeTicket();
|
|
19720
|
-
const attrs = attributes ? stringifyObjectValues(attributes) : void 0;
|
|
19721
|
-
const [pairs, , diff] = this.tree.style([fromPos, toPos], attrs, ticket);
|
|
19722
|
-
this.context.acc(diff);
|
|
19723
|
-
for (const pair of pairs) {
|
|
19724
|
-
this.context.registerGCPair(pair);
|
|
19725
|
-
}
|
|
19726
|
-
this.context.push(
|
|
19727
|
-
TreeStyleOperation.create(
|
|
19728
|
-
this.tree.getCreatedAt(),
|
|
19729
|
-
fromPos,
|
|
19730
|
-
toPos,
|
|
19731
|
-
attrs ? new Map(Object.entries(attrs)) : /* @__PURE__ */ new Map(),
|
|
19732
|
-
ticket
|
|
19733
|
-
)
|
|
19734
|
-
);
|
|
19571
|
+
Code.ErrNotInitialized,
|
|
19572
|
+
"Tree is not initialized yet"
|
|
19573
|
+
);
|
|
19574
|
+
}
|
|
19575
|
+
return this.tree.pathToIndex(path);
|
|
19735
19576
|
}
|
|
19736
19577
|
/**
|
|
19737
|
-
* `
|
|
19578
|
+
* `pathRangeToPosRange` converts the path range into the position range.
|
|
19738
19579
|
*/
|
|
19739
|
-
|
|
19580
|
+
pathRangeToPosRange(range) {
|
|
19740
19581
|
if (!this.context || !this.tree) {
|
|
19741
19582
|
throw new YorkieError(
|
|
19742
19583
|
Code.ErrNotInitialized,
|
|
19743
19584
|
"Tree is not initialized yet"
|
|
19744
19585
|
);
|
|
19745
19586
|
}
|
|
19746
|
-
|
|
19587
|
+
const indexRange = [
|
|
19588
|
+
this.tree.pathToIndex(range[0]),
|
|
19589
|
+
this.tree.pathToIndex(range[1])
|
|
19590
|
+
];
|
|
19591
|
+
const posRange = this.tree.indexRangeToPosRange(indexRange);
|
|
19592
|
+
return [posRange[0].toStruct(), posRange[1].toStruct()];
|
|
19593
|
+
}
|
|
19594
|
+
/**
|
|
19595
|
+
* `indexRangeToPosRange` converts the index range into the position range.
|
|
19596
|
+
*/
|
|
19597
|
+
indexRangeToPosRange(range) {
|
|
19598
|
+
if (!this.context || !this.tree) {
|
|
19747
19599
|
throw new YorkieError(
|
|
19748
|
-
Code.
|
|
19749
|
-
"
|
|
19600
|
+
Code.ErrNotInitialized,
|
|
19601
|
+
"Tree is not initialized yet"
|
|
19750
19602
|
);
|
|
19751
19603
|
}
|
|
19752
|
-
|
|
19753
|
-
const toPos = this.tree.findPos(toIdx);
|
|
19754
|
-
const ticket = this.context.issueTimeTicket();
|
|
19755
|
-
const [pairs, , diff] = this.tree.removeStyle(
|
|
19756
|
-
[fromPos, toPos],
|
|
19757
|
-
attributesToRemove,
|
|
19758
|
-
ticket
|
|
19759
|
-
);
|
|
19760
|
-
this.context.acc(diff);
|
|
19761
|
-
for (const pair of pairs) {
|
|
19762
|
-
this.context.registerGCPair(pair);
|
|
19763
|
-
}
|
|
19764
|
-
this.context.push(
|
|
19765
|
-
TreeStyleOperation.createTreeRemoveStyleOperation(
|
|
19766
|
-
this.tree.getCreatedAt(),
|
|
19767
|
-
fromPos,
|
|
19768
|
-
toPos,
|
|
19769
|
-
attributesToRemove,
|
|
19770
|
-
ticket
|
|
19771
|
-
)
|
|
19772
|
-
);
|
|
19604
|
+
return this.tree.indexRangeToPosStructRange(range);
|
|
19773
19605
|
}
|
|
19774
|
-
|
|
19775
|
-
|
|
19776
|
-
|
|
19777
|
-
|
|
19778
|
-
|
|
19779
|
-
|
|
19780
|
-
|
|
19781
|
-
|
|
19782
|
-
}
|
|
19783
|
-
}
|
|
19784
|
-
}
|
|
19785
|
-
const ticket = this.context.getLastTimeTicket();
|
|
19786
|
-
let crdtNodes = new Array();
|
|
19787
|
-
if (((_a2 = contents[0]) == null ? void 0 : _a2.type) === DefaultTextType) {
|
|
19788
|
-
let compVal = "";
|
|
19789
|
-
for (const content of contents) {
|
|
19790
|
-
const { value } = content;
|
|
19791
|
-
compVal += value;
|
|
19792
|
-
}
|
|
19793
|
-
crdtNodes.push(
|
|
19794
|
-
CRDTTreeNode.create(
|
|
19795
|
-
CRDTTreeNodeID.of(this.context.issueTimeTicket(), 0),
|
|
19796
|
-
DefaultTextType,
|
|
19797
|
-
compVal
|
|
19798
|
-
)
|
|
19606
|
+
/**
|
|
19607
|
+
* `posRangeToIndexRange` converts the position range into the index range.
|
|
19608
|
+
*/
|
|
19609
|
+
posRangeToIndexRange(range) {
|
|
19610
|
+
if (!this.context || !this.tree) {
|
|
19611
|
+
throw new YorkieError(
|
|
19612
|
+
Code.ErrNotInitialized,
|
|
19613
|
+
"Tree is not initialized yet"
|
|
19799
19614
|
);
|
|
19800
|
-
} else {
|
|
19801
|
-
crdtNodes = contents.map((content) => content && createCRDTTreeNode(this.context, content)).filter((a) => a);
|
|
19802
|
-
}
|
|
19803
|
-
const [, pairs, diff] = this.tree.edit(
|
|
19804
|
-
[fromPos, toPos],
|
|
19805
|
-
crdtNodes.length ? crdtNodes.map((crdtNode) => crdtNode == null ? void 0 : crdtNode.deepcopy()) : void 0,
|
|
19806
|
-
splitLevel,
|
|
19807
|
-
ticket,
|
|
19808
|
-
() => this.context.issueTimeTicket()
|
|
19809
|
-
);
|
|
19810
|
-
this.context.acc(diff);
|
|
19811
|
-
for (const pair of pairs) {
|
|
19812
|
-
this.context.registerGCPair(pair);
|
|
19813
19615
|
}
|
|
19814
|
-
|
|
19815
|
-
|
|
19816
|
-
|
|
19817
|
-
|
|
19818
|
-
|
|
19819
|
-
crdtNodes.length ? crdtNodes : void 0,
|
|
19820
|
-
splitLevel,
|
|
19821
|
-
ticket
|
|
19822
|
-
)
|
|
19823
|
-
);
|
|
19824
|
-
return true;
|
|
19616
|
+
const posRange = [
|
|
19617
|
+
CRDTTreePos.fromStruct(range[0]),
|
|
19618
|
+
CRDTTreePos.fromStruct(range[1])
|
|
19619
|
+
];
|
|
19620
|
+
return this.tree.posRangeToIndexRange(posRange);
|
|
19825
19621
|
}
|
|
19826
19622
|
/**
|
|
19827
|
-
* `
|
|
19623
|
+
* `posRangeToPathRange` converts the position range into the path range.
|
|
19828
19624
|
*/
|
|
19829
|
-
|
|
19625
|
+
posRangeToPathRange(range) {
|
|
19830
19626
|
if (!this.context || !this.tree) {
|
|
19831
19627
|
throw new YorkieError(
|
|
19832
19628
|
Code.ErrNotInitialized,
|
|
19833
19629
|
"Tree is not initialized yet"
|
|
19834
19630
|
);
|
|
19835
19631
|
}
|
|
19836
|
-
|
|
19837
|
-
|
|
19838
|
-
|
|
19839
|
-
|
|
19632
|
+
const posRange = [
|
|
19633
|
+
CRDTTreePos.fromStruct(range[0]),
|
|
19634
|
+
CRDTTreePos.fromStruct(range[1])
|
|
19635
|
+
];
|
|
19636
|
+
return this.tree.posRangeToPathRange(posRange);
|
|
19637
|
+
}
|
|
19638
|
+
}
|
|
19639
|
+
function createJSON(context, target) {
|
|
19640
|
+
return createJSONObject(context, target);
|
|
19641
|
+
}
|
|
19642
|
+
function toWrappedElement(context, elem) {
|
|
19643
|
+
if (!elem) {
|
|
19644
|
+
return;
|
|
19645
|
+
} else if (elem instanceof Primitive) {
|
|
19646
|
+
return elem;
|
|
19647
|
+
} else if (elem instanceof CRDTObject) {
|
|
19648
|
+
return createJSONObject(context, elem);
|
|
19649
|
+
} else if (elem instanceof CRDTArray) {
|
|
19650
|
+
return createJSONArray(context, elem);
|
|
19651
|
+
} else if (elem instanceof CRDTText) {
|
|
19652
|
+
return new Text(context, elem);
|
|
19653
|
+
} else if (elem instanceof CRDTCounter) {
|
|
19654
|
+
const counter = new Counter(CounterType.Int, 0);
|
|
19655
|
+
counter.initialize(context, elem);
|
|
19656
|
+
return counter;
|
|
19657
|
+
} else if (elem instanceof CRDTTree) {
|
|
19658
|
+
const tree = new Tree();
|
|
19659
|
+
tree.initialize(context, elem);
|
|
19660
|
+
return tree;
|
|
19661
|
+
}
|
|
19662
|
+
throw new TypeError(`Unsupported type of element: ${typeof elem}`);
|
|
19663
|
+
}
|
|
19664
|
+
function toJSONElement(context, elem) {
|
|
19665
|
+
const wrappedElement = toWrappedElement(context, elem);
|
|
19666
|
+
if (wrappedElement instanceof Primitive) {
|
|
19667
|
+
return wrappedElement.getValue();
|
|
19668
|
+
}
|
|
19669
|
+
return wrappedElement;
|
|
19670
|
+
}
|
|
19671
|
+
function buildCRDTElement(context, value, createdAt) {
|
|
19672
|
+
let element;
|
|
19673
|
+
if (Primitive.isSupport(value)) {
|
|
19674
|
+
element = Primitive.of(value, createdAt);
|
|
19675
|
+
} else if (Array.isArray(value)) {
|
|
19676
|
+
element = CRDTArray.create(
|
|
19677
|
+
createdAt,
|
|
19678
|
+
ArrayProxy.buildArrayElements(context, value)
|
|
19679
|
+
);
|
|
19680
|
+
} else if (typeof value === "object") {
|
|
19681
|
+
if (value instanceof Text) {
|
|
19682
|
+
element = CRDTText.create(RGATreeSplit.create(), createdAt);
|
|
19683
|
+
value.initialize(context, element);
|
|
19684
|
+
} else if (value instanceof Counter) {
|
|
19685
|
+
element = CRDTCounter.create(
|
|
19686
|
+
value.getValueType(),
|
|
19687
|
+
value.getValue(),
|
|
19688
|
+
createdAt
|
|
19840
19689
|
);
|
|
19841
|
-
|
|
19842
|
-
if (
|
|
19843
|
-
|
|
19844
|
-
|
|
19845
|
-
|
|
19690
|
+
value.initialize(context, element);
|
|
19691
|
+
} else if (value instanceof Tree) {
|
|
19692
|
+
element = CRDTTree.create(value.buildRoot(context), createdAt);
|
|
19693
|
+
value.initialize(context, element);
|
|
19694
|
+
} else {
|
|
19695
|
+
element = CRDTObject.create(
|
|
19696
|
+
createdAt,
|
|
19697
|
+
ObjectProxy.buildObjectMembers(context, value)
|
|
19846
19698
|
);
|
|
19847
19699
|
}
|
|
19848
|
-
|
|
19849
|
-
|
|
19850
|
-
|
|
19851
|
-
|
|
19852
|
-
|
|
19853
|
-
|
|
19854
|
-
|
|
19855
|
-
|
|
19700
|
+
} else {
|
|
19701
|
+
throw new TypeError(`Unsupported type of value: ${typeof value}`);
|
|
19702
|
+
}
|
|
19703
|
+
return element;
|
|
19704
|
+
}
|
|
19705
|
+
class CRDTRoot {
|
|
19706
|
+
constructor(rootObject) {
|
|
19707
|
+
/**
|
|
19708
|
+
* `rootObject` is the root object of the document.
|
|
19709
|
+
*/
|
|
19710
|
+
__publicField(this, "rootObject");
|
|
19711
|
+
/**
|
|
19712
|
+
* `elementPairMapByCreatedAt` is a hash table that maps the creation time of
|
|
19713
|
+
* an element to the element itself and its parent.
|
|
19714
|
+
*/
|
|
19715
|
+
__publicField(this, "elementPairMapByCreatedAt");
|
|
19716
|
+
/**
|
|
19717
|
+
* `gcElementSetByCreatedAt` is a hash set that contains the creation
|
|
19718
|
+
* time of the removed element. It is used to find the removed element when
|
|
19719
|
+
* executing garbage collection.
|
|
19720
|
+
*/
|
|
19721
|
+
__publicField(this, "gcElementSetByCreatedAt");
|
|
19722
|
+
/**
|
|
19723
|
+
* `gcPairMap` is a hash table that maps the IDString of GCChild to the
|
|
19724
|
+
* element itself and its parent.
|
|
19725
|
+
*/
|
|
19726
|
+
__publicField(this, "gcPairMap");
|
|
19727
|
+
/**
|
|
19728
|
+
* `docSize` is a structure that represents the size of the document.
|
|
19729
|
+
*/
|
|
19730
|
+
__publicField(this, "docSize");
|
|
19731
|
+
this.rootObject = rootObject;
|
|
19732
|
+
this.elementPairMapByCreatedAt = /* @__PURE__ */ new Map();
|
|
19733
|
+
this.gcElementSetByCreatedAt = /* @__PURE__ */ new Set();
|
|
19734
|
+
this.gcPairMap = /* @__PURE__ */ new Map();
|
|
19735
|
+
this.docSize = { live: { data: 0, meta: 0 }, gc: { data: 0, meta: 0 } };
|
|
19736
|
+
this.registerElement(rootObject, void 0);
|
|
19737
|
+
rootObject.getDescendants((elem) => {
|
|
19738
|
+
if (elem.getRemovedAt()) {
|
|
19739
|
+
this.registerRemovedElement(elem);
|
|
19740
|
+
}
|
|
19741
|
+
if (elem instanceof CRDTText || elem instanceof CRDTTree) {
|
|
19742
|
+
for (const pair of elem.getGCPairs()) {
|
|
19743
|
+
this.registerGCPair(pair);
|
|
19744
|
+
}
|
|
19745
|
+
}
|
|
19746
|
+
return false;
|
|
19747
|
+
});
|
|
19748
|
+
}
|
|
19749
|
+
/**
|
|
19750
|
+
* `create` creates a new instance of Root.
|
|
19751
|
+
*/
|
|
19752
|
+
static create() {
|
|
19753
|
+
return new CRDTRoot(CRDTObject.create(InitialTimeTicket));
|
|
19754
|
+
}
|
|
19755
|
+
/**
|
|
19756
|
+
* `findByCreatedAt` returns the element of given creation time.
|
|
19757
|
+
*/
|
|
19758
|
+
findByCreatedAt(createdAt) {
|
|
19759
|
+
const pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
|
|
19760
|
+
if (!pair) {
|
|
19761
|
+
return;
|
|
19762
|
+
}
|
|
19763
|
+
return pair.element;
|
|
19856
19764
|
}
|
|
19857
19765
|
/**
|
|
19858
|
-
* `
|
|
19766
|
+
* `findElementPairByCreatedAt` returns the element and parent pair
|
|
19767
|
+
* of given creation time.
|
|
19859
19768
|
*/
|
|
19860
|
-
|
|
19861
|
-
|
|
19862
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
|
|
19866
|
-
|
|
19867
|
-
|
|
19868
|
-
|
|
19869
|
-
|
|
19870
|
-
"path length should be equal"
|
|
19871
|
-
);
|
|
19769
|
+
findElementPairByCreatedAt(createdAt) {
|
|
19770
|
+
return this.elementPairMapByCreatedAt.get(createdAt.toIDString());
|
|
19771
|
+
}
|
|
19772
|
+
/**
|
|
19773
|
+
* `createSubPaths` creates an array of the sub paths for the given element.
|
|
19774
|
+
*/
|
|
19775
|
+
createSubPaths(createdAt) {
|
|
19776
|
+
let pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
|
|
19777
|
+
if (!pair) {
|
|
19778
|
+
return [];
|
|
19872
19779
|
}
|
|
19873
|
-
|
|
19874
|
-
|
|
19875
|
-
|
|
19876
|
-
|
|
19780
|
+
const subPaths = [];
|
|
19781
|
+
while (pair.parent) {
|
|
19782
|
+
const createdAt2 = pair.element.getCreatedAt();
|
|
19783
|
+
const subPath = pair.parent.subPathOf(createdAt2);
|
|
19784
|
+
if (subPath === void 0) {
|
|
19785
|
+
throw new YorkieError(
|
|
19786
|
+
Code.ErrInvalidArgument,
|
|
19787
|
+
`cant find the given element: ${createdAt2.toIDString()}`
|
|
19788
|
+
);
|
|
19789
|
+
}
|
|
19790
|
+
subPaths.unshift(subPath);
|
|
19791
|
+
pair = this.elementPairMapByCreatedAt.get(
|
|
19792
|
+
pair.parent.getCreatedAt().toIDString()
|
|
19877
19793
|
);
|
|
19878
19794
|
}
|
|
19879
|
-
|
|
19880
|
-
|
|
19881
|
-
return this.editInternal(fromPos, toPos, contents, splitLevel);
|
|
19795
|
+
subPaths.unshift("$");
|
|
19796
|
+
return subPaths;
|
|
19882
19797
|
}
|
|
19883
19798
|
/**
|
|
19884
|
-
* `
|
|
19799
|
+
* `createPath` creates path of the given element.
|
|
19885
19800
|
*/
|
|
19886
|
-
|
|
19887
|
-
|
|
19888
|
-
|
|
19889
|
-
|
|
19890
|
-
|
|
19891
|
-
|
|
19801
|
+
createPath(createdAt) {
|
|
19802
|
+
return this.createSubPaths(createdAt).join(".");
|
|
19803
|
+
}
|
|
19804
|
+
/**
|
|
19805
|
+
* `registerElement` registers the given element and its descendants to hash table.
|
|
19806
|
+
*/
|
|
19807
|
+
registerElement(element, parent) {
|
|
19808
|
+
this.elementPairMapByCreatedAt.set(element.getCreatedAt().toIDString(), {
|
|
19809
|
+
parent,
|
|
19810
|
+
element
|
|
19811
|
+
});
|
|
19812
|
+
addDataSizes(this.docSize.live, element.getDataSize());
|
|
19813
|
+
if (element instanceof CRDTContainer) {
|
|
19814
|
+
element.getDescendants((elem, par) => {
|
|
19815
|
+
this.elementPairMapByCreatedAt.set(elem.getCreatedAt().toIDString(), {
|
|
19816
|
+
parent: par,
|
|
19817
|
+
element: elem
|
|
19818
|
+
});
|
|
19819
|
+
addDataSizes(this.docSize.live, elem.getDataSize());
|
|
19820
|
+
return false;
|
|
19821
|
+
});
|
|
19892
19822
|
}
|
|
19893
|
-
|
|
19894
|
-
|
|
19895
|
-
|
|
19896
|
-
|
|
19897
|
-
|
|
19823
|
+
}
|
|
19824
|
+
/**
|
|
19825
|
+
* `deregisterElement` deregister the given element and its descendants from hash table.
|
|
19826
|
+
*/
|
|
19827
|
+
deregisterElement(element) {
|
|
19828
|
+
let count = 0;
|
|
19829
|
+
const deregisterElementInternal = (elem) => {
|
|
19830
|
+
const createdAt = elem.getCreatedAt().toIDString();
|
|
19831
|
+
subDataSize(this.docSize.gc, elem.getDataSize());
|
|
19832
|
+
this.elementPairMapByCreatedAt.delete(createdAt);
|
|
19833
|
+
this.gcElementSetByCreatedAt.delete(createdAt);
|
|
19834
|
+
count++;
|
|
19835
|
+
};
|
|
19836
|
+
deregisterElementInternal(element);
|
|
19837
|
+
if (element instanceof CRDTContainer) {
|
|
19838
|
+
element.getDescendants((e) => {
|
|
19839
|
+
deregisterElementInternal(e);
|
|
19840
|
+
return false;
|
|
19841
|
+
});
|
|
19898
19842
|
}
|
|
19899
|
-
|
|
19900
|
-
const toPos = this.tree.findPos(toIdx);
|
|
19901
|
-
return this.editInternal(
|
|
19902
|
-
fromPos,
|
|
19903
|
-
toPos,
|
|
19904
|
-
content ? [content] : [],
|
|
19905
|
-
splitLevel
|
|
19906
|
-
);
|
|
19843
|
+
return count;
|
|
19907
19844
|
}
|
|
19908
19845
|
/**
|
|
19909
|
-
* `
|
|
19846
|
+
* `registerRemovedElement` registers the given element to the hash set.
|
|
19910
19847
|
*/
|
|
19911
|
-
|
|
19912
|
-
|
|
19913
|
-
|
|
19914
|
-
|
|
19915
|
-
|
|
19916
|
-
|
|
19848
|
+
registerRemovedElement(element) {
|
|
19849
|
+
addDataSizes(this.docSize.gc, element.getDataSize());
|
|
19850
|
+
subDataSize(this.docSize.live, element.getDataSize());
|
|
19851
|
+
this.docSize.live.meta += TimeTicketSize;
|
|
19852
|
+
this.gcElementSetByCreatedAt.add(element.getCreatedAt().toIDString());
|
|
19853
|
+
}
|
|
19854
|
+
/**
|
|
19855
|
+
* `registerGCPair` registers the given pair to hash table.
|
|
19856
|
+
*/
|
|
19857
|
+
registerGCPair(pair) {
|
|
19858
|
+
const prev = this.gcPairMap.get(pair.child.toIDString());
|
|
19859
|
+
if (prev) {
|
|
19860
|
+
this.gcPairMap.delete(pair.child.toIDString());
|
|
19861
|
+
return;
|
|
19917
19862
|
}
|
|
19918
|
-
|
|
19919
|
-
|
|
19920
|
-
|
|
19921
|
-
|
|
19922
|
-
|
|
19863
|
+
this.gcPairMap.set(pair.child.toIDString(), pair);
|
|
19864
|
+
const size = this.gcPairMap.get(pair.child.toIDString()).child.getDataSize();
|
|
19865
|
+
addDataSizes(this.docSize.gc, size);
|
|
19866
|
+
subDataSize(this.docSize.live, size);
|
|
19867
|
+
if (!(pair.child instanceof RHTNode)) {
|
|
19868
|
+
this.docSize.live.meta += TimeTicketSize;
|
|
19923
19869
|
}
|
|
19924
|
-
const fromPos = this.tree.findPos(fromIdx);
|
|
19925
|
-
const toPos = this.tree.findPos(toIdx);
|
|
19926
|
-
return this.editInternal(fromPos, toPos, contents, splitLevel);
|
|
19927
19870
|
}
|
|
19928
19871
|
/**
|
|
19929
|
-
* `
|
|
19872
|
+
* `getElementMapSize` returns the size of element map.
|
|
19930
19873
|
*/
|
|
19931
|
-
|
|
19932
|
-
|
|
19933
|
-
throw new YorkieError(
|
|
19934
|
-
Code.ErrNotInitialized,
|
|
19935
|
-
"Tree is not initialized yet"
|
|
19936
|
-
);
|
|
19937
|
-
}
|
|
19938
|
-
return this.tree.toXML();
|
|
19874
|
+
getElementMapSize() {
|
|
19875
|
+
return this.elementPairMapByCreatedAt.size;
|
|
19939
19876
|
}
|
|
19940
19877
|
/**
|
|
19941
|
-
* `
|
|
19878
|
+
* `getGarbageElementSetSize()` returns the size of removed element set.
|
|
19942
19879
|
*/
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
)
|
|
19880
|
+
getGarbageElementSetSize() {
|
|
19881
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19882
|
+
for (const createdAt of this.gcElementSetByCreatedAt) {
|
|
19883
|
+
seen.add(createdAt);
|
|
19884
|
+
const pair = this.elementPairMapByCreatedAt.get(createdAt);
|
|
19885
|
+
if (pair.element instanceof CRDTContainer) {
|
|
19886
|
+
pair.element.getDescendants((el) => {
|
|
19887
|
+
seen.add(el.getCreatedAt().toIDString());
|
|
19888
|
+
return false;
|
|
19889
|
+
});
|
|
19890
|
+
}
|
|
19949
19891
|
}
|
|
19950
|
-
return
|
|
19892
|
+
return seen.size;
|
|
19951
19893
|
}
|
|
19952
19894
|
/**
|
|
19953
|
-
* `
|
|
19954
|
-
* @internal
|
|
19895
|
+
* `getObject` returns root object.
|
|
19955
19896
|
*/
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
throw new YorkieError(
|
|
19959
|
-
Code.ErrNotInitialized,
|
|
19960
|
-
"Tree is not initialized yet"
|
|
19961
|
-
);
|
|
19962
|
-
}
|
|
19963
|
-
return this.tree.toJSForTest();
|
|
19897
|
+
getObject() {
|
|
19898
|
+
return this.rootObject;
|
|
19964
19899
|
}
|
|
19965
19900
|
/**
|
|
19966
|
-
* `
|
|
19967
|
-
*
|
|
19968
|
-
* @internal
|
|
19901
|
+
* `getGarbageLen` returns length of nodes which can be garbage collected.
|
|
19969
19902
|
*/
|
|
19970
|
-
|
|
19971
|
-
|
|
19972
|
-
throw new YorkieError(
|
|
19973
|
-
Code.ErrNotInitialized,
|
|
19974
|
-
"Tree is not initialized yet"
|
|
19975
|
-
);
|
|
19976
|
-
}
|
|
19977
|
-
return this.tree.toJSInfoForTest();
|
|
19903
|
+
getGarbageLen() {
|
|
19904
|
+
return this.getGarbageElementSetSize() + this.gcPairMap.size;
|
|
19978
19905
|
}
|
|
19979
19906
|
/**
|
|
19980
|
-
* `
|
|
19907
|
+
* `getDocSize` returns the size of the document.
|
|
19981
19908
|
*/
|
|
19982
|
-
|
|
19983
|
-
|
|
19984
|
-
throw new YorkieError(
|
|
19985
|
-
Code.ErrNotInitialized,
|
|
19986
|
-
"Tree is not initialized yet"
|
|
19987
|
-
);
|
|
19988
|
-
}
|
|
19989
|
-
return this.tree.getRootTreeNode();
|
|
19909
|
+
getDocSize() {
|
|
19910
|
+
return this.docSize;
|
|
19990
19911
|
}
|
|
19991
19912
|
/**
|
|
19992
|
-
* `
|
|
19913
|
+
* `deepcopy` copies itself deeply.
|
|
19993
19914
|
*/
|
|
19994
|
-
|
|
19995
|
-
|
|
19996
|
-
throw new YorkieError(
|
|
19997
|
-
Code.ErrNotInitialized,
|
|
19998
|
-
"Tree is not initialized yet"
|
|
19999
|
-
);
|
|
20000
|
-
}
|
|
20001
|
-
return this.tree.indexToPath(index);
|
|
19915
|
+
deepcopy() {
|
|
19916
|
+
return new CRDTRoot(this.rootObject.deepcopy());
|
|
20002
19917
|
}
|
|
20003
19918
|
/**
|
|
20004
|
-
* `
|
|
19919
|
+
* `garbageCollect` purges elements that were removed before the given time.
|
|
20005
19920
|
*/
|
|
20006
|
-
|
|
20007
|
-
|
|
20008
|
-
|
|
20009
|
-
|
|
20010
|
-
|
|
20011
|
-
)
|
|
19921
|
+
garbageCollect(minSyncedVersionVector) {
|
|
19922
|
+
let count = 0;
|
|
19923
|
+
for (const createdAt of this.gcElementSetByCreatedAt) {
|
|
19924
|
+
const pair = this.elementPairMapByCreatedAt.get(createdAt);
|
|
19925
|
+
const removedAt = pair.element.getRemovedAt();
|
|
19926
|
+
if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
|
|
19927
|
+
pair.parent.purge(pair.element);
|
|
19928
|
+
count += this.deregisterElement(pair.element);
|
|
19929
|
+
}
|
|
19930
|
+
}
|
|
19931
|
+
for (const [, pair] of this.gcPairMap) {
|
|
19932
|
+
const removedAt = pair.child.getRemovedAt();
|
|
19933
|
+
if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
|
|
19934
|
+
pair.parent.purge(pair.child);
|
|
19935
|
+
subDataSize(this.docSize.gc, pair.child.getDataSize());
|
|
19936
|
+
this.gcPairMap.delete(pair.child.toIDString());
|
|
19937
|
+
count += 1;
|
|
19938
|
+
}
|
|
20012
19939
|
}
|
|
20013
|
-
return
|
|
19940
|
+
return count;
|
|
20014
19941
|
}
|
|
20015
19942
|
/**
|
|
20016
|
-
* `
|
|
19943
|
+
* `toJSON` returns the JSON encoding of this root object.
|
|
20017
19944
|
*/
|
|
20018
|
-
|
|
20019
|
-
|
|
20020
|
-
throw new YorkieError(
|
|
20021
|
-
Code.ErrNotInitialized,
|
|
20022
|
-
"Tree is not initialized yet"
|
|
20023
|
-
);
|
|
20024
|
-
}
|
|
20025
|
-
const indexRange = [
|
|
20026
|
-
this.tree.pathToIndex(range[0]),
|
|
20027
|
-
this.tree.pathToIndex(range[1])
|
|
20028
|
-
];
|
|
20029
|
-
const posRange = this.tree.indexRangeToPosRange(indexRange);
|
|
20030
|
-
return [posRange[0].toStruct(), posRange[1].toStruct()];
|
|
19945
|
+
toJSON() {
|
|
19946
|
+
return this.rootObject.toJSON();
|
|
20031
19947
|
}
|
|
20032
19948
|
/**
|
|
20033
|
-
* `
|
|
19949
|
+
* `toSortedJSON` returns the sorted JSON encoding of this root object.
|
|
20034
19950
|
*/
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
throw new YorkieError(
|
|
20038
|
-
Code.ErrNotInitialized,
|
|
20039
|
-
"Tree is not initialized yet"
|
|
20040
|
-
);
|
|
20041
|
-
}
|
|
20042
|
-
return this.tree.indexRangeToPosStructRange(range);
|
|
19951
|
+
toSortedJSON() {
|
|
19952
|
+
return this.rootObject.toSortedJSON();
|
|
20043
19953
|
}
|
|
20044
19954
|
/**
|
|
20045
|
-
* `
|
|
19955
|
+
* `getStats` returns the current statistics of the root object.
|
|
19956
|
+
* This includes counts of various types of elements and structural information.
|
|
20046
19957
|
*/
|
|
20047
|
-
|
|
20048
|
-
|
|
20049
|
-
|
|
20050
|
-
|
|
20051
|
-
|
|
20052
|
-
|
|
20053
|
-
}
|
|
20054
|
-
const posRange = [
|
|
20055
|
-
CRDTTreePos.fromStruct(range[0]),
|
|
20056
|
-
CRDTTreePos.fromStruct(range[1])
|
|
20057
|
-
];
|
|
20058
|
-
return this.tree.posRangeToIndexRange(posRange);
|
|
19958
|
+
getStats() {
|
|
19959
|
+
return {
|
|
19960
|
+
elements: this.getElementMapSize(),
|
|
19961
|
+
gcPairs: this.gcPairMap.size,
|
|
19962
|
+
gcElements: this.getGarbageElementSetSize()
|
|
19963
|
+
};
|
|
20059
19964
|
}
|
|
20060
19965
|
/**
|
|
20061
|
-
* `
|
|
19966
|
+
* `acc` accumulates the given DataSize to Live.
|
|
20062
19967
|
*/
|
|
20063
|
-
|
|
20064
|
-
|
|
20065
|
-
throw new YorkieError(
|
|
20066
|
-
Code.ErrNotInitialized,
|
|
20067
|
-
"Tree is not initialized yet"
|
|
20068
|
-
);
|
|
20069
|
-
}
|
|
20070
|
-
const posRange = [
|
|
20071
|
-
CRDTTreePos.fromStruct(range[0]),
|
|
20072
|
-
CRDTTreePos.fromStruct(range[1])
|
|
20073
|
-
];
|
|
20074
|
-
return this.tree.posRangeToPathRange(posRange);
|
|
20075
|
-
}
|
|
20076
|
-
}
|
|
20077
|
-
function createJSON(context, target) {
|
|
20078
|
-
return createJSONObject(context, target);
|
|
20079
|
-
}
|
|
20080
|
-
function toWrappedElement(context, elem) {
|
|
20081
|
-
if (!elem) {
|
|
20082
|
-
return;
|
|
20083
|
-
} else if (elem instanceof Primitive) {
|
|
20084
|
-
return elem;
|
|
20085
|
-
} else if (elem instanceof CRDTObject) {
|
|
20086
|
-
return createJSONObject(context, elem);
|
|
20087
|
-
} else if (elem instanceof CRDTArray) {
|
|
20088
|
-
return createJSONArray(context, elem);
|
|
20089
|
-
} else if (elem instanceof CRDTText) {
|
|
20090
|
-
return new Text(context, elem);
|
|
20091
|
-
} else if (elem instanceof CRDTCounter) {
|
|
20092
|
-
const counter = new Counter(CounterType.Int, 0);
|
|
20093
|
-
counter.initialize(context, elem);
|
|
20094
|
-
return counter;
|
|
20095
|
-
} else if (elem instanceof CRDTTree) {
|
|
20096
|
-
const tree = new Tree();
|
|
20097
|
-
tree.initialize(context, elem);
|
|
20098
|
-
return tree;
|
|
20099
|
-
}
|
|
20100
|
-
throw new TypeError(`Unsupported type of element: ${typeof elem}`);
|
|
20101
|
-
}
|
|
20102
|
-
function toJSONElement(context, elem) {
|
|
20103
|
-
const wrappedElement = toWrappedElement(context, elem);
|
|
20104
|
-
if (wrappedElement instanceof Primitive) {
|
|
20105
|
-
return wrappedElement.getValue();
|
|
20106
|
-
}
|
|
20107
|
-
return wrappedElement;
|
|
20108
|
-
}
|
|
20109
|
-
function buildCRDTElement(context, value, createdAt) {
|
|
20110
|
-
let element;
|
|
20111
|
-
if (Primitive.isSupport(value)) {
|
|
20112
|
-
element = Primitive.of(value, createdAt);
|
|
20113
|
-
} else if (Array.isArray(value)) {
|
|
20114
|
-
element = CRDTArray.create(
|
|
20115
|
-
createdAt,
|
|
20116
|
-
ArrayProxy.buildArrayElements(context, value)
|
|
20117
|
-
);
|
|
20118
|
-
} else if (typeof value === "object") {
|
|
20119
|
-
if (value instanceof Text) {
|
|
20120
|
-
element = CRDTText.create(RGATreeSplit.create(), createdAt);
|
|
20121
|
-
value.initialize(context, element);
|
|
20122
|
-
} else if (value instanceof Counter) {
|
|
20123
|
-
element = CRDTCounter.create(
|
|
20124
|
-
value.getValueType(),
|
|
20125
|
-
value.getValue(),
|
|
20126
|
-
createdAt
|
|
20127
|
-
);
|
|
20128
|
-
value.initialize(context, element);
|
|
20129
|
-
} else if (value instanceof Tree) {
|
|
20130
|
-
element = CRDTTree.create(value.buildRoot(context), createdAt);
|
|
20131
|
-
value.initialize(context, element);
|
|
20132
|
-
} else {
|
|
20133
|
-
element = CRDTObject.create(
|
|
20134
|
-
createdAt,
|
|
20135
|
-
ObjectProxy.buildObjectMembers(context, value)
|
|
20136
|
-
);
|
|
20137
|
-
}
|
|
20138
|
-
} else {
|
|
20139
|
-
throw new TypeError(`Unsupported type of value: ${typeof value}`);
|
|
19968
|
+
acc(diff) {
|
|
19969
|
+
addDataSizes(this.docSize.live, diff);
|
|
20140
19970
|
}
|
|
20141
|
-
return element;
|
|
20142
19971
|
}
|
|
20143
19972
|
class Presence {
|
|
20144
19973
|
constructor(changeContext, presence) {
|
|
@@ -20168,7 +19997,6 @@ class Presence {
|
|
|
20168
19997
|
}
|
|
20169
19998
|
/**
|
|
20170
19999
|
* `clear` clears the presence.
|
|
20171
|
-
* @internal
|
|
20172
20000
|
*/
|
|
20173
20001
|
clear() {
|
|
20174
20002
|
this.presence = {};
|
|
@@ -20270,6 +20098,156 @@ class History {
|
|
|
20270
20098
|
replace(this.redoStack);
|
|
20271
20099
|
}
|
|
20272
20100
|
}
|
|
20101
|
+
function validateYorkieRuleset(data, ruleset) {
|
|
20102
|
+
const errors = [];
|
|
20103
|
+
for (const rule of ruleset) {
|
|
20104
|
+
const value = getValueByPath(data, rule.path);
|
|
20105
|
+
const result = validateValue(value, rule);
|
|
20106
|
+
if (!result.valid) {
|
|
20107
|
+
for (const error of result.errors || []) {
|
|
20108
|
+
errors.push(error);
|
|
20109
|
+
}
|
|
20110
|
+
}
|
|
20111
|
+
}
|
|
20112
|
+
return {
|
|
20113
|
+
valid: errors.length === 0,
|
|
20114
|
+
errors
|
|
20115
|
+
};
|
|
20116
|
+
}
|
|
20117
|
+
function getValueByPath(obj, path) {
|
|
20118
|
+
if (!path.startsWith("$")) {
|
|
20119
|
+
throw new Error(`Path must start with $, got ${path}`);
|
|
20120
|
+
}
|
|
20121
|
+
const keys = path.split(".");
|
|
20122
|
+
let current = obj;
|
|
20123
|
+
for (let i = 1; i < keys.length; i++) {
|
|
20124
|
+
const key = keys[i];
|
|
20125
|
+
if (!(current instanceof CRDTObject)) {
|
|
20126
|
+
return void 0;
|
|
20127
|
+
}
|
|
20128
|
+
current = current.get(key);
|
|
20129
|
+
}
|
|
20130
|
+
return current;
|
|
20131
|
+
}
|
|
20132
|
+
function validateValue(value, rule) {
|
|
20133
|
+
switch (rule.type) {
|
|
20134
|
+
case "string":
|
|
20135
|
+
case "boolean":
|
|
20136
|
+
case "integer":
|
|
20137
|
+
case "double":
|
|
20138
|
+
case "long":
|
|
20139
|
+
case "date":
|
|
20140
|
+
case "bytes":
|
|
20141
|
+
case "null":
|
|
20142
|
+
return validatePrimitiveValue(value, rule);
|
|
20143
|
+
case "object":
|
|
20144
|
+
if (!(value instanceof CRDTObject)) {
|
|
20145
|
+
return {
|
|
20146
|
+
valid: false,
|
|
20147
|
+
errors: [
|
|
20148
|
+
{
|
|
20149
|
+
path: rule.path,
|
|
20150
|
+
message: `expected object at path ${rule.path}`
|
|
20151
|
+
}
|
|
20152
|
+
]
|
|
20153
|
+
};
|
|
20154
|
+
}
|
|
20155
|
+
break;
|
|
20156
|
+
case "array":
|
|
20157
|
+
if (!(value instanceof CRDTArray)) {
|
|
20158
|
+
return {
|
|
20159
|
+
valid: false,
|
|
20160
|
+
errors: [
|
|
20161
|
+
{
|
|
20162
|
+
path: rule.path,
|
|
20163
|
+
message: `expected array at path ${rule.path}`
|
|
20164
|
+
}
|
|
20165
|
+
]
|
|
20166
|
+
};
|
|
20167
|
+
}
|
|
20168
|
+
break;
|
|
20169
|
+
case "yorkie.Text":
|
|
20170
|
+
if (!(value instanceof CRDTText)) {
|
|
20171
|
+
return {
|
|
20172
|
+
valid: false,
|
|
20173
|
+
errors: [
|
|
20174
|
+
{
|
|
20175
|
+
path: rule.path,
|
|
20176
|
+
message: `expected yorkie.Text at path ${rule.path}`
|
|
20177
|
+
}
|
|
20178
|
+
]
|
|
20179
|
+
};
|
|
20180
|
+
}
|
|
20181
|
+
break;
|
|
20182
|
+
case "yorkie.Tree":
|
|
20183
|
+
if (!(value instanceof CRDTTree)) {
|
|
20184
|
+
return {
|
|
20185
|
+
valid: false,
|
|
20186
|
+
errors: [
|
|
20187
|
+
{
|
|
20188
|
+
path: rule.path,
|
|
20189
|
+
message: `expected yorkie.Tree at path ${rule.path}`
|
|
20190
|
+
}
|
|
20191
|
+
]
|
|
20192
|
+
};
|
|
20193
|
+
}
|
|
20194
|
+
break;
|
|
20195
|
+
case "yorkie.Counter":
|
|
20196
|
+
if (!(value instanceof CRDTCounter)) {
|
|
20197
|
+
return {
|
|
20198
|
+
valid: false,
|
|
20199
|
+
errors: [
|
|
20200
|
+
{
|
|
20201
|
+
path: rule.path,
|
|
20202
|
+
message: `expected yorkie.Counter at path ${rule.path}`
|
|
20203
|
+
}
|
|
20204
|
+
]
|
|
20205
|
+
};
|
|
20206
|
+
}
|
|
20207
|
+
break;
|
|
20208
|
+
default:
|
|
20209
|
+
throw new Error(`Unknown rule type: ${rule.type}`);
|
|
20210
|
+
}
|
|
20211
|
+
return {
|
|
20212
|
+
valid: true
|
|
20213
|
+
};
|
|
20214
|
+
}
|
|
20215
|
+
function getPrimitiveType(type) {
|
|
20216
|
+
switch (type) {
|
|
20217
|
+
case "null":
|
|
20218
|
+
return PrimitiveType.Null;
|
|
20219
|
+
case "boolean":
|
|
20220
|
+
return PrimitiveType.Boolean;
|
|
20221
|
+
case "integer":
|
|
20222
|
+
return PrimitiveType.Integer;
|
|
20223
|
+
case "long":
|
|
20224
|
+
return PrimitiveType.Long;
|
|
20225
|
+
case "double":
|
|
20226
|
+
return PrimitiveType.Double;
|
|
20227
|
+
case "string":
|
|
20228
|
+
return PrimitiveType.String;
|
|
20229
|
+
case "bytes":
|
|
20230
|
+
return PrimitiveType.Bytes;
|
|
20231
|
+
case "date":
|
|
20232
|
+
return PrimitiveType.Date;
|
|
20233
|
+
default:
|
|
20234
|
+
throw new Error(`Unknown primitive type: ${type}`);
|
|
20235
|
+
}
|
|
20236
|
+
}
|
|
20237
|
+
function validatePrimitiveValue(value, rule) {
|
|
20238
|
+
if (value instanceof Primitive && value.getType() === getPrimitiveType(rule.type)) {
|
|
20239
|
+
return { valid: true };
|
|
20240
|
+
}
|
|
20241
|
+
return {
|
|
20242
|
+
valid: false,
|
|
20243
|
+
errors: [
|
|
20244
|
+
{
|
|
20245
|
+
path: rule.path,
|
|
20246
|
+
message: `expected ${rule.type} at path ${rule.path}`
|
|
20247
|
+
}
|
|
20248
|
+
]
|
|
20249
|
+
};
|
|
20250
|
+
}
|
|
20273
20251
|
const EventSourceDevPanel = "yorkie-devtools-panel";
|
|
20274
20252
|
const EventSourceSDK = "yorkie-devtools-sdk";
|
|
20275
20253
|
function isDocEventForReplay(event) {
|
|
@@ -20405,57 +20383,44 @@ class Document {
|
|
|
20405
20383
|
__publicField(this, "key");
|
|
20406
20384
|
__publicField(this, "status");
|
|
20407
20385
|
__publicField(this, "opts");
|
|
20386
|
+
__publicField(this, "maxSizeLimit");
|
|
20387
|
+
__publicField(this, "schemaRules");
|
|
20408
20388
|
__publicField(this, "changeID");
|
|
20409
20389
|
__publicField(this, "checkpoint");
|
|
20410
20390
|
__publicField(this, "localChanges");
|
|
20411
|
-
__publicField(this, "maxSizeLimit");
|
|
20412
|
-
__publicField(this, "schemaRules");
|
|
20413
20391
|
__publicField(this, "root");
|
|
20392
|
+
__publicField(this, "presences");
|
|
20414
20393
|
__publicField(this, "clone");
|
|
20394
|
+
__publicField(this, "internalHistory");
|
|
20395
|
+
__publicField(this, "isUpdating");
|
|
20396
|
+
__publicField(this, "onlineClients");
|
|
20415
20397
|
__publicField(this, "eventStream");
|
|
20416
20398
|
__publicField(this, "eventStreamObserver");
|
|
20417
|
-
/**
|
|
20418
|
-
* `onlineClients` is a set of client IDs that are currently online.
|
|
20419
|
-
*/
|
|
20420
|
-
__publicField(this, "onlineClients");
|
|
20421
|
-
/**
|
|
20422
|
-
* `presences` is a map of client IDs to their presence information.
|
|
20423
|
-
*/
|
|
20424
|
-
__publicField(this, "presences");
|
|
20425
20399
|
/**
|
|
20426
20400
|
* `history` is exposed to the user to manage undo/redo operations.
|
|
20427
20401
|
*/
|
|
20428
20402
|
__publicField(this, "history");
|
|
20429
|
-
/**
|
|
20430
|
-
* `internalHistory` is used to manage undo/redo operations internally.
|
|
20431
|
-
*/
|
|
20432
|
-
__publicField(this, "internalHistory");
|
|
20433
|
-
/**
|
|
20434
|
-
* `isUpdating` is whether the document is updating by updater or not. It is
|
|
20435
|
-
* used to prevent the updater from calling undo/redo.
|
|
20436
|
-
*/
|
|
20437
|
-
__publicField(this, "isUpdating");
|
|
20438
|
-
this.opts = opts || {};
|
|
20439
20403
|
this.key = key;
|
|
20440
20404
|
this.status = "detached";
|
|
20441
|
-
this.
|
|
20405
|
+
this.opts = opts || {};
|
|
20406
|
+
this.maxSizeLimit = 0;
|
|
20407
|
+
this.schemaRules = [];
|
|
20442
20408
|
this.changeID = InitialChangeID;
|
|
20443
20409
|
this.checkpoint = InitialCheckpoint;
|
|
20444
20410
|
this.localChanges = [];
|
|
20445
|
-
this.
|
|
20446
|
-
this.schemaRules = [];
|
|
20447
|
-
this.eventStream = createObservable((observer) => {
|
|
20448
|
-
this.eventStreamObserver = observer;
|
|
20449
|
-
});
|
|
20450
|
-
this.onlineClients = /* @__PURE__ */ new Set();
|
|
20411
|
+
this.root = CRDTRoot.create();
|
|
20451
20412
|
this.presences = /* @__PURE__ */ new Map();
|
|
20452
|
-
this.
|
|
20413
|
+
this.onlineClients = /* @__PURE__ */ new Set();
|
|
20453
20414
|
this.internalHistory = new History();
|
|
20415
|
+
this.isUpdating = false;
|
|
20416
|
+
this.eventStream = createObservable(
|
|
20417
|
+
(observer) => this.eventStreamObserver = observer
|
|
20418
|
+
);
|
|
20454
20419
|
this.history = {
|
|
20455
|
-
canUndo: this.
|
|
20456
|
-
canRedo: this.
|
|
20457
|
-
undo: this.
|
|
20458
|
-
redo: this.
|
|
20420
|
+
canUndo: () => this.internalHistory.hasUndo() && !this.isUpdating,
|
|
20421
|
+
canRedo: () => this.internalHistory.hasRedo() && !this.isUpdating,
|
|
20422
|
+
undo: () => this.executeUndoRedo(true),
|
|
20423
|
+
redo: () => this.executeUndoRedo(false)
|
|
20459
20424
|
};
|
|
20460
20425
|
setupDevtools(this);
|
|
20461
20426
|
}
|
|
@@ -20469,7 +20434,7 @@ class Document {
|
|
|
20469
20434
|
}
|
|
20470
20435
|
this.ensureClone();
|
|
20471
20436
|
const actorID = this.changeID.getActorID();
|
|
20472
|
-
const
|
|
20437
|
+
const ctx = ChangeContext.create(
|
|
20473
20438
|
this.changeID,
|
|
20474
20439
|
this.clone.root,
|
|
20475
20440
|
this.clone.presences.get(actorID) || {},
|
|
@@ -20477,29 +20442,23 @@ class Document {
|
|
|
20477
20442
|
);
|
|
20478
20443
|
try {
|
|
20479
20444
|
const proxy = createJSON(
|
|
20480
|
-
|
|
20445
|
+
ctx,
|
|
20481
20446
|
this.clone.root.getObject()
|
|
20482
20447
|
);
|
|
20483
20448
|
if (!this.presences.has(actorID)) {
|
|
20484
20449
|
this.clone.presences.set(actorID, {});
|
|
20485
20450
|
}
|
|
20486
20451
|
this.isUpdating = true;
|
|
20487
|
-
updater(
|
|
20488
|
-
proxy,
|
|
20489
|
-
new Presence(context, this.clone.presences.get(actorID))
|
|
20490
|
-
);
|
|
20452
|
+
updater(proxy, new Presence(ctx, this.clone.presences.get(actorID)));
|
|
20491
20453
|
} catch (err) {
|
|
20492
20454
|
this.clone = void 0;
|
|
20493
20455
|
throw err;
|
|
20494
20456
|
} finally {
|
|
20495
20457
|
this.isUpdating = false;
|
|
20496
20458
|
}
|
|
20497
|
-
const
|
|
20498
|
-
if (!
|
|
20499
|
-
const result = validateYorkieRuleset(
|
|
20500
|
-
(_a2 = this.clone) == null ? void 0 : _a2.root.getObject(),
|
|
20501
|
-
schemaRules
|
|
20502
|
-
);
|
|
20459
|
+
const rules = this.getSchemaRules();
|
|
20460
|
+
if (!ctx.isPresenceOnlyChange() && rules.length) {
|
|
20461
|
+
const result = validateYorkieRuleset((_a2 = this.clone) == null ? void 0 : _a2.root.getObject(), rules);
|
|
20503
20462
|
if (!result.valid) {
|
|
20504
20463
|
this.clone = void 0;
|
|
20505
20464
|
throw new YorkieError(
|
|
@@ -20509,18 +20468,18 @@ class Document {
|
|
|
20509
20468
|
}
|
|
20510
20469
|
}
|
|
20511
20470
|
const size = totalDocSize((_c2 = this.clone) == null ? void 0 : _c2.root.getDocSize());
|
|
20512
|
-
if (!
|
|
20471
|
+
if (!ctx.isPresenceOnlyChange() && this.maxSizeLimit > 0 && this.maxSizeLimit < size) {
|
|
20513
20472
|
this.clone = void 0;
|
|
20514
20473
|
throw new YorkieError(
|
|
20515
20474
|
Code.ErrDocumentSizeExceedsLimit,
|
|
20516
20475
|
`document size exceeded: ${size} > ${this.maxSizeLimit}`
|
|
20517
20476
|
);
|
|
20518
20477
|
}
|
|
20519
|
-
if (
|
|
20478
|
+
if (ctx.hasChange()) {
|
|
20520
20479
|
if (logger.isEnabled(LogLevel.Trivial)) {
|
|
20521
20480
|
logger.trivial(`trying to update a local change: ${this.toJSON()}`);
|
|
20522
20481
|
}
|
|
20523
|
-
const change =
|
|
20482
|
+
const change = ctx.toChange();
|
|
20524
20483
|
const { opInfos, reverseOps } = change.execute(
|
|
20525
20484
|
this.root,
|
|
20526
20485
|
this.presences,
|
|
@@ -20534,7 +20493,7 @@ class Document {
|
|
|
20534
20493
|
);
|
|
20535
20494
|
}
|
|
20536
20495
|
}
|
|
20537
|
-
const reversePresence =
|
|
20496
|
+
const reversePresence = ctx.getReversePresence();
|
|
20538
20497
|
if (reversePresence) {
|
|
20539
20498
|
reverseOps.push({
|
|
20540
20499
|
type: "presence",
|
|
@@ -20542,15 +20501,15 @@ class Document {
|
|
|
20542
20501
|
});
|
|
20543
20502
|
}
|
|
20544
20503
|
this.localChanges.push(change);
|
|
20545
|
-
if (reverseOps.length
|
|
20504
|
+
if (reverseOps.length) {
|
|
20546
20505
|
this.internalHistory.pushUndo(reverseOps);
|
|
20547
20506
|
}
|
|
20548
|
-
if (opInfos.length
|
|
20507
|
+
if (opInfos.length) {
|
|
20549
20508
|
this.internalHistory.clearRedo();
|
|
20550
20509
|
}
|
|
20551
|
-
this.changeID =
|
|
20510
|
+
this.changeID = ctx.getNextID();
|
|
20552
20511
|
const event = [];
|
|
20553
|
-
if (opInfos.length
|
|
20512
|
+
if (opInfos.length) {
|
|
20554
20513
|
event.push({
|
|
20555
20514
|
type: "local-change",
|
|
20556
20515
|
source: OpSource.Local,
|
|
@@ -20772,32 +20731,9 @@ class Document {
|
|
|
20772
20731
|
* `publish` triggers an event in this document, which can be received by
|
|
20773
20732
|
* callback functions from document.subscribe().
|
|
20774
20733
|
*/
|
|
20775
|
-
publish(
|
|
20734
|
+
publish(events) {
|
|
20776
20735
|
if (this.eventStreamObserver) {
|
|
20777
|
-
this.eventStreamObserver.next(
|
|
20778
|
-
}
|
|
20779
|
-
}
|
|
20780
|
-
isSameElementOrChildOf(elem, parent) {
|
|
20781
|
-
if (parent === elem) {
|
|
20782
|
-
return true;
|
|
20783
|
-
}
|
|
20784
|
-
const nodePath = elem.split(".");
|
|
20785
|
-
const targetPath = parent.split(".");
|
|
20786
|
-
return targetPath.every((path, index) => path === nodePath[index]);
|
|
20787
|
-
}
|
|
20788
|
-
/**
|
|
20789
|
-
* `removePushedLocalChanges` removes local changes that have been applied to
|
|
20790
|
-
* the server from the local changes.
|
|
20791
|
-
*
|
|
20792
|
-
* @param clientSeq - client sequence number to remove local changes before it
|
|
20793
|
-
*/
|
|
20794
|
-
removePushedLocalChanges(clientSeq) {
|
|
20795
|
-
while (this.localChanges.length) {
|
|
20796
|
-
const change = this.localChanges[0];
|
|
20797
|
-
if (change.getID().getClientSeq() > clientSeq) {
|
|
20798
|
-
break;
|
|
20799
|
-
}
|
|
20800
|
-
this.localChanges.shift();
|
|
20736
|
+
this.eventStreamObserver.next(events);
|
|
20801
20737
|
}
|
|
20802
20738
|
}
|
|
20803
20739
|
/**
|
|
@@ -20805,13 +20741,9 @@ class Document {
|
|
|
20805
20741
|
* 1. Remove local changes applied to server.
|
|
20806
20742
|
* 2. Update the checkpoint.
|
|
20807
20743
|
* 3. Do Garbage collection.
|
|
20808
|
-
*
|
|
20809
|
-
* @param pack - change pack
|
|
20810
|
-
* @internal
|
|
20811
20744
|
*/
|
|
20812
20745
|
applyChangePack(pack) {
|
|
20813
|
-
|
|
20814
|
-
if (hasSnapshot) {
|
|
20746
|
+
if (pack.hasSnapshot()) {
|
|
20815
20747
|
this.applySnapshot(
|
|
20816
20748
|
pack.getCheckpoint().getServerSeq(),
|
|
20817
20749
|
pack.getVersionVector(),
|
|
@@ -20823,7 +20755,7 @@ class Document {
|
|
|
20823
20755
|
this.removePushedLocalChanges(pack.getCheckpoint().getClientSeq());
|
|
20824
20756
|
}
|
|
20825
20757
|
this.checkpoint = this.checkpoint.forward(pack.getCheckpoint());
|
|
20826
|
-
if (!hasSnapshot) {
|
|
20758
|
+
if (!pack.hasSnapshot()) {
|
|
20827
20759
|
this.garbageCollect(pack.getVersionVector());
|
|
20828
20760
|
}
|
|
20829
20761
|
if (pack.getIsRemoved()) {
|
|
@@ -20838,16 +20770,12 @@ class Document {
|
|
|
20838
20770
|
}
|
|
20839
20771
|
/**
|
|
20840
20772
|
* `getCheckpoint` returns the checkpoint of this document.
|
|
20841
|
-
*
|
|
20842
|
-
* @internal
|
|
20843
20773
|
*/
|
|
20844
20774
|
getCheckpoint() {
|
|
20845
20775
|
return this.checkpoint;
|
|
20846
20776
|
}
|
|
20847
20777
|
/**
|
|
20848
20778
|
* `getChangeID` returns the change id of this document.
|
|
20849
|
-
*
|
|
20850
|
-
* @internal
|
|
20851
20779
|
*/
|
|
20852
20780
|
getChangeID() {
|
|
20853
20781
|
return this.changeID;
|
|
@@ -20860,8 +20788,6 @@ class Document {
|
|
|
20860
20788
|
}
|
|
20861
20789
|
/**
|
|
20862
20790
|
* `ensureClone` make a clone of root.
|
|
20863
|
-
*
|
|
20864
|
-
* @internal
|
|
20865
20791
|
*/
|
|
20866
20792
|
ensureClone() {
|
|
20867
20793
|
if (this.clone) {
|
|
@@ -20875,8 +20801,6 @@ class Document {
|
|
|
20875
20801
|
/**
|
|
20876
20802
|
* `createChangePack` create change pack of the local changes to send to the
|
|
20877
20803
|
* remote server.
|
|
20878
|
-
*
|
|
20879
|
-
* @internal
|
|
20880
20804
|
*/
|
|
20881
20805
|
createChangePack() {
|
|
20882
20806
|
const changes = Array.from(this.localChanges);
|
|
@@ -20892,8 +20816,6 @@ class Document {
|
|
|
20892
20816
|
/**
|
|
20893
20817
|
* `setActor` sets actor into this document. This is also applied in the local
|
|
20894
20818
|
* changes the document has.
|
|
20895
|
-
*
|
|
20896
|
-
* @internal
|
|
20897
20819
|
*/
|
|
20898
20820
|
setActor(actorID) {
|
|
20899
20821
|
for (const change of this.localChanges) {
|
|
@@ -20927,8 +20849,6 @@ class Document {
|
|
|
20927
20849
|
}
|
|
20928
20850
|
/**
|
|
20929
20851
|
* `getCloneRoot` returns clone object.
|
|
20930
|
-
*
|
|
20931
|
-
* @internal
|
|
20932
20852
|
*/
|
|
20933
20853
|
getCloneRoot() {
|
|
20934
20854
|
if (!this.clone) {
|
|
@@ -20941,12 +20861,12 @@ class Document {
|
|
|
20941
20861
|
*/
|
|
20942
20862
|
getRoot() {
|
|
20943
20863
|
this.ensureClone();
|
|
20944
|
-
const
|
|
20864
|
+
const ctx = ChangeContext.create(
|
|
20945
20865
|
this.changeID.next(),
|
|
20946
20866
|
this.clone.root,
|
|
20947
20867
|
this.clone.presences.get(this.changeID.getActorID()) || {}
|
|
20948
20868
|
);
|
|
20949
|
-
return createJSON(
|
|
20869
|
+
return createJSON(ctx, this.clone.root.getObject());
|
|
20950
20870
|
}
|
|
20951
20871
|
/**
|
|
20952
20872
|
* `getDocSize` returns the size of this document.
|
|
@@ -20980,8 +20900,6 @@ class Document {
|
|
|
20980
20900
|
}
|
|
20981
20901
|
/**
|
|
20982
20902
|
* `garbageCollect` purges elements that were removed before the given time.
|
|
20983
|
-
*
|
|
20984
|
-
* @internal
|
|
20985
20903
|
*/
|
|
20986
20904
|
garbageCollect(minSyncedVersionVector) {
|
|
20987
20905
|
if (this.opts.disableGC) {
|
|
@@ -20994,16 +20912,12 @@ class Document {
|
|
|
20994
20912
|
}
|
|
20995
20913
|
/**
|
|
20996
20914
|
* `getRootObject` returns root object.
|
|
20997
|
-
*
|
|
20998
|
-
* @internal
|
|
20999
20915
|
*/
|
|
21000
20916
|
getRootObject() {
|
|
21001
20917
|
return this.root.getObject();
|
|
21002
20918
|
}
|
|
21003
20919
|
/**
|
|
21004
20920
|
* `getGarbageLen` returns the length of elements should be purged.
|
|
21005
|
-
*
|
|
21006
|
-
* @internal
|
|
21007
20921
|
*/
|
|
21008
20922
|
getGarbageLen() {
|
|
21009
20923
|
return this.root.getGarbageLen();
|
|
@@ -21098,13 +21012,13 @@ class Document {
|
|
|
21098
21012
|
applyChange(change, source) {
|
|
21099
21013
|
this.ensureClone();
|
|
21100
21014
|
change.execute(this.clone.root, this.clone.presences, source);
|
|
21101
|
-
const
|
|
21015
|
+
const events = [];
|
|
21102
21016
|
const actorID = change.getID().getActorID();
|
|
21103
21017
|
if (change.hasPresenceChange() && this.onlineClients.has(actorID)) {
|
|
21104
21018
|
const presenceChange = change.getPresenceChange();
|
|
21105
21019
|
switch (presenceChange.type) {
|
|
21106
21020
|
case PresenceChangeType.Put:
|
|
21107
|
-
|
|
21021
|
+
events.push(
|
|
21108
21022
|
this.presences.has(actorID) ? {
|
|
21109
21023
|
type: "presence-changed",
|
|
21110
21024
|
source,
|
|
@@ -21123,7 +21037,7 @@ class Document {
|
|
|
21123
21037
|
);
|
|
21124
21038
|
break;
|
|
21125
21039
|
case PresenceChangeType.Clear:
|
|
21126
|
-
|
|
21040
|
+
events.push({
|
|
21127
21041
|
type: "unwatched",
|
|
21128
21042
|
source: OpSource.Remote,
|
|
21129
21043
|
value: {
|
|
@@ -21137,9 +21051,9 @@ class Document {
|
|
|
21137
21051
|
}
|
|
21138
21052
|
const { opInfos } = change.execute(this.root, this.presences, source);
|
|
21139
21053
|
this.changeID = this.changeID.syncClocks(change.getID());
|
|
21140
|
-
if (opInfos.length
|
|
21054
|
+
if (opInfos.length) {
|
|
21141
21055
|
const rawChange = this.isEnableDevtools() ? change.toStruct() : void 0;
|
|
21142
|
-
|
|
21056
|
+
events.push(
|
|
21143
21057
|
source === OpSource.Remote ? {
|
|
21144
21058
|
type: "remote-change",
|
|
21145
21059
|
source,
|
|
@@ -21165,8 +21079,8 @@ class Document {
|
|
|
21165
21079
|
}
|
|
21166
21080
|
);
|
|
21167
21081
|
}
|
|
21168
|
-
if (
|
|
21169
|
-
this.publish(
|
|
21082
|
+
if (events.length) {
|
|
21083
|
+
this.publish(events);
|
|
21170
21084
|
}
|
|
21171
21085
|
}
|
|
21172
21086
|
/**
|
|
@@ -21194,14 +21108,14 @@ class Document {
|
|
|
21194
21108
|
}
|
|
21195
21109
|
if (resp.body.case === "event") {
|
|
21196
21110
|
const { type, publisher } = resp.body.value;
|
|
21197
|
-
const
|
|
21111
|
+
const events = [];
|
|
21198
21112
|
if (type === DocEventType$1.DOCUMENT_WATCHED) {
|
|
21199
21113
|
if (this.onlineClients.has(publisher) && this.hasPresence(publisher)) {
|
|
21200
21114
|
return;
|
|
21201
21115
|
}
|
|
21202
21116
|
this.addOnlineClient(publisher);
|
|
21203
21117
|
if (this.hasPresence(publisher)) {
|
|
21204
|
-
|
|
21118
|
+
events.push({
|
|
21205
21119
|
type: "watched",
|
|
21206
21120
|
source: OpSource.Remote,
|
|
21207
21121
|
value: {
|
|
@@ -21214,7 +21128,7 @@ class Document {
|
|
|
21214
21128
|
const presence = this.getPresence(publisher);
|
|
21215
21129
|
this.removeOnlineClient(publisher);
|
|
21216
21130
|
if (presence) {
|
|
21217
|
-
|
|
21131
|
+
events.push({
|
|
21218
21132
|
type: "unwatched",
|
|
21219
21133
|
source: OpSource.Remote,
|
|
21220
21134
|
value: { clientID: publisher, presence }
|
|
@@ -21224,7 +21138,7 @@ class Document {
|
|
|
21224
21138
|
if (resp.body.value.body) {
|
|
21225
21139
|
const { topic, payload } = resp.body.value.body;
|
|
21226
21140
|
const decoder = new TextDecoder();
|
|
21227
|
-
|
|
21141
|
+
events.push({
|
|
21228
21142
|
type: "broadcast",
|
|
21229
21143
|
value: {
|
|
21230
21144
|
clientID: publisher,
|
|
@@ -21234,8 +21148,8 @@ class Document {
|
|
|
21234
21148
|
});
|
|
21235
21149
|
}
|
|
21236
21150
|
}
|
|
21237
|
-
if (
|
|
21238
|
-
this.publish(
|
|
21151
|
+
if (events.length) {
|
|
21152
|
+
this.publish(events);
|
|
21239
21153
|
}
|
|
21240
21154
|
}
|
|
21241
21155
|
}
|
|
@@ -21256,62 +21170,51 @@ class Document {
|
|
|
21256
21170
|
]);
|
|
21257
21171
|
}
|
|
21258
21172
|
/**
|
|
21259
|
-
* `
|
|
21173
|
+
* `applyDocEventsForReplay` applies the given events into this document.
|
|
21260
21174
|
*/
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21175
|
+
applyDocEventsForReplay(events) {
|
|
21176
|
+
for (const event of events) {
|
|
21177
|
+
if (event.type === "status-changed") {
|
|
21178
|
+
this.applyStatus(event.value.status);
|
|
21179
|
+
if (event.value.status === "attached") {
|
|
21180
|
+
this.setActor(event.value.actorID);
|
|
21181
|
+
}
|
|
21182
|
+
continue;
|
|
21266
21183
|
}
|
|
21267
|
-
|
|
21268
|
-
|
|
21269
|
-
|
|
21270
|
-
|
|
21271
|
-
|
|
21272
|
-
|
|
21273
|
-
|
|
21274
|
-
|
|
21275
|
-
|
|
21276
|
-
|
|
21277
|
-
|
|
21278
|
-
|
|
21279
|
-
|
|
21280
|
-
|
|
21281
|
-
|
|
21282
|
-
|
|
21283
|
-
|
|
21284
|
-
|
|
21285
|
-
|
|
21286
|
-
|
|
21287
|
-
|
|
21184
|
+
if (event.type === "snapshot") {
|
|
21185
|
+
const { snapshot, serverSeq, snapshotVector } = event.value;
|
|
21186
|
+
if (!snapshot) continue;
|
|
21187
|
+
this.applySnapshot(
|
|
21188
|
+
BigInt(serverSeq),
|
|
21189
|
+
converter.hexToVersionVector(snapshotVector),
|
|
21190
|
+
converter.hexToBytes(snapshot)
|
|
21191
|
+
);
|
|
21192
|
+
continue;
|
|
21193
|
+
}
|
|
21194
|
+
if (event.type === "local-change" || event.type === "remote-change") {
|
|
21195
|
+
if (!event.rawChange) continue;
|
|
21196
|
+
const change = Change.fromStruct(event.rawChange);
|
|
21197
|
+
this.applyChange(change, event.source);
|
|
21198
|
+
}
|
|
21199
|
+
if (event.type === "initialized") {
|
|
21200
|
+
const onlineClients = /* @__PURE__ */ new Set();
|
|
21201
|
+
for (const { clientID, presence } of event.value) {
|
|
21202
|
+
onlineClients.add(clientID);
|
|
21203
|
+
this.presences.set(clientID, presence);
|
|
21204
|
+
}
|
|
21205
|
+
this.setOnlineClients(onlineClients);
|
|
21206
|
+
} else if (event.type === "watched") {
|
|
21207
|
+
const { clientID, presence } = event.value;
|
|
21208
|
+
this.addOnlineClient(clientID);
|
|
21209
|
+
this.presences.set(clientID, presence);
|
|
21210
|
+
} else if (event.type === "unwatched") {
|
|
21211
|
+
const { clientID } = event.value;
|
|
21212
|
+
this.removeOnlineClient(clientID);
|
|
21213
|
+
this.presences.delete(clientID);
|
|
21214
|
+
} else if (event.type === "presence-changed") {
|
|
21215
|
+
const { clientID, presence } = event.value;
|
|
21288
21216
|
this.presences.set(clientID, presence);
|
|
21289
21217
|
}
|
|
21290
|
-
this.setOnlineClients(onlineClients);
|
|
21291
|
-
return;
|
|
21292
|
-
}
|
|
21293
|
-
if (event.type === "watched") {
|
|
21294
|
-
const { clientID, presence } = event.value;
|
|
21295
|
-
this.addOnlineClient(clientID);
|
|
21296
|
-
this.presences.set(clientID, presence);
|
|
21297
|
-
return;
|
|
21298
|
-
}
|
|
21299
|
-
if (event.type === "unwatched") {
|
|
21300
|
-
const { clientID } = event.value;
|
|
21301
|
-
this.removeOnlineClient(clientID);
|
|
21302
|
-
this.presences.delete(clientID);
|
|
21303
|
-
}
|
|
21304
|
-
if (event.type === "presence-changed") {
|
|
21305
|
-
const { clientID, presence } = event.value;
|
|
21306
|
-
this.presences.set(clientID, presence);
|
|
21307
|
-
}
|
|
21308
|
-
}
|
|
21309
|
-
/**
|
|
21310
|
-
* `applyDocEventsForReplay` applies the given events into this document.
|
|
21311
|
-
*/
|
|
21312
|
-
applyDocEventsForReplay(event) {
|
|
21313
|
-
for (const docEvent of event) {
|
|
21314
|
-
this.applyDocEventForReplay(docEvent);
|
|
21315
21218
|
}
|
|
21316
21219
|
}
|
|
21317
21220
|
/**
|
|
@@ -21324,51 +21227,41 @@ class Document {
|
|
|
21324
21227
|
`path must start with "$"`
|
|
21325
21228
|
);
|
|
21326
21229
|
}
|
|
21327
|
-
const
|
|
21328
|
-
|
|
21230
|
+
const paths = path.split(".");
|
|
21231
|
+
paths.shift();
|
|
21329
21232
|
let value = this.getRoot();
|
|
21330
|
-
for (const key of
|
|
21233
|
+
for (const key of paths) {
|
|
21331
21234
|
value = value[key];
|
|
21332
|
-
if (value
|
|
21235
|
+
if (!value) return void 0;
|
|
21333
21236
|
}
|
|
21334
21237
|
return value;
|
|
21335
21238
|
}
|
|
21336
21239
|
/**
|
|
21337
21240
|
* `setOnlineClients` sets the given online client set.
|
|
21338
|
-
*
|
|
21339
|
-
* @internal
|
|
21340
21241
|
*/
|
|
21341
21242
|
setOnlineClients(onlineClients) {
|
|
21342
21243
|
this.onlineClients = onlineClients;
|
|
21343
21244
|
}
|
|
21344
21245
|
/**
|
|
21345
21246
|
* `resetOnlineClients` resets the online client set.
|
|
21346
|
-
*
|
|
21347
|
-
* @internal
|
|
21348
21247
|
*/
|
|
21349
21248
|
resetOnlineClients() {
|
|
21350
21249
|
this.onlineClients = /* @__PURE__ */ new Set();
|
|
21351
21250
|
}
|
|
21352
21251
|
/**
|
|
21353
21252
|
* `addOnlineClient` adds the given clientID into the online client set.
|
|
21354
|
-
*
|
|
21355
|
-
* @internal
|
|
21356
21253
|
*/
|
|
21357
21254
|
addOnlineClient(clientID) {
|
|
21358
21255
|
this.onlineClients.add(clientID);
|
|
21359
21256
|
}
|
|
21360
21257
|
/**
|
|
21361
21258
|
* `removeOnlineClient` removes the clientID from the online client set.
|
|
21362
|
-
*
|
|
21363
|
-
* @internal
|
|
21364
21259
|
*/
|
|
21365
21260
|
removeOnlineClient(clientID) {
|
|
21366
21261
|
this.onlineClients.delete(clientID);
|
|
21367
21262
|
}
|
|
21368
21263
|
/**
|
|
21369
21264
|
* `hasPresence` returns whether the given clientID has a presence or not.
|
|
21370
|
-
*
|
|
21371
|
-
* @internal
|
|
21372
21265
|
*/
|
|
21373
21266
|
hasPresence(clientID) {
|
|
21374
21267
|
return this.presences.has(clientID);
|
|
@@ -21432,8 +21325,6 @@ class Document {
|
|
|
21432
21325
|
/**
|
|
21433
21326
|
* `getPresenceForTest` returns the presence of the given clientID
|
|
21434
21327
|
* regardless of whether the client is online or not.
|
|
21435
|
-
*
|
|
21436
|
-
* @internal
|
|
21437
21328
|
*/
|
|
21438
21329
|
getPresenceForTest(clientID) {
|
|
21439
21330
|
const p = this.presences.get(clientID);
|
|
@@ -21441,8 +21332,6 @@ class Document {
|
|
|
21441
21332
|
}
|
|
21442
21333
|
/**
|
|
21443
21334
|
* `getSelfForTest` returns the client that has attached this document.
|
|
21444
|
-
*
|
|
21445
|
-
* @internal
|
|
21446
21335
|
*/
|
|
21447
21336
|
getSelfForTest() {
|
|
21448
21337
|
return {
|
|
@@ -21452,193 +21341,135 @@ class Document {
|
|
|
21452
21341
|
}
|
|
21453
21342
|
/**
|
|
21454
21343
|
* `getOthersForTest` returns all the other clients in online, sorted by clientID.
|
|
21455
|
-
*
|
|
21456
|
-
* @internal
|
|
21457
21344
|
*/
|
|
21458
21345
|
getOthersForTest() {
|
|
21459
21346
|
const myClientID = this.getChangeID().getActorID();
|
|
21460
21347
|
return this.getPresences().filter((a) => a.clientID !== myClientID).sort((a, b) => a.clientID > b.clientID ? 1 : -1);
|
|
21461
21348
|
}
|
|
21462
21349
|
/**
|
|
21463
|
-
* `
|
|
21350
|
+
* `getUndoStackForTest` returns the undo stack for test.
|
|
21464
21351
|
*/
|
|
21465
|
-
|
|
21466
|
-
return this.internalHistory.
|
|
21352
|
+
getUndoStackForTest() {
|
|
21353
|
+
return this.internalHistory.getUndoStackForTest();
|
|
21467
21354
|
}
|
|
21468
21355
|
/**
|
|
21469
|
-
* `
|
|
21356
|
+
* `getRedoStackForTest` returns the redo stack for test.
|
|
21470
21357
|
*/
|
|
21471
|
-
|
|
21472
|
-
return this.internalHistory.
|
|
21358
|
+
getRedoStackForTest() {
|
|
21359
|
+
return this.internalHistory.getRedoStackForTest();
|
|
21473
21360
|
}
|
|
21474
21361
|
/**
|
|
21475
|
-
* `
|
|
21476
|
-
* It does not impact operations made by other clients.
|
|
21362
|
+
* `broadcast` the payload to the given topic.
|
|
21477
21363
|
*/
|
|
21478
|
-
|
|
21479
|
-
|
|
21480
|
-
|
|
21481
|
-
|
|
21482
|
-
|
|
21483
|
-
|
|
21484
|
-
}
|
|
21485
|
-
const undoOps = this.internalHistory.popUndo();
|
|
21486
|
-
if (undoOps === void 0) {
|
|
21487
|
-
throw new YorkieError(
|
|
21488
|
-
Code.ErrRefused,
|
|
21489
|
-
"There is no operation to be undone"
|
|
21490
|
-
);
|
|
21491
|
-
}
|
|
21492
|
-
this.ensureClone();
|
|
21493
|
-
const context = ChangeContext.create(
|
|
21494
|
-
this.changeID,
|
|
21495
|
-
this.clone.root,
|
|
21496
|
-
this.clone.presences.get(this.changeID.getActorID()) || {}
|
|
21497
|
-
);
|
|
21498
|
-
for (const undoOp of undoOps) {
|
|
21499
|
-
if (!(undoOp instanceof Operation)) {
|
|
21500
|
-
const presence = new Presence(
|
|
21501
|
-
context,
|
|
21502
|
-
deepcopy(this.clone.presences.get(this.changeID.getActorID()))
|
|
21503
|
-
);
|
|
21504
|
-
presence.set(undoOp.value, { addToHistory: true });
|
|
21505
|
-
continue;
|
|
21506
|
-
}
|
|
21507
|
-
const ticket = context.issueTimeTicket();
|
|
21508
|
-
undoOp.setExecutedAt(ticket);
|
|
21509
|
-
if (undoOp instanceof ArraySetOperation) {
|
|
21510
|
-
const prev = undoOp.getCreatedAt();
|
|
21511
|
-
undoOp.getValue().setCreatedAt(ticket);
|
|
21512
|
-
this.internalHistory.reconcileCreatedAt(prev, ticket);
|
|
21513
|
-
} else if (undoOp instanceof AddOperation) {
|
|
21514
|
-
const prev = undoOp.getValue().getCreatedAt();
|
|
21515
|
-
undoOp.getValue().setCreatedAt(ticket);
|
|
21516
|
-
this.internalHistory.reconcileCreatedAt(prev, ticket);
|
|
21364
|
+
broadcast(topic, payload, options) {
|
|
21365
|
+
this.publish([
|
|
21366
|
+
{
|
|
21367
|
+
type: "local-broadcast",
|
|
21368
|
+
value: { topic, payload },
|
|
21369
|
+
options
|
|
21517
21370
|
}
|
|
21518
|
-
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
|
|
21522
|
-
|
|
21523
|
-
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
reverseOps.push({
|
|
21530
|
-
type: "presence",
|
|
21531
|
-
value: reversePresence
|
|
21532
|
-
});
|
|
21533
|
-
}
|
|
21534
|
-
if (reverseOps.length > 0) {
|
|
21535
|
-
this.internalHistory.pushRedo(reverseOps);
|
|
21536
|
-
}
|
|
21537
|
-
if (!change.hasPresenceChange() && opInfos.length === 0) {
|
|
21538
|
-
return;
|
|
21539
|
-
}
|
|
21540
|
-
this.localChanges.push(change);
|
|
21541
|
-
this.changeID = context.getNextID();
|
|
21542
|
-
const actorID = this.changeID.getActorID();
|
|
21543
|
-
const event = [];
|
|
21544
|
-
if (opInfos.length > 0) {
|
|
21545
|
-
event.push({
|
|
21546
|
-
type: "local-change",
|
|
21547
|
-
source: OpSource.UndoRedo,
|
|
21548
|
-
value: {
|
|
21549
|
-
message: change.getMessage() || "",
|
|
21550
|
-
operations: opInfos,
|
|
21551
|
-
actor: actorID,
|
|
21552
|
-
clientSeq: change.getID().getClientSeq(),
|
|
21553
|
-
serverSeq: change.getID().getServerSeq()
|
|
21554
|
-
},
|
|
21555
|
-
rawChange: this.isEnableDevtools() ? change.toStruct() : void 0
|
|
21556
|
-
});
|
|
21371
|
+
]);
|
|
21372
|
+
}
|
|
21373
|
+
/**
|
|
21374
|
+
* `getVersionVector` returns the version vector of document
|
|
21375
|
+
*/
|
|
21376
|
+
getVersionVector() {
|
|
21377
|
+
return this.changeID.getVersionVector();
|
|
21378
|
+
}
|
|
21379
|
+
isSameElementOrChildOf(elem, parent) {
|
|
21380
|
+
if (parent === elem) {
|
|
21381
|
+
return true;
|
|
21557
21382
|
}
|
|
21558
|
-
|
|
21559
|
-
|
|
21560
|
-
|
|
21561
|
-
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21566
|
-
|
|
21383
|
+
const nodePath = elem.split(".");
|
|
21384
|
+
return parent.split(".").every((path, index) => path === nodePath[index]);
|
|
21385
|
+
}
|
|
21386
|
+
/**
|
|
21387
|
+
* `removePushedLocalChanges` removes local changes that have been applied to
|
|
21388
|
+
* the server from the local changes.
|
|
21389
|
+
*
|
|
21390
|
+
* @param clientSeq - client sequence number to remove local changes before it
|
|
21391
|
+
*/
|
|
21392
|
+
removePushedLocalChanges(clientSeq) {
|
|
21393
|
+
while (this.localChanges.length) {
|
|
21394
|
+
const change = this.localChanges[0];
|
|
21395
|
+
if (change.getID().getClientSeq() > clientSeq) {
|
|
21396
|
+
break;
|
|
21397
|
+
}
|
|
21398
|
+
this.localChanges.shift();
|
|
21567
21399
|
}
|
|
21568
|
-
this.publish(event);
|
|
21569
21400
|
}
|
|
21570
21401
|
/**
|
|
21571
|
-
* `
|
|
21572
|
-
* It does not impact operations made by other clients.
|
|
21402
|
+
* `executeUndoRedo` executes undo or redo operation with shared logic.
|
|
21573
21403
|
*/
|
|
21574
|
-
|
|
21404
|
+
executeUndoRedo(isUndo) {
|
|
21575
21405
|
if (this.isUpdating) {
|
|
21576
21406
|
throw new YorkieError(
|
|
21577
21407
|
Code.ErrRefused,
|
|
21578
|
-
"Redo is not allowed during an update
|
|
21408
|
+
`${isUndo ? "Undo" : "Redo"} is not allowed during an update`
|
|
21579
21409
|
);
|
|
21580
21410
|
}
|
|
21581
|
-
const
|
|
21582
|
-
if (
|
|
21411
|
+
const ops = isUndo ? this.internalHistory.popUndo() : this.internalHistory.popRedo();
|
|
21412
|
+
if (!ops) {
|
|
21583
21413
|
throw new YorkieError(
|
|
21584
21414
|
Code.ErrRefused,
|
|
21585
|
-
|
|
21415
|
+
`There is no operation to be ${isUndo ? "undone" : "redone"}`
|
|
21586
21416
|
);
|
|
21587
21417
|
}
|
|
21588
21418
|
this.ensureClone();
|
|
21589
|
-
const
|
|
21419
|
+
const ctx = ChangeContext.create(
|
|
21590
21420
|
this.changeID,
|
|
21591
21421
|
this.clone.root,
|
|
21592
21422
|
this.clone.presences.get(this.changeID.getActorID()) || {}
|
|
21593
21423
|
);
|
|
21594
|
-
for (const
|
|
21595
|
-
if (!(
|
|
21424
|
+
for (const op of ops) {
|
|
21425
|
+
if (!(op instanceof Operation)) {
|
|
21596
21426
|
const presence = new Presence(
|
|
21597
|
-
|
|
21427
|
+
ctx,
|
|
21598
21428
|
deepcopy(this.clone.presences.get(this.changeID.getActorID()))
|
|
21599
21429
|
);
|
|
21600
|
-
presence.set(
|
|
21430
|
+
presence.set(op.value, { addToHistory: true });
|
|
21601
21431
|
continue;
|
|
21602
21432
|
}
|
|
21603
|
-
const ticket =
|
|
21604
|
-
|
|
21605
|
-
if (
|
|
21606
|
-
const prev =
|
|
21607
|
-
|
|
21433
|
+
const ticket = ctx.issueTimeTicket();
|
|
21434
|
+
op.setExecutedAt(ticket);
|
|
21435
|
+
if (op instanceof ArraySetOperation) {
|
|
21436
|
+
const prev = op.getCreatedAt();
|
|
21437
|
+
op.getValue().setCreatedAt(ticket);
|
|
21608
21438
|
this.internalHistory.reconcileCreatedAt(prev, ticket);
|
|
21609
|
-
} else if (
|
|
21610
|
-
const prev =
|
|
21611
|
-
|
|
21439
|
+
} else if (op instanceof AddOperation) {
|
|
21440
|
+
const prev = op.getValue().getCreatedAt();
|
|
21441
|
+
op.getValue().setCreatedAt(ticket);
|
|
21612
21442
|
this.internalHistory.reconcileCreatedAt(prev, ticket);
|
|
21613
21443
|
}
|
|
21614
|
-
|
|
21444
|
+
ctx.push(op);
|
|
21615
21445
|
}
|
|
21616
|
-
const change =
|
|
21446
|
+
const change = ctx.toChange();
|
|
21617
21447
|
change.execute(this.clone.root, this.clone.presences, OpSource.UndoRedo);
|
|
21618
21448
|
const { opInfos, reverseOps } = change.execute(
|
|
21619
21449
|
this.root,
|
|
21620
21450
|
this.presences,
|
|
21621
21451
|
OpSource.UndoRedo
|
|
21622
21452
|
);
|
|
21623
|
-
const
|
|
21624
|
-
if (
|
|
21625
|
-
reverseOps.push({
|
|
21626
|
-
type: "presence",
|
|
21627
|
-
value: reversePresence
|
|
21628
|
-
});
|
|
21453
|
+
const reverse = ctx.getReversePresence();
|
|
21454
|
+
if (reverse) {
|
|
21455
|
+
reverseOps.push({ type: "presence", value: reverse });
|
|
21629
21456
|
}
|
|
21630
|
-
if (reverseOps.length
|
|
21631
|
-
|
|
21457
|
+
if (reverseOps.length) {
|
|
21458
|
+
if (isUndo) {
|
|
21459
|
+
this.internalHistory.pushRedo(reverseOps);
|
|
21460
|
+
} else {
|
|
21461
|
+
this.internalHistory.pushUndo(reverseOps);
|
|
21462
|
+
}
|
|
21632
21463
|
}
|
|
21633
|
-
if (!change.hasPresenceChange() && opInfos.length
|
|
21464
|
+
if (!change.hasPresenceChange() && !opInfos.length) {
|
|
21634
21465
|
return;
|
|
21635
21466
|
}
|
|
21636
21467
|
this.localChanges.push(change);
|
|
21637
|
-
this.changeID =
|
|
21468
|
+
this.changeID = ctx.getNextID();
|
|
21638
21469
|
const actorID = this.changeID.getActorID();
|
|
21639
|
-
const
|
|
21640
|
-
if (opInfos.length
|
|
21641
|
-
|
|
21470
|
+
const events = [];
|
|
21471
|
+
if (opInfos.length) {
|
|
21472
|
+
events.push({
|
|
21642
21473
|
type: "local-change",
|
|
21643
21474
|
source: OpSource.UndoRedo,
|
|
21644
21475
|
value: {
|
|
@@ -21652,7 +21483,7 @@ class Document {
|
|
|
21652
21483
|
});
|
|
21653
21484
|
}
|
|
21654
21485
|
if (change.hasPresenceChange()) {
|
|
21655
|
-
|
|
21486
|
+
events.push({
|
|
21656
21487
|
type: "presence-changed",
|
|
21657
21488
|
source: OpSource.UndoRedo,
|
|
21658
21489
|
value: {
|
|
@@ -21661,36 +21492,7 @@ class Document {
|
|
|
21661
21492
|
}
|
|
21662
21493
|
});
|
|
21663
21494
|
}
|
|
21664
|
-
this.publish(
|
|
21665
|
-
}
|
|
21666
|
-
/**
|
|
21667
|
-
* `getUndoStackForTest` returns the undo stack for test.
|
|
21668
|
-
*/
|
|
21669
|
-
getUndoStackForTest() {
|
|
21670
|
-
return this.internalHistory.getUndoStackForTest();
|
|
21671
|
-
}
|
|
21672
|
-
/**
|
|
21673
|
-
* `getRedoStackForTest` returns the redo stack for test.
|
|
21674
|
-
*/
|
|
21675
|
-
getRedoStackForTest() {
|
|
21676
|
-
return this.internalHistory.getRedoStackForTest();
|
|
21677
|
-
}
|
|
21678
|
-
/**
|
|
21679
|
-
* `broadcast` the payload to the given topic.
|
|
21680
|
-
*/
|
|
21681
|
-
broadcast(topic, payload, options) {
|
|
21682
|
-
const broadcastEvent = {
|
|
21683
|
-
type: "local-broadcast",
|
|
21684
|
-
value: { topic, payload },
|
|
21685
|
-
options
|
|
21686
|
-
};
|
|
21687
|
-
this.publish([broadcastEvent]);
|
|
21688
|
-
}
|
|
21689
|
-
/**
|
|
21690
|
-
* `getVersionVector` returns the version vector of document
|
|
21691
|
-
*/
|
|
21692
|
-
getVersionVector() {
|
|
21693
|
-
return this.changeID.getVersionVector();
|
|
21495
|
+
this.publish(events);
|
|
21694
21496
|
}
|
|
21695
21497
|
}
|
|
21696
21498
|
function createAuthInterceptor(apiKey, token) {
|
|
@@ -21713,7 +21515,7 @@ function createAuthInterceptor(apiKey, token) {
|
|
|
21713
21515
|
};
|
|
21714
21516
|
}
|
|
21715
21517
|
const name$1 = "@yorkie-js/sdk";
|
|
21716
|
-
const version$1 = "0.6.
|
|
21518
|
+
const version$1 = "0.6.29";
|
|
21717
21519
|
const pkg$1 = {
|
|
21718
21520
|
name: name$1,
|
|
21719
21521
|
version: version$1
|
|
@@ -21811,11 +21613,10 @@ class Client {
|
|
|
21811
21613
|
createMetricInterceptor(opts == null ? void 0 : opts.userAgent)
|
|
21812
21614
|
],
|
|
21813
21615
|
fetch: (input, init) => {
|
|
21814
|
-
|
|
21616
|
+
return fetch(input, {
|
|
21815
21617
|
...init,
|
|
21816
21618
|
keepalive: this.keepalive
|
|
21817
|
-
};
|
|
21818
|
-
return fetch(input, newInit);
|
|
21619
|
+
});
|
|
21819
21620
|
}
|
|
21820
21621
|
})
|
|
21821
21622
|
);
|
|
@@ -22609,7 +22410,7 @@ if (typeof globalThis !== "undefined") {
|
|
|
22609
22410
|
};
|
|
22610
22411
|
}
|
|
22611
22412
|
const name = "@yorkie-js/react";
|
|
22612
|
-
const version = "0.6.
|
|
22413
|
+
const version = "0.6.29";
|
|
22613
22414
|
const pkg = {
|
|
22614
22415
|
name,
|
|
22615
22416
|
version
|