@fluidframework/merge-tree 1.2.7 → 2.0.0-dev.1.3.0.96595
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/.mocharc.js +12 -0
- package/README.md +2 -2
- package/dist/MergeTreeTextHelper.d.ts +23 -0
- package/dist/MergeTreeTextHelper.d.ts.map +1 -0
- package/dist/MergeTreeTextHelper.js +133 -0
- package/dist/MergeTreeTextHelper.js.map +1 -0
- package/dist/base.d.ts +2 -26
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js.map +1 -1
- package/dist/client.d.ts +27 -16
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +81 -101
- package/dist/client.js.map +1 -1
- package/dist/collections/heap.d.ts +28 -0
- package/dist/collections/heap.d.ts.map +1 -0
- package/dist/collections/heap.js +65 -0
- package/dist/collections/heap.js.map +1 -0
- package/dist/collections/index.d.ts +11 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +23 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/intervalTree.d.ts +60 -0
- package/dist/collections/intervalTree.d.ts.map +1 -0
- package/dist/collections/intervalTree.js +99 -0
- package/dist/collections/intervalTree.js.map +1 -0
- package/dist/collections/list.d.ts +39 -0
- package/dist/collections/list.d.ts.map +1 -0
- package/dist/collections/list.js +155 -0
- package/dist/collections/list.js.map +1 -0
- package/dist/collections/rbTree.d.ts +154 -0
- package/dist/collections/rbTree.d.ts.map +1 -0
- package/dist/{collections.js → collections/rbTree.js} +15 -478
- package/dist/collections/rbTree.js.map +1 -0
- package/dist/collections/stack.d.ts +16 -0
- package/dist/collections/stack.d.ts.map +1 -0
- package/dist/collections/stack.js +30 -0
- package/dist/collections/stack.js.map +1 -0
- package/dist/collections/tst.d.ts +55 -0
- package/dist/collections/tst.d.ts.map +1 -0
- package/dist/collections/tst.js +171 -0
- package/dist/collections/tst.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/localReference.d.ts +48 -99
- package/dist/localReference.d.ts.map +1 -1
- package/dist/localReference.js +132 -169
- package/dist/localReference.js.map +1 -1
- package/dist/mergeTree.d.ts +71 -302
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +395 -642
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts +1 -1
- package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/dist/mergeTreeDeltaCallback.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +344 -0
- package/dist/mergeTreeNodes.d.ts.map +1 -0
- package/dist/mergeTreeNodes.js +383 -0
- package/dist/mergeTreeNodes.js.map +1 -0
- package/dist/mergeTreeTracking.d.ts +1 -1
- package/dist/mergeTreeTracking.d.ts.map +1 -1
- package/dist/mergeTreeTracking.js.map +1 -1
- package/dist/opBuilder.d.ts +1 -1
- package/dist/opBuilder.d.ts.map +1 -1
- package/dist/opBuilder.js.map +1 -1
- package/dist/partialLengths.d.ts +188 -18
- package/dist/partialLengths.d.ts.map +1 -1
- package/dist/partialLengths.js +495 -253
- package/dist/partialLengths.js.map +1 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js.map +1 -1
- package/dist/referencePositions.d.ts +6 -26
- package/dist/referencePositions.d.ts.map +1 -1
- package/dist/referencePositions.js +3 -20
- package/dist/referencePositions.js.map +1 -1
- package/dist/segmentGroupCollection.d.ts +3 -1
- package/dist/segmentGroupCollection.d.ts.map +1 -1
- package/dist/segmentGroupCollection.js +14 -1
- package/dist/segmentGroupCollection.js.map +1 -1
- package/dist/segmentPropertiesManager.d.ts +10 -1
- package/dist/segmentPropertiesManager.d.ts.map +1 -1
- package/dist/segmentPropertiesManager.js +42 -13
- package/dist/segmentPropertiesManager.js.map +1 -1
- package/dist/snapshotChunks.d.ts +2 -1
- package/dist/snapshotChunks.d.ts.map +1 -1
- package/dist/snapshotChunks.js.map +1 -1
- package/dist/snapshotLoader.d.ts.map +1 -1
- package/dist/snapshotLoader.js.map +1 -1
- package/dist/snapshotV1.d.ts +1 -1
- package/dist/snapshotV1.d.ts.map +1 -1
- package/dist/snapshotV1.js +1 -1
- package/dist/snapshotV1.js.map +1 -1
- package/dist/snapshotlegacy.d.ts +5 -1
- package/dist/snapshotlegacy.d.ts.map +1 -1
- package/dist/snapshotlegacy.js +4 -0
- package/dist/snapshotlegacy.js.map +1 -1
- package/dist/sortedSegmentSet.d.ts +1 -1
- package/dist/sortedSegmentSet.d.ts.map +1 -1
- package/dist/sortedSegmentSet.js.map +1 -1
- package/dist/textSegment.d.ts +7 -7
- package/dist/textSegment.d.ts.map +1 -1
- package/dist/textSegment.js +3 -125
- package/dist/textSegment.js.map +1 -1
- package/{DEV.md → docs/DEV.md} +2 -2
- package/docs/Obliterate.md +639 -0
- package/{REFERENCEPOSITIONS.md → docs/REFERENCEPOSITIONS.md} +2 -2
- package/lib/MergeTreeTextHelper.d.ts +23 -0
- package/lib/MergeTreeTextHelper.d.ts.map +1 -0
- package/lib/MergeTreeTextHelper.js +129 -0
- package/lib/MergeTreeTextHelper.js.map +1 -0
- package/lib/base.d.ts +2 -26
- package/lib/base.d.ts.map +1 -1
- package/lib/base.js.map +1 -1
- package/lib/client.d.ts +27 -16
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +79 -99
- package/lib/client.js.map +1 -1
- package/lib/collections/heap.d.ts +28 -0
- package/lib/collections/heap.d.ts.map +1 -0
- package/lib/collections/heap.js +61 -0
- package/lib/collections/heap.js.map +1 -0
- package/lib/collections/index.d.ts +11 -0
- package/lib/collections/index.d.ts.map +1 -0
- package/lib/collections/index.js +11 -0
- package/lib/collections/index.js.map +1 -0
- package/lib/collections/intervalTree.d.ts +60 -0
- package/lib/collections/intervalTree.d.ts.map +1 -0
- package/lib/collections/intervalTree.js +94 -0
- package/lib/collections/intervalTree.js.map +1 -0
- package/lib/collections/list.d.ts +39 -0
- package/lib/collections/list.d.ts.map +1 -0
- package/lib/collections/list.js +149 -0
- package/lib/collections/list.js.map +1 -0
- package/lib/collections/rbTree.d.ts +154 -0
- package/lib/collections/rbTree.d.ts.map +1 -0
- package/lib/{collections.js → collections/rbTree.js} +14 -469
- package/lib/collections/rbTree.js.map +1 -0
- package/lib/collections/stack.d.ts +16 -0
- package/lib/collections/stack.d.ts.map +1 -0
- package/lib/collections/stack.js +26 -0
- package/lib/collections/stack.js.map +1 -0
- package/lib/collections/tst.d.ts +55 -0
- package/lib/collections/tst.d.ts.map +1 -0
- package/lib/collections/tst.js +167 -0
- package/lib/collections/tst.js.map +1 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/localReference.d.ts +48 -99
- package/lib/localReference.d.ts.map +1 -1
- package/lib/localReference.js +132 -170
- package/lib/localReference.js.map +1 -1
- package/lib/mergeTree.d.ts +71 -302
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +371 -607
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts +1 -1
- package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
- package/lib/mergeTreeDeltaCallback.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +344 -0
- package/lib/mergeTreeNodes.d.ts.map +1 -0
- package/lib/mergeTreeNodes.js +369 -0
- package/lib/mergeTreeNodes.js.map +1 -0
- package/lib/mergeTreeTracking.d.ts +1 -1
- package/lib/mergeTreeTracking.d.ts.map +1 -1
- package/lib/mergeTreeTracking.js.map +1 -1
- package/lib/opBuilder.d.ts +1 -1
- package/lib/opBuilder.d.ts.map +1 -1
- package/lib/opBuilder.js.map +1 -1
- package/lib/partialLengths.d.ts +188 -18
- package/lib/partialLengths.d.ts.map +1 -1
- package/lib/partialLengths.js +491 -249
- package/lib/partialLengths.js.map +1 -1
- package/lib/properties.d.ts.map +1 -1
- package/lib/properties.js.map +1 -1
- package/lib/referencePositions.d.ts +6 -26
- package/lib/referencePositions.d.ts.map +1 -1
- package/lib/referencePositions.js +3 -20
- package/lib/referencePositions.js.map +1 -1
- package/lib/segmentGroupCollection.d.ts +3 -1
- package/lib/segmentGroupCollection.d.ts.map +1 -1
- package/lib/segmentGroupCollection.js +14 -1
- package/lib/segmentGroupCollection.js.map +1 -1
- package/lib/segmentPropertiesManager.d.ts +10 -1
- package/lib/segmentPropertiesManager.d.ts.map +1 -1
- package/lib/segmentPropertiesManager.js +42 -13
- package/lib/segmentPropertiesManager.js.map +1 -1
- package/lib/snapshotChunks.d.ts +2 -1
- package/lib/snapshotChunks.d.ts.map +1 -1
- package/lib/snapshotChunks.js.map +1 -1
- package/lib/snapshotLoader.d.ts.map +1 -1
- package/lib/snapshotLoader.js.map +1 -1
- package/lib/snapshotV1.d.ts +1 -1
- package/lib/snapshotV1.d.ts.map +1 -1
- package/lib/snapshotV1.js +1 -1
- package/lib/snapshotV1.js.map +1 -1
- package/lib/snapshotlegacy.d.ts +5 -1
- package/lib/snapshotlegacy.d.ts.map +1 -1
- package/lib/snapshotlegacy.js +4 -0
- package/lib/snapshotlegacy.js.map +1 -1
- package/lib/sortedSegmentSet.d.ts +1 -1
- package/lib/sortedSegmentSet.d.ts.map +1 -1
- package/lib/sortedSegmentSet.js.map +1 -1
- package/lib/textSegment.d.ts +7 -7
- package/lib/textSegment.d.ts.map +1 -1
- package/lib/textSegment.js +1 -122
- package/lib/textSegment.js.map +1 -1
- package/package.json +99 -20
- package/src/MergeTreeTextHelper.ts +170 -0
- package/src/base.ts +2 -35
- package/src/client.ts +91 -111
- package/src/collections/heap.ts +75 -0
- package/src/collections/index.ts +11 -0
- package/src/collections/intervalTree.ts +146 -0
- package/src/collections/list.ts +165 -0
- package/src/{collections.ts → collections/rbTree.ts} +84 -563
- package/src/collections/stack.ts +27 -0
- package/src/collections/tst.ts +212 -0
- package/src/index.ts +8 -2
- package/src/localReference.ts +152 -203
- package/src/mergeTree.ts +578 -996
- package/src/mergeTreeDeltaCallback.ts +1 -1
- package/src/mergeTreeNodes.ts +752 -0
- package/src/mergeTreeTracking.ts +1 -1
- package/src/opBuilder.ts +1 -1
- package/src/partialLengths.ts +631 -258
- package/src/properties.ts +1 -0
- package/src/referencePositions.ts +10 -44
- package/src/segmentGroupCollection.ts +17 -2
- package/src/segmentPropertiesManager.ts +46 -12
- package/src/snapshotChunks.ts +2 -1
- package/src/snapshotLoader.ts +2 -1
- package/src/snapshotV1.ts +3 -3
- package/src/snapshotlegacy.ts +6 -2
- package/src/sortedSegmentSet.ts +1 -1
- package/src/textSegment.ts +10 -157
- package/dist/collections.d.ts +0 -197
- package/dist/collections.d.ts.map +0 -1
- package/dist/collections.js.map +0 -1
- package/lib/collections.d.ts +0 -197
- package/lib/collections.d.ts.map +0 -1
- package/lib/collections.js.map +0 -1
package/src/properties.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Stack } from "./collections";
|
|
7
|
-
import { ISegment } from "./
|
|
7
|
+
import { ISegment } from "./mergeTreeNodes";
|
|
8
8
|
import { ReferenceType, ICombiningOp } from "./ops";
|
|
9
9
|
import { PropertySet, MapLike } from "./properties";
|
|
10
10
|
|
|
@@ -63,51 +63,23 @@ export interface ReferencePosition {
|
|
|
63
63
|
getSegment(): ISegment | undefined;
|
|
64
64
|
getOffset(): number;
|
|
65
65
|
addProperties(newProps: PropertySet, op?: ICombiningOp): void;
|
|
66
|
-
isLeaf():
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @deprecated - use refHasTileLabels
|
|
70
|
-
*/
|
|
71
|
-
hasTileLabels(): boolean;
|
|
72
|
-
/**
|
|
73
|
-
* @deprecated - use refHasRangeLabels
|
|
74
|
-
*/
|
|
75
|
-
hasRangeLabels(): boolean;
|
|
76
|
-
/**
|
|
77
|
-
* @deprecated - use refHasTileLabel
|
|
78
|
-
*/
|
|
79
|
-
hasTileLabel(label: string): boolean;
|
|
80
|
-
/**
|
|
81
|
-
* @deprecated - use refHasRangeLabel
|
|
82
|
-
*/
|
|
83
|
-
hasRangeLabel(label: string): boolean;
|
|
84
|
-
/**
|
|
85
|
-
* @deprecated - use refGetTileLabels
|
|
86
|
-
*/
|
|
87
|
-
getTileLabels(): string[] | undefined;
|
|
88
|
-
/**
|
|
89
|
-
* @deprecated - use refGetRangeLabels
|
|
90
|
-
*/
|
|
91
|
-
getRangeLabels(): string[] | undefined;
|
|
66
|
+
isLeaf(): this is ISegment;
|
|
92
67
|
}
|
|
93
68
|
|
|
69
|
+
/**
|
|
70
|
+
* @deprecated for internal use only. public export will be removed.
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
94
73
|
export type RangeStackMap = MapLike<Stack<ReferencePosition>>;
|
|
74
|
+
|
|
95
75
|
export const DetachedReferencePosition = -1;
|
|
96
76
|
|
|
97
77
|
export function minReferencePosition<T extends ReferencePosition>(a: T, b: T): T {
|
|
98
|
-
|
|
99
|
-
return a;
|
|
100
|
-
} else {
|
|
101
|
-
return b;
|
|
102
|
-
}
|
|
78
|
+
return compareReferencePositions(a, b) < 0 ? a : b;
|
|
103
79
|
}
|
|
104
80
|
|
|
105
81
|
export function maxReferencePosition<T extends ReferencePosition>(a: T, b: T): T {
|
|
106
|
-
|
|
107
|
-
return a;
|
|
108
|
-
} else {
|
|
109
|
-
return b;
|
|
110
|
-
}
|
|
82
|
+
return compareReferencePositions(a, b) > 0 ? a : b;
|
|
111
83
|
}
|
|
112
84
|
|
|
113
85
|
export function compareReferencePositions(a: ReferencePosition, b: ReferencePosition): number {
|
|
@@ -116,12 +88,6 @@ export function compareReferencePositions(a: ReferencePosition, b: ReferencePosi
|
|
|
116
88
|
if (aSeg === bSeg) {
|
|
117
89
|
return a.getOffset() - b.getOffset();
|
|
118
90
|
} else {
|
|
119
|
-
|
|
120
|
-
|| (bSeg !== undefined &&
|
|
121
|
-
aSeg.ordinal < bSeg.ordinal)) {
|
|
122
|
-
return -1;
|
|
123
|
-
} else {
|
|
124
|
-
return 1;
|
|
125
|
-
}
|
|
91
|
+
return aSeg === undefined || (bSeg !== undefined && aSeg.ordinal < bSeg.ordinal) ? -1 : 1;
|
|
126
92
|
}
|
|
127
93
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { List, ListMakeHead } from "./collections";
|
|
7
|
-
import { ISegment, SegmentGroup } from "./
|
|
7
|
+
import { ISegment, SegmentGroup } from "./mergeTreeNodes";
|
|
8
8
|
|
|
9
9
|
export class SegmentGroupCollection {
|
|
10
10
|
private readonly segmentGroups: List<SegmentGroup>;
|
|
@@ -30,11 +30,26 @@ export class SegmentGroupCollection {
|
|
|
30
30
|
return this.segmentGroups.dequeue();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
public pop?(): SegmentGroup | undefined {
|
|
34
|
+
return this.segmentGroups.pop ? this.segmentGroups.pop() : undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
33
37
|
public clear() {
|
|
34
38
|
this.segmentGroups.clear();
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
public copyTo(segment: ISegment) {
|
|
38
|
-
this.segmentGroups.walk((sg) => segment.segmentGroups.
|
|
42
|
+
this.segmentGroups.walk((sg) => segment.segmentGroups.enqueueOnCopy(sg, this.segment));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private enqueueOnCopy(segmentGroup: SegmentGroup, sourceSegment: ISegment) {
|
|
46
|
+
this.enqueue(segmentGroup);
|
|
47
|
+
if (segmentGroup.previousProps) {
|
|
48
|
+
// duplicate the previousProps for this segment
|
|
49
|
+
const index = segmentGroup.segments.indexOf(sourceSegment);
|
|
50
|
+
if (index !== -1) {
|
|
51
|
+
segmentGroup.previousProps.push(segmentGroup.previousProps[index]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
39
54
|
}
|
|
40
55
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
7
7
|
|
|
8
8
|
import { assert } from "@fluidframework/common-utils";
|
|
9
|
-
import { UnassignedSequenceNumber } from "./constants";
|
|
9
|
+
import { UnassignedSequenceNumber, UniversalSequenceNumber } from "./constants";
|
|
10
10
|
import { ICombiningOp, IMergeTreeAnnotateMsg } from "./ops";
|
|
11
11
|
import {
|
|
12
12
|
combine,
|
|
@@ -15,6 +15,17 @@ import {
|
|
|
15
15
|
PropertySet,
|
|
16
16
|
} from "./properties";
|
|
17
17
|
|
|
18
|
+
export enum PropertiesRollback {
|
|
19
|
+
/** Not in a rollback */
|
|
20
|
+
None,
|
|
21
|
+
|
|
22
|
+
/** Rollback */
|
|
23
|
+
Rollback,
|
|
24
|
+
|
|
25
|
+
/** Rollback of a rewrite */
|
|
26
|
+
Rewrite,
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
export class PropertiesManager {
|
|
19
30
|
private pendingKeyUpdateCount: MapLike<number> | undefined;
|
|
20
31
|
private pendingRewriteCount: number;
|
|
@@ -24,11 +35,20 @@ export class PropertiesManager {
|
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
public ackPendingProperties(annotateOp: IMergeTreeAnnotateMsg) {
|
|
27
|
-
|
|
38
|
+
const rewrite = !!annotateOp.combiningOp && annotateOp.combiningOp.name === "rewrite";
|
|
39
|
+
this.decrementPendingCounts(rewrite, annotateOp.props);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private decrementPendingCounts(rewrite: boolean, props: PropertySet) {
|
|
43
|
+
if (rewrite) {
|
|
28
44
|
this.pendingRewriteCount--;
|
|
29
45
|
}
|
|
30
|
-
for (const key of Object.keys(
|
|
46
|
+
for (const key of Object.keys(props)) {
|
|
31
47
|
if (this.pendingKeyUpdateCount?.[key] !== undefined) {
|
|
48
|
+
if (rewrite && props[key] === null) {
|
|
49
|
+
// We don't track the pending count for this redundant case
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
32
52
|
assert(this.pendingKeyUpdateCount[key] > 0,
|
|
33
53
|
0x05c /* "Trying to update more annotate props than do exist!" */);
|
|
34
54
|
this.pendingKeyUpdateCount[key]--;
|
|
@@ -45,21 +65,35 @@ export class PropertiesManager {
|
|
|
45
65
|
newProps: PropertySet,
|
|
46
66
|
op?: ICombiningOp,
|
|
47
67
|
seq?: number,
|
|
48
|
-
collaborating: boolean = false
|
|
68
|
+
collaborating: boolean = false,
|
|
69
|
+
rollback: PropertiesRollback = PropertiesRollback.None): PropertySet | undefined {
|
|
49
70
|
if (!this.pendingKeyUpdateCount) {
|
|
50
71
|
this.pendingKeyUpdateCount = createMap<number>();
|
|
51
72
|
}
|
|
52
73
|
|
|
53
74
|
// There are outstanding local rewrites, so block all non-local changes
|
|
54
|
-
if (this.pendingRewriteCount > 0 && seq !== UnassignedSequenceNumber &&
|
|
75
|
+
if (this.pendingRewriteCount > 0 && seq !== UnassignedSequenceNumber && seq !== UniversalSequenceNumber
|
|
76
|
+
&& collaborating) {
|
|
55
77
|
return undefined;
|
|
56
78
|
}
|
|
57
79
|
|
|
80
|
+
// Clean up counts for rolled back edits before modifying oldProps
|
|
81
|
+
if (collaborating) {
|
|
82
|
+
if (rollback === PropertiesRollback.Rollback) {
|
|
83
|
+
this.decrementPendingCounts(false, newProps);
|
|
84
|
+
} else if (rollback === PropertiesRollback.Rewrite) {
|
|
85
|
+
// oldProps is the correct props for tracking counts on rewrite because the ones in newProps include
|
|
86
|
+
// those that were implicitly cleared by the rewrite for which we don't track pending counts.
|
|
87
|
+
this.decrementPendingCounts(true, oldProps);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
58
91
|
const rewrite = (op && op.name === "rewrite");
|
|
59
92
|
const combiningOp = !rewrite ? op ? op : undefined : undefined;
|
|
60
93
|
|
|
61
94
|
const shouldModifyKey = (key: string): boolean => {
|
|
62
95
|
if (seq === UnassignedSequenceNumber
|
|
96
|
+
|| seq === UniversalSequenceNumber
|
|
63
97
|
|| this.pendingKeyUpdateCount?.[key] === undefined
|
|
64
98
|
|| combiningOp) {
|
|
65
99
|
return true;
|
|
@@ -87,6 +121,11 @@ export class PropertiesManager {
|
|
|
87
121
|
for (const key of Object.keys(newProps)) {
|
|
88
122
|
if (collaborating) {
|
|
89
123
|
if (seq === UnassignedSequenceNumber) {
|
|
124
|
+
if (rewrite && newProps[key] === null) {
|
|
125
|
+
// This case has already been handled above and
|
|
126
|
+
// we don't want to track the pending count for it in case of rollback
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
90
129
|
if (this.pendingKeyUpdateCount?.[key] === undefined) {
|
|
91
130
|
this.pendingKeyUpdateCount[key] = 0;
|
|
92
131
|
}
|
|
@@ -97,14 +136,9 @@ export class PropertiesManager {
|
|
|
97
136
|
}
|
|
98
137
|
|
|
99
138
|
const previousValue: any = oldProps[key];
|
|
100
|
-
// The delta should be null if undefined, as
|
|
139
|
+
// The delta should be null if undefined, as that's how we encode delete
|
|
101
140
|
deltas[key] = (previousValue === undefined) ? null : previousValue;
|
|
102
|
-
|
|
103
|
-
if (combiningOp) {
|
|
104
|
-
newValue = combine(combiningOp, previousValue, newValue, seq);
|
|
105
|
-
} else {
|
|
106
|
-
newValue = newProps[key];
|
|
107
|
-
}
|
|
141
|
+
const newValue = combiningOp ? combine(combiningOp, previousValue, undefined, seq) : newProps[key];
|
|
108
142
|
if (newValue === null) {
|
|
109
143
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
110
144
|
delete oldProps[key];
|
package/src/snapshotChunks.ts
CHANGED
|
@@ -63,7 +63,8 @@ export interface IJSONSegmentWithMergeInfo {
|
|
|
63
63
|
client?: string;
|
|
64
64
|
seq?: number;
|
|
65
65
|
/**
|
|
66
|
-
* @deprecated
|
|
66
|
+
* @deprecated Use {@link IJSONSegmentWithMergeInfo.removedClientIds} instead.
|
|
67
|
+
* This only exists for backwards compatability.
|
|
67
68
|
*/
|
|
68
69
|
removedClient?: string;
|
|
69
70
|
removedClientIds?: string[];
|
package/src/snapshotLoader.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
|
14
14
|
import { AttachState } from "@fluidframework/container-definitions";
|
|
15
15
|
import { Client } from "./client";
|
|
16
16
|
import { NonCollabClient, UniversalSequenceNumber } from "./constants";
|
|
17
|
-
import { ISegment
|
|
17
|
+
import { ISegment } from "./mergeTreeNodes";
|
|
18
18
|
import { IJSONSegment } from "./ops";
|
|
19
19
|
import {
|
|
20
20
|
IJSONSegmentWithMergeInfo,
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "./snapshotChunks";
|
|
24
24
|
import { SnapshotV1 } from "./snapshotV1";
|
|
25
25
|
import { SnapshotLegacy } from "./snapshotlegacy";
|
|
26
|
+
import { MergeTree } from "./mergeTree";
|
|
26
27
|
|
|
27
28
|
export class SnapshotLoader {
|
|
28
29
|
private readonly logger: ITelemetryLogger;
|
package/src/snapshotV1.ts
CHANGED
|
@@ -14,8 +14,7 @@ import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
|
|
|
14
14
|
import { UnassignedSequenceNumber } from "./constants";
|
|
15
15
|
import {
|
|
16
16
|
ISegment,
|
|
17
|
-
|
|
18
|
-
} from "./mergeTree";
|
|
17
|
+
} from "./mergeTreeNodes";
|
|
19
18
|
import {
|
|
20
19
|
matchProperties,
|
|
21
20
|
PropertySet,
|
|
@@ -29,6 +28,7 @@ import {
|
|
|
29
28
|
serializeAsMaxSupportedVersion,
|
|
30
29
|
} from "./snapshotChunks";
|
|
31
30
|
import { SnapshotLegacy } from "./snapshotlegacy";
|
|
31
|
+
import { MergeTree } from "./mergeTree";
|
|
32
32
|
|
|
33
33
|
export class SnapshotV1 {
|
|
34
34
|
// Split snapshot into two entries - headers (small) and body (overflow) for faster loading initial content
|
|
@@ -200,7 +200,7 @@ export class SnapshotV1 {
|
|
|
200
200
|
prev = segment;
|
|
201
201
|
}
|
|
202
202
|
} else {
|
|
203
|
-
// This segment needs to preserve
|
|
203
|
+
// This segment needs to preserve its metadata as it may be referenced by future ops. It's ineligible
|
|
204
204
|
// for coalescing, so emit the 'prev' segment now (if any).
|
|
205
205
|
pushSeg(prev);
|
|
206
206
|
prev = undefined;
|
package/src/snapshotlegacy.ts
CHANGED
|
@@ -16,14 +16,14 @@ import { SummaryTreeBuilder } from "@fluidframework/runtime-utils";
|
|
|
16
16
|
import { NonCollabClient, UnassignedSequenceNumber } from "./constants";
|
|
17
17
|
import {
|
|
18
18
|
ISegment,
|
|
19
|
-
|
|
20
|
-
} from "./mergeTree";
|
|
19
|
+
} from "./mergeTreeNodes";
|
|
21
20
|
import { IJSONSegment } from "./ops";
|
|
22
21
|
import { matchProperties } from "./properties";
|
|
23
22
|
import {
|
|
24
23
|
MergeTreeChunkLegacy,
|
|
25
24
|
serializeAsMinSupportedVersion,
|
|
26
25
|
} from "./snapshotChunks";
|
|
26
|
+
import { MergeTree } from "./mergeTree";
|
|
27
27
|
|
|
28
28
|
interface SnapshotHeader {
|
|
29
29
|
chunkCount?: number;
|
|
@@ -36,6 +36,10 @@ interface SnapshotHeader {
|
|
|
36
36
|
minSeq?: number;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated for internal use only. public export will be removed.
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
39
43
|
export class SnapshotLegacy {
|
|
40
44
|
public static readonly header = "header";
|
|
41
45
|
public static readonly body = "body";
|
package/src/sortedSegmentSet.ts
CHANGED
package/src/textSegment.ts
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { BaseSegment, ISegment, Marker, MergeTree } from "./mergeTree";
|
|
6
|
+
import { BaseSegment, ISegment, Marker } from "./mergeTreeNodes";
|
|
8
7
|
import { IJSONSegment } from "./ops";
|
|
9
8
|
import { PropertySet } from "./properties";
|
|
10
9
|
import { LocalReferenceCollection } from "./localReference";
|
|
@@ -121,159 +120,13 @@ export class TextSegment extends BaseSegment {
|
|
|
121
120
|
}
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
interface
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
parallelMarkers: Marker[];
|
|
134
|
-
parallelMarkerLabel: string;
|
|
135
|
-
tagsInProgress: string[];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function isTextAndMarkerAccumulator(accum: ITextAccumulator): accum is ITextAndMarkerAccumulator {
|
|
139
|
-
return accum.parallelArrays === true;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
type ITextAccumulatorType = ITextAccumulator | ITextAndMarkerAccumulator;
|
|
143
|
-
export class MergeTreeTextHelper {
|
|
144
|
-
constructor(private readonly mergeTree: MergeTree) { }
|
|
145
|
-
|
|
146
|
-
public getTextAndMarkers(refSeq: number, clientId: number, label: string, start?: number, end?: number) {
|
|
147
|
-
const range = this.getValidRange(start, end, refSeq, clientId);
|
|
148
|
-
const accum: ITextAndMarkerAccumulator = {
|
|
149
|
-
parallelArrays: true,
|
|
150
|
-
parallelMarkerLabel: label,
|
|
151
|
-
parallelMarkers: [],
|
|
152
|
-
parallelText: [],
|
|
153
|
-
tagsInProgress: [],
|
|
154
|
-
textSegment: new TextSegment(""),
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
this.mergeTree.mapRange<ITextAndMarkerAccumulator>(
|
|
158
|
-
{ leaf: this.gatherText },
|
|
159
|
-
refSeq,
|
|
160
|
-
clientId,
|
|
161
|
-
accum,
|
|
162
|
-
range.start,
|
|
163
|
-
range.end);
|
|
164
|
-
|
|
165
|
-
return { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
public getText(refSeq: number, clientId: number, placeholder = "", start?: number, end?: number) {
|
|
169
|
-
const range = this.getValidRange(start, end, refSeq, clientId);
|
|
170
|
-
|
|
171
|
-
const accum: ITextAccumulator = { textSegment: new TextSegment(""), placeholder };
|
|
172
|
-
|
|
173
|
-
this.mergeTree.mapRange<ITextAccumulator>(
|
|
174
|
-
{ leaf: this.gatherText },
|
|
175
|
-
refSeq,
|
|
176
|
-
clientId,
|
|
177
|
-
accum,
|
|
178
|
-
range.start,
|
|
179
|
-
range.end);
|
|
180
|
-
return accum.textSegment.text;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
private getValidRange(
|
|
184
|
-
start: number | undefined,
|
|
185
|
-
end: number | undefined,
|
|
186
|
-
refSeq: number,
|
|
187
|
-
clientId: number,
|
|
188
|
-
): IIntegerRange {
|
|
189
|
-
const range: IIntegerRange = {
|
|
190
|
-
end: end ?? this.mergeTree.getLength(refSeq, clientId),
|
|
191
|
-
start: start ?? 0,
|
|
192
|
-
};
|
|
193
|
-
return range;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private readonly gatherText = (segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,
|
|
197
|
-
end: number, accumText: ITextAccumulatorType) => {
|
|
198
|
-
let _start = start;
|
|
199
|
-
if (TextSegment.is(segment)) {
|
|
200
|
-
let beginTags = "";
|
|
201
|
-
let endTags = "";
|
|
202
|
-
if (isTextAndMarkerAccumulator(accumText)) {
|
|
203
|
-
// TODO: let clients pass in function to get tag
|
|
204
|
-
const tags = [] as string[];
|
|
205
|
-
const initTags = [] as string[];
|
|
206
|
-
|
|
207
|
-
if (segment.properties?.["font-weight"]) {
|
|
208
|
-
tags.push("b");
|
|
209
|
-
}
|
|
210
|
-
if (segment.properties?.["text-decoration"]) {
|
|
211
|
-
tags.push("u");
|
|
212
|
-
}
|
|
213
|
-
const remTags = [] as string[];
|
|
214
|
-
if (tags.length > 0) {
|
|
215
|
-
for (const tag of tags) {
|
|
216
|
-
if (!accumText.tagsInProgress.includes(tag)) {
|
|
217
|
-
beginTags += `<${tag}>`;
|
|
218
|
-
initTags.push(tag);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
for (const accumTag of accumText.tagsInProgress) {
|
|
222
|
-
if (!tags.includes(accumTag)) {
|
|
223
|
-
endTags += `</${accumTag}>`;
|
|
224
|
-
remTags.push(accumTag);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
for (const initTag of initTags.reverse()) {
|
|
228
|
-
accumText.tagsInProgress.push(initTag);
|
|
229
|
-
}
|
|
230
|
-
} else {
|
|
231
|
-
for (const accumTag of accumText.tagsInProgress) {
|
|
232
|
-
endTags += `</${accumTag}>`;
|
|
233
|
-
remTags.push(accumTag);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
for (const remTag of remTags) {
|
|
237
|
-
const remdex = accumText.tagsInProgress.indexOf(remTag);
|
|
238
|
-
if (remdex >= 0) {
|
|
239
|
-
accumText.tagsInProgress.splice(remdex, 1);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
accumText.textSegment.text += endTags;
|
|
244
|
-
accumText.textSegment.text += beginTags;
|
|
245
|
-
if ((_start <= 0) && (end >= segment.text.length)) {
|
|
246
|
-
accumText.textSegment.text += segment.text;
|
|
247
|
-
} else {
|
|
248
|
-
if (_start < 0) {
|
|
249
|
-
_start = 0;
|
|
250
|
-
}
|
|
251
|
-
if (end >= segment.text.length) {
|
|
252
|
-
accumText.textSegment.text += segment.text.substring(_start);
|
|
253
|
-
} else {
|
|
254
|
-
accumText.textSegment.text += segment.text.substring(_start, end);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
} else {
|
|
258
|
-
if (accumText.placeholder && (accumText.placeholder.length > 0)) {
|
|
259
|
-
if (accumText.placeholder === "*") {
|
|
260
|
-
const marker = segment as Marker;
|
|
261
|
-
accumText.textSegment.text += `\n${marker.toString()}`;
|
|
262
|
-
} else {
|
|
263
|
-
for (let i = 0; i < segment.cachedLength; i++) {
|
|
264
|
-
accumText.textSegment.text += accumText.placeholder;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
} else if (isTextAndMarkerAccumulator(accumText)) {
|
|
268
|
-
const marker = segment as Marker;
|
|
269
|
-
if (marker.hasTileLabel(accumText.parallelMarkerLabel)) {
|
|
270
|
-
accumText.parallelMarkers.push(marker);
|
|
271
|
-
accumText.parallelText.push(accumText.textSegment.text);
|
|
272
|
-
accumText.textSegment.text = "";
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return true;
|
|
278
|
-
};
|
|
123
|
+
export interface IMergeTreeTextHelper{
|
|
124
|
+
/**
|
|
125
|
+
* @deprecated If consuming via sequence, use `getTextAndMarkers` exported from `\@fluidframework/sequence`.
|
|
126
|
+
* Otherwise, define your own accumulation model and use `Client.walkSegments`.
|
|
127
|
+
*/
|
|
128
|
+
getTextAndMarkers(refSeq: number, clientId: number, label: string, start?: number, end?: number): {
|
|
129
|
+
parallelText: string[];
|
|
130
|
+
parallelMarkers: Marker[]; };
|
|
131
|
+
getText(refSeq: number, clientId: number, placeholder: string, start?: number, end?: number): string;
|
|
279
132
|
}
|