Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge-Tree and SharedString ISegment Deprecations #23323

Merged
Merged
40 changes: 40 additions & 0 deletions .changeset/real-grapes-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
"@fluidframework/merge-tree": minor
"@fluidframework/sequence": minor
---
---
"section": deprecation
---

Merge-Tree and SharedString ISegment Deprecations

The current ISegment interface over-exposes a number of properties which do not have an external use case, and any external usage could result in damage to the underlying merge-tree including data corruption.

The only use case that will continue to be supported is determining if a segment is removed. For this purpose we've add the following `function segmentIsRemoved(segment: ISegment): boolean`
anthony-murphy marked this conversation as resolved.
Show resolved Hide resolved

For example, checking if a segment is not removed would change as follows:
``` diff
- if(segment.removedSeq === undefined){
+ if(!segmentIsRemoved(segment)){
```

The following properties are deprecated on ISegment and its implementations:
- clientId
- index
- localMovedSeq
- localRefs
- localRemovedSeq
- localSeq
- movedClientsIds
- movedSeq
- movedSeqs
- ordinal
- removedClientIds
- removedSeq
- seq
- wasMovedOnInsert

Additionally, the following interfaces are also deprecated, and will become internal:
- IMergeNodeCommon
- IMoveInfo
- IRemovalInfo
11 changes: 7 additions & 4 deletions examples/data-objects/webflow/src/view/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import assert from "assert";

