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