@fluidframework/merge-tree 2.41.0 → 2.43.0-343119

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.
Files changed (154) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/client.d.ts +9 -6
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +79 -36
  5. package/dist/client.js.map +1 -1
  6. package/dist/collections/list.d.ts +95 -5
  7. package/dist/collections/list.d.ts.map +1 -1
  8. package/dist/collections/list.js +67 -5
  9. package/dist/collections/list.js.map +1 -1
  10. package/dist/constants.d.ts +5 -0
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +6 -1
  13. package/dist/constants.js.map +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/mergeTree.d.ts +9 -9
  19. package/dist/mergeTree.d.ts.map +1 -1
  20. package/dist/mergeTree.js +15 -7
  21. package/dist/mergeTree.js.map +1 -1
  22. package/dist/perspective.d.ts +15 -0
  23. package/dist/perspective.d.ts.map +1 -1
  24. package/dist/perspective.js +25 -1
  25. package/dist/perspective.js.map +1 -1
  26. package/dist/revertibles.js +1 -1
  27. package/dist/revertibles.js.map +1 -1
  28. package/dist/stamps.d.ts +1 -0
  29. package/dist/stamps.d.ts.map +1 -1
  30. package/dist/stamps.js +5 -1
  31. package/dist/stamps.js.map +1 -1
  32. package/dist/test/beastTest.spec.js +1 -1
  33. package/dist/test/beastTest.spec.js.map +1 -1
  34. package/dist/test/client.annotateMarker.spec.js +1 -1
  35. package/dist/test/client.annotateMarker.spec.js.map +1 -1
  36. package/dist/test/client.applyMsg.spec.js +25 -25
  37. package/dist/test/client.applyMsg.spec.js.map +1 -1
  38. package/dist/test/client.applyStashedOpFarm.spec.d.ts.map +1 -1
  39. package/dist/test/client.applyStashedOpFarm.spec.js +3 -3
  40. package/dist/test/client.applyStashedOpFarm.spec.js.map +1 -1
  41. package/dist/test/client.attributionFarm.spec.js +1 -1
  42. package/dist/test/client.attributionFarm.spec.js.map +1 -1
  43. package/dist/test/client.getPosition.spec.js +1 -0
  44. package/dist/test/client.getPosition.spec.js.map +1 -1
  45. package/dist/test/client.localReference.spec.js +62 -48
  46. package/dist/test/client.localReference.spec.js.map +1 -1
  47. package/dist/test/client.localReferenceFarm.spec.js +1 -0
  48. package/dist/test/client.localReferenceFarm.spec.js.map +1 -1
  49. package/dist/test/client.reconnectFarm.spec.js +1 -1
  50. package/dist/test/client.reconnectFarm.spec.js.map +1 -1
  51. package/dist/test/client.rollback.spec.js +8 -6
  52. package/dist/test/client.rollback.spec.js.map +1 -1
  53. package/dist/test/client.searchForMarker.spec.js +2 -2
  54. package/dist/test/client.searchForMarker.spec.js.map +1 -1
  55. package/dist/test/clientTestHelper.js +1 -1
  56. package/dist/test/clientTestHelper.js.map +1 -1
  57. package/dist/test/mergeTree.annotate.spec.js +25 -25
  58. package/dist/test/mergeTree.annotate.spec.js.map +1 -1
  59. package/dist/test/mergeTree.markRangeRemoved.spec.js +1 -1
  60. package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  61. package/dist/test/obliterate.spec.js +4 -4
  62. package/dist/test/obliterate.spec.js.map +1 -1
  63. package/dist/test/resetPendingSegmentsToOp.spec.js +14 -14
  64. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  65. package/dist/test/snapshot.utils.js +1 -1
  66. package/dist/test/snapshot.utils.js.map +1 -1
  67. package/dist/test/sortedSegmentSet.spec.js +3 -3
  68. package/dist/test/sortedSegmentSet.spec.js.map +1 -1
  69. package/dist/test/testClient.js +3 -3
  70. package/dist/test/testClient.js.map +1 -1
  71. package/dist/test/tracking.spec.js +7 -7
  72. package/dist/test/tracking.spec.js.map +1 -1
  73. package/dist/test/wordUnitTests.spec.js.map +1 -1
  74. package/lib/client.d.ts +9 -6
  75. package/lib/client.d.ts.map +1 -1
  76. package/lib/client.js +81 -38
  77. package/lib/client.js.map +1 -1
  78. package/lib/collections/list.d.ts +95 -5
  79. package/lib/collections/list.d.ts.map +1 -1
  80. package/lib/collections/list.js +67 -5
  81. package/lib/collections/list.js.map +1 -1
  82. package/lib/constants.d.ts +5 -0
  83. package/lib/constants.d.ts.map +1 -1
  84. package/lib/constants.js +5 -0
  85. package/lib/constants.js.map +1 -1
  86. package/lib/index.d.ts +1 -1
  87. package/lib/index.d.ts.map +1 -1
  88. package/lib/index.js +1 -1
  89. package/lib/index.js.map +1 -1
  90. package/lib/mergeTree.d.ts +9 -9
  91. package/lib/mergeTree.d.ts.map +1 -1
  92. package/lib/mergeTree.js +15 -7
  93. package/lib/mergeTree.js.map +1 -1
  94. package/lib/perspective.d.ts +15 -0
  95. package/lib/perspective.d.ts.map +1 -1
  96. package/lib/perspective.js +23 -0
  97. package/lib/perspective.js.map +1 -1
  98. package/lib/revertibles.js +1 -1
  99. package/lib/revertibles.js.map +1 -1
  100. package/lib/stamps.d.ts +1 -0
  101. package/lib/stamps.d.ts.map +1 -1
  102. package/lib/stamps.js +4 -1
  103. package/lib/stamps.js.map +1 -1
  104. package/lib/test/beastTest.spec.js +1 -1
  105. package/lib/test/beastTest.spec.js.map +1 -1
  106. package/lib/test/client.annotateMarker.spec.js +1 -1
  107. package/lib/test/client.annotateMarker.spec.js.map +1 -1
  108. package/lib/test/client.applyMsg.spec.js +25 -25
  109. package/lib/test/client.applyMsg.spec.js.map +1 -1
  110. package/lib/test/client.applyStashedOpFarm.spec.d.ts.map +1 -1
  111. package/lib/test/client.applyStashedOpFarm.spec.js +3 -3
  112. package/lib/test/client.applyStashedOpFarm.spec.js.map +1 -1
  113. package/lib/test/client.attributionFarm.spec.js +1 -1
  114. package/lib/test/client.attributionFarm.spec.js.map +1 -1
  115. package/lib/test/client.getPosition.spec.js +1 -0
  116. package/lib/test/client.getPosition.spec.js.map +1 -1
  117. package/lib/test/client.localReference.spec.js +62 -48
  118. package/lib/test/client.localReference.spec.js.map +1 -1
  119. package/lib/test/client.localReferenceFarm.spec.js +1 -0
  120. package/lib/test/client.localReferenceFarm.spec.js.map +1 -1
  121. package/lib/test/client.reconnectFarm.spec.js +1 -1
  122. package/lib/test/client.reconnectFarm.spec.js.map +1 -1
  123. package/lib/test/client.rollback.spec.js +8 -6
  124. package/lib/test/client.rollback.spec.js.map +1 -1
  125. package/lib/test/client.searchForMarker.spec.js +2 -2
  126. package/lib/test/client.searchForMarker.spec.js.map +1 -1
  127. package/lib/test/clientTestHelper.js +1 -1
  128. package/lib/test/clientTestHelper.js.map +1 -1
  129. package/lib/test/mergeTree.annotate.spec.js +25 -25
  130. package/lib/test/mergeTree.annotate.spec.js.map +1 -1
  131. package/lib/test/mergeTree.markRangeRemoved.spec.js +1 -1
  132. package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  133. package/lib/test/obliterate.spec.js +4 -4
  134. package/lib/test/obliterate.spec.js.map +1 -1
  135. package/lib/test/resetPendingSegmentsToOp.spec.js +14 -14
  136. package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  137. package/lib/test/snapshot.utils.js +1 -1
  138. package/lib/test/snapshot.utils.js.map +1 -1
  139. package/lib/test/sortedSegmentSet.spec.js +3 -3
  140. package/lib/test/sortedSegmentSet.spec.js.map +1 -1
  141. package/lib/test/testClient.js +3 -3
  142. package/lib/test/testClient.js.map +1 -1
  143. package/lib/test/tracking.spec.js +7 -7
  144. package/lib/test/tracking.spec.js.map +1 -1
  145. package/lib/test/wordUnitTests.spec.js.map +1 -1
  146. package/package.json +16 -16
  147. package/src/client.ts +117 -50
  148. package/src/collections/list.ts +101 -5
  149. package/src/constants.ts +6 -0
  150. package/src/index.ts +3 -0
  151. package/src/mergeTree.ts +30 -24
  152. package/src/perspective.ts +26 -0
  153. package/src/revertibles.ts +1 -1
  154. package/src/stamps.ts +9 -1
