@fluidframework/sequence 2.0.0-internal.1.4.2 → 2.0.0-internal.2.0.0

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 (117) hide show
  1. package/dist/defaultMap.d.ts.map +1 -1
  2. package/dist/defaultMap.js +1 -0
  3. package/dist/defaultMap.js.map +1 -1
  4. package/dist/index.d.ts +4 -5
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -4
  7. package/dist/index.js.map +1 -1
  8. package/dist/intervalCollection.d.ts +271 -34
  9. package/dist/intervalCollection.d.ts.map +1 -1
  10. package/dist/intervalCollection.js +343 -97
  11. package/dist/intervalCollection.js.map +1 -1
  12. package/dist/intervalTree.d.ts +72 -0
  13. package/dist/intervalTree.d.ts.map +1 -0
  14. package/dist/intervalTree.js +91 -0
  15. package/dist/intervalTree.js.map +1 -0
  16. package/dist/packageVersion.d.ts +1 -1
  17. package/dist/packageVersion.js +1 -1
  18. package/dist/packageVersion.js.map +1 -1
  19. package/dist/sequence.d.ts +66 -15
  20. package/dist/sequence.d.ts.map +1 -1
  21. package/dist/sequence.js +73 -19
  22. package/dist/sequence.js.map +1 -1
  23. package/dist/sequenceDeltaEvent.d.ts +15 -1
  24. package/dist/sequenceDeltaEvent.d.ts.map +1 -1
  25. package/dist/sequenceDeltaEvent.js +2 -1
  26. package/dist/sequenceDeltaEvent.js.map +1 -1
  27. package/dist/sequenceFactory.d.ts +0 -89
  28. package/dist/sequenceFactory.d.ts.map +1 -1
  29. package/dist/sequenceFactory.js +2 -142
  30. package/dist/sequenceFactory.js.map +1 -1
  31. package/dist/sharedIntervalCollection.d.ts +0 -6
  32. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  33. package/dist/sharedIntervalCollection.js +0 -7
  34. package/dist/sharedIntervalCollection.js.map +1 -1
  35. package/dist/sharedSequence.d.ts +2 -2
  36. package/dist/sharedString.d.ts +16 -15
  37. package/dist/sharedString.d.ts.map +1 -1
  38. package/dist/sharedString.js +96 -15
  39. package/dist/sharedString.js.map +1 -1
  40. package/lib/defaultMap.d.ts.map +1 -1
  41. package/lib/defaultMap.js +1 -0
  42. package/lib/defaultMap.js.map +1 -1
  43. package/lib/index.d.ts +4 -5
  44. package/lib/index.d.ts.map +1 -1
  45. package/lib/index.js +2 -4
  46. package/lib/index.js.map +1 -1
  47. package/lib/intervalCollection.d.ts +271 -34
  48. package/lib/intervalCollection.d.ts.map +1 -1
  49. package/lib/intervalCollection.js +341 -98
  50. package/lib/intervalCollection.js.map +1 -1
  51. package/lib/intervalTree.d.ts +72 -0
  52. package/lib/intervalTree.d.ts.map +1 -0
  53. package/lib/intervalTree.js +86 -0
  54. package/lib/intervalTree.js.map +1 -0
  55. package/lib/packageVersion.d.ts +1 -1
  56. package/lib/packageVersion.js +1 -1
  57. package/lib/packageVersion.js.map +1 -1
  58. package/lib/sequence.d.ts +66 -15
  59. package/lib/sequence.d.ts.map +1 -1
  60. package/lib/sequence.js +73 -19
  61. package/lib/sequence.js.map +1 -1
  62. package/lib/sequenceDeltaEvent.d.ts +15 -1
  63. package/lib/sequenceDeltaEvent.d.ts.map +1 -1
  64. package/lib/sequenceDeltaEvent.js +2 -1
  65. package/lib/sequenceDeltaEvent.js.map +1 -1
  66. package/lib/sequenceFactory.d.ts +0 -89
  67. package/lib/sequenceFactory.d.ts.map +1 -1
  68. package/lib/sequenceFactory.js +1 -139
  69. package/lib/sequenceFactory.js.map +1 -1
  70. package/lib/sharedIntervalCollection.d.ts +0 -6
  71. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  72. package/lib/sharedIntervalCollection.js +0 -7
  73. package/lib/sharedIntervalCollection.js.map +1 -1
  74. package/lib/sharedSequence.d.ts +2 -2
  75. package/lib/sharedString.d.ts +16 -15
  76. package/lib/sharedString.d.ts.map +1 -1
  77. package/lib/sharedString.js +97 -16
  78. package/lib/sharedString.js.map +1 -1
  79. package/package.json +99 -27
  80. package/src/defaultMap.ts +3 -0
  81. package/src/index.ts +4 -4
  82. package/src/intervalCollection.ts +486 -143
  83. package/src/intervalTree.ts +166 -0
  84. package/src/packageVersion.ts +1 -1
  85. package/src/sequence.ts +86 -30
  86. package/src/sequenceDeltaEvent.ts +18 -4
  87. package/src/sequenceFactory.ts +2 -163
  88. package/src/sharedIntervalCollection.ts +0 -11
  89. package/src/sharedString.ts +120 -23
  90. package/tsconfig.json +0 -1
  91. package/dist/sharedNumberSequence.d.ts +0 -50
  92. package/dist/sharedNumberSequence.d.ts.map +0 -1
  93. package/dist/sharedNumberSequence.js +0 -61
  94. package/dist/sharedNumberSequence.js.map +0 -1
  95. package/dist/sharedObjectSequence.d.ts +0 -50
  96. package/dist/sharedObjectSequence.d.ts.map +0 -1
  97. package/dist/sharedObjectSequence.js +0 -61
  98. package/dist/sharedObjectSequence.js.map +0 -1
  99. package/dist/sparsematrix.d.ts +0 -152
  100. package/dist/sparsematrix.d.ts.map +0 -1
  101. package/dist/sparsematrix.js +0 -343
  102. package/dist/sparsematrix.js.map +0 -1
  103. package/lib/sharedNumberSequence.d.ts +0 -50
  104. package/lib/sharedNumberSequence.d.ts.map +0 -1
  105. package/lib/sharedNumberSequence.js +0 -57
  106. package/lib/sharedNumberSequence.js.map +0 -1
  107. package/lib/sharedObjectSequence.d.ts +0 -50
  108. package/lib/sharedObjectSequence.d.ts.map +0 -1
  109. package/lib/sharedObjectSequence.js +0 -57
  110. package/lib/sharedObjectSequence.js.map +0 -1
  111. package/lib/sparsematrix.d.ts +0 -152
  112. package/lib/sparsematrix.d.ts.map +0 -1
  113. package/lib/sparsematrix.js +0 -334
  114. package/lib/sparsematrix.js.map +0 -1
  115. package/src/sharedNumberSequence.ts +0 -62
  116. package/src/sharedObjectSequence.ts +0 -62
  117. package/src/sparsematrix.ts +0 -434
