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.cjs
CHANGED
|
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
OpId: () => OpId,
|
|
34
33
|
RepTree: () => RepTree,
|
|
35
34
|
StateVector: () => StateVector,
|
|
36
35
|
TreeState: () => TreeState,
|
|
@@ -48,54 +47,51 @@ __export(index_exports, {
|
|
|
48
47
|
module.exports = __toCommonJS(index_exports);
|
|
49
48
|
|
|
50
49
|
// src/OpId.ts
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
} else {
|
|
74
|
-
return opIdA.peerId.localeCompare(opIdB.peerId);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
static equals(opIdA, opIdB) {
|
|
78
|
-
if (opIdA === opIdB) {
|
|
79
|
-
return true;
|
|
80
|
-
} else if (!opIdA || !opIdB) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
return _OpId.compare(opIdA, opIdB) === 0;
|
|
84
|
-
}
|
|
85
|
-
static tryParseStr(opIdStr) {
|
|
86
|
-
const parts = opIdStr.split("@");
|
|
87
|
-
if (parts.length !== 2) {
|
|
88
|
-
throw new Error(`Invalid OpId string: ${opIdStr}`);
|
|
89
|
-
}
|
|
90
|
-
return new _OpId(parseInt(parts[0], 10), parts[1]);
|
|
50
|
+
function createOpId(counter, peerId) {
|
|
51
|
+
return { counter, peerId };
|
|
52
|
+
}
|
|
53
|
+
function compareOpId(opIdA, opIdB) {
|
|
54
|
+
if (typeof opIdA === "string") {
|
|
55
|
+
const parsedA = tryParseOpIdStr(opIdA);
|
|
56
|
+
if (!parsedA) throw new Error(`Invalid OpId string: ${opIdA}`);
|
|
57
|
+
opIdA = parsedA;
|
|
58
|
+
}
|
|
59
|
+
if (typeof opIdB === "string") {
|
|
60
|
+
const parsedB = tryParseOpIdStr(opIdB);
|
|
61
|
+
if (!parsedB) throw new Error(`Invalid OpId string: ${opIdB}`);
|
|
62
|
+
opIdB = parsedB;
|
|
63
|
+
}
|
|
64
|
+
const counterA = opIdA.counter;
|
|
65
|
+
const counterB = opIdB.counter;
|
|
66
|
+
if (counterA > counterB) {
|
|
67
|
+
return 1;
|
|
68
|
+
} else if (counterA < counterB) {
|
|
69
|
+
return -1;
|
|
70
|
+
} else {
|
|
71
|
+
return opIdA.peerId.localeCompare(opIdB.peerId);
|
|
91
72
|
}
|
|
92
|
-
|
|
93
|
-
|
|
73
|
+
}
|
|
74
|
+
function equalsOpId(opIdA, opIdB) {
|
|
75
|
+
if (opIdA === opIdB) {
|
|
76
|
+
return true;
|
|
77
|
+
} else if (!opIdA || !opIdB) {
|
|
78
|
+
return false;
|
|
94
79
|
}
|
|
95
|
-
|
|
96
|
-
|
|
80
|
+
return compareOpId(opIdA, opIdB) === 0;
|
|
81
|
+
}
|
|
82
|
+
function tryParseOpIdStr(opIdStr) {
|
|
83
|
+
const parts = opIdStr.split("@");
|
|
84
|
+
if (parts.length !== 2) {
|
|
85
|
+
throw new Error(`Invalid OpId string: ${opIdStr}`);
|
|
97
86
|
}
|
|
98
|
-
|
|
87
|
+
return createOpId(parseInt(parts[0], 10), parts[1]);
|
|
88
|
+
}
|
|
89
|
+
function isOpIdGreaterThan(opIdA, opIdB) {
|
|
90
|
+
return compareOpId(opIdA, opIdB) === 1;
|
|
91
|
+
}
|
|
92
|
+
function opIdToString(opId) {
|
|
93
|
+
return `${opId.counter}@${opId.peerId}`;
|
|
94
|
+
}
|
|
99
95
|
|
|
100
96
|
// src/operations.ts
|
|
101
97
|
function isMoveVertexOp(op) {
|
|
@@ -111,13 +107,13 @@ function isModifyPropertyOp(op) {
|
|
|
111
107
|
return "key" in op && "value" in op && typeof op.value === "object" && op.value !== null && "type" in op.value;
|
|
112
108
|
}
|
|
113
109
|
function newMoveVertexOp(clock, peerId, targetId, parentId) {
|
|
114
|
-
return { id:
|
|
110
|
+
return { id: createOpId(clock, peerId), targetId, parentId };
|
|
115
111
|
}
|
|
116
112
|
function newSetVertexPropertyOp(clock, peerId, targetId, key, value) {
|
|
117
|
-
return { id:
|
|
113
|
+
return { id: createOpId(clock, peerId), targetId, key, value, transient: false };
|
|
118
114
|
}
|
|
119
115
|
function newSetTransientVertexPropertyOp(clock, peerId, targetId, key, value) {
|
|
120
|
-
return { id:
|
|
116
|
+
return { id: createOpId(clock, peerId), targetId, key, value, transient: true };
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
// src/VertexState.ts
|
|
@@ -949,7 +945,7 @@ var _RepTree = class _RepTree {
|
|
|
949
945
|
}
|
|
950
946
|
applyOps(ops) {
|
|
951
947
|
for (const op of ops) {
|
|
952
|
-
if (this.knownOps.has(op.id
|
|
948
|
+
if (this.knownOps.has(opIdToString(op.id))) {
|
|
953
949
|
continue;
|
|
954
950
|
}
|
|
955
951
|
this.applyOperation(op);
|
|
@@ -957,16 +953,16 @@ var _RepTree = class _RepTree {
|
|
|
957
953
|
}
|
|
958
954
|
/** Applies operations in an optimized way, sorting move ops by OpId to avoid undo-do-redo cycles */
|
|
959
955
|
applyOpsOptimizedForLotsOfMoves(ops) {
|
|
960
|
-
const newMoveOps = ops.filter((op) => isMoveVertexOp(op) && !this.knownOps.has(op.id
|
|
956
|
+
const newMoveOps = ops.filter((op) => isMoveVertexOp(op) && !this.knownOps.has(opIdToString(op.id)));
|
|
961
957
|
if (newMoveOps.length > 0) {
|
|
962
958
|
const allMoveOps = [...this.moveOps, ...newMoveOps];
|
|
963
|
-
allMoveOps.sort((a, b) =>
|
|
959
|
+
allMoveOps.sort((a, b) => compareOpId(a.id, b.id));
|
|
964
960
|
for (let i = 0, len = allMoveOps.length; i < len; i++) {
|
|
965
961
|
const op = allMoveOps[i];
|
|
966
962
|
this.applyMove(op);
|
|
967
963
|
}
|
|
968
964
|
}
|
|
969
|
-
const propertyOps = ops.filter((op) => isAnyPropertyOp(op) && !this.knownOps.has(op.id
|
|
965
|
+
const propertyOps = ops.filter((op) => isAnyPropertyOp(op) && !this.knownOps.has(opIdToString(op.id)));
|
|
970
966
|
for (let i = 0, len = propertyOps.length; i < len; i++) {
|
|
971
967
|
const op = propertyOps[i];
|
|
972
968
|
this.applyProperty(op);
|
|
@@ -988,7 +984,7 @@ var _RepTree = class _RepTree {
|
|
|
988
984
|
return false;
|
|
989
985
|
}
|
|
990
986
|
for (let i = 0; i < movesA.length; i++) {
|
|
991
|
-
if (!
|
|
987
|
+
if (!equalsOpId(movesA[i].id, movesB[i].id)) {
|
|
992
988
|
return false;
|
|
993
989
|
}
|
|
994
990
|
}
|
|
@@ -1133,7 +1129,7 @@ var _RepTree = class _RepTree {
|
|
|
1133
1129
|
}
|
|
1134
1130
|
this.updateLamportClock(op);
|
|
1135
1131
|
const lastOp = this.moveOps.length > 0 ? this.moveOps[this.moveOps.length - 1] : null;
|
|
1136
|
-
if (lastOp === null || op.id
|
|
1132
|
+
if (lastOp === null || isOpIdGreaterThan(op.id, lastOp.id)) {
|
|
1137
1133
|
this.moveOps.push(op);
|
|
1138
1134
|
this.reportOpAsApplied(op);
|
|
1139
1135
|
this.tryToMove(op);
|
|
@@ -1142,7 +1138,7 @@ var _RepTree = class _RepTree {
|
|
|
1142
1138
|
for (let i = this.moveOps.length - 1; i >= 0; i--) {
|
|
1143
1139
|
const moveOp = this.moveOps[i];
|
|
1144
1140
|
targetIndex = i;
|
|
1145
|
-
if (op.id
|
|
1141
|
+
if (isOpIdGreaterThan(op.id, moveOp.id)) {
|
|
1146
1142
|
break;
|
|
1147
1143
|
} else {
|
|
1148
1144
|
this.undoMove(moveOp);
|
|
@@ -1222,21 +1218,20 @@ var _RepTree = class _RepTree {
|
|
|
1222
1218
|
}
|
|
1223
1219
|
applyLLWProperty(op, targetVertex) {
|
|
1224
1220
|
const prevTransientOpId = this.transientPropertiesAndTheirOpIds.get(`${op.key}@${op.targetId}`);
|
|
1225
|
-
const prevProp = targetVertex.getProperty(op.key);
|
|
1226
1221
|
const prevOpId = this.propertiesAndTheirOpIds.get(`${op.key}@${op.targetId}`);
|
|
1227
1222
|
if (!op.transient) {
|
|
1228
1223
|
this.setPropertyOps.push(op);
|
|
1229
|
-
if (!
|
|
1224
|
+
if (!prevOpId || isOpIdGreaterThan(op.id, prevOpId)) {
|
|
1230
1225
|
this.setLLWPropertyAndItsOpId(op);
|
|
1231
1226
|
} else {
|
|
1232
|
-
this.knownOps.add(op.id
|
|
1227
|
+
this.knownOps.add(opIdToString(op.id));
|
|
1233
1228
|
}
|
|
1234
|
-
if (prevTransientOpId && op.id
|
|
1229
|
+
if (prevTransientOpId && isOpIdGreaterThan(op.id, prevTransientOpId)) {
|
|
1235
1230
|
this.transientPropertiesAndTheirOpIds.delete(`${op.key}@${op.targetId}`);
|
|
1236
1231
|
targetVertex.removeTransientProperty(op.key);
|
|
1237
1232
|
}
|
|
1238
1233
|
} else {
|
|
1239
|
-
if (!prevTransientOpId || op.id
|
|
1234
|
+
if (!prevTransientOpId || isOpIdGreaterThan(op.id, prevTransientOpId)) {
|
|
1240
1235
|
this.setTransientPropertyAndItsOpId(op);
|
|
1241
1236
|
}
|
|
1242
1237
|
}
|
|
@@ -1271,7 +1266,7 @@ var _RepTree = class _RepTree {
|
|
|
1271
1266
|
}
|
|
1272
1267
|
}
|
|
1273
1268
|
reportOpAsApplied(op) {
|
|
1274
|
-
this.knownOps.add(op.id
|
|
1269
|
+
this.knownOps.add(opIdToString(op.id));
|
|
1275
1270
|
if (this._stateVectorEnabled) {
|
|
1276
1271
|
this.stateVector.updateFromOp(op);
|
|
1277
1272
|
}
|
|
@@ -1298,7 +1293,7 @@ var _RepTree = class _RepTree {
|
|
|
1298
1293
|
undoMove(op) {
|
|
1299
1294
|
const targetVertex = this.state.getVertex(op.targetId);
|
|
1300
1295
|
if (!targetVertex) {
|
|
1301
|
-
console.error(`An attempt to undo move operation ${op.id
|
|
1296
|
+
console.error(`An attempt to undo move operation ${opIdToString(op.id)} failed because the target vertex ${op.targetId} not found`);
|
|
1302
1297
|
return;
|
|
1303
1298
|
}
|
|
1304
1299
|
const prevParentId = this.parentIdBeforeMove.get(op.id);
|
|
@@ -1341,7 +1336,7 @@ var _RepTree = class _RepTree {
|
|
|
1341
1336
|
}
|
|
1342
1337
|
}
|
|
1343
1338
|
}
|
|
1344
|
-
missingOps.sort((a, b) =>
|
|
1339
|
+
missingOps.sort((a, b) => compareOpId(a.id, b.id));
|
|
1345
1340
|
return missingOps;
|
|
1346
1341
|
}
|
|
1347
1342
|
/**
|
|
@@ -1369,7 +1364,6 @@ _RepTree.NULL_VERTEX_ID = "0";
|
|
|
1369
1364
|
var RepTree = _RepTree;
|
|
1370
1365
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1371
1366
|
0 && (module.exports = {
|
|
1372
|
-
OpId,
|
|
1373
1367
|
RepTree,
|
|
1374
1368
|
StateVector,
|
|
1375
1369
|
TreeState,
|