reptree 0.2.0 → 0.2.2
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/index.cjs +59 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -8
- package/dist/index.d.ts +2 -8
- package/dist/index.js +59 -64
- package/dist/index.js.map +1 -1
- package/package.json +3 -5
package/dist/index.js
CHANGED
|
@@ -1,52 +1,49 @@
|
|
|
1
1
|
// src/OpId.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (!(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (!(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} else {
|
|
25
|
-
return opIdA.peerId.localeCompare(opIdB.peerId);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
static equals(opIdA, opIdB) {
|
|
29
|
-
if (opIdA === opIdB) {
|
|
30
|
-
return true;
|
|
31
|
-
} else if (!opIdA || !opIdB) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
return _OpId.compare(opIdA, opIdB) === 0;
|
|
35
|
-
}
|
|
36
|
-
static tryParseStr(opIdStr) {
|
|
37
|
-
const parts = opIdStr.split("@");
|
|
38
|
-
if (parts.length !== 2) {
|
|
39
|
-
throw new Error(`Invalid OpId string: ${opIdStr}`);
|
|
40
|
-
}
|
|
41
|
-
return new _OpId(parseInt(parts[0], 10), parts[1]);
|
|
2
|
+
function createOpId(counter, peerId) {
|
|
3
|
+
return { counter, peerId };
|
|
4
|
+
}
|
|
5
|
+
function compareOpId(opIdA, opIdB) {
|
|
6
|
+
if (typeof opIdA === "string") {
|
|
7
|
+
const parsedA = tryParseOpIdStr(opIdA);
|
|
8
|
+
if (!parsedA) throw new Error(`Invalid OpId string: ${opIdA}`);
|
|
9
|
+
opIdA = parsedA;
|
|
10
|
+
}
|
|
11
|
+
if (typeof opIdB === "string") {
|
|
12
|
+
const parsedB = tryParseOpIdStr(opIdB);
|
|
13
|
+
if (!parsedB) throw new Error(`Invalid OpId string: ${opIdB}`);
|
|
14
|
+
opIdB = parsedB;
|
|
15
|
+
}
|
|
16
|
+
const counterA = opIdA.counter;
|
|
17
|
+
const counterB = opIdB.counter;
|
|
18
|
+
if (counterA > counterB) {
|
|
19
|
+
return 1;
|
|
20
|
+
} else if (counterA < counterB) {
|
|
21
|
+
return -1;
|
|
22
|
+
} else {
|
|
23
|
+
return opIdA.peerId.localeCompare(opIdB.peerId);
|
|
42
24
|
}
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
}
|
|
26
|
+
function equalsOpId(opIdA, opIdB) {
|
|
27
|
+
if (opIdA === opIdB) {
|
|
28
|
+
return true;
|
|
29
|
+
} else if (!opIdA || !opIdB) {
|
|
30
|
+
return false;
|
|
45
31
|
}
|
|
46
|
-
|
|
47
|
-
|
|
32
|
+
return compareOpId(opIdA, opIdB) === 0;
|
|
33
|
+
}
|
|
34
|
+
function tryParseOpIdStr(opIdStr) {
|
|
35
|
+
const parts = opIdStr.split("@");
|
|
36
|
+
if (parts.length !== 2) {
|
|
37
|
+
throw new Error(`Invalid OpId string: ${opIdStr}`);
|
|
48
38
|
}
|
|
49
|
-
|
|
39
|
+
return createOpId(parseInt(parts[0], 10), parts[1]);
|
|
40
|
+
}
|
|
41
|
+
function isOpIdGreaterThan(opIdA, opIdB) {
|
|
42
|
+
return compareOpId(opIdA, opIdB) === 1;
|
|
43
|
+
}
|
|
44
|
+
function opIdToString(opId) {
|
|
45
|
+
return `${opId.counter}@${opId.peerId}`;
|
|
46
|
+
}
|
|
50
47
|
|
|
51
48
|
// src/operations.ts
|
|
52
49
|
function isMoveVertexOp(op) {
|
|
@@ -62,13 +59,13 @@ function isModifyPropertyOp(op) {
|
|
|
62
59
|
return "key" in op && "value" in op && typeof op.value === "object" && op.value !== null && "type" in op.value;
|
|
63
60
|
}
|
|
64
61
|
function newMoveVertexOp(clock, peerId, targetId, parentId) {
|
|
65
|
-
return { id:
|
|
62
|
+
return { id: createOpId(clock, peerId), targetId, parentId };
|
|
66
63
|
}
|
|
67
64
|
function newSetVertexPropertyOp(clock, peerId, targetId, key, value) {
|
|
68
|
-
return { id:
|
|
65
|
+
return { id: createOpId(clock, peerId), targetId, key, value, transient: false };
|
|
69
66
|
}
|
|
70
67
|
function newSetTransientVertexPropertyOp(clock, peerId, targetId, key, value) {
|
|
71
|
-
return { id:
|
|
68
|
+
return { id: createOpId(clock, peerId), targetId, key, value, transient: true };
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
// src/VertexState.ts
|
|
@@ -900,7 +897,7 @@ var _RepTree = class _RepTree {
|
|
|
900
897
|
}
|
|
901
898
|
applyOps(ops) {
|
|
902
899
|
for (const op of ops) {
|
|
903
|
-
if (this.knownOps.has(op.id
|
|
900
|
+
if (this.knownOps.has(opIdToString(op.id))) {
|
|
904
901
|
continue;
|
|
905
902
|
}
|
|
906
903
|
this.applyOperation(op);
|
|
@@ -908,16 +905,16 @@ var _RepTree = class _RepTree {
|
|
|
908
905
|
}
|
|
909
906
|
/** Applies operations in an optimized way, sorting move ops by OpId to avoid undo-do-redo cycles */
|
|
910
907
|
applyOpsOptimizedForLotsOfMoves(ops) {
|
|
911
|
-
const newMoveOps = ops.filter((op) => isMoveVertexOp(op) && !this.knownOps.has(op.id
|
|
908
|
+
const newMoveOps = ops.filter((op) => isMoveVertexOp(op) && !this.knownOps.has(opIdToString(op.id)));
|
|
912
909
|
if (newMoveOps.length > 0) {
|
|
913
910
|
const allMoveOps = [...this.moveOps, ...newMoveOps];
|
|
914
|
-
allMoveOps.sort((a, b) =>
|
|
911
|
+
allMoveOps.sort((a, b) => compareOpId(a.id, b.id));
|
|
915
912
|
for (let i = 0, len = allMoveOps.length; i < len; i++) {
|
|
916
913
|
const op = allMoveOps[i];
|
|
917
914
|
this.applyMove(op);
|
|
918
915
|
}
|
|
919
916
|
}
|
|
920
|
-
const propertyOps = ops.filter((op) => isAnyPropertyOp(op) && !this.knownOps.has(op.id
|
|
917
|
+
const propertyOps = ops.filter((op) => isAnyPropertyOp(op) && !this.knownOps.has(opIdToString(op.id)));
|
|
921
918
|
for (let i = 0, len = propertyOps.length; i < len; i++) {
|
|
922
919
|
const op = propertyOps[i];
|
|
923
920
|
this.applyProperty(op);
|
|
@@ -939,7 +936,7 @@ var _RepTree = class _RepTree {
|
|
|
939
936
|
return false;
|
|
940
937
|
}
|
|
941
938
|
for (let i = 0; i < movesA.length; i++) {
|
|
942
|
-
if (!
|
|
939
|
+
if (!equalsOpId(movesA[i].id, movesB[i].id)) {
|
|
943
940
|
return false;
|
|
944
941
|
}
|
|
945
942
|
}
|
|
@@ -1084,7 +1081,7 @@ var _RepTree = class _RepTree {
|
|
|
1084
1081
|
}
|
|
1085
1082
|
this.updateLamportClock(op);
|
|
1086
1083
|
const lastOp = this.moveOps.length > 0 ? this.moveOps[this.moveOps.length - 1] : null;
|
|
1087
|
-
if (lastOp === null || op.id
|
|
1084
|
+
if (lastOp === null || isOpIdGreaterThan(op.id, lastOp.id)) {
|
|
1088
1085
|
this.moveOps.push(op);
|
|
1089
1086
|
this.reportOpAsApplied(op);
|
|
1090
1087
|
this.tryToMove(op);
|
|
@@ -1093,7 +1090,7 @@ var _RepTree = class _RepTree {
|
|
|
1093
1090
|
for (let i = this.moveOps.length - 1; i >= 0; i--) {
|
|
1094
1091
|
const moveOp = this.moveOps[i];
|
|
1095
1092
|
targetIndex = i;
|
|
1096
|
-
if (op.id
|
|
1093
|
+
if (isOpIdGreaterThan(op.id, moveOp.id)) {
|
|
1097
1094
|
break;
|
|
1098
1095
|
} else {
|
|
1099
1096
|
this.undoMove(moveOp);
|
|
@@ -1173,21 +1170,20 @@ var _RepTree = class _RepTree {
|
|
|
1173
1170
|
}
|
|
1174
1171
|
applyLLWProperty(op, targetVertex) {
|
|
1175
1172
|
const prevTransientOpId = this.transientPropertiesAndTheirOpIds.get(`${op.key}@${op.targetId}`);
|
|
1176
|
-
const prevProp = targetVertex.getProperty(op.key);
|
|
1177
1173
|
const prevOpId = this.propertiesAndTheirOpIds.get(`${op.key}@${op.targetId}`);
|
|
1178
1174
|
if (!op.transient) {
|
|
1179
1175
|
this.setPropertyOps.push(op);
|
|
1180
|
-
if (!
|
|
1176
|
+
if (!prevOpId || isOpIdGreaterThan(op.id, prevOpId)) {
|
|
1181
1177
|
this.setLLWPropertyAndItsOpId(op);
|
|
1182
1178
|
} else {
|
|
1183
|
-
this.knownOps.add(op.id
|
|
1179
|
+
this.knownOps.add(opIdToString(op.id));
|
|
1184
1180
|
}
|
|
1185
|
-
if (prevTransientOpId && op.id
|
|
1181
|
+
if (prevTransientOpId && isOpIdGreaterThan(op.id, prevTransientOpId)) {
|
|
1186
1182
|
this.transientPropertiesAndTheirOpIds.delete(`${op.key}@${op.targetId}`);
|
|
1187
1183
|
targetVertex.removeTransientProperty(op.key);
|
|
1188
1184
|
}
|
|
1189
1185
|
} else {
|
|
1190
|
-
if (!prevTransientOpId || op.id
|
|
1186
|
+
if (!prevTransientOpId || isOpIdGreaterThan(op.id, prevTransientOpId)) {
|
|
1191
1187
|
this.setTransientPropertyAndItsOpId(op);
|
|
1192
1188
|
}
|
|
1193
1189
|
}
|
|
@@ -1222,7 +1218,7 @@ var _RepTree = class _RepTree {
|
|
|
1222
1218
|
}
|
|
1223
1219
|
}
|
|
1224
1220
|
reportOpAsApplied(op) {
|
|
1225
|
-
this.knownOps.add(op.id
|
|
1221
|
+
this.knownOps.add(opIdToString(op.id));
|
|
1226
1222
|
if (this._stateVectorEnabled) {
|
|
1227
1223
|
this.stateVector.updateFromOp(op);
|
|
1228
1224
|
}
|
|
@@ -1249,7 +1245,7 @@ var _RepTree = class _RepTree {
|
|
|
1249
1245
|
undoMove(op) {
|
|
1250
1246
|
const targetVertex = this.state.getVertex(op.targetId);
|
|
1251
1247
|
if (!targetVertex) {
|
|
1252
|
-
console.error(`An attempt to undo move operation ${op.id
|
|
1248
|
+
console.error(`An attempt to undo move operation ${opIdToString(op.id)} failed because the target vertex ${op.targetId} not found`);
|
|
1253
1249
|
return;
|
|
1254
1250
|
}
|
|
1255
1251
|
const prevParentId = this.parentIdBeforeMove.get(op.id);
|
|
@@ -1292,7 +1288,7 @@ var _RepTree = class _RepTree {
|
|
|
1292
1288
|
}
|
|
1293
1289
|
}
|
|
1294
1290
|
}
|
|
1295
|
-
missingOps.sort((a, b) =>
|
|
1291
|
+
missingOps.sort((a, b) => compareOpId(a.id, b.id));
|
|
1296
1292
|
return missingOps;
|
|
1297
1293
|
}
|
|
1298
1294
|
/**
|
|
@@ -1319,7 +1315,6 @@ var _RepTree = class _RepTree {
|
|
|
1319
1315
|
_RepTree.NULL_VERTEX_ID = "0";
|
|
1320
1316
|
var RepTree = _RepTree;
|
|
1321
1317
|
export {
|
|
1322
|
-
OpId,
|
|
1323
1318
|
RepTree,
|
|
1324
1319
|
StateVector,
|
|
1325
1320
|
TreeState,
|