From 8d2af8ba7635c7c254266fbb4354bf437c5f49e1 Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Thu, 12 Dec 2024 14:50:30 -0800 Subject: [PATCH 1/7] Deprecate over-exposed ISegment properites --- .../data-objects/webflow/src/view/layout.ts | 11 +- .../api-report/merge-tree.legacy.alpha.api.md | 67 ++++++--- .../dds/merge-tree/src/endOfTreeSegment.ts | 7 +- packages/dds/merge-tree/src/index.ts | 1 + packages/dds/merge-tree/src/mergeTree.ts | 10 ++ packages/dds/merge-tree/src/mergeTreeNodes.ts | 129 +++++++++++++++++- packages/dds/merge-tree/src/partialLengths.ts | 4 + 7 files changed, 200 insertions(+), 29 deletions(-) diff --git a/examples/data-objects/webflow/src/view/layout.ts b/examples/data-objects/webflow/src/view/layout.ts index 84685d9a68e8..25bc98eb3a8f 100644 --- a/examples/data-objects/webflow/src/view/layout.ts +++ b/examples/data-objects/webflow/src/view/layout.ts @@ -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, @@ -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. @@ -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) { @@ -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); } } diff --git a/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md b/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md index dfcebd7202e5..368465401d56 100644 --- a/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md +++ b/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md @@ -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; @@ -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; @@ -73,7 +73,7 @@ export abstract class BaseSegment implements ISegment { readonly trackingCollection: TrackingGroupCollection; // (undocumented) abstract readonly type: string; - // (undocumented) + // @deprecated (undocumented) wasMovedOnInsert?: boolean | undefined; } @@ -160,7 +160,7 @@ export interface IMarkerDef { refType?: ReferenceType; } -// @alpha +// @alpha @deprecated export interface IMergeNodeCommon { index: number; // (undocumented) @@ -320,7 +320,7 @@ export interface IMergeTreeSegmentDelta { segment: ISegment; } -// @alpha +// @alpha @deprecated export interface IMoveInfo { localMovedSeq?: number; movedClientIds: number[]; @@ -345,7 +345,7 @@ export interface IRelativePosition { offset?: number; } -// @alpha +// @alpha @deprecated export interface IRemovalInfo { localRemovedSeq?: number; removedClientIds: number[]; @@ -353,21 +353,47 @@ export interface IRemovalInfo { } // @alpha -export interface ISegment extends IMergeNodeCommon, Partial, Partial { +export interface ISegment { // (undocumented) append(segment: ISegment): void; attribution?: IAttributionCollection; 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; @@ -377,6 +403,8 @@ export interface ISegment extends IMergeNodeCommon, Partial, Parti readonly trackingCollection: TrackingGroupCollection; // (undocumented) readonly type: string; + // @deprecated + wasMovedOnInsert?: boolean; } // @alpha (undocumented) @@ -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) diff --git a/packages/dds/merge-tree/src/endOfTreeSegment.ts b/packages/dds/merge-tree/src/endOfTreeSegment.ts index 555d5b62b659..31e48a76d0d1 100644 --- a/packages/dds/merge-tree/src/endOfTreeSegment.ts +++ b/packages/dds/merge-tree/src/endOfTreeSegment.ts @@ -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, @@ -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"; @@ -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"; diff --git a/packages/dds/merge-tree/src/index.ts b/packages/dds/merge-tree/src/index.ts index 75d1c454ca89..02bb51c078b6 100644 --- a/packages/dds/merge-tree/src/index.ts +++ b/packages/dds/merge-tree/src/index.ts @@ -63,6 +63,7 @@ export { IMergeNodeCommon, IMoveInfo, IRemovalInfo, + segmentIsRemoved, ISegment, ISegmentAction, Marker, diff --git a/packages/dds/merge-tree/src/mergeTree.ts b/packages/dds/merge-tree/src/mergeTree.ts index 9dd4857661f6..9729f42918a9 100644 --- a/packages/dds/merge-tree/src/mergeTree.ts +++ b/packages/dds/merge-tree/src/mergeTree.ts @@ -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, @@ -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]; @@ -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; @@ -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; @@ -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; @@ -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, diff --git a/packages/dds/merge-tree/src/mergeTreeNodes.ts b/packages/dds/merge-tree/src/mergeTreeNodes.ts index 316b709fd915..e81767a6e123 100644 --- a/packages/dds/merge-tree/src/mergeTreeNodes.ts +++ b/packages/dds/merge-tree/src/mergeTreeNodes.ts @@ -34,6 +34,7 @@ import { PropertiesManager } from "./segmentPropertiesManager.js"; * Common properties for a node in a merge tree. * @legacy * @alpha + * @deprecated - This interface will be removed in 2.20 with no replacement. */ export interface IMergeNodeCommon { /** @@ -58,9 +59,12 @@ export interface IMergeNodeCommon { * * @internal */ -export type ISegmentInternal = ISegment & { - localRefs?: LocalReferenceCollection; -}; +export type ISegmentInternal = Omit & + Partial & + Partial & + Partial & { + localRefs?: LocalReferenceCollection; + }; /** * We use tiered interface to control visibility of segment properties. @@ -89,6 +93,7 @@ export type IMergeNode = MergeBlock | ISegmentLeaf; * Contains removal information associated to an {@link ISegment}. * @legacy * @alpha + * @deprecated - This interface will be removed in 2.20 with no replacement. */ export interface IRemovalInfo { /** @@ -133,6 +138,7 @@ export function toRemovalInfo( * in the future, when moves _are_ supported. * @legacy * @alpha + * @deprecated - This interface will be removed in 2.20 with no replacement. */ export interface IMoveInfo { /** @@ -211,7 +217,7 @@ export function toMoveInfo(maybe: Partial | undefined): IMoveInfo | u * @legacy * @alpha */ -export interface ISegment extends IMergeNodeCommon, Partial, Partial { +export interface ISegment { readonly type: string; readonly trackingCollection: TrackingGroupCollection; @@ -223,6 +229,7 @@ export interface ISegment extends IMergeNodeCommon, Partial, Parti * after the tree. These segments cannot be referenced by regular operations * and exist primarily as a bucket for local references to slide onto during * deletion of regular segments. + * @deprecated - This property will be removed in 2.20 with no replacement. */ readonly endpointType?: "start" | "end"; @@ -254,6 +261,7 @@ export interface ISegment extends IMergeNodeCommon, Partial, Parti * * @privateRemarks * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq. + * @deprecated - This property will be removed in 2.20 with no replacement. */ localSeq?: number; /** @@ -265,19 +273,23 @@ export interface ISegment extends IMergeNodeCommon, Partial, Parti * * @privateRemarks * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq. + * @deprecated - This property will be removed in 2.20 with no replacement. */ localRemovedSeq?: number; /** * Seq at which this segment was inserted. * If undefined, it is assumed the segment was inserted prior to the collab window's minimum sequence number. + * @deprecated - This property will be removed in 2.20 with no replacement. */ seq?: number; /** * Short clientId for the client that inserted this segment. + * @deprecated - This property will be removed in 2.20 with no replacement. */ clientId: number; /** * Local references added to this segment. + * @deprecated - This property will be removed in 2.20 with no replacement. */ localRefs?: LocalReferenceCollection; /** @@ -292,6 +304,73 @@ export interface ISegment extends IMergeNodeCommon, Partial, Parti // Changing this to something other than any would break consumers. // eslint-disable-next-line @typescript-eslint/no-explicit-any toJSONObject(): any; + isLeaf(): this is ISegment; + + /** + * {@inheritDoc @fluidframework/merge-tree#IMergeNodeCommon.index} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + index: number; + /** + * {@inheritDoc @fluidframework/merge-tree#IMergeNodeCommon.ordinal} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + ordinal: string; + + /** + * {@inheritDoc @fluidframework/merge-tree#IRemovalInfo.removedSeq} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + removedSeq?: number; + /** + * {@inheritDoc @fluidframework/merge-tree#IRemovalInfo.removedClientIds} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + removedClientIds?: number[]; + /** + * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.localMovedSeq} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + localMovedSeq?: number; + /** + * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.movedSeq} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + movedSeq?: number; + + /** + * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.movedSeqs} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + movedSeqs?: number[]; + /** + * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.moveDst} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + moveDst?: ReferencePosition; + /** + * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.movedClientIds} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + movedClientIds?: number[]; + /** + * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.wasMovedOnInsert} + * @deprecated - This property will be removed in 2.20 with no replacement. + */ + wasMovedOnInsert?: boolean; +} + +/** + * Determine if a segment has been removed. + * @legacy + * @alpha + */ +export function segmentIsRemoved(segment: ISegment): boolean { + const leaf: ISegmentLeaf = segment; + if (leaf.removedSeq === undefined) { + return false; + } + return true; } /** @@ -494,15 +573,45 @@ export function seqLTE(seq: number, minOrRefSeq: number): boolean { * @alpha */ export abstract class BaseSegment implements ISegment { + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public clientId: number = LocalClientId; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public seq: number = UniversalSequenceNumber; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public removedSeq?: number; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public removedClientIds?: number[]; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public movedSeq?: number; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public movedSeqs?: number[]; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public movedClientIds?: number[]; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public wasMovedOnInsert?: boolean | undefined; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public index: number = 0; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public ordinal: string = ""; public cachedLength: number = 0; @@ -513,10 +622,22 @@ export abstract class BaseSegment implements ISegment { public attribution?: IAttributionCollection; public properties?: PropertySet; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public localRefs?: LocalReferenceCollection; public abstract readonly type: string; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public localSeq?: number; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public localRemovedSeq?: number; + /** + * @deprecated - This property will be removed in 2.20 with no replacement. + */ public localMovedSeq?: number; public constructor(properties?: PropertySet) { diff --git a/packages/dds/merge-tree/src/partialLengths.ts b/packages/dds/merge-tree/src/partialLengths.ts index e971a618fd95..297a529ba907 100644 --- a/packages/dds/merge-tree/src/partialLengths.ts +++ b/packages/dds/merge-tree/src/partialLengths.ts @@ -12,7 +12,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, ISegmentLeaf, compareNumbers, @@ -639,7 +641,9 @@ export class PartialSequenceLengths { private static insertSegment( combinedPartialLengths: PartialSequenceLengths, segment: ISegmentLeaf, + // eslint-disable-next-line import/no-deprecated removalInfo?: IRemovalInfo, + // eslint-disable-next-line import/no-deprecated moveInfo?: IMoveInfo, ): void { const removalIsLocal = From 48bb106191f4d3b1788a966e9ec72d53954d81a1 Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Thu, 12 Dec 2024 16:26:32 -0800 Subject: [PATCH 2/7] add changeset --- .changeset/real-grapes-kick.md | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .changeset/real-grapes-kick.md diff --git a/.changeset/real-grapes-kick.md b/.changeset/real-grapes-kick.md new file mode 100644 index 000000000000..c7ffa5e734f0 --- /dev/null +++ b/.changeset/real-grapes-kick.md @@ -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` + +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 From 59051de77eb37472bce9eee25e9b4026a448f62f Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Thu, 12 Dec 2024 16:48:53 -0800 Subject: [PATCH 3/7] deprecate LocalReferenceCollection --- .changeset/real-grapes-kick.md | 3 ++- .../merge-tree/api-report/merge-tree.legacy.alpha.api.md | 2 +- packages/dds/merge-tree/src/endOfTreeSegment.ts | 2 ++ packages/dds/merge-tree/src/localReference.ts | 1 + packages/dds/merge-tree/src/mergeTree.ts | 9 +++++++++ packages/dds/merge-tree/src/mergeTreeNodes.ts | 5 +++++ packages/dds/merge-tree/src/revertibles.ts | 3 +++ 7 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.changeset/real-grapes-kick.md b/.changeset/real-grapes-kick.md index c7ffa5e734f0..21439fddbbf7 100644 --- a/.changeset/real-grapes-kick.md +++ b/.changeset/real-grapes-kick.md @@ -34,7 +34,8 @@ The following properties are deprecated on ISegment and its implementations: - seq - wasMovedOnInsert -Additionally, the following interfaces are also deprecated, and will become internal: +Additionally, the following types are also deprecated, and will become internal: - IMergeNodeCommon - IMoveInfo - IRemovalInfo +- LocalReferenceCollection diff --git a/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md b/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md index 368465401d56..83c61ee8a1e8 100644 --- a/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md +++ b/packages/dds/merge-tree/api-report/merge-tree.legacy.alpha.api.md @@ -427,7 +427,7 @@ export interface ITrackingGroup { unlink(trackable: Trackable): boolean; } -// @alpha @sealed +// @alpha @sealed @deprecated export class LocalReferenceCollection { [Symbol.iterator](): { next(): IteratorResult; diff --git a/packages/dds/merge-tree/src/endOfTreeSegment.ts b/packages/dds/merge-tree/src/endOfTreeSegment.ts index 31e48a76d0d1..f85a928e4d6d 100644 --- a/packages/dds/merge-tree/src/endOfTreeSegment.ts +++ b/packages/dds/merge-tree/src/endOfTreeSegment.ts @@ -6,6 +6,7 @@ import { assert } from "@fluidframework/core-utils/internal"; import { LocalClientId } from "./constants.js"; +// eslint-disable-next-line import/no-deprecated import { LocalReferenceCollection } from "./localReference.js"; import { MergeTree } from "./mergeTree.js"; import { NodeAction, depthFirstNodeWalk } from "./mergeTreeNodeWalk.js"; @@ -72,6 +73,7 @@ abstract class BaseEndpointSegment { abstract get ordinal(): string; + // eslint-disable-next-line import/no-deprecated localRefs?: LocalReferenceCollection; /* diff --git a/packages/dds/merge-tree/src/localReference.ts b/packages/dds/merge-tree/src/localReference.ts index cc89f89d0aaa..02b96924ca6c 100644 --- a/packages/dds/merge-tree/src/localReference.ts +++ b/packages/dds/merge-tree/src/localReference.ts @@ -228,6 +228,7 @@ export function setValidateRefCount( * * @legacy * @alpha + * @deprecated - This class will be removed in 2.20 with no replacement. */ export class LocalReferenceCollection { public static append(seg1: ISegment, seg2: ISegment): void { diff --git a/packages/dds/merge-tree/src/mergeTree.ts b/packages/dds/merge-tree/src/mergeTree.ts index 9729f42918a9..9df717458d48 100644 --- a/packages/dds/merge-tree/src/mergeTree.ts +++ b/packages/dds/merge-tree/src/mergeTree.ts @@ -20,6 +20,7 @@ import { } from "./constants.js"; import { EndOfTreeSegment, StartOfTreeSegment } from "./endOfTreeSegment.js"; import { + // eslint-disable-next-line import/no-deprecated LocalReferenceCollection, LocalReferencePosition, SlidingPreference, @@ -886,7 +887,9 @@ export class MergeTree { */ private slideAckedRemovedSegmentReferences(segments: ISegmentLeaf[]): void { // References are slid in groups to preserve their order. + // eslint-disable-next-line import/no-deprecated let currentForwardSlideGroup: LocalReferenceCollection[] = []; + // eslint-disable-next-line import/no-deprecated let currentBackwardSlideGroup: LocalReferenceCollection[] = []; let currentForwardMaybeEndpoint: "start" | "end" | undefined; @@ -900,6 +903,7 @@ export class MergeTree { const slideGroup = ( currentSlideDestination: ISegmentLeaf | undefined, currentSlideIsForward: boolean | undefined, + // eslint-disable-next-line import/no-deprecated currentSlideGroup: LocalReferenceCollection[], pred: (ref: LocalReferencePosition) => boolean, maybeEndpoint: "start" | "end" | undefined, @@ -924,6 +928,7 @@ export class MergeTree { if (maybeEndpoint) { const endpoint = maybeEndpoint === "start" ? this.startOfTree : this.endOfTree; + // eslint-disable-next-line import/no-deprecated const localRefs = LocalReferenceCollection.setOrGet(endpoint); if (currentSlideIsForward) { localRefs.addBeforeTombstones(...endpointRefsToAdd); @@ -943,6 +948,7 @@ export class MergeTree { } } } else { + // eslint-disable-next-line import/no-deprecated const localRefs = LocalReferenceCollection.setOrGet(currentSlideDestination); if (currentSlideIsForward) { localRefs.addBeforeTombstones(...nonEndpointRefsToAdd); @@ -956,11 +962,13 @@ export class MergeTree { segment: ISegmentLeaf, currentSlideDestination: ISegmentLeaf | undefined, currentSlideIsForward: boolean | undefined, + // eslint-disable-next-line import/no-deprecated currentSlideGroup: LocalReferenceCollection[], pred: (ref: LocalReferencePosition) => boolean, slidingPreference: SlidingPreference, currentMaybeEndpoint: "start" | "end" | undefined, reassign: ( + // eslint-disable-next-line import/no-deprecated localRefs: LocalReferenceCollection, slideToSegment: ISegmentLeaf | undefined, slideIsForward: boolean, @@ -2520,6 +2528,7 @@ export class MergeTree { segment = _segment; } + // eslint-disable-next-line import/no-deprecated const localRefs = LocalReferenceCollection.setOrGet(segment); const segRef = localRefs.createLocalRef( diff --git a/packages/dds/merge-tree/src/mergeTreeNodes.ts b/packages/dds/merge-tree/src/mergeTreeNodes.ts index e81767a6e123..755573ea532c 100644 --- a/packages/dds/merge-tree/src/mergeTreeNodes.ts +++ b/packages/dds/merge-tree/src/mergeTreeNodes.ts @@ -14,6 +14,7 @@ import { UnassignedSequenceNumber, UniversalSequenceNumber, } from "./constants.js"; +// eslint-disable-next-line import/no-deprecated import { LocalReferenceCollection, type LocalReferencePosition } from "./localReference.js"; import { TrackingGroupCollection } from "./mergeTreeTracking.js"; import { IJSONSegment, IMarkerDef, ReferenceType } from "./ops.js"; @@ -63,6 +64,7 @@ export type ISegmentInternal = Omit & Partial & Partial & { + // eslint-disable-next-line import/no-deprecated localRefs?: LocalReferenceCollection; }; @@ -291,6 +293,7 @@ export interface ISegment { * Local references added to this segment. * @deprecated - This property will be removed in 2.20 with no replacement. */ + // eslint-disable-next-line import/no-deprecated localRefs?: LocalReferenceCollection; /** * Properties that have been added to this segment via annotation. @@ -625,6 +628,7 @@ export abstract class BaseSegment implements ISegment { /** * @deprecated - This property will be removed in 2.20 with no replacement. */ + // eslint-disable-next-line import/no-deprecated public localRefs?: LocalReferenceCollection; public abstract readonly type: string; /** @@ -731,6 +735,7 @@ export abstract class BaseSegment implements ISegment { public append(other: ISegment): void { // Note: Must call 'appendLocalRefs' before modifying this segment's length as // 'this.cachedLength' is used to adjust the offsets of the local refs. + // eslint-disable-next-line import/no-deprecated LocalReferenceCollection.append(this, other); if (this.attribution) { assert( diff --git a/packages/dds/merge-tree/src/revertibles.ts b/packages/dds/merge-tree/src/revertibles.ts index b50b3329eb89..dad9056b6747 100644 --- a/packages/dds/merge-tree/src/revertibles.ts +++ b/packages/dds/merge-tree/src/revertibles.ts @@ -8,6 +8,7 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal"; import { DoublyLinkedList } from "./collections/index.js"; import { EndOfTreeSegment } from "./endOfTreeSegment.js"; +// eslint-disable-next-line import/no-deprecated import { LocalReferenceCollection, LocalReferencePosition } from "./localReference.js"; import { MergeTree, findRootMergeBlock } from "./mergeTree.js"; import { IMergeTreeDeltaCallbackArgs } from "./mergeTreeDeltaCallback.js"; @@ -98,6 +99,7 @@ function findMergeTreeWithRevert(trackable: Trackable): MergeTreeWithRevert { const refCallbacks: MergeTreeWithRevert["__mergeTreeRevertible"]["refCallbacks"] = { afterSlide: (r: LocalReferencePosition) => { if (mergeTree.referencePositionToLocalPosition(r) === DetachedReferencePosition) { + // eslint-disable-next-line import/no-deprecated const refs = LocalReferenceCollection.setOrGet(detachedReferences); refs.addAfterTombstones([r]); } @@ -354,6 +356,7 @@ function revertLocalRemove( } if (insertRef !== undefined) { + // eslint-disable-next-line import/no-deprecated const localRefs = LocalReferenceCollection.setOrGet(insertSegment); if (insertRef.before?.empty === false) { localRefs.addBeforeTombstones(insertRef.before.map((n) => n.data)); From 5f280dea9a42645a7b59b43fbf470a5362e41a2f Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Fri, 13 Dec 2024 08:53:17 -0800 Subject: [PATCH 4/7] Update .changeset/real-grapes-kick.md Co-authored-by: Alex Villarreal <716334+alexvy86@users.noreply.github.com> --- .changeset/real-grapes-kick.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/real-grapes-kick.md b/.changeset/real-grapes-kick.md index 21439fddbbf7..74627a74950e 100644 --- a/.changeset/real-grapes-kick.md +++ b/.changeset/real-grapes-kick.md @@ -10,7 +10,7 @@ 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` +The only use case that will continue to be supported is determining if a segment is removed. For this purpose we've added the free function `segmentIsRemoved(segment: ISegment): boolean`. For example, checking if a segment is not removed would change as follows: ``` diff From c61d5c4b19be945e69b31e08d8eb25bbeae65956 Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Fri, 13 Dec 2024 08:53:33 -0800 Subject: [PATCH 5/7] Update .changeset/real-grapes-kick.md Co-authored-by: Alex Villarreal <716334+alexvy86@users.noreply.github.com> --- .changeset/real-grapes-kick.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/real-grapes-kick.md b/.changeset/real-grapes-kick.md index 74627a74950e..111d9fa44cda 100644 --- a/.changeset/real-grapes-kick.md +++ b/.changeset/real-grapes-kick.md @@ -34,7 +34,7 @@ The following properties are deprecated on ISegment and its implementations: - seq - wasMovedOnInsert -Additionally, the following types are also deprecated, and will become internal: +Additionally, the following types are also deprecated, and will become internal (i.e. users of the Fluid Framework will not have access to them): - IMergeNodeCommon - IMoveInfo - IRemovalInfo From 21334a9d4749e8e8417b3bc2ae33e3a3ba9edcd2 Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Fri, 13 Dec 2024 11:07:32 -0800 Subject: [PATCH 6/7] Update packages/dds/merge-tree/src/mergeTreeNodes.ts Co-authored-by: Abram Sanderson --- packages/dds/merge-tree/src/mergeTreeNodes.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/dds/merge-tree/src/mergeTreeNodes.ts b/packages/dds/merge-tree/src/mergeTreeNodes.ts index 755573ea532c..19587496d024 100644 --- a/packages/dds/merge-tree/src/mergeTreeNodes.ts +++ b/packages/dds/merge-tree/src/mergeTreeNodes.ts @@ -370,10 +370,7 @@ export interface ISegment { */ export function segmentIsRemoved(segment: ISegment): boolean { const leaf: ISegmentLeaf = segment; - if (leaf.removedSeq === undefined) { - return false; - } - return true; + return leaf.removedSeg !== undefined; } /** From e59894adc5ad211147252dfa4db6336c414cc4f2 Mon Sep 17 00:00:00 2001 From: Tony Murphy Date: Fri, 13 Dec 2024 11:16:15 -0800 Subject: [PATCH 7/7] fix typo --- packages/dds/merge-tree/src/mergeTreeNodes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dds/merge-tree/src/mergeTreeNodes.ts b/packages/dds/merge-tree/src/mergeTreeNodes.ts index 19587496d024..3d8d8b83680e 100644 --- a/packages/dds/merge-tree/src/mergeTreeNodes.ts +++ b/packages/dds/merge-tree/src/mergeTreeNodes.ts @@ -370,7 +370,7 @@ export interface ISegment { */ export function segmentIsRemoved(segment: ISegment): boolean { const leaf: ISegmentLeaf = segment; - return leaf.removedSeg !== undefined; + return leaf.removedSeq !== undefined; } /**