@fluidframework/merge-tree 0.59.2001 → 0.59.3000

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 (93) hide show
  1. package/.eslintrc.js +0 -1
  2. package/dist/client.d.ts +15 -4
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +60 -34
  5. package/dist/client.js.map +1 -1
  6. package/dist/collections.d.ts +7 -1
  7. package/dist/collections.d.ts.map +1 -1
  8. package/dist/collections.js +27 -1
  9. package/dist/collections.js.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/localReference.d.ts +104 -10
  15. package/dist/localReference.d.ts.map +1 -1
  16. package/dist/localReference.js +152 -96
  17. package/dist/localReference.js.map +1 -1
  18. package/dist/mergeTree.d.ts +28 -21
  19. package/dist/mergeTree.d.ts.map +1 -1
  20. package/dist/mergeTree.js +100 -88
  21. package/dist/mergeTree.js.map +1 -1
  22. package/dist/partialLengths.js +10 -10
  23. package/dist/partialLengths.js.map +1 -1
  24. package/dist/referencePositions.d.ts +55 -0
  25. package/dist/referencePositions.d.ts.map +1 -0
  26. package/dist/referencePositions.js +93 -0
  27. package/dist/referencePositions.js.map +1 -0
  28. package/dist/segmentGroupCollection.js +1 -1
  29. package/dist/segmentGroupCollection.js.map +1 -1
  30. package/dist/segmentPropertiesManager.js +5 -5
  31. package/dist/segmentPropertiesManager.js.map +1 -1
  32. package/dist/snapshotChunks.js.map +1 -1
  33. package/dist/snapshotLoader.d.ts.map +1 -1
  34. package/dist/snapshotLoader.js +9 -9
  35. package/dist/snapshotLoader.js.map +1 -1
  36. package/dist/snapshotV1.js +7 -7
  37. package/dist/snapshotV1.js.map +1 -1
  38. package/dist/snapshotlegacy.js +6 -6
  39. package/dist/snapshotlegacy.js.map +1 -1
  40. package/dist/sortedSegmentSet.d.ts.map +1 -1
  41. package/dist/sortedSegmentSet.js +1 -1
  42. package/dist/sortedSegmentSet.js.map +1 -1
  43. package/dist/textSegment.js +3 -2
  44. package/dist/textSegment.js.map +1 -1
  45. package/lib/client.d.ts +15 -4
  46. package/lib/client.d.ts.map +1 -1
  47. package/lib/client.js +31 -5
  48. package/lib/client.js.map +1 -1
  49. package/lib/collections.d.ts +7 -1
  50. package/lib/collections.d.ts.map +1 -1
  51. package/lib/collections.js +26 -1
  52. package/lib/collections.js.map +1 -1
  53. package/lib/index.d.ts +1 -0
  54. package/lib/index.d.ts.map +1 -1
  55. package/lib/index.js +1 -0
  56. package/lib/index.js.map +1 -1
  57. package/lib/localReference.d.ts +104 -10
  58. package/lib/localReference.d.ts.map +1 -1
  59. package/lib/localReference.js +146 -90
  60. package/lib/localReference.js.map +1 -1
  61. package/lib/mergeTree.d.ts +28 -21
  62. package/lib/mergeTree.d.ts.map +1 -1
  63. package/lib/mergeTree.js +67 -51
  64. package/lib/mergeTree.js.map +1 -1
  65. package/lib/referencePositions.d.ts +55 -0
  66. package/lib/referencePositions.d.ts.map +1 -0
  67. package/lib/referencePositions.js +80 -0
  68. package/lib/referencePositions.js.map +1 -0
  69. package/lib/segmentPropertiesManager.js.map +1 -1
  70. package/lib/snapshotChunks.js.map +1 -1
  71. package/lib/snapshotLoader.d.ts.map +1 -1
  72. package/lib/snapshotLoader.js.map +1 -1
  73. package/lib/snapshotV1.js.map +1 -1
  74. package/lib/snapshotlegacy.js +1 -1
  75. package/lib/snapshotlegacy.js.map +1 -1
  76. package/lib/sortedSegmentSet.d.ts.map +1 -1
  77. package/lib/sortedSegmentSet.js +1 -1
  78. package/lib/sortedSegmentSet.js.map +1 -1
  79. package/lib/textSegment.js +3 -2
  80. package/lib/textSegment.js.map +1 -1
  81. package/package.json +161 -14
  82. package/src/client.ts +45 -19
  83. package/src/collections.ts +55 -54
  84. package/src/index.ts +1 -0
  85. package/src/localReference.ts +190 -100
  86. package/src/mergeTree.ts +107 -99
  87. package/src/referencePositions.ts +126 -0
  88. package/src/snapshotChunks.ts +8 -8
  89. package/src/snapshotLoader.ts +4 -4
  90. package/src/snapshotV1.ts +1 -1
  91. package/src/snapshotlegacy.ts +2 -2
  92. package/src/sortedSegmentSet.ts +4 -4
  93. package/src/textSegment.ts +2 -2
