@fluidframework/merge-tree 2.10.0-306579 → 2.10.0-307399

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/api-report/merge-tree.legacy.alpha.api.md +27 -0
  2. package/dist/collections/index.d.ts +1 -1
  3. package/dist/collections/index.d.ts.map +1 -1
  4. package/dist/collections/index.js +2 -1
  5. package/dist/collections/index.js.map +1 -1
  6. package/dist/collections/list.d.ts +7 -0
  7. package/dist/collections/list.d.ts.map +1 -1
  8. package/dist/collections/list.js +27 -1
  9. package/dist/collections/list.js.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/legacy.d.ts +2 -0
  14. package/dist/mergeTree.d.ts.map +1 -1
  15. package/dist/mergeTree.js +10 -9
  16. package/dist/mergeTree.js.map +1 -1
  17. package/dist/ops.d.ts +36 -0
  18. package/dist/ops.d.ts.map +1 -1
  19. package/dist/ops.js.map +1 -1
  20. package/dist/segmentPropertiesManager.d.ts +81 -8
  21. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  22. package/dist/segmentPropertiesManager.js +211 -61
  23. package/dist/segmentPropertiesManager.js.map +1 -1
  24. package/dist/test/propertyManager.spec.d.ts +6 -0
  25. package/dist/test/propertyManager.spec.d.ts.map +1 -0
  26. package/dist/test/propertyManager.spec.js +156 -0
  27. package/dist/test/propertyManager.spec.js.map +1 -0
  28. package/dist/zamboni.d.ts.map +1 -1
  29. package/dist/zamboni.js +1 -0
  30. package/dist/zamboni.js.map +1 -1
  31. package/lib/collections/index.d.ts +1 -1
  32. package/lib/collections/index.d.ts.map +1 -1
  33. package/lib/collections/index.js +1 -1
  34. package/lib/collections/index.js.map +1 -1
  35. package/lib/collections/list.d.ts +7 -0
  36. package/lib/collections/list.d.ts.map +1 -1
  37. package/lib/collections/list.js +25 -0
  38. package/lib/collections/list.js.map +1 -1
  39. package/lib/index.d.ts +2 -2
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js.map +1 -1
  42. package/lib/legacy.d.ts +2 -0
  43. package/lib/mergeTree.d.ts.map +1 -1
  44. package/lib/mergeTree.js +10 -9
  45. package/lib/mergeTree.js.map +1 -1
  46. package/lib/ops.d.ts +36 -0
  47. package/lib/ops.d.ts.map +1 -1
  48. package/lib/ops.js.map +1 -1
  49. package/lib/segmentPropertiesManager.d.ts +81 -8
  50. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  51. package/lib/segmentPropertiesManager.js +212 -62
  52. package/lib/segmentPropertiesManager.js.map +1 -1
  53. package/lib/test/propertyManager.spec.d.ts +6 -0
  54. package/lib/test/propertyManager.spec.d.ts.map +1 -0
  55. package/lib/test/propertyManager.spec.js +154 -0
  56. package/lib/test/propertyManager.spec.js.map +1 -0
  57. package/lib/zamboni.d.ts.map +1 -1
  58. package/lib/zamboni.js +1 -0
  59. package/lib/zamboni.js.map +1 -1
  60. package/package.json +24 -17
  61. package/src/collections/index.ts +7 -1
  62. package/src/collections/list.ts +29 -0
  63. package/src/index.ts +3 -0
  64. package/src/mergeTree.ts +16 -11
  65. package/src/ops.ts +38 -0
  66. package/src/segmentPropertiesManager.ts +277 -88
  67. package/src/zamboni.ts +3 -0
package/dist/ops.d.ts CHANGED
@@ -182,6 +182,42 @@ export interface IMergeTreeAnnotateMsg extends IMergeTreeDelta {
182
182
  pos2?: number;
183
183
  relativePos2?: IRelativePosition;
184
184
  props: Record<string, any>;
185
+ adjust?: never;
186
+ }
187
+ /**
188
+ * Used to define per key adjustments in an {@link IMergeTreeAnnotateAdjustMsg}
189
+ * @alpha
190
+ * @legacy
191
+ */
192
+ export interface AdjustParams {
193
+ /**
194
+ * The adjustment delta which will be summed with the current value if it is a number,
195
+ * or summed with zero if the current value is not a number.
196
+ */
197
+ delta: number;
198
+ /**
199
+ * An optional minimum value for the computed value of the key this adjustment is applied to.
200
+ * The minimum will be applied after the value is applied.
201
+ */
202
+ min?: number | undefined;
203
+ /**
204
+ * An optional maximum value for the computed value of the key this adjustment is applied to.
205
+ * The maximum will be applied after the value is applied.
206
+ */
207
+ max?: number | undefined;
208
+ }
209
+ /**
210
+ * @legacy
211
+ * @alpha
212
+ */
213
+ export interface IMergeTreeAnnotateAdjustMsg extends IMergeTreeDelta {
214
+ type: typeof MergeTreeDeltaType.ANNOTATE;
215
+ pos1?: number;
216
+ pos2?: number;
217
+ relativePos1?: undefined;
218
+ relativePos2?: undefined;
219
+ props?: never;
220
+ adjust: Record<string, AdjustParams>;
185
221
  }
