@fluidframework/merge-tree 1.2.6 → 2.0.0-dev.1.3.0.96595

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 (244) hide show
  1. package/.mocharc.js +12 -0
  2. package/README.md +2 -2
  3. package/dist/MergeTreeTextHelper.d.ts +23 -0
  4. package/dist/MergeTreeTextHelper.d.ts.map +1 -0
  5. package/dist/MergeTreeTextHelper.js +133 -0
  6. package/dist/MergeTreeTextHelper.js.map +1 -0
  7. package/dist/base.d.ts +2 -26
  8. package/dist/base.d.ts.map +1 -1
  9. package/dist/base.js.map +1 -1
  10. package/dist/client.d.ts +27 -16
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +81 -101
  13. package/dist/client.js.map +1 -1
  14. package/dist/collections/heap.d.ts +28 -0
  15. package/dist/collections/heap.d.ts.map +1 -0
  16. package/dist/collections/heap.js +65 -0
  17. package/dist/collections/heap.js.map +1 -0
  18. package/dist/collections/index.d.ts +11 -0
  19. package/dist/collections/index.d.ts.map +1 -0
  20. package/dist/collections/index.js +23 -0
  21. package/dist/collections/index.js.map +1 -0
  22. package/dist/collections/intervalTree.d.ts +60 -0
  23. package/dist/collections/intervalTree.d.ts.map +1 -0
  24. package/dist/collections/intervalTree.js +99 -0
  25. package/dist/collections/intervalTree.js.map +1 -0
  26. package/dist/collections/list.d.ts +39 -0
  27. package/dist/collections/list.d.ts.map +1 -0
  28. package/dist/collections/list.js +155 -0
  29. package/dist/collections/list.js.map +1 -0
  30. package/dist/collections/rbTree.d.ts +154 -0
  31. package/dist/collections/rbTree.d.ts.map +1 -0
  32. package/dist/{collections.js → collections/rbTree.js} +15 -478
  33. package/dist/collections/rbTree.js.map +1 -0
  34. package/dist/collections/stack.d.ts +16 -0
  35. package/dist/collections/stack.d.ts.map +1 -0
  36. package/dist/collections/stack.js +30 -0
  37. package/dist/collections/stack.js.map +1 -0
  38. package/dist/collections/tst.d.ts +55 -0
  39. package/dist/collections/tst.d.ts.map +1 -0
  40. package/dist/collections/tst.js +171 -0
  41. package/dist/collections/tst.js.map +1 -0
  42. package/dist/index.d.ts +3 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +4 -2
  45. package/dist/index.js.map +1 -1
  46. package/dist/localReference.d.ts +48 -99
  47. package/dist/localReference.d.ts.map +1 -1
  48. package/dist/localReference.js +132 -169
  49. package/dist/localReference.js.map +1 -1
  50. package/dist/mergeTree.d.ts +71 -302
  51. package/dist/mergeTree.d.ts.map +1 -1
  52. package/dist/mergeTree.js +395 -642
  53. package/dist/mergeTree.js.map +1 -1
  54. package/dist/mergeTreeDeltaCallback.d.ts +1 -1
  55. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  56. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  57. package/dist/mergeTreeNodes.d.ts +344 -0
  58. package/dist/mergeTreeNodes.d.ts.map +1 -0
  59. package/dist/mergeTreeNodes.js +383 -0
  60. package/dist/mergeTreeNodes.js.map +1 -0
  61. package/dist/mergeTreeTracking.d.ts +1 -1
  62. package/dist/mergeTreeTracking.d.ts.map +1 -1
  63. package/dist/mergeTreeTracking.js.map +1 -1
  64. package/dist/opBuilder.d.ts +1 -1
  65. package/dist/opBuilder.d.ts.map +1 -1
  66. package/dist/opBuilder.js.map +1 -1
  67. package/dist/partialLengths.d.ts +188 -18
  68. package/dist/partialLengths.d.ts.map +1 -1
  69. package/dist/partialLengths.js +495 -253
  70. package/dist/partialLengths.js.map +1 -1
  71. package/dist/properties.d.ts.map +1 -1
  72. package/dist/properties.js.map +1 -1
  73. package/dist/referencePositions.d.ts +6 -26
  74. package/dist/referencePositions.d.ts.map +1 -1
  75. package/dist/referencePositions.js +3 -20
  76. package/dist/referencePositions.js.map +1 -1
  77. package/dist/segmentGroupCollection.d.ts +3 -1
  78. package/dist/segmentGroupCollection.d.ts.map +1 -1
  79. package/dist/segmentGroupCollection.js +14 -1
  80. package/dist/segmentGroupCollection.js.map +1 -1
  81. package/dist/segmentPropertiesManager.d.ts +10 -1
  82. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  83. package/dist/segmentPropertiesManager.js +42 -13
  84. package/dist/segmentPropertiesManager.js.map +1 -1
  85. package/dist/snapshotChunks.d.ts +2 -1
  86. package/dist/snapshotChunks.d.ts.map +1 -1
  87. package/dist/snapshotChunks.js.map +1 -1
  88. package/dist/snapshotLoader.d.ts.map +1 -1
  89. package/dist/snapshotLoader.js.map +1 -1
  90. package/dist/snapshotV1.d.ts +1 -1
  91. package/dist/snapshotV1.d.ts.map +1 -1
  92. package/dist/snapshotV1.js +1 -1
  93. package/dist/snapshotV1.js.map +1 -1
  94. package/dist/snapshotlegacy.d.ts +5 -1
  95. package/dist/snapshotlegacy.d.ts.map +1 -1
  96. package/dist/snapshotlegacy.js +4 -0
  97. package/dist/snapshotlegacy.js.map +1 -1
  98. package/dist/sortedSegmentSet.d.ts +1 -1
  99. package/dist/sortedSegmentSet.d.ts.map +1 -1
  100. package/dist/sortedSegmentSet.js.map +1 -1
  101. package/dist/textSegment.d.ts +7 -7
  102. package/dist/textSegment.d.ts.map +1 -1
  103. package/dist/textSegment.js +3 -125
  104. package/dist/textSegment.js.map +1 -1
  105. package/{DEV.md → docs/DEV.md} +2 -2
  106. package/docs/Obliterate.md +639 -0
  107. package/{REFERENCEPOSITIONS.md → docs/REFERENCEPOSITIONS.md} +2 -2
  108. package/lib/MergeTreeTextHelper.d.ts +23 -0
  109. package/lib/MergeTreeTextHelper.d.ts.map +1 -0
  110. package/lib/MergeTreeTextHelper.js +129 -0
  111. package/lib/MergeTreeTextHelper.js.map +1 -0
  112. package/lib/base.d.ts +2 -26
  113. package/lib/base.d.ts.map +1 -1
  114. package/lib/base.js.map +1 -1
  115. package/lib/client.d.ts +27 -16
  116. package/lib/client.d.ts.map +1 -1
  117. package/lib/client.js +79 -99
  118. package/lib/client.js.map +1 -1
  119. package/lib/collections/heap.d.ts +28 -0
  120. package/lib/collections/heap.d.ts.map +1 -0
  121. package/lib/collections/heap.js +61 -0
  122. package/lib/collections/heap.js.map +1 -0
  123. package/lib/collections/index.d.ts +11 -0
  124. package/lib/collections/index.d.ts.map +1 -0
  125. package/lib/collections/index.js +11 -0
  126. package/lib/collections/index.js.map +1 -0
  127. package/lib/collections/intervalTree.d.ts +60 -0
  128. package/lib/collections/intervalTree.d.ts.map +1 -0
  129. package/lib/collections/intervalTree.js +94 -0
  130. package/lib/collections/intervalTree.js.map +1 -0
  131. package/lib/collections/list.d.ts +39 -0
  132. package/lib/collections/list.d.ts.map +1 -0
  133. package/lib/collections/list.js +149 -0
  134. package/lib/collections/list.js.map +1 -0
  135. package/lib/collections/rbTree.d.ts +154 -0
  136. package/lib/collections/rbTree.d.ts.map +1 -0
  137. package/lib/{collections.js → collections/rbTree.js} +14 -469
  138. package/lib/collections/rbTree.js.map +1 -0
  139. package/lib/collections/stack.d.ts +16 -0
  140. package/lib/collections/stack.d.ts.map +1 -0
  141. package/lib/collections/stack.js +26 -0
  142. package/lib/collections/stack.js.map +1 -0
  143. package/lib/collections/tst.d.ts +55 -0
  144. package/lib/collections/tst.d.ts.map +1 -0
  145. package/lib/collections/tst.js +167 -0
  146. package/lib/collections/tst.js.map +1 -0
  147. package/lib/index.d.ts +3 -1
  148. package/lib/index.d.ts.map +1 -1
  149. package/lib/index.js +3 -1
  150. package/lib/index.js.map +1 -1
  151. package/lib/localReference.d.ts +48 -99
  152. package/lib/localReference.d.ts.map +1 -1
  153. package/lib/localReference.js +132 -170
  154. package/lib/localReference.js.map +1 -1
  155. package/lib/mergeTree.d.ts +71 -302
  156. package/lib/mergeTree.d.ts.map +1 -1
  157. package/lib/mergeTree.js +371 -607
  158. package/lib/mergeTree.js.map +1 -1
  159. package/lib/mergeTreeDeltaCallback.d.ts +1 -1
  160. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  161. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  162. package/lib/mergeTreeNodes.d.ts +344 -0
  163. package/lib/mergeTreeNodes.d.ts.map +1 -0
  164. package/lib/mergeTreeNodes.js +369 -0
  165. package/lib/mergeTreeNodes.js.map +1 -0
  166. package/lib/mergeTreeTracking.d.ts +1 -1
  167. package/lib/mergeTreeTracking.d.ts.map +1 -1
  168. package/lib/mergeTreeTracking.js.map +1 -1
  169. package/lib/opBuilder.d.ts +1 -1
  170. package/lib/opBuilder.d.ts.map +1 -1
  171. package/lib/opBuilder.js.map +1 -1
  172. package/lib/partialLengths.d.ts +188 -18
  173. package/lib/partialLengths.d.ts.map +1 -1
  174. package/lib/partialLengths.js +491 -249
  175. package/lib/partialLengths.js.map +1 -1
  176. package/lib/properties.d.ts.map +1 -1
  177. package/lib/properties.js.map +1 -1
  178. package/lib/referencePositions.d.ts +6 -26
  179. package/lib/referencePositions.d.ts.map +1 -1
  180. package/lib/referencePositions.js +3 -20
  181. package/lib/referencePositions.js.map +1 -1
  182. package/lib/segmentGroupCollection.d.ts +3 -1
  183. package/lib/segmentGroupCollection.d.ts.map +1 -1
  184. package/lib/segmentGroupCollection.js +14 -1
  185. package/lib/segmentGroupCollection.js.map +1 -1
  186. package/lib/segmentPropertiesManager.d.ts +10 -1
  187. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  188. package/lib/segmentPropertiesManager.js +42 -13
  189. package/lib/segmentPropertiesManager.js.map +1 -1
  190. package/lib/snapshotChunks.d.ts +2 -1
  191. package/lib/snapshotChunks.d.ts.map +1 -1
  192. package/lib/snapshotChunks.js.map +1 -1
  193. package/lib/snapshotLoader.d.ts.map +1 -1
  194. package/lib/snapshotLoader.js.map +1 -1
  195. package/lib/snapshotV1.d.ts +1 -1
  196. package/lib/snapshotV1.d.ts.map +1 -1
  197. package/lib/snapshotV1.js +1 -1
  198. package/lib/snapshotV1.js.map +1 -1
  199. package/lib/snapshotlegacy.d.ts +5 -1
  200. package/lib/snapshotlegacy.d.ts.map +1 -1
  201. package/lib/snapshotlegacy.js +4 -0
  202. package/lib/snapshotlegacy.js.map +1 -1
  203. package/lib/sortedSegmentSet.d.ts +1 -1
  204. package/lib/sortedSegmentSet.d.ts.map +1 -1
  205. package/lib/sortedSegmentSet.js.map +1 -1
  206. package/lib/textSegment.d.ts +7 -7
  207. package/lib/textSegment.d.ts.map +1 -1
  208. package/lib/textSegment.js +1 -122
  209. package/lib/textSegment.js.map +1 -1
  210. package/package.json +99 -20
  211. package/src/MergeTreeTextHelper.ts +170 -0
  212. package/src/base.ts +2 -35
  213. package/src/client.ts +91 -111
  214. package/src/collections/heap.ts +75 -0
  215. package/src/collections/index.ts +11 -0
  216. package/src/collections/intervalTree.ts +146 -0
  217. package/src/collections/list.ts +165 -0
  218. package/src/{collections.ts → collections/rbTree.ts} +84 -563
  219. package/src/collections/stack.ts +27 -0
  220. package/src/collections/tst.ts +212 -0
  221. package/src/index.ts +8 -2
  222. package/src/localReference.ts +152 -203
  223. package/src/mergeTree.ts +578 -996
  224. package/src/mergeTreeDeltaCallback.ts +1 -1
  225. package/src/mergeTreeNodes.ts +752 -0
  226. package/src/mergeTreeTracking.ts +1 -1
  227. package/src/opBuilder.ts +1 -1
  228. package/src/partialLengths.ts +631 -258
  229. package/src/properties.ts +1 -0
  230. package/src/referencePositions.ts +10 -44
  231. package/src/segmentGroupCollection.ts +17 -2
  232. package/src/segmentPropertiesManager.ts +46 -12
  233. package/src/snapshotChunks.ts +2 -1
  234. package/src/snapshotLoader.ts +2 -1
  235. package/src/snapshotV1.ts +3 -3
  236. package/src/snapshotlegacy.ts +6 -2
  237. package/src/sortedSegmentSet.ts +1 -1
  238. package/src/textSegment.ts +10 -157
  239. package/dist/collections.d.ts +0 -197
  240. package/dist/collections.d.ts.map +0 -1
  241. package/dist/collections.js.map +0 -1
  242. package/lib/collections.d.ts +0 -197
  243. package/lib/collections.d.ts.map +0 -1
  244. package/lib/collections.js.map +0 -1