package/src/mergeTree.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
7
7
  /* eslint-disable @typescript-eslint/consistent-type-assertions */
8
8
 
9
- /* eslint-disable no-bitwise */
9
+ /* eslint-disable @typescript-eslint/prefer-optional-chain, no-bitwise */
10
10
 
11
11
  import { assert } from "@fluidframework/common-utils";
12
12
  import {
@@ -50,26 +50,20 @@ import {
50
50
  matchProperties,
51
51
  PropertySet,
52
52
  } from "./properties";
53
+ import {
54
+ refTypeIncludesFlag,
55
+ RangeStackMap,
56
+ ReferencePosition,
57
+ refGetRangeLabels,
58
+ refGetTileLabels,
59
+ refHasRangeLabel,
60
+ refHasRangeLabels,
61
+ refHasTileLabel,
62
+ refHasTileLabels,
63
+ } from "./referencePositions";
53
64
  import { SegmentGroupCollection } from "./segmentGroupCollection";
54
65
  import { PropertiesManager } from "./segmentPropertiesManager";
55
-
56
- export interface ReferencePosition {
57
- properties?: PropertySet;
58
- refType: ReferenceType;
59
- // True if this reference is a segment.
60
- isLeaf(): boolean;
61
- getSegment(): ISegment | undefined;
62
- getOffset(): number;
63
- addProperties(newProps: PropertySet, op?: ICombiningOp): void;
64
- hasTileLabels(): boolean;
65
- hasRangeLabels(): boolean;
66
- hasTileLabel(label: string): boolean;
67
- hasRangeLabel(label: string): boolean;
68
- getTileLabels(): string[] | undefined;
69
- getRangeLabels(): string[] | undefined;
70
- }
71
-
72
- export type RangeStackMap = MapLike<Stack<ReferencePosition>>;
66
+ import { Client } from "./client";
73
67
 
74
68
  export interface IMergeNodeCommon {
75
69
  parent?: IMergeBlock;
@@ -265,7 +259,7 @@ export class MergeNode implements IMergeNodeCommon {
265
259
  }
266
260
 
267
261
  function addTile(tile: ReferencePosition, tiles: object) {
268
- const tileLabels = tile.getTileLabels();
262
+ const tileLabels = refGetTileLabels(tile);
269
263
  if (tileLabels) {
270
264
  for (const tileLabel of tileLabels) {
271
265
  tiles[tileLabel] = tile;
@@ -274,7 +268,7 @@ function addTile(tile: ReferencePosition, tiles: object) {
274
268
  }
275
269
 
276
270
  function addTileIfNotPresent(tile: ReferencePosition, tiles: object) {
277
- const tileLabels = tile.getTileLabels();
271
+ const tileLabels = refGetTileLabels(tile);
278
272
  if (tileLabels) {
279
273
  for (const tileLabel of tileLabels) {
280
274
  if (tiles[tileLabel] === undefined) {
@@ -302,14 +296,14 @@ function applyStackDelta(currentStackMap: RangeStackMap, deltaStackMap: RangeSta
302
296
  }
303
297
 
304
298
  function applyRangeReference(stack: Stack<ReferencePosition>, delta: ReferencePosition) {
305
- if (delta.refType & ReferenceType.NestBegin) {
299
+ if (refTypeIncludesFlag(delta, ReferenceType.NestBegin)) {
306
300
  stack.push(delta);
307
301
  return true;
308
302
  } else {
309
303
  // Assume delta is end reference
310
304
  const top = stack.top();
311
305
  // TODO: match end with begin
312
- if (top && (top.refType & ReferenceType.NestBegin)) {
306
+ if (top && (refTypeIncludesFlag(top, ReferenceType.NestBegin))) {
313
307
  stack.pop();
314
308
  } else {
315
309
  stack.push(delta);
@@ -340,14 +334,14 @@ function addNodeReferences(
340
334
  if (markerId) {
341
335
  mergeTree.mapIdToSegment(markerId, segment);
342
336
  }
343
- if (segment.refType & ReferenceType.Tile) {
337
+ if (refTypeIncludesFlag(segment, ReferenceType.Tile)) {
344
338
  addTile(segment, rightmostTiles);
345
339
  addTileIfNotPresent(segment, leftmostTiles);
346
340
  }
347
341
  if (segment.refType & (ReferenceType.NestBegin | ReferenceType.NestEnd)) {
348
- const rangeLabels = segment.getRangeLabels();
342
+ const rangeLabels = refGetRangeLabels(segment);
349
343
  if (rangeLabels) {
350
- for (const label of segment.getRangeLabels()!) {
344
+ for (const label of rangeLabels) {
351
345
  updateRangeInfo(label, segment);
352
346
  }
353
347
  }
@@ -357,12 +351,12 @@ function addNodeReferences(
357
351
  if (baseSegment.localRefs && (baseSegment.localRefs.hierRefCount !== undefined) &&
358
352
  (baseSegment.localRefs.hierRefCount > 0)) {
359
353
  for (const lref of baseSegment.localRefs) {
360
- if (lref.refType & ReferenceType.Tile) {
354
+ if (refTypeIncludesFlag(lref, ReferenceType.Tile)) {
361
355
  addTile(lref, rightmostTiles);
362
356
  addTileIfNotPresent(lref, leftmostTiles);
363
357
  }
364
358
  if (lref.refType & (ReferenceType.NestBegin | ReferenceType.NestEnd)) {
365
- for (const label of lref.getRangeLabels()!) {
359
+ for (const label of refGetRangeLabels(lref)!) {
366
360
  updateRangeInfo(label, lref);
367
361
  }
368
362
  }
@@ -622,43 +616,9 @@ export abstract class BaseSegment extends MergeNode implements ISegment {
622
616
  protected abstract createSplitSegmentAt(pos: number): BaseSegment | undefined;
623
617
  }
624
618
 
625
- export const reservedTileLabelsKey = "referenceTileLabels";
626
- export const reservedRangeLabelsKey = "referenceRangeLabels";
627
619
  export const reservedMarkerIdKey = "markerId";
628
620
  export const reservedMarkerSimpleTypeKey = "markerSimpleType";
629
621
 
630
- export const refGetTileLabels = (refPos: ReferencePosition) =>
631
- (refPos.refType & ReferenceType.Tile)
632
- && refPos.properties ? refPos.properties[reservedTileLabelsKey] as string[] : undefined;
633
-
634
- export const refGetRangeLabels = (refPos: ReferencePosition) =>
635
- (refPos.refType & (ReferenceType.NestBegin | ReferenceType.NestEnd))
636
- && refPos.properties ? refPos.properties[reservedRangeLabelsKey] as string[] : undefined;
637
-
638
- export function refHasTileLabel(refPos: ReferencePosition, label: string) {
639
- const tileLabels = refPos.getTileLabels();
640
- if (tileLabels) {
641
- for (const refLabel of tileLabels) {
642
- if (label === refLabel) {
643
- return true;
644
- }
645
- }
646
- }
647
- return false;
648
- }
649
-
650
- export function refHasRangeLabel(refPos: ReferencePosition, label: string) {
651
- const rangeLabels = refPos.getRangeLabels();
652
- if (rangeLabels) {
653
- for (const refLabel of rangeLabels) {
654
- if (label === refLabel) {
655
- return true;
656
- }
657
- }
658
- }
659
- return false;
660
- }
661
-
662
622
  export interface IJSONMarkerSegment extends IJSONSegment {
663
623
  marker: IMarkerDef;
664
624
  }
@@ -728,42 +688,55 @@ export class Marker extends BaseSegment implements ReferencePosition {
728
688
  }
729
689
  }
730
690
 
691
+ /**
692
+ * @deprecated - use refHasTileLabels
693
+ */
731
694
  hasTileLabels() {
732
- return !!this.getTileLabels();
695
+ return refHasTileLabels(this);
733
696
  }
734
-
697
+ /**
698
+ * @deprecated - use refHasRangeLabels
699
+ */
735
700
  hasRangeLabels() {
736
- return !!this.getRangeLabels();
701
+ return refHasRangeLabels(this);
737
702
  }
738
-
703
+ /**
704
+ * @deprecated - use refHasTileLabel
705
+ */
739
706
  hasTileLabel(label: string): boolean {
740
707
  return refHasTileLabel(this, label);
741
708
  }
742
-
709
+ /**
710
+ * @deprecated - use refHasRangeLabel
711
+ */
743
712
  hasRangeLabel(label: string): boolean {
744
713
  return refHasRangeLabel(this, label);
745
714
  }
746
-
715
+ /**
716
+ * @deprecated - use refGetTileLabels
717
+ */
747
718
  getTileLabels(): string[] | undefined {
748
719
  return refGetTileLabels(this);
749
720
  }
750
-
721
+ /**
722
+ * @deprecated - use refGetRangeLabels
723
+ */
751
724
  getRangeLabels(): string[] | undefined {
752
725
  return refGetRangeLabels(this);
753
726
  }
754
727
 
755
728
  toString() {
756
729
  let bbuf = "";
757
- if (this.refType & ReferenceType.Tile) {
730
+ if (refTypeIncludesFlag(this, ReferenceType.Tile)) {
758
731
  bbuf += "Tile";
759
732
  }
760
- if (this.refType & ReferenceType.NestBegin) {
733
+ if (refTypeIncludesFlag(this, ReferenceType.NestBegin)) {
761
734
  if (bbuf.length > 0) {
762
735
  bbuf += "; ";
763
736
  }
764
737
  bbuf += "RangeBegin";
765
738
  }
766
- if (this.refType & ReferenceType.NestEnd) {
739
+ if (refTypeIncludesFlag(this, ReferenceType.NestEnd)) {
767
740
  if (bbuf.length > 0) {
768
741
  bbuf += "; ";
769
742
  }
@@ -774,7 +747,7 @@ export class Marker extends BaseSegment implements ReferencePosition {
774
747
  if (id) {
775
748
  bbuf += ` (${id}) `;
776
749
  }
777
- const tileLabels = this.getTileLabels();
750
+ const tileLabels = refGetTileLabels(this);
778
751
  if (tileLabels) {
779
752
  lbuf += "tile -- ";
780
753
  for (let i = 0, len = tileLabels.length; i < len; i++) {
@@ -785,10 +758,10 @@ export class Marker extends BaseSegment implements ReferencePosition {
785
758
  lbuf += tileLabel;
786
759
  }
787
760
  }
788
- const rangeLabels = this.getRangeLabels();
761
+ const rangeLabels = refGetRangeLabels(this);
789
762
  if (rangeLabels) {
790
763
  let rangeKind = "begin";
791
- if (this.refType & ReferenceType.NestEnd) {
764
+ if (refTypeIncludesFlag(this, ReferenceType.NestEnd)) {
792
765
  rangeKind = "end";
793
766
  }
794
767
  if (tileLabels) {
@@ -931,7 +904,7 @@ interface IMarkerSearchRangeInfo {
931
904
 
932
905
  function applyLeafRangeMarker(marker: Marker, searchInfo: IMarkerSearchRangeInfo) {
933
906
  for (const rangeLabel of searchInfo.rangeLabels) {
934
- if (marker.hasRangeLabel(rangeLabel)) {
907
+ if (refHasRangeLabel(marker, rangeLabel)) {
935
908
  let currentStack = searchInfo.stacks[rangeLabel];
936
909
  if (currentStack === undefined) {
937
910
  currentStack = new Stack<Marker>();
@@ -981,7 +954,7 @@ function recordTileStart(
981
954
  end: number,
982
955
  searchInfo: IReferenceSearchInfo) {
983
956
  if (Marker.is(segment)) {
984
- if (segment.hasTileLabel(searchInfo.tileLabel)) {
957
+ if (refHasTileLabel(segment, searchInfo.tileLabel)) {
985
958
  searchInfo.tile = segment;
986
959
  }
987
960
  }
@@ -994,7 +967,7 @@ function tileShift(
994
967
  if (node.isLeaf()) {
995
968
  const seg = node;
996
969
  if ((searchInfo.mergeTree.localNetLength(seg) > 0) && Marker.is(seg)) {
997
- if (seg.hasTileLabel(searchInfo.tileLabel)) {
970
+ if (refHasTileLabel(seg, searchInfo.tileLabel)) {
998
971
  searchInfo.tile = seg;
999
972
  }
1000
973
  }
@@ -1134,7 +1107,7 @@ export class MergeTree {
1134
1107
  // and update the block's info.
1135
1108
  for (let childIndex = 0;
1136
1109
  childIndex < maxChildren && nodeIndex < nodes.length; // While we still have children & nodes left
1137
- childIndex++ , nodeIndex++ // Advance to next child & node
1110
+ childIndex++, nodeIndex++ // Advance to next child & node
1138
1111
  ) {
1139
1112
  // Insert the next node into the current block
1140
1113
  this.addNode(block, nodes[nodeIndex]);
@@ -1202,11 +1175,13 @@ export class MergeTree {
1202
1175
  } else {
1203
1176
  // Notify maintenance event observers that the segment is being unlinked from the MergeTree
1204
1177
  if (this.mergeTreeMaintenanceCallback) {
1205
- this.mergeTreeMaintenanceCallback({
1206
- operation: MergeTreeMaintenanceType.UNLINK,
1207
- deltaSegments: [{ segment }],
1208
- },
1209
- undefined);
1178
+ this.mergeTreeMaintenanceCallback(
1179
+ {
1180
+ operation: MergeTreeMaintenanceType.UNLINK,
1181
+ deltaSegments: [{ segment }],
1182
+ },
1183
+ undefined,
1184
+ );
1210
1185
  }
1211
1186
 
1212
1187
  segment.parent = undefined;
@@ -1223,11 +1198,13 @@ export class MergeTree {
1223
1198
  if (canAppend) {
1224
1199
  prevSegment!.append(segment);
1225
1200
  if (this.mergeTreeMaintenanceCallback) {
1226
- this.mergeTreeMaintenanceCallback({
1227
- operation: MergeTreeMaintenanceType.APPEND,
1228
- deltaSegments: [{ segment: prevSegment! }, { segment }],
1229
- },
1230
- undefined);
1201
+ this.mergeTreeMaintenanceCallback(
1202
+ {
1203
+ operation: MergeTreeMaintenanceType.APPEND,
1204
+ deltaSegments: [{ segment: prevSegment! }, { segment }],
1205
+ },
1206
+ undefined,
1207
+ );
1231
1208
  }
1232
1209
  segment.parent = undefined;
1233
1210
  segment.trackingCollection.trackingGroups.forEach((tg) => tg.unlink(segment));
@@ -1461,7 +1438,7 @@ export class MergeTree {
1461
1438
  const segment = node;
1462
1439
  const removalInfo = toRemovalInfo(segment);
1463
1440
 
1464
- if(removalInfo !== undefined
1441
+ if (removalInfo !== undefined
1465
1442
  && removalInfo.removedSeq !== UnassignedSequenceNumber
1466
1443
  && removalInfo.removedSeq <= refSeq) {
1467
1444
  // this segment is a tombstone eligible for zamboni
@@ -1485,7 +1462,7 @@ export class MergeTree {
1485
1462
  // the segment was inserted and removed before the
1486
1463
  // this context, so it will never exist for this
1487
1464
  // context
1488
- if(removalInfo !== undefined
1465
+ if (removalInfo !== undefined
1489
1466
  && removalInfo.removedSeq !== UnassignedSequenceNumber) {
1490
1467
  return undefined;
1491
1468
  }
@@ -1707,10 +1684,10 @@ export class MergeTree {
1707
1684
  nodesToUpdate.push(pendingSegment.parent!);
1708
1685
  }
1709
1686
  deltaSegments.push({
1710
- segment:pendingSegment,
1687
+ segment: pendingSegment,
1711
1688
  });
1712
1689
  });
1713
- if(this.mergeTreeMaintenanceCallback) {
1690
+ if (this.mergeTreeMaintenanceCallback) {
1714
1691
  this.mergeTreeMaintenanceCallback(
1715
1692
  {
1716
1693
  deltaSegments,
@@ -1874,7 +1851,7 @@ export class MergeTree {
1874
1851
  }
1875
1852
  const backLen = this.nodeLength(backSeg, this.collabWindow.currentSeq, clientId);
1876
1853
  // ignore removed segments
1877
- if(backLen === undefined) {
1854
+ if (backLen === undefined) {
1878
1855
  return true;
1879
1856
  }
1880
1857
  // Find the nearest 0 length seg we can insert over, as all other inserts
@@ -1940,7 +1917,7 @@ export class MergeTree {
1940
1917
  remoteClientPosition: number,
1941
1918
  remoteClientRefSeq: number,
1942
1919
  remoteClientId: number): number | undefined {
1943
- if(remoteClientRefSeq < this.collabWindow.minSeq) {
1920
+ if (remoteClientRefSeq < this.collabWindow.minSeq) {
1944
1921
  return undefined;
1945
1922
  }
1946
1923
 
@@ -2001,9 +1978,9 @@ export class MergeTree {
2001
1978
  const saveIfLocal = (locSegment: ISegment) => {
2002
1979
  // Save segment so can assign sequence number when acked by server
2003
1980
  if (this.collabWindow.collaborating) {
2004
- if ((locSegment.seq === UnassignedSequenceNumber) &&
2005
- (clientId === this.collabWindow.clientId)) {
1981
+ if ((locSegment.seq === UnassignedSequenceNumber) && (clientId === this.collabWindow.clientId)) {
2006
1982
  segmentGroup = this.addToPendingList(locSegment, segmentGroup, localSeq);
1983
+ // eslint-disable-next-line @typescript-eslint/brace-style
2007
1984
  }
2008
1985
  // LocSegment.seq === 0 when coming from SharedSegmentSequence.loadBody()
2009
1986
  // In all other cases this has to be true (checked by addToLRUSet):
@@ -2070,7 +2047,7 @@ export class MergeTree {
2070
2047
  operation: MergeTreeMaintenanceType.SPLIT,
2071
2048
  deltaSegments: [{ segment }, { segment: next }],
2072
2049
  },
2073
- undefined);
2050
+ undefined);
2074
2051
  }
2075
2052
 
2076
2053
  return { next };
@@ -2178,7 +2155,7 @@ export class MergeTree {
2178
2155
  for (childIndex = 0; childIndex < block.childCount; childIndex++) {
2179
2156
  child = children[childIndex];
2180
2157
  const len = this.nodeLength(child, refSeq, clientId);
2181
- if(len === undefined) {
2158
+ if (len === undefined) {
2182
2159
  // if the seg len in undefined, the segment
2183
2160
  // will be removed, so should just be skipped for now
2184
2161
  continue;
@@ -2467,6 +2444,34 @@ export class MergeTree {
2467
2444
  }
2468
2445
  }
2469
2446
 
2447
+ public removeLocalReferencePosition(lref: ReferencePosition): ReferencePosition | undefined {
2448
+ const segment = lref.getSegment();
2449
+ if (segment) {
2450
+ const removedRefs = segment?.localRefs?.removeLocalRef(lref);
2451
+ if (removedRefs !== undefined) {
2452
+ this.blockUpdatePathLengths(segment.parent, TreeMaintenanceSequenceNumber,
2453
+ LocalClientId);
2454
+ }
2455
+ return removedRefs;
2456
+ }
2457
+ }
2458
+ public createLocalReferencePosition(
2459
+ segment: ISegment, offset: number, refType: ReferenceType, properties: PropertySet | undefined,
2460
+ client: Client,
2461
+ ): ReferencePosition {
2462
+ const localRefs = segment.localRefs ?? new LocalReferenceCollection(segment);
2463
+ segment.localRefs = localRefs;
2464
+
2465
+ const segRef = localRefs.createLocalRef(offset, refType, properties, client);
2466
+
2467
+ this.blockUpdatePathLengths(segment.parent, TreeMaintenanceSequenceNumber,
2468
+ LocalClientId);
2469
+ return segRef;
2470
+ }
2471
+
2472
+ /**
2473
+ * @deprecated - use removeLocalReferencePosition
2474
+ */
2470
2475
  public removeLocalReference(segment: ISegment, lref: LocalReference) {
2471
2476
  if (segment.localRefs) {
2472
2477
  const removedRef = segment.localRefs.removeLocalRef(lref);
@@ -2477,6 +2482,9 @@ export class MergeTree {
2477
2482
  }
2478
2483
  }
2479
2484
 
2485
+ /**
2486
+ * @deprecated - use createLocalReference
2487
+ */
2480
2488
  public addLocalReference(lref: LocalReference) {
2481
2489
  const segment = lref.segment!;
2482
2490
  let localRefs = segment.localRefs;
@@ -0,0 +1,126 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { Stack } from "./collections";
7
+ import { ISegment } from "./mergeTree";
8
+ import { ReferenceType, ICombiningOp } from "./ops";
9
+ import { PropertySet, MapLike } from "./properties";
10
+
11
+ export const reservedTileLabelsKey = "referenceTileLabels";
12
+ export const reservedRangeLabelsKey = "referenceRangeLabels";
13
+
14
+ export function refTypeIncludesFlag(refPos: ReferencePosition, flags: ReferenceType): boolean {
15
+ // eslint-disable-next-line no-bitwise
16
+ return (refPos.refType & flags) !== 0;
17
+ }
18
+
19
+ export const refGetTileLabels = (refPos: ReferencePosition): string[] | undefined =>
20
+ refTypeIncludesFlag(refPos, ReferenceType.Tile)
21
+ && refPos.properties ? refPos.properties[reservedTileLabelsKey] as string[] : undefined;
22
+
23
+ export const refGetRangeLabels = (refPos: ReferencePosition): string[] | undefined =>
24
+ // eslint-disable-next-line no-bitwise
25
+ (refTypeIncludesFlag(refPos, ReferenceType.NestBegin | ReferenceType.NestEnd))
26
+ && refPos.properties ? refPos.properties[reservedRangeLabelsKey] as string[] : undefined;
27
+
28
+ export function refHasTileLabel(refPos: ReferencePosition, label: string): boolean {
29
+ const tileLabels = refGetTileLabels(refPos);
30
+ if (tileLabels) {
31
+ for (const refLabel of tileLabels) {
32
+ if (label === refLabel) {
33
+ return true;
34
+ }
35
+ }
36
+ }
37
+ return false;
38
+ }
39
+
40
+ export function refHasRangeLabel(refPos: ReferencePosition, label: string): boolean {
41
+ const rangeLabels = refGetRangeLabels(refPos);
42
+ if (rangeLabels) {
43
+ for (const refLabel of rangeLabels) {
44
+ if (label === refLabel) {
45
+ return true;
46
+ }
47
+ }
48
+ }
49
+ return false;
50
+ }
51
+ export function refHasTileLabels(refPos: ReferencePosition): boolean {
52
+ return refGetTileLabels(refPos) !== undefined;
53
+ }
54
+ export function refHasRangeLabels(refPos: ReferencePosition): boolean {
55
+ return refGetRangeLabels(refPos) !== undefined;
56
+ }
57
+
58
+ export interface ReferencePosition {
59
+ properties?: PropertySet;
60
+ refType: ReferenceType;
61
+
62
+ getSegment(): ISegment | undefined;
63
+ getOffset(): number;
64
+ addProperties(newProps: PropertySet, op?: ICombiningOp): void;
65
+ isLeaf(): boolean;
66
+
67
+ /**
68
+ * @deprecated - use refHasTileLabels
69
+ */
70
+ hasTileLabels(): boolean;
71
+ /**
72
+ * @deprecated - use refHasRangeLabels
73
+ */
74
+ hasRangeLabels(): boolean;
75
+ /**
76
+ * @deprecated - use refHasTileLabel
77
+ */
78
+ hasTileLabel(label: string): boolean;
79
+ /**
80
+ * @deprecated - use refHasRangeLabel
81
+ */
82
+ hasRangeLabel(label: string): boolean;
83
+ /**
84
+ * @deprecated - use refGetTileLabels
85
+ */
86
+ getTileLabels(): string[] | undefined;
87
+ /**
88
+ * @deprecated - use refGetRangeLabels
89
+ */
90
+ getRangeLabels(): string[] | undefined;
91
+ }
92
+
93
+ export type RangeStackMap = MapLike<Stack<ReferencePosition>>;
94
+ export const DetachedReferencePosition = -1;
95
+
96
+ export function minReferencePosition<T extends ReferencePosition>(a: T, b: T): T {
97
+ if (compareReferencePositions(a, b) < 0) {
98
+ return a;
99
+ } else {
100
+ return b;
101
+ }
102
+ }
103
+
104
+ export function maxReferencePosition<T extends ReferencePosition>(a: T, b: T): T {
105
+ if (compareReferencePositions(a, b) > 0) {
106
+ return a;
107
+ } else {
108
+ return b;
109
+ }
110
+ }
111
+
112
+ export function compareReferencePositions(a: ReferencePosition, b: ReferencePosition): number {
113
+ const aSeg = a.getSegment();
114
+ const bSeg = b.getSegment();
115
+ if (aSeg === bSeg) {
116
+ return a.getOffset() - b.getOffset();
117
+ } else {
118
+ if (aSeg === undefined
119
+ || (bSeg !== undefined &&
120
+ aSeg.ordinal < bSeg.ordinal)) {
121
+ return -1;
122
+ } else {
123
+ return 1;
124
+ }
125
+ }
126
+ }
@@ -20,7 +20,7 @@ export type JsonSegmentSpecs = IJSONSegment | IJSONSegmentWithMergeInfo;
20
20
 
21
21
  export interface MergeTreeChunkLegacy extends VersionedMergeTreeChunk {
22
22
  version: undefined;
23
- chunkStartSegmentIndex: number,
23
+ chunkStartSegmentIndex: number;
24
24
  chunkSegmentCount: number;
25
25
  chunkLengthChars: number;
26
26
  totalLengthChars?: number;
@@ -32,19 +32,19 @@ export interface MergeTreeChunkLegacy extends VersionedMergeTreeChunk {
32
32
  }
33
33
 
34
34
  export interface MergeTreeHeaderChunkMetadata {
35
- id: string,
35
+ id: string;
36
36
  }
37
37
 
38
38
  export interface MergeTreeHeaderMetadata {
39
- totalLength: number,
40
- totalSegmentCount: number,
41
- orderedChunkMetadata: MergeTreeHeaderChunkMetadata[],
42
- sequenceNumber: number,
43
- minSequenceNumber: number,
39
+ totalLength: number;
40
+ totalSegmentCount: number;
41
+ orderedChunkMetadata: MergeTreeHeaderChunkMetadata[];
42
+ sequenceNumber: number;
43
+ minSequenceNumber: number;
44
44
  }
45
45
 
46
46
  export interface MergeTreeChunkV1 extends VersionedMergeTreeChunk {
47
- version: "1",
47
+ version: "1";
48
48
  startIndex: number;
49
49
  segmentCount: number;
50
50
  length: number;
@@ -38,18 +38,18 @@ export class SnapshotLoader {
38
38
 
39
39
  public async initialize(
40
40
  services: IChannelStorageService,
41
- ): Promise<{ catchupOpsP: Promise<ISequencedDocumentMessage[]> }> {
41
+ ): Promise<{ catchupOpsP: Promise<ISequencedDocumentMessage[]>; }> {
42
42
  const headerLoadedP =
43
43
  services.readBlob(SnapshotLegacy.header).then((header) => {
44
44
  assert(!!header, 0x05f /* "Missing blob header on legacy snapshot!" */);
45
- return this.loadHeader(bufferToString(header,"utf8"));
45
+ return this.loadHeader(bufferToString(header, "utf8"));
46
46
  });
47
47
 
48
48
  const catchupOpsP =
49
49
  this.loadBodyAndCatchupOps(headerLoadedP, services);
50
50
 
51
51
  catchupOpsP.catch(
52
- (err)=>this.logger.sendErrorEvent({ eventName: "CatchupOpsLoadFailure" },err));
52
+ (err) => this.logger.sendErrorEvent({ eventName: "CatchupOpsLoadFailure" }, err));
53
53
 
54
54
  await headerLoadedP;
55
55
 
@@ -111,7 +111,7 @@ export class SnapshotLoader {
111
111
  }
112
112
  if (spec.removedClientIds !== undefined) {
113
113
  seg.removedClientIds = spec.removedClientIds?.map(
114
- (sid)=> this.client.getOrAddShortClientId(sid));
114
+ (sid) => this.client.getOrAddShortClientId(sid));
115
115
  }
116
116
  } else {
117
117
  seg = this.client.specToSegment(spec);
package/src/snapshotV1.ts CHANGED
@@ -225,7 +225,7 @@ export class SnapshotV1 {
225
225
  ? this.getLongClientId(segment.removedClientIds[0])
226
226
  : undefined;
227
227
 
228
- raw.removedClientIds = segment.removedClientIds?.map((id)=>this.getLongClientId(id));
228
+ raw.removedClientIds = segment.removedClientIds?.map((id) => this.getLongClientId(id));
229
229
  }
230
230
 
231
231
  // Sanity check that we are preserving either the seq < minSeq or a removed segment's info.
@@ -131,7 +131,7 @@ export class SnapshotLegacy {
131
131
  segments === chunk1.totalSegmentCount,
132
132
  0x05e /* "emit: mismatch in totalSegmentCount" */);
133
133
 
134
- if(catchUpMsgs !== undefined && catchUpMsgs.length > 0) {
134
+ if (catchUpMsgs !== undefined && catchUpMsgs.length > 0) {
135
135
  builder.addBlob(
136
136
  this.mergeTree.options?.catchUpBlobName ?? SnapshotLegacy.catchupOps,
137
137
  serializer ? serializer.stringify(catchUpMsgs, bind) : JSON.stringify(catchUpMsgs));
@@ -157,7 +157,7 @@ export class SnapshotLegacy {
157
157
  if ((segment.seq !== UnassignedSequenceNumber) && (segment.seq! <= this.seq!) &&
158
158
  ((segment.removedSeq === undefined) || (segment.removedSeq === UnassignedSequenceNumber) ||
159
159
  (segment.removedSeq > this.seq!))) {
160
- if (prev && prev.canAppend(segment)
160
+ if (prev?.canAppend(segment)
161
161
  && matchProperties(prev.properties, segment.properties)
162
162
  ) {
163
163
  prev = prev.clone();