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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/defaultMap.d.ts.map +1 -1
  2. package/dist/defaultMap.js +1 -0
  3. package/dist/defaultMap.js.map +1 -1
  4. package/dist/index.d.ts +4 -5
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -4
  7. package/dist/index.js.map +1 -1
  8. package/dist/intervalCollection.d.ts +271 -34
  9. package/dist/intervalCollection.d.ts.map +1 -1
  10. package/dist/intervalCollection.js +343 -97
  11. package/dist/intervalCollection.js.map +1 -1
  12. package/dist/intervalTree.d.ts +72 -0
  13. package/dist/intervalTree.d.ts.map +1 -0
  14. package/dist/intervalTree.js +91 -0
  15. package/dist/intervalTree.js.map +1 -0
  16. package/dist/packageVersion.d.ts +1 -1
  17. package/dist/packageVersion.js +1 -1
  18. package/dist/packageVersion.js.map +1 -1
  19. package/dist/sequence.d.ts +66 -15
  20. package/dist/sequence.d.ts.map +1 -1
  21. package/dist/sequence.js +73 -19
  22. package/dist/sequence.js.map +1 -1
  23. package/dist/sequenceDeltaEvent.d.ts +15 -1
  24. package/dist/sequenceDeltaEvent.d.ts.map +1 -1
  25. package/dist/sequenceDeltaEvent.js +2 -1
  26. package/dist/sequenceDeltaEvent.js.map +1 -1
  27. package/dist/sequenceFactory.d.ts +0 -89
  28. package/dist/sequenceFactory.d.ts.map +1 -1
  29. package/dist/sequenceFactory.js +2 -142
  30. package/dist/sequenceFactory.js.map +1 -1
  31. package/dist/sharedIntervalCollection.d.ts +0 -6
  32. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  33. package/dist/sharedIntervalCollection.js +0 -7
  34. package/dist/sharedIntervalCollection.js.map +1 -1
  35. package/dist/sharedSequence.d.ts +2 -2
  36. package/dist/sharedString.d.ts +16 -15
  37. package/dist/sharedString.d.ts.map +1 -1
  38. package/dist/sharedString.js +96 -15
  39. package/dist/sharedString.js.map +1 -1
  40. package/lib/defaultMap.d.ts.map +1 -1
  41. package/lib/defaultMap.js +1 -0
  42. package/lib/defaultMap.js.map +1 -1
  43. package/lib/index.d.ts +4 -5
  44. package/lib/index.d.ts.map +1 -1
  45. package/lib/index.js +2 -4
  46. package/lib/index.js.map +1 -1
  47. package/lib/intervalCollection.d.ts +271 -34
  48. package/lib/intervalCollection.d.ts.map +1 -1
  49. package/lib/intervalCollection.js +341 -98
  50. package/lib/intervalCollection.js.map +1 -1
  51. package/lib/intervalTree.d.ts +72 -0
  52. package/lib/intervalTree.d.ts.map +1 -0
  53. package/lib/intervalTree.js +86 -0
  54. package/lib/intervalTree.js.map +1 -0
  55. package/lib/packageVersion.d.ts +1 -1
  56. package/lib/packageVersion.js +1 -1
  57. package/lib/packageVersion.js.map +1 -1
  58. package/lib/sequence.d.ts +66 -15
  59. package/lib/sequence.d.ts.map +1 -1
  60. package/lib/sequence.js +73 -19
  61. package/lib/sequence.js.map +1 -1
  62. package/lib/sequenceDeltaEvent.d.ts +15 -1
  63. package/lib/sequenceDeltaEvent.d.ts.map +1 -1
  64. package/lib/sequenceDeltaEvent.js +2 -1
  65. package/lib/sequenceDeltaEvent.js.map +1 -1
  66. package/lib/sequenceFactory.d.ts +0 -89
  67. package/lib/sequenceFactory.d.ts.map +1 -1
  68. package/lib/sequenceFactory.js +1 -139
  69. package/lib/sequenceFactory.js.map +1 -1
  70. package/lib/sharedIntervalCollection.d.ts +0 -6
  71. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  72. package/lib/sharedIntervalCollection.js +0 -7
  73. package/lib/sharedIntervalCollection.js.map +1 -1
  74. package/lib/sharedSequence.d.ts +2 -2
  75. package/lib/sharedString.d.ts +16 -15
  76. package/lib/sharedString.d.ts.map +1 -1
  77. package/lib/sharedString.js +97 -16
  78. package/lib/sharedString.js.map +1 -1
  79. package/package.json +99 -27
  80. package/src/defaultMap.ts +3 -0
  81. package/src/index.ts +4 -4
  82. package/src/intervalCollection.ts +486 -143
  83. package/src/intervalTree.ts +166 -0
  84. package/src/packageVersion.ts +1 -1
  85. package/src/sequence.ts +86 -30
  86. package/src/sequenceDeltaEvent.ts +18 -4
  87. package/src/sequenceFactory.ts +2 -163
  88. package/src/sharedIntervalCollection.ts +0 -11
  89. package/src/sharedString.ts +120 -23
  90. package/tsconfig.json +0 -1
  91. package/dist/sharedNumberSequence.d.ts +0 -50
  92. package/dist/sharedNumberSequence.d.ts.map +0 -1
  93. package/dist/sharedNumberSequence.js +0 -61
  94. package/dist/sharedNumberSequence.js.map +0 -1
  95. package/dist/sharedObjectSequence.d.ts +0 -50
  96. package/dist/sharedObjectSequence.d.ts.map +0 -1
  97. package/dist/sharedObjectSequence.js +0 -61
  98. package/dist/sharedObjectSequence.js.map +0 -1
  99. package/dist/sparsematrix.d.ts +0 -152
  100. package/dist/sparsematrix.d.ts.map +0 -1
  101. package/dist/sparsematrix.js +0 -343
  102. package/dist/sparsematrix.js.map +0 -1
  103. package/lib/sharedNumberSequence.d.ts +0 -50
  104. package/lib/sharedNumberSequence.d.ts.map +0 -1
  105. package/lib/sharedNumberSequence.js +0 -57
  106. package/lib/sharedNumberSequence.js.map +0 -1
  107. package/lib/sharedObjectSequence.d.ts +0 -50
  108. package/lib/sharedObjectSequence.d.ts.map +0 -1
  109. package/lib/sharedObjectSequence.js +0 -57
  110. package/lib/sharedObjectSequence.js.map +0 -1
  111. package/lib/sparsematrix.d.ts +0 -152
  112. package/lib/sparsematrix.d.ts.map +0 -1
  113. package/lib/sparsematrix.js +0 -334
  114. package/lib/sparsematrix.js.map +0 -1
  115. package/src/sharedNumberSequence.ts +0 -62
  116. package/src/sharedObjectSequence.ts +0 -62
  117. package/src/sparsematrix.ts +0 -434
