@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/lib/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/lib/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/lib/ops.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ops.js","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,CAAN,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,KAAb,aAAa,QAsCxB;AAUD,mFAAmF;AACnF;;;GAGG;AACH,MAAM,CAAC,MAAM,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,MAAM,CAAN,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,KAAb,aAAa,QAsCxB;AAUD,mFAAmF;AACnF;;;GAGG;AACH,MAAM,CAAC,MAAM,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"}
@@ -2,10 +2,10 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
6
5
  import { assert } from "@fluidframework/core-utils/internal";
6
+ import { DoublyLinkedList, iterateListValuesWhile } from "./collections/index.js";
7
7
  import { UnassignedSequenceNumber, UniversalSequenceNumber } from "./constants.js";
8
- import { clone, createMap, extend } from "./properties.js";
8
+ import { clone, createMap } from "./properties.js";
9
9
  /**
10
10
  * @internal
11
11
  */
@@ -31,101 +31,251 @@ export function copyPropertiesAndManager(source, destination) {
31
31
  }
32
32
  else {
33
33
  destination.propertyManager ?? (destination.propertyManager = new PropertiesManager());
34
- destination.properties = source.propertyManager.copyTo(source.properties, destination.properties, destination.propertyManager);
34
+ source.propertyManager.copyTo(source.properties, destination);
35
35
  }
36
36
  }
37
37
  }
