@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
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
766
|
-
|
|
887
|
+
return {
|
|
888
|
+
value: this.results[this.index++],
|
|
889
|
+
done: false,
|
|
890
|
+
};
|
|
767
891
|
}
|
|
768
892
|
return {
|
|
769
|
-
value:
|
|
770
|
-
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
*
|
|
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.
|
|
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(
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
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
|
-
|
|
1006
|
-
|
|
1007
|
-
//
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
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.
|
|
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: (
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1507
|
+
if (!this.localCollection) {
|
|
1265
1508
|
throw new LoggingError("attachSequence must be called");
|
|
1266
1509
|
}
|
|
1267
1510
|
return this.localCollection.nextInterval(pos);
|