@@ -16,9 +16,10 @@ var __rest = (this && this.__rest) || function (s, e) {
16
16
  /* eslint-disable no-bitwise */
17
17
  import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
18
18
  import { UsageError } from "@fluidframework/container-utils";
19
- import { addProperties, compareReferencePositions, createMap, IntervalTree, MergeTreeDeltaType, minReferencePosition, PropertiesManager, RedBlackTree, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, maxReferencePosition, createDetachedLocalReferencePosition, DetachedReferencePosition, } from "@fluidframework/merge-tree";
19
+ import { addProperties, compareReferencePositions, createMap, MergeTreeDeltaType, minReferencePosition, PropertiesManager, RedBlackTree, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, maxReferencePosition, createDetachedLocalReferencePosition, DetachedReferencePosition, } from "@fluidframework/merge-tree";
20
20
  import { LoggingError } from "@fluidframework/telemetry-utils";
21
21
  import { v4 as uuid } from "uuid";
22
+ import { IntervalTree } from "./intervalTree";
22
23
  const reservedIntervalIdKey = "intervalId";
23
24
  export var IntervalType;
24
25
  (function (IntervalType) {
@@ -64,6 +65,9 @@ function compressInterval(interval) {
64
65
  Object.assign(Object.assign({}, properties), { [reservedRangeLabelsKey]: undefined }),
65
66
  ];
66
67
  }
68
+ /**
69
+ * Serializable interval whose endpoints are plain-old numbers.
70
+ */
67
71
  export class Interval {
68
72
  constructor(start, end, props) {
69
73
  this.start = start;
@@ -74,6 +78,9 @@ export class Interval {
74
78
  this.addProperties(props);
75
79
  }
76
80
  }
81
+ /**
82
+ * {@inheritDoc ISerializableInterval.getIntervalId}
83
+ */
77
84
  getIntervalId() {
78
85
  var _a;
79
86
  const id = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
@@ -82,22 +89,36 @@ export class Interval {
82
89
  }
83
90
  return `${id}`;
84
91
  }
92
+ /**
93
+ * @returns an array containing any auxiliary property sets added with `addPropertySet`.
94
+ */
85
95
  getAdditionalPropertySets() {
86
- return this.auxProps;
96
+ var _a;
97
+ return (_a = this.auxProps) !== null && _a !== void 0 ? _a : [];
87
98
  }
99
+ /**
100
+ * Adds an auxiliary set of properties to this interval.
101
+ * These properties can be recovered using `getAdditionalPropertySets`
102
+ * @param props - set of properties to add
103
+ * @remarks - This gets called as part of the default conflict resolver for `IntervalCollection<Interval>`
104
+ * (i.e. non-sequence-based interval collections). However, the additional properties don't get serialized.
105
+ * This functionality seems half-baked.
106
+ */
88
107
  addPropertySet(props) {
89
108
  if (this.auxProps === undefined) {
90
109
  this.auxProps = [];
91
110
  }
92
111
  this.auxProps.push(props);
93
112
  }
94
- serialize(client) {
95
- var _a;
96
- const seq = (_a = client === null || client === void 0 ? void 0 : client.getCurrentSeq()) !== null && _a !== void 0 ? _a : 0;
113
+ /**
114
+ * {@inheritDoc ISerializableInterval.serialize}
115
+ * @internal
116
+ */
117
+ serialize() {
97
118
  const serializedInterval = {
98
119
  end: this.end,
99
120
  intervalType: 0,
100
- sequenceNumber: seq,
121
+ sequenceNumber: 0,
101
122
  start: this.start,
102
123
  };
103
124
  if (this.properties) {
@@ -105,9 +126,15 @@ export class Interval {
105
126
  }
106
127
  return serializedInterval;
107
128
  }
129
+ /**
130
+ * {@inheritDoc IInterval.clone}
131
+ */
108
132
  clone() {
109
133
  return new Interval(this.start, this.end, this.properties);
110
134
  }
135
+ /**
136
+ * {@inheritDoc IInterval.compare}
137
+ */
111
138
  compare(b) {
112
139
  const startResult = this.compareStart(b);
113
140
  if (startResult === 0) {
@@ -131,29 +158,47 @@ export class Interval {
131
158
  return startResult;
132
159
  }
133
160
  }
161
+ /**
162
+ * {@inheritDoc IInterval.compareStart}
163
+ */
134
164
  compareStart(b) {
135
165
  return this.start - b.start;
136
166
  }
167
+ /**
168
+ * {@inheritDoc IInterval.compareEnd}
169
+ */
137
170
  compareEnd(b) {
138
171
  return this.end - b.end;
139
172
  }
173
+ /**
174
+ * {@inheritDoc IInterval.overlaps}
175
+ */
140
176
  overlaps(b) {
141
177
  const result = (this.start <= b.end) &&
142
178
  (this.end >= b.start);
143
179
  return result;
144
180
  }
181
+ /**
182
+ * {@inheritDoc IInterval.union}
183
+ */
145
184
  union(b) {
146
185
  return new Interval(Math.min(this.start, b.start), Math.max(this.end, b.end), this.properties);
147
186
  }
148
187
  getProperties() {
149
188
  return this.properties;
150
189
  }
190
+ /**
191
+ * {@inheritDoc ISerializableInterval.addProperties}
192
+ */
151
193
  addProperties(newProps, collaborating = false, seq, op) {
152
194
  if (newProps) {
153
195
  this.initializeProperties();
154
196
  return this.propertyManager.addProperties(this.properties, newProps, op, seq, collaborating);
155
197
  }
156
198
  }
199
+ /**
200
+ * {@inheritDoc IInterval.modify}
201
+ */
157
202
  modify(label, start, end, op) {
158
203
  const startPos = start !== null && start !== void 0 ? start : this.start;
159
204
  const endPos = end !== null && end !== void 0 ? end : this.end;
@@ -177,8 +222,23 @@ export class Interval {
177
222
  }
178
223
  }
179
224
  }
225
+ /**
226
+ * Interval impelmentation whose ends are associated with positions in a mutatable sequence.
227
+ * As such, when content is inserted into the middle of the interval, the interval expands to
228
+ * include that content.
229
+ */
180
230
  export class SequenceInterval {
181
- constructor(client, start, end, intervalType, props) {
231
+ constructor(client,
232
+ /**
233
+ * Start endpoint of this interval.
234
+ * @remarks - This endpoint can be resolved into a character position using the SharedString it's a part of.
235
+ */
236
+ start,
237
+ /**
238
+ * End endpoint of this interval.
239
+ * @remarks - This endpoint can be resolved into a character position using the SharedString it's a part of.
240
+ */
241
+ end, intervalType, props) {
182
242
  this.client = client;
183
243
  this.start = start;
184
244
  this.end = end;
@@ -218,13 +278,17 @@ export class SequenceInterval {
218
278
  this.end.callbacks = undefined;
219
279
  }
220
280
  }
221
- serialize(client) {
222
- const startPosition = client.localReferencePositionToPosition(this.start);
223
- const endPosition = client.localReferencePositionToPosition(this.end);
281
+ /**
282
+ * {@inheritDoc ISerializableInterval.serialize}
283
+ * @internal
284
+ */
285
+ serialize() {
286
+ const startPosition = this.client.localReferencePositionToPosition(this.start);
287
+ const endPosition = this.client.localReferencePositionToPosition(this.end);
224
288
  const serializedInterval = {
225
289
  end: endPosition,
226
290
  intervalType: this.intervalType,
227
- sequenceNumber: client.getCurrentSeq(),
291
+ sequenceNumber: this.client.getCurrentSeq(),
228
292
  start: startPosition,
229
293
  };
230
294
  if (this.properties) {
@@ -232,9 +296,15 @@ export class SequenceInterval {
232
296
  }
233
297
  return serializedInterval;
234
298
  }
299
+ /**
300
+ * {@inheritDoc IInterval.clone}
301
+ */
235
302
  clone() {
236
303
  return new SequenceInterval(this.client, this.start, this.end, this.intervalType, this.properties);
237
304
  }
305
+ /**
306
+ * {@inheritDoc IInterval.compare}
307
+ */
238
308
  compare(b) {
239
309
  const startResult = this.compareStart(b);
240
310
  if (startResult === 0) {
@@ -258,17 +328,29 @@ export class SequenceInterval {
258
328
  return startResult;
259
329
  }
260
330
  }
331
+ /**
332
+ * {@inheritDoc IInterval.compareStart}
333
+ */
261
334
  compareStart(b) {
262
335
  return compareReferencePositions(this.start, b.start);
263
336
  }
337
+ /**
338
+ * {@inheritDoc IInterval.compareEnd}
339
+ */
264
340
  compareEnd(b) {
265
341
  return compareReferencePositions(this.end, b.end);
266
342
  }
343
+ /**
344
+ * {@inheritDoc IInterval.overlaps}
345
+ */
267
346
  overlaps(b) {
268
347
  const result = (compareReferencePositions(this.start, b.end) <= 0) &&
269
348
  (compareReferencePositions(this.end, b.start) >= 0);
270
349
  return result;
271
350
  }
351
+ /**
352
+ * {@inheritDoc ISerializableInterval.getIntervalId}
353
+ */
272
354
  getIntervalId() {
273
355
  var _a;
274
356
  const id = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
@@ -277,18 +359,31 @@ export class SequenceInterval {
277
359
  }
278
360
  return `${id}`;
279
361
  }
362
+ /**
363
+ * {@inheritDoc IInterval.union}
364
+ */
280
365
  union(b) {
281
366
  return new SequenceInterval(this.client, minReferencePosition(this.start, b.start), maxReferencePosition(this.end, b.end), this.intervalType);
282
367
  }
368
+ /**
369
+ * {@inheritDoc ISerializableInterval.addProperties}
370
+ */
283
371
  addProperties(newProps, collab = false, seq, op) {
284
372
  this.initializeProperties();
285
373
  return this.propertyManager.addProperties(this.properties, newProps, op, seq, collab);
286
374
  }
375
+ /**
376
+ * @returns whether this interval overlaps two numerical positions.
377
+ * @remarks - this is currently strict overlap, which doesn't align with the endpoint treatment of`.overlaps()`
378
+ */
287
379
  overlapsPos(bstart, bend) {
288
380
  const startPos = this.client.localReferencePositionToPosition(this.start);
289
381
  const endPos = this.client.localReferencePositionToPosition(this.end);
290
382
  return (endPos > bstart) && (startPos < bend);
291
383
  }
384
+ /**
385
+ * {@inheritDoc IInterval.modify}
386
+ */
292
387
  modify(label, start, end, op, localSeq) {
293
388
  const getRefType = (baseType) => {
294
389
  let refType = baseType;
@@ -301,12 +396,16 @@ export class SequenceInterval {
301
396
  let startRef = this.start;
302
397
  if (start !== undefined) {
303
398
  startRef = createPositionReference(this.client, start, getRefType(this.start.refType), op, undefined, localSeq);
304
- startRef.addProperties(this.start.properties);
399
+ if (this.start.properties) {
400
+ startRef.addProperties(this.start.properties);
401
+ }
305
402
  }
306
403
  let endRef = this.end;
307
404
  if (end !== undefined) {
308
405
  endRef = createPositionReference(this.client, end, getRefType(this.end.refType), op, undefined, localSeq);
309
- endRef.addProperties(this.end.properties);
406
+ if (this.end.properties) {
407
+ endRef.addProperties(this.end.properties);
408
+ }
310
409
  }
311
410
  const newInterval = new SequenceInterval(this.client, startRef, endRef, this.intervalType);
312
411
  if (this.properties) {
@@ -343,12 +442,12 @@ function createPositionReference(client, pos, refType, op, fromSnapshot, localSe
343
442
  segoff = client.getSlideToSegment(segoff);
344
443
  }
345
444
  else {
346
- assert((refType & ReferenceType.SlideOnRemove) === 0 || fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
445
+ assert((refType & ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
347
446
  segoff = client.getContainingSegment(pos, undefined, localSeq);
348
447
  }
349
448
  return createPositionReferenceFromSegoff(client, segoff, refType, op);
350
449
  }
351
- function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
450
+ export function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
352
451
  let beginRefType = ReferenceType.RangeBegin;
353
452
  let endRefType = ReferenceType.RangeEnd;
354
453
  if (intervalType === IntervalType.Transient) {
@@ -523,6 +622,10 @@ export class LocalIntervalCollection {
523
622
  }
524
623
  }
525
624
  }
625
+ /**
626
+ * @returns an array of all intervals contained in this collection that overlap the range
627
+ * `[startPosition, endPosition]`.
628
+ */
526
629
  findOverlappingIntervals(startPosition, endPosition) {
527
630
  if (endPosition < startPosition || this.intervalTree.intervals.isEmpty()) {
528
631
  return [];
@@ -617,20 +720,38 @@ export class LocalIntervalCollection {
617
720
  return newInterval;
618
721
  }
619
722
  serialize() {
620
- const client = this.client;
621
723
  const intervals = this.intervalTree.intervals.keys();
622
724
  return {
623
725
  label: this.label,
624
- intervals: intervals.map((interval) => compressInterval(interval.serialize(client))),
726
+ intervals: intervals.map((interval) => compressInterval(interval.serialize())),
625
727
  version: 2,
626
728
  };
627
729
  }
628
730
  addIntervalListeners(interval) {
731
+ const cloneRef = (ref) => {
732
+ const segment = ref.getSegment();
733
+ if (segment === undefined) {
734
+ // Cloning is unnecessary: refs which have slid off the string entirely
735
+ // never get slid back on. Creation code for refs doesn't accept undefined segment
736
+ // either, so this must be special-cased.
737
+ return ref;
738
+ }
739
+ return this.client.createLocalReferencePosition(segment, ref.getOffset(), ReferenceType.Transient, ref.properties);
740
+ };
629
741
  if (interval instanceof SequenceInterval) {
630
- interval.addPositionChangeListeners(() => this.removeIntervalFromIndex(interval), () => {
742
+ let previousInterval;
743
+ interval.addPositionChangeListeners(() => {
744
+ assert(!previousInterval, 0x3f9 /* Invalid interleaving of before/after slide */);
745
+ previousInterval = interval.clone();
746
+ previousInterval.start = cloneRef(previousInterval.start);
747
+ previousInterval.end = cloneRef(previousInterval.end);
748
+ this.removeIntervalFromIndex(interval);
749
+ }, () => {
631
750
  var _a;
751
+ assert(previousInterval !== undefined, 0x3fa /* Invalid interleaving of before/after slide */);
632
752
  this.addIntervalToIndex(interval);
633
- (_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval);
753
+ (_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval, previousInterval);
754
+ previousInterval = undefined;
634
755
  });
635
756
  }
636
757
  }
@@ -641,7 +762,7 @@ export class LocalIntervalCollection {
641
762
  }
642
763
  }
643
764
  LocalIntervalCollection.legacyIdPrefix = "legacy";
644
- const compareSequenceIntervalEnds = (a, b) => compareReferencePositions(a.end, b.end);
765
+ export const compareSequenceIntervalEnds = (a, b) => compareReferencePositions(a.end, b.end);
645
766
  class SequenceIntervalCollectionFactory {
646
767
  load(emitter, raw = []) {
647
768
  const helpers = {
@@ -704,7 +825,7 @@ export class IntervalCollectionValueType {
704
825
  IntervalCollectionValueType.Name = "sharedIntervalCollection";
705
826
  IntervalCollectionValueType._factory = new IntervalCollectionFactory();
706
827
  IntervalCollectionValueType._ops = makeOpsMap();
707
- function makeOpsMap() {
828
+ export function makeOpsMap() {
708
829
  const rebase = (collection, op, localOpMetadata) => {
709
830
  const { localSeq } = localOpMetadata;
710
831
  const rebasedValue = collection.rebaseLocalInterval(op.opName, op.value, localSeq);
@@ -720,6 +841,7 @@ function makeOpsMap() {
720
841
  if (!params) {
721
842
  return;
722
843
  }
844
+ assert(op !== undefined, 0x3fb /* op should exist here */);
723
845
  collection.ackAdd(params, local, op);
724
846
  },
725
847
  rebase,
@@ -729,6 +851,7 @@ function makeOpsMap() {
729
851
  "delete",
730
852
  {
731
853
  process: (collection, params, local, op) => {
854
+ assert(op !== undefined, 0x3fc /* op should exist here */);
732
855
  collection.ackDelete(params, local, op);
733
856
  },
734
857
  rebase: (collection, op, localOpMetadata) => {
@@ -746,6 +869,7 @@ function makeOpsMap() {
746
869
  if (!params) {
747
870
  return;
748
871
  }
872
+ assert(op !== undefined, 0x3fd /* op should exist here */);
749
873
  collection.ackChange(params, local, op);
750
874
  },
751
875
  rebase,
@@ -759,18 +883,25 @@ export class IntervalCollectionIterator {
759
883
  collection.gatherIterationResults(this.results, iteratesForward, start, end);
760
884
  }
761
885
  next() {
762
- let _value;
763
- let _done = true;
764
886
  if (this.index < this.results.length) {
765
- _value = this.results[this.index++];
766
- _done = false;
887
+ return {
888
+ value: this.results[this.index++],
889
+ done: false,
890
+ };
767
891
  }
768
892
  return {
769
- value: _value,
770
- done: _done,
893
+ value: undefined,
894
+ done: true,
771
895
  };
772
896
  }
773
897
  }
898
+ /**
899
+ * Collection of intervals that supports addition, modification, removal, and efficient spatial querying.
900
+ * This class is not a DDS in its own right, but emits events on mutating operations such that it's possible to
901
+ * integrate into a DDS.
902
+ * This aligns with its usage in `SharedSegmentSequence`, which allows associating intervals to positions in the
903
+ * sequence DDS which are broadcast to all other clients in an eventually consistent fashion.
904
+ */
774
905
  export class IntervalCollection extends TypedEventEmitter {
775
906
  /** @internal */
776
907
  constructor(helpers, requiresClient, emitter, serializedIntervals) {
@@ -787,6 +918,7 @@ export class IntervalCollection extends TypedEventEmitter {
787
918
  get attached() {
788
919
  return !!this.localCollection;
789
920
  }
921
+ /** @internal */
790
922
  attachGraph(client, label) {
791
923
  if (this.attached) {
792
924
  throw new LoggingError("Only supports one Sequence attach");
@@ -796,13 +928,15 @@ export class IntervalCollection extends TypedEventEmitter {
796
928
  }
797
929
  // Instantiate the local interval collection based on the saved intervals
798
930
  this.client = client;
799
- this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval) => this.emit("changeInterval", interval, true, undefined));
931
+ this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval, previousInterval) => this.emitChange(interval, previousInterval, true));
800
932
  if (this.savedSerializedIntervals) {
801
933
  for (const serializedInterval of this.savedSerializedIntervals) {
802
934
  this.localCollection.ensureSerializedId(serializedInterval);
803
935
  const { start, end, intervalType, properties } = serializedInterval;
804
936
  const interval = this.helpers.create(label, start, end, client, intervalType, undefined, true);
805
- interval.addProperties(properties);
937
+ if (properties) {
938
+ interval.addProperties(properties);
939
+ }
806
940
  this.localCollection.add(interval);
807
941
  }
808
942
  }
@@ -817,14 +951,37 @@ export class IntervalCollection extends TypedEventEmitter {
817
951
  }
818
952
  return 0;
819
953
  }
954
+ emitChange(interval, previousInterval, local, op) {
955
+ // Temporarily make references transient so that positional queries work (non-transient refs
956
+ // on resolve to DetachedPosition on any segments that don't contain them). The original refType
957
+ // is restored as single-endpoint changes re-use previous references.
958
+ let startRefType;
959
+ let endRefType;
960
+ if (previousInterval instanceof SequenceInterval) {
961
+ startRefType = previousInterval.start.refType;
962
+ endRefType = previousInterval.end.refType;
963
+ previousInterval.start.refType = ReferenceType.Transient;
964
+ previousInterval.end.refType = ReferenceType.Transient;
965
+ this.emit("changeInterval", interval, previousInterval, local, op);
966
+ previousInterval.start.refType = startRefType;
967
+ previousInterval.end.refType = endRefType;
968
+ }
969
+ else {
970
+ this.emit("changeInterval", interval, previousInterval, local, op);
971
+ }
972
+ }
973
+ /**
974
+ * @returns the interval in this collection that has the provided `id`.
975
+ * If no interval in the collection has this `id`, returns `undefined`.
976
+ */
820
977
  getIntervalById(id) {
821
- if (!this.attached) {
978
+ if (!this.localCollection) {
822
979
  throw new LoggingError("attach must be called before accessing intervals");
823
980
  }
824
981
  return this.localCollection.getIntervalById(id);
825
982
  }
826
983
  /**
827
- * Create a new interval and add it to the collection
984
+ * Creates a new interval and add it to the collection.
828
985
  * @param start - interval start position
829
986
  * @param end - interval end position
830
987
  * @param intervalType - type of the interval. All intervals are SlideOnRemove. Intervals may not be Transient.
@@ -833,7 +990,7 @@ export class IntervalCollection extends TypedEventEmitter {
833
990
  */
834
991
  add(start, end, intervalType, props) {
835
992
  var _a, _b;
836
- if (!this.attached) {
993
+ if (!this.localCollection) {
837
994
  throw new LoggingError("attach must be called prior to adding intervals");
838
995
  }
839
996
  if (intervalType & IntervalType.Transient) {
@@ -855,12 +1012,15 @@ export class IntervalCollection extends TypedEventEmitter {
855
1012
  return interval;
856
1013
  }
857
1014
  deleteExistingInterval(interval, local, op) {
1015
+ if (!this.localCollection) {
1016
+ throw new LoggingError("Attach must be called before accessing intervals");
1017
+ }
858
1018
  // The given interval is known to exist in the collection.
859
1019
  this.localCollection.removeExistingInterval(interval);
860
1020
  if (interval) {
861
1021
  // Local ops get submitted to the server. Remote ops have the deserializer run.
862
1022
  if (local) {
863
- this.emitter.emit("delete", undefined, interval.serialize(this.client), { localSeq: this.getNextLocalSeq() });
1023
+ this.emitter.emit("delete", undefined, interval.serialize(), { localSeq: this.getNextLocalSeq() });
864
1024
  }
865
1025
  else {
866
1026
  if (this.onDeserialize) {
@@ -870,13 +1030,27 @@ export class IntervalCollection extends TypedEventEmitter {
870
1030
  }
871
1031
  this.emit("deleteInterval", interval, local, op);
872
1032
  }
1033
+ /**
1034
+ * Removes an interval from the collection.
1035
+ * @param id - Id of the interval to remove
1036
+ * @returns the removed interval
1037
+ */
873
1038
  removeIntervalById(id) {
1039
+ if (!this.localCollection) {
1040
+ throw new LoggingError("Attach must be called before accessing intervals");
1041
+ }
874
1042
  const interval = this.localCollection.getIntervalById(id);
875
1043
  if (interval) {
876
1044
  this.deleteExistingInterval(interval, true, undefined);
877
1045
  }
878
1046
  return interval;
879
1047
  }
1048
+ /**
1049
+ * Changes the properties on an existing interval.
1050
+ * @param id - Id of the interval whose properties should be changed
1051
+ * @param props - Property set to apply to the interval. Shallow merging is used between any existing properties
1052
+ * and `prop`, i.e. the interval will end up with a property object equivalent to `{ ...oldProps, ...props }`.
1053
+ */
880
1054
  changeProperties(id, props) {
881
1055
  if (!this.attached) {
882
1056
  throw new LoggingError("Attach must be called before accessing intervals");
@@ -891,7 +1065,7 @@ export class IntervalCollection extends TypedEventEmitter {
891
1065
  if (interval) {
892
1066
  // Pass Unassigned as the sequence number to indicate that this is a local op that is waiting for an ack.
893
1067
  const deltaProps = interval.addProperties(props, true, UnassignedSequenceNumber);
894
- const serializedInterval = interval.serialize(this.client);
1068
+ const serializedInterval = interval.serialize();
895
1069
  // Emit a change op that will only change properties. Add the ID to
896
1070
  // the property bag provided by the caller.
897
1071
  serializedInterval.start = undefined;
@@ -899,12 +1073,18 @@ export class IntervalCollection extends TypedEventEmitter {
899
1073
  serializedInterval.properties = props;
900
1074
  serializedInterval.properties[reservedIntervalIdKey] = interval.getIntervalId();
901
1075
  this.emitter.emit("change", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
902
- this.emit("propertyChanged", interval, deltaProps);
1076
+ this.emit("propertyChanged", interval, deltaProps, true, undefined);
903
1077
  }
904
- this.emit("changeInterval", interval, true, undefined);
905
1078
  }
1079
+ /**
1080
+ * Changes the endpoints of an existing interval.
1081
+ * @param id - Id of the interval to change
1082
+ * @param start - New start value, if defined. `undefined` signifies this endpoint should be left unchanged.
1083
+ * @param end - New end value, if defined. `undefined` signifies this endpoint should be left unchanged.
1084
+ * @returns the interval that was changed, if it existed in the collection.
1085
+ */
906
1086
  change(id, start, end) {
907
- if (!this.attached) {
1087
+ if (!this.localCollection) {
908
1088
  throw new LoggingError("Attach must be called before accessing intervals");
909
1089
  }
910
1090
  // Force id to be a string.
@@ -914,7 +1094,10 @@ export class IntervalCollection extends TypedEventEmitter {
914
1094
  const interval = this.getIntervalById(id);
915
1095
  if (interval) {
916
1096
  const newInterval = this.localCollection.changeInterval(interval, start, end);
917
- const serializedInterval = interval.serialize(this.client);
1097
+ if (!newInterval) {
1098
+ return undefined;
1099
+ }
1100
+ const serializedInterval = interval.serialize();
918
1101
  serializedInterval.start = start;
919
1102
  serializedInterval.end = end;
920
1103
  // Emit a property bag containing only the ID, as we don't intend for this op to change any properties.
@@ -924,7 +1107,7 @@ export class IntervalCollection extends TypedEventEmitter {
924
1107
  };
925
1108
  this.emitter.emit("change", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
926
1109
  this.addPendingChange(id, serializedInterval);
927
- this.emit("changeInterval", newInterval, true, undefined);
1110
+ this.emitChange(newInterval, interval, true);
928
1111
  return newInterval;
929
1112
  }
930
1113
  // No interval to change
@@ -981,65 +1164,70 @@ export class IntervalCollection extends TypedEventEmitter {
981
1164
  /** @internal */
982
1165
  ackChange(serializedInterval, local, op) {
983
1166
  var _a, _b, _c, _d;
984
- if (!this.attached) {
1167
+ if (!this.localCollection) {
985
1168
  throw new LoggingError("Attach must be called before accessing intervals");
986
1169
  }
987
- let interval;
988
1170
  if (local) {
989
1171
  // This is an ack from the server. Remove the pending change.
990
1172
  this.removePendingChange(serializedInterval);
991
- const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
992
- interval = this.getIntervalById(id);
993
- if (interval) {
994
- // Let the propertyManager prune its pending change-properties set.
995
- (_b = interval.propertyManager) === null || _b === void 0 ? void 0 : _b.ackPendingProperties({
996
- type: MergeTreeDeltaType.ANNOTATE,
997
- props: (_c = serializedInterval.properties) !== null && _c !== void 0 ? _c : {},
998
- });
999
- this.ackInterval(interval, op);
1000
- }
1173
+ }
1174
+ // Note that the ID is in the property bag only to allow us to find the interval.
1175
+ // This API cannot change the ID, and writing to the ID property will result in an exception. So we
1176
+ // strip it out of the properties here.
1177
+ const _e = (_a = serializedInterval.properties) !== null && _a !== void 0 ? _a : {}, _f = reservedIntervalIdKey, id = _e[_f], newProps = __rest(_e, [typeof _f === "symbol" ? _f : _f + ""]);
1178
+ assert(id !== undefined, 0x3fe /* id must exist on the interval */);
1179
+ const interval = this.getIntervalById(id);
1180
+ if (!interval) {
1181
+ // The interval has been removed locally; no-op.
1182
+ return;
1183
+ }
1184
+ if (local) {
1185
+ // Let the propertyManager prune its pending change-properties set.
1186
+ (_b = interval.propertyManager) === null || _b === void 0 ? void 0 : _b.ackPendingProperties({
1187
+ type: MergeTreeDeltaType.ANNOTATE,
1188
+ props: (_c = serializedInterval.properties) !== null && _c !== void 0 ? _c : {},
1189
+ });
1190
+ this.ackInterval(interval, op);
1001
1191
  }
1002
1192
  else {
1003
1193
  // If there are pending changes with this ID, don't apply the remote start/end change, as the local ack
1004
1194
  // should be the winning change.
1005
- // Note that the ID is in the property bag only to allow us to find the interval.
1006
- // This API cannot change the ID, and writing to the ID property will result in an exception. So we
1007
- // strip it out of the properties here.
1008
- const _e = serializedInterval.properties, _f = reservedIntervalIdKey, id = _e[_f], newProps = __rest(_e, [typeof _f === "symbol" ? _f : _f + ""]);
1009
- interval = this.getIntervalById(id);
1010
- if (interval) {
1011
- let start;
1012
- let end;
1013
- // Track pending start/end independently of one another.
1014
- if (!this.hasPendingChangeStart(id)) {
1015
- start = serializedInterval.start;
1016
- }
1017
- if (!this.hasPendingChangeEnd(id)) {
1018
- end = serializedInterval.end;
1019
- }
1020
- if (start !== undefined || end !== undefined) {
1021
- // If changeInterval gives us a new interval, work with that one. Otherwise keep working with
1022
- // the one we originally found in the tree.
1023
- interval = (_d = this.localCollection.changeInterval(interval, start, end, op)) !== null && _d !== void 0 ? _d : interval;
1024
- }
1025
- const deltaProps = interval.addProperties(newProps, true, op.sequenceNumber);
1026
- if (this.onDeserialize) {
1027
- this.onDeserialize(interval);
1028
- }
1029
- this.emit("propertyChanged", interval, deltaProps);
1195
+ let start;
1196
+ let end;
1197
+ // Track pending start/end independently of one another.
1198
+ if (!this.hasPendingChangeStart(id)) {
1199
+ start = serializedInterval.start;
1200
+ }
1201
+ if (!this.hasPendingChangeEnd(id)) {
1202
+ end = serializedInterval.end;
1203
+ }
1204
+ let newInterval = interval;
1205
+ if (start !== undefined || end !== undefined) {
1206
+ // If changeInterval gives us a new interval, work with that one. Otherwise keep working with
1207
+ // the one we originally found in the tree.
1208
+ newInterval = (_d = this.localCollection.changeInterval(interval, start, end, op)) !== null && _d !== void 0 ? _d : interval;
1209
+ }
1210
+ const deltaProps = newInterval.addProperties(newProps, true, op.sequenceNumber);
1211
+ if (this.onDeserialize) {
1212
+ this.onDeserialize(newInterval);
1213
+ }
1214
+ if (newInterval !== interval) {
1215
+ this.emitChange(newInterval, interval, local, op);
1216
+ }
1217
+ const changedProperties = Object.keys(newProps).length > 0;
1218
+ if (changedProperties) {
1219
+ this.emit("propertyChanged", interval, deltaProps, local, op);
1030
1220
  }
1031
- }
1032
- if (interval) {
1033
- this.emit("changeInterval", interval, local, op);
1034
1221
  }
1035
1222
  }
1036
1223
  addConflictResolver(conflictResolver) {
1037
- if (!this.attached) {
1224
+ if (!this.localCollection) {
1038
1225
  throw new LoggingError("attachSequence must be called");
1039
1226
  }
1040
1227
  this.localCollection.addConflictResolver(conflictResolver);
1041
1228
  }
1042
1229
  attachDeserializer(onDeserialize) {
1230
+ var _a;
1043
1231
  // If no deserializer is specified can skip all processing work
1044
1232
  if (!onDeserialize) {
1045
1233
  return;
@@ -1047,7 +1235,7 @@ export class IntervalCollection extends TypedEventEmitter {
1047
1235
  // Start by storing the callbacks so that any subsequent modifications make use of them
1048
1236
  this.onDeserialize = onDeserialize;
1049
1237
  // Trigger the async prepare work across all values in the collection
1050
- this.localCollection.map((interval) => {
1238
+ (_a = this.localCollection) === null || _a === void 0 ? void 0 : _a.map((interval) => {
1051
1239
  onDeserialize(interval);
1052
1240
  });
1053
1241
  }
@@ -1059,7 +1247,7 @@ export class IntervalCollection extends TypedEventEmitter {
1059
1247
  * @internal
1060
1248
  */
1061
1249
  rebaseLocalInterval(opName, serializedInterval, localSeq) {
1062
- var _a, _b;
1250
+ var _a, _b, _c, _d, _e, _f, _g;
1063
1251
  if (!this.client) {
1064
1252
  // If there's no associated mergeTree client, the originally submitted op is still correct.
1065
1253
  return serializedInterval;
@@ -1073,12 +1261,12 @@ export class IntervalCollection extends TypedEventEmitter {
1073
1261
  const endRebased = end === undefined ? undefined :
1074
1262
  this.client.rebasePosition(end, sequenceNumber, localSeq);
1075
1263
  const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
1076
- const localInterval = this.localCollection.getIntervalById(intervalId);
1264
+ const localInterval = (_a = this.localCollection) === null || _a === void 0 ? void 0 : _a.getIntervalById(intervalId);
1077
1265
  const rebased = {
1078
1266
  start: startRebased,
1079
1267
  end: endRebased,
1080
1268
  intervalType,
1081
- sequenceNumber: (_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.getCurrentSeq()) !== null && _b !== void 0 ? _b : 0,
1269
+ sequenceNumber: (_c = (_b = this.client) === null || _b === void 0 ? void 0 : _b.getCurrentSeq()) !== null && _c !== void 0 ? _c : 0,
1082
1270
  properties,
1083
1271
  };
1084
1272
  if (opName === "change" && (this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
@@ -1089,7 +1277,7 @@ export class IntervalCollection extends TypedEventEmitter {
1089
1277
  // delete the interval
1090
1278
  if (startRebased === DetachedReferencePosition || endRebased === DetachedReferencePosition) {
1091
1279
  if (localInterval) {
1092
- this.localCollection.removeExistingInterval(localInterval);
1280
+ (_d = this.localCollection) === null || _d === void 0 ? void 0 : _d.removeExistingInterval(localInterval);
1093
1281
  }
1094
1282
  return undefined;
1095
1283
  }
@@ -1102,14 +1290,21 @@ export class IntervalCollection extends TypedEventEmitter {
1102
1290
  const endSegment = this.getSlideToSegment(localInterval.end);
1103
1291
  // we need to slide because the reference has been removed
1104
1292
  if (startSegment || endSegment) {
1105
- const newStart = startSegment && this.client.getPosition(startSegment.segment, localSeq) + startSegment.offset;
1106
- const newEnd = endSegment && this.client.getPosition(endSegment.segment, localSeq) + endSegment.offset;
1107
- this.localCollection.changeInterval(localInterval, newStart, newEnd, undefined, localSeq);
1293
+ const newStart = startSegment && this.client.getPosition(startSegment.segment, localSeq) + ((_e = startSegment.offset) !== null && _e !== void 0 ? _e : 0);
1294
+ const newEnd = endSegment && this.client.getPosition(endSegment.segment, localSeq) + ((_f = endSegment.offset) !== null && _f !== void 0 ? _f : 0);
1295
+ (_g = this.localCollection) === null || _g === void 0 ? void 0 : _g.changeInterval(localInterval, newStart, newEnd, undefined, localSeq);
1108
1296
  }
1109
1297
  return rebased;
1110
1298
  }
1111
1299
  getSlideToSegment(lref) {
1300
+ var _a, _b;
1301
+ if (!this.client) {
1302
+ throw new LoggingError("client does not exist");
1303
+ }
1112
1304
  const segoff = { segment: lref.getSegment(), offset: lref.getOffset() };
1305
+ if (((_b = (_a = segoff.segment) === null || _a === void 0 ? void 0 : _a.localRefs) === null || _b === void 0 ? void 0 : _b.has(lref)) !== true) {
1306
+ return undefined;
1307
+ }
1113
1308
  const newSegoff = this.client.getSlideToSegment(segoff);
1114
1309
  const value = (segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset) ? undefined : newSegoff;
1115
1310
  return value;
@@ -1121,6 +1316,7 @@ export class IntervalCollection extends TypedEventEmitter {
1121
1316
  lref.refType = refType;
1122
1317
  }
1123
1318
  ackInterval(interval, op) {
1319
+ var _a, _b;
1124
1320
  // Only SequenceIntervals need potential sliding
1125
1321
  if (!(interval instanceof SequenceInterval)) {
1126
1322
  return;
@@ -1143,27 +1339,44 @@ export class IntervalCollection extends TypedEventEmitter {
1143
1339
  const needsStartUpdate = newStart !== undefined && !hasPendingStartChange;
1144
1340
  const needsEndUpdate = newEnd !== undefined && !hasPendingEndChange;
1145
1341
  if (needsStartUpdate || needsEndUpdate) {
1342
+ if (!this.localCollection) {
1343
+ throw new LoggingError("Attach must be called before accessing intervals");
1344
+ }
1345
+ // `interval`'s endpoints will get modified in-place, so clone it prior to doing so for event emission.
1346
+ const oldInterval = interval.clone();
1146
1347
  // In this case, where we change the start or end of an interval,
1147
1348
  // it is necessary to remove and re-add the interval listeners.
1148
1349
  // This ensures that the correct listeners are added to the LocalReferencePosition.
1149
1350
  this.localCollection.removeExistingInterval(interval);
1351
+ if (!this.client) {
1352
+ throw new LoggingError("client does not exist");
1353
+ }
1150
1354
  if (needsStartUpdate) {
1151
1355
  const props = interval.start.properties;
1152
- this.client.removeLocalReferencePosition(interval.start);
1153
1356
  interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op);
1154
1357
  if (props) {
1155
1358
  interval.start.addProperties(props);
1156
1359
  }
1360
+ const oldSeg = oldInterval.start.getSegment();
1361
+ // remove and rebuild start interval as transient for event
1362
+ this.client.removeLocalReferencePosition(oldInterval.start);
1363
+ oldInterval.start.refType = ReferenceType.Transient;
1364
+ (_a = oldSeg === null || oldSeg === void 0 ? void 0 : oldSeg.localRefs) === null || _a === void 0 ? void 0 : _a.addLocalRef(oldInterval.start, oldInterval.start.getOffset());
1157
1365
  }
1158
1366
  if (needsEndUpdate) {
1159
1367
  const props = interval.end.properties;
1160
- this.client.removeLocalReferencePosition(interval.end);
1161
1368
  interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op);
1162
1369
  if (props) {
1163
1370
  interval.end.addProperties(props);
1164
1371
  }
1372
+ // remove and rebuild end interval as transient for event
1373
+ const oldSeg = oldInterval.end.getSegment();
1374
+ this.client.removeLocalReferencePosition(oldInterval.end);
1375
+ oldInterval.end.refType = ReferenceType.Transient;
1376
+ (_b = oldSeg === null || oldSeg === void 0 ? void 0 : oldSeg.localRefs) === null || _b === void 0 ? void 0 : _b.addLocalRef(oldInterval.end, oldInterval.end.getOffset());
1165
1377
  }
1166
1378
  this.localCollection.add(interval);
1379
+ this.emitChange(interval, oldInterval, true, op);
1167
1380
  }
1168
1381
  }
1169
1382
  /** @internal */
@@ -1177,7 +1390,7 @@ export class IntervalCollection extends TypedEventEmitter {
1177
1390
  }
1178
1391
  return;
1179
1392
  }
1180
- if (!this.attached) {
1393
+ if (!this.localCollection) {
1181
1394
  throw new LoggingError("attachSequence must be called");
1182
1395
  }
1183
1396
  this.localCollection.ensureSerializedId(serializedInterval);
@@ -1198,7 +1411,7 @@ export class IntervalCollection extends TypedEventEmitter {
1198
1411
  // locally deleted interval whenever a lookup happens.
1199
1412
  return;
1200
1413
  }
1201
- if (!this.attached) {
1414
+ if (!this.localCollection) {
1202
1415
  throw new LoggingError("attach must be called prior to deleting intervals");
1203
1416
  }
1204
1417
  const id = this.localCollection.ensureSerializedId(serializedInterval);
@@ -1211,57 +1424,87 @@ export class IntervalCollection extends TypedEventEmitter {
1211
1424
  * @internal
1212
1425
  */
1213
1426
  serializeInternal() {
1214
- if (!this.attached) {
1427
+ if (!this.localCollection) {
1215
1428
  throw new LoggingError("attachSequence must be called");
1216
1429
  }
1217
1430
  return this.localCollection.serialize();
1218
1431
  }
1432
+ /**
1433
+ * @returns an iterator over all intervals in this collection.
1434
+ */
1219
1435
  [Symbol.iterator]() {
1220
1436
  const iterator = new IntervalCollectionIterator(this);
1221
1437
  return iterator;
1222
1438
  }
1439
+ /**
1440
+ * @returns a forward iterator over all intervals in this collection with start point equal to `startPosition`.
1441
+ */
1223
1442
  CreateForwardIteratorWithStartPosition(startPosition) {
1224
1443
  const iterator = new IntervalCollectionIterator(this, true, startPosition);
1225
1444
  return iterator;
1226
1445
  }
1446
+ /**
1447
+ * @returns a backward iterator over all intervals in this collection with start point equal to `startPosition`.
1448
+ */
1227
1449
  CreateBackwardIteratorWithStartPosition(startPosition) {
1228
1450
  const iterator = new IntervalCollectionIterator(this, false, startPosition);
1229
1451
  return iterator;
1230
1452
  }
1453
+ /**
1454
+ * @returns a forward iterator over all intervals in this collection with end point equal to `endPosition`.
1455
+ */
1231
1456
  CreateForwardIteratorWithEndPosition(endPosition) {
1232
1457
  const iterator = new IntervalCollectionIterator(this, true, undefined, endPosition);
1233
1458
  return iterator;
1234
1459
  }
1460
+ /**
1461
+ * @returns a backward iterator over all intervals in this collection with end point equal to `endPosition`.
1462
+ */
1235
1463
  CreateBackwardIteratorWithEndPosition(endPosition) {
1236
1464
  const iterator = new IntervalCollectionIterator(this, false, undefined, endPosition);
1237
1465
  return iterator;
1238
1466
  }
1467
+ /**
1468
+ * Gathers iteration results that optionally match a start/end criteria into the provided array.
1469
+ * @param results - Array to gather the results into. In lieu of a return value, this array will be populated with
1470
+ * intervals matching the query upon edit.
1471
+ * @param iteratesForward - whether or not iteration should be in the forward direction
1472
+ * @param start - If provided, only match intervals whose start point is equal to `start`.
1473
+ * @param end - If provided, only match intervals whose end point is equal to `end`.
1474
+ */
1239
1475
  gatherIterationResults(results, iteratesForward, start, end) {
1240
- if (!this.attached) {
1476
+ if (!this.localCollection) {
1241
1477
  return;
1242
1478
  }
1243
1479
  this.localCollection.gatherIterationResults(results, iteratesForward, start, end);
1244
1480
  }
1481
+ /**
1482
+ * @returns an array of all intervals in this collection that overlap with the interval
1483
+ * `[startPosition, endPosition]`.
1484
+ */
1245
1485
  findOverlappingIntervals(startPosition, endPosition) {
1246
- if (!this.attached) {
1486
+ if (!this.localCollection) {
1247
1487
  throw new LoggingError("attachSequence must be called");
1248
1488
  }
1249
1489
  return this.localCollection.findOverlappingIntervals(startPosition, endPosition);
1250
1490
  }
1491
+ /**
1492
+ * Applies a function to each interval in this collection.
1493
+ */
1251
1494
  map(fn) {
1252
- if (!this.attached) {
1495
+ if (!this.localCollection) {
1253
1496
  throw new LoggingError("attachSequence must be called");
1254
1497
  }
1255
1498
  this.localCollection.map(fn);
1256
1499
  }
1257
1500
  previousInterval(pos) {
1258
- if (!this.attached) {
1501
+ if (!this.localCollection) {
1259
1502
  throw new LoggingError("attachSequence must be called");
1260
1503
  }
1261
1504
  return this.localCollection.previousInterval(pos);
1262
1505
  }
1263
1506
  nextInterval(pos) {
1264
- if (!this.attached) {
1507
+ if (!this.localCollection) {
1265
1508
  throw new LoggingError("attachSequence must be called");
1266
1509
  }
1267
1510
  return this.localCollection.nextInterval(pos);