package/src/properties.ts CHANGED
@@ -95,6 +95,7 @@ export function matchProperties(a: PropertySet | undefined, b: PropertySet | und
95
95
  return false;
96
96
  }
97
97
  }
98
+
98
99
  return true;
99
100
  }
100
101
 
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { Stack } from "./collections";
7
- import { ISegment } from "./mergeTree";
7
+ import { ISegment } from "./mergeTreeNodes";
8
8
  import { ReferenceType, ICombiningOp } from "./ops";
9
9
  import { PropertySet, MapLike } from "./properties";
10
10
 
@@ -63,51 +63,23 @@ export interface ReferencePosition {
63
63
  getSegment(): ISegment | undefined;
64
64
  getOffset(): number;
65
65
  addProperties(newProps: PropertySet, op?: ICombiningOp): void;
66
- isLeaf(): boolean;
67
-
68
- /**
69
- * @deprecated - use refHasTileLabels
70
- */
71
- hasTileLabels(): boolean;
72
- /**
73
- * @deprecated - use refHasRangeLabels
74
- */
75
- hasRangeLabels(): boolean;
76
- /**
77
- * @deprecated - use refHasTileLabel
78
- */
79
- hasTileLabel(label: string): boolean;
80
- /**
81
- * @deprecated - use refHasRangeLabel
82
- */
83
- hasRangeLabel(label: string): boolean;
84
- /**
85
- * @deprecated - use refGetTileLabels
86
- */
87
- getTileLabels(): string[] | undefined;
88
- /**
89
- * @deprecated - use refGetRangeLabels
90
- */
91
- getRangeLabels(): string[] | undefined;
66
+ isLeaf(): this is ISegment;
92
67
  }
