@sovereignbase/convergent-replicated-list 1.3.2 → 1.3.4

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 CHANGED
@@ -237,10 +237,10 @@ function moveEntryToPredecessor(crListReplica, linkedListEntry, predecessor, del
237
237
 
238
238
  // src/.helpers/indexFromPropertyKey/index.ts
239
239
  function indexFromPropertyKey(index) {
240
- if (typeof index !== "string" || !/^(0|[1-9]\d*)$/.test(index))
241
- return void 0;
240
+ if (typeof index !== "string") return void 0;
242
241
  const listIndex = Number(index);
243
- return Number.isSafeInteger(listIndex) ? listIndex : void 0;
242
+ if (!Number.isSafeInteger(listIndex) || listIndex < 0) return void 0;
243
+ return String(listIndex) === index ? listIndex : void 0;
244
244
  }
245
245
 
246
246
  // src/.helpers/trySpliceInsertedParent/index.ts
@@ -276,6 +276,42 @@ function trySpliceInsertedParent(crListReplica, insertedEntries, reparentedEntri
276
276
  return true;
277
277
  }
278
278
 
279
+ // src/.helpers/trySpliceReplacement/index.ts
280
+ function trySpliceReplacement(crListReplica, insertedEntries, reparentedEntries, tombstoneCount) {
281
+ if (tombstoneCount === 0 || insertedEntries.length !== 1 || reparentedEntries.length > 1)
282
+ return false;
283
+ const inserted = insertedEntries[0];
284
+ const predecessor = inserted.predecessor === "\0" ? void 0 : crListReplica.parentMap.get(inserted.predecessor);
285
+ if (inserted.predecessor !== "\0" && !predecessor) return false;
286
+ const siblings = crListReplica.childrenMap.get(inserted.predecessor);
287
+ if (_optionalChain([siblings, 'optionalAccess', _20 => _20.length]) !== 1 || siblings[0] !== inserted) return false;
288
+ const reparented = reparentedEntries[0];
289
+ const next = _optionalChain([reparented, 'optionalAccess', _21 => _21.entry]);
290
+ if (next) {
291
+ const children = crListReplica.childrenMap.get(inserted.uuidv7);
292
+ if (next.predecessor !== inserted.uuidv7 || !crListReplica.tombstones.has(reparented.previousPredecessor) || _optionalChain([children, 'optionalAccess', _22 => _22.length]) !== 1 || children[0] !== next || next.prev !== predecessor)
293
+ return false;
294
+ } else if (_optionalChain([crListReplica, 'access', _23 => _23.childrenMap, 'access', _24 => _24.get, 'call', _25 => _25(inserted.uuidv7), 'optionalAccess', _26 => _26.length])) {
295
+ return false;
296
+ }
297
+ if (_optionalChain([predecessor, 'optionalAccess', _27 => _27.next]) !== next) return false;
298
+ if (!predecessor && crListReplica.cursor !== next) return false;
299
+ const expectedIndex = predecessor ? predecessor.index + 1 : 0;
300
+ void linkEntryBetween(predecessor, inserted, next);
301
+ let current = inserted;
302
+ let index = expectedIndex;
303
+ while (current) {
304
+ current.index = index;
305
+ index++;
306
+ current = current.next;
307
+ }
308
+ crListReplica.index = /* @__PURE__ */ new Map([[inserted.index, inserted]]);
309
+ crListReplica.cursor = inserted;
310
+ crListReplica.cursorIndex = inserted.index;
311
+ crListReplica.size = crListReplica.parentMap.size;
312
+ return true;
313
+ }
314
+
279
315
  // src/core/crud/create/index.ts
280
316
 
281
317
  function __create(snapshot) {
@@ -307,11 +343,11 @@ function __create(snapshot) {
307
343
  );
308
344
  if (!linkedListEntry) continue;
309
345
  void attachEntryToIndexes(crListReplica, linkedListEntry);
310
- if (canUseLinearProjection && linkedListEntry.predecessor === (_nullishCoalesce(_optionalChain([previous, 'optionalAccess', _20 => _20.uuidv7]), () => ( "\0")))) {
346
+ if (canUseLinearProjection && linkedListEntry.predecessor === (_nullishCoalesce(_optionalChain([previous, 'optionalAccess', _28 => _28.uuidv7]), () => ( "\0")))) {
311
347
  linkedListEntry.index = crListReplica.parentMap.size - 1;
312
348
  void linkEntryBetween(previous, linkedListEntry, void 0);
313
349
  previous = linkedListEntry;
314
- void _optionalChain([crListReplica, 'access', _21 => _21.index, 'optionalAccess', _22 => _22.set, 'call', _23 => _23(linkedListEntry.index, linkedListEntry)]);
350
+ void _optionalChain([crListReplica, 'access', _29 => _29.index, 'optionalAccess', _30 => _30.set, 'call', _31 => _31(linkedListEntry.index, linkedListEntry)]);
315
351
  continue;
316
352
  }
317
353
  canUseLinearProjection = false;
@@ -330,7 +366,7 @@ function __create(snapshot) {
330
366
  function __read(targetIndex, crListReplica) {
331
367
  try {
332
368
  void seekCursorToIndex(targetIndex, crListReplica);
333
- return _optionalChain([crListReplica, 'access', _24 => _24.cursor, 'optionalAccess', _25 => _25.value]);
369
+ return _optionalChain([crListReplica, 'access', _32 => _32.cursor, 'optionalAccess', _33 => _33.value]);
334
370
  } catch (e) {
335
371
  return void 0;
336
372
  }
@@ -366,7 +402,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
366
402
  crListReplica.cursor = linkedListEntry;
367
403
  crListReplica.cursorIndex = linkedListEntry.index;
368
404
  void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
369
- _optionalChain([crListReplica, 'access', _26 => _26.index, 'optionalAccess', _27 => _27.set, 'call', _28 => _28(linkedListEntry.index, linkedListEntry)]);
405
+ _optionalChain([crListReplica, 'access', _34 => _34.index, 'optionalAccess', _35 => _35.set, 'call', _36 => _36(linkedListEntry.index, linkedListEntry)]);
370
406
  change[linkedListEntry.index] = linkedListEntry.value;
371
407
  break;
372
408
  }
@@ -382,7 +418,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
382
418
  void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
383
419
  crListReplica.cursor = linkedListEntry;
384
420
  crListReplica.cursorIndex = linkedListEntry.index;
385
- void _optionalChain([crListReplica, 'access', _29 => _29.index, 'optionalAccess', _30 => _30.set, 'call', _31 => _31(linkedListEntry.index, linkedListEntry)]);
421
+ void _optionalChain([crListReplica, 'access', _37 => _37.index, 'optionalAccess', _38 => _38.set, 'call', _39 => _39(linkedListEntry.index, linkedListEntry)]);
386
422
  change[linkedListEntry.index] = linkedListEntry.value;
387
423
  break;
388
424
  }
@@ -409,13 +445,13 @@ function __update(listIndex, listValues, crListReplica, mode) {
409
445
  }
410
446
  void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
411
447
  void crListReplica.tombstones.add(entryToOverwrite.uuidv7);
412
- void _optionalChain([delta, 'access', _32 => _32.tombstones, 'optionalAccess', _33 => _33.push, 'call', _34 => _34(entryToOverwrite.uuidv7)]);
448
+ void _optionalChain([delta, 'access', _40 => _40.tombstones, 'optionalAccess', _41 => _41.push, 'call', _42 => _42(entryToOverwrite.uuidv7)]);
413
449
  void detachEntryFromIndexes(crListReplica, entryToOverwrite);
414
450
  entryToOverwrite.next = void 0;
415
451
  entryToOverwrite.prev = void 0;
416
452
  crListReplica.cursor = linkedListEntry;
417
453
  crListReplica.cursorIndex = actualIndex;
418
- void _optionalChain([crListReplica, 'access', _35 => _35.index, 'optionalAccess', _36 => _36.set, 'call', _37 => _37(linkedListEntry.index, linkedListEntry)]);
454
+ void _optionalChain([crListReplica, 'access', _43 => _43.index, 'optionalAccess', _44 => _44.set, 'call', _45 => _45(linkedListEntry.index, linkedListEntry)]);
419
455
  change[actualIndex] = linkedListEntry.value;
420
456
  break;
421
457
  }
@@ -424,7 +460,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
424
460
  crListReplica.cursor = linkedListEntry;
425
461
  crListReplica.cursorIndex = linkedListEntry.index;
426
462
  void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
427
- void _optionalChain([crListReplica, 'access', _38 => _38.index, 'optionalAccess', _39 => _39.set, 'call', _40 => _40(linkedListEntry.index, linkedListEntry)]);
463
+ void _optionalChain([crListReplica, 'access', _46 => _46.index, 'optionalAccess', _47 => _47.set, 'call', _48 => _48(linkedListEntry.index, linkedListEntry)]);
428
464
  change[linkedListEntry.index] = linkedListEntry.value;
429
465
  break;
430
466
  }
@@ -453,7 +489,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
453
489
  crListReplica.cursor = linkedListEntry;
454
490
  crListReplica.cursorIndex = linkedListEntry.index;
455
491
  if (next) crListReplica.index = /* @__PURE__ */ new Map();
456
- void _optionalChain([crListReplica, 'access', _41 => _41.index, 'optionalAccess', _42 => _42.set, 'call', _43 => _43(linkedListEntry.index, linkedListEntry)]);
492
+ void _optionalChain([crListReplica, 'access', _49 => _49.index, 'optionalAccess', _50 => _50.set, 'call', _51 => _51(linkedListEntry.index, linkedListEntry)]);
457
493
  change[linkedListEntry.index] = linkedListEntry.value;
458
494
  break;
459
495
  }
