@yorkie-js/sdk 0.6.49 → 0.7.0
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-sdk.d.ts
CHANGED
|
@@ -1920,12 +1920,12 @@ declare class CRDTTree extends CRDTElement implements GCParent {
|
|
|
1920
1920
|
* `edit` edits the tree with the given range and content.
|
|
1921
1921
|
* If the content is undefined, the range will be removed.
|
|
1922
1922
|
*/
|
|
1923
|
-
edit(range: [CRDTTreePos, CRDTTreePos], contents: Array<CRDTTreeNode> | undefined, splitLevel: number, editedAt: TimeTicket, issueTimeTicket: (() => TimeTicket) | undefined, versionVector?: VersionVector): [Array<TreeChange>, Array<GCPair>, DataSize];
|
|
1923
|
+
edit(range: [CRDTTreePos, CRDTTreePos], contents: Array<CRDTTreeNode> | undefined, splitLevel: number, editedAt: TimeTicket, issueTimeTicket: (() => TimeTicket) | undefined, versionVector?: VersionVector): [Array<TreeChange>, Array<GCPair>, DataSize, Array<CRDTTreeNode>, number];
|
|
1924
1924
|
/**
|
|
1925
1925
|
* `editT` edits the given range with the given value.
|
|
1926
1926
|
* This method uses indexes instead of a pair of TreePos for testing.
|
|
1927
1927
|
*/
|
|
1928
|
-
editT(range: [number, number], contents: Array<CRDTTreeNode> | undefined, splitLevel: number, editedAt: TimeTicket, issueTimeTicket: () => TimeTicket): [Array<TreeChange>, Array<GCPair>, DataSize];
|
|
1928
|
+
editT(range: [number, number], contents: Array<CRDTTreeNode> | undefined, splitLevel: number, editedAt: TimeTicket, issueTimeTicket: () => TimeTicket): [Array<TreeChange>, Array<GCPair>, DataSize, Array<CRDTTreeNode>, number];
|
|
1929
1929
|
/**
|
|
1930
1930
|
* `move` move the given source range to the given target range.
|
|
1931
1931
|
*/
|
package/dist/yorkie-js-sdk.es.js
CHANGED
|
@@ -12495,7 +12495,7 @@ class CRDTTree extends CRDTElement {
|
|
|
12495
12495
|
}
|
|
12496
12496
|
}
|
|
12497
12497
|
}
|
|
12498
|
-
return [changes, pairs, diff];
|
|
12498
|
+
return [changes, pairs, diff, nodesToBeRemoved, fromIdx];
|
|
12499
12499
|
}
|
|
12500
12500
|
/**
|
|
12501
12501
|
* `editT` edits the given range with the given value.
|
|
@@ -12933,29 +12933,46 @@ class CRDTTree extends CRDTElement {
|
|
|
12933
12933
|
return [prev, prev.isText ? TokenType.Text : TokenType.End];
|
|
12934
12934
|
}
|
|
12935
12935
|
}
|
|
12936
|
+
function clearRemovedAt(node) {
|
|
12937
|
+
traverseAll(node, (n) => {
|
|
12938
|
+
n.removedAt = void 0;
|
|
12939
|
+
n.visibleSize = n.totalSize;
|
|
12940
|
+
});
|
|
12941
|
+
}
|
|
12936
12942
|
class TreeEditOperation extends Operation {
|
|
12937
12943
|
fromPos;
|
|
12938
12944
|
toPos;
|
|
12939
12945
|
contents;
|
|
12940
12946
|
splitLevel;
|
|
12941
|
-
|
|
12947
|
+
isUndoOp;
|
|
12948
|
+
fromIdx;
|
|
12949
|
+
toIdx;
|
|
12950
|
+
lastFromIdx;
|
|
12951
|
+
lastToIdx;
|
|
12952
|
+
constructor(parentCreatedAt, fromPos, toPos, contents, splitLevel, executedAt, isUndoOp, fromIdx, toIdx) {
|
|
12942
12953
|
super(parentCreatedAt, executedAt);
|
|
12943
12954
|
this.fromPos = fromPos;
|
|
12944
12955
|
this.toPos = toPos;
|
|
12945
12956
|
this.contents = contents;
|
|
12946
12957
|
this.splitLevel = splitLevel;
|
|
12958
|
+
this.isUndoOp = isUndoOp;
|
|
12959
|
+
this.fromIdx = fromIdx;
|
|
12960
|
+
this.toIdx = toIdx;
|
|
12947
12961
|
}
|
|
12948
12962
|
/**
|
|
12949
12963
|
* `create` creates a new instance of EditOperation.
|
|
12950
12964
|
*/
|
|
12951
|
-
static create(parentCreatedAt, fromPos, toPos, contents, splitLevel, executedAt) {
|
|
12965
|
+
static create(parentCreatedAt, fromPos, toPos, contents, splitLevel, executedAt, isUndoOp, fromIdx, toIdx) {
|
|
12952
12966
|
return new TreeEditOperation(
|
|
12953
12967
|
parentCreatedAt,
|
|
12954
12968
|
fromPos,
|
|
12955
12969
|
toPos,
|
|
12956
12970
|
contents,
|
|
12957
12971
|
splitLevel,
|
|
12958
|
-
executedAt
|
|
12972
|
+
executedAt,
|
|
12973
|
+
isUndoOp,
|
|
12974
|
+
fromIdx,
|
|
12975
|
+
toIdx
|
|
12959
12976
|
);
|
|
12960
12977
|
}
|
|
12961
12978
|
/**
|
|
@@ -12977,7 +12994,15 @@ class TreeEditOperation extends Operation {
|
|
|
12977
12994
|
}
|
|
12978
12995
|
const editedAt = this.getExecutedAt();
|
|
12979
12996
|
const tree = parentObject;
|
|
12980
|
-
|
|
12997
|
+
if (this.isUndoOp && this.fromIdx !== void 0 && this.toIdx !== void 0) {
|
|
12998
|
+
this.fromPos = tree.findPos(this.fromIdx);
|
|
12999
|
+
if (this.fromIdx === this.toIdx) {
|
|
13000
|
+
this.toPos = this.fromPos;
|
|
13001
|
+
} else {
|
|
13002
|
+
this.toPos = tree.findPos(this.toIdx);
|
|
13003
|
+
}
|
|
13004
|
+
}
|
|
13005
|
+
const [changes, pairs, diff, removedNodes, preEditFromIdx] = tree.edit(
|
|
12981
13006
|
[this.fromPos, this.toPos],
|
|
12982
13007
|
this.contents?.map((content) => content.deepcopy()),
|
|
12983
13008
|
this.splitLevel,
|
|
@@ -13003,6 +13028,13 @@ class TreeEditOperation extends Operation {
|
|
|
13003
13028
|
})(),
|
|
13004
13029
|
versionVector
|
|
13005
13030
|
);
|
|
13031
|
+
this.lastFromIdx = preEditFromIdx;
|
|
13032
|
+
const removedSize = removedNodes.reduce(
|
|
13033
|
+
(sum, node) => sum + node.paddedSize(),
|
|
13034
|
+
0
|
|
13035
|
+
);
|
|
13036
|
+
this.lastToIdx = preEditFromIdx + removedSize;
|
|
13037
|
+
const reverseOp = this.splitLevel === 0 ? this.toReverseOperation(tree, removedNodes, preEditFromIdx) : void 0;
|
|
13006
13038
|
root.acc(diff);
|
|
13007
13039
|
for (const pair of pairs) {
|
|
13008
13040
|
root.registerGCPair(pair);
|
|
@@ -13021,9 +13053,131 @@ class TreeEditOperation extends Operation {
|
|
|
13021
13053
|
toPath
|
|
13022
13054
|
};
|
|
13023
13055
|
}
|
|
13024
|
-
)
|
|
13056
|
+
),
|
|
13057
|
+
reverseOp
|
|
13025
13058
|
};
|
|
13026
13059
|
}
|
|
13060
|
+
/**
|
|
13061
|
+
* `toReverseOperation` creates the reverse operation for undo.
|
|
13062
|
+
*
|
|
13063
|
+
* The reverse op stores both CRDTTreePos (for initial use) and integer
|
|
13064
|
+
* indices (for reconciliation adjustment when remote edits arrive).
|
|
13065
|
+
* At undo execution time, the integer indices take precedence and are
|
|
13066
|
+
* converted to CRDTTreePos via tree.findPos().
|
|
13067
|
+
*
|
|
13068
|
+
* @param tree - The CRDTTree after the edit has been applied
|
|
13069
|
+
* @param removedNodes - Nodes that were removed by this edit
|
|
13070
|
+
* @param preEditFromIdx - The from index captured BEFORE the edit
|
|
13071
|
+
*/
|
|
13072
|
+
toReverseOperation(tree, removedNodes, preEditFromIdx) {
|
|
13073
|
+
const insertedContentSize = this.contents ? this.contents.reduce((sum, node) => sum + node.paddedSize(), 0) : 0;
|
|
13074
|
+
const maxNeededIdx = preEditFromIdx + insertedContentSize;
|
|
13075
|
+
if (maxNeededIdx > tree.getSize()) {
|
|
13076
|
+
return void 0;
|
|
13077
|
+
}
|
|
13078
|
+
const topLevelRemoved = removedNodes.filter(
|
|
13079
|
+
(node) => !node.parent || !removedNodes.includes(node.parent)
|
|
13080
|
+
);
|
|
13081
|
+
const reverseContents = topLevelRemoved.length > 0 ? topLevelRemoved.map((n) => {
|
|
13082
|
+
const clone = n.deepcopy();
|
|
13083
|
+
clearRemovedAt(clone);
|
|
13084
|
+
return clone;
|
|
13085
|
+
}) : void 0;
|
|
13086
|
+
const reverseFromPos = tree.findPos(preEditFromIdx);
|
|
13087
|
+
let reverseToPos;
|
|
13088
|
+
if (insertedContentSize > 0) {
|
|
13089
|
+
reverseToPos = tree.findPos(preEditFromIdx + insertedContentSize);
|
|
13090
|
+
} else {
|
|
13091
|
+
reverseToPos = reverseFromPos;
|
|
13092
|
+
}
|
|
13093
|
+
const reverseFromIdx = preEditFromIdx;
|
|
13094
|
+
const reverseToIdx = preEditFromIdx + insertedContentSize;
|
|
13095
|
+
return TreeEditOperation.create(
|
|
13096
|
+
this.getParentCreatedAt(),
|
|
13097
|
+
reverseFromPos,
|
|
13098
|
+
reverseToPos,
|
|
13099
|
+
reverseContents,
|
|
13100
|
+
0,
|
|
13101
|
+
// splitLevel always 0
|
|
13102
|
+
void 0,
|
|
13103
|
+
// executedAt set during undo
|
|
13104
|
+
true,
|
|
13105
|
+
// isUndoOp
|
|
13106
|
+
reverseFromIdx,
|
|
13107
|
+
reverseToIdx
|
|
13108
|
+
);
|
|
13109
|
+
}
|
|
13110
|
+
/**
|
|
13111
|
+
* `normalizePos` returns the visible-index range of this operation.
|
|
13112
|
+
* For undo ops, returns the stored (possibly reconciled) indices.
|
|
13113
|
+
* For forward ops, returns the pre-edit indices captured during execute().
|
|
13114
|
+
*/
|
|
13115
|
+
normalizePos() {
|
|
13116
|
+
if (this.isUndoOp && this.fromIdx !== void 0 && this.toIdx !== void 0) {
|
|
13117
|
+
return [this.fromIdx, this.toIdx];
|
|
13118
|
+
}
|
|
13119
|
+
if (this.lastFromIdx !== void 0 && this.lastToIdx !== void 0) {
|
|
13120
|
+
return [this.lastFromIdx, this.lastToIdx];
|
|
13121
|
+
}
|
|
13122
|
+
return [0, 0];
|
|
13123
|
+
}
|
|
13124
|
+
/**
|
|
13125
|
+
* `reconcileOperation` adjusts this undo operation's integer indices
|
|
13126
|
+
* when a remote edit modifies the same tree. Uses the same 6-case
|
|
13127
|
+
* overlap logic as EditOperation.reconcileOperation for Text.
|
|
13128
|
+
*/
|
|
13129
|
+
reconcileOperation(remoteFrom, remoteTo, contentLen) {
|
|
13130
|
+
if (!this.isUndoOp) {
|
|
13131
|
+
return;
|
|
13132
|
+
}
|
|
13133
|
+
if (this.fromIdx === void 0 || this.toIdx === void 0) {
|
|
13134
|
+
return;
|
|
13135
|
+
}
|
|
13136
|
+
if (remoteFrom > remoteTo) {
|
|
13137
|
+
return;
|
|
13138
|
+
}
|
|
13139
|
+
const remoteRangeLen = remoteTo - remoteFrom;
|
|
13140
|
+
const localFrom = this.fromIdx;
|
|
13141
|
+
const localTo = this.toIdx;
|
|
13142
|
+
const apply = (na, nb) => {
|
|
13143
|
+
this.fromIdx = Math.max(0, na);
|
|
13144
|
+
this.toIdx = Math.max(0, nb);
|
|
13145
|
+
};
|
|
13146
|
+
if (remoteTo <= localFrom) {
|
|
13147
|
+
apply(
|
|
13148
|
+
localFrom - remoteRangeLen + contentLen,
|
|
13149
|
+
localTo - remoteRangeLen + contentLen
|
|
13150
|
+
);
|
|
13151
|
+
return;
|
|
13152
|
+
}
|
|
13153
|
+
if (localTo <= remoteFrom) {
|
|
13154
|
+
return;
|
|
13155
|
+
}
|
|
13156
|
+
if (remoteFrom <= localFrom && localTo <= remoteTo && remoteFrom !== remoteTo) {
|
|
13157
|
+
apply(remoteFrom, remoteFrom);
|
|
13158
|
+
return;
|
|
13159
|
+
}
|
|
13160
|
+
if (localFrom <= remoteFrom && remoteTo <= localTo && localFrom !== localTo) {
|
|
13161
|
+
apply(localFrom, localTo - remoteRangeLen + contentLen);
|
|
13162
|
+
return;
|
|
13163
|
+
}
|
|
13164
|
+
if (remoteFrom < localFrom && localFrom < remoteTo && remoteTo < localTo) {
|
|
13165
|
+
apply(remoteFrom, remoteFrom + (localTo - remoteTo));
|
|
13166
|
+
return;
|
|
13167
|
+
}
|
|
13168
|
+
if (localFrom < remoteFrom && remoteFrom < localTo && localTo < remoteTo) {
|
|
13169
|
+
apply(localFrom, remoteFrom);
|
|
13170
|
+
return;
|
|
13171
|
+
}
|
|
13172
|
+
}
|
|
13173
|
+
/**
|
|
13174
|
+
* `getContentSize` returns the total visible size of this operation's
|
|
13175
|
+
* content (for reconciliation).
|
|
13176
|
+
*/
|
|
13177
|
+
getContentSize() {
|
|
13178
|
+
if (!this.contents) return 0;
|
|
13179
|
+
return this.contents.reduce((sum, node) => sum + node.paddedSize(), 0);
|
|
13180
|
+
}
|
|
13027
13181
|
/**
|
|
13028
13182
|
* `getEffectedCreatedAt` returns the creation time of the effected element.
|
|
13029
13183
|
*/
|
|
@@ -17951,6 +18105,24 @@ class History {
|
|
|
17951
18105
|
replace(this.undoStack);
|
|
17952
18106
|
replace(this.redoStack);
|
|
17953
18107
|
}
|
|
18108
|
+
/**
|
|
18109
|
+
* `reconcileTreeEdit` reconciles the tree edit operation.
|
|
18110
|
+
* Scan both undo/redo stacks and adjust tree edit operations
|
|
18111
|
+
* when a remote edit modifies the same tree.
|
|
18112
|
+
*/
|
|
18113
|
+
reconcileTreeEdit(parentCreatedAt, rangeFrom, rangeTo, contentSize) {
|
|
18114
|
+
const replace = (stack) => {
|
|
18115
|
+
for (const ops of stack) {
|
|
18116
|
+
for (const op of ops) {
|
|
18117
|
+
if (op instanceof TreeEditOperation && op.getParentCreatedAt().compare(parentCreatedAt) === 0) {
|
|
18118
|
+
op.reconcileOperation(rangeFrom, rangeTo, contentSize);
|
|
18119
|
+
}
|
|
18120
|
+
}
|
|
18121
|
+
}
|
|
18122
|
+
};
|
|
18123
|
+
replace(this.undoStack);
|
|
18124
|
+
replace(this.redoStack);
|
|
18125
|
+
}
|
|
17954
18126
|
}
|
|
17955
18127
|
function validateYorkieRuleset(data, ruleset) {
|
|
17956
18128
|
const errors = [];
|
|
@@ -18909,6 +19081,15 @@ class Document {
|
|
|
18909
19081
|
op.getContent()?.length ?? 0
|
|
18910
19082
|
);
|
|
18911
19083
|
}
|
|
19084
|
+
if (op instanceof TreeEditOperation) {
|
|
19085
|
+
const [from, to] = op.normalizePos();
|
|
19086
|
+
this.internalHistory.reconcileTreeEdit(
|
|
19087
|
+
op.getParentCreatedAt(),
|
|
19088
|
+
from,
|
|
19089
|
+
to,
|
|
19090
|
+
op.getContentSize()
|
|
19091
|
+
);
|
|
19092
|
+
}
|
|
18912
19093
|
}
|
|
18913
19094
|
this.changeID = this.changeID.syncClocks(change.getID());
|
|
18914
19095
|
if (opInfos.length) {
|
|
@@ -19454,7 +19635,7 @@ function createAuthInterceptor(apiKey, token) {
|
|
|
19454
19635
|
};
|
|
19455
19636
|
}
|
|
19456
19637
|
const name = "@yorkie-js/sdk";
|
|
19457
|
-
const version = "0.
|
|
19638
|
+
const version = "0.7.0";
|
|
19458
19639
|
const pkg = {
|
|
19459
19640
|
name,
|
|
19460
19641
|
version
|