@@ -0,0 +1,166 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ IIntegerRange,
8
+ RBNode,
9
+ IRBAugmentation,
10
+ IRBMatcher,
11
+ RedBlackTree,
12
+ ConflictAction,
13
+ RBNodeActions,
14
+ } from "@fluidframework/merge-tree";
15
+ import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
16
+
17
+ export interface AugmentedIntervalNode {
18
+ minmax: IInterval;
19
+ }
20
+
21
+ export const integerRangeToString = (range: IIntegerRange) => `[${range.start},${range.end})`;
22
+
23
+ /**
24
+ * Basic interval abstraction
25
+ */
26
+ export interface IInterval {
27
+ /**
28
+ * @returns a new interval object with identical semantics.
29
+ */
30
+ clone(): IInterval;
31
+ /**
32
+ * Compares this interval to `b` with standard comparator semantics:
33
+ * - returns -1 if this is less than `b`
34
+ * - returns 1 if this is greater than `b`
35
+ * - returns 0 if this is equivalent to `b`
36
+ * @param b - Interval to compare against
37
+ */
38
+ compare(b: IInterval): number;
39
+ /**
40
+ * Compares the start endpoint of this interval to `b`'s start endpoint.
41
+ * Standard comparator semantics apply.
42
+ * @param b - Interval to compare against
43
+ */
44
+ compareStart(b: IInterval): number;
45
+ /**
46
+ * Compares the end endpoint of this interval to `b`'s end endpoint.
47
+ * Standard comparator semantics apply.
48
+ * @param b - Interval to compare against
49
+ */
50
+ compareEnd(b: IInterval): number;
51
+ /**
52
+ * Modifies one or more of the endpoints of this interval, returning a new interval representing the result.
53
+ * @internal
54
+ */
55
+ modify(
56
+ label: string,
57
+ start: number | undefined,
58
+ end: number | undefined,
59
+ op?: ISequencedDocumentMessage,
60
+ localSeq?: number
61
+ ): IInterval | undefined;
62
+ /**
63
+ * @returns whether this interval overlaps with `b`.
64
+ * Since intervals are inclusive, this includes cases where endpoints are equal.
65
+ */
66
+ overlaps(b: IInterval): boolean;
67
+ /**
68
+ * Unions this interval with `b`, returning a new interval.
69
+ * The union operates as a convex hull, i.e. if the two intervals are disjoint, the return value includes
70
+ * intermediate values between the two intervals.
71
+ * @internal
72
+ */
73
+ union(b: IInterval): IInterval;
74
+ }
75
+
76
+ const intervalComparer = (a: IInterval, b: IInterval) => a.compare(b);
77
+
78
+ export type IntervalNode<T extends IInterval> = RBNode<T, AugmentedIntervalNode>;
79
+
80
+ export type IntervalConflictResolver<TInterval> = (a: TInterval, b: TInterval) => TInterval;
81
+
82
+ export class IntervalTree<T extends IInterval> implements IRBAugmentation<T, AugmentedIntervalNode>,
83
+ IRBMatcher<T, AugmentedIntervalNode> {
84
+ public intervals = new RedBlackTree<T, AugmentedIntervalNode>(intervalComparer, this);
85
+
86
+ public remove(x: T) {
87
+ this.intervals.remove(x);
88
+ }
89
+
90
+ public removeExisting(x: T) {
91
+ this.intervals.removeExisting(x);
92
+ }
93
+
94
+ public put(x: T, conflict?: IntervalConflictResolver<T>) {
95
+ let rbConflict: ConflictAction<T, AugmentedIntervalNode> | undefined;
96
+ if (conflict) {
97
+ rbConflict = (key: T, currentKey: T) => {
98
+ const ival = conflict(key, currentKey);
99
+ return {
100
+ key: ival,
101
+ };
102
+ };
103
+ }
104
+ this.intervals.put(x, { minmax: x.clone() }, rbConflict);
105
+ }
106
+
107
+ public map(fn: (x: T) => void) {
108
+ const actions: RBNodeActions<T, AugmentedIntervalNode> = {
109
+ infix: (node) => {
110
+ fn(node.key);
111
+ return true;
112
+ },
113
+ showStructure: true,
114
+ };
115
+ this.intervals.walk(actions);
116
+ }
117
+
118
+ public mapUntil(fn: (X: T) => boolean) {
119
+ const actions: RBNodeActions<T, AugmentedIntervalNode> = {
120
+ infix: (node) => {
121
+ return fn(node.key);
122
+ },
123
+ showStructure: true,
124
+ };
125
+ this.intervals.walk(actions);
126
+ }
127
+
128
+ public mapBackward(fn: (x: T) => void) {
129
+ const actions: RBNodeActions<T, AugmentedIntervalNode> = {
130
+ infix: (node) => {
131
+ fn(node.key);
132
+ return true;
133
+ },
134
+ showStructure: true,
135
+ };
136
+ this.intervals.walkBackward(actions);
137
+ }
138
+
139
+ // TODO: toString()
140
+ public match(x: T) {
141
+ return this.intervals.gather(x, this);
142
+ }
143
+
144
+ public matchNode(node: IntervalNode<T> | undefined, key: T) {
145
+ return !!node && node.key.overlaps(key);
146
+ }
147
+
148
+ public continueSubtree(node: IntervalNode<T> | undefined, key: T) {
149
+ return !!node && node.data.minmax.overlaps(key);
150
+ }
151
+
152
+ public update(node: IntervalNode<T>) {
153
+ if (node.left && node.right) {
154
+ node.data.minmax = node.key.union(
155
+ node.left.data.minmax.union(node.right.data.minmax));
156
+ } else {
157
+ if (node.left) {
158
+ node.data.minmax = node.key.union(node.left.data.minmax);
159
+ } else if (node.right) {
160
+ node.data.minmax = node.key.union(node.right.data.minmax);
161
+ } else {
162
+ node.data.minmax = node.key.clone();
163
+ }
164
+ }
165
+ }
166
+ }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/sequence";
9
- export const pkgVersion = "2.0.0-internal.1.4.2";
9
+ export const pkgVersion = "2.0.0-internal.2.0.0";
package/src/sequence.ts CHANGED
@@ -36,6 +36,7 @@ import {
36
36
  RangeStackMap,
37
37
  ReferencePosition,
38
38
  ReferenceType,
39
+ MergeTreeRevertibleDriver,
39
40
  SegmentGroup,
40
41
  } from "@fluidframework/merge-tree";