@@ -462,7 +498,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
462
498
  crListReplica.cursor = linkedListEntry;
463
499
  crListReplica.cursorIndex = linkedListEntry.index;
464
500
  void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
465
- void _optionalChain([crListReplica, 'access', _44 => _44.index, 'optionalAccess', _45 => _45.set, 'call', _46 => _46(linkedListEntry.index, linkedListEntry)]);
501
+ void _optionalChain([crListReplica, 'access', _52 => _52.index, 'optionalAccess', _53 => _53.set, 'call', _54 => _54(linkedListEntry.index, linkedListEntry)]);
466
502
  change[linkedListEntry.index] = linkedListEntry.value;
467
503
  mode = "after";
468
504
  listIndex = linkedListEntry.index - 1;
@@ -473,7 +509,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
473
509
  const actualIndex = _nullishCoalesce(crListReplica.cursorIndex, () => ( listIndex));
474
510
  const prev = crListReplica.cursor.prev;
475
511
  linkedListEntry.index = actualIndex;
476
- linkedListEntry.predecessor = _nullishCoalesce(_optionalChain([prev, 'optionalAccess', _47 => _47.uuidv7]), () => ( "\0"));
512
+ linkedListEntry.predecessor = _nullishCoalesce(_optionalChain([prev, 'optionalAccess', _55 => _55.uuidv7]), () => ( "\0"));
477
513
  void linkEntryBetween(prev, linkedListEntry, crListReplica.cursor);