package/lib/client.js CHANGED
@@ -10,14 +10,14 @@ import { toDeltaManagerInternal } from "@fluidframework/runtime-utils/internal";
10
10
  import { LoggingError, UsageError, } from "@fluidframework/telemetry-utils/internal";
11
11
  import { MergeTreeTextHelper } from "./MergeTreeTextHelper.js";
12
12
  import { RedBlackTree } from "./collections/index.js";
13
- import { NonCollabClient, UniversalSequenceNumber } from "./constants.js";
13
+ import { NonCollabClient, SquashClient, UniversalSequenceNumber } from "./constants.js";
14
14
  import { SlidingPreference } from "./localReference.js";
15
15
  import { MergeTree, errorIfOptionNotTrue, getSlideToSegoff, isRemovedAndAcked, } from "./mergeTree.js";
16
16
  import { walkAllChildSegments } from "./mergeTreeNodeWalk.js";
17
17
  import { compareStrings, isSegmentLeaf, } from "./mergeTreeNodes.js";
18
18
  import { createAdjustRangeOp, createAnnotateMarkerOp, createAnnotateRangeOp, createGroupOp, createInsertSegmentOp, createObliterateRangeOp, createObliterateRangeOpSided, createRemoveRangeOp, } from "./opBuilder.js";