41
42
  import { ObjectStoragePartition, SummaryTreeBuilder } from "@fluidframework/runtime-utils";
@@ -50,13 +51,13 @@ import {
50
51
  import { IEventThisPlaceHolder } from "@fluidframework/common-definitions";
51
52
  import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
52
53
 
54
+ import { DefaultMap } from "./defaultMap";
55
+ import { IMapMessageLocalMetadata, IValueChanged } from "./defaultMapInterfaces";
53
56
  import {
54
57
  IntervalCollection,
55
58
  SequenceInterval,
56
59
  SequenceIntervalCollectionValueType,
57
60
  } from "./intervalCollection";
58
- import { DefaultMap } from "./defaultMap";
59
- import { IMapMessageLocalMetadata, IValueChanged } from "./defaultMapInterfaces";
60
61
  import { SequenceDeltaEvent, SequenceMaintenanceEvent } from "./sequenceDeltaEvent";
61
62
  import { ISharedIntervalCollection } from "./sharedIntervalCollection";
62
63
 
@@ -106,7 +107,7 @@ export interface ISharedSegmentSequenceEvents extends ISharedObjectEvents {
106
107
 
107
108
  export abstract class SharedSegmentSequence<T extends ISegment>
108
109
  extends SharedObject<ISharedSegmentSequenceEvents>
109
- implements ISharedIntervalCollection<SequenceInterval> {
110
+ implements ISharedIntervalCollection<SequenceInterval>, MergeTreeRevertibleDriver {
110
111
  get loaded(): Promise<void> {
111
112
  return this.loadedDeferred.promise;
112
113
  }
@@ -143,6 +144,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
143
144
  case MergeTreeDeltaType.REMOVE: {
144
145
  const lastRem = ops[ops.length - 1] as IMergeTreeRemoveMsg;
145
146
  if (lastRem?.pos1 === r.position) {
147
+ assert(lastRem.pos2 !== undefined, 0x3ff /* pos2 should not be undefined here */);
146
148
  lastRem.pos2 += r.segment.cachedLength;
147
149
  } else {
148
150
  ops.push(createRemoveRangeOp(
@@ -159,7 +161,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
159
161
  }
160
162
 
161
163
  protected client: Client;
162
- // Deferred that triggers once the object is loaded
164
+ /** `Deferred` that triggers once the object is loaded */
163
165
  protected loadedDeferred = new Deferred<void>();
164
166
  // cache out going ops created when partial loading
165
167
  private readonly loadedDeferredOutgoingOps:
@@ -237,9 +239,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
237
239
  */
238
240
  public removeRange(start: number, end: number): IMergeTreeRemoveMsg {
239
241
  const removeOp = this.client.removeRangeLocal(start, end);
240
- if (removeOp) {
241
- this.submitSequenceMessage(removeOp);
242
- }
242
+ this.submitSequenceMessage(removeOp);
243
243
  return removeOp;
244
244
  }
245
245
 
@@ -248,7 +248,12 @@ export abstract class SharedSegmentSequence<T extends ISegment>
248
248
  this.submitSequenceMessage(groupOp);
249
249
  }
250
250
 
251
- public getContainingSegment(pos: number) {
251
+ /**
252
+ * Finds the segment information (i.e. segment + offset) corresponding to a character position in the SharedString.
253
+ * If the position is past the end of the string, `segment` and `offset` on the returned object may be undefined.
254
+ * @param pos - Character position (index) into the current local view of the SharedString.
255
+ */
256
+ public getContainingSegment(pos: number): { segment: T | undefined; offset: number | undefined; } {
252
257
  return this.client.getContainingSegment<T>(pos);
253
258
  }
254
259
 
@@ -297,6 +302,14 @@ export abstract class SharedSegmentSequence<T extends ISegment>
297
302
  return this.client.getRangeExtentsOfPosition(pos);
298
303
  }
299
304
 
305
+ /**
306
+ * Creates a `LocalReferencePosition` on this SharedString. If the refType does not include
307
+ * ReferenceType.Transient, the returned reference will be added to the localRefs on the provided segment.
308
+ * @param segment - Segment to add the local reference on
309
+ * @param offset - Offset on the segment at which to place the local reference
310
+ * @param refType - ReferenceType for the created local reference
311
+ * @param properties - PropertySet to place on the created local reference
312
+ */
300
313
  public createLocalReferencePosition(
301
314
  segment: T,
302
315
  offset: number,
@@ -309,10 +322,20 @@ export abstract class SharedSegmentSequence<T extends ISegment>
309
322
  properties);
310
323
  }
311
324
 
325
+ /**
326
+ * Resolves a `ReferencePosition` into a character position using this client's perspective.
327
+ */
312
328
  public localReferencePositionToPosition(lref: ReferencePosition): number {
313
329
  return this.client.localReferencePositionToPosition(lref);
314
330
  }
315
331
 
332
+ /**
333
+ * Removes a `LocalReferencePosition` from this SharedString.
334
+ */
335
+ public removeLocalReferencePosition(lref: LocalReferencePosition) {
336
+ return this.client.removeLocalReferencePosition(lref);
337
+ }
338
+
316
339
  /**
317
340
  * Resolves a remote client's position against the local sequence
318
341
  * and returns the remote client's position relative to the local
@@ -330,11 +353,12 @@ export abstract class SharedSegmentSequence<T extends ISegment>
330
353
  public resolveRemoteClientPosition(
331
354
  remoteClientPosition: number,
332
355
  remoteClientRefSeq: number,
333
- remoteClientId: string): number {
356
+ remoteClientId: string): number | undefined {
334
357
  return this.client.resolveRemoteClientPosition(
335
358
  remoteClientPosition,
336
359
  remoteClientRefSeq,
337
- remoteClientId);
360
+ remoteClientId,
361
+ );
338
362
  }
339
363
 
340
364
  public submitSequenceMessage(message: IMergeTreeOp) {
@@ -349,16 +373,12 @@ export abstract class SharedSegmentSequence<T extends ISegment>
349
373
  // local ops until loading is complete, and then
350
374
  // they will be resent
351
375
  if (!this.loadedDeferred.isCompleted) {
352
- this.loadedDeferredOutgoingOps.push([translated, metadata]);
376
+ this.loadedDeferredOutgoingOps.push(metadata ? [translated, metadata] : translated);
353
377
  } else {
354
378
  this.submitLocalMessage(translated, metadata);
355
379
  }
356
380
  }
357
381
 
358
- public removeLocalReferencePosition(lref: LocalReferencePosition) {
359
- return this.client.removeLocalReferencePosition(lref);
360
- }
361
-
362
382
  /**
363
383
  * Given a position specified relative to a marker id, lookup the marker
364
384
  * and convert the position to a character position.
@@ -383,40 +403,54 @@ export abstract class SharedSegmentSequence<T extends ISegment>
383
403
  */
384
404
  public walkSegments<TClientData>(
385
405
  handler: ISegmentAction<TClientData>,
386
- start?: number, end?: number, accum?: TClientData,
387
- splitRange: boolean = false) {
388
- return this.client.walkSegments<TClientData>(handler, start, end, accum, splitRange);
406
+ start?: number,
407
+ end?: number,
408
+ accum?: TClientData,
409
+ splitRange: boolean = false,
410
+ ): void {
411
+ this.client.walkSegments(handler, start, end, accum as TClientData, splitRange);
389
412
  }
390
413
 
391
- /**
392
- * @deprecated for internal use only. public export will be removed.
393
- * @internal
394
- */
395
414
  public getStackContext(startPos: number, rangeLabels: string[]): RangeStackMap {
396
415
  return this.client.getStackContext(startPos, rangeLabels);
397
416
  }
398
417
 
418
+ /**
419
+ * @returns - The most recent sequence number which has been acked by the server and processed by this
420
+ * SharedSegmentSequence.
421
+ */
399
422
  public getCurrentSeq() {
400
423
  return this.client.getCurrentSeq();
401
424
  }
402
425
 
426
+ /**
427
+ * Inserts a segment directly before a `ReferencePosition`.
428
+ * @param refPos - The reference position to insert the segment at
429
+ * @param segment - The segment to insert
430
+ */
403
431
  public insertAtReferencePosition(pos: ReferencePosition, segment: T) {
404
432
  const insertOp = this.client.insertAtReferencePositionLocal(pos, segment);
405
433
  if (insertOp) {
406
434
  this.submitSequenceMessage(insertOp);
407
435
  }
408
436
  }
409
-
410
437
  /**
411
- * @deprecated `IntervalCollection`s are created on a first-write wins basis, and concurrent creates
412
- * are supported. Use {@link SharedSegmentSequence.getIntervalCollection} instead.
438
+ * Inserts a segment
439
+ * @param start - The position to insert the segment at
440
+ * @param spec - The segment to inserts spec
413
441
  */
414
- public async waitIntervalCollection(
415
- label: string,
416
- ): Promise<IntervalCollection<SequenceInterval>> {
417
- return this.intervalCollections.get(label);
442
+ public insertFromSpec(pos: number, spec: IJSONSegment) {
443
+ const segment = this.segmentFromSpec(spec);
444
+ const insertOp = this.client.insertSegmentLocal(pos, segment);
445
+ if (insertOp) {
446
+ this.submitSequenceMessage(insertOp);
447
+ }
418
448
  }
419
449
 
450
+ /**
451
+ * Retrieves the interval collection keyed on `label`. If no such interval collection exists,
452
+ * creates one.
453
+ */
420
454
  public getIntervalCollection(label: string): IntervalCollection<SequenceInterval> {
421
455
  return this.intervalCollections.get(label);
422
456
  }
@@ -436,6 +470,9 @@ export abstract class SharedSegmentSequence<T extends ISegment>
436
470
  return this.intervalCollections.keys();
437
471
  }
438
472
 
473
+ /**
474
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.summarizeCore}
475
+ */
439
476
  protected summarizeCore(
440
477
  serializer: IFluidSerializer,
441
478
  telemetryContext?: ITelemetryContext,
@@ -483,20 +520,30 @@ export abstract class SharedSegmentSequence<T extends ISegment>
483
520
  if (insert) {
484
521
  if (start < end) {
485
522
  const remove = this.client.removeRangeLocal(start, end);
486
- this.submitSequenceMessage(createGroupOp(insert, remove));
523
+ const op = remove ? createGroupOp(insert, remove) : insert;
524
+ this.submitSequenceMessage(op);
487
525
  } else {
488
526
  this.submitSequenceMessage(insert);
489
527
  }
490
528
  }
491
529
  }
492
530
 
531
+ /**
532
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.onConnect}
533
+ */
493
534
  protected onConnect() {
494
535
  // Update merge tree collaboration information with new client ID and then resend pending ops
495
536
  this.client.startOrUpdateCollaboration(this.runtime.clientId);
496
537
  }
497
538
 
539
+ /**
540
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.onDisconnect}
541
+ */
498
542
  protected onDisconnect() { }
499
543
 
544
+ /**
545
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.reSubmitCore}
546
+ */
500
547
  protected reSubmitCore(content: any, localOpMetadata: unknown) {
501
548
  if (!this.intervalCollections.tryResubmitMessage(content, localOpMetadata as IMapMessageLocalMetadata)) {
502
549
  this.submitSequenceMessage(
@@ -564,6 +611,9 @@ export abstract class SharedSegmentSequence<T extends ISegment>
564
611
  }
565
612
  }
566
613
 
614
+ /**
615
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processCore}
616
+ */
567
617
  protected processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown) {
568
618
  // if loading isn't complete, we need to cache all
569
619
  // incoming ops to be applied after loading is complete
@@ -586,6 +636,9 @@ export abstract class SharedSegmentSequence<T extends ISegment>
586
636
  }
587
637
  }
588
638
 
639
+ /**
640
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.didAttach}
641
+ */
589
642
  protected didAttach() {
590
643
  // If we are not local, and we've attached we need to start generating and sending ops
591
644
  // so start collaboration and provide a default client id incase we are not connected
@@ -594,6 +647,9 @@ export abstract class SharedSegmentSequence<T extends ISegment>
594
647
  }
595
648
  }
596
649
 
650
+ /**
651
+ * {@inheritDoc @fluidframework/shared-object-base#SharedObject.initializeLocalCore}
652
+ */
597
653
  protected initializeLocalCore() {
598
654
  super.initializeLocalCore();
599
655
  this.loadFinished();
@@ -44,7 +44,7 @@ export abstract class SequenceEvent<TOperation extends MergeTreeDeltaOperationTy
44
44
  const newRange: ISequenceDeltaRange<TOperation> = {
45
45
  operation: this.deltaArgs.operation,
46
46
  position: this.mergeTreeClient.getPosition(delta.segment),
47
- propertyDeltas: delta.propertyDeltas,
47
+ propertyDeltas: delta.propertyDeltas ?? {},
48
48
  segment: delta.segment,
49
49
  };
50
50
  set.addOrUpdate(newRange);
@@ -72,7 +72,7 @@ export abstract class SequenceEvent<TOperation extends MergeTreeDeltaOperationTy
72
72
  /**
73
73
  * The client id of the client that made the change which caused the delta event
74
74
  */
75
- public get clientId(): string {
75
+ public get clientId(): string | undefined {
76
76
  return this.mergeTreeClient.longClientId;
77
77
  }
78
78
 
@@ -139,6 +139,11 @@ export class SequenceMaintenanceEvent extends SequenceEvent<MergeTreeMaintenance
139
139
  * A range that has changed corresponding to a segment modification.
140
140
  */
141
141
  export interface ISequenceDeltaRange<TOperation extends MergeTreeDeltaOperationTypes = MergeTreeDeltaOperationTypes> {
142
+ /**
143
+ * The type of operation that changed this range.
144
+ * @remarks - Consuming code should typically compare this to the enum values defined in
145
+ * `MergeTreeDeltaOperationTypes`.
146
+ */
142
147
  operation: TOperation;
143
148
  /**
144
149
  * The index of the start of the range.
@@ -148,11 +153,20 @@ export interface ISequenceDeltaRange<TOperation extends MergeTreeDeltaOperationT
148
153
  * The segment that corresponds to the range.
149
154
  */
150
155
  segment: ISegment;
156
+ /**
157
+ * Deltas object which contains all modified properties with their previous values.
158
+ * Since `undefined` doesn't survive a round-trip through JSON serialization, the old value being absent
159
+ * is instead encoded with `null`.
160
+ * @remarks - This object is motivated by undo/redo scenarios, and provides a convenient "inverse op" to apply to
161
+ * undo a property change.
162
+ * @example - If a segment initially had properties `{ foo: "1", bar: 2 }` and it was annotated with
163
+ * `{ foo: 3, baz: 5 }`, the corresponding event would have a `propertyDeltas` of `{ foo: "1", baz: null }`.
164
+ */
151
165
  propertyDeltas: PropertySet;
152
166
  }
153
167
 
154
168
  class Lazy<T> {
155
- private pValue: T;
169
+ private pValue: T | undefined;
156
170
  private pEvaluated: boolean;
157
171
  constructor(private readonly valueGenerator: () => T) {
158
172
  this.pEvaluated = false;
@@ -167,6 +181,6 @@ class Lazy<T> {
167
181
  this.pEvaluated = true;
168
182
  this.pValue = this.valueGenerator();
169
183
  }
170
- return this.pValue;
184
+ return this.pValue as T;
171
185
  }
172
186
  }