@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
@@ -0,0 +1,752 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
7
+
8
+ /* eslint-disable @typescript-eslint/prefer-optional-chain, no-bitwise */
9
+
10
+ import { assert } from "@fluidframework/common-utils";
11
+ import {
12
+ LocalClientId,
13
+ UnassignedSequenceNumber,
14
+ UniversalSequenceNumber,
15
+ } from "./constants";
16
+ import {
17
+ LocalReferenceCollection,
18
+ LocalReferencePosition,
19
+ } from "./localReference";
20
+ import { MergeTree } from "./mergeTree";
21
+ import {
22
+ IMergeTreeDeltaOpArgs,
23
+ } from "./mergeTreeDeltaCallback";
24
+ import { TrackingGroupCollection } from "./mergeTreeTracking";
25
+ import {
26
+ ICombiningOp,
27
+ IJSONSegment,
28
+ IMarkerDef,
29
+ MergeTreeDeltaType,
30
+ ReferenceType,
31
+ } from "./ops";
32
+ import { PartialSequenceLengths } from "./partialLengths";
33
+ import {
34
+ clone,
35
+ createMap,
36
+ MapLike,
37
+ PropertySet,
38
+ } from "./properties";
39
+ import {
40
+ refTypeIncludesFlag,
41
+ RangeStackMap,
42
+ ReferencePosition,
43
+ refGetRangeLabels,
44
+ refGetTileLabels,
45
+ } from "./referencePositions";
46
+ import { SegmentGroupCollection } from "./segmentGroupCollection";
47
+ import { PropertiesManager, PropertiesRollback } from "./segmentPropertiesManager";
48
+
49
+ /**
50
+ * Common properties for a node in a merge tree.
51
+ */
52
+ export interface IMergeNodeCommon {
53
+ parent?: IMergeBlock;
54
+ /**
55
+ * The length of the contents of the node.
56
+ */
57
+ cachedLength: number;
58
+ /**
59
+ * The index of this node in its parent's list of children.
60
+ */
61
+ index: number;
62
+ /**
63
+ * A string that can be used for comparing the location of this node to other `MergeNode`s in the same tree.
64
+ * `a.ordinal < b.ordinal` if and only if `a` comes before `b` in a pre-order traversal of the tree.
65
+ */
66
+ ordinal: string;
67
+ isLeaf(): this is ISegment;
68
+ }
69
+
70
+ export type IMergeNode = IMergeBlock | ISegment;
71
+
72
+ /**
73
+ * Internal (i.e. non-leaf) node in a merge tree.
74
+ */
75
+ export interface IMergeBlock extends IMergeNodeCommon {
76
+ needsScour?: boolean;
77
+ /**
78
+ * Number of direct children of this node
79
+ */
80
+ childCount: number;
81
+ /**
82
+ * Array of child nodes.
83
+ *
84
+ * @remarks To avoid reallocation, this is always initialized to have maximum length as deemed by
85
+ * the merge tree's branching factor. Use `childCount` to determine how many children this node actually has.
86
+ */
87
+ children: IMergeNode[];
88
+ /**
89
+ * Supports querying the total length of all descendants of this IMergeBlock from the perspective of any
90
+ * (clientId, seq) within the collab window.
91
+ *
92
+ * @remarks This is only optional for implementation reasons (internal nodes can be created/moved without
93
+ * immediately initializing the partial lengths). Aside from mid-update on tree operations, these lengths
94
+ * objects are always defined.
95
+ */
96
+ partialLengths?: PartialSequenceLengths;
97
+ hierBlock(): IHierBlock | undefined;
98
+ assignChild(child: IMergeNode, index: number, updateOrdinal?: boolean): void;
99
+ setOrdinal(child: IMergeNode, index: number): void;
100
+ }
101
+
102
+ export interface IHierBlock extends IMergeBlock {
103
+ hierToString(indentCount: number): string;
104
+ /**
105
+ * @deprecated for internal use only. public export will be removed.
106
+ * @internal
107
+ */
108
+ addNodeReferences(mergeTree: MergeTree, node: IMergeNode): void;
109
+ rightmostTiles: MapLike<ReferencePosition>;
110
+ leftmostTiles: MapLike<ReferencePosition>;
111
+ /**
112
+ * @deprecated for internal use only. public export will be removed.
113
+ * @internal
114
+ */
115
+ rangeStacks: RangeStackMap;
116
+ }
117
+
118
+ /**
119
+ * Contains removal information associated to an {@link ISegment}.
120
+ */
121
+ export interface IRemovalInfo {
122
+ /**
123
+ * Local seq at which this segment was removed, if the removal is yet-to-be acked.
124
+ */
125
+ localRemovedSeq?: number;
126
+ /**
127
+ * Seq at which this segment was removed.
128
+ */
129
+ removedSeq: number;
130
+ /**
131
+ * List of client IDs that have removed this segment.
132
+ * The client that actually removed the segment (i.e. whose removal op was sequenced first) is stored as the first
133
+ * client in this list. Other clients in the list have all issued concurrent ops to remove the segment.
134
+ * @remarks When this list has length \> 1, this is referred to as the "overlapping remove" case.
135
+ */
136
+ removedClientIds: number[];
137
+ }
138
+
139
+ export function toRemovalInfo(maybe: Partial<IRemovalInfo> | undefined): IRemovalInfo | undefined {
140
+ if (maybe?.removedClientIds !== undefined && maybe?.removedSeq !== undefined) {
141
+ return maybe as IRemovalInfo;
142
+ }
143
+ assert(maybe?.removedClientIds === undefined && maybe?.removedSeq === undefined,
144
+ 0x2bf /* "both removedClientIds and removedSeq should be set or not set" */);
145
+ }
146
+
147
+ /**
148
+ * A segment representing a portion of the merge tree.
149
+ * Segments are leaf nodes of the merge tree and contain data.
150
+ */
151
+ export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo> {
152
+ readonly type: string;
153
+ readonly segmentGroups: SegmentGroupCollection;
154
+ readonly trackingCollection: TrackingGroupCollection;
155
+ /**
156
+ * Manages pending local state for properties on this segment.
157
+ */
158
+ propertyManager?: PropertiesManager;
159
+ /**
160
+ * Local seq at which this segment was inserted. If this is defined, `seq` will be UnassignedSequenceNumber.
161
+ * Once the segment is acked, this field is cleared.
162
+ */
163
+ localSeq?: number;
164
+ /**
165
+ * Local seq at which this segment was removed. If this is defined, `removedSeq` will initially be set to
166
+ * UnassignedSequenceNumber. However, if another client concurrently removes the same segment, `removedSeq`
167
+ * will be updated to the seq at which that client removed this segment.
168
+ *
169
+ * Like `localSeq`, this field is cleared once the local removal of the segment is acked.
170
+ */
171
+ localRemovedSeq?: number;
172
+ /**
173
+ * Seq at which this segment was inserted.
174
+ * If undefined, it is assumed the segment was inserted prior to the collab window's minimum sequence number.
175
+ */
176
+ seq?: number;
177
+ /**
178
+ * Short clientId for the client that inserted this segment.
179
+ */
180
+ clientId: number;
181
+ /**
182
+ * Local references added to this segment.
183
+ */
184
+ localRefs?: LocalReferenceCollection;
185
+ /**
186
+ * Properties that have been added to this segment via annotation.
187
+ */
188
+ properties?: PropertySet;
189
+ addProperties(
190
+ newProps: PropertySet,
191
+ op?: ICombiningOp,
192
+ seq?: number,
193
+ collabWindow?: CollaborationWindow,
194
+ rollback?: PropertiesRollback,
195
+ ): PropertySet | undefined;
196
+ clone(): ISegment;
197
+ canAppend(segment: ISegment): boolean;
198
+ append(segment: ISegment): void;
199
+ splitAt(pos: number): ISegment | undefined;
200
+ toJSONObject(): any;
201
+ /**
202
+ * Acks the current segment against the segment group, op, and merge tree.
203
+ *
204
+ * Throws error if the segment state doesn't match segment group or op.
205
+ * E.g. Segment group not first is pending queue.
206
+ * Inserted segment does not have unassigned sequence number.
207
+ *
208
+ * Returns true if the op modifies the segment, otherwise false.
209
+ * The only current false case is overlapping remove, where a segment is removed
210
+ * by a previously sequenced operation before the current operation is acked.
211
+ *
212
+ * @deprecated for internal use only. public export will be removed.
213
+ * @internal
214
+ */
215
+ ack(segmentGroup: SegmentGroup, opArgs: IMergeTreeDeltaOpArgs, mergeTree: MergeTree): boolean;
216
+ }
217
+
218
+ export interface IMarkerModifiedAction {
219
+ // eslint-disable-next-line @typescript-eslint/prefer-function-type
220
+ (marker: Marker): void;
221
+ }
222
+
223
+ export interface ISegmentAction<TClientData> {
224
+ // eslint-disable-next-line @typescript-eslint/prefer-function-type
225
+ (segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,
226
+ end: number, accum: TClientData): boolean;
227
+ }
228
+
229
+ export interface ISegmentChanges {
230
+ next?: ISegment;
231
+ replaceCurrent?: ISegment;
232
+ }
233
+
234
+ export interface BlockAction<TClientData> {
235
+ // eslint-disable-next-line @typescript-eslint/prefer-function-type
236
+ (
237
+ block: IMergeBlock,
238
+ pos: number,
239
+ refSeq: number,
240
+ clientId: number,
241
+ start: number | undefined,
242
+ end: number | undefined,
243
+ accum: TClientData,
244
+ ): boolean;
245
+ }
246
+
247
+ export interface NodeAction<TClientData> {
248
+ // eslint-disable-next-line @typescript-eslint/prefer-function-type
249
+ (
250
+ node: IMergeNode,
251
+ pos: number,
252
+ refSeq: number,
253
+ clientId: number,
254
+ start: number | undefined,
255
+ end: number | undefined,
256
+ clientData: TClientData,
257
+ ): boolean;
258
+ }
259
+
260
+ export interface IncrementalSegmentAction<TContext> {
261
+ (segment: ISegment, state: IncrementalMapState<TContext>);
262
+ }
263
+
264
+ export interface IncrementalBlockAction<TContext> {
265
+ (state: IncrementalMapState<TContext>);
266
+ }
267
+
268
+ export interface BlockUpdateActions {
269
+ child: (block: IMergeBlock, index: number) => void;
270
+ }
271
+
272
+ export interface InsertContext {
273
+ candidateSegment?: ISegment;
274
+ prepareEvents?: boolean;
275
+ structureChange?: boolean;
276
+ leaf: (segment: ISegment | undefined, pos: number, ic: InsertContext) => ISegmentChanges;
277
+ continuePredicate?: (continueFromBlock: IMergeBlock) => boolean;
278
+ }
279
+
280
+ export interface SegmentActions<TClientData> {
281
+ leaf?: ISegmentAction<TClientData>;
282
+ shift?: NodeAction<TClientData>;
283
+ contains?: NodeAction<TClientData>;
284
+ pre?: BlockAction<TClientData>;
285
+ post?: BlockAction<TClientData>;
286
+ }
287
+
288
+ export interface IncrementalSegmentActions<TContext> {
289
+ leaf: IncrementalSegmentAction<TContext>;
290
+ pre?: IncrementalBlockAction<TContext>;
291
+ post?: IncrementalBlockAction<TContext>;
292
+ }
293
+
294
+ export interface SearchResult {
295
+ text: string;
296
+ pos: number;
297
+ }
298
+
299
+ export interface MergeTreeStats {
300
+ maxHeight: number;
301
+ nodeCount: number;
302
+ leafCount: number;
303
+ removedLeafCount: number;
304
+ liveCount: number;
305
+ histo: number[];
306
+ windowTime?: number;
307
+ packTime?: number;
308
+ ordTime?: number;
309
+ maxOrdTime?: number;
310
+ }
311
+
312
+ export interface SegmentGroup {
313
+ segments: ISegment[];
314
+ previousProps?: PropertySet[];
315
+ removedReferences?: LocalReferencePosition[];
316
+ localSeq: number;
317
+ }
318
+
319
+ export class MergeNode implements IMergeNodeCommon {
320
+ index: number = 0;
321
+ ordinal: string = "";
322
+ parent?: IMergeBlock;
323
+ cachedLength: number = 0;
324
+
325
+ isLeaf() {
326
+ return false;
327
+ }
328
+ }
329
+ export function ordinalToArray(ord: string) {
330
+ const a: number[] = [];
331
+ if (ord) {
332
+ for (let i = 0, len = ord.length; i < len; i++) {
333
+ a.push(ord.charCodeAt(i));
334
+ }
335
+ }
336
+ return a;
337
+ }
338
+
339
+ // Note that the actual branching factor of the MergeTree is `MaxNodesInBlock - 1`. This is because
340
+ // the MergeTree always inserts first, then checks for overflow and splits if the child count equals
341
+ // `MaxNodesInBlock`. (i.e., `MaxNodesInBlock` contains 1 extra slot for temporary storage to
342
+ // facilitate splits.)
343
+ export const MaxNodesInBlock = 8;
344
+
345
+ export class MergeBlock extends MergeNode implements IMergeBlock {
346
+ public children: IMergeNode[];
347
+ public constructor(public childCount: number) {
348
+ super();
349
+ this.children = new Array<IMergeNode>(MaxNodesInBlock);
350
+ }
351
+
352
+ public hierBlock(): IHierBlock | undefined {
353
+ return undefined;
354
+ }
355
+
356
+ public setOrdinal(child: IMergeNode, index: number) {
357
+ let childCount = this.childCount;
358
+ if (childCount === 8) {
359
+ childCount = 7;
360
+ }
361
+ assert((childCount >= 1) && (childCount <= 7), 0x040 /* "Child count is not within [1,7] range!" */);
362
+ let localOrdinal: number;
363
+ const ordinalWidth = 1 << (MaxNodesInBlock - (childCount + 1));
364
+ if (index === 0) {
365
+ localOrdinal = ordinalWidth - 1;
366
+ } else {
367
+ const prevOrd = this.children[index - 1].ordinal;
368
+ const prevOrdCode = prevOrd.charCodeAt(prevOrd.length - 1);
369
+ localOrdinal = prevOrdCode + ordinalWidth;
370
+ }
371
+ child.ordinal = this.ordinal + String.fromCharCode(localOrdinal);
372
+ assert(child.ordinal.length === (this.ordinal.length + 1), 0x041 /* "Unexpected child ordinal length!" */);
373
+ if (index > 0) {
374
+ assert(
375
+ child.ordinal > this.children[index - 1].ordinal,
376
+ 0x042, /* "Child ordinal <= previous sibling ordinal!" */
377
+ );
378
+ }
379
+ }
380
+
381
+ public assignChild(child: IMergeNode, index: number, updateOrdinal = true) {
382
+ child.parent = this;
383
+ child.index = index;
384
+ if (updateOrdinal) {
385
+ this.setOrdinal(child, index);
386
+ }
387
+ this.children[index] = child;
388
+ }
389
+ }
390
+
391
+ export abstract class BaseSegment extends MergeNode implements ISegment {
392
+ public clientId: number = LocalClientId;
393
+ public seq: number = UniversalSequenceNumber;
394
+ public removedSeq?: number;
395
+ public removedClientIds?: number[];
396
+ public readonly segmentGroups: SegmentGroupCollection = new SegmentGroupCollection(this);
397
+ public readonly trackingCollection: TrackingGroupCollection = new TrackingGroupCollection(this);
398
+ public propertyManager?: PropertiesManager;
399
+ public properties?: PropertySet;
400
+ public localRefs?: LocalReferenceCollection;
401
+ public abstract readonly type: string;
402
+ public localSeq?: number;
403
+ public localRemovedSeq?: number;
404
+
405
+ public addProperties(newProps: PropertySet, op?: ICombiningOp, seq?: number,
406
+ collabWindow?: CollaborationWindow, rollback: PropertiesRollback = PropertiesRollback.None) {
407
+ if (!this.propertyManager) {
408
+ this.propertyManager = new PropertiesManager();
409
+ }
410
+ if (!this.properties) {
411
+ this.properties = createMap<any>();
412
+ }
413
+ return this.propertyManager.addProperties(
414
+ this.properties,
415
+ newProps,
416
+ op,
417
+ seq,
418
+ collabWindow && collabWindow.collaborating,
419
+ rollback,
420
+ );
421
+ }
422
+
423
+ public hasProperty(key: string): boolean {
424
+ return !!this.properties && (this.properties[key] !== undefined);
425
+ }
426
+
427
+ public isLeaf() {
428
+ return true;
429
+ }
430
+
431
+ protected cloneInto(b: ISegment) {
432
+ b.clientId = this.clientId;
433
+ // TODO: deep clone properties
434
+ b.properties = clone(this.properties);
435
+ b.removedClientIds = this.removedClientIds?.slice();
436
+ // TODO: copy removed client overlap and branch removal info
437
+ b.removedSeq = this.removedSeq;
438
+ b.seq = this.seq;
439
+ }
440
+
441
+ public canAppend(segment: ISegment): boolean {
442
+ return false;
443
+ }
444
+
445
+ protected addSerializedProps(jseg: IJSONSegment) {
446
+ if (this.properties) {
447
+ jseg.props = this.properties;
448
+ }
449
+ }
450
+
451
+ public abstract toJSONObject(): any;
452
+
453
+ /**
454
+ * @deprecated for internal use only. public export will be removed.
455
+ * @internal
456
+ */
457
+ public ack(segmentGroup: SegmentGroup, opArgs: IMergeTreeDeltaOpArgs, mergeTree: MergeTree): boolean {
458
+ const currentSegmentGroup = this.segmentGroups.dequeue();
459
+ assert(currentSegmentGroup === segmentGroup, 0x043 /* "On ack, unexpected segmentGroup!" */);
460
+ switch (opArgs.op.type) {
461
+ case MergeTreeDeltaType.ANNOTATE:
462
+ assert(!!this.propertyManager, 0x044 /* "On annotate ack, missing segment property manager!" */);
463
+ this.propertyManager.ackPendingProperties(opArgs.op);
464
+ return true;
465
+
466
+ case MergeTreeDeltaType.INSERT:
467
+ assert(this.seq === UnassignedSequenceNumber, 0x045 /* "On insert, seq number already assigned!" */);
468
+ this.seq = opArgs.sequencedMessage!.sequenceNumber;
469
+ this.localSeq = undefined;
470
+ return true;
471
+
472
+ case MergeTreeDeltaType.REMOVE:
473
+ const removalInfo: IRemovalInfo | undefined = toRemovalInfo(this);
474
+ assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
475
+ this.localRemovedSeq = undefined;
476
+ if (removalInfo.removedSeq === UnassignedSequenceNumber) {
477
+ removalInfo.removedSeq = opArgs.sequencedMessage!.sequenceNumber;
478
+ return true;
479
+ }
480
+ return false;
481
+
482
+ default:
483
+ throw new Error(`${opArgs.op.type} is in unrecognized operation type`);
484
+ }
485
+ }
486
+
487
+ public splitAt(pos: number): ISegment | undefined {
488
+ if (pos > 0) {
489
+ const leafSegment = this.createSplitSegmentAt(pos);
490
+ if (leafSegment) {
491
+ this.copyPropertiesTo(leafSegment);
492
+ leafSegment.parent = this.parent;
493
+
494
+ // Give the leaf a temporary yet valid ordinal.
495
+ // when this segment is put in the tree, it will get its real ordinal,
496
+ // but this ordinal meets all the necessary invariants for now.
497
+ leafSegment.ordinal = this.ordinal + String.fromCharCode(0);
498
+
499
+ leafSegment.removedClientIds = this.removedClientIds?.slice();
500
+ leafSegment.removedSeq = this.removedSeq;
501
+ leafSegment.localRemovedSeq = this.localRemovedSeq;
502
+ leafSegment.seq = this.seq;
503
+ leafSegment.localSeq = this.localSeq;
504
+ leafSegment.clientId = this.clientId;
505
+ this.segmentGroups.copyTo(leafSegment);
506
+ this.trackingCollection.copyTo(leafSegment);
507
+ if (this.localRefs) {
508
+ this.localRefs.split(pos, leafSegment);
509
+ }
510
+ }
511
+ return leafSegment;
512
+ }
513
+ }
514
+
515
+ private copyPropertiesTo(other: ISegment) {
516
+ if (this.propertyManager) {
517
+ if (this.properties) {
518
+ other.propertyManager = new PropertiesManager();
519
+ other.properties = this.propertyManager.copyTo(
520
+ this.properties,
521
+ other.properties,
522
+ other.propertyManager,
523
+ );
524
+ }
525
+ }
526
+ }
527
+
528
+ public abstract clone(): ISegment;
529
+ public abstract append(segment: ISegment): void;
530
+ protected abstract createSplitSegmentAt(pos: number): BaseSegment | undefined;
531
+ }
532
+
533
+ export const reservedMarkerIdKey = "markerId";
534
+ export const reservedMarkerSimpleTypeKey = "markerSimpleType";
535
+
536
+ export interface IJSONMarkerSegment extends IJSONSegment {
537
+ marker: IMarkerDef;
538
+ }
539
+
540
+ export class Marker extends BaseSegment implements ReferencePosition {
541
+ public static readonly type = "Marker";
542
+ public static is(segment: ISegment): segment is Marker {
543
+ return segment.type === Marker.type;
544
+ }
545
+ public readonly type = Marker.type;
546
+
547
+ public static make(
548
+ refType: ReferenceType, props?: PropertySet) {
549
+ const marker = new Marker(refType);
550
+ if (props) {
551
+ marker.addProperties(props);
552
+ }
553
+ return marker;
554
+ }
555
+
556
+ constructor(public refType: ReferenceType) {
557
+ super();
558
+ this.cachedLength = 1;
559
+ }
560
+
561
+ toJSONObject() {
562
+ const obj: IJSONMarkerSegment = { marker: { refType: this.refType } };
563
+ super.addSerializedProps(obj);
564
+ return obj;
565
+ }
566
+
567
+ static fromJSONObject(spec: any) {
568
+ if (spec && typeof spec === "object" && "marker" in spec) {
569
+ return Marker.make(
570
+ spec.marker.refType,
571
+ spec.props as PropertySet);
572
+ }
573
+ return undefined;
574
+ }
575
+
576
+ clone() {
577
+ const b = Marker.make(this.refType, this.properties);
578
+ this.cloneInto(b);
579
+ return b;
580
+ }
581
+
582
+ getSegment() {
583
+ return this;
584
+ }
585
+
586
+ getOffset() {
587
+ return 0;
588
+ }
589
+
590
+ hasSimpleType(simpleTypeName: string) {
591
+ return !!this.properties &&
592
+ this.properties[reservedMarkerSimpleTypeKey] === simpleTypeName;
593
+ }
594
+
595
+ getProperties() {
596
+ return this.properties;
597
+ }
598
+
599
+ getId(): string | undefined {
600
+ if (this.properties && this.properties[reservedMarkerIdKey]) {
601
+ return this.properties[reservedMarkerIdKey] as string;
602
+ }
603
+ }
604
+
605
+ toString() {
606
+ let bbuf = "";
607
+ if (refTypeIncludesFlag(this, ReferenceType.Tile)) {
608
+ bbuf += "Tile";
609
+ }
610
+ if (refTypeIncludesFlag(this, ReferenceType.NestBegin)) {
611
+ if (bbuf.length > 0) {
612
+ bbuf += "; ";
613
+ }
614
+ bbuf += "RangeBegin";
615
+ }
616
+ if (refTypeIncludesFlag(this, ReferenceType.NestEnd)) {
617
+ if (bbuf.length > 0) {
618
+ bbuf += "; ";
619
+ }
620
+ bbuf += "RangeEnd";
621
+ }
622
+ let lbuf = "";
623
+ const id = this.getId();
624
+ if (id) {
625
+ bbuf += ` (${id}) `;
626
+ }
627
+ const tileLabels = refGetTileLabels(this);
628
+ if (tileLabels) {
629
+ lbuf += "tile -- ";
630
+ for (let i = 0, len = tileLabels.length; i < len; i++) {
631
+ const tileLabel = tileLabels[i];
632
+ if (i > 0) {
633
+ lbuf += "; ";
634
+ }
635
+ lbuf += tileLabel;
636
+ }
637
+ }
638
+ const rangeLabels = refGetRangeLabels(this);
639
+ if (rangeLabels) {
640
+ let rangeKind = "begin";
641
+ if (refTypeIncludesFlag(this, ReferenceType.NestEnd)) {
642
+ rangeKind = "end";
643
+ }
644
+ if (tileLabels) {
645
+ lbuf += " ";
646
+ }
647
+ lbuf += `range ${rangeKind} -- `;
648
+ const labels = rangeLabels;
649
+ for (let i = 0, len = labels.length; i < len; i++) {
650
+ const rangeLabel = labels[i];
651
+ if (i > 0) {
652
+ lbuf += "; ";
653
+ }
654
+ lbuf += rangeLabel;
655
+ }
656
+ }
657
+ let pbuf = "";
658
+ if (this.properties) {
659
+ pbuf += JSON.stringify(this.properties, (key, value) => {
660
+ // Avoid circular reference when stringifying makers containing handles.
661
+ // (Substitute a debug string instead.)
662
+ const handle = !!value && value.IFluidHandle;
663
+
664
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
665
+ return handle
666
+ ? `#Handle(${handle.routeContext.path}/${handle.path})`
667
+ : value;
668
+ });
669
+ }
670
+ return `M ${bbuf}: ${lbuf} ${pbuf}`;
671
+ }
672
+
673
+ protected createSplitSegmentAt(pos: number) {
674
+ return undefined;
675
+ }
676
+
677
+ canAppend(segment: ISegment): boolean {
678
+ return false;
679
+ }
680
+
681
+ append() { throw new Error("Can not append to marker"); }
682
+ }
683
+
684
+ export enum IncrementalExecOp {
685
+ Go,
686
+ Stop,
687
+ Yield,
688
+ }
689
+
690
+ export class IncrementalMapState<TContext> {
691
+ op = IncrementalExecOp.Go;
692
+ constructor(
693
+ public block: IMergeBlock,
694
+ public actions: IncrementalSegmentActions<TContext>,
695
+ public pos: number,
696
+ public refSeq: number,
697
+ public clientId: number,
698
+ public context: TContext,
699
+ public start: number,
700
+ public end: number,
701
+ public childIndex = 0,
702
+ ) {
703
+ }
704
+ }
705
+
706
+ export class CollaborationWindow {
707
+ clientId = LocalClientId;
708
+ collaborating = false;
709
+ // Lowest-numbered segment in window; no client can reference a state before this one
710
+ minSeq = 0;
711
+ // Highest-numbered segment in window and current
712
+ // reference segment for this client
713
+ currentSeq = 0;
714
+
715
+ localSeq = 0;
716
+
717
+ loadFrom(a: CollaborationWindow) {
718
+ this.clientId = a.clientId;
719
+ this.collaborating = a.collaborating;
720
+ this.minSeq = a.minSeq;
721
+ this.currentSeq = a.currentSeq;
722
+ }
723
+ }
724
+
725
+ export const compareNumbers = (a: number, b: number) => a - b;
726
+
727
+ export const compareStrings = (a: string, b: string) => a.localeCompare(b);
728
+
729
+ const indentStrings = ["", " ", " "];
730
+ export function internedSpaces(n: number) {
731
+ if (indentStrings[n] === undefined) {
732
+ indentStrings[n] = "";
733
+ for (let i = 0; i < n; i++) {
734
+ indentStrings[n] += " ";
735
+ }
736
+ }
737
+ return indentStrings[n];
738
+ }
739
+
740
+ export interface IConsensusInfo {
741
+ marker: Marker;
742
+ callback: (m: Marker) => void;
743
+ }
744
+
745
+ export interface SegmentAccumulator {
746
+ segments: ISegment[];
747
+ }
748
+
749
+ export interface MinListener {
750
+ minRequired: number;
751
+ onMinGE(minSeq: number): void;
752
+ }