@sovereignbase/convergent-replicated-list 1.3.4 → 1.3.6
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/README.md +207 -206
- package/dist/index.cjs +174 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -11
- package/dist/index.d.ts +19 -11
- package/dist/index.js +148 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -294,8 +294,17 @@ function trySpliceReplacement(crListReplica, insertedEntries, reparentedEntries,
|
|
|
294
294
|
} else if (crListReplica.childrenMap.get(inserted.uuidv7)?.length) {
|
|
295
295
|
return false;
|
|
296
296
|
}
|
|
297
|
-
if (predecessor
|
|
298
|
-
|
|
297
|
+
if (predecessor) {
|
|
298
|
+
if (predecessor.next !== next) return false;
|
|
299
|
+
} else {
|
|
300
|
+
let reachable = 0;
|
|
301
|
+
let current2 = next;
|
|
302
|
+
while (current2) {
|
|
303
|
+
reachable++;
|
|
304
|
+
current2 = current2.next;
|
|
305
|
+
}
|
|
306
|
+
if (reachable !== crListReplica.parentMap.size - 1) return false;
|
|
307
|
+
}
|
|
299
308
|
const expectedIndex = predecessor ? predecessor.index + 1 : 0;
|
|
300
309
|
void linkEntryBetween(predecessor, inserted, next);
|
|
301
310
|
let current = inserted;
|
|
@@ -312,6 +321,48 @@ function trySpliceReplacement(crListReplica, insertedEntries, reparentedEntries,
|
|
|
312
321
|
return true;
|
|
313
322
|
}
|
|
314
323
|
|
|
324
|
+
// src/.helpers/trySpliceSiblingInsert/index.ts
|
|
325
|
+
function trySpliceSiblingInsert(crListReplica, insertedEntries, reparentedEntries, tombstoneCount) {
|
|
326
|
+
if (tombstoneCount !== 0 || insertedEntries.length !== 1 || reparentedEntries.length !== 0)
|
|
327
|
+
return false;
|
|
328
|
+
const inserted = insertedEntries[0];
|
|
329
|
+
if (inserted.predecessor === "\0") return false;
|
|
330
|
+
if (crListReplica.childrenMap.get(inserted.uuidv7)?.length) return false;
|
|
331
|
+
const predecessor = crListReplica.parentMap.get(inserted.predecessor);
|
|
332
|
+
const siblings = crListReplica.childrenMap.get(inserted.predecessor);
|
|
333
|
+
if (!predecessor || !siblings || siblings.length < 2) return false;
|
|
334
|
+
void siblings.sort((a, b) => a.uuidv7 > b.uuidv7 ? 1 : -1);
|
|
335
|
+
const siblingIndex = siblings.indexOf(inserted);
|
|
336
|
+
if (siblingIndex === -1) return false;
|
|
337
|
+
const lastSibling = siblings[siblings.length - 1];
|
|
338
|
+
if (lastSibling !== inserted && lastSibling.next) return false;
|
|
339
|
+
const previousSibling = siblings[siblingIndex - 1];
|
|
340
|
+
const nextSibling = siblings[siblingIndex + 1];
|
|
341
|
+
if (previousSibling?.uuidv7) {
|
|
342
|
+
if (crListReplica.childrenMap.get(previousSibling.uuidv7)?.length)
|
|
343
|
+
return false;
|
|
344
|
+
if (previousSibling.next !== nextSibling) return false;
|
|
345
|
+
} else if (predecessor.next !== nextSibling) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
const prev = previousSibling ?? predecessor;
|
|
349
|
+
const next = nextSibling;
|
|
350
|
+
if (next && next.prev !== prev) return false;
|
|
351
|
+
void linkEntryBetween(prev, inserted, next);
|
|
352
|
+
let current = inserted;
|
|
353
|
+
let index = prev.index + 1;
|
|
354
|
+
while (current) {
|
|
355
|
+
current.index = index;
|
|
356
|
+
index++;
|
|
357
|
+
current = current.next;
|
|
358
|
+
}
|
|
359
|
+
crListReplica.index = /* @__PURE__ */ new Map([[inserted.index, inserted]]);
|
|
360
|
+
crListReplica.cursor = inserted;
|
|
361
|
+
crListReplica.cursorIndex = inserted.index;
|
|
362
|
+
crListReplica.size = crListReplica.parentMap.size;
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
|
|
315
366
|
// src/core/crud/create/index.ts
|
|
316
367
|
import { isUuidV7 as isUuidV72, prototype } from "@sovereignbase/utils";
|
|
317
368
|
function __create(snapshot) {
|
|
@@ -385,6 +436,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
385
436
|
if (listValues.length === 0) return false;
|
|
386
437
|
const change = {};
|
|
387
438
|
const delta = { values: [], tombstones: [] };
|
|
439
|
+
let displacedEntry;
|
|
388
440
|
for (const listValue of listValues) {
|
|
389
441
|
const v7 = uuidv7();
|
|
390
442
|
const linkedListEntry = {
|
|
@@ -433,15 +485,27 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
433
485
|
linkedListEntry,
|
|
434
486
|
entryToOverwrite.next
|
|
435
487
|
);
|
|
436
|
-
if (entryToOverwrite.next) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
);
|
|
488
|
+
if (entryToOverwrite.next?.predecessor === entryToOverwrite.uuidv7) {
|
|
489
|
+
const overwriteNext = entryToOverwrite.next;
|
|
490
|
+
const owSibs = crListReplica.childrenMap.get(
|
|
491
|
+
overwriteNext.predecessor
|
|
492
|
+
);
|
|
493
|
+
if (owSibs) {
|
|
494
|
+
const i = owSibs.indexOf(overwriteNext);
|
|
495
|
+
if (i !== -1) owSibs.splice(i, 1);
|
|
444
496
|
}
|
|
497
|
+
overwriteNext.predecessor = linkedListEntry.uuidv7;
|
|
498
|
+
const newSibs = crListReplica.childrenMap.get(linkedListEntry.uuidv7);
|
|
499
|
+
if (newSibs) newSibs.push(overwriteNext);
|
|
500
|
+
else
|
|
501
|
+
crListReplica.childrenMap.set(linkedListEntry.uuidv7, [
|
|
502
|
+
overwriteNext
|
|
503
|
+
]);
|
|
504
|
+
delta.values?.push({
|
|
505
|
+
uuidv7: overwriteNext.uuidv7,
|
|
506
|
+
value: overwriteNext.value,
|
|
507
|
+
predecessor: overwriteNext.predecessor
|
|
508
|
+
});
|
|
445
509
|
}
|
|
446
510
|
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
447
511
|
void crListReplica.tombstones.add(entryToOverwrite.uuidv7);
|
|
@@ -475,20 +539,24 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
475
539
|
linkedListEntry.index = actualIndex + 1;
|
|
476
540
|
linkedListEntry.predecessor = crListReplica.cursor.uuidv7;
|
|
477
541
|
void linkEntryBetween(crListReplica.cursor, linkedListEntry, next);
|
|
478
|
-
if (next) {
|
|
479
|
-
if (
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
542
|
+
if (next && next.predecessor === crListReplica.cursor.uuidv7) {
|
|
543
|
+
if (!displacedEntry) {
|
|
544
|
+
displacedEntry = next;
|
|
545
|
+
const sibs = crListReplica.childrenMap.get(next.predecessor);
|
|
546
|
+
if (sibs) {
|
|
547
|
+
const i = sibs.indexOf(next);
|
|
548
|
+
if (i !== -1) sibs.splice(i, 1);
|
|
549
|
+
}
|
|
486
550
|
}
|
|
551
|
+
displacedEntry.predecessor = linkedListEntry.uuidv7;
|
|
487
552
|
}
|
|
488
553
|
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
489
554
|
crListReplica.cursor = linkedListEntry;
|
|
490
555
|
crListReplica.cursorIndex = linkedListEntry.index;
|
|
491
|
-
if (next)
|
|
556
|
+
if (next) {
|
|
557
|
+
if (crListReplica.index) crListReplica.index.clear();
|
|
558
|
+
else crListReplica.index = /* @__PURE__ */ new Map();
|
|
559
|
+
}
|
|
492
560
|
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
493
561
|
change[linkedListEntry.index] = linkedListEntry.value;
|
|
494
562
|
break;
|
|
@@ -512,17 +580,23 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
512
580
|
linkedListEntry.predecessor = prev?.uuidv7 ?? "\0";
|
|
513
581
|
void linkEntryBetween(prev, linkedListEntry, crListReplica.cursor);
|
|
514
582
|
if (crListReplica.cursor.predecessor === linkedListEntry.predecessor) {
|
|
515
|
-
|
|
516
|
-
crListReplica
|
|
517
|
-
crListReplica.
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
583
|
+
if (!displacedEntry) {
|
|
584
|
+
displacedEntry = crListReplica.cursor;
|
|
585
|
+
const sibs = crListReplica.childrenMap.get(
|
|
586
|
+
crListReplica.cursor.predecessor
|
|
587
|
+
);
|
|
588
|
+
if (sibs) {
|
|
589
|
+
const i = sibs.indexOf(crListReplica.cursor);
|
|
590
|
+
if (i !== -1) sibs.splice(i, 1);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
displacedEntry.predecessor = linkedListEntry.uuidv7;
|
|
521
594
|
}
|
|
522
595
|
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
523
596
|
crListReplica.cursor = linkedListEntry;
|
|
524
597
|
crListReplica.cursorIndex = actualIndex;
|
|
525
|
-
crListReplica.index
|
|
598
|
+
if (crListReplica.index) crListReplica.index.clear();
|
|
599
|
+
else crListReplica.index = /* @__PURE__ */ new Map();
|
|
526
600
|
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
527
601
|
change[actualIndex] = linkedListEntry.value;
|
|
528
602
|
mode = "after";
|
|
@@ -533,6 +607,19 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
533
607
|
crListReplica.size = crListReplica.parentMap.size;
|
|
534
608
|
listIndex++;
|
|
535
609
|
}
|
|
610
|
+
if (displacedEntry) {
|
|
611
|
+
const sibs = crListReplica.childrenMap.get(displacedEntry.predecessor);
|
|
612
|
+
if (sibs) sibs.push(displacedEntry);
|
|
613
|
+
else
|
|
614
|
+
crListReplica.childrenMap.set(displacedEntry.predecessor, [
|
|
615
|
+
displacedEntry
|
|
616
|
+
]);
|
|
617
|
+
delta.values?.push({
|
|
618
|
+
uuidv7: displacedEntry.uuidv7,
|
|
619
|
+
value: displacedEntry.value,
|
|
620
|
+
predecessor: displacedEntry.predecessor
|
|
621
|
+
});
|
|
622
|
+
}
|
|
536
623
|
return { change, delta };
|
|
537
624
|
}
|
|
538
625
|
|
|
@@ -645,7 +732,7 @@ function __merge(crListReplica, crListDelta) {
|
|
|
645
732
|
}
|
|
646
733
|
}
|
|
647
734
|
}
|
|
648
|
-
if (!Object.hasOwn(crListDelta, "values") || !Array.isArray(crListDelta.values)) {
|
|
735
|
+
if (!Object.hasOwn(crListDelta, "values") || !Array.isArray(crListDelta.values) || crListDelta.values.length === 0 && tailTombstoneMovedCursor) {
|
|
649
736
|
if (newTombsIndices.length === 0) return false;
|
|
650
737
|
if (newTombsIndices.length === 1 && tailTombstoneMovedCursor) {
|
|
651
738
|
if (crListReplica.cursor) {
|
|
@@ -714,7 +801,12 @@ function __merge(crListReplica, crListDelta) {
|
|
|
714
801
|
}
|
|
715
802
|
}
|
|
716
803
|
if (needsRelink) {
|
|
717
|
-
if (!
|
|
804
|
+
if (!trySpliceSiblingInsert(
|
|
805
|
+
crListReplica,
|
|
806
|
+
newVals,
|
|
807
|
+
reparentedVals,
|
|
808
|
+
newTombsIndices.length
|
|
809
|
+
) && !trySpliceInsertedParent(crListReplica, newVals, reparentedVals) && !trySpliceReplacement(
|
|
718
810
|
crListReplica,
|
|
719
811
|
newVals,
|
|
720
812
|
reparentedVals,
|
|
@@ -868,32 +960,32 @@ var CRList = class {
|
|
|
868
960
|
return this.state.size;
|
|
869
961
|
}
|
|
870
962
|
/**
|
|
871
|
-
* Inserts
|
|
963
|
+
* Inserts values before an index.
|
|
872
964
|
*
|
|
873
|
-
* If `beforeIndex` is omitted,
|
|
965
|
+
* If `beforeIndex` is omitted, values are inserted at the start of the list.
|
|
874
966
|
*
|
|
875
|
-
* @param
|
|
967
|
+
* @param values - Values to insert.
|
|
876
968
|
* @param beforeIndex - The index to insert before.
|
|
877
969
|
*/
|
|
878
|
-
prepend(
|
|
879
|
-
const result = __update(beforeIndex ?? 0,
|
|
970
|
+
prepend(values, beforeIndex) {
|
|
971
|
+
const result = __update(beforeIndex ?? 0, values, this.state, "before");
|
|
880
972
|
if (!result) return;
|
|
881
973
|
const { delta, change } = result;
|
|
882
974
|
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
883
975
|
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
884
976
|
}
|
|
885
977
|
/**
|
|
886
|
-
* Inserts
|
|
978
|
+
* Inserts values after an index.
|
|
887
979
|
*
|
|
888
|
-
* If `afterIndex` is omitted,
|
|
980
|
+
* If `afterIndex` is omitted, values are appended at the end of the list.
|
|
889
981
|
*
|
|
890
|
-
* @param
|
|
982
|
+
* @param values - Values to insert.
|
|
891
983
|
* @param afterIndex - The index to insert after.
|
|
892
984
|
*/
|
|
893
|
-
append(
|
|
985
|
+
append(values, afterIndex) {
|
|
894
986
|
const result = __update(
|
|
895
987
|
afterIndex ?? this.state.size,
|
|
896
|
-
|
|
988
|
+
values,
|
|
897
989
|
this.state,
|
|
898
990
|
"after"
|
|
899
991
|
);
|
|
@@ -903,12 +995,26 @@ var CRList = class {
|
|
|
903
995
|
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
904
996
|
}
|
|
905
997
|
/**
|
|
906
|
-
*
|
|
998
|
+
* Overwrites entries starting at an index.
|
|
999
|
+
*
|
|
1000
|
+
* @param index - The index to start overwriting at.
|
|
1001
|
+
* @param values - Values to write.
|
|
1002
|
+
*/
|
|
1003
|
+
update(index, values) {
|
|
1004
|
+
const result = __update(index, values, this.state, "overwrite");
|
|
1005
|
+
if (!result) return;
|
|
1006
|
+
const { delta, change } = result;
|
|
1007
|
+
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
1008
|
+
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Removes one or more entries starting at an index.
|
|
907
1012
|
*
|
|
908
|
-
* @param index - The index to remove.
|
|
1013
|
+
* @param index - The first index to remove.
|
|
1014
|
+
* @param count - Number of entries to remove. Defaults to `1`.
|
|
909
1015
|
*/
|
|
910
|
-
remove(index) {
|
|
911
|
-
const result = __delete(this.state, index, index +
|
|
1016
|
+
remove(index, count = 1) {
|
|
1017
|
+
const result = __delete(this.state, index, index + count);
|
|
912
1018
|
if (!result) return;
|
|
913
1019
|
const { delta, change } = result;
|
|
914
1020
|
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|