93
68
 
69
+ /**
70
+ * @deprecated for internal use only. public export will be removed.
71
+ * @internal
72
+ */
94
73
  export type RangeStackMap = MapLike<Stack<ReferencePosition>>;
74
+
95
75
  export const DetachedReferencePosition = -1;
96
76
 
97
77
  export function minReferencePosition<T extends ReferencePosition>(a: T, b: T): T {
98
- if (compareReferencePositions(a, b) < 0) {
99
- return a;
100
- } else {
101
- return b;
102
- }
78
+ return compareReferencePositions(a, b) < 0 ? a : b;
103
79
  }
104
80
 
105
81
  export function maxReferencePosition<T extends ReferencePosition>(a: T, b: T): T {
106
- if (compareReferencePositions(a, b) > 0) {
107
- return a;
108
- } else {
109
- return b;
110
- }
82
+ return compareReferencePositions(a, b) > 0 ? a : b;
111
83
  }
112
84
 
113
85
  export function compareReferencePositions(a: ReferencePosition, b: ReferencePosition): number {
@@ -116,12 +88,6 @@ export function compareReferencePositions(a: ReferencePosition, b: ReferencePosi
116
88
  if (aSeg === bSeg) {
117
89
  return a.getOffset() - b.getOffset();
118
90
  } else {
119
- if (aSeg === undefined
120
- || (bSeg !== undefined &&
121
- aSeg.ordinal < bSeg.ordinal)) {
122
- return -1;
123
- } else {
124
- return 1;
125
- }
91
+ return aSeg === undefined || (bSeg !== undefined && aSeg.ordinal < bSeg.ordinal) ? -1 : 1;
126
92
  }
127
93
  }
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { List, ListMakeHead } from "./collections";
7
- import { ISegment, SegmentGroup } from "./mergeTree";
7
+ import { ISegment, SegmentGroup } from "./mergeTreeNodes";
8
8
 
9
9
  export class SegmentGroupCollection {
10
10
  private readonly segmentGroups: List<SegmentGroup>;
@@ -30,11 +30,26 @@ export class SegmentGroupCollection {
30
30
  return this.segmentGroups.dequeue();
31
31
  }
32
32
 
33
+ public pop?(): SegmentGroup | undefined {
34
+ return this.segmentGroups.pop ? this.segmentGroups.pop() : undefined;
35
+ }
36
+
33
37
  public clear() {
34
38
  this.segmentGroups.clear();
35
39
  }
36
40
 
37
41
  public copyTo(segment: ISegment) {
38
- this.segmentGroups.walk((sg) => segment.segmentGroups.enqueue(sg));
42
+ this.segmentGroups.walk((sg) => segment.segmentGroups.enqueueOnCopy(sg, this.segment));
43
+ }
44
+
45
+ private enqueueOnCopy(segmentGroup: SegmentGroup, sourceSegment: ISegment) {
46
+ this.enqueue(segmentGroup);
47
+ if (segmentGroup.previousProps) {
48
+ // duplicate the previousProps for this segment
49
+ const index = segmentGroup.segments.indexOf(sourceSegment);
50
+ if (index !== -1) {
51
+ segmentGroup.previousProps.push(segmentGroup.previousProps[index]);
52
+ }
53
+ }
39
54
  }
40
55
  }
@@ -6,7 +6,7 @@
6
6
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
7
7
 
8
8
  import { assert } from "@fluidframework/common-utils";
9
- import { UnassignedSequenceNumber } from "./constants";
9
+ import { UnassignedSequenceNumber, UniversalSequenceNumber } from "./constants";
10
10
  import { ICombiningOp, IMergeTreeAnnotateMsg } from "./ops";
11
11
  import {
12
12
  combine,
@@ -15,6 +15,17 @@ import {
15
15
  PropertySet,
16
16
  } from "./properties";
17
17
 
18
+ export enum PropertiesRollback {
19
+ /** Not in a rollback */
20
+ None,
21
+
22
+ /** Rollback */
23
+ Rollback,
24
+
25
+ /** Rollback of a rewrite */
26
+ Rewrite,
27
+ }
28
+
18
29
  export class PropertiesManager {
19
30
  private pendingKeyUpdateCount: MapLike<number> | undefined;
20
31
  private pendingRewriteCount: number;
@@ -24,11 +35,20 @@ export class PropertiesManager {
24
35
  }
25
36
 
26
37
  public ackPendingProperties(annotateOp: IMergeTreeAnnotateMsg) {
27
- if (annotateOp.combiningOp && annotateOp.combiningOp.name === "rewrite") {
38
+ const rewrite = !!annotateOp.combiningOp && annotateOp.combiningOp.name === "rewrite";
39
+ this.decrementPendingCounts(rewrite, annotateOp.props);
40
+ }
41
+
42
+ private decrementPendingCounts(rewrite: boolean, props: PropertySet) {
43
+ if (rewrite) {
28
44
  this.pendingRewriteCount--;
29
45
  }
30
- for (const key of Object.keys(annotateOp.props)) {
46
+ for (const key of Object.keys(props)) {
31
47
  if (this.pendingKeyUpdateCount?.[key] !== undefined) {
48
+ if (rewrite && props[key] === null) {
49
+ // We don't track the pending count for this redundant case
50
+ continue;
51
+ }
32
52
  assert(this.pendingKeyUpdateCount[key] > 0,
33
53
  0x05c /* "Trying to update more annotate props than do exist!" */);
34
54
  this.pendingKeyUpdateCount[key]--;
@@ -45,21 +65,35 @@ export class PropertiesManager {
45
65
  newProps: PropertySet,
46
66
  op?: ICombiningOp,
47
67
  seq?: number,
48
- collaborating: boolean = false): PropertySet | undefined {
68
+ collaborating: boolean = false,
69
+ rollback: PropertiesRollback = PropertiesRollback.None): PropertySet | undefined {
49
70
  if (!this.pendingKeyUpdateCount) {
50
71
  this.pendingKeyUpdateCount = createMap<number>();
51
72
  }
52
73
 
53
74
  // There are outstanding local rewrites, so block all non-local changes
54
- if (this.pendingRewriteCount > 0 && seq !== UnassignedSequenceNumber && collaborating) {
75
+ if (this.pendingRewriteCount > 0 && seq !== UnassignedSequenceNumber && seq !== UniversalSequenceNumber
76
+ && collaborating) {
55
77
  return undefined;
56
78
  }
57
79
 
80
+ // Clean up counts for rolled back edits before modifying oldProps
81
+ if (collaborating) {
82
+ if (rollback === PropertiesRollback.Rollback) {
83
+ this.decrementPendingCounts(false, newProps);
84
+ } else if (rollback === PropertiesRollback.Rewrite) {
85
+ // oldProps is the correct props for tracking counts on rewrite because the ones in newProps include
86
+ // those that were implicitly cleared by the rewrite for which we don't track pending counts.
87
+ this.decrementPendingCounts(true, oldProps);
88
+ }
89
+ }
90
+
58
91
  const rewrite = (op && op.name === "rewrite");
59
92
  const combiningOp = !rewrite ? op ? op : undefined : undefined;
60
93
 
61
94
  const shouldModifyKey = (key: string): boolean => {
62
95
  if (seq === UnassignedSequenceNumber
96
+ || seq === UniversalSequenceNumber
63
97
  || this.pendingKeyUpdateCount?.[key] === undefined
64
98
  || combiningOp) {
65
99
  return true;
@@ -87,6 +121,11 @@ export class PropertiesManager {
87
121
  for (const key of Object.keys(newProps)) {
88
122
  if (collaborating) {
89
123
  if (seq === UnassignedSequenceNumber) {
124
+ if (rewrite && newProps[key] === null) {
125
+ // This case has already been handled above and
126
+ // we don't want to track the pending count for it in case of rollback
127
+ continue;
128
+ }
90
129
  if (this.pendingKeyUpdateCount?.[key] === undefined) {
91
130
  this.pendingKeyUpdateCount[key] = 0;
92
131
  }
@@ -97,14 +136,9 @@ export class PropertiesManager {
97
136
  }
98
137
 
99
138
  const previousValue: any = oldProps[key];
100
- // The delta should be null if undefined, as thats how we encode delete
139
+ // The delta should be null if undefined, as that's how we encode delete
101
140
  deltas[key] = (previousValue === undefined) ? null : previousValue;
102
- let newValue: any;
103
- if (combiningOp) {
104
- newValue = combine(combiningOp, previousValue, newValue, seq);
105
- } else {
106
- newValue = newProps[key];
107
- }
141
+ const newValue = combiningOp ? combine(combiningOp, previousValue, undefined, seq) : newProps[key];
108
142
  if (newValue === null) {
109
143
  // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
110
144
  delete oldProps[key];
@@ -63,7 +63,8 @@ export interface IJSONSegmentWithMergeInfo {
63
63
  client?: string;
64
64
  seq?: number;
65
65
  /**
66
- * @deprecated - use removedClientIds instead. this only exists for back-compat
66
+ * @deprecated Use {@link IJSONSegmentWithMergeInfo.removedClientIds} instead.
67
+ * This only exists for backwards compatability.
67
68
  */
68
69
  removedClient?: string;
69
70
  removedClientIds?: string[];
@@ -14,7 +14,7 @@ import { ITelemetryLogger } from "@fluidframework/common-definitions";
14
14
  import { AttachState } from "@fluidframework/container-definitions";
15
15
  import { Client } from "./client";
16
16
  import { NonCollabClient, UniversalSequenceNumber } from "./constants";
17
- import { ISegment, MergeTree } from "./mergeTree";
17
+ import { ISegment } from "./mergeTreeNodes";
18
18
  import { IJSONSegment } from "./ops";
19
19
  import {
20
20
  IJSONSegmentWithMergeInfo,
@@ -23,6 +23,7 @@ import {
23
23
  } from "./snapshotChunks";
24
24
  import { SnapshotV1 } from "./snapshotV1";
25
25
  import { SnapshotLegacy } from "./snapshotlegacy";
26
+ import { MergeTree } from "./mergeTree";
26
27
 
27
28
  export class SnapshotLoader {
28
29
  private readonly logger: ITelemetryLogger;
package/src/snapshotV1.ts CHANGED
@@ -14,8 +14,7 @@ import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
14
14
  import { UnassignedSequenceNumber } from "./constants";
15
15
  import {
16
16
  ISegment,
17
- MergeTree,
18
- } from "./mergeTree";
17
+ } from "./mergeTreeNodes";
19
18
  import {
20
19
  matchProperties,
21
20
  PropertySet,
@@ -29,6 +28,7 @@ import {
29
28
  serializeAsMaxSupportedVersion,
30
29
  } from "./snapshotChunks";
31
30
  import { SnapshotLegacy } from "./snapshotlegacy";
31
+ import { MergeTree } from "./mergeTree";
32
32
 
33
33
  export class SnapshotV1 {
34
34
  // Split snapshot into two entries - headers (small) and body (overflow) for faster loading initial content
@@ -200,7 +200,7 @@ export class SnapshotV1 {
200
200
  prev = segment;
201
201
  }
202
202
  } else {
203
- // This segment needs to preserve it's metadata as it may be referenced by future ops. It's ineligible
203
+ // This segment needs to preserve its metadata as it may be referenced by future ops. It's ineligible
204
204
  // for coalescing, so emit the 'prev' segment now (if any).
205
205
  pushSeg(prev);
206
206
  prev = undefined;
@@ -16,14 +16,14 @@ import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
16
16
  import { NonCollabClient, UnassignedSequenceNumber } from "./constants";
17
17
  import {
18
18
  ISegment,
19
- MergeTree,
20
- } from "./mergeTree";
19
+ } from "./mergeTreeNodes";
21
20
  import { IJSONSegment } from "./ops";
22
21
  import { matchProperties } from "./properties";
23
22
  import {
24
23
  MergeTreeChunkLegacy,
25
24
  serializeAsMinSupportedVersion,
26
25
  } from "./snapshotChunks";
26
+ import { MergeTree } from "./mergeTree";
27
27
 
28
28
  interface SnapshotHeader {
29
29
  chunkCount?: number;
@@ -36,6 +36,10 @@ interface SnapshotHeader {
36
36
  minSeq?: number;
37
37
  }
38
38
 
39
+ /**
40
+ * @deprecated for internal use only. public export will be removed.
41
+ * @internal
42
+ */
39
43
  export class SnapshotLegacy {
40
44
  public static readonly header = "header";
41
45
  public static readonly body = "body";
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ISegment } from "./mergeTree";
6
+ import { ISegment } from "./mergeTreeNodes";
7
7
 
8
8
  /**
9
9
  * Stores a unique and sorted set of segments, or objects with segments
@@ -3,8 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IIntegerRange } from "./base";
7
- import { BaseSegment, ISegment, Marker, MergeTree } from "./mergeTree";
6
+ import { BaseSegment, ISegment, Marker } from "./mergeTreeNodes";
8
7
  import { IJSONSegment } from "./ops";
9
8
  import { PropertySet } from "./properties";
10
9
  import { LocalReferenceCollection } from "./localReference";
@@ -121,159 +120,13 @@ export class TextSegment extends BaseSegment {
121
120
  }
122
121
  }
123
122
 
124
- interface ITextAccumulator {
125
- textSegment: TextSegment;
126
- placeholder?: string;
127
- parallelArrays?: boolean;
128
- }
129
-
130
- interface ITextAndMarkerAccumulator extends ITextAccumulator {
131
- parallelArrays: true;
132
- parallelText: string[];
133
- parallelMarkers: Marker[];
134
- parallelMarkerLabel: string;
135
- tagsInProgress: string[];
136
- }
137
-
138
- function isTextAndMarkerAccumulator(accum: ITextAccumulator): accum is ITextAndMarkerAccumulator {
139
- return accum.parallelArrays === true;
140
- }
141
-
142
- type ITextAccumulatorType = ITextAccumulator | ITextAndMarkerAccumulator;
143
- export class MergeTreeTextHelper {
144
- constructor(private readonly mergeTree: MergeTree) { }
145
-
146
- public getTextAndMarkers(refSeq: number, clientId: number, label: string, start?: number, end?: number) {
147
- const range = this.getValidRange(start, end, refSeq, clientId);
148
- const accum: ITextAndMarkerAccumulator = {
149
- parallelArrays: true,
150
- parallelMarkerLabel: label,
151
- parallelMarkers: [],
152
- parallelText: [],
153
- tagsInProgress: [],
154
- textSegment: new TextSegment(""),
155
- };
156
-
157
- this.mergeTree.mapRange<ITextAndMarkerAccumulator>(
158
- { leaf: this.gatherText },
159
- refSeq,
160
- clientId,
161
- accum,
162
- range.start,
163
- range.end);
164
-
165
- return { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };
166
- }
167
-
168
- public getText(refSeq: number, clientId: number, placeholder = "", start?: number, end?: number) {
169
- const range = this.getValidRange(start, end, refSeq, clientId);
170
-
171
- const accum: ITextAccumulator = { textSegment: new TextSegment(""), placeholder };
172
-
173
- this.mergeTree.mapRange<ITextAccumulator>(
174
- { leaf: this.gatherText },
175
- refSeq,
176
- clientId,
177
- accum,
178
- range.start,
179
- range.end);
180
- return accum.textSegment.text;
181
- }
182
-
183
- private getValidRange(
184
- start: number | undefined,
185
- end: number | undefined,
186
- refSeq: number,
187
- clientId: number,
188
- ): IIntegerRange {
189
- const range: IIntegerRange = {
190
- end: end ?? this.mergeTree.getLength(refSeq, clientId),
191
- start: start ?? 0,
192
- };
193
- return range;
194
- }
195
-
196
- private readonly gatherText = (segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,
197
- end: number, accumText: ITextAccumulatorType) => {
198
- let _start = start;
199
- if (TextSegment.is(segment)) {
200
- let beginTags = "";
201
- let endTags = "";
202
- if (isTextAndMarkerAccumulator(accumText)) {
203
- // TODO: let clients pass in function to get tag
204
- const tags = [] as string[];
205
- const initTags = [] as string[];
206
-
207
- if (segment.properties?.["font-weight"]) {
208
- tags.push("b");
209
- }
210
- if (segment.properties?.["text-decoration"]) {
211
- tags.push("u");
212
- }
213
- const remTags = [] as string[];
214
- if (tags.length > 0) {
215
- for (const tag of tags) {
216
- if (!accumText.tagsInProgress.includes(tag)) {
217
- beginTags += `<${tag}>`;
218
- initTags.push(tag);
219
- }
220
- }
221
- for (const accumTag of accumText.tagsInProgress) {
222
- if (!tags.includes(accumTag)) {
223
- endTags += `</${accumTag}>`;
224
- remTags.push(accumTag);
225
- }
226
- }
227
- for (const initTag of initTags.reverse()) {
228
- accumText.tagsInProgress.push(initTag);
229
- }
230
- } else {
231
- for (const accumTag of accumText.tagsInProgress) {
232
- endTags += `</${accumTag}>`;
233
- remTags.push(accumTag);
234
- }
235
- }
236
- for (const remTag of remTags) {
237
- const remdex = accumText.tagsInProgress.indexOf(remTag);
238
- if (remdex >= 0) {
239
- accumText.tagsInProgress.splice(remdex, 1);
240
- }
241
- }
242
- }
243
- accumText.textSegment.text += endTags;
244
- accumText.textSegment.text += beginTags;
245
- if ((_start <= 0) && (end >= segment.text.length)) {
246
- accumText.textSegment.text += segment.text;
247
- } else {
248
- if (_start < 0) {
249
- _start = 0;
250
- }
251
- if (end >= segment.text.length) {
252
- accumText.textSegment.text += segment.text.substring(_start);
253
- } else {
254
- accumText.textSegment.text += segment.text.substring(_start, end);
255
- }
256
- }
257
- } else {
258
- if (accumText.placeholder && (accumText.placeholder.length > 0)) {
259
- if (accumText.placeholder === "*") {
260
- const marker = segment as Marker;
261
- accumText.textSegment.text += `\n${marker.toString()}`;
262
- } else {
263
- for (let i = 0; i < segment.cachedLength; i++) {
264
- accumText.textSegment.text += accumText.placeholder;
265
- }
266
- }
267
- } else if (isTextAndMarkerAccumulator(accumText)) {
268
- const marker = segment as Marker;
269
- if (marker.hasTileLabel(accumText.parallelMarkerLabel)) {
270
- accumText.parallelMarkers.push(marker);
271
- accumText.parallelText.push(accumText.textSegment.text);
272
- accumText.textSegment.text = "";
273
- }
274
- }
275
- }
276
-
277
- return true;
278
- };
123
+ export interface IMergeTreeTextHelper{
124
+ /**
125
+ * @deprecated If consuming via sequence, use `getTextAndMarkers` exported from `\@fluidframework/sequence`.
126
+ * Otherwise, define your own accumulation model and use `Client.walkSegments`.
127
+ */
128
+ getTextAndMarkers(refSeq: number, clientId: number, label: string, start?: number, end?: number): {
129
+ parallelText: string[];
130
+ parallelMarkers: Marker[]; };
131
+ getText(refSeq: number, clientId: number, placeholder: string, start?: number, end?: number): string;
279
132
  }