@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
@@ -5,91 +5,121 @@
5
5
 
6
6
  import { assert } from "@fluidframework/common-utils";
7
7
  import { Client } from "./client";
8
+ import { List, ListMakeHead, ListRemoveEntry } from "./collections";
8
9
  import {
9
10
  ISegment,
11
+ } from "./mergeTree";
12
+ import { ICombiningOp, ReferenceType } from "./ops";
13
+ import { addProperties, PropertySet } from "./properties";
14
+ import {
15
+ minReferencePosition,
16
+ maxReferencePosition,
17
+ compareReferencePositions,
18
+ refHasTileLabels,
19
+ refHasRangeLabels,
10
20
  ReferencePosition,
11
21
  refGetRangeLabels,
12
22
  refGetTileLabels,
13
23
  refHasRangeLabel,
14
24
  refHasTileLabel,
15
- } from "./mergeTree";
16
- import { ICombiningOp, ReferenceType } from "./ops";
17
- import { addProperties, PropertySet } from "./properties";
25
+ refTypeIncludesFlag,
26
+ } from "./referencePositions";
18
27
 
28
+ /**
29
+ * @deprecated - Use ReferencePosition
30
+ */
19
31
  export class LocalReference implements ReferencePosition {
32
+ /**
33
+ * @deprecated - use DetachedReferencePosition
34
+ */
20
35
  public static readonly DetachedPosition: number = -1;
21
36
 
22
37
  public properties: PropertySet | undefined;
38
+ /**
39
+ * @deprecated - use properties to store pair
40
+ */
23
41
  public pairedRef?: LocalReference;
42
+ /**
43
+ * @deprecated - use getSegment
44
+ */
24
45
  public segment: ISegment | undefined;
25
46
 
47
+ /**
48
+ * @deprecated - use createReferencePosition
49
+ */
26
50
  constructor(
27
51
  private readonly client: Client,
28
52
  initSegment: ISegment,
29
- public offset = 0,
53
+ /**
54
+ * @deprecated - use getOffset
55
+ */
56
+ public offset: number = 0,
30
57
  public refType = ReferenceType.Simple,
58
+ properties?: PropertySet,
31
59
  ) {
32
60
  this.segment = initSegment;
61
+ this.properties = properties;
33
62
  }
34
63
 
64
+ /**
65
+ * @deprecated - use minReferencePosition
66
+ */
35
67
  public min(b: LocalReference) {
36
- if (this.compare(b) < 0) {
37
- return this;
38
- } else {
39
- return b;
40
- }
68
+ return minReferencePosition(this, b);
41
69
  }
42
-
70
+ /**
71
+ * @deprecated - use maxReferencePosition
72
+ */
43
73
  public max(b: LocalReference) {
44
- if (this.compare(b) > 0) {
45
- return this;
46
- } else {
47
- return b;
48
- }
74
+ return maxReferencePosition(this, b);
49
75
  }
50
-
76
+ /**
77
+ * @deprecated - use compareReferencePositions
78
+ */
51
79
  public compare(b: LocalReference) {
52
- if (this.segment === b.segment) {
53
- return this.offset - b.offset;
54
- } else {
55
- if (this.segment === undefined
56
- || (b.segment !== undefined &&
57
- this.segment.ordinal < b.segment.ordinal)) {
58
- return -1;
59
- } else {
60
- return 1;
61
- }
62
- }
80
+ return compareReferencePositions(this, b);
63
81
  }
64
82
 
83
+ /**
84
+ * @deprecated - use getLocalReferencePosition
85
+ */
65
86
  public toPosition() {
66
- if (this.segment && this.segment.parent) {
67
- return this.getOffset() + this.client.getPosition(this.segment);
68
- } else {
69
- return LocalReference.DetachedPosition;
70
- }
87
+ return this.getClient().localReferencePositionToPosition(this);
71
88
  }
72
89
 
73
- public hasTileLabels() {
74
- return !!this.getTileLabels();
90
+ /**
91
+ * @deprecated - use refHasTileLabels
92
+ */
93
+ public hasTileLabels(): boolean {
94
+ return refHasTileLabels(this);
75
95
  }
76
-
77
- public hasRangeLabels() {
78
- return !!this.getRangeLabels();
96
+ /**
97
+ * @deprecated - use refHasRangeLabels
98
+ */
99
+ public hasRangeLabels(): boolean {
100
+ return refHasRangeLabels(this);
79
101
  }
80
-
102
+ /**
103
+ * @deprecated - use refHasTileLabel
104
+ */
81
105
  public hasTileLabel(label: string): boolean {
82
106
  return refHasTileLabel(this, label);
83
107
  }
84
-
108
+ /**
109
+ * @deprecated - use refHasRangeLabel
110
+ */
85
111
  public hasRangeLabel(label: string): boolean {
86
112
  return refHasRangeLabel(this, label);
87
113
  }
88
-
114
+ /**
115
+ * @deprecated - use refGetTileLabels
116
+ */
89
117
  public getTileLabels(): string[] | undefined {
90
118
  return refGetTileLabels(this);
91
119
  }
92
-
120
+ /**
121
+ * @deprecated - use refGetRangeLabels
122
+ */
93
123
  public getRangeLabels(): string[] | undefined {
94
124
  return refGetRangeLabels(this);
95
125
  }
@@ -102,6 +132,9 @@ export class LocalReference implements ReferencePosition {
102
132
  this.properties = addProperties(this.properties, newProps, op);
103
133
  }
104
134
 
135
+ /**
136
+ * @deprecated - no longer supported
137
+ */
105
138
  public getClient() {
106
139
  return this.client;
107
140
  }
@@ -123,13 +156,17 @@ export class LocalReference implements ReferencePosition {
123
156
  }
124
157
 
125
158
  interface IRefsAtOffset {
126
- before?: LocalReference[];
127
- at?: LocalReference[];
128
- after?: LocalReference[];
159
+ before?: List<LocalReference>;
160
+ at?: List<LocalReference>;
161
+ after?: List<LocalReference>;
162
+ }
163
+
164
+ function assertLocalReferences(lref: ReferencePosition | LocalReference): asserts lref is LocalReference {
165
+ assert(lref instanceof LocalReference, 0x2e0 /* "lref not a Local Reference" */);
129
166
  }
130
167
 
131
168
  /**
132
- * Represents a collection of {@link LocalReference}s associated with one segment in a merge-tree.
169
+ * Represents a collection of {@link ReferencePosition}s associated with one segment in a merge-tree.
133
170
  */
134
171
  export class LocalReferenceCollection {
135
172
  public static append(seg1: ISegment, seg2: ISegment) {
@@ -140,18 +177,25 @@ export class LocalReferenceCollection {
140
177
  assert(seg1.localRefs.refsByOffset.length === seg1.cachedLength,
141
178
  0x2be /* "LocalReferences array contains a gap" */);
142
179
  seg1.localRefs.append(seg2.localRefs);
143
- }
144
- else if (seg1.localRefs) {
180
+ } else if (seg1.localRefs) {
145
181
  // Since creating the LocalReferenceCollection, we may have appended
146
182
  // segments that had no local references. Account for them now by padding the array.
147
183
  seg1.localRefs.refsByOffset.length += seg2.cachedLength;
148
184
  }
149
185
  }
150
186
 
187
+ /**
188
+ *
189
+ * @internal - this method should only be called by mergeTree
190
+ */
151
191
  public hierRefCount: number = 0;
152
192
  private readonly refsByOffset: (IRefsAtOffset | undefined)[];
153
193
  private refCount: number = 0;
154
194
 
195
+ /**
196
+ *
197
+ * @internal - this method should only be called by mergeTree
198
+ */
155
199
  constructor(
156
200
  /** Segment this `LocalReferenceCollection` is associated to. */
157
201
  private readonly segment: ISegment,
@@ -162,6 +206,10 @@ export class LocalReferenceCollection {
162
206
  this.refsByOffset = initialRefsByfOffset;
163
207
  }
164
208
 
209
+ /**
210
+ *
211
+ * @internal - this method should only be called by mergeTree
212
+ */
165
213
  public [Symbol.iterator]() {
166
214
  const subiterators: IterableIterator<LocalReference>[] = [];
167
215
  for (const refs of this.refsByOffset) {
@@ -198,16 +246,20 @@ export class LocalReferenceCollection {
198
246
  return iterator;
199
247
  }
200
248
 
249
+ /**
250
+ *
251
+ * @internal - this method should only be called by mergeTree
252
+ */
201
253
  public clear() {
202
254
  this.refCount = 0;
203
255
  this.hierRefCount = 0;
204
- const detachSegments = (refs: LocalReference[] | undefined) => {
256
+ const detachSegments = (refs: List<LocalReference> | undefined) => {
205
257
  if (refs) {
206
- refs.forEach((r) => {
258
+ for (const r of refs) {
207
259
  if (r.segment === this.segment) {
208
260
  r.segment = undefined;
209
261
  }
210
- });
262
+ }
211
263
  }
212
264
  };
213
265
  for (let i = 0; i < this.refsByOffset.length; i++) {
@@ -221,41 +273,80 @@ export class LocalReferenceCollection {
221
273
  }
222
274
  }
223
275
 
276
+ /**
277
+ *
278
+ * @internal - this method should only be called by mergeTree
279
+ */
224
280
  public get empty() {
225
281
  return this.refCount === 0;
226
282
  }
227
283
 
228
- public addLocalRef(lref: LocalReference) {
229
- const refsAtOffset = this.refsByOffset[lref.offset];
230
- if (refsAtOffset === undefined) {
231
- this.refsByOffset[lref.offset] = {
232
- at: [lref],
233
- };
234
- } else if (refsAtOffset.at === undefined) {
235
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
236
- this.refsByOffset[lref.offset]!.at = [lref];
237
- } else {
238
- refsAtOffset.at.push(lref);
284
+ /**
285
+ *
286
+ * @internal - this method should only be called by mergeTree
287
+ */
288
+ public createLocalRef(
289
+ offset: number,
290
+ refType: ReferenceType,
291
+ properties: PropertySet | undefined,
292
+ client: Client): ReferencePosition {
293
+ const ref = new LocalReference(
294
+ client,
295
+ this.segment,
296
+ offset,
297
+ refType,
298
+ properties,
299
+ );
300
+ if (!refTypeIncludesFlag(ref, ReferenceType.Transient)) {
301
+ this.addLocalRef(ref);
239
302
  }
303
+ return ref;
304
+ }
240
305
 
241
- if (lref.hasRangeLabels() || lref.hasTileLabels()) {
306
+ /**
307
+ *
308
+ * @internal - this method should only be called by mergeTree
309
+ */
310
+ public addLocalRef(lref: LocalReference | ReferencePosition) {
311
+ assert(
312
+ !refTypeIncludesFlag(lref, ReferenceType.Transient),
313
+ 0x2df /* "transient references cannot be bound to segments" */);
314
+ assertLocalReferences(lref);
315
+ const refsAtOffset = this.refsByOffset[lref.getOffset()] =
316
+ this.refsByOffset[lref.getOffset()]
317
+ ?? { at: ListMakeHead() };
318
+ const atRefs = refsAtOffset.at =
319
+ refsAtOffset.at
320
+ ?? ListMakeHead();
321
+
322
+ atRefs.enqueue(lref);
323
+
324
+ if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
242
325
  this.hierRefCount++;
243
326
  }
244
327
  this.refCount++;
245
328
  }
246
329
 
247
- public removeLocalRef(lref: LocalReference) {
248
- const tryRemoveRef = (refs: LocalReference[] | undefined) => {
330
+ /**
331
+ *
332
+ * @internal - this method should only be called by mergeTree
333
+ */
334
+ public removeLocalRef(lref: LocalReference | ReferencePosition) {
335
+ assertLocalReferences(lref);
336
+ const tryRemoveRef = (refs: List<LocalReference> | undefined) => {
249
337
  if (refs) {
250
- const index = refs.indexOf(lref);
251
- if (index >= 0) {
252
- refs.splice(index, 1);
253
- if (lref.hasRangeLabels() || lref.hasTileLabels()) {
254
- this.hierRefCount--;
338
+ let node = refs;
339
+ do {
340
+ node = node.next;
341
+ if (node.data === lref) {
342
+ ListRemoveEntry(node);
343
+ if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
344
+ this.hierRefCount--;
345
+ }
346
+ this.refCount--;
347
+ return lref;
255
348
  }
256
- this.refCount--;
257
- return lref;
258
- }
349
+ } while (!node.isHead);
259
350
  }
260
351
  };
261
352
  const refAtOffset = this.refsByOffset[lref.offset];
@@ -278,6 +369,8 @@ export class LocalReferenceCollection {
278
369
  }
279
370
 
280
371
  /**
372
+ * @internal - this method should only be called by mergeTree
373
+ *
281
374
  * Called by 'append()' implementations to append local refs from the given 'other' segment to the
282
375
  * end of 'this' segment.
283
376
  *
@@ -301,6 +394,8 @@ export class LocalReferenceCollection {
301
394
  }
302
395
 
303
396
  /**
397
+ * @internal - this method should only be called by mergeTree
398
+ *
304
399
  * Splits this `LocalReferenceCollection` into the intervals [0, offset) and [offset, originalLength).
305
400
  * Local references in the former half of this split will remain associated with the segment used on construction.
306
401
  * Local references in the latter half of this split will be transferred to `splitSeg`,
@@ -320,7 +415,7 @@ export class LocalReferenceCollection {
320
415
  for (const lref of localRefs) {
321
416
  lref.segment = splitSeg;
322
417
  lref.offset -= offset;
323
- if (lref.hasRangeLabels() || lref.hasTileLabels()) {
418
+ if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
324
419
  this.hierRefCount--;
325
420
  localRefs.hierRefCount++;
326
421
  }
@@ -333,17 +428,17 @@ export class LocalReferenceCollection {
333
428
  }
334
429
  }
335
430
 
336
- public addBeforeTombstones(...refs: Iterable<LocalReference>[]) {
337
- const beforeRefs: LocalReference[] = [];
431
+ public addBeforeTombstones(...refs: Iterable<LocalReference | ReferencePosition>[]) {
432
+ const beforeRefs = this.refsByOffset[0]?.before ?? ListMakeHead();
338
433
 
339
434
  for (const iterable of refs) {
340
435
  for (const lref of iterable) {
341
- // eslint-disable-next-line no-bitwise
342
- if (lref.refType & ReferenceType.SlideOnRemove) {
436
+ assertLocalReferences(lref);
437
+ if (refTypeIncludesFlag(lref, ReferenceType.SlideOnRemove)) {
343
438
  beforeRefs.push(lref);
344
439
  lref.segment = this.segment;
345
440
  lref.offset = 0;
346
- if (lref.hasRangeLabels() || lref.hasTileLabels()) {
441
+ if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
347
442
  this.hierRefCount++;
348
443
  }
349
444
  this.refCount++;
@@ -352,28 +447,27 @@ export class LocalReferenceCollection {
352
447
  }
353
448
  }
354
449
  }
355
- if (beforeRefs.length > 0) {
356
- if (this.refsByOffset[0] === undefined) {
357
- this.refsByOffset[0] = { before: beforeRefs };
358
- } else if (this.refsByOffset[0].before === undefined) {
359
- this.refsByOffset[0].before = beforeRefs;
360
- } else {
361
- this.refsByOffset[0].before.unshift(...beforeRefs);
362
- }
450
+ if (!beforeRefs.empty() && this.refsByOffset[0]?.before === undefined) {
451
+ const refsAtOffset = this.refsByOffset[0] =
452
+ this.refsByOffset[0]
453
+ ?? { before: beforeRefs };
454
+ refsAtOffset.before = refsAtOffset.before ?? beforeRefs;
363
455
  }
364
456
  }
365
457
 
366
- public addAfterTombstones(...refs: Iterable<LocalReference>[]) {
367
- const afterRefs: LocalReference[] = [];
458
+ public addAfterTombstones(...refs: Iterable<LocalReference | ReferencePosition>[]) {
459
+ const lastOffset = this.refsByOffset.length - 1;
460
+ const afterRefs =
461
+ this.refsByOffset[lastOffset]?.after ?? ListMakeHead();
368
462
 
369
463
  for (const iterable of refs) {
370
464
  for (const lref of iterable) {
371
- // eslint-disable-next-line no-bitwise
372
- if (lref.refType & ReferenceType.SlideOnRemove) {
465
+ assertLocalReferences(lref);
466
+ if (refTypeIncludesFlag(lref, ReferenceType.SlideOnRemove)) {
373
467
  afterRefs.push(lref);
374
468
  lref.segment = this.segment;
375
469
  lref.offset = this.segment.cachedLength - 1;
376
- if (lref.hasRangeLabels() || lref.hasTileLabels()) {
470
+ if (refHasRangeLabels(lref) || refHasTileLabels(lref)) {
377
471
  this.hierRefCount++;
378
472
  }
379
473
  this.refCount++;
@@ -382,15 +476,11 @@ export class LocalReferenceCollection {
382
476
  }
383
477
  }
384
478
  }
385
- if (afterRefs.length > 0) {
386
- const refsAtOffset = this.refsByOffset[this.segment.cachedLength - 1];
387
- if (refsAtOffset === undefined) {
388
- this.refsByOffset[this.segment.cachedLength - 1] = { after: afterRefs };
389
- } else if (refsAtOffset.after === undefined) {
390
- refsAtOffset.after = afterRefs;
391
- } else {
392
- refsAtOffset.after.push(...afterRefs);
393
- }
479
+ if (!afterRefs.empty() && this.refsByOffset[lastOffset]?.after === undefined) {
480
+ const refsAtOffset = this.refsByOffset[lastOffset] =
481
+ this.refsByOffset[lastOffset]
482
+ ?? { after: afterRefs };
483
+ refsAtOffset.after = refsAtOffset.after ?? afterRefs;
394
484
  }
395
485
  }
396
486
  }