@fluidframework/sequence 2.32.0 → 2.33.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/CHANGELOG.md +16 -0
- package/api-report/sequence.legacy.alpha.api.md +39 -39
- package/dist/intervalCollection.d.ts +14 -9
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +137 -77
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalCollectionMap.d.ts +5 -4
- package/dist/intervalCollectionMap.d.ts.map +1 -1
- package/dist/intervalCollectionMap.js +25 -50
- package/dist/intervalCollectionMap.js.map +1 -1
- package/dist/intervalCollectionMapInterfaces.d.ts +22 -15
- package/dist/intervalCollectionMapInterfaces.d.ts.map +1 -1
- package/dist/intervalCollectionMapInterfaces.js.map +1 -1
- package/dist/intervalIndex/intervalIndex.d.ts +1 -1
- package/dist/intervalIndex/intervalIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/dist/intervals/sequenceInterval.d.ts +3 -3
- package/dist/intervals/sequenceInterval.d.ts.map +1 -1
- package/dist/intervals/sequenceInterval.js +10 -9
- package/dist/intervals/sequenceInterval.js.map +1 -1
- 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 +4 -0
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +10 -0
- package/dist/sequence.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts +1 -1
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedString.d.ts +0 -4
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +0 -11
- package/dist/sharedString.js.map +1 -1
- package/lib/intervalCollection.d.ts +14 -9
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +138 -78
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalCollectionMap.d.ts +5 -4
- package/lib/intervalCollectionMap.d.ts.map +1 -1
- package/lib/intervalCollectionMap.js +26 -51
- package/lib/intervalCollectionMap.js.map +1 -1
- package/lib/intervalCollectionMapInterfaces.d.ts +22 -15
- package/lib/intervalCollectionMapInterfaces.d.ts.map +1 -1
- package/lib/intervalCollectionMapInterfaces.js.map +1 -1
- package/lib/intervalIndex/intervalIndex.d.ts +1 -1
- package/lib/intervalIndex/intervalIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/lib/intervals/sequenceInterval.d.ts +3 -3
- package/lib/intervals/sequenceInterval.d.ts.map +1 -1
- package/lib/intervals/sequenceInterval.js +10 -9
- package/lib/intervals/sequenceInterval.js.map +1 -1
- 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 +4 -0
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +10 -0
- package/lib/sequence.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedString.d.ts +0 -4
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +0 -11
- package/lib/sharedString.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +18 -20
- package/src/intervalCollection.ts +188 -96
- package/src/intervalCollectionMap.ts +31 -60
- package/src/intervalCollectionMapInterfaces.ts +34 -29
- package/src/intervalIndex/intervalIndex.ts +1 -1
- package/src/intervalIndex/overlappingIntervalsIndex.ts +1 -1
- package/src/intervals/sequenceInterval.ts +14 -2
- package/src/packageVersion.ts +1 -1
- package/src/sequence.ts +15 -0
- package/src/sharedIntervalCollection.ts +1 -1
- package/src/sharedString.ts +0 -11
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.intervalLocatorFromEndpoint = exports.IntervalCollection = exports.
|
|
7
|
+
exports.intervalLocatorFromEndpoint = exports.IntervalCollection = exports.LocalIntervalCollection = exports.computeStickinessFromSide = exports.toOptionalSequencePlace = exports.toSequencePlace = exports.sidesFromStickiness = void 0;
|
|
8
8
|
/* eslint-disable no-bitwise */
|
|
9
9
|
const client_utils_1 = require("@fluid-internal/client-utils");
|
|
10
10
|
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
@@ -116,7 +116,7 @@ class LocalIntervalCollection {
|
|
|
116
116
|
this.removeIntervalFromIndexes(interval);
|
|
117
117
|
this.removeIntervalListeners(interval);
|
|
118
118
|
}
|
|
119
|
-
addInterval(id, start, end, props, op) {
|
|
119
|
+
addInterval(id, start, end, props, op, rollback) {
|
|
120
120
|
// This check is intended to prevent scenarios where a random interval is created and then
|
|
121
121
|
// inserted into a collection. The aim is to ensure that the collection is created first
|
|
122
122
|
// then the user can create/add intervals based on the collection
|
|
@@ -124,7 +124,7 @@ class LocalIntervalCollection {
|
|
|
124
124
|
props[internal_2.reservedRangeLabelsKey][0] !== this.label) {
|
|
125
125
|
throw new internal_3.LoggingError("Adding an interval that belongs to another interval collection is not permitted");
|
|
126
126
|
}
|
|
127
|
-
const interval = (0, index_js_2.createSequenceInterval)(this.label, id, start, end, this.client, index_js_2.IntervalType.SlideOnRemove, op, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint, props);
|
|
127
|
+
const interval = (0, index_js_2.createSequenceInterval)(this.label, id, start, end, this.client, index_js_2.IntervalType.SlideOnRemove, op, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint, props, rollback);
|
|
128
128
|
this.add(interval);
|
|
129
129
|
return interval;
|
|
130
130
|
}
|
|
@@ -197,51 +197,6 @@ class LocalIntervalCollection {
|
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
exports.LocalIntervalCollection = LocalIntervalCollection;
|
|
200
|
-
const rebase = (collection, op, localOpMetadata) => {
|
|
201
|
-
const { localSeq } = localOpMetadata;
|
|
202
|
-
const rebasedValue = collection.rebaseLocalInterval(op.opName, op.value, localSeq);
|
|
203
|
-
if (rebasedValue === undefined) {
|
|
204
|
-
return undefined;
|
|
205
|
-
}
|
|
206
|
-
const rebasedOp = { ...op, value: rebasedValue };
|
|
207
|
-
return { rebasedOp, rebasedLocalOpMetadata: localOpMetadata };
|
|
208
|
-
};
|
|
209
|
-
exports.opsMap = {
|
|
210
|
-
[index_js_2.IntervalDeltaOpType.ADD]: {
|
|
211
|
-
process: (collection, params, local, op, localOpMetadata) => {
|
|
212
|
-
// if params is undefined, the interval was deleted during
|
|
213
|
-
// rebasing
|
|
214
|
-
if (!params) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
(0, internal_1.assert)(op !== undefined, 0x3fb /* op should exist here */);
|
|
218
|
-
collection.ackAdd(params, local, op, localOpMetadata);
|
|
219
|
-
},
|
|
220
|
-
rebase,
|
|
221
|
-
},
|
|
222
|
-
[index_js_2.IntervalDeltaOpType.DELETE]: {
|
|
223
|
-
process: (collection, params, local, op) => {
|
|
224
|
-
(0, internal_1.assert)(op !== undefined, 0x3fc /* op should exist here */);
|
|
225
|
-
collection.ackDelete(params, local, op);
|
|
226
|
-
},
|
|
227
|
-
rebase: (collection, op, localOpMetadata) => {
|
|
228
|
-
// Deletion of intervals is based on id, so requires no rebasing.
|
|
229
|
-
return { rebasedOp: op, rebasedLocalOpMetadata: localOpMetadata };
|
|
230
|
-
},
|
|
231
|
-
},
|
|
232
|
-
[index_js_2.IntervalDeltaOpType.CHANGE]: {
|
|
233
|
-
process: (collection, params, local, op, localOpMetadata) => {
|
|
234
|
-
// if params is undefined, the interval was deleted during
|
|
235
|
-
// rebasing
|
|
236
|
-
if (!params) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
(0, internal_1.assert)(op !== undefined, 0x3fd /* op should exist here */);
|
|
240
|
-
collection.ackChange(params, local, op, localOpMetadata);
|
|
241
|
-
},
|
|
242
|
-
rebase,
|
|
243
|
-
},
|
|
244
|
-
};
|
|
245
200
|
class IntervalCollectionIterator {
|
|
246
201
|
constructor(collection, iteratesForward = true, start, end) {
|
|
247
202
|
this.results = [];
|
|
@@ -308,6 +263,112 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
308
263
|
}
|
|
309
264
|
return true;
|
|
310
265
|
}
|
|
266
|
+
rollback(op, localOpMetadata) {
|
|
267
|
+
const { opName, value } = op;
|
|
268
|
+
const { id, properties } = (0, index_js_2.getSerializedProperties)(value);
|
|
269
|
+
const { localSeq, previous } = localOpMetadata;
|
|
270
|
+
switch (opName) {
|
|
271
|
+
case "add": {
|
|
272
|
+
const interval = this.getIntervalById(id);
|
|
273
|
+
if (interval) {
|
|
274
|
+
this.deleteExistingInterval({ interval, local: true, rollback: true });
|
|
275
|
+
}
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
case "change": {
|
|
279
|
+
(0, internal_1.assert)(previous !== undefined, 0xb7c /* must have previous for change */);
|
|
280
|
+
const endpointsChanged = value.start !== undefined && value.end !== undefined;
|
|
281
|
+
const start = endpointsChanged
|
|
282
|
+
? toOptionalSequencePlace(previous.start, previous.startSide)
|
|
283
|
+
: undefined;
|
|
284
|
+
const end = endpointsChanged
|
|
285
|
+
? toOptionalSequencePlace(previous.end, previous.endSide)
|
|
286
|
+
: undefined;
|
|
287
|
+
this.change(id, {
|
|
288
|
+
start,
|
|
289
|
+
end,
|
|
290
|
+
props: Object.keys(properties).length > 0 ? properties : undefined,
|
|
291
|
+
rollback: true,
|
|
292
|
+
});
|
|
293
|
+
this.localSeqToSerializedInterval.delete(localSeq);
|
|
294
|
+
if (endpointsChanged) {
|
|
295
|
+
this.removePendingChange(value);
|
|
296
|
+
}
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
case "delete": {
|
|
300
|
+
(0, internal_1.assert)(previous !== undefined, 0xb7d /* must have previous for delete */);
|
|
301
|
+
this.add({
|
|
302
|
+
id,
|
|
303
|
+
start: toSequencePlace(previous.start, previous.startSide),
|
|
304
|
+
end: toSequencePlace(previous.end, previous.endSide),
|
|
305
|
+
props: Object.keys(properties).length > 0 ? properties : undefined,
|
|
306
|
+
rollback: true,
|
|
307
|
+
});
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
default:
|
|
311
|
+
(0, internal_1.unreachableCase)(opName);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
process(op, local, message, localOpMetadata) {
|
|
315
|
+
const { opName, value } = op;
|
|
316
|
+
switch (opName) {
|
|
317
|
+
case "add": {
|
|
318
|
+
this.ackAdd(value, local, message, localOpMetadata);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case "delete": {
|
|
322
|
+
this.ackDelete(value, local, message);
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
case "change": {
|
|
326
|
+
this.ackChange(value, local, message, localOpMetadata);
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
default:
|
|
330
|
+
(0, internal_1.unreachableCase)(opName);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
resubmitMessage(op, localOpMetadata) {
|
|
334
|
+
const { opName, value } = op;
|
|
335
|
+
const { localSeq } = localOpMetadata;
|
|
336
|
+
const rebasedValue = opName === "delete" ? value : this.rebaseLocalInterval(opName, value, localSeq);
|
|
337
|
+
if (rebasedValue === undefined) {
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
this.submitDelta({ opName, value: rebasedValue }, localOpMetadata);
|
|
341
|
+
}
|
|
342
|
+
applyStashedOp(op) {
|
|
343
|
+
const { opName, value } = op;
|
|
344
|
+
const { id, properties } = (0, index_js_2.getSerializedProperties)(value);
|
|
345
|
+
switch (opName) {
|
|
346
|
+
case "add": {
|
|
347
|
+
this.add({
|
|
348
|
+
id,
|
|
349
|
+
// Todo: we should improve typing so we know add ops always have start and end
|
|
350
|
+
start: toSequencePlace(value.start, value.startSide),
|
|
351
|
+
end: toSequencePlace(value.end, value.endSide),
|
|
352
|
+
props: properties,
|
|
353
|
+
});
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case "change": {
|
|
357
|
+
this.change(id, {
|
|
358
|
+
start: toOptionalSequencePlace(value.start, value.startSide),
|
|
359
|
+
end: toOptionalSequencePlace(value.end, value.endSide),
|
|
360
|
+
props: properties,
|
|
361
|
+
});
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
case "delete": {
|
|
365
|
+
this.removeIntervalById(id);
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
default:
|
|
369
|
+
throw new Error("unknown ops should not be stashed");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
311
372
|
rebasePositionWithSegmentSlide(pos, seqNumberFrom, localSeq) {
|
|
312
373
|
if (!this.client) {
|
|
313
374
|
throw new internal_3.LoggingError("mergeTree client must exist");
|
|
@@ -417,7 +478,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
417
478
|
/**
|
|
418
479
|
* {@inheritdoc IIntervalCollection.add}
|
|
419
480
|
*/
|
|
420
|
-
add({ id, start, end, props, }) {
|
|
481
|
+
add({ id, start, end, props, rollback, }) {
|
|
421
482
|
if (!this.localCollection) {
|
|
422
483
|
throw new internal_3.LoggingError("attach must be called prior to adding intervals");
|
|
423
484
|
}
|
|
@@ -427,7 +488,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
427
488
|
startSide !== undefined &&
|
|
428
489
|
endSide !== undefined, 0x793 /* start and end cannot be undefined because they were not passed in as undefined */);
|
|
429
490
|
this.assertStickinessEnabled(start, end);
|
|
430
|
-
const interval = this.localCollection.addInterval(id ?? (0, uuid_1.v4)(), toSequencePlace(startPos, startSide), toSequencePlace(endPos, endSide), props);
|
|
491
|
+
const interval = this.localCollection.addInterval(id ?? (0, uuid_1.v4)(), toSequencePlace(startPos, startSide), toSequencePlace(endPos, endSide), props, undefined, rollback);
|
|
431
492
|
if (interval) {
|
|
432
493
|
if (!this.isCollaborating) {
|
|
433
494
|
setSlideOnRemove(interval.start);
|
|
@@ -435,20 +496,20 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
435
496
|
}
|
|
436
497
|
const serializedInterval = interval.serialize();
|
|
437
498
|
const localSeq = this.getNextLocalSeq();
|
|
438
|
-
if (this.isCollaborating) {
|
|
499
|
+
if (this.isCollaborating && rollback !== true) {
|
|
439
500
|
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
501
|
+
this.submitDelta({
|
|
502
|
+
opName: "add",
|
|
503
|
+
value: serializedInterval,
|
|
504
|
+
}, {
|
|
505
|
+
localSeq,
|
|
506
|
+
});
|
|
440
507
|
}
|
|
441
|
-
this.submitDelta({
|
|
442
|
-
opName: "add",
|
|
443
|
-
value: serializedInterval,
|
|
444
|
-
}, {
|
|
445
|
-
localSeq,
|
|
446
|
-
});
|
|
447
508
|
}
|
|
448
509
|
this.emit("addInterval", interval, true, undefined);
|
|
449
510
|
return interval;
|
|
450
511
|
}
|
|
451
|
-
deleteExistingInterval(interval, local, op) {
|
|
512
|
+
deleteExistingInterval({ interval, local, op, rollback, }) {
|
|
452
513
|
if (!this.localCollection) {
|
|
453
514
|
throw new internal_3.LoggingError("Attach must be called before accessing intervals");
|
|
454
515
|
}
|
|
@@ -456,12 +517,13 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
456
517
|
this.localCollection.removeExistingInterval(interval);
|
|
457
518
|
if (interval) {
|
|
458
519
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
459
|
-
if (local) {
|
|
520
|
+
if (local && rollback !== true) {
|
|
460
521
|
this.submitDelta({
|
|
461
522
|
opName: "delete",
|
|
462
523
|
value: interval.serialize(),
|
|
463
524
|
}, {
|
|
464
525
|
localSeq: this.getNextLocalSeq(),
|
|
526
|
+
previous: interval.serialize(),
|
|
465
527
|
});
|
|
466
528
|
}
|
|
467
529
|
else {
|
|
@@ -481,14 +543,14 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
481
543
|
}
|
|
482
544
|
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
483
545
|
if (interval) {
|
|
484
|
-
this.deleteExistingInterval(interval, true
|
|
546
|
+
this.deleteExistingInterval({ interval, local: true });
|
|
485
547
|
}
|
|
486
548
|
return interval;
|
|
487
549
|
}
|
|
488
550
|
/**
|
|
489
551
|
* {@inheritdoc IIntervalCollection.change}
|
|
490
552
|
*/
|
|
491
|
-
change(id, { start, end, props }) {
|
|
553
|
+
change(id, { start, end, props, rollback, }) {
|
|
492
554
|
if (!this.localCollection) {
|
|
493
555
|
throw new internal_3.LoggingError("Attach must be called before accessing intervals");
|
|
494
556
|
}
|
|
@@ -510,7 +572,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
510
572
|
let deltaProps;
|
|
511
573
|
let newInterval;
|
|
512
574
|
if (props !== undefined) {
|
|
513
|
-
deltaProps = interval.changeProperties(props);
|
|
575
|
+
deltaProps = interval.changeProperties(props, undefined, rollback);
|
|
514
576
|
}
|
|
515
577
|
const changeEndpoints = start !== undefined && end !== undefined;
|
|
516
578
|
if (changeEndpoints) {
|
|
@@ -520,27 +582,25 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
520
582
|
setSlideOnRemove(newInterval.end);
|
|
521
583
|
}
|
|
522
584
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
props,
|
|
526
|
-
|
|
527
|
-
});
|
|
528
|
-
const localSeq = this.getNextLocalSeq();
|
|
529
|
-
if (this.isCollaborating) {
|
|
585
|
+
if (this.isCollaborating && rollback !== true) {
|
|
586
|
+
// Emit a property bag containing the ID and the other (if any) properties changed
|
|
587
|
+
const serializedInterval = (newInterval ?? interval).serializeDelta({ props, includeEndpoints: changeEndpoints });
|
|
588
|
+
const localSeq = this.getNextLocalSeq();
|
|
530
589
|
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
590
|
+
this.addPendingChange(id, serializedInterval);
|
|
591
|
+
this.submitDelta({
|
|
592
|
+
opName: "change",
|
|
593
|
+
value: serializedInterval,
|
|
594
|
+
}, {
|
|
595
|
+
localSeq,
|
|
596
|
+
previous: interval.serialize(),
|
|
597
|
+
});
|
|
531
598
|
}
|
|
532
|
-
this.submitDelta({
|
|
533
|
-
opName: "change",
|
|
534
|
-
value: serializedInterval,
|
|
535
|
-
}, {
|
|
536
|
-
localSeq,
|
|
537
|
-
});
|
|
538
599
|
if (deltaProps !== undefined) {
|
|
539
600
|
this.emit("propertyChanged", interval, deltaProps, true, undefined);
|
|
540
601
|
this.emit("changed", newInterval ?? interval, deltaProps, newInterval ? interval : undefined, true, false);
|
|
541
602
|
}
|
|
542
603
|
if (newInterval) {
|
|
543
|
-
this.addPendingChange(id, serializedInterval);
|
|
544
604
|
this.emitChange(newInterval, interval, true, false);
|
|
545
605
|
this.client?.removeLocalReferencePosition(interval.start);
|
|
546
606
|
this.client?.removeLocalReferencePosition(interval.end);
|
|
@@ -836,7 +896,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
|
|
|
836
896
|
const { id } = (0, index_js_2.getSerializedProperties)(serializedInterval);
|
|
837
897
|
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
838
898
|
if (interval) {
|
|
839
|
-
this.deleteExistingInterval(interval, local, op);
|
|
899
|
+
this.deleteExistingInterval({ interval, local, op });
|
|
840
900
|
}
|
|
841
901
|
}
|
|
842
902
|
serializeInternal(version) {
|