import { EventEmitter } from "@fluid-example/example-utils";
import { MergeTreeMaintenanceType } from "@fluidframework/merge-tree/internal";
import {
MergeTreeMaintenanceType,
segmentIsRemoved,
} from "@fluidframework/merge-tree/internal";
import {
ISegment,
LocalReferencePosition,
Expand Down Expand Up @@ -309,7 +312,7 @@ export class Layout extends EventEmitter {
);

// Must not request a formatter for a removed segment.
assert.strictEqual(segment.removedSeq, undefined);
assert.strictEqual(segmentIsRemoved(segment), false);

// If we've checkpointed this segment previously, we can potentially reuse our previous state to
// minimize damage to the DOM.
Expand Down Expand Up @@ -421,7 +424,7 @@ export class Layout extends EventEmitter {

public nodeToSegment(node: Node): ISegment {
const seg = this.nodeToSegmentMap.get(node);
return seg && (seg.removedSeq === undefined ? seg : undefined);
return seg && (!segmentIsRemoved(seg) ? seg : undefined);
}

public segmentAndOffsetToNodeAndOffset(segment: ISegment, offset: number) {
Expand Down Expand Up @@ -609,7 +612,7 @@ export class Layout extends EventEmitter {

// If the segment was removed, promptly remove any DOM nodes it emitted.
for (const { segment } of e.ranges) {
if (segment.removedSeq) {
if (segmentIsRemoved(segment)) {
this.removeSegment(segment);
}
}
Expand Down
67 changes: 49 additions & 18 deletions packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export abstract class BaseSegment implements ISegment {
cachedLength: number;
// (undocumented)
canAppend(segment: ISegment): boolean;
// (undocumented)
// @deprecated (undocumented)
clientId: number;
// (undocumented)
abstract clone(): ISegment;
Expand All @@ -37,33 +37,33 @@ export abstract class BaseSegment implements ISegment {
protected abstract createSplitSegmentAt(pos: number): BaseSegment | undefined;
// (undocumented)
hasProperty(key: string): boolean;
// (undocumented)
// @deprecated (undocumented)
index: number;
// (undocumented)
isLeaf(): this is ISegment;
// (undocumented)
// @deprecated (undocumented)
localMovedSeq?: number;
// (undocumented)
// @deprecated (undocumented)
localRefs?: LocalReferenceCollection;
// (undocumented)
// @deprecated (undocumented)
localRemovedSeq?: number;
// (undocumented)
// @deprecated (undocumented)
localSeq?: number;
// (undocumented)
// @deprecated (undocumented)
movedClientIds?: number[];
// (undocumented)
// @deprecated (undocumented)
movedSeq?: number;
// (undocumented)
// @deprecated (undocumented)
movedSeqs?: number[];
// (undocumented)
// @deprecated (undocumented)
ordinal: string;
// (undocumented)
properties?: PropertySet;
// (undocumented)
// @deprecated (undocumented)
removedClientIds?: number[];
// (undocumented)
// @deprecated (undocumented)
removedSeq?: number;
// (undocumented)
// @deprecated (undocumented)
seq: number;
// (undocumented)
splitAt(pos: number): ISegment | undefined;
Expand All @@ -73,7 +73,7 @@ export abstract class BaseSegment implements ISegment {
readonly trackingCollection: TrackingGroupCollection;
// (undocumented)
abstract readonly type: string;
// (undocumented)
// @deprecated (undocumented)
wasMovedOnInsert?: boolean | undefined;
}

Expand Down Expand Up @@ -160,7 +160,7 @@ export interface IMarkerDef {
refType?: ReferenceType;
}

// @alpha
// @alpha @deprecated
export interface IMergeNodeCommon {
index: number;
// (undocumented)
Expand Down Expand Up @@ -320,7 +320,7 @@ export interface IMergeTreeSegmentDelta {
segment: ISegment;
}

// @alpha
// @alpha @deprecated
export interface IMoveInfo {
localMovedSeq?: number;
movedClientIds: number[];
Expand All @@ -345,29 +345,55 @@ export interface IRelativePosition {
offset?: number;
}

// @alpha
// @alpha @deprecated
export interface IRemovalInfo {
localRemovedSeq?: number;
removedClientIds: number[];
removedSeq: number;
}

// @alpha
export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo>, Partial<IMoveInfo> {
export interface ISegment {
// (undocumented)
append(segment: ISegment): void;
attribution?: IAttributionCollection<AttributionKey>;
cachedLength: number;
// (undocumented)
canAppend(segment: ISegment): boolean;
// @deprecated
clientId: number;
// (undocumented)
clone(): ISegment;
// @deprecated
readonly endpointType?: "start" | "end";
// @deprecated
index: number;
// (undocumented)
isLeaf(): this is ISegment;
// @deprecated
localMovedSeq?: number;
// @deprecated
localRefs?: LocalReferenceCollection;
// @deprecated
localRemovedSeq?: number;
// @deprecated
localSeq?: number;
// @deprecated
movedClientIds?: number[];
// @deprecated
movedSeq?: number;
// @deprecated
movedSeqs?: number[];
// @deprecated
moveDst?: ReferencePosition;
// @deprecated
ordinal: string;
properties?: PropertySet;
// @deprecated
removedClientIds?: number[];
// @deprecated
removedSeq?: number;
// @deprecated
seq?: number;
// (undocumented)
splitAt(pos: number): ISegment | undefined;
Expand All @@ -377,6 +403,8 @@ export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo>, Parti
readonly trackingCollection: TrackingGroupCollection;
// (undocumented)
readonly type: string;
// @deprecated
wasMovedOnInsert?: boolean;
}

// @alpha (undocumented)
Expand Down Expand Up @@ -568,6 +596,9 @@ export const reservedMarkerIdKey = "markerId";
// @alpha
export function revertMergeTreeDeltaRevertibles(driver: MergeTreeRevertibleDriver, revertibles: MergeTreeDeltaRevertible[]): void;

// @alpha
export function segmentIsRemoved(segment: ISegment): boolean;

// @alpha (undocumented)
export interface SequenceOffsets {
// (undocumented)
Expand Down
7 changes: 4 additions & 3 deletions packages/dds/merge-tree/src/endOfTreeSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { LocalClientId } from "./constants.js";
import { LocalReferenceCollection } from "./localReference.js";
import { MergeTree } from "./mergeTree.js";
import { NodeAction, depthFirstNodeWalk } from "./mergeTreeNodeWalk.js";
import { IRemovalInfo, ISegment, ISegmentLeaf, type MergeBlock } from "./mergeTreeNodes.js";
// eslint-disable-next-line import/no-deprecated
import { ISegment, ISegmentLeaf, type MergeBlock } from "./mergeTreeNodes.js";

/**
* This is a special segment that is not bound or known by the merge tree itself,
Expand Down Expand Up @@ -99,7 +100,7 @@ const notSupported = (): never => {
/**
* The position immediately prior to the start of the tree
*/
export class StartOfTreeSegment extends BaseEndpointSegment implements ISegment, IRemovalInfo {
export class StartOfTreeSegment extends BaseEndpointSegment implements ISegment {
type: string = "StartOfTreeSegment";
readonly endpointType = "start";

Expand Down Expand Up @@ -149,7 +150,7 @@ export class StartOfTreeSegment extends BaseEndpointSegment implements ISegment,
/**
* The position immediately after the end of the tree
*/
export class EndOfTreeSegment extends BaseEndpointSegment implements ISegment, IRemovalInfo {
export class EndOfTreeSegment extends BaseEndpointSegment implements ISegment {
type: string = "EndOfTreeSegment";
readonly endpointType = "end";

Expand Down
1 change: 1 addition & 0 deletions packages/dds/merge-tree/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export {
IMergeNodeCommon,
IMoveInfo,
IRemovalInfo,
segmentIsRemoved,
ISegment,
ISegmentAction,
Marker,
Expand Down
10 changes: 10 additions & 0 deletions packages/dds/merge-tree/src/mergeTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ import {
// eslint-disable-next-line import/no-deprecated
CollaborationWindow,
IMergeNode,
// eslint-disable-next-line import/no-deprecated
IMoveInfo,
// eslint-disable-next-line import/no-deprecated
IRemovalInfo,
ISegmentAction,
ISegmentChanges,
Expand Down Expand Up @@ -100,6 +102,7 @@ import { Side, type InteriorSequencePlace } from "./sequencePlace.js";
import { SortedSegmentSet } from "./sortedSegmentSet.js";
import { zamboniSegments } from "./zamboni.js";

// eslint-disable-next-line import/no-deprecated
function markSegmentMoved(seg: ISegmentLeaf, moveInfo: IMoveInfo): void {
seg.moveDst = moveInfo.moveDst;
seg.movedClientIds = [...moveInfo.movedClientIds];
Expand All @@ -109,19 +112,23 @@ function markSegmentMoved(seg: ISegmentLeaf, moveInfo: IMoveInfo): void {
seg.wasMovedOnInsert = moveInfo.wasMovedOnInsert;
}

// eslint-disable-next-line import/no-deprecated
function isMoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
return toMoveInfo(segment) !== undefined;
}

// eslint-disable-next-line import/no-deprecated
function isRemoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
return toRemovalInfo(segment) !== undefined;
}

// eslint-disable-next-line import/no-deprecated
function isRemovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
const removalInfo = toRemovalInfo(segment);
return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
}

// eslint-disable-next-line import/no-deprecated
function isMovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
const moveInfo = toMoveInfo(segment);
return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
Expand Down Expand Up @@ -180,6 +187,7 @@ function ackSegment(
}

case MergeTreeDeltaType.REMOVE: {
// eslint-disable-next-line import/no-deprecated
const removalInfo: IRemovalInfo | undefined = toRemovalInfo(segment);
assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
segment.localRemovedSeq = undefined;
Expand All @@ -192,6 +200,7 @@ function ackSegment(

case MergeTreeDeltaType.OBLITERATE:
case MergeTreeDeltaType.OBLITERATE_SIDED: {
// eslint-disable-next-line import/no-deprecated
const moveInfo: IMoveInfo | undefined = toMoveInfo(segment);
assert(moveInfo !== undefined, 0x86e /* On obliterate ack, missing move info! */);
const obliterateInfo = segmentGroup.obliterateInfo;
Expand Down Expand Up @@ -1649,6 +1658,7 @@ export class MergeTree {
}

if (oldest && newest?.clientId !== clientId) {
// eslint-disable-next-line import/no-deprecated
const moveInfo: IMoveInfo = {
movedClientIds,
movedSeq: oldest.seq,
Expand Down
Loading
Loading