478
514
  if (crListReplica.cursor.predecessor === linkedListEntry.predecessor) {
479
515
  void moveEntryToPredecessor(
@@ -487,7 +523,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
487
523
  crListReplica.cursor = linkedListEntry;
488
524
  crListReplica.cursorIndex = actualIndex;
489
525
  crListReplica.index = /* @__PURE__ */ new Map();
490
- void _optionalChain([crListReplica, 'access', _48 => _48.index, 'optionalAccess', _49 => _49.set, 'call', _50 => _50(linkedListEntry.index, linkedListEntry)]);
526
+ void _optionalChain([crListReplica, 'access', _56 => _56.index, 'optionalAccess', _57 => _57.set, 'call', _58 => _58(linkedListEntry.index, linkedListEntry)]);
491
527
  change[actualIndex] = linkedListEntry.value;
492
528
  mode = "after";
493
529
  listIndex = linkedListEntry.index - 1;
@@ -501,6 +537,7 @@ function __update(listIndex, listValues, crListReplica, mode) {
501
537
  }
502
538
 
503
539
  // src/core/crud/delete/index.ts
540
+
504
541
  function __delete(crListReplica, startIndex, endIndex) {
505
542
  const change = {};
506
543
  const delta = { values: [], tombstones: [] };
@@ -513,17 +550,43 @@ function __delete(crListReplica, startIndex, endIndex) {
513
550
  void seekCursorToIndex(listIndex, crListReplica);
514
551
  if (!crListReplica.cursor) return false;
515
552
  let current = crListReplica.cursor;
553
+ const predecessor = _nullishCoalesce(_optionalChain([current, 'access', _59 => _59.prev, 'optionalAccess', _60 => _60.uuidv7]), () => ( "\0"));
554
+ const deletedIds = /* @__PURE__ */ new Set();
516
555
  let deleted = 0;
517
556
  let currentIndex = _nullishCoalesce(crListReplica.cursorIndex, () => ( listIndex));
518
557
  while (current && deleted < deleteCount) {
519
558
  const next = current.next;
520
559
  change[currentIndex] = void 0;
521
- void _optionalChain([crListReplica, 'access', _51 => _51.index, 'optionalAccess', _52 => _52.delete, 'call', _53 => _53(currentIndex)]);
560
+ void deletedIds.add(current.uuidv7);
561
+ void _optionalChain([crListReplica, 'access', _61 => _61.index, 'optionalAccess', _62 => _62.delete, 'call', _63 => _63(currentIndex)]);
522
562
  void deleteLiveEntry(crListReplica, current, delta);
523
563
  current = next;
524
564
  currentIndex++;
525
565
  deleted++;
526
566
  }
567
+ if (current && deletedIds.has(current.predecessor)) {
568
+ const replacement = {
569
+ uuidv7: _uuid.v7.call(void 0, ),
570
+ value: current.value,
571
+ predecessor,
572
+ index: listIndex,
573
+ next: void 0,
574
+ prev: void 0
575
+ };
576
+ const prev = current.prev;
577
+ const next = current.next;
578
+ void deleteLiveEntry(crListReplica, current, delta);
579
+ void linkEntryBetween(prev, replacement, next);
580
+ void attachEntryToIndexes(crListReplica, replacement, delta);
581
+ if (_optionalChain([next, 'optionalAccess', _64 => _64.predecessor]) === current.uuidv7)
582
+ void moveEntryToPredecessor(
583
+ crListReplica,
584
+ next,
585
+ replacement.uuidv7,
586
+ delta
587
+ );
588
+ current = replacement;
589
+ }
527
590
  crListReplica.size = crListReplica.parentMap.size;
528
591
  crListReplica.cursor = _nullishCoalesce(current, () => ( crListReplica.cursor));
529
592
  crListReplica.cursorIndex = current ? listIndex : crListReplica.cursor ? Math.max(0, crListReplica.size - 1) : void 0;
@@ -544,6 +607,7 @@ function __merge(crListReplica, crListDelta) {
544
607
  const newTombsIndices = [];
545
608
  const reparentedVals = [];
546
609
  const change = {};
610
+ let tailTombstoneMovedCursor = false;
547
611
  let needsRelink = false;
548
612
  if (Object.hasOwn(crListDelta, "values") && Array.isArray(crListDelta.values) && crListDelta.values.length === 1 && (!Object.hasOwn(crListDelta, "tombstones") || Array.isArray(crListDelta.tombstones) && crListDelta.tombstones.length === 0)) {
549
613
  const linkedListEntry = materializeSnapshotEntry(
@@ -560,7 +624,7 @@ function __merge(crListReplica, crListDelta) {
560
624
  crListReplica.cursorIndex = linkedListEntry.index;
561
625
  void attachEntryToIndexes(crListReplica, linkedListEntry);
562
626
  crListReplica.size = crListReplica.parentMap.size;
563
- void _optionalChain([crListReplica, 'access', _54 => _54.index, 'optionalAccess', _55 => _55.set, 'call', _56 => _56(linkedListEntry.index, linkedListEntry)]);
627
+ void _optionalChain([crListReplica, 'access', _65 => _65.index, 'optionalAccess', _66 => _66.set, 'call', _67 => _67(linkedListEntry.index, linkedListEntry)]);
564
628
  return { [linkedListEntry.index]: linkedListEntry.value };
565
629
  }
566
630
  }
@@ -571,15 +635,31 @@ function __merge(crListReplica, crListDelta) {
571
635
  void crListReplica.tombstones.add(tombstone);
572
636
  const linkedListEntry = crListReplica.parentMap.get(tombstone);
573
637
  if (linkedListEntry) {
638
+ const wasTail = linkedListEntry.next === void 0;
639
+ const wasCursor = crListReplica.cursor === linkedListEntry;
574
640
  void newTombsIndices.push(linkedListEntry.index);
575
- void _optionalChain([crListReplica, 'access', _57 => _57.index, 'optionalAccess', _58 => _58.delete, 'call', _59 => _59(linkedListEntry.index)]);
641
+ void _optionalChain([crListReplica, 'access', _68 => _68.index, 'optionalAccess', _69 => _69.delete, 'call', _70 => _70(linkedListEntry.index)]);
576
642
  void deleteLiveEntry(crListReplica, linkedListEntry);
643
+ tailTombstoneMovedCursor = wasTail && wasCursor;
577
644
  needsRelink = true;
578
645
  }
579
646
  }
580
647
  }
581
648
  if (!Object.hasOwn(crListDelta, "values") || !Array.isArray(crListDelta.values)) {
582
649
  if (newTombsIndices.length === 0) return false;
650
+ if (newTombsIndices.length === 1 && tailTombstoneMovedCursor) {
651
+ if (crListReplica.cursor) {
652
+ crListReplica.cursorIndex = crListReplica.size - 1;
653
+ void _optionalChain([crListReplica, 'access', _71 => _71.index, 'optionalAccess', _72 => _72.set, 'call', _73 => _73(
654
+ crListReplica.cursorIndex,
655
+ crListReplica.cursor
656
+ )]);
657
+ } else {
658
+ crListReplica.cursorIndex = void 0;
659
+ }
660
+ change[newTombsIndices[0]] = void 0;
661
+ return change;
662
+ }
583
663
  void rebuildLiveIndex(crListReplica);
584
664
  for (const index of newTombsIndices) {
585
665
  change[index] = void 0;
@@ -617,7 +697,7 @@ function __merge(crListReplica, crListDelta) {
617
697
  crListReplica.cursor = linkedListEntry;
618
698
  crListReplica.cursorIndex = linkedListEntry.index;
619
699
  crListReplica.size = crListReplica.parentMap.size;
620
- void _optionalChain([crListReplica, 'access', _60 => _60.index, 'optionalAccess', _61 => _61.set, 'call', _62 => _62(linkedListEntry.index, linkedListEntry)]);
700
+ void _optionalChain([crListReplica, 'access', _74 => _74.index, 'optionalAccess', _75 => _75.set, 'call', _76 => _76(linkedListEntry.index, linkedListEntry)]);
621
701
  } else {
622
702
  needsRelink = true;
623
703
  }
@@ -628,13 +708,18 @@ function __merge(crListReplica, crListDelta) {
628
708
  crListReplica.cursor = linkedListEntry;
629
709
  crListReplica.cursorIndex = linkedListEntry.index;
630
710
  crListReplica.size = crListReplica.parentMap.size;
631
- void _optionalChain([crListReplica, 'access', _63 => _63.index, 'optionalAccess', _64 => _64.set, 'call', _65 => _65(linkedListEntry.index, linkedListEntry)]);
711
+ void _optionalChain([crListReplica, 'access', _77 => _77.index, 'optionalAccess', _78 => _78.set, 'call', _79 => _79(linkedListEntry.index, linkedListEntry)]);
632
712
  } else {
633
713
  needsRelink = true;
634
714
  }
635
715
  }
636
716
  if (needsRelink) {
637
- if (!trySpliceInsertedParent(crListReplica, newVals, reparentedVals)) {
717
+ if (!trySpliceInsertedParent(crListReplica, newVals, reparentedVals) && !trySpliceReplacement(
718
+ crListReplica,
719
+ newVals,
720
+ reparentedVals,
721
+ newTombsIndices.length
722
+ )) {
638
723
  void rebuildLiveProjection(crListReplica);
639
724
  }
640
725
  }
@@ -839,8 +924,8 @@ var CRList = class {
839
924
  * @param thisArg - Optional `this` value for the predicate.
840
925
  */
841
926
  find(predicate, thisArg) {
842
- let linkedListEntry = _nullishCoalesce(_optionalChain([this, 'access', _66 => _66.state, 'access', _67 => _67.index, 'optionalAccess', _68 => _68.get, 'call', _69 => _69(0)]), () => ( this.state.cursor));
843
- while (_optionalChain([linkedListEntry, 'optionalAccess', _70 => _70.prev])) linkedListEntry = linkedListEntry.prev;
927
+ let linkedListEntry = _nullishCoalesce(_optionalChain([this, 'access', _80 => _80.state, 'access', _81 => _81.index, 'optionalAccess', _82 => _82.get, 'call', _83 => _83(0)]), () => ( this.state.cursor));
928
+ while (_optionalChain([linkedListEntry, 'optionalAccess', _84 => _84.prev])) linkedListEntry = linkedListEntry.prev;
844
929
  let index = 0;
845
930
  while (linkedListEntry) {
846
931
  if (predicate.call(thisArg, linkedListEntry.value, index, this))
@@ -950,9 +1035,11 @@ var CRList = class {
950
1035
  * Iterates over current live values in index order.
951
1036
  */
952
1037
  *[Symbol.iterator]() {
953
- for (let index = 0; index < this.size; index++) {
954
- const value = this[index];
955
- yield value;
1038
+ let linkedListEntry = _nullishCoalesce(_optionalChain([this, 'access', _85 => _85.state, 'access', _86 => _86.index, 'optionalAccess', _87 => _87.get, 'call', _88 => _88(0)]), () => ( this.state.cursor));
1039
+ while (_optionalChain([linkedListEntry, 'optionalAccess', _89 => _89.prev])) linkedListEntry = linkedListEntry.prev;
1040
+ while (linkedListEntry) {
1041
+ yield linkedListEntry.value;
1042
+ linkedListEntry = linkedListEntry.next;
956
1043
  }
957
1044
  }
958
1045
  /**
@@ -965,8 +1052,13 @@ var CRList = class {
965
1052
  * @param thisArg - Optional `this` value for the callback.
966
1053
  */
967
1054
  forEach(callback, thisArg) {
968
- for (let index = 0; index < this.size; index++) {
969
- void callback.call(thisArg, this[index], index, this);
1055
+ let linkedListEntry = _nullishCoalesce(_optionalChain([this, 'access', _90 => _90.state, 'access', _91 => _91.index, 'optionalAccess', _92 => _92.get, 'call', _93 => _93(0)]), () => ( this.state.cursor));
1056
+ while (_optionalChain([linkedListEntry, 'optionalAccess', _94 => _94.prev])) linkedListEntry = linkedListEntry.prev;
1057
+ let index = 0;
1058
+ while (linkedListEntry) {
1059
+ void callback.call(thisArg, linkedListEntry.value, index, this);
1060
+ linkedListEntry = linkedListEntry.next;
1061
+ index++;
970
1062
  }
971
1063
  }
972
1064
  };