19
19
  import { MergeTreeDeltaType, ReferenceType, } from "./ops.js";
20
- import { LocalReconnectingPerspective, PriorPerspective, } from "./perspective.js";
20
+ import { LocalReconnectingPerspective, LocalSquashPerspective, PriorPerspective, } from "./perspective.js";
21
21
  import { DetachedReferencePosition } from "./referencePositions.js";
22
22
  import { isInserted, isRemoved, overwriteInfo, toRemovalInfo, } from "./segmentInfos.js";
23
23
  import { Side } from "./sequencePlace.js";
@@ -186,8 +186,10 @@ export class Client extends TypedEventEmitter {
186
186
  }
187
187
  return this.insertSegmentLocal(pos, segment);
188
188
  }
189
- walkSegments(handler, start, end, accum, splitRange = false) {
190
- this._mergeTree.mapRange(handler, this._mergeTree.localPerspective, accum, start, end, splitRange);
189
+ walkSegments(handler, start, end, accum, splitRange = false, perspective) {
190
+ this._mergeTree.mapRange(handler, perspective === undefined
191
+ ? this.getCollabWindow().localPerspective
192
+ : this.getOperationPerspective(perspective), accum, start, end, splitRange);
191
193
  }
192
194
  walkAllSegments(action, accum) {
193
195
  return walkAllChildSegments(this._mergeTree.root, accum === undefined ? action : (seg) => action(seg, accum));
@@ -551,11 +553,13 @@ export class Client extends TypedEventEmitter {
551
553
  const useNewSlidingBehavior = true;
552
554
  // Destructuring segment + offset is convenient and segment is reassigned
553
555
  // eslint-disable-next-line prefer-const
554
- let { segment: newSegment, offset: newOffset } = getSlideToSegoff({ segment: oldSegment, offset: oldOffset }, slidePreference, reconnectingPerspective, useNewSlidingBehavior);
555
- newSegment ??=
556
- slidePreference === SlidingPreference.FORWARD
556
+ const segOff = getSlideToSegoff({ segment: oldSegment, offset: oldOffset }, slidePreference, reconnectingPerspective, useNewSlidingBehavior);
557
+ const { segment: newSegment, offset: newOffset } = segOff ?? {
558
+ segment: slidePreference === SlidingPreference.FORWARD
557
559
  ? this._mergeTree.endOfTree
558
- : this._mergeTree.startOfTree;
560
+ : this._mergeTree.startOfTree,
561
+ offset: 0,
562
+ };
559
563
  assert(isSegmentLeaf(newSegment) && newOffset !== undefined, 0xb62 /* Invalid new segment on rebase */);
560
564
  const newSide = newSegment === oldSegment
561
565
  ? side
@@ -566,9 +570,9 @@ export class Client extends TypedEventEmitter {
566
570
  : Side.After;
567
571
  return { segment: newSegment, offset: newOffset, side: newSide };
568
572
  }
569
- computeNewObliterateEndpoints(obliterateInfo) {
573
+ computeNewObliterateEndpoints(obliterateInfo, squash) {
570
574
  const { currentSeq, clientId } = this.getCollabWindow();
571
- const reconnectingPerspective = new LocalReconnectingPerspective(currentSeq, clientId, obliterateInfo.stamp.localSeq - 1);
575
+ const reconnectingPerspective = new (squash ? LocalSquashPerspective : LocalReconnectingPerspective)(currentSeq, clientId, obliterateInfo.stamp.localSeq - 1);
572
576
  const newStart = this.rebaseSidedLocalReference(obliterateInfo.start, obliterateInfo.startSide, reconnectingPerspective, SlidingPreference.FORWARD);
573
577
  const newEnd = this.rebaseSidedLocalReference(obliterateInfo.end, obliterateInfo.endSide, reconnectingPerspective, SlidingPreference.BACKWARD);
574
578
  return {
@@ -576,7 +580,7 @@ export class Client extends TypedEventEmitter {
576
580
  end: newEnd,
577
581
  };
578
582
  }
579
- resetPendingDeltaToOps(resetOp, segmentGroup) {
583
+ resetPendingDeltaToOps(resetOp, segmentGroup, squash) {
580
584
  assert(!!segmentGroup, 0x033 /* "Segment group undefined" */);
581
585
  const NACKedSegmentGroup = this.pendingRebase?.shift()?.data;
582
586
  assert(segmentGroup === NACKedSegmentGroup, 0x034 /* "Segment group not at head of pending rebase queue" */);
@@ -603,11 +607,17 @@ export class Client extends TypedEventEmitter {
603
607
  for (const segment of segmentGroup.segments) {
604
608
  assert(isRemovedAndAcked(segment), 0xb66 /* On reconnect, obliterate applied to new segments even though original ones were not removed. */);
605
609
  const lastRemove = segment.removes[segment.removes.length - 1];
606
- assert(lastRemove.type === "sliceRemove" && lastRemove.localSeq === segmentGroup.localSeq, 0xb67 /* Last remove should be the obliterate that is being resubmitted. */);
607
- // The original obliterate affected this segment, but it has since been removed and overlapping removes
608
- // are only possible when they are concurrent. We adjust the metadata on that segment now to reflect
609
- // the fact that the obliterate no longer affects it.
610
- segment.removes.pop();
610
+ assert((lastRemove.type === "sliceRemove" &&
611
+ lastRemove.localSeq === segmentGroup.localSeq) ||
612
+ opstampUtils.isSquashedOp(lastRemove), 0xbad /* Last remove should be the obliterate that is being resubmitted. */);
613
+ // The original obliterate affected this segment, but it has since been removed.
614
+ // This can happen when a concurrent obliterate also removed the segment, as well as when the segment was
615
+ // only locally inserted and its insertion was squashed upon reconnecting.
616
+ // In the concurrent removal case (where we didn't avoid sending the segment's insertion in the first place due
617
+ // to squashing), we adjust the metadata on that segment to reflect the fact that this obliterate no longer removes it.
618
+ if (!opstampUtils.isSquashedOp(lastRemove)) {
619
+ segment.removes.pop();
620
+ }
611
621
  }
612
622
  this._mergeTree.rebaseObliterateTo(obliterateInfo, undefined);
613
623
  return [];
@@ -636,19 +646,24 @@ export class Client extends TypedEventEmitter {
636
646
  };
637
647
  for (const segment of segmentGroup.segments) {
638
648
  assert(segment.segmentGroups?.remove(segmentGroup) === true, 0x035 /* "Segment group not in segment pending queue" */);
639
- if ((segment.ordinal > newStartSegment.ordinal &&
640
- segment.ordinal < newEndSegment.ordinal) ||
641
- (segment === newStartSegment && newStartSide === Side.Before) ||
642
- (segment === newEndSegment && newEndSide === Side.After)) {
649
+ if (!isRemovedAndAcked(segment) &&
650
+ ((segment.ordinal > newStartSegment.ordinal &&
651
+ segment.ordinal < newEndSegment.ordinal) ||
652
+ (segment === newStartSegment && newStartSide === Side.Before) ||
653
+ (segment === newEndSegment && newEndSide === Side.After))) {
643
654
  segment.segmentGroups.enqueue(newObliterate.segmentGroup);
644
655
  }
645
656
  else {
646
657
  assert(isRemovedAndAcked(segment), 0xb69 /* On reconnect, obliterate applied to new segments even though original ones were not removed. */);
647
658
  const lastRemove = segment.removes[segment.removes.length - 1];
648
- assert(lastRemove.type === "sliceRemove" && lastRemove.localSeq === segmentGroup.localSeq, 0xb6a /* Last remove should be the obliterate that is being resubmitted. */);
649
- // The original obliterate affected this segment, but it has since been removed and it's impossible to apply the
650
- // local obliterate so that is so. We adjust the metadata on that segment now.
651
- segment.removes.pop();
659
+ assert((lastRemove.type === "sliceRemove" &&
660
+ lastRemove.localSeq === segmentGroup.localSeq) ||
661
+ opstampUtils.isSquashedOp(lastRemove), 0xbae /* Last remove should be the obliterate that is being resubmitted. */);
662
+ if (!opstampUtils.isSquashedOp(lastRemove)) {
663
+ // The original obliterate affected this segment, but it has since been removed and it's impossible to apply the
664
+ // local obliterate so that is so. We adjust the metadata on that segment now.
665
+ segment.removes.pop();
666
+ }
652
667
  }
653
668
  }
654
669
  this._mergeTree.rebaseObliterateTo(obliterateInfo, newObliterate);
@@ -701,9 +716,19 @@ export class Client extends TypedEventEmitter {
701
716
  break;
702
717
  }
703
718
  case MergeTreeDeltaType.INSERT: {
719
+ if (isInserted(segment) && opstampUtils.isSquashedOp(segment.insert)) {
720
+ break;
721
+ }
704
722
  assert(isInserted(segment) && opstampUtils.isLocal(segment.insert), 0x037 /* "Segment already has assigned sequence number" */);
705
723
  const removeInfo = toRemovalInfo(segment);
706
- if (removeInfo !== undefined && opstampUtils.isAcked(removeInfo.removes[0])) {
724
+ const unusedStamp = { seq: 0, clientId: 0 };
725
+ if (removeInfo !== undefined && squash) {
726
+ assert(removeInfo.removes.length === 1 ||
727
+ opstampUtils.isAcked(removeInfo.removes[removeInfo.removes.length - 2]), 0xbaf /* Expected only one local remove */);
728
+ this.squashInsertion(segment);
729
+ break;
730
+ }
731
+ else if (removeInfo !== undefined && opstampUtils.isAcked(removeInfo.removes[0])) {
707
732
  assert(removeInfo.removes[0].type === "sliceRemove", 0xb5c /* Remove on insertion must be caused by obliterate. */);
708
733
  errorIfOptionNotTrue(this._mergeTree.options, "mergeTreeEnableObliterateReconnect");
709
734
  // the segment was remotely obliterated, so is considered removed
@@ -718,6 +743,7 @@ export class Client extends TypedEventEmitter {
718
743
  clientId: NonCollabClient,
719
744
  },
720
745
  });
746
+ this._mergeTree.blockUpdatePathLengths(segment.parent, unusedStamp, true);
721
747
  break;
722
748
  }
723
749
  const segInsertOp = segment.clone();
@@ -857,13 +883,34 @@ export class Client extends TypedEventEmitter {
857
883
  const shortRemoteClientId = this.getOrAddShortClientId(remoteClientId);
858
884
  return this._mergeTree.resolveRemoteClientPosition(remoteClientPosition, remoteClientRefSeq, shortRemoteClientId);
859
885
  }
886
+ squashInsertion(segment) {
887
+ overwriteInfo(segment, {
888
+ insert: {
889
+ type: "insert",
890
+ seq: UniversalSequenceNumber,
891
+ localSeq: undefined,
892
+ clientId: SquashClient,
893
+ },
894
+ removes: [
895
+ {
896
+ type: "setRemove",
897
+ seq: UniversalSequenceNumber,
898
+ localSeq: undefined,
899
+ clientId: SquashClient,
900
+ },
901
+ ],
902
+ });
903
+ this._mergeTree.blockUpdatePathLengths(segment.parent, { seq: 0, clientId: 0 }, true);
904
+ }
860
905
  /**
861
906
  * Given a pending operation and segment group, regenerate the op, so it
862
907
  * can be resubmitted
863
908
  * @param resetOp - The op to reset
864
909
  * @param segmentGroup - The segment group associated with the op
910
+ * @param squash - whether intermediate states should be squashed. See `IDeltaHandler.reSubmit`'s squash parameter
911
+ * documentation for more details.
865
912
  */
866
- regeneratePendingOp(resetOp, localOpMetadata) {
913
+ regeneratePendingOp(resetOp, localOpMetadata, squash) {
867
914
  const segmentGroup = localOpMetadata;
868
915
  if (this.pendingRebase === undefined || this.pendingRebase.empty) {
869
916
  let firstGroup;
@@ -885,13 +932,14 @@ export class Client extends TypedEventEmitter {
885
932
  if (this.lastNormalization === undefined ||
886
933
  collabWindow.currentSeq !== this.lastNormalization.refSeq ||
887
934
  collabWindow.localSeq !== this.lastNormalization.localRefSeq) {
935
+ const allPendingSegments = [...this._mergeTree.pendingSegments, ...this.pendingRebase];
888
936
  // Compute obliterate endpoint destinations before segments are normalized.
889
937
  // Segment normalization can affect what should be the semantically correct segments for the endpoints to be placed on.
890
938
  this.cachedObliterateRebases.clear();
891
- for (const group of [...this._mergeTree.pendingSegments, ...this.pendingRebase]) {
939
+ for (const group of allPendingSegments) {
892
940
  const { obliterateInfo } = group.data;
893
941
  if (obliterateInfo !== undefined) {
894
- const { start, end } = this.computeNewObliterateEndpoints(obliterateInfo);
942
+ const { start, end } = this.computeNewObliterateEndpoints(obliterateInfo, squash);
895
943
  const { localSeq } = obliterateInfo.stamp;
896
944
  assert(localSeq !== undefined, 0xb6d /* Local seq must be defined */);
897
945
  this.cachedObliterateRebases.set(localSeq, { start, end });
@@ -909,20 +957,20 @@ export class Client extends TypedEventEmitter {
909
957
  if (Array.isArray(segmentGroup)) {
910
958
  assert(resetOp.ops.length === segmentGroup.length, 0x03a /* "Number of ops in 'resetOp' must match the number of segment groups provided." */);
911
959
  for (let i = 0; i < resetOp.ops.length; i++) {
912
- opList.push(...this.resetPendingDeltaToOps(resetOp.ops[i], segmentGroup[i]));
960
+ opList.push(...this.resetPendingDeltaToOps(resetOp.ops[i], segmentGroup[i], squash));
913
961
  }
914
962
  }
915
963
  else {
916
964
  // A group op containing a single op will pass a direct reference to 'segmentGroup'
917
965
  // rather than an array of segment groups. (See 'peekPendingSegmentGroups()')
918
966
  assert(resetOp.ops.length === 1, 0x03b /* "Number of ops in 'resetOp' must match the number of segment groups provided." */);
919
- opList.push(...this.resetPendingDeltaToOps(resetOp.ops[0], segmentGroup));
967
+ opList.push(...this.resetPendingDeltaToOps(resetOp.ops[0], segmentGroup, squash));
920
968
  }
921
969
  }
922
970
  else {
923
971
  assert(resetOp.type !== MergeTreeDeltaType.GROUP, 0x03c /* "Reset op has 'group' delta type!" */);
924
972
  assert(!Array.isArray(segmentGroup), 0x03d /* "segmentGroup is array rather than singleton!" */);
925
- opList.push(...this.resetPendingDeltaToOps(resetOp, segmentGroup));
973
+ opList.push(...this.resetPendingDeltaToOps(resetOp, segmentGroup, squash));
926
974
  }
927
975
  return opList.length === 1 ? opList[0] : createGroupOp(...opList);
928
976
  }
@@ -1009,19 +1057,14 @@ export class Client extends TypedEventEmitter {
1009
1057
  return this._mergeTree.getContainingSegment(pos, perspective);
1010
1058
  }
1011
1059
  getPropertiesAtPosition(pos) {
1012
- let propertiesAtPosition;
1013
1060
  const segoff = this.getContainingSegment(pos);
1014
- const seg = segoff.segment;
1015
- if (seg) {
1016
- propertiesAtPosition = seg.properties;
1017
- }
1018
- return propertiesAtPosition;
1061
+ return segoff?.segment?.properties;
1019
1062
  }
1020
1063
  getRangeExtentsOfPosition(pos) {
1021
1064
  let posStart;
1022
1065
  let posAfterEnd;
1023
1066
  const segoff = this.getContainingSegment(pos);
1024
- const seg = segoff.segment;
1067
+ const seg = segoff?.segment;
1025
1068
  if (seg) {
1026
1069
  posStart = this.getPosition(seg);
1027
1070
  posAfterEnd = posStart + seg.cachedLength;