@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
|
@@ -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
|
+
}
|
package/src/packageVersion.ts
CHANGED
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
*
|
|
412
|
-
*
|
|
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
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
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
|
}
|