186
222
  /**
187
223
  * @deprecated The ability to create group ops will be removed in an upcoming
package/dist/ops.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"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"}
package/dist/ops.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ops.js","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;GAIG;AACH,IAAY,aAsCX;AAtCD,WAAY,aAAa;IACxB,qDAAY,CAAA;IACZ;;OAEG;IACH,iDAAU,CAAA;IAEV;;;;OAIG;IACH,8DAAiB,CAAA;IAEjB;;;;OAIG;IACH,0DAAe,CAAA;IAEf;;;;;;OAMG;IACH,oEAAoB,CAAA;IACpB;;OAEG;IACH,mEAAmB,CAAA;IACnB;;;OAGG;IACH,6DAAiB,CAAA;AAClB,CAAC,EAtCW,aAAa,6BAAb,aAAa,QAsCxB;AAUD,mFAAmF;AACnF;;;GAGG;AACU,QAAA,kBAAkB,GAAG;IACjC,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,QAAQ,EAAE,CAAC;IACX;;OAEG;IACH,KAAK,EAAE,CAAC;IACR,UAAU,EAAE,CAAC;IACb,gBAAgB,EAAE,CAAC;CACV,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Flags enum that dictates behavior of a {@link ReferencePosition}\n * @legacy\n * @alpha\n */\nexport enum ReferenceType {\n\tSimple = 0x0,\n\t/**\n\t * Allows this reference to be located using the `searchForMarker` API on merge-tree.\n\t */\n\tTile = 0x1,\n\n\t/**\n\t * Denotes that this reference begins the start of an interval. This is\n\t * generally not meaningful outside the context of interval collections\n\t * on SharedString.\n\t */\n\tRangeBegin = 0x10,\n\n\t/**\n\t * Denotes that this reference is the end of an interval. This is\n\t * generally not meaningful outside the context of interval collections\n\t * on SharedString.\n\t */\n\tRangeEnd = 0x20,\n\n\t/**\n\t * When a segment is marked removed (locally or with ack), this reference will slide to the first\n\t * valid option of:\n\t * 1. the start of the next furthest segment\n\t * 2. the end of the next nearest segment\n\t * 3. DetachedReferencePosition\n\t */\n\tSlideOnRemove = 0x40,\n\t/**\n\t * When a segment is marked removed (locally or with ack), this reference will remain on that segment.\n\t */\n\tStayOnRemove = 0x80,\n\t/**\n\t * Specifies that the reference position should never be added to the segment it refers to.\n\t * This is useful for comparison/iteration purposes\n\t */\n\tTransient = 0x100,\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMarkerDef {\n\trefType?: ReferenceType;\n}\n\n// Note: Assigned positive integers to avoid clashing with MergeTreeMaintenanceType\n/**\n * @legacy\n * @alpha\n */\nexport const MergeTreeDeltaType = {\n\tINSERT: 0,\n\tREMOVE: 1,\n\tANNOTATE: 2,\n\t/**\n\t * @deprecated The ability to create group ops will be removed in an upcoming release, as group ops are redundant with he native batching capabilities of the runtime\n\t */\n\tGROUP: 3,\n\tOBLITERATE: 4,\n\tOBLITERATE_SIDED: 5,\n} as const;\n\n/**\n * @legacy\n * @alpha\n */\nexport type MergeTreeDeltaType = (typeof MergeTreeDeltaType)[keyof typeof MergeTreeDeltaType];\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeDelta {\n\t/**\n\t * Type of this change.\n\t */\n\ttype: MergeTreeDeltaType;\n}\n\n/**\n * A position specified relative to a segment.\n * @legacy\n * @alpha\n */\nexport interface IRelativePosition {\n\t/**\n\t * String identifier specifying a segment.\n\t */\n\tid?: string;\n\t/**\n\t * If true, insert before the specified segment. If false or not defined,\n\t * insert after the specified segment.\n\t */\n\tbefore?: boolean;\n\t/**\n\t * A positive number \\>= 1. If before is false, offset is added to the position.\n\t * If before is true, offset is subtracted from the position.\n\t */\n\toffset?: number;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeInsertMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.INSERT;\n\tpos1?: number;\n\trelativePos1?: IRelativePosition;\n\tpos2?: number;\n\trelativePos2?: IRelativePosition;\n\t// The segment must be allowed to be of any type in order to acommodate converting from\n\t// JSON to a segment.\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tseg?: any;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeRemoveMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.REMOVE;\n\tpos1?: number;\n\trelativePos1?: IRelativePosition;\n\tpos2?: number;\n\trelativePos2?: IRelativePosition;\n}\n\n/**\n * @deprecated We no longer intend to support this functionality and it will\n * be removed in a future release. There is no replacement for this\n * functionality.\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeObliterateMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.OBLITERATE;\n\tpos1?: number;\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos1?: never;\n\tpos2?: number;\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos2?: never;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeObliterateSidedMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.OBLITERATE_SIDED;\n\tpos1: { pos: number; before: boolean };\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos1?: never;\n\tpos2: { pos: number; before: boolean };\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos2?: never;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeAnnotateMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.ANNOTATE;\n\tpos1?: number;\n\trelativePos1?: IRelativePosition;\n\tpos2?: number;\n\trelativePos2?: IRelativePosition;\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprops: Record<string, any>;\n}\n\n/**\n * @deprecated The ability to create group ops will be removed in an upcoming\n * release, as group ops are redundant with the native batching capabilities\n * of the runtime\n *\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeGroupMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.GROUP;\n\tops: IMergeTreeDeltaOp[];\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IJSONSegment {\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprops?: Record<string, any>;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport type IMergeTreeDeltaOp =\n\t| IMergeTreeInsertMsg\n\t| IMergeTreeRemoveMsg\n\t| IMergeTreeAnnotateMsg\n\t| IMergeTreeObliterateMsg\n\t| IMergeTreeObliterateSidedMsg;\n\n/**\n * @legacy\n * @alpha\n */\nexport type IMergeTreeOp = IMergeTreeDeltaOp | IMergeTreeGroupMsg;\n"]}
1
+ {"version":3,"file":"ops.js","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;GAIG;AACH,IAAY,aAsCX;AAtCD,WAAY,aAAa;IACxB,qDAAY,CAAA;IACZ;;OAEG;IACH,iDAAU,CAAA;IAEV;;;;OAIG;IACH,8DAAiB,CAAA;IAEjB;;;;OAIG;IACH,0DAAe,CAAA;IAEf;;;;;;OAMG;IACH,oEAAoB,CAAA;IACpB;;OAEG;IACH,mEAAmB,CAAA;IACnB;;;OAGG;IACH,6DAAiB,CAAA;AAClB,CAAC,EAtCW,aAAa,6BAAb,aAAa,QAsCxB;AAUD,mFAAmF;AACnF;;;GAGG;AACU,QAAA,kBAAkB,GAAG;IACjC,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,QAAQ,EAAE,CAAC;IACX;;OAEG;IACH,KAAK,EAAE,CAAC;IACR,UAAU,EAAE,CAAC;IACb,gBAAgB,EAAE,CAAC;CACV,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Flags enum that dictates behavior of a {@link ReferencePosition}\n * @legacy\n * @alpha\n */\nexport enum ReferenceType {\n\tSimple = 0x0,\n\t/**\n\t * Allows this reference to be located using the `searchForMarker` API on merge-tree.\n\t */\n\tTile = 0x1,\n\n\t/**\n\t * Denotes that this reference begins the start of an interval. This is\n\t * generally not meaningful outside the context of interval collections\n\t * on SharedString.\n\t */\n\tRangeBegin = 0x10,\n\n\t/**\n\t * Denotes that this reference is the end of an interval. This is\n\t * generally not meaningful outside the context of interval collections\n\t * on SharedString.\n\t */\n\tRangeEnd = 0x20,\n\n\t/**\n\t * When a segment is marked removed (locally or with ack), this reference will slide to the first\n\t * valid option of:\n\t * 1. the start of the next furthest segment\n\t * 2. the end of the next nearest segment\n\t * 3. DetachedReferencePosition\n\t */\n\tSlideOnRemove = 0x40,\n\t/**\n\t * When a segment is marked removed (locally or with ack), this reference will remain on that segment.\n\t */\n\tStayOnRemove = 0x80,\n\t/**\n\t * Specifies that the reference position should never be added to the segment it refers to.\n\t * This is useful for comparison/iteration purposes\n\t */\n\tTransient = 0x100,\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMarkerDef {\n\trefType?: ReferenceType;\n}\n\n// Note: Assigned positive integers to avoid clashing with MergeTreeMaintenanceType\n/**\n * @legacy\n * @alpha\n */\nexport const MergeTreeDeltaType = {\n\tINSERT: 0,\n\tREMOVE: 1,\n\tANNOTATE: 2,\n\t/**\n\t * @deprecated The ability to create group ops will be removed in an upcoming release, as group ops are redundant with he native batching capabilities of the runtime\n\t */\n\tGROUP: 3,\n\tOBLITERATE: 4,\n\tOBLITERATE_SIDED: 5,\n} as const;\n\n/**\n * @legacy\n * @alpha\n */\nexport type MergeTreeDeltaType = (typeof MergeTreeDeltaType)[keyof typeof MergeTreeDeltaType];\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeDelta {\n\t/**\n\t * Type of this change.\n\t */\n\ttype: MergeTreeDeltaType;\n}\n\n/**\n * A position specified relative to a segment.\n * @legacy\n * @alpha\n */\nexport interface IRelativePosition {\n\t/**\n\t * String identifier specifying a segment.\n\t */\n\tid?: string;\n\t/**\n\t * If true, insert before the specified segment. If false or not defined,\n\t * insert after the specified segment.\n\t */\n\tbefore?: boolean;\n\t/**\n\t * A positive number \\>= 1. If before is false, offset is added to the position.\n\t * If before is true, offset is subtracted from the position.\n\t */\n\toffset?: number;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeInsertMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.INSERT;\n\tpos1?: number;\n\trelativePos1?: IRelativePosition;\n\tpos2?: number;\n\trelativePos2?: IRelativePosition;\n\t// The segment must be allowed to be of any type in order to acommodate converting from\n\t// JSON to a segment.\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tseg?: any;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeRemoveMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.REMOVE;\n\tpos1?: number;\n\trelativePos1?: IRelativePosition;\n\tpos2?: number;\n\trelativePos2?: IRelativePosition;\n}\n\n/**\n * @deprecated We no longer intend to support this functionality and it will\n * be removed in a future release. There is no replacement for this\n * functionality.\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeObliterateMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.OBLITERATE;\n\tpos1?: number;\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos1?: never;\n\tpos2?: number;\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos2?: never;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeObliterateSidedMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.OBLITERATE_SIDED;\n\tpos1: { pos: number; before: boolean };\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos1?: never;\n\tpos2: { pos: number; before: boolean };\n\t/**\n\t * This field is currently unused, but we keep it around to make the union\n\t * type of all merge-tree messages have the same fields\n\t */\n\trelativePos2?: never;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeAnnotateMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.ANNOTATE;\n\tpos1?: number;\n\trelativePos1?: IRelativePosition;\n\tpos2?: number;\n\trelativePos2?: IRelativePosition;\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprops: Record<string, any>;\n\tadjust?: never;\n}\n\n/**\n * Used to define per key adjustments in an {@link IMergeTreeAnnotateAdjustMsg}\n * @alpha\n * @legacy\n */\nexport interface AdjustParams {\n\t/**\n\t * The adjustment delta which will be summed with the current value if it is a number,\n\t * or summed with zero if the current value is not a number.\n\t */\n\tdelta: number;\n\t/**\n\t * An optional minimum value for the computed value of the key this adjustment is applied to.\n\t * The minimum will be applied after the value is applied.\n\t */\n\tmin?: number | undefined;\n\t/**\n\t * An optional maximum value for the computed value of the key this adjustment is applied to.\n\t * The maximum will be applied after the value is applied.\n\t */\n\tmax?: number | undefined;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeAnnotateAdjustMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.ANNOTATE;\n\tpos1?: number;\n\tpos2?: number;\n\trelativePos1?: undefined;\n\trelativePos2?: undefined;\n\tprops?: never;\n\tadjust: Record<string, AdjustParams>;\n}\n\n/**\n * @deprecated The ability to create group ops will be removed in an upcoming\n * release, as group ops are redundant with the native batching capabilities\n * of the runtime\n *\n * @legacy\n * @alpha\n */\nexport interface IMergeTreeGroupMsg extends IMergeTreeDelta {\n\ttype: typeof MergeTreeDeltaType.GROUP;\n\tops: IMergeTreeDeltaOp[];\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport interface IJSONSegment {\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprops?: Record<string, any>;\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport type IMergeTreeDeltaOp =\n\t| IMergeTreeInsertMsg\n\t| IMergeTreeRemoveMsg\n\t| IMergeTreeAnnotateMsg\n\t| IMergeTreeObliterateMsg\n\t| IMergeTreeObliterateSidedMsg;\n\n/**\n * @legacy\n * @alpha\n */\nexport type IMergeTreeOp = IMergeTreeDeltaOp | IMergeTreeGroupMsg;\n"]}
@@ -2,8 +2,8 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IMergeTreeAnnotateMsg } from "./ops.js";
6
- import { PropertySet } from "./properties.js";
5
+ import type { IMergeTreeAnnotateAdjustMsg, IMergeTreeAnnotateMsg } from "./ops.js";
6
+ import { MapLike, PropertySet } from "./properties.js";
7
7
  /**
8
8
  * @internal
9
9
  */