38
+ function computePropertyValue(consensus, ...changes) {
39
+ let computedValue = consensus;
40
+ for (const change of changes) {
41
+ for (const op of change) {
42
+ const { raw, adjust } = op;
43
+ if (adjust === undefined) {
44
+ computedValue = raw;
45
+ }
46
+ else {
47
+ const adjusted = (typeof computedValue === "number" ? computedValue : 0) + adjust.delta;
48
+ if (adjust.max !== undefined && adjusted > adjust.max) {
49
+ computedValue = adjust.max;
50
+ }
51
+ else if (adjust.min !== undefined && adjusted < adjust.min) {
52
+ computedValue = adjust.min;
53
+ }
54
+ else {
55
+ computedValue = adjusted;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ return computedValue;
61
+ }
62
+ const opToChanges = (op, seq) => [
63
+ ...Object.entries(op.props ?? {})
64
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
65
+ .map(([k, raw]) => [k, { raw, seq }])
66
+ .filter(([_, v]) => v.raw !== undefined),
67
+ ...Object.entries(op.adjust ?? {}).map(([k, adjust]) => [
68
+ k,
69
+ { adjust, seq },
70
+ ]),
71
+ ];
72
+ function applyChanges(op, seg, seq, run) {
73
+ const properties = (seg.properties ?? (seg.properties = createMap()));
74
+ const deltas = {};
75
+ for (const [key, value] of opToChanges(op, seq)) {
76
+ run(properties, deltas, key, value);
77
+ if (properties[key] === null) {
78
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
79
+ delete properties[key];
80
+ }
81
+ }
82
+ return deltas;
83
+ }
38
84
  /**
85
+ * The PropertiesManager class handles changes to properties, both remote and local.
86
+ * It manages the lifecycle for local property changes, ensures all property changes are eventually consistent,
87
+ * and provides methods to acknowledge changes, update the minimum sequence number (msn), and copy properties to another manager.
88
+ * This class is essential for maintaining the integrity and consistency of property changes in collaborative environments.
39
89
  * @internal
40
90
  */
41
91
  export class PropertiesManager {
42
- ackPendingProperties(annotateOp) {
43
- this.decrementPendingCounts(annotateOp.props);
92
+ constructor() {
93
+ this.changes = new Map();
44
94
  }
45
- decrementPendingCounts(props) {
46
- for (const [key, value] of Object.entries(props)) {
47
- if (value !== undefined && this.pendingKeyUpdateCount?.[key] !== undefined) {
48
- assert(this.pendingKeyUpdateCount[key] > 0, 0x05c /* "Trying to update more annotate props than do exist!" */);
49
- this.pendingKeyUpdateCount[key]--;
50
- if (this.pendingKeyUpdateCount?.[key] === 0) {
51
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
52
- delete this.pendingKeyUpdateCount[key];
95
+ /**
96
+ * Rolls back local property changes.
97
+ * This method reverts property changes based on the provided operation and segment.
98
+ * If the operation is part of a collaborative session, it ensures that the changes are consistent with the remote state.
99
+ *
100
+ * @param op - The operation containing property changes. This can be an adjustment or a set of properties.
101
+ * @param seg - The segment containing properties. This object may have a properties map that will be modified.
102
+ * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.
103
+ * @returns The deltas of the rolled-back properties. This is a map-like object representing the changes that were reverted.
104
+ */
105
+ rollbackProperties(op, seg, collaborating = false) {
106
+ return applyChanges(op, seg, UniversalSequenceNumber, (properties, deltas, key, value) => {
107
+ // eslint-disable-next-line unicorn/no-null
108
+ const previousValue = properties[key] ?? null;
109
+ const pending = this.changes.get(key);
110
+ if (collaborating) {
111
+ assert(pending !== undefined, "Pending changes must exist for rollback when collaborating");
112
+ pending.local.pop();
113
+ properties[key] = computePropertyValue(pending.msnConsensus, pending.remote.map((n) => n.data), pending.local.map((n) => n.data));
114
+ if (pending.local.empty && pending.remote.empty) {
115
+ this.changes.delete(key);
53
116
  }
54
117
  }
55
- }
118
+ else {
119
+ assert(pending === undefined, "Pending changes must not exist when not collaborating");
120
+ properties[key] = computePropertyValue(previousValue, [value]);
121
+ }
122
+ deltas[key] = previousValue;
123
+ });
56
124
  }
57
- addProperties(oldProps, newProps, seq, collaborating = false, rollback = PropertiesRollback.None) {
58
- this.pendingKeyUpdateCount ?? (this.pendingKeyUpdateCount = createMap());
59
- // Clean up counts for rolled back edits before modifying oldProps
60
- if (collaborating && rollback === PropertiesRollback.Rollback) {
61
- this.decrementPendingCounts(newProps);
125
+ /**
126
+ * Handles property changes.
127
+ * This method applies property changes based on the provided operation, segment, sequence number, and collaboration state.
128
+ * It also handles rolling back changes if specified.
129
+ *
130
+ * @param op - The operation containing property changes.
131
+ * @param seg - The segment containing properties.
132
+ * @param seq - The sequence number for the operation.
133
+ * @param msn - The minimum sequence number for the operation.
134
+ * @param collaborating - Indicates if the operation is part of a collaborative session. Defaults to false.
135
+ * @param rollback - Specifies if the changes should be rolled back. Defaults to PropertiesRollback.None.
136
+ * @returns The deltas of the applied or rolled-back properties. This is a map-like object representing the changes.
137
+ */
138
+ handleProperties(op, seg, seq, msn, collaborating = false, rollback = PropertiesRollback.None) {
139
+ if (rollback === PropertiesRollback.Rollback) {
140
+ return this.rollbackProperties(op, seg, collaborating);
62
141
  }
63
- const shouldModifyKey = (key) => {
64
- if (seq === UnassignedSequenceNumber ||
65
- seq === UniversalSequenceNumber ||
66
- this.pendingKeyUpdateCount?.[key] === undefined) {
67
- return true;
68
- }
69
- return false;
70
- };
71
- const deltas = {};
72
- for (const [key, newValue] of Object.entries(newProps)) {
73
- if (newValue === undefined) {
74
- continue;
75
- }
142
+ const rtn = applyChanges(op, seg, seq, (properties, deltas, key, value) => {
143
+ // eslint-disable-next-line unicorn/no-null
144
+ const previousValue = properties[key] ?? null;
76
145
  if (collaborating) {
77
- if (seq === UnassignedSequenceNumber) {
78
- if (this.pendingKeyUpdateCount?.[key] === undefined) {
79
- this.pendingKeyUpdateCount[key] = 0;
146
+ const pending = this.changes.get(key) ?? {
147
+ msnConsensus: previousValue,
148
+ remote: new DoublyLinkedList(),
149
+ local: new DoublyLinkedList(),
150
+ };
151
+ this.changes.set(key, pending);
152
+ const local = seq === UnassignedSequenceNumber;
153
+ if (local) {
154
+ pending.local.push(value);
155
+ }
156
+ else {
157
+ // we only track remotes if there are adjusts, as only adjusts make application anti-commutative
158
+ // this will limit the impact of this change to only those using adjusts. Additionally, we only
159
+ // need to track remotes at all to support emitting the legacy snapshot format, which only sharedstring
160
+ // uses. when we remove the ability to emit that format, we can remove all remote op tracking
161
+ if (value.raw !== undefined && pending.remote.empty) {
162
+ pending.msnConsensus = computePropertyValue(pending.msnConsensus, [value]);
163
+ }
164
+ else {
165
+ pending.remote.push(value);
80
166
  }
81
- this.pendingKeyUpdateCount[key]++;
82
167
  }
83
- else if (!shouldModifyKey(key)) {
84
- continue;
168
+ properties[key] = computePropertyValue(pending.msnConsensus, pending.remote.map((n) => n.data), pending.local.map((n) => n.data));
169
+ if (local || pending.local.empty || properties[key] !== previousValue) {
170
+ deltas[key] = previousValue;
85
171
  }
86
172
  }
87
- const previousValue = oldProps[key];
88
- // The delta should be null if undefined, as that's how we encode delete
89
- // eslint-disable-next-line unicorn/no-null
90
- deltas[key] = previousValue === undefined ? null : previousValue;
91
- if (newValue === null) {
92
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
93
- delete oldProps[key];
173
+ else {
174
+ properties[key] = computePropertyValue(previousValue, [value]);
175
+ deltas[key] = previousValue;
176
+ }
177
+ });
178
+ this.updateMsn(msn);
179
+ return rtn;
180
+ }
181
+ /**
182
+ * Acknowledges property changes.
183
+ * This method acknowledges the property changes based on the provided sequence number and operation.
184
+ *
185
+ * @param seq - The sequence number for the operation.
186
+ * @param msn - The minimum sequence number for the operation.
187
+ * @param op - The operation containing property changes.
188
+ */
189
+ ack(seq, msn, op) {
190
+ for (const [key, value] of opToChanges(op, seq)) {
191
+ const change = this.changes.get(key);
192
+ const acked = change?.local?.shift();
193
+ assert(change !== undefined && acked !== undefined, "must have local change to ack");
194
+ // we only track remotes if there are adjusts, as only adjusts make application anti-commutative
195
+ // this will limit the impact of this change to only those using adjusts. Additionally, we only
196
+ // need to track remotes at all to support emitting the legacy snapshot format, which only sharedstring
197
+ // uses. when we remove the ability to emit that format, we can remove all remote op tracking
198
+ if (value.raw !== undefined && change.remote.empty) {
199
+ change.msnConsensus = computePropertyValue(change.msnConsensus, [value]);
94
200
  }
95
201
  else {
96
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
97
- oldProps[key] = newValue;
202
+ change.remote.push(value);
98
203
  }
99
204
  }
100
- return deltas;
205
+ this.updateMsn(msn);
101
206
  }
102
- copyTo(oldProps, newProps, newManager) {
103
- if (oldProps) {
104
- // eslint-disable-next-line no-param-reassign
105
- newProps ?? (newProps = createMap());
106
- if (!newManager) {
107
- throw new Error("Must provide new PropertyManager");
207
+ /**
208
+ * Updates the minimum sequence number (msn).
209
+ * This method updates the minimum sequence number and removes any changes that have been acknowledged.
210
+ *
211
+ * @param msn - The minimum sequence number to update.
212
+ */
213
+ updateMsn(msn) {
214
+ for (const [key, pending] of this.changes) {
215
+ pending.msnConsensus = computePropertyValue(pending.msnConsensus, iterateListValuesWhile(pending.remote.first, (n) => {
216
+ if (n.data.seq <= msn) {
217
+ n.list?.remove(n);
218
+ return true;
219
+ }
220
+ return false;
221
+ }));
222
+ if (pending.local.empty && pending.remote.empty) {
223
+ this.changes.delete(key);
108
224
  }
109
- extend(newProps, oldProps);
110
- if (this.pendingKeyUpdateCount) {
111
- newManager.pendingKeyUpdateCount = clone(this.pendingKeyUpdateCount);
225
+ }
226
+ }
227
+ /**
228
+ * Copies properties to another manager.
229
+ * This method copies the properties and their changes from the current manager to the destination manager.
230
+ *
231
+ * @param oldProps - The old properties to be copied.
232
+ * @param dest - The destination object containing properties and property manager.
233
+ */
234
+ copyTo(oldProps, dest) {
235
+ const newManager = (dest.propertyManager ?? (dest.propertyManager = new PropertiesManager()));
236
+ dest.properties = clone(oldProps);
237
+ for (const [key, { local, remote, msnConsensus }] of this.changes.entries()) {
238
+ newManager.changes.set(key, {
239
+ msnConsensus,
240
+ remote: new DoublyLinkedList(remote.empty ? undefined : remote.map((c) => c.data)),
241
+ local: new DoublyLinkedList(local.empty ? undefined : local.map((c) => c.data)),
242
+ });
243
+ }
244
+ }
245
+ /**
246
+ * Gets properties at a specific sequence number.
247
+ * This method retrieves the properties at the given sequence number.
248
+ * This is only needed to support emitting snapshots in the legacy format.
249
+ * 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.
250
+ *
251
+ * @param oldProps - The old properties to be retrieved.
252
+ * @param sequenceNumber - The sequence number to get properties at.
253
+ * @returns The properties at the given sequence number.
254
+ */
255
+ getAtSeq(oldProps, sequenceNumber) {
256
+ const properties = { ...oldProps };
257
+ for (const [key, changes] of this.changes) {
258
+ properties[key] = computePropertyValue(changes.msnConsensus, iterateListValuesWhile(changes.remote.first, (c) => c.data.seq <= sequenceNumber));
259
+ if (properties[key] === null) {
260
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
261
+ delete properties[key];
112
262
  }
113
263
  }
114
- return newProps;
264
+ return properties;
115
265
  }
116
266
  /**
117
267
  * Determines if all of the defined properties in a given property set are pending.
268
+ *
269
+ * @param props - The properties to check.
270
+ * @returns True if all the properties are pending, false otherwise.
118
271
  */
119
272
  hasPendingProperties(props) {
120
273
  for (const [key, value] of Object.entries(props)) {
121
- if (value !== undefined && this.pendingKeyUpdateCount?.[key] === undefined) {
274
+ if (value !== undefined && this.changes.get(key)?.local.empty !== false) {
122
275
  return false;
123
276
  }
124
277
  }
125
278
  return true;
126
279
  }
127
- hasPendingProperty(key) {
128
- return (this.pendingKeyUpdateCount?.[key] ?? 0) > 0;
129
- }
130
280
  }
131
281
  //# sourceMappingURL=segmentPropertiesManager.js.map
@@ -1 +1 @@
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\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"}