@fluidframework/sequence 2.0.0-internal.4.2.1 → 2.0.0-internal.4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/defaultMap.d.ts +3 -2
  3. package/dist/defaultMap.d.ts.map +1 -1
  4. package/dist/defaultMap.js +4 -3
  5. package/dist/defaultMap.js.map +1 -1
  6. package/dist/defaultMapInterfaces.d.ts +12 -1
  7. package/dist/defaultMapInterfaces.d.ts.map +1 -1
  8. package/dist/defaultMapInterfaces.js.map +1 -1
  9. package/dist/index.d.ts +3 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +11 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/intervalCollection.d.ts +199 -46
  14. package/dist/intervalCollection.d.ts.map +1 -1
  15. package/dist/intervalCollection.js +164 -78
  16. package/dist/intervalCollection.js.map +1 -1
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.js +1 -1
  19. package/dist/packageVersion.js.map +1 -1
  20. package/dist/revertibles.d.ts +104 -0
  21. package/dist/revertibles.d.ts.map +1 -0
  22. package/dist/revertibles.js +374 -0
  23. package/dist/revertibles.js.map +1 -0
  24. package/dist/sequence.d.ts +2 -2
  25. package/dist/sequence.d.ts.map +1 -1
  26. package/dist/sequence.js +3 -3
  27. package/dist/sequence.js.map +1 -1
  28. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  29. package/dist/sharedIntervalCollection.js +1 -1
  30. package/dist/sharedIntervalCollection.js.map +1 -1
  31. package/lib/defaultMap.d.ts +3 -2
  32. package/lib/defaultMap.d.ts.map +1 -1
  33. package/lib/defaultMap.js +4 -3
  34. package/lib/defaultMap.js.map +1 -1
  35. package/lib/defaultMapInterfaces.d.ts +12 -1
  36. package/lib/defaultMapInterfaces.d.ts.map +1 -1
  37. package/lib/defaultMapInterfaces.js.map +1 -1
  38. package/lib/index.d.ts +3 -2
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +2 -1
  41. package/lib/index.js.map +1 -1
  42. package/lib/intervalCollection.d.ts +199 -46
  43. package/lib/intervalCollection.d.ts.map +1 -1
  44. package/lib/intervalCollection.js +164 -78
  45. package/lib/intervalCollection.js.map +1 -1
  46. package/lib/packageVersion.d.ts +1 -1
  47. package/lib/packageVersion.js +1 -1
  48. package/lib/packageVersion.js.map +1 -1
  49. package/lib/revertibles.d.ts +104 -0
  50. package/lib/revertibles.d.ts.map +1 -0
  51. package/lib/revertibles.js +364 -0
  52. package/lib/revertibles.js.map +1 -0
  53. package/lib/sequence.d.ts +2 -2
  54. package/lib/sequence.d.ts.map +1 -1
  55. package/lib/sequence.js +3 -3
  56. package/lib/sequence.js.map +1 -1
  57. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  58. package/lib/sharedIntervalCollection.js +1 -1
  59. package/lib/sharedIntervalCollection.js.map +1 -1
  60. package/package.json +38 -14
  61. package/src/defaultMap.ts +4 -1
  62. package/src/defaultMapInterfaces.ts +13 -1
  63. package/src/index.ts +16 -1
  64. package/src/intervalCollection.ts +370 -57
  65. package/src/packageVersion.ts +1 -1
  66. package/src/revertibles.ts +572 -0
  67. package/src/sequence.ts +12 -3
  68. package/src/sharedIntervalCollection.ts +3 -2
  69. package/.vscode/launch.json +0 -16
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/sequence";
9
- export const pkgVersion = "2.0.0-internal.4.2.1";
9
+ export const pkgVersion = "2.0.0-internal.4.4.0";
@@ -0,0 +1,572 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /* eslint-disable no-bitwise */
6
+
7
+ import { assert, unreachableCase } from "@fluidframework/common-utils";
8
+ import {
9
+ appendToMergeTreeDeltaRevertibles,
10
+ discardMergeTreeDeltaRevertible,
11
+ isMergeTreeDeltaRevertible,
12
+ LocalReferencePosition,
13
+ MergeTreeDeltaOperationType,
14
+ MergeTreeDeltaRevertible,
15
+ MergeTreeDeltaType,
16
+ PropertySet,
17
+ ReferenceType,
18
+ refTypeIncludesFlag,
19
+ revertMergeTreeDeltaRevertibles,
20
+ SortedSet,
21
+ } from "@fluidframework/merge-tree";
22
+ import { IntervalOpType, SequenceInterval } from "./intervalCollection";
23
+ import { SharedString, SharedStringSegment } from "./sharedString";
24
+ import { ISequenceDeltaRange, SequenceDeltaEvent } from "./sequenceDeltaEvent";
25
+
26
+ /**
27
+ * Data for undoing edits on SharedStrings and Intervals.
28
+ *
29
+ * Revertibles are new and require the option mergeTreeUseNewLengthCalculations to
30
+ * be set as true on the underlying merge tree in order to function correctly.
31
+ *
32
+ * @alpha
33
+ */
34
+ export type SharedStringRevertible = MergeTreeDeltaRevertible | IntervalRevertible;
35
+
36
+ const idMap = new Map<string, string>();
37
+
38
+ type IntervalOpType = typeof IntervalOpType[keyof typeof IntervalOpType];
39
+
40
+ /**
41
+ * Data for undoing edits affecting Intervals.
42
+ *
43
+ * Revertibles are new and require the option mergeTreeUseNewLengthCalculations to
44
+ * be set as true on the underlying merge tree in order to function correctly.
45
+ *
46
+ * @alpha
47
+ */
48
+ export type IntervalRevertible =
49
+ | {
50
+ event: typeof IntervalOpType.CHANGE;
51
+ interval: SequenceInterval;
52
+ start: LocalReferencePosition;
53
+ end: LocalReferencePosition;
54
+ }
55
+ | {
56
+ event: typeof IntervalOpType.ADD;
57
+ interval: SequenceInterval;
58
+ }
59
+ | {
60
+ event: typeof IntervalOpType.DELETE;
61
+ interval: SequenceInterval;
62
+ start: LocalReferencePosition;
63
+ end: LocalReferencePosition;
64
+ }
65
+ | {
66
+ event: typeof IntervalOpType.PROPERTY_CHANGED;
67
+ interval: SequenceInterval;
68
+ propertyDeltas: PropertySet;
69
+ }
70
+ | {
71
+ event: typeof IntervalOpType.POSITION_REMOVE;
72
+ intervals: {
73
+ intervalId: string;
74
+ label: string;
75
+ startOffset?: number; // interval start index within a removed range
76
+ endOffset?: number; // interval end index within a removed range
77
+ }[];
78
+ // local refs used by IntervalOpType.CHANGE and DELETE revertibles
79
+ revertibleRefs: {
80
+ revertible: IntervalRevertible;
81
+ offset: number;
82
+ isStart: boolean;
83
+ }[];
84
+ mergeTreeRevertible: MergeTreeDeltaRevertible;
85
+ };
86
+
87
+ type TypedRevertible<T extends IntervalRevertible["event"]> = IntervalRevertible & { event: T };
88
+
89
+ function getUpdatedIdFromInterval(interval: SequenceInterval): string {
90
+ const maybeId = interval.getIntervalId();
91
+ return getUpdatedId(maybeId);
92
+ }
93
+
94
+ function getUpdatedId(intervalId: string): string {
95
+ return idMap.get(intervalId) ?? intervalId;
96
+ }
97
+
98
+ /**
99
+ * Create revertibles for adding an interval
100
+ * @alpha
101
+ */
102
+ export function appendAddIntervalToRevertibles(
103
+ interval: SequenceInterval,
104
+ revertibles: SharedStringRevertible[],
105
+ ) {
106
+ revertibles.push({
107
+ event: IntervalOpType.ADD,
108
+ interval,
109
+ });
110
+
111
+ return revertibles;
112
+ }
113
+
114
+ /**
115
+ * Create revertibles for deleting an interval
116
+ * @alpha
117
+ */
118
+ export function appendDeleteIntervalToRevertibles(
119
+ string: SharedString,
120
+ interval: SequenceInterval,
121
+ revertibles: SharedStringRevertible[],
122
+ ) {
123
+ const startSeg = interval.start.getSegment() as SharedStringSegment;
124
+ const endSeg = interval.end.getSegment() as SharedStringSegment;
125
+ const startRef = string.createLocalReferencePosition(
126
+ startSeg,
127
+ interval.start.getOffset(),
128
+ ReferenceType.StayOnRemove | ReferenceType.RangeBegin,
129
+ undefined,
130
+ );
131
+ const endRef = string.createLocalReferencePosition(
132
+ endSeg,
133
+ interval.end.getOffset(),
134
+ ReferenceType.StayOnRemove | ReferenceType.RangeEnd,
135
+ undefined,
136
+ );
137
+ const revertible = {
138
+ event: IntervalOpType.DELETE,
139
+ interval,
140
+ start: startRef,
141
+ end: endRef,
142
+ };
143
+ revertible.start.addProperties({ revertible });
144
+ revertible.end.addProperties({ revertible });
145
+ revertibles.push(revertible);
146
+
147
+ return revertibles;
148
+ }
149
+
150
+ /**
151
+ * Create revertibles for moving endpoints of an interval
152
+ * @alpha
153
+ */
154
+ export function appendChangeIntervalToRevertibles(
155
+ string: SharedString,
156
+ newInterval: SequenceInterval,
157
+ previousInterval: SequenceInterval,
158
+ revertibles: SharedStringRevertible[],
159
+ ) {
160
+ const startSeg = previousInterval.start.getSegment() as SharedStringSegment;
161
+ const endSeg = previousInterval.end.getSegment() as SharedStringSegment;
162
+ const prevStartRef = string.createLocalReferencePosition(
163
+ startSeg,
164
+ previousInterval.start.getOffset(),
165
+ ReferenceType.StayOnRemove | ReferenceType.RangeBegin,
166
+ undefined,
167
+ );
168
+ const prevEndRef = string.createLocalReferencePosition(
169
+ endSeg,
170
+ previousInterval.end.getOffset(),
171
+ ReferenceType.StayOnRemove | ReferenceType.RangeEnd,
172
+ undefined,
173
+ );
174
+ const revertible = {
175
+ event: IntervalOpType.CHANGE,
176
+ interval: newInterval,
177
+ start: prevStartRef,
178
+ end: prevEndRef,
179
+ };
180
+ revertible.start.addProperties({ revertible });
181
+ revertible.end.addProperties({ revertible });
182
+ revertibles.push(revertible);
183
+
184
+ return revertibles;
185
+ }
186
+
187
+ /**
188
+ * Create revertibles for changing properties of an interval
189
+ * @alpha
190
+ */
191
+ export function appendIntervalPropertyChangedToRevertibles(
192
+ interval: SequenceInterval,
193
+ deltas: PropertySet,
194
+ revertibles: SharedStringRevertible[],
195
+ ) {
196
+ revertibles.push({
197
+ event: IntervalOpType.PROPERTY_CHANGED,
198
+ interval,
199
+ propertyDeltas: deltas,
200
+ });
201
+
202
+ return revertibles;
203
+ }
204
+
205
+ function addIfIntervalEndpoint(
206
+ ref: LocalReferencePosition,
207
+ segmentLengths: number,
208
+ startIntervals: { offset: number; interval: SequenceInterval }[],
209
+ endIntervals: { offset: number; interval: SequenceInterval }[],
210
+ ) {
211
+ if (refTypeIncludesFlag(ref.refType, ReferenceType.RangeBegin)) {
212
+ const interval = ref.properties?.interval;
213
+ if (interval && interval instanceof SequenceInterval) {
214
+ startIntervals.push({ offset: segmentLengths + interval.start.getOffset(), interval });
215
+ return true;
216
+ }
217
+ } else if (refTypeIncludesFlag(ref.refType, ReferenceType.RangeEnd)) {
218
+ const interval = ref.properties?.interval;
219
+ if (interval && interval instanceof SequenceInterval) {
220
+ endIntervals.push({ offset: segmentLengths + interval.end.getOffset(), interval });
221
+ return true;
222
+ }
223
+ }
224
+ return false;
225
+ }
226
+
227
+ function addIfRevertibleRef(
228
+ ref: LocalReferencePosition,
229
+ segmentLengths: number,
230
+ revertibleRefs: {
231
+ revertible: IntervalRevertible;
232
+ offset: number;
233
+ isStart: boolean;
234
+ }[],
235
+ ) {
236
+ const revertible = ref.properties?.revertible;
237
+ if (revertible) {
238
+ revertibleRefs.push({
239
+ revertible,
240
+ offset: segmentLengths + ref.getOffset(),
241
+ isStart: refTypeIncludesFlag(ref.refType, ReferenceType.RangeBegin),
242
+ });
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Create revertibles for SharedStringDeltas, handling indirectly modified intervals
248
+ * (e.g. reverting remove of a range that contains an interval will move the interval back)
249
+ *
250
+ * Revertibles are new and require the option mergeTreeUseNewLengthCalculations to
251
+ * be set as true on the underlying merge tree in order to function correctly.
252
+ *
253
+ * @alpha
254
+ */
255
+ export function appendSharedStringDeltaToRevertibles(
256
+ string: SharedString,
257
+ delta: SequenceDeltaEvent,
258
+ revertibles: SharedStringRevertible[],
259
+ ) {
260
+ if (delta.ranges.length === 0) {
261
+ return;
262
+ }
263
+ if (delta.deltaOperation === MergeTreeDeltaType.REMOVE) {
264
+ const startIntervals: { offset: number; interval: SequenceInterval }[] = [];
265
+ const endIntervals: { offset: number; interval: SequenceInterval }[] = [];
266
+ const revertibleRefs: {
267
+ revertible: IntervalRevertible;
268
+ offset: number;
269
+ isStart: boolean;
270
+ }[] = [];
271
+ let segmentLengths = 0;
272
+
273
+ // find interval endpoints in each segment
274
+ for (const deltaRange of delta.ranges) {
275
+ const refs = deltaRange.segment.localRefs;
276
+ if (refs !== undefined && deltaRange.position !== -1) {
277
+ for (const ref of refs) {
278
+ addIfIntervalEndpoint(ref, segmentLengths, startIntervals, endIntervals);
279
+ addIfRevertibleRef(ref, segmentLengths, revertibleRefs);
280
+ }
281
+ }
282
+ segmentLengths += deltaRange.segment.cachedLength;
283
+ }
284
+
285
+ if (startIntervals.length > 0 || endIntervals.length > 0 || revertibleRefs.length > 0) {
286
+ const removeRevertibles: MergeTreeDeltaRevertible[] = [];
287
+ appendToMergeTreeDeltaRevertibles(string, delta.deltaArgs, removeRevertibles);
288
+ assert(
289
+ removeRevertibles.length === 1,
290
+ 0x6c4 /* Remove revertible should be a single delta */,
291
+ );
292
+
293
+ const revertible: TypedRevertible<typeof IntervalOpType.POSITION_REMOVE> = {
294
+ event: IntervalOpType.POSITION_REMOVE,
295
+ intervals: [],
296
+ revertibleRefs,
297
+ mergeTreeRevertible: removeRevertibles[0],
298
+ };
299
+
300
+ // add an interval for each startInterval, accounting for any corresponding endIntervals
301
+ startIntervals.forEach(({ interval, offset }) => {
302
+ // find any corresponding end for this interval
303
+ const endIntervalIndex = endIntervals.findIndex((end) => {
304
+ return end.interval === interval;
305
+ });
306
+ let endOffset: number | undefined;
307
+ if (endIntervalIndex !== -1) {
308
+ endOffset = endIntervals[endIntervalIndex].offset;
309
+ endIntervals.splice(endIntervalIndex, 1);
310
+ }
311
+
312
+ revertible.intervals.push({
313
+ intervalId: interval.getIntervalId(),
314
+ label: interval.properties.referenceRangeLabels[0],
315
+ startOffset: offset,
316
+ endOffset,
317
+ });
318
+ });
319
+
320
+ // add any remaining endIntervals that aren't matched with a startInterval
321
+ endIntervals.forEach(({ interval, offset }) => {
322
+ revertible.intervals.push({
323
+ intervalId: interval.getIntervalId(),
324
+ label: interval.properties.referenceRangeLabels[0],
325
+ endOffset: offset,
326
+ });
327
+ });
328
+
329
+ revertibles.push(revertible);
330
+ return;
331
+ }
332
+ }
333
+
334
+ // Handle any merge tree delta that is not REMOVE or is REMOVE with no interval endpoints
335
+ const mergeTreeRevertibles: MergeTreeDeltaRevertible[] = [];
336
+ // Allow merging MergeTreeDeltaRevertible with previous
337
+ if (revertibles.length > 0 && isMergeTreeDeltaRevertible(revertibles[revertibles.length - 1])) {
338
+ mergeTreeRevertibles.push(revertibles.pop() as MergeTreeDeltaRevertible);
339
+ }
340
+ appendToMergeTreeDeltaRevertibles(string, delta.deltaArgs, mergeTreeRevertibles);
341
+ revertibles.push(...mergeTreeRevertibles);
342
+ }
343
+
344
+ /**
345
+ * Clean up resources held by revertibles that are no longer needed.
346
+ * @alpha
347
+ */
348
+ export function discardSharedStringRevertibles(
349
+ sharedString: SharedString,
350
+ revertibles: SharedStringRevertible[],
351
+ ) {
352
+ revertibles.forEach((r) => {
353
+ if (isMergeTreeDeltaRevertible(r)) {
354
+ discardMergeTreeDeltaRevertible([r]);
355
+ } else if (r.event === IntervalOpType.CHANGE || r.event === IntervalOpType.DELETE) {
356
+ sharedString.removeLocalReferencePosition(r.start);
357
+ sharedString.removeLocalReferencePosition(r.end);
358
+ }
359
+ });
360
+ }
361
+
362
+ // Uses of referenceRangeLabels will be removed once AB#4081 is completed.
363
+ function revertLocalAdd(
364
+ string: SharedString,
365
+ revertible: TypedRevertible<typeof IntervalOpType.ADD>,
366
+ ) {
367
+ const id = getUpdatedIdFromInterval(revertible.interval);
368
+ const label = revertible.interval.properties.referenceRangeLabels[0];
369
+ string.getIntervalCollection(label).removeIntervalById(id);
370
+ }
371
+
372
+ function revertLocalDelete(
373
+ string: SharedString,
374
+ revertible: TypedRevertible<typeof IntervalOpType.DELETE>,
375
+ ) {
376
+ const label = revertible.interval.properties.referenceRangeLabels[0];
377
+ const start = string.localReferencePositionToPosition(revertible.start);
378
+ const end = string.localReferencePositionToPosition(revertible.end);
379
+ const type = revertible.interval.intervalType;
380
+ // reusing the id causes eventual consistency bugs, so it is removed here and recreated in add
381
+ const { intervalId, ...props } = revertible.interval.properties;
382
+ const int = string.getIntervalCollection(label).add(start, end, type, props);
383
+
384
+ idMap.forEach((newId, oldId) => {
385
+ if (intervalId === newId) {
386
+ idMap.set(oldId, getUpdatedIdFromInterval(int));
387
+ }
388
+ });
389
+ idMap.set(intervalId, int.getIntervalId());
390
+
391
+ string.removeLocalReferencePosition(revertible.start);
392
+ string.removeLocalReferencePosition(revertible.end);
393
+ }
394
+
395
+ function revertLocalChange(
396
+ string: SharedString,
397
+ revertible: TypedRevertible<typeof IntervalOpType.CHANGE>,
398
+ ) {
399
+ const label = revertible.interval.properties.referenceRangeLabels[0];
400
+ const id = getUpdatedIdFromInterval(revertible.interval);
401
+ const start = string.localReferencePositionToPosition(revertible.start);
402
+ const end = string.localReferencePositionToPosition(revertible.end);
403
+ string.getIntervalCollection(label).change(id, start, end);
404
+
405
+ string.removeLocalReferencePosition(revertible.start);
406
+ string.removeLocalReferencePosition(revertible.end);
407
+ }
408
+
409
+ function revertLocalPropertyChanged(
410
+ string: SharedString,
411
+ revertible: TypedRevertible<typeof IntervalOpType.PROPERTY_CHANGED>,
412
+ ) {
413
+ const label = revertible.interval.properties.referenceRangeLabels[0];
414
+ const id = getUpdatedIdFromInterval(revertible.interval);
415
+ const newProps = revertible.propertyDeltas;
416
+ string.getIntervalCollection(label).changeProperties(id, newProps);
417
+ }
418
+
419
+ function newPosition(offset: number | undefined, restoredRanges: SortedRangeSet) {
420
+ if (offset === undefined) {
421
+ return undefined;
422
+ }
423
+
424
+ let offsetFromSegment = offset;
425
+ for (const rangeInfo of restoredRanges.items) {
426
+ if (offsetFromSegment < rangeInfo.length) {
427
+ // find the segment inside the range
428
+ for (const range of rangeInfo.ranges) {
429
+ if (range.segment.cachedLength > offsetFromSegment) {
430
+ return { segment: range.segment, offset: offsetFromSegment };
431
+ }
432
+ offsetFromSegment -= range.segment.cachedLength;
433
+ }
434
+ }
435
+ offsetFromSegment -= rangeInfo.length;
436
+ }
437
+
438
+ return undefined;
439
+ }
440
+
441
+ function newEndpointPosition(
442
+ offset: number | undefined,
443
+ restoredRanges: SortedRangeSet,
444
+ sharedString: SharedString,
445
+ ) {
446
+ const pos = newPosition(offset, restoredRanges);
447
+ return pos === undefined ? undefined : sharedString.getPosition(pos.segment) + pos.offset;
448
+ }
449
+
450
+ interface RangeInfo {
451
+ ranges: readonly Readonly<ISequenceDeltaRange<MergeTreeDeltaOperationType>>[];
452
+ length: number;
453
+ }
454
+
455
+ class SortedRangeSet extends SortedSet<RangeInfo, string> {
456
+ protected getKey(item: RangeInfo): string {
457
+ return item.ranges[0].segment.ordinal;
458
+ }
459
+ }
460
+
461
+ function revertLocalSequenceRemove(
462
+ sharedString: SharedString,
463
+ revertible: TypedRevertible<typeof IntervalOpType.POSITION_REMOVE>,
464
+ ) {
465
+ const restoredRanges = new SortedRangeSet();
466
+ const saveSegments = (event: SequenceDeltaEvent) => {
467
+ if (event.ranges.length > 0) {
468
+ let length = 0;
469
+ event.ranges.forEach((range) => {
470
+ length += range.segment.cachedLength;
471
+ });
472
+ restoredRanges.addOrUpdate({ ranges: event.ranges, length });
473
+ }
474
+ };
475
+ sharedString.on("sequenceDelta", saveSegments);
476
+ revertMergeTreeDeltaRevertibles(sharedString, [revertible.mergeTreeRevertible]);
477
+ sharedString.off("sequenceDelta", saveSegments);
478
+
479
+ revertible.intervals.forEach((intervalInfo) => {
480
+ const intervalCollection = sharedString.getIntervalCollection(intervalInfo.label);
481
+ const intervalId = getUpdatedId(intervalInfo.intervalId);
482
+ const interval = intervalCollection.getIntervalById(intervalId);
483
+ if (interval !== undefined) {
484
+ const newStart = newEndpointPosition(
485
+ intervalInfo.startOffset,
486
+ restoredRanges,
487
+ sharedString,
488
+ );
489
+ const newEnd = newEndpointPosition(
490
+ intervalInfo.endOffset,
491
+ restoredRanges,
492
+ sharedString,
493
+ );
494
+ if (newStart !== undefined || newEnd !== undefined) {
495
+ intervalCollection.change(intervalId, newStart, newEnd);
496
+ }
497
+ }
498
+ });
499
+
500
+ // fix up the local references used by delete and change revertibles
501
+ revertible.revertibleRefs.forEach((revertibleRef) => {
502
+ assert(
503
+ revertibleRef.revertible.event === IntervalOpType.CHANGE ||
504
+ revertibleRef.revertible.event === IntervalOpType.DELETE,
505
+ 0x6c5 /* revertible is not delete or change */,
506
+ );
507
+ const pos = newPosition(revertibleRef.offset, restoredRanges);
508
+ if (pos !== undefined) {
509
+ if (revertibleRef.isStart) {
510
+ sharedString.removeLocalReferencePosition(revertibleRef.revertible.start);
511
+ const newRef = sharedString.createLocalReferencePosition(
512
+ pos.segment as SharedStringSegment,
513
+ pos.offset,
514
+ ReferenceType.StayOnRemove | ReferenceType.RangeBegin,
515
+ { revertible: revertibleRef.revertible },
516
+ );
517
+ revertibleRef.revertible.start = newRef;
518
+ } else {
519
+ sharedString.removeLocalReferencePosition(revertibleRef.revertible.end);
520
+ const newRef = sharedString.createLocalReferencePosition(
521
+ pos.segment as SharedStringSegment,
522
+ pos.offset,
523
+ ReferenceType.StayOnRemove | ReferenceType.RangeEnd,
524
+ { revertible: revertibleRef.revertible },
525
+ );
526
+ revertibleRef.revertible.end = newRef;
527
+ }
528
+ }
529
+ });
530
+ }
531
+
532
+ /**
533
+ * Invoke revertibles to reverse prior edits
534
+ *
535
+ * Revertibles are new and require the option mergeTreeUseNewLengthCalculations to
536
+ * be set as true on the underlying merge tree in order to function correctly.
537
+ *
538
+ * @alpha
539
+ */
540
+ export function revertSharedStringRevertibles(
541
+ sharedString: SharedString,
542
+ revertibles: SharedStringRevertible[],
543
+ ) {
544
+ while (revertibles.length > 0) {
545
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
546
+ const r = revertibles.pop()!;
547
+ if ("event" in r) {
548
+ const event = r.event;
549
+ switch (event) {
550
+ case IntervalOpType.ADD:
551
+ revertLocalAdd(sharedString, r);
552
+ break;
553
+ case IntervalOpType.DELETE:
554
+ revertLocalDelete(sharedString, r);
555
+ break;
556
+ case IntervalOpType.CHANGE:
557
+ revertLocalChange(sharedString, r);
558
+ break;
559
+ case IntervalOpType.PROPERTY_CHANGED:
560
+ revertLocalPropertyChanged(sharedString, r);
561
+ break;
562
+ case IntervalOpType.POSITION_REMOVE:
563
+ revertLocalSequenceRemove(sharedString, r);
564
+ break;
565
+ default:
566
+ unreachableCase(event);
567
+ }
568
+ } else {
569
+ revertMergeTreeDeltaRevertibles(sharedString, [r]);
570
+ }
571
+ }
572
+ }
package/src/sequence.ts CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  ReferenceType,
36
36
  MergeTreeRevertibleDriver,
37
37
  SegmentGroup,
38
+ SlidingPreference,
38
39
  } from "@fluidframework/merge-tree";
39
40
  import { ObjectStoragePartition, SummaryTreeBuilder } from "@fluidframework/runtime-utils";
40
41
  import {
@@ -48,7 +49,7 @@ import {
48
49
  import { IEventThisPlaceHolder } from "@fluidframework/common-definitions";
49
50
  import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
50
51
 
51
- import { DefaultMap } from "./defaultMap";
52
+ import { DefaultMap, IMapOperation } from "./defaultMap";
52
53
  import { IMapMessageLocalMetadata, IValueChanged } from "./defaultMapInterfaces";
53
54
  import {
54
55
  IntervalCollection,
@@ -219,6 +220,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
219
220
  this.handle,
220
221
  (op, localOpMetadata) => this.submitLocalMessage(op, localOpMetadata),
221
222
  new SequenceIntervalCollectionValueType(),
223
+ dataStoreRuntime.options,
222
224
  );
223
225
  }
224
226
 
@@ -307,8 +309,15 @@ export abstract class SharedSegmentSequence<T extends ISegment>
307
309
  offset: number,
308
310
  refType: ReferenceType,
309
311
  properties: PropertySet | undefined,
312
+ slidingPreference?: SlidingPreference,
310
313
  ): LocalReferencePosition {
311
- return this.client.createLocalReferencePosition(segment, offset, refType, properties);
314
+ return this.client.createLocalReferencePosition(
315
+ segment,
316
+ offset,
317
+ refType,
318
+ properties,
319
+ slidingPreference,
320
+ );
312
321
  }
313
322
 
314
323
  /**
@@ -634,7 +643,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
634
643
  );
635
644
 
636
645
  const handled = this.intervalCollections.tryProcessMessage(
637
- message.contents,
646
+ message.contents as IMapOperation,
638
647
  local,
639
648
  message,
640
649
  localOpMetadata,
@@ -24,7 +24,7 @@ import {
24
24
  IntervalCollectionValueType,
25
25
  ISerializableInterval,
26
26
  } from "./intervalCollection";
27
- import { DefaultMap } from "./defaultMap";
27
+ import { DefaultMap, IMapOperation } from "./defaultMap";
28
28
  import { pkgVersion } from "./packageVersion";
29
29
  import { IMapMessageLocalMetadata } from "./defaultMapInterfaces";
30
30
 
@@ -122,6 +122,7 @@ export class SharedIntervalCollection
122
122
  this.handle,
123
123
  (op, localOpMetadata) => this.submitLocalMessage(op, localOpMetadata),
124
124
  new IntervalCollectionValueType(),
125
+ runtime.options,
125
126
  );
126
127
  }
127
128
 
@@ -163,7 +164,7 @@ export class SharedIntervalCollection
163
164
  ) {
164
165
  if (message.type === MessageType.Operation) {
165
166
  this.intervalCollections.tryProcessMessage(
166
- message.contents,
167
+ message.contents as IMapOperation,
167
168
  local,
168
169
  message,
169
170
  localOpMetadata,
@@ -1,16 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "name": "Sequence Test",
9
- "type": "node",
10
- "request": "launch",
11
- "program": "${workspaceRoot}/../../../node_modules/mocha/bin/_mocha",
12
- "args": ["dist/test", "--no-timeouts", "--exit"],
13
- "cwd": "${workspaceRoot}"
14
- }
15
- ]
16
- }