@@ -31,16 +31,89 @@ export declare function copyPropertiesAndManager(source: {
31
31
  /**
32
32
  * @internal
33
33
  */
34
+ export type PropsOrAdjust = Pick<IMergeTreeAnnotateAdjustMsg, "props" | "adjust"> | Pick<IMergeTreeAnnotateMsg, "props" | "adjust">;
35
+ /**
36
+ * The PropertiesManager class handles changes to properties, both remote and local.
37
+ * It manages the lifecycle for local property changes, ensures all property changes are eventually consistent,
38
+ * and provides methods to acknowledge changes, update the minimum sequence number (msn), and copy properties to another manager.
39
+ * This class is essential for maintaining the integrity and consistency of property changes in collaborative environments.
40
+ * @internal
41
+ */
34
42
  export declare class PropertiesManager {
35
- private pendingKeyUpdateCount;
36
- ackPendingProperties(annotateOp: IMergeTreeAnnotateMsg): void;
37
- private decrementPendingCounts;
38
- addProperties(oldProps: PropertySet, newProps: PropertySet, seq?: number, collaborating?: boolean, rollback?: PropertiesRollback): PropertySet;
39
- copyTo(oldProps: PropertySet, newProps: PropertySet | undefined, newManager: PropertiesManager): PropertySet | undefined;
43
+ private readonly changes;
44
+ /**
45
+ * Rolls back local property changes.
46
+ * This method reverts property changes based on the provided operation and segment.
47
+ * If the operation is part of a collaborative session, it ensures that the changes are consistent with the remote state.
48
+ *
49
+ * @param op - The operation containing property changes. This can be an adjustment or a set of properties.
50
+ * @param seg - The segment containing properties. This object may have a properties map that will be modified.
51
+ * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.
52
+ * @returns The deltas of the rolled-back properties. This is a map-like object representing the changes that were reverted.
53
+ */
54
+ rollbackProperties(op: PropsOrAdjust, seg: {
55
+ properties?: MapLike<unknown>;
56
+ }, collaborating?: boolean): MapLike<unknown>;
57
+ /**
58
+ * Handles property changes.
59
+ * This method applies property changes based on the provided operation, segment, sequence number, and collaboration state.
60
+ * It also handles rolling back changes if specified.
61
+ *
62
+ * @param op - The operation containing property changes.
63
+ * @param seg - The segment containing properties.
64
+ * @param seq - The sequence number for the operation.
65
+ * @param msn - The minimum sequence number for the operation.
66
+ * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.
67
+ * @param rollback - Specifies if the changes should be rolled back. Defaults to PropertiesRollback.None.
68
+ * @returns The deltas of the applied or rolled-back properties. This is a map-like object representing the changes.
69
+ */
70
+ handleProperties(op: PropsOrAdjust, seg: {
71
+ properties?: MapLike<unknown>;
72
+ }, seq: number, msn: number, collaborating?: boolean, rollback?: PropertiesRollback): MapLike<unknown>;
73
+ /**
74
+ * Acknowledges property changes.
75
+ * This method acknowledges the property changes based on the provided sequence number and operation.
76
+ *
77
+ * @param seq - The sequence number for the operation.
78
+ * @param msn - The minimum sequence number for the operation.
79
+ * @param op - The operation containing property changes.
80
+ */
81
+ ack(seq: number, msn: number, op: PropsOrAdjust): void;
82
+ /**
83
+ * Updates the minimum sequence number (msn).
84
+ * This method updates the minimum sequence number and removes any changes that have been acknowledged.
85
+ *
86
+ * @param msn - The minimum sequence number to update.
87
+ */
88
+ updateMsn(msn: number): void;
89
+ /**
90
+ * Copies properties to another manager.
91
+ * This method copies the properties and their changes from the current manager to the destination manager.
92
+ *
93
+ * @param oldProps - The old properties to be copied.
94
+ * @param dest - The destination object containing properties and property manager.
95
+ */
96
+ copyTo(oldProps: PropertySet | undefined, dest: {
97
+ properties?: PropertySet;
98
+ propertyManager?: PropertiesManager;
99
+ }): void;
100
+ /**
101
+ * Gets properties at a specific sequence number.
102
+ * This method retrieves the properties at the given sequence number.
103
+ * This is only needed to support emitting snapshots in the legacy format.
104
+ * If we remove the ability to emit the legacy format, we can remove this method, along with the need to track remote changes at all.
105
+ *
106
+ * @param oldProps - The old properties to be retrieved.
107
+ * @param sequenceNumber - The sequence number to get properties at.
108
+ * @returns The properties at the given sequence number.
109
+ */
110
+ getAtSeq(oldProps: MapLike<unknown> | undefined, sequenceNumber: number): MapLike<unknown>;
40
111
  /**
41
112
  * Determines if all of the defined properties in a given property set are pending.
113
+ *
114
+ * @param props - The properties to check.
115
+ * @returns True if all the properties are pending, false otherwise.
42
116
  */
43
117
  hasPendingProperties(props: PropertySet): boolean;
44
- hasPendingProperty(key: string): boolean;
45
118
  }
46
119
  //# sourceMappingURL=segmentPropertiesManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"segmentPropertiesManager.d.ts","sourceRoot":"","sources":["../src/segmentPropertiesManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAW,WAAW,EAA4B,MAAM,iBAAiB,CAAC;AAEjF;;GAEG;AACH,oBAAY,kBAAkB;IAC7B;;OAEG;IACH,IAAI,IAAA;IAEJ;;OAEG;IACH,QAAQ,IAAA;CACR;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,MAAM,EAAE;IACP,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACpC,EACD,WAAW,EAAE;IACZ,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACpC,GACC,IAAI,CAaN;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,qBAAqB,CAA8B;IAEpD,oBAAoB,CAAC,UAAU,EAAE,qBAAqB,GAAG,IAAI;IAIpE,OAAO,CAAC,sBAAsB;IAgBvB,aAAa,CACnB,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,WAAW,EACrB,GAAG,CAAC,EAAE,MAAM,EACZ,aAAa,GAAE,OAAe,EAC9B,QAAQ,GAAE,kBAA4C,GACpD,WAAW;IAqDP,MAAM,CACZ,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,WAAW,GAAG,SAAS,EACjC,UAAU,EAAE,iBAAiB,GAC3B,WAAW,GAAG,SAAS;IAgB1B;;OAEG;IACI,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;IASjD,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG/C"}
1
+ {"version":3,"file":"segmentPropertiesManager.d.ts","sourceRoot":"","sources":["../src/segmentPropertiesManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAEX,2BAA2B,EAC3B,qBAAqB,EACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAoB,MAAM,iBAAiB,CAAC;AAEzE;;GAEG;AACH,oBAAY,kBAAkB;IAC7B;;OAEG;IACH,IAAI,IAAA;IAEJ;;OAEG;IACH,QAAQ,IAAA;CACR;AACD;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,MAAM,EAAE;IACP,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACpC,EACD,WAAW,EAAE;IACZ,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,eAAe,CAAC,EAAE,iBAAiB,CAAC;CACpC,GACC,IAAI,CASN;AAsCD;;GAEG;AACH,MAAM,MAAM,aAAa,GACtB,IAAI,CAAC,2BAA2B,EAAE,OAAO,GAAG,QAAQ,CAAC,GACrD,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,QAAQ,CAAC,CAAC;AAoCnD;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D;;;;;;;;;OASG;IACI,kBAAkB,CACxB,EAAE,EAAE,aAAa,EACjB,GAAG,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,EACtC,aAAa,GAAE,OAAe,GAC5B,OAAO,CAAC,OAAO,CAAC;IA4BnB;;;;;;;;;;;;OAYG;IACI,gBAAgB,CACtB,EAAE,EAAE,aAAa,EACjB,GAAG,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,EACtC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,aAAa,GAAE,OAAe,EAC9B,QAAQ,GAAE,kBAA4C,GACpD,OAAO,CAAC,OAAO,CAAC;IA6CnB;;;;;;;OAOG;IACI,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,GAAG,IAAI;IAkB7D;;;;;OAKG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAkBnC;;;;;;OAMG;IACI,MAAM,CACZ,QAAQ,EAAE,WAAW,GAAG,SAAS,EACjC,IAAI,EAAE;QACL,UAAU,CAAC,EAAE,WAAW,CAAC;QACzB,eAAe,CAAC,EAAE,iBAAiB,CAAC;KACpC,GACC,IAAI;IAYP;;;;;;;;;OASG;IACI,QAAQ,CACd,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,EACtC,cAAc,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,CAAC;IAenB;;;;;OAKG;IACI,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;CAQxD"}
@@ -5,8 +5,8 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.PropertiesManager = exports.copyPropertiesAndManager = exports.PropertiesRollback = void 0;
8
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
9
8
  const internal_1 = require("@fluidframework/core-utils/internal");
9
+ const index_js_1 = require("./collections/index.js");
10
10
  const constants_js_1 = require("./constants.js");
11
11
  const properties_js_1 = require("./properties.js");
12
12
  /**
@@ -34,103 +34,253 @@ function copyPropertiesAndManager(source, destination) {
34
34
  }
35
35
  else {
36
36
  destination.propertyManager ?? (destination.propertyManager = new PropertiesManager());
37
- destination.properties = source.propertyManager.copyTo(source.properties, destination.properties, destination.propertyManager);
37
+ source.propertyManager.copyTo(source.properties, destination);
38
38
  }
39
39
  }
40
40
  }
41
41
  exports.copyPropertiesAndManager = copyPropertiesAndManager;
42
+ function computePropertyValue(consensus, ...changes) {
43
+ let computedValue = consensus;
44
+ for (const change of changes) {
45
+ for (const op of change) {
46
+ const { raw, adjust } = op;
47
+ if (adjust === undefined) {
48
+ computedValue = raw;
49
+ }
50
+ else {
51
+ const adjusted = (typeof computedValue === "number" ? computedValue : 0) + adjust.delta;
52
+ if (adjust.max !== undefined && adjusted > adjust.max) {
53
+ computedValue = adjust.max;
54
+ }
55
+ else if (adjust.min !== undefined && adjusted < adjust.min) {
56
+ computedValue = adjust.min;
57
+ }
58
+ else {
59
+ computedValue = adjusted;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ return computedValue;
65
+ }
66
+ const opToChanges = (op, seq) => [
67
+ ...Object.entries(op.props ?? {})
68
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
69
+ .map(([k, raw]) => [k, { raw, seq }])
70
+ .filter(([_, v]) => v.raw !== undefined),
71
+ ...Object.entries(op.adjust ?? {}).map(([k, adjust]) => [
72
+ k,
73
+ { adjust, seq },
74
+ ]),
75
+ ];
76
+ function applyChanges(op, seg, seq, run) {
77
+ const properties = (seg.properties ?? (seg.properties = (0, properties_js_1.createMap)()));
78
+ const deltas = {};
79
+ for (const [key, value] of opToChanges(op, seq)) {
80
+ run(properties, deltas, key, value);
81
+ if (properties[key] === null) {
82
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
83
+ delete properties[key];
84
+ }
85
+ }
86
+ return deltas;
87
+ }
42
88
  /**
89
+ * The PropertiesManager class handles changes to properties, both remote and local.
90
+ * It manages the lifecycle for local property changes, ensures all property changes are eventually consistent,
91
+ * and provides methods to acknowledge changes, update the minimum sequence number (msn), and copy properties to another manager.
92
+ * This class is essential for maintaining the integrity and consistency of property changes in collaborative environments.
43
93
  * @internal
44
94
  */
45
95
  class PropertiesManager {
46
- ackPendingProperties(annotateOp) {
47
- this.decrementPendingCounts(annotateOp.props);
96
+ constructor() {
97
+ this.changes = new Map();
48
98
  }
49
- decrementPendingCounts(props) {
50
- for (const [key, value] of Object.entries(props)) {
51
- if (value !== undefined && this.pendingKeyUpdateCount?.[key] !== undefined) {
52
- (0, internal_1.assert)(this.pendingKeyUpdateCount[key] > 0, 0x05c /* "Trying to update more annotate props than do exist!" */);
53
- this.pendingKeyUpdateCount[key]--;
54
- if (this.pendingKeyUpdateCount?.[key] === 0) {
55
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
56
- delete this.pendingKeyUpdateCount[key];
99
+ /**
100
+ * Rolls back local property changes.
101
+ * This method reverts property changes based on the provided operation and segment.
102
+ * If the operation is part of a collaborative session, it ensures that the changes are consistent with the remote state.
103
+ *
104
+ * @param op - The operation containing property changes. This can be an adjustment or a set of properties.
105
+ * @param seg - The segment containing properties. This object may have a properties map that will be modified.
106
+ * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.
107
+ * @returns The deltas of the rolled-back properties. This is a map-like object representing the changes that were reverted.
108
+ */
109
+ rollbackProperties(op, seg, collaborating = false) {
110
+ return applyChanges(op, seg, constants_js_1.UniversalSequenceNumber, (properties, deltas, key, value) => {
111
+ // eslint-disable-next-line unicorn/no-null
112
+ const previousValue = properties[key] ?? null;
113
+ const pending = this.changes.get(key);
114
+ if (collaborating) {
115
+ (0, internal_1.assert)(pending !== undefined, "Pending changes must exist for rollback when collaborating");
116
+ pending.local.pop();
117
+ properties[key] = computePropertyValue(pending.msnConsensus, pending.remote.map((n) => n.data), pending.local.map((n) => n.data));
118
+ if (pending.local.empty && pending.remote.empty) {
119
+ this.changes.delete(key);
57
120
  }
58
121
  }
59
- }
122
+ else {
123
+ (0, internal_1.assert)(pending === undefined, "Pending changes must not exist when not collaborating");
124
+ properties[key] = computePropertyValue(previousValue, [value]);
125
+ }
126
+ deltas[key] = previousValue;
127
+ });
60
128
  }
61
- addProperties(oldProps, newProps, seq, collaborating = false, rollback = PropertiesRollback.None) {
62
- this.pendingKeyUpdateCount ?? (this.pendingKeyUpdateCount = (0, properties_js_1.createMap)());
63
- // Clean up counts for rolled back edits before modifying oldProps
64
- if (collaborating && rollback === PropertiesRollback.Rollback) {
65
- this.decrementPendingCounts(newProps);
129
+ /**
130
+ * Handles property changes.
131
+ * This method applies property changes based on the provided operation, segment, sequence number, and collaboration state.
132
+ * It also handles rolling back changes if specified.
133
+ *
134
+ * @param op - The operation containing property changes.
135
+ * @param seg - The segment containing properties.
136
+ * @param seq - The sequence number for the operation.
137
+ * @param msn - The minimum sequence number for the operation.
138
+ * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.
139
+ * @param rollback - Specifies if the changes should be rolled back. Defaults to PropertiesRollback.None.
140
+ * @returns The deltas of the applied or rolled-back properties. This is a map-like object representing the changes.
141
+ */
142
+ handleProperties(op, seg, seq, msn, collaborating = false, rollback = PropertiesRollback.None) {
143
+ if (rollback === PropertiesRollback.Rollback) {
144
+ return this.rollbackProperties(op, seg, collaborating);
66
145
  }
67
- const shouldModifyKey = (key) => {
68
- if (seq === constants_js_1.UnassignedSequenceNumber ||
69
- seq === constants_js_1.UniversalSequenceNumber ||
70
- this.pendingKeyUpdateCount?.[key] === undefined) {
71
- return true;
72
- }
73
- return false;
74
- };
75
- const deltas = {};
76
- for (const [key, newValue] of Object.entries(newProps)) {
77
- if (newValue === undefined) {
78
- continue;
79
- }
146
+ const rtn = applyChanges(op, seg, seq, (properties, deltas, key, value) => {
147
+ // eslint-disable-next-line unicorn/no-null
148
+ const previousValue = properties[key] ?? null;
80
149
  if (collaborating) {
81
- if (seq === constants_js_1.UnassignedSequenceNumber) {
82
- if (this.pendingKeyUpdateCount?.[key] === undefined) {
83
- this.pendingKeyUpdateCount[key] = 0;
150
+ const pending = this.changes.get(key) ?? {
151
+ msnConsensus: previousValue,
152
+ remote: new index_js_1.DoublyLinkedList(),
153
+ local: new index_js_1.DoublyLinkedList(),
154
+ };
155
+ this.changes.set(key, pending);
156
+ const local = seq === constants_js_1.UnassignedSequenceNumber;
157
+ if (local) {
158
+ pending.local.push(value);
159
+ }
160
+ else {
161
+ // we only track remotes if there are adjusts, as only adjusts make application anti-commutative
162
+ // this will limit the impact of this change to only those using adjusts. Additionally, we only
163
+ // need to track remotes at all to support emitting the legacy snapshot format, which only sharedstring
164
+ // uses. when we remove the ability to emit that format, we can remove all remote op tracking
165
+ if (value.raw !== undefined && pending.remote.empty) {
166
+ pending.msnConsensus = computePropertyValue(pending.msnConsensus, [value]);
167
+ }
168
+ else {
169
+ pending.remote.push(value);
84
170
  }
85
- this.pendingKeyUpdateCount[key]++;
86
171
  }
87
- else if (!shouldModifyKey(key)) {
88
- continue;
172
+ properties[key] = computePropertyValue(pending.msnConsensus, pending.remote.map((n) => n.data), pending.local.map((n) => n.data));
173
+ if (local || pending.local.empty || properties[key] !== previousValue) {
174
+ deltas[key] = previousValue;
89
175
  }
90
176
  }
91
- const previousValue = oldProps[key];
92
- // The delta should be null if undefined, as that's how we encode delete
93
- // eslint-disable-next-line unicorn/no-null
94
- deltas[key] = previousValue === undefined ? null : previousValue;
95
- if (newValue === null) {
96
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
97
- delete oldProps[key];
177
+ else {
178
+ properties[key] = computePropertyValue(previousValue, [value]);
179
+ deltas[key] = previousValue;
180
+ }
181
+ });
182
+ this.updateMsn(msn);
183
+ return rtn;
184
+ }
185
+ /**
186
+ * Acknowledges property changes.
187
+ * This method acknowledges the property changes based on the provided sequence number and operation.
188
+ *
189
+ * @param seq - The sequence number for the operation.
190
+ * @param msn - The minimum sequence number for the operation.
191
+ * @param op - The operation containing property changes.
192
+ */
193
+ ack(seq, msn, op) {
194
+ for (const [key, value] of opToChanges(op, seq)) {
195
+ const change = this.changes.get(key);
196
+ const acked = change?.local?.shift();
197
+ (0, internal_1.assert)(change !== undefined && acked !== undefined, "must have local change to ack");
198
+ // we only track remotes if there are adjusts, as only adjusts make application anti-commutative
199
+ // this will limit the impact of this change to only those using adjusts. Additionally, we only
200
+ // need to track remotes at all to support emitting the legacy snapshot format, which only sharedstring
201
+ // uses. when we remove the ability to emit that format, we can remove all remote op tracking
202
+ if (value.raw !== undefined && change.remote.empty) {
203
+ change.msnConsensus = computePropertyValue(change.msnConsensus, [value]);
98
204
  }
99
205
  else {
100
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
101
- oldProps[key] = newValue;
206
+ change.remote.push(value);
102
207
  }
103
208
  }
104
- return deltas;
209
+ this.updateMsn(msn);
105
210
  }
106
- copyTo(oldProps, newProps, newManager) {
107
- if (oldProps) {
108
- // eslint-disable-next-line no-param-reassign
109
- newProps ?? (newProps = (0, properties_js_1.createMap)());
110
- if (!newManager) {
111
- throw new Error("Must provide new PropertyManager");
211
+ /**
212
+ * Updates the minimum sequence number (msn).
213
+ * This method updates the minimum sequence number and removes any changes that have been acknowledged.
214
+ *
215
+ * @param msn - The minimum sequence number to update.
216
+ */
217
+ updateMsn(msn) {
218
+ for (const [key, pending] of this.changes) {
219
+ pending.msnConsensus = computePropertyValue(pending.msnConsensus, (0, index_js_1.iterateListValuesWhile)(pending.remote.first, (n) => {
220
+ if (n.data.seq <= msn) {
221
+ n.list?.remove(n);
222
+ return true;
223
+ }
224
+ return false;
225
+ }));
226
+ if (pending.local.empty && pending.remote.empty) {
227
+ this.changes.delete(key);
112
228
  }
113
- (0, properties_js_1.extend)(newProps, oldProps);
114
- if (this.pendingKeyUpdateCount) {
115
- newManager.pendingKeyUpdateCount = (0, properties_js_1.clone)(this.pendingKeyUpdateCount);
229
+ }
230
+ }
231
+ /**
232
+ * Copies properties to another manager.
233
+ * This method copies the properties and their changes from the current manager to the destination manager.
234
+ *
235
+ * @param oldProps - The old properties to be copied.
236
+ * @param dest - The destination object containing properties and property manager.
237
+ */
238
+ copyTo(oldProps, dest) {
239
+ const newManager = (dest.propertyManager ?? (dest.propertyManager = new PropertiesManager()));
240
+ dest.properties = (0, properties_js_1.clone)(oldProps);
241
+ for (const [key, { local, remote, msnConsensus }] of this.changes.entries()) {
242
+ newManager.changes.set(key, {
243
+ msnConsensus,
244
+ remote: new index_js_1.DoublyLinkedList(remote.empty ? undefined : remote.map((c) => c.data)),
245
+ local: new index_js_1.DoublyLinkedList(local.empty ? undefined : local.map((c) => c.data)),
246
+ });
247
+ }
248
+ }
249
+ /**
250
+ * Gets properties at a specific sequence number.
251
+ * This method retrieves the properties at the given sequence number.
252
+ * This is only needed to support emitting snapshots in the legacy format.
253
+ * If we remove the ability to emit the legacy format, we can remove this method, along with the need to track remote changes at all.
254
+ *
255
+ * @param oldProps - The old properties to be retrieved.
256
+ * @param sequenceNumber - The sequence number to get properties at.
257
+ * @returns The properties at the given sequence number.
258
+ */
259
+ getAtSeq(oldProps, sequenceNumber) {
260
+ const properties = { ...oldProps };
261
+ for (const [key, changes] of this.changes) {
262
+ properties[key] = computePropertyValue(changes.msnConsensus, (0, index_js_1.iterateListValuesWhile)(changes.remote.first, (c) => c.data.seq <= sequenceNumber));
263
+ if (properties[key] === null) {
264
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
265
+ delete properties[key];
116
266
  }
117
267
  }
118
- return newProps;
268
+ return properties;
119
269
  }
120
270
  /**
121
271
  * Determines if all of the defined properties in a given property set are pending.
272
+ *
273
+ * @param props - The properties to check.
274
+ * @returns True if all the properties are pending, false otherwise.
122
275
  */
123
276
  hasPendingProperties(props) {
124
277
  for (const [key, value] of Object.entries(props)) {
125
- if (value !== undefined && this.pendingKeyUpdateCount?.[key] === undefined) {
278
+ if (value !== undefined && this.changes.get(key)?.local.empty !== false) {
126
279
  return false;
127
280
  }
128
281
  }
129
282
  return true;
130
283
  }
131
- hasPendingProperty(key) {
132
- return (this.pendingKeyUpdateCount?.[key] ?? 0) > 0;
133
- }
134
284
  }
135
285
  exports.PropertiesManager = PropertiesManager;
136
286
  //# sourceMappingURL=segmentPropertiesManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"segmentPropertiesManager.js","sourceRoot":"","sources":["../src/segmentPropertiesManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6DAA6D;AAE7D,kEAA6D;AAE7D,iDAAmF;AAEnF,mDAAiF;AAEjF;;GAEG;AACH,IAAY,kBAUX;AAVD,WAAY,kBAAkB;IAC7B;;OAEG;IACH,2DAAI,CAAA;IAEJ;;OAEG;IACH,mEAAQ,CAAA;AACT,CAAC,EAVW,kBAAkB,kCAAlB,kBAAkB,QAU7B;AAED;;;GAGG;AACH,SAAgB,wBAAwB,CACvC,MAGC,EACD,WAGC;IAED,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YAC1C,WAAW,CAAC,UAAU,GAAG,IAAA,qBAAK,EAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACP,WAAW,CAAC,eAAe,KAA3B,WAAW,CAAC,eAAe,GAAK,IAAI,iBAAiB,EAAE,EAAC;YACxD,WAAW,CAAC,UAAU,GAAG,MAAM,CAAC,eAAe,CAAC,MAAM,CACrD,MAAM,CAAC,UAAU,EACjB,WAAW,CAAC,UAAU,EACtB,WAAW,CAAC,eAAe,CAC3B,CAAC;QACH,CAAC;IACF,CAAC;AACF,CAAC;AAtBD,4DAsBC;AAED;;GAEG;AACH,MAAa,iBAAiB;IAGtB,oBAAoB,CAAC,UAAiC;QAC5D,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAEO,sBAAsB,CAAC,KAAkB;QAChD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC5E,IAAA,iBAAM,EACL,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAE,GAAG,CAAC,EACpC,KAAK,CAAC,2DAA2D,CACjE,CAAC;gBACF,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7C,gEAAgE;oBAChE,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;gBACxC,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAEM,aAAa,CACnB,QAAqB,EACrB,QAAqB,EACrB,GAAY,EACZ,gBAAyB,KAAK,EAC9B,WAA+B,kBAAkB,CAAC,IAAI;QAEtD,IAAI,CAAC,qBAAqB,KAA1B,IAAI,CAAC,qBAAqB,GAAK,IAAA,yBAAS,GAAU,EAAC;QAEnD,kEAAkE;QAClE,IAAI,aAAa,IAAI,QAAQ,KAAK,kBAAkB,CAAC,QAAQ,EAAE,CAAC;YAC/D,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,eAAe,GAAG,CAAC,GAAW,EAAW,EAAE;YAChD,IACC,GAAG,KAAK,uCAAwB;gBAChC,GAAG,KAAK,sCAAuB;gBAC/B,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,KAAK,SAAS,EAC9C,CAAC;gBACF,OAAO,IAAI,CAAC;YACb,CAAC;YACD,OAAO,KAAK,CAAC;QACd,CAAC,CAAC;QAEF,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC5B,SAAS;YACV,CAAC;YAED,IAAI,aAAa,EAAE,CAAC;gBACnB,IAAI,GAAG,KAAK,uCAAwB,EAAE,CAAC;oBACtC,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;wBACrD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACrC,CAAC;oBACD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,CAAC;qBAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClC,SAAS;gBACV,CAAC;YACF,CAAC;YAED,MAAM,aAAa,GAAY,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC7C,wEAAwE;YACxE,2CAA2C;YAC3C,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC;YACjE,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACvB,gEAAgE;gBAChE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACP,mEAAmE;gBACnE,QAAQ,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;YAC1B,CAAC;QACF,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,MAAM,CACZ,QAAqB,EACrB,QAAiC,EACjC,UAA6B;QAE7B,IAAI,QAAQ,EAAE,CAAC;YACd,6CAA6C;YAC7C,QAAQ,KAAR,QAAQ,GAAK,IAAA,yBAAS,GAAW,EAAC;YAClC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACrD,CAAC;YACD,IAAA,sBAAM,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAE3B,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAChC,UAAU,CAAC,qBAAqB,GAAG,IAAA,qBAAK,EAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YACtE,CAAC;QACF,CAAC;QACD,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED;;OAEG;IACI,oBAAoB,CAAC,KAAkB;QAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC5E,OAAO,KAAK,CAAC;YACd,CAAC;QACF,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,kBAAkB,CAAC,GAAW;QACpC,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;CACD;AArHD,8CAqHC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { UnassignedSequenceNumber, UniversalSequenceNumber } from \"./constants.js\";\nimport { IMergeTreeAnnotateMsg } from \"./ops.js\";\nimport { MapLike, PropertySet, clone, createMap, extend } from \"./properties.js\";\n\n/**\n * @internal\n */\nexport enum PropertiesRollback {\n\t/**\n\t * Not in a rollback\n\t */\n\tNone,\n\n\t/**\n\t * Rollback\n\t */\n\tRollback,\n}\n\n/**\n * Minimally copies properties and the property manager from source to destination.\n * @internal\n */\nexport function copyPropertiesAndManager(\n\tsource: {\n\t\tproperties?: PropertySet;\n\t\tpropertyManager?: PropertiesManager;\n\t},\n\tdestination: {\n\t\tproperties?: PropertySet;\n\t\tpropertyManager?: PropertiesManager;\n\t},\n): void {\n\tif (source.properties) {\n\t\tif (source.propertyManager === undefined) {\n\t\t\tdestination.properties = clone(source.properties);\n\t\t} else {\n\t\t\tdestination.propertyManager ??= new PropertiesManager();\n\t\t\tdestination.properties = source.propertyManager.copyTo(\n\t\t\t\tsource.properties,\n\t\t\t\tdestination.properties,\n\t\t\t\tdestination.propertyManager,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * @internal\n */\nexport class PropertiesManager {\n\tprivate pendingKeyUpdateCount: MapLike<number> | undefined;\n\n\tpublic ackPendingProperties(annotateOp: IMergeTreeAnnotateMsg): void {\n\t\tthis.decrementPendingCounts(annotateOp.props);\n\t}\n\n\tprivate decrementPendingCounts(props: PropertySet): void {\n\t\tfor (const [key, value] of Object.entries(props)) {\n\t\t\tif (value !== undefined && this.pendingKeyUpdateCount?.[key] !== undefined) {\n\t\t\t\tassert(\n\t\t\t\t\tthis.pendingKeyUpdateCount[key]! > 0,\n\t\t\t\t\t0x05c /* \"Trying to update more annotate props than do exist!\" */,\n\t\t\t\t);\n\t\t\t\tthis.pendingKeyUpdateCount[key]--;\n\t\t\t\tif (this.pendingKeyUpdateCount?.[key] === 0) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\t\tdelete this.pendingKeyUpdateCount[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic addProperties(\n\t\toldProps: PropertySet,\n\t\tnewProps: PropertySet,\n\t\tseq?: number,\n\t\tcollaborating: boolean = false,\n\t\trollback: PropertiesRollback = PropertiesRollback.None,\n\t): PropertySet {\n\t\tthis.pendingKeyUpdateCount ??= createMap<number>();\n\n\t\t// Clean up counts for rolled back edits before modifying oldProps\n\t\tif (collaborating && rollback === PropertiesRollback.Rollback) {\n\t\t\tthis.decrementPendingCounts(newProps);\n\t\t}\n\n\t\tconst shouldModifyKey = (key: string): boolean => {\n\t\t\tif (\n\t\t\t\tseq === UnassignedSequenceNumber ||\n\t\t\t\tseq === UniversalSequenceNumber ||\n\t\t\t\tthis.pendingKeyUpdateCount?.[key] === undefined\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\tconst deltas: PropertySet = {};\n\n\t\tfor (const [key, newValue] of Object.entries(newProps)) {\n\t\t\tif (newValue === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (collaborating) {\n\t\t\t\tif (seq === UnassignedSequenceNumber) {\n\t\t\t\t\tif (this.pendingKeyUpdateCount?.[key] === undefined) {\n\t\t\t\t\t\tthis.pendingKeyUpdateCount[key] = 0;\n\t\t\t\t\t}\n\t\t\t\t\tthis.pendingKeyUpdateCount[key]++;\n\t\t\t\t} else if (!shouldModifyKey(key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst previousValue: unknown = oldProps[key];\n\t\t\t// The delta should be null if undefined, as that's how we encode delete\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tdeltas[key] = previousValue === undefined ? null : previousValue;\n\t\t\tif (newValue === null) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\tdelete oldProps[key];\n\t\t\t} else {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\toldProps[key] = newValue;\n\t\t\t}\n\t\t}\n\n\t\treturn deltas;\n\t}\n\n\tpublic copyTo(\n\t\toldProps: PropertySet,\n\t\tnewProps: PropertySet | undefined,\n\t\tnewManager: PropertiesManager,\n\t): PropertySet | undefined {\n\t\tif (oldProps) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\tnewProps ??= createMap<unknown>();\n\t\t\tif (!newManager) {\n\t\t\t\tthrow new Error(\"Must provide new PropertyManager\");\n\t\t\t}\n\t\t\textend(newProps, oldProps);\n\n\t\t\tif (this.pendingKeyUpdateCount) {\n\t\t\t\tnewManager.pendingKeyUpdateCount = clone(this.pendingKeyUpdateCount);\n\t\t\t}\n\t\t}\n\t\treturn newProps;\n\t}\n\n\t/**\n\t * Determines if all of the defined properties in a given property set are pending.\n\t */\n\tpublic hasPendingProperties(props: PropertySet): boolean {\n\t\tfor (const [key, value] of Object.entries(props)) {\n\t\t\tif (value !== undefined && this.pendingKeyUpdateCount?.[key] === undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic hasPendingProperty(key: string): boolean {\n\t\treturn (this.pendingKeyUpdateCount?.[key] ?? 0) > 0;\n\t}\n}\n"]}
1
+ {"version":3,"file":"segmentPropertiesManager.js","sourceRoot":"","sources":["../src/segmentPropertiesManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { DoublyLinkedList, iterateListValuesWhile } from \"./collections/index.js\";\nimport { UnassignedSequenceNumber, UniversalSequenceNumber } from \"./constants.js\";\nimport type {\n\tAdjustParams,\n\tIMergeTreeAnnotateAdjustMsg,\n\tIMergeTreeAnnotateMsg,\n} from \"./ops.js\";\nimport { MapLike, PropertySet, clone, createMap } from \"./properties.js\";\n\n/**\n * @internal\n */\nexport enum PropertiesRollback {\n\t/**\n\t * Not in a rollback\n\t */\n\tNone,\n\n\t/**\n\t * Rollback\n\t */\n\tRollback,\n}\n/**\n * Minimally copies properties and the property manager from source to destination.\n * @internal\n */\nexport function copyPropertiesAndManager(\n\tsource: {\n\t\tproperties?: PropertySet;\n\t\tpropertyManager?: PropertiesManager;\n\t},\n\tdestination: {\n\t\tproperties?: PropertySet;\n\t\tpropertyManager?: PropertiesManager;\n\t},\n): void {\n\tif (source.properties) {\n\t\tif (source.propertyManager === undefined) {\n\t\t\tdestination.properties = clone(source.properties);\n\t\t} else {\n\t\t\tdestination.propertyManager ??= new PropertiesManager();\n\t\t\tsource.propertyManager.copyTo(source.properties, destination);\n\t\t}\n\t}\n}\n\ntype PropertyChange = {\n\tseq: number;\n} & ({ adjust: AdjustParams; raw?: undefined } | { raw: unknown; adjust?: undefined });\n\ninterface PropertyChanges {\n\tmsnConsensus: unknown;\n\tremote: DoublyLinkedList<PropertyChange>;\n\tlocal: DoublyLinkedList<PropertyChange>;\n}\n\nfunction computePropertyValue(\n\tconsensus: unknown,\n\t...changes: Iterable<PropertyChange>[]\n): unknown {\n\tlet computedValue: unknown = consensus;\n\tfor (const change of changes) {\n\t\tfor (const op of change) {\n\t\t\tconst { raw, adjust } = op;\n\t\t\tif (adjust === undefined) {\n\t\t\t\tcomputedValue = raw;\n\t\t\t} else {\n\t\t\t\tconst adjusted =\n\t\t\t\t\t(typeof computedValue === \"number\" ? computedValue : 0) + adjust.delta;\n\t\t\t\tif (adjust.max !== undefined && adjusted > adjust.max) {\n\t\t\t\t\tcomputedValue = adjust.max;\n\t\t\t\t} else if (adjust.min !== undefined && adjusted < adjust.min) {\n\t\t\t\t\tcomputedValue = adjust.min;\n\t\t\t\t} else {\n\t\t\t\t\tcomputedValue = adjusted;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn computedValue;\n}\n\n/**\n * @internal\n */\nexport type PropsOrAdjust =\n\t| Pick<IMergeTreeAnnotateAdjustMsg, \"props\" | \"adjust\">\n\t| Pick<IMergeTreeAnnotateMsg, \"props\" | \"adjust\">;\n\nconst opToChanges = (op: PropsOrAdjust, seq: number): [string, PropertyChange][] => [\n\t...Object.entries(op.props ?? {})\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t.map<[string, PropertyChange]>(([k, raw]) => [k, { raw, seq }])\n\t\t.filter(([_, v]) => v.raw !== undefined),\n\t...Object.entries(op.adjust ?? {}).map<[string, PropertyChange]>(([k, adjust]) => [\n\t\tk,\n\t\t{ adjust, seq },\n\t]),\n];\n\nfunction applyChanges(\n\top: PropsOrAdjust,\n\tseg: { properties?: MapLike<unknown> },\n\tseq: number,\n\trun: (\n\t\tproperties: MapLike<unknown>,\n\t\tdeltas: MapLike<unknown>,\n\t\tkey: string,\n\t\tvalue: PropertyChange,\n\t) => void,\n): MapLike<unknown> {\n\tconst properties = (seg.properties ??= createMap<unknown>());\n\tconst deltas: MapLike<unknown> = {};\n\tfor (const [key, value] of opToChanges(op, seq)) {\n\t\trun(properties, deltas, key, value);\n\t\tif (properties[key] === null) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\tdelete properties[key];\n\t\t}\n\t}\n\treturn deltas;\n}\n\n/**\n * The PropertiesManager class handles changes to properties, both remote and local.\n * It manages the lifecycle for local property changes, ensures all property changes are eventually consistent,\n * and provides methods to acknowledge changes, update the minimum sequence number (msn), and copy properties to another manager.\n * This class is essential for maintaining the integrity and consistency of property changes in collaborative environments.\n * @internal\n */\nexport class PropertiesManager {\n\tprivate readonly changes = new Map<string, PropertyChanges>();\n\n\t/**\n\t * Rolls back local property changes.\n\t * This method reverts property changes based on the provided operation and segment.\n\t * If the operation is part of a collaborative session, it ensures that the changes are consistent with the remote state.\n\t *\n\t * @param op - The operation containing property changes. This can be an adjustment or a set of properties.\n\t * @param seg - The segment containing properties. This object may have a properties map that will be modified.\n\t * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.\n\t * @returns The deltas of the rolled-back properties. This is a map-like object representing the changes that were reverted.\n\t */\n\tpublic rollbackProperties(\n\t\top: PropsOrAdjust,\n\t\tseg: { properties?: MapLike<unknown> },\n\t\tcollaborating: boolean = false,\n\t): MapLike<unknown> {\n\t\treturn applyChanges(op, seg, UniversalSequenceNumber, (properties, deltas, key, value) => {\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst previousValue = properties[key] ?? null;\n\n\t\t\tconst pending = this.changes.get(key);\n\t\t\tif (collaborating) {\n\t\t\t\tassert(\n\t\t\t\t\tpending !== undefined,\n\t\t\t\t\t\"Pending changes must exist for rollback when collaborating\",\n\t\t\t\t);\n\t\t\t\tpending.local.pop();\n\t\t\t\tproperties[key] = computePropertyValue(\n\t\t\t\t\tpending.msnConsensus,\n\t\t\t\t\tpending.remote.map((n) => n.data),\n\t\t\t\t\tpending.local.map((n) => n.data),\n\t\t\t\t);\n\t\t\t\tif (pending.local.empty && pending.remote.empty) {\n\t\t\t\t\tthis.changes.delete(key);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert(pending === undefined, \"Pending changes must not exist when not collaborating\");\n\t\t\t\tproperties[key] = computePropertyValue(previousValue, [value]);\n\t\t\t}\n\t\t\tdeltas[key] = previousValue;\n\t\t});\n\t}\n\n\t/**\n\t * Handles property changes.\n\t * This method applies property changes based on the provided operation, segment, sequence number, and collaboration state.\n\t * It also handles rolling back changes if specified.\n\t *\n\t * @param op - The operation containing property changes.\n\t * @param seg - The segment containing properties.\n\t * @param seq - The sequence number for the operation.\n\t * @param msn - The minimum sequence number for the operation.\n\t * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.\n\t * @param rollback - Specifies if the changes should be rolled back. Defaults to PropertiesRollback.None.\n\t * @returns The deltas of the applied or rolled-back properties. This is a map-like object representing the changes.\n\t */\n\tpublic handleProperties(\n\t\top: PropsOrAdjust,\n\t\tseg: { properties?: MapLike<unknown> },\n\t\tseq: number,\n\t\tmsn: number,\n\t\tcollaborating: boolean = false,\n\t\trollback: PropertiesRollback = PropertiesRollback.None,\n\t): MapLike<unknown> {\n\t\tif (rollback === PropertiesRollback.Rollback) {\n\t\t\treturn this.rollbackProperties(op, seg, collaborating);\n\t\t}\n\t\tconst rtn = applyChanges(op, seg, seq, (properties, deltas, key, value) => {\n\t\t\t// eslint-disable-next-line unicorn/no-null\n\t\t\tconst previousValue = properties[key] ?? null;\n\t\t\tif (collaborating) {\n\t\t\t\tconst pending: PropertyChanges | undefined = this.changes.get(key) ?? {\n\t\t\t\t\tmsnConsensus: previousValue,\n\t\t\t\t\tremote: new DoublyLinkedList(),\n\t\t\t\t\tlocal: new DoublyLinkedList(),\n\t\t\t\t};\n\t\t\t\tthis.changes.set(key, pending);\n\t\t\t\tconst local = seq === UnassignedSequenceNumber;\n\t\t\t\tif (local) {\n\t\t\t\t\tpending.local.push(value);\n\t\t\t\t} else {\n\t\t\t\t\t// we only track remotes if there are adjusts, as only adjusts make application anti-commutative\n\t\t\t\t\t// this will limit the impact of this change to only those using adjusts. Additionally, we only\n\t\t\t\t\t// need to track remotes at all to support emitting the legacy snapshot format, which only sharedstring\n\t\t\t\t\t// uses. when we remove the ability to emit that format, we can remove all remote op tracking\n\t\t\t\t\tif (value.raw !== undefined && pending.remote.empty) {\n\t\t\t\t\t\tpending.msnConsensus = computePropertyValue(pending.msnConsensus, [value]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpending.remote.push(value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tproperties[key] = computePropertyValue(\n\t\t\t\t\tpending.msnConsensus,\n\t\t\t\t\tpending.remote.map((n) => n.data),\n\t\t\t\t\tpending.local.map((n) => n.data),\n\t\t\t\t);\n\t\t\t\tif (local || pending.local.empty || properties[key] !== previousValue) {\n\t\t\t\t\tdeltas[key] = previousValue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tproperties[key] = computePropertyValue(previousValue, [value]);\n\t\t\t\tdeltas[key] = previousValue;\n\t\t\t}\n\t\t});\n\t\tthis.updateMsn(msn);\n\t\treturn rtn;\n\t}\n\n\t/**\n\t * Acknowledges property changes.\n\t * This method acknowledges the property changes based on the provided sequence number and operation.\n\t *\n\t * @param seq - The sequence number for the operation.\n\t * @param msn - The minimum sequence number for the operation.\n\t * @param op - The operation containing property changes.\n\t */\n\tpublic ack(seq: number, msn: number, op: PropsOrAdjust): void {\n\t\tfor (const [key, value] of opToChanges(op, seq)) {\n\t\t\tconst change = this.changes.get(key);\n\t\t\tconst acked = change?.local?.shift();\n\t\t\tassert(change !== undefined && acked !== undefined, \"must have local change to ack\");\n\t\t\t// we only track remotes if there are adjusts, as only adjusts make application anti-commutative\n\t\t\t// this will limit the impact of this change to only those using adjusts. Additionally, we only\n\t\t\t// need to track remotes at all to support emitting the legacy snapshot format, which only sharedstring\n\t\t\t// uses. when we remove the ability to emit that format, we can remove all remote op tracking\n\t\t\tif (value.raw !== undefined && change.remote.empty) {\n\t\t\t\tchange.msnConsensus = computePropertyValue(change.msnConsensus, [value]);\n\t\t\t} else {\n\t\t\t\tchange.remote.push(value);\n\t\t\t}\n\t\t}\n\t\tthis.updateMsn(msn);\n\t}\n\n\t/**\n\t * Updates the minimum sequence number (msn).\n\t * This method updates the minimum sequence number and removes any changes that have been acknowledged.\n\t *\n\t * @param msn - The minimum sequence number to update.\n\t */\n\tpublic updateMsn(msn: number): void {\n\t\tfor (const [key, pending] of this.changes) {\n\t\t\tpending.msnConsensus = computePropertyValue(\n\t\t\t\tpending.msnConsensus,\n\t\t\t\titerateListValuesWhile(pending.remote.first, (n) => {\n\t\t\t\t\tif (n.data.seq <= msn) {\n\t\t\t\t\t\tn.list?.remove(n);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (pending.local.empty && pending.remote.empty) {\n\t\t\t\tthis.changes.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Copies properties to another manager.\n\t * This method copies the properties and their changes from the current manager to the destination manager.\n\t *\n\t * @param oldProps - The old properties to be copied.\n\t * @param dest - The destination object containing properties and property manager.\n\t */\n\tpublic copyTo(\n\t\toldProps: PropertySet | undefined,\n\t\tdest: {\n\t\t\tproperties?: PropertySet;\n\t\t\tpropertyManager?: PropertiesManager;\n\t\t},\n\t): void {\n\t\tconst newManager = (dest.propertyManager ??= new PropertiesManager());\n\t\tdest.properties = clone(oldProps);\n\t\tfor (const [key, { local, remote, msnConsensus }] of this.changes.entries()) {\n\t\t\tnewManager.changes.set(key, {\n\t\t\t\tmsnConsensus,\n\t\t\t\tremote: new DoublyLinkedList(remote.empty ? undefined : remote.map((c) => c.data)),\n\t\t\t\tlocal: new DoublyLinkedList(local.empty ? undefined : local.map((c) => c.data)),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Gets properties at a specific sequence number.\n\t * This method retrieves the properties at the given sequence number.\n\t * This is only needed to support emitting snapshots in the legacy format.\n\t * If we remove the ability to emit the legacy format, we can remove this method, along with the need to track remote changes at all.\n\t *\n\t * @param oldProps - The old properties to be retrieved.\n\t * @param sequenceNumber - The sequence number to get properties at.\n\t * @returns The properties at the given sequence number.\n\t */\n\tpublic getAtSeq(\n\t\toldProps: MapLike<unknown> | undefined,\n\t\tsequenceNumber: number,\n\t): MapLike<unknown> {\n\t\tconst properties: MapLike<unknown> = { ...oldProps };\n\t\tfor (const [key, changes] of this.changes) {\n\t\t\tproperties[key] = computePropertyValue(\n\t\t\t\tchanges.msnConsensus,\n\t\t\t\titerateListValuesWhile(changes.remote.first, (c) => c.data.seq <= sequenceNumber),\n\t\t\t);\n\t\t\tif (properties[key] === null) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\tdelete properties[key];\n\t\t\t}\n\t\t}\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Determines if all of the defined properties in a given property set are pending.\n\t *\n\t * @param props - The properties to check.\n\t * @returns True if all the properties are pending, false otherwise.\n\t */\n\tpublic hasPendingProperties(props: PropertySet): boolean {\n\t\tfor (const [key, value] of Object.entries(props)) {\n\t\t\tif (value !== undefined && this.changes.get(key)?.local.empty !== false) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=propertyManager.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propertyManager.spec.d.ts","sourceRoot":"","sources":["../../src/test/propertyManager.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}