@fluidframework/merge-tree 2.0.0-rc.3.0.3 → 2.0.0-rc.4.0.0

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 (106) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/merge-tree.api.md +4 -8
  3. package/dist/client.d.ts +1 -1
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +8 -3
  6. package/dist/client.js.map +1 -1
  7. package/dist/legacy.d.ts +3 -1
  8. package/dist/mergeTree.d.ts +0 -1
  9. package/dist/mergeTree.d.ts.map +1 -1
  10. package/dist/mergeTree.js +40 -55
  11. package/dist/mergeTree.js.map +1 -1
  12. package/dist/mergeTreeDeltaCallback.d.ts +29 -3
  13. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  14. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  15. package/dist/mergeTreeNodes.d.ts +12 -7
  16. package/dist/mergeTreeNodes.d.ts.map +1 -1
  17. package/dist/mergeTreeNodes.js +6 -18
  18. package/dist/mergeTreeNodes.js.map +1 -1
  19. package/dist/opBuilder.js +2 -2
  20. package/dist/opBuilder.js.map +1 -1
  21. package/dist/properties.d.ts.map +1 -1
  22. package/dist/properties.js +1 -1
  23. package/dist/properties.js.map +1 -1
  24. package/dist/referencePositions.d.ts +2 -2
  25. package/dist/referencePositions.js +2 -2
  26. package/dist/referencePositions.js.map +1 -1
  27. package/dist/segmentPropertiesManager.d.ts +4 -1
  28. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  29. package/dist/segmentPropertiesManager.js +23 -11
  30. package/dist/segmentPropertiesManager.js.map +1 -1
  31. package/dist/snapshotChunks.d.ts +1 -1
  32. package/dist/snapshotChunks.d.ts.map +1 -1
  33. package/dist/snapshotChunks.js.map +1 -1
  34. package/dist/snapshotLoader.d.ts +1 -1
  35. package/dist/snapshotLoader.d.ts.map +1 -1
  36. package/dist/snapshotLoader.js.map +1 -1
  37. package/dist/snapshotV1.d.ts +1 -1
  38. package/dist/snapshotV1.d.ts.map +1 -1
  39. package/dist/snapshotV1.js.map +1 -1
  40. package/dist/snapshotlegacy.d.ts +1 -1
  41. package/dist/snapshotlegacy.d.ts.map +1 -1
  42. package/dist/snapshotlegacy.js.map +1 -1
  43. package/dist/test/mergeTree.annotate.deltaCallback.spec.js +0 -1
  44. package/dist/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
  45. package/dist/textSegment.js +1 -1
  46. package/dist/textSegment.js.map +1 -1
  47. package/lib/client.d.ts +1 -1
  48. package/lib/client.d.ts.map +1 -1
  49. package/lib/client.js +9 -4
  50. package/lib/client.js.map +1 -1
  51. package/lib/legacy.d.ts +3 -1
  52. package/lib/mergeTree.d.ts +0 -1
  53. package/lib/mergeTree.d.ts.map +1 -1
  54. package/lib/mergeTree.js +41 -56
  55. package/lib/mergeTree.js.map +1 -1
  56. package/lib/mergeTreeDeltaCallback.d.ts +29 -3
  57. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  58. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  59. package/lib/mergeTreeNodes.d.ts +12 -7
  60. package/lib/mergeTreeNodes.d.ts.map +1 -1
  61. package/lib/mergeTreeNodes.js +5 -16
  62. package/lib/mergeTreeNodes.js.map +1 -1
  63. package/lib/opBuilder.js +2 -2
  64. package/lib/opBuilder.js.map +1 -1
  65. package/lib/properties.d.ts.map +1 -1
  66. package/lib/properties.js +1 -1
  67. package/lib/properties.js.map +1 -1
  68. package/lib/referencePositions.d.ts +2 -2
  69. package/lib/referencePositions.js +2 -2
  70. package/lib/referencePositions.js.map +1 -1
  71. package/lib/segmentPropertiesManager.d.ts +4 -1
  72. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  73. package/lib/segmentPropertiesManager.js +23 -11
  74. package/lib/segmentPropertiesManager.js.map +1 -1
  75. package/lib/snapshotChunks.d.ts +1 -1
  76. package/lib/snapshotChunks.d.ts.map +1 -1
  77. package/lib/snapshotChunks.js.map +1 -1
  78. package/lib/snapshotLoader.d.ts +1 -1
  79. package/lib/snapshotLoader.d.ts.map +1 -1
  80. package/lib/snapshotLoader.js +1 -1
  81. package/lib/snapshotLoader.js.map +1 -1
  82. package/lib/snapshotV1.d.ts +1 -1
  83. package/lib/snapshotV1.d.ts.map +1 -1
  84. package/lib/snapshotV1.js.map +1 -1
  85. package/lib/snapshotlegacy.d.ts +1 -1
  86. package/lib/snapshotlegacy.d.ts.map +1 -1
  87. package/lib/snapshotlegacy.js.map +1 -1
  88. package/lib/test/mergeTree.annotate.deltaCallback.spec.js +0 -1
  89. package/lib/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
  90. package/lib/textSegment.js +1 -1
  91. package/lib/textSegment.js.map +1 -1
  92. package/lib/tsdoc-metadata.json +1 -1
  93. package/package.json +20 -24
  94. package/src/client.ts +13 -6
  95. package/src/mergeTree.ts +43 -65
  96. package/src/mergeTreeDeltaCallback.ts +33 -3
  97. package/src/mergeTreeNodes.ts +18 -22
  98. package/src/opBuilder.ts +2 -2
  99. package/src/properties.ts +5 -2
  100. package/src/referencePositions.ts +2 -2
  101. package/src/segmentPropertiesManager.ts +27 -14
  102. package/src/snapshotChunks.ts +1 -1
  103. package/src/snapshotLoader.ts +5 -2
  104. package/src/snapshotV1.ts +1 -2
  105. package/src/snapshotlegacy.ts +1 -2
  106. package/src/textSegment.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mergeTree.annotate.deltaCallback.spec.js","sourceRoot":"","sources":["../../src/test/mergeTree.annotate.deltaCallback.spec.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 { strict as assert } from \"assert\";\n\nimport { LocalClientId, UnassignedSequenceNumber, UniversalSequenceNumber } from \"../constants.js\";\nimport { MergeTree } from \"../mergeTree.js\";\nimport { MergeTreeMaintenanceType } from \"../mergeTreeDeltaCallback.js\";\nimport { MergeTreeDeltaType } from \"../ops.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { countOperations, insertSegments, insertText, markRangeRemoved } from \"./testUtils.js\";\n\ndescribe(\"MergeTree\", () => {\n\tlet mergeTree: MergeTree;\n\tconst localClientId = 17;\n\tlet currentSequenceNumber: number;\n\tbeforeEach(() => {\n\t\tmergeTree = new MergeTree();\n\t\tinsertSegments({\n\t\t\tmergeTree,\n\t\t\tpos: 0,\n\t\t\tsegments: [TextSegment.make(\"hello world\")],\n\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\tclientId: LocalClientId,\n\t\t\tseq: UniversalSequenceNumber,\n\t\t\topArgs: undefined,\n\t\t});\n\n\t\tcurrentSequenceNumber = 0;\n\t\tmergeTree.startCollaboration(\n\t\t\tlocalClientId,\n\t\t\t/* minSeq: */ currentSequenceNumber,\n\t\t\t/* currentSeq: */ currentSequenceNumber,\n\t\t);\n\t});\n\n\tdescribe(\"annotateRange\", () => {\n\t\tit(\"Event on annotation\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t4,\n\t\t\t\t6,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"No event on annotation of empty range\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t3,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\t++currentSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 1,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Annotate over local insertion\", () => {\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 4,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\ttext: \"a\",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t8,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Annotate over remote insertion\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 4,\n\t\t\t\trefSeq: remoteSequenceNumber,\n\t\t\t\tclientId: remoteClientId,\n\t\t\t\tseq: ++remoteSequenceNumber,\n\t\t\t\ttext: \"a\",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t8,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Annotate over remote deletion\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tmarkRangeRemoved({\n\t\t\t\tmergeTree,\n\t\t\t\tstart: 4,\n\t\t\t\tend: 6,\n\t\t\t\trefSeq: remoteSequenceNumber,\n\t\t\t\tclientId: remoteClientId,\n\t\t\t\tseq: ++remoteSequenceNumber,\n\t\t\t\toverwrite: false,\n\t\t\t\topArgs: undefined as any,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t8,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Remote annotate within local deletion\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tmarkRangeRemoved({\n\t\t\t\tmergeTree,\n\t\t\t\tstart: 3,\n\t\t\t\tend: 8,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\toverwrite: false,\n\t\t\t\topArgs: undefined as any,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t4,\n\t\t\t\t6,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tremoteSequenceNumber,\n\t\t\t\tremoteClientId,\n\t\t\t\t++remoteSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
1
+ {"version":3,"file":"mergeTree.annotate.deltaCallback.spec.js","sourceRoot":"","sources":["../../src/test/mergeTree.annotate.deltaCallback.spec.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 { strict as assert } from \"assert\";\n\nimport { LocalClientId, UnassignedSequenceNumber, UniversalSequenceNumber } from \"../constants.js\";\nimport { MergeTree } from \"../mergeTree.js\";\nimport { MergeTreeMaintenanceType } from \"../mergeTreeDeltaCallback.js\";\nimport { MergeTreeDeltaType } from \"../ops.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { countOperations, insertSegments, insertText, markRangeRemoved } from \"./testUtils.js\";\n\ndescribe(\"MergeTree\", () => {\n\tlet mergeTree: MergeTree;\n\tconst localClientId = 17;\n\tlet currentSequenceNumber: number;\n\tbeforeEach(() => {\n\t\tmergeTree = new MergeTree();\n\t\tinsertSegments({\n\t\t\tmergeTree,\n\t\t\tpos: 0,\n\t\t\tsegments: [TextSegment.make(\"hello world\")],\n\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\tclientId: LocalClientId,\n\t\t\tseq: UniversalSequenceNumber,\n\t\t\topArgs: undefined,\n\t\t});\n\n\t\tcurrentSequenceNumber = 0;\n\t\tmergeTree.startCollaboration(\n\t\t\tlocalClientId,\n\t\t\t/* minSeq: */ currentSequenceNumber,\n\t\t\t/* currentSeq: */ currentSequenceNumber,\n\t\t);\n\t});\n\n\tdescribe(\"annotateRange\", () => {\n\t\tit(\"Event on annotation\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t4,\n\t\t\t\t6,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"No event on annotation of empty range\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t3,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\t++currentSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 1,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Annotate over local insertion\", () => {\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 4,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\ttext: \"a\",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t8,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Annotate over remote insertion\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 4,\n\t\t\t\trefSeq: remoteSequenceNumber,\n\t\t\t\tclientId: remoteClientId,\n\t\t\t\tseq: ++remoteSequenceNumber,\n\t\t\t\ttext: \"a\",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t8,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Annotate over remote deletion\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tmarkRangeRemoved({\n\t\t\t\tmergeTree,\n\t\t\t\tstart: 4,\n\t\t\t\tend: 6,\n\t\t\t\trefSeq: remoteSequenceNumber,\n\t\t\t\tclientId: remoteClientId,\n\t\t\t\tseq: ++remoteSequenceNumber,\n\t\t\t\toverwrite: false,\n\t\t\t\topArgs: undefined as any,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t3,\n\t\t\t\t8,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tcurrentSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUnassignedSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.ANNOTATE]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Remote annotate within local deletion\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tmarkRangeRemoved({\n\t\t\t\tmergeTree,\n\t\t\t\tstart: 3,\n\t\t\t\tend: 8,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\toverwrite: false,\n\t\t\t\topArgs: undefined as any,\n\t\t\t});\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.annotateRange(\n\t\t\t\t4,\n\t\t\t\t6,\n\t\t\t\t{\n\t\t\t\t\tfoo: \"bar\",\n\t\t\t\t},\n\t\t\t\tremoteSequenceNumber,\n\t\t\t\tremoteClientId,\n\t\t\t\t++remoteSequenceNumber,\n\t\t\t\tundefined as any,\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 2,\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
@@ -47,7 +47,7 @@ export class TextSegment extends BaseSegment {
47
47
  toJSONObject() {
48
48
  // To reduce snapshot/ops size, we serialize a TextSegment as a plain 'string' if it is
49
49
  // not annotated.
50
- return this.properties ? { text: this.text, props: this.properties } : this.text;
50
+ return this.properties ? { text: this.text, props: { ...this.properties } } : this.text;
51
51
  }
52
52
  clone(start = 0, end) {
53
53
  const text = this.text.substring(start, end);
@@ -1 +1 @@
1
- {"version":3,"file":"textSegment.js","sourceRoot":"","sources":["../src/textSegment.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 { BaseSegment, ISegment } from \"./mergeTreeNodes.js\";\nimport { IJSONSegment } from \"./ops.js\";\nimport { PropertySet } from \"./properties.js\";\n\n// Maximum length of text segment to be considered to be merged with other segment.\n// Maximum segment length is at least 2x of it (not taking into account initial segment creation).\n// The bigger it is, the more expensive it is to break segment into sub-segments (on edits)\n// The smaller it is, the more segments we have in snapshots (and in memory) - it's more expensive to load snapshots.\n// Small number also makes ReplayTool produce false positives (\"same\" snapshots have slightly different binary\n// representations). More measurements needs to be done, but it's very likely the right spot is somewhere between\n// 1K-2K mark. That said, we also break segments on newline and there are very few segments that are longer than 256\n// because of it. Must be an even number.\n// Exported for test use only.\nexport const TextSegmentGranularity = 256;\n\n/**\n * @alpha\n */\nexport interface IJSONTextSegment extends IJSONSegment {\n\ttext: string;\n}\n\n/**\n * @alpha\n */\nexport class TextSegment extends BaseSegment {\n\tpublic static readonly type = \"TextSegment\";\n\tpublic readonly type = TextSegment.type;\n\n\tpublic static is(segment: ISegment): segment is TextSegment {\n\t\treturn segment.type === TextSegment.type;\n\t}\n\n\tpublic static make(text: string, props?: PropertySet) {\n\t\tconst seg = new TextSegment(text);\n\t\tif (props) {\n\t\t\tseg.addProperties(props);\n\t\t}\n\t\treturn seg;\n\t}\n\n\tpublic static fromJSONObject(spec: any) {\n\t\tif (typeof spec === \"string\") {\n\t\t\treturn new TextSegment(spec);\n\t\t} else if (spec && typeof spec === \"object\" && \"text\" in spec) {\n\t\t\tconst textSpec = spec as IJSONTextSegment;\n\t\t\treturn TextSegment.make(textSpec.text, textSpec.props as PropertySet);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tconstructor(public text: string) {\n\t\tsuper();\n\t\tthis.cachedLength = text.length;\n\t}\n\n\tpublic toJSONObject(): IJSONTextSegment | string {\n\t\t// To reduce snapshot/ops size, we serialize a TextSegment as a plain 'string' if it is\n\t\t// not annotated.\n\t\treturn this.properties ? { text: this.text, props: this.properties } : this.text;\n\t}\n\n\tpublic clone(start = 0, end?: number) {\n\t\tconst text = this.text.substring(start, end);\n\t\tconst b = TextSegment.make(text, this.properties);\n\t\tthis.cloneInto(b);\n\t\treturn b;\n\t}\n\n\tpublic canAppend(segment: ISegment): boolean {\n\t\treturn (\n\t\t\t!this.text.endsWith(\"\\n\") &&\n\t\t\tTextSegment.is(segment) &&\n\t\t\t(this.cachedLength <= TextSegmentGranularity ||\n\t\t\t\tsegment.cachedLength <= TextSegmentGranularity)\n\t\t);\n\t}\n\n\tpublic toString() {\n\t\treturn this.text;\n\t}\n\n\tpublic append(segment: ISegment) {\n\t\tassert(TextSegment.is(segment), 0x447 /* can only append text segment */);\n\t\tsuper.append(segment);\n\t\tthis.text += segment.text;\n\t}\n\n\tprotected createSplitSegmentAt(pos: number) {\n\t\tif (pos > 0) {\n\t\t\tconst remainingText = this.text.substring(pos);\n\t\t\tthis.text = this.text.substring(0, pos);\n\t\t\tthis.cachedLength = this.text.length;\n\t\t\tconst leafSegment = new TextSegment(remainingText);\n\t\t\treturn leafSegment;\n\t\t}\n\t}\n}\n\n/**\n * @deprecated This functionality was not meant to be exported and will be removed in a future release\n * @alpha\n */\nexport interface IMergeTreeTextHelper {\n\tgetText(\n\t\trefSeq: number,\n\t\tclientId: number,\n\t\tplaceholder: string,\n\t\tstart?: number,\n\t\tend?: number,\n\t): string;\n}\n"]}
1
+ {"version":3,"file":"textSegment.js","sourceRoot":"","sources":["../src/textSegment.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 { BaseSegment, ISegment } from \"./mergeTreeNodes.js\";\nimport { IJSONSegment } from \"./ops.js\";\nimport { PropertySet } from \"./properties.js\";\n\n// Maximum length of text segment to be considered to be merged with other segment.\n// Maximum segment length is at least 2x of it (not taking into account initial segment creation).\n// The bigger it is, the more expensive it is to break segment into sub-segments (on edits)\n// The smaller it is, the more segments we have in snapshots (and in memory) - it's more expensive to load snapshots.\n// Small number also makes ReplayTool produce false positives (\"same\" snapshots have slightly different binary\n// representations). More measurements needs to be done, but it's very likely the right spot is somewhere between\n// 1K-2K mark. That said, we also break segments on newline and there are very few segments that are longer than 256\n// because of it. Must be an even number.\n// Exported for test use only.\nexport const TextSegmentGranularity = 256;\n\n/**\n * @alpha\n */\nexport interface IJSONTextSegment extends IJSONSegment {\n\ttext: string;\n}\n\n/**\n * @alpha\n */\nexport class TextSegment extends BaseSegment {\n\tpublic static readonly type = \"TextSegment\";\n\tpublic readonly type = TextSegment.type;\n\n\tpublic static is(segment: ISegment): segment is TextSegment {\n\t\treturn segment.type === TextSegment.type;\n\t}\n\n\tpublic static make(text: string, props?: PropertySet) {\n\t\tconst seg = new TextSegment(text);\n\t\tif (props) {\n\t\t\tseg.addProperties(props);\n\t\t}\n\t\treturn seg;\n\t}\n\n\tpublic static fromJSONObject(spec: any) {\n\t\tif (typeof spec === \"string\") {\n\t\t\treturn new TextSegment(spec);\n\t\t} else if (spec && typeof spec === \"object\" && \"text\" in spec) {\n\t\t\tconst textSpec = spec as IJSONTextSegment;\n\t\t\treturn TextSegment.make(textSpec.text, textSpec.props as PropertySet);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tconstructor(public text: string) {\n\t\tsuper();\n\t\tthis.cachedLength = text.length;\n\t}\n\n\tpublic toJSONObject(): IJSONTextSegment | string {\n\t\t// To reduce snapshot/ops size, we serialize a TextSegment as a plain 'string' if it is\n\t\t// not annotated.\n\t\treturn this.properties ? { text: this.text, props: { ...this.properties } } : this.text;\n\t}\n\n\tpublic clone(start = 0, end?: number) {\n\t\tconst text = this.text.substring(start, end);\n\t\tconst b = TextSegment.make(text, this.properties);\n\t\tthis.cloneInto(b);\n\t\treturn b;\n\t}\n\n\tpublic canAppend(segment: ISegment): boolean {\n\t\treturn (\n\t\t\t!this.text.endsWith(\"\\n\") &&\n\t\t\tTextSegment.is(segment) &&\n\t\t\t(this.cachedLength <= TextSegmentGranularity ||\n\t\t\t\tsegment.cachedLength <= TextSegmentGranularity)\n\t\t);\n\t}\n\n\tpublic toString() {\n\t\treturn this.text;\n\t}\n\n\tpublic append(segment: ISegment) {\n\t\tassert(TextSegment.is(segment), 0x447 /* can only append text segment */);\n\t\tsuper.append(segment);\n\t\tthis.text += segment.text;\n\t}\n\n\tprotected createSplitSegmentAt(pos: number) {\n\t\tif (pos > 0) {\n\t\t\tconst remainingText = this.text.substring(pos);\n\t\t\tthis.text = this.text.substring(0, pos);\n\t\t\tthis.cachedLength = this.text.length;\n\t\t\tconst leafSegment = new TextSegment(remainingText);\n\t\t\treturn leafSegment;\n\t\t}\n\t}\n}\n\n/**\n * @deprecated This functionality was not meant to be exported and will be removed in a future release\n * @alpha\n */\nexport interface IMergeTreeTextHelper {\n\tgetText(\n\t\trefSeq: number,\n\t\tclientId: number,\n\t\tplaceholder: string,\n\t\tstart?: number,\n\t\tend?: number,\n\t): string;\n}\n"]}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.42.3"
8
+ "packageVersion": "7.43.1"
9
9
  }
10
10
  ]
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/merge-tree",
3
- "version": "2.0.0-rc.3.0.3",
3
+ "version": "2.0.0-rc.4.0.0",
4
4
  "description": "Merge tree",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -79,31 +79,31 @@
79
79
  "temp-directory": "nyc/.nyc_output"
80
80
  },
81
81
  "dependencies": {
82
- "@fluid-internal/client-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
83
- "@fluidframework/container-definitions": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
84
- "@fluidframework/core-interfaces": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
85
- "@fluidframework/core-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
86
- "@fluidframework/datastore-definitions": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
82
+ "@fluid-internal/client-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
83
+ "@fluidframework/container-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
84
+ "@fluidframework/core-interfaces": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
85
+ "@fluidframework/core-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
86
+ "@fluidframework/datastore-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
87
87
  "@fluidframework/protocol-definitions": "^3.2.0",
88
- "@fluidframework/runtime-definitions": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
89
- "@fluidframework/runtime-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
90
- "@fluidframework/shared-object-base": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
91
- "@fluidframework/telemetry-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0"
88
+ "@fluidframework/runtime-definitions": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
89
+ "@fluidframework/runtime-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
90
+ "@fluidframework/shared-object-base": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
91
+ "@fluidframework/telemetry-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0"
92
92
  },
93
93
  "devDependencies": {
94
94
  "@arethetypeswrong/cli": "^0.15.2",
95
95
  "@biomejs/biome": "^1.6.2",
96
- "@fluid-internal/mocha-test-setup": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
97
- "@fluid-private/stochastic-test-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
98
- "@fluid-private/test-pairwise-generator": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
96
+ "@fluid-internal/mocha-test-setup": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
97
+ "@fluid-private/stochastic-test-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
98
+ "@fluid-private/test-pairwise-generator": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
99
99
  "@fluid-tools/benchmark": "^0.48.0",
100
- "@fluid-tools/build-cli": "^0.37.0",
100
+ "@fluid-tools/build-cli": "^0.38.0",
101
101
  "@fluidframework/build-common": "^2.0.3",
102
- "@fluidframework/build-tools": "^0.37.0",
102
+ "@fluidframework/build-tools": "^0.38.0",
103
103
  "@fluidframework/eslint-config-fluid": "^5.1.0",
104
- "@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.0.0-internal.8.0.0",
105
- "@fluidframework/test-runtime-utils": ">=2.0.0-rc.3.0.3 <2.0.0-rc.3.1.0",
106
- "@microsoft/api-extractor": "^7.42.3",
104
+ "@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.0.0-rc.3.0.0",
105
+ "@fluidframework/test-runtime-utils": ">=2.0.0-rc.4.0.0 <2.0.0-rc.4.1.0",
106
+ "@microsoft/api-extractor": "^7.43.1",
107
107
  "@types/diff": "^3.5.1",
108
108
  "@types/mocha": "^9.1.1",
109
109
  "@types/node": "^18.19.0",
@@ -122,11 +122,7 @@
122
122
  "typescript": "~5.1.6"
123
123
  },
124
124
  "typeValidation": {
125
- "broken": {
126
- "ClassDeclaration_Client": {
127
- "backCompat": false
128
- }
129
- }
125
+ "broken": {}
130
126
  },
131
127
  "scripts": {
132
128
  "api": "fluid-build . --task api",
@@ -163,7 +159,7 @@
163
159
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
164
160
  "test:stress": "cross-env FUZZ_STRESS_RUN=1 FUZZ_TEST_COUNT=1 npm run test:mocha",
165
161
  "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
166
- "typetests:gen": "fluid-type-test-generator",
162
+ "typetests:gen": "flub generate typetests --dir . -v --publicFallback",
167
163
  "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
168
164
  }
169
165
  }
package/src/client.ts CHANGED
@@ -15,8 +15,12 @@ import {
15
15
  import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
16
16
  import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
17
17
  import { IFluidSerializer } from "@fluidframework/shared-object-base";
18
- import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
19
- import { LoggingError, UsageError } from "@fluidframework/telemetry-utils/internal";
18
+ import {
19
+ ITelemetryLoggerExt,
20
+ LoggingError,
21
+ UsageError,
22
+ } from "@fluidframework/telemetry-utils/internal";
23
+ import { toDeltaManagerInternal } from "@fluidframework/runtime-utils/internal";
20
24
 
21
25
  import { MergeTreeTextHelper } from "./MergeTreeTextHelper.js";
22
26
  import { DoublyLinkedList, RedBlackTree } from "./collections/index.js";
@@ -66,7 +70,8 @@ import {
66
70
  MergeTreeDeltaType,
67
71
  ReferenceType,
68
72
  } from "./ops.js";
69
- import { PropertySet } from "./properties.js";
73
+ // eslint-disable-next-line import/no-deprecated
74
+ import { PropertySet, createMap } from "./properties.js";
70
75
  import { DetachedReferencePosition, ReferencePosition } from "./referencePositions.js";
71
76
  import { SnapshotLoader } from "./snapshotLoader.js";
72
77
  import { SnapshotV1 } from "./snapshotV1.js";
@@ -770,7 +775,7 @@ export class Client extends TypedEventEmitter<IClientEvents> {
770
775
  switch (resetOp.type) {
771
776
  case MergeTreeDeltaType.ANNOTATE:
772
777
  assert(
773
- segment.propertyManager?.hasPendingProperties() === true,
778
+ segment.propertyManager?.hasPendingProperties(resetOp.props) === true,
774
779
  0x036 /* "Segment has no pending properties" */,
775
780
  );
776
781
  // if the segment has been removed or obliterated, there's no need to send the annotate op
@@ -800,7 +805,9 @@ export class Client extends TypedEventEmitter<IClientEvents> {
800
805
  let segInsertOp = segment;
801
806
  if (typeof resetOp.seg === "object" && resetOp.seg.props !== undefined) {
802
807
  segInsertOp = segment.clone();
803
- segInsertOp.properties = resetOp.seg.props;
808
+ // eslint-disable-next-line import/no-deprecated
809
+ segInsertOp.properties = createMap();
810
+ segInsertOp.addProperties(resetOp.seg.props);
804
811
  }
805
812
  if (segment.movedSeq !== UnassignedSequenceNumber) {
806
813
  removeMoveInfo(segment);
@@ -1077,7 +1084,7 @@ export class Client extends TypedEventEmitter<IClientEvents> {
1077
1084
  serializer: IFluidSerializer,
1078
1085
  catchUpMsgs: ISequencedDocumentMessage[],
1079
1086
  ): ISummaryTreeWithStats {
1080
- const deltaManager = runtime.deltaManager;
1087
+ const deltaManager = toDeltaManagerInternal(runtime.deltaManager);
1081
1088
  const minSeq = deltaManager.minimumSequenceNumber;
1082
1089
 
1083
1090
  // Catch up to latest MSN, if we have not had a chance to do it.
package/src/mergeTree.ts CHANGED
@@ -45,7 +45,6 @@ import {
45
45
  BlockAction,
46
46
  // eslint-disable-next-line import/no-deprecated
47
47
  CollaborationWindow,
48
- HierMergeBlock,
49
48
  IMergeNode,
50
49
  IMoveInfo,
51
50
  IRemovalInfo,
@@ -69,7 +68,7 @@ import { createAnnotateRangeOp, createInsertSegmentOp, createRemoveRangeOp } fro
69
68
  import { IMergeTreeDeltaOp, IRelativePosition, MergeTreeDeltaType, ReferenceType } from "./ops.js";
70
69
  import { PartialSequenceLengths } from "./partialLengths.js";
71
70
  // eslint-disable-next-line import/no-deprecated
72
- import { MapLike, PropertySet, createMap, extend, extendIfUndefined } from "./properties.js";
71
+ import { PropertySet, createMap, extend, extendIfUndefined } from "./properties.js";
73
72
  import {
74
73
  DetachedReferencePosition,
75
74
  ReferencePosition,
@@ -134,26 +133,6 @@ const LRUSegmentComparer: IComparer<LRUSegment> = {
134
133
  compare: (a, b) => a.maxSeq - b.maxSeq,
135
134
  };
136
135
 
137
- function addTile(tile: ReferencePosition, tiles: MapLike<ReferencePosition>) {
138
- const tileLabels = refGetTileLabels(tile);
139
- if (tileLabels) {
140
- for (const tileLabel of tileLabels) {
141
- tiles[tileLabel] = tile;
142
- }
143
- }
144
- }
145
-
146
- function addTileIfNotPresent(tile: ReferencePosition, tiles: MapLike<ReferencePosition>) {
147
- const tileLabels = refGetTileLabels(tile);
148
- if (tileLabels) {
149
- for (const tileLabel of tileLabels) {
150
- if (tiles[tileLabel] === undefined) {
151
- tiles[tileLabel] = tile;
152
- }
153
- }
154
- }
155
- }
156
-
157
136
  /**
158
137
  * @alpha
159
138
  */
@@ -479,7 +458,7 @@ export class MergeTree {
479
458
  }
480
459
 
481
460
  public makeBlock(childCount: number) {
482
- const block: MergeBlock = new HierMergeBlock(childCount);
461
+ const block = new MergeBlock(childCount);
483
462
  block.ordinal = "";
484
463
  return block;
485
464
  }
@@ -1099,7 +1078,6 @@ export class MergeTree {
1099
1078
  foundMarker = node;
1100
1079
  }
1101
1080
  } else {
1102
- assert(node.hierBlock(), 0x90b /* must be hierBlock */);
1103
1081
  const marker = forwards
1104
1082
  ? node.leftmostTiles[markerLabel]
1105
1083
  : node.rightmostTiles[markerLabel];
@@ -1850,7 +1828,9 @@ export class MergeTree {
1850
1828
  this.collabWindow.collaborating,
1851
1829
  rollback,
1852
1830
  );
1853
- deltaSegments.push({ segment, propertyDeltas });
1831
+ if (!isRemovedOrMoved(segment)) {
1832
+ deltaSegments.push({ segment, propertyDeltas });
1833
+ }
1854
1834
  if (this.collabWindow.collaborating) {
1855
1835
  if (seq === UnassignedSequenceNumber) {
1856
1836
  segmentGroup = this.addToPendingList(
@@ -2460,55 +2440,53 @@ export class MergeTree {
2460
2440
 
2461
2441
  normalize();
2462
2442
  }
2463
-
2464
- private addNodeReferences(
2465
- node: IMergeNode,
2466
- rightmostTiles: MapLike<ReferencePosition>,
2467
- leftmostTiles: MapLike<ReferencePosition>,
2468
- ) {
2469
- if (node.isLeaf()) {
2470
- const segment = node;
2471
- if ((this.localNetLength(segment) ?? 0) > 0 && Marker.is(segment)) {
2472
- const markerId = segment.getId();
2473
- // Also in insertMarker but need for reload segs case
2474
- // can add option for this only from reload segs
2475
- if (markerId) {
2476
- this.idToMarker.set(markerId, segment);
2477
- }
2478
- if (refTypeIncludesFlag(segment, ReferenceType.Tile)) {
2479
- addTile(segment, rightmostTiles);
2480
- addTileIfNotPresent(segment, leftmostTiles);
2481
- }
2482
- }
2483
- } else {
2484
- assert(node.hierBlock(), 0x90c /* must be hier block */);
2485
- // eslint-disable-next-line import/no-deprecated
2486
- extend(rightmostTiles, node.rightmostTiles);
2487
- // eslint-disable-next-line import/no-deprecated
2488
- extendIfUndefined(leftmostTiles, node.leftmostTiles);
2489
- }
2490
- }
2491
-
2492
2443
  private blockUpdate(block: MergeBlock) {
2493
2444
  let len: number | undefined;
2494
- if (block.hierBlock()) {
2495
- // eslint-disable-next-line import/no-deprecated
2496
- block.rightmostTiles = createMap<Marker>();
2497
- // eslint-disable-next-line import/no-deprecated
2498
- block.leftmostTiles = createMap<Marker>();
2499
- }
2445
+
2446
+ // eslint-disable-next-line import/no-deprecated
2447
+ const rightmostTiles = createMap<Marker>();
2448
+ // eslint-disable-next-line import/no-deprecated
2449
+ const leftmostTiles = createMap<Marker>();
2450
+
2500
2451
  for (let i = 0; i < block.childCount; i++) {
2501
- const child = block.children[i];
2502
- const nodeLength = nodeTotalLength(this, child);
2452
+ const node = block.children[i];
2453
+ const nodeLength = nodeTotalLength(this, node);
2503
2454
  if (nodeLength !== undefined) {
2504
2455
  len ??= 0;
2505
2456
  len += nodeLength;
2506
2457
  }
2507
- if (block.hierBlock()) {
2508
- this.addNodeReferences(child, block.rightmostTiles, block.leftmostTiles);
2458
+ if (node.isLeaf()) {
2459
+ const segment = node;
2460
+ if ((this.localNetLength(segment) ?? 0) > 0 && Marker.is(segment)) {
2461
+ const markerId = segment.getId();
2462
+ // Also in insertMarker but need for reload segs case
2463
+ // can add option for this only from reload segs
2464
+ if (markerId) {
2465
+ this.idToMarker.set(markerId, segment);
2466
+ }
2467
+
2468
+ if (refTypeIncludesFlag(segment, ReferenceType.Tile)) {
2469
+ const tileLabels = refGetTileLabels(segment);
2470
+ if (tileLabels) {
2471
+ for (const tileLabel of tileLabels) {
2472
+ // this depends on walking children in order
2473
+ // The later, and right most children overwrite
2474
+ // whereas early, and left most do not overwrite
2475
+ rightmostTiles[tileLabel] = segment;
2476
+ leftmostTiles[tileLabel] ??= segment;
2477
+ }
2478
+ }
2479
+ }
2480
+ }
2481
+ } else {
2482
+ // eslint-disable-next-line import/no-deprecated
2483
+ extend(rightmostTiles, node.rightmostTiles);
2484
+ // eslint-disable-next-line import/no-deprecated
2485
+ extendIfUndefined(leftmostTiles, node.leftmostTiles);
2509
2486
  }
2510
2487
  }
2511
-
2488
+ block.leftmostTiles = leftmostTiles;
2489
+ block.rightmostTiles = rightmostTiles;
2512
2490
  block.cachedLength = len;
2513
2491
  }
2514
2492
 
@@ -70,7 +70,19 @@ export type MergeTreeDeltaOperationTypes = MergeTreeDeltaOperationType | MergeTr
70
70
  export interface IMergeTreeDeltaCallbackArgs<
71
71
  TOperationType extends MergeTreeDeltaOperationTypes = MergeTreeDeltaOperationType,
72
72
  > {
73
+ /**
74
+ * The type of operation that affected segments in the merge-tree.
75
+ * The affected segments can be accessed via {@link IMergeTreeDeltaCallbackArgs.deltaSegments|deltaSegments}.
76
+ *
77
+ * See {@link MergeTreeDeltaOperationType} and {@link (MergeTreeMaintenanceType:type)} for possible values.
78
+ */
73
79
  readonly operation: TOperationType;
80
+
81
+ /**
82
+ * A list of deltas describing actions taken on segments.
83
+ *
84
+ * Deltas are not guaranteed to be in any particular order.
85
+ */
74
86
  readonly deltaSegments: IMergeTreeSegmentDelta[];
75
87
  }
76
88
 
@@ -78,7 +90,20 @@ export interface IMergeTreeDeltaCallbackArgs<
78
90
  * @alpha
79
91
  */
80
92
  export interface IMergeTreeSegmentDelta {
93
+ /**
94
+ * The segment this delta affected.
95
+ */
81
96
  segment: ISegment;
97
+
98
+ /**
99
+ * A property set containing changes to properties on this segment.
100
+ *
101
+ * @remarks - Deleting a property is represented using `null` as the value.
102
+ * @example
103
+ *
104
+ * An annotation change which deleted the property "foo" and set "bar" to 5 would be represented as:
105
+ * `{ foo: null, bar: 5 }`.
106
+ */
82
107
  propertyDeltas?: PropertySet;
83
108
  }
84
109
 
@@ -92,13 +117,18 @@ export interface IMergeTreeDeltaOpArgs {
92
117
  */
93
118
  // eslint-disable-next-line import/no-deprecated
94
119
  readonly groupOp?: IMergeTreeGroupMsg;
120
+
95
121
  /**
96
- * The merge tree operation
122
+ * The {@link IMergeTreeOp} corresponding to the delta.
123
+ *
124
+ * @remarks - This is useful for determining the type of change (see {@link (MergeTreeDeltaType:type)}).
97
125
  */
98
126
  readonly op: IMergeTreeOp;
127
+
99
128
  /**
100
- * Get the sequence message, should only be null if the
101
- * Delta op args are for an unacked local change
129
+ * The {@link @fluidframework/protocol-definitions#ISequencedDocumentMessage} corresponding to this acknowledged change.
130
+ *
131
+ * This field is omitted for deltas corresponding to unacknowledged changes.
102
132
  */
103
133
  readonly sequencedMessage?: ISequencedDocumentMessage;
104
134
  }
@@ -397,6 +397,19 @@ export class MergeBlock implements IMergeNodeCommon {
397
397
  public ordinal: string = "";
398
398
  public cachedLength: number | undefined = 0;
399
399
 
400
+ /**
401
+ * Maps each tile label in this block to the rightmost (i.e. furthest) marker associated with that tile label.
402
+ * When combined with the tree structure of MergeBlocks, this allows accelerated queries for nearest tile
403
+ * with a certain label before a given position
404
+ */
405
+ public rightmostTiles: Readonly<MapLike<Marker>>;
406
+ /**
407
+ * Maps each tile label in this block to the leftmost (i.e. nearest) marker associated with that tile label.
408
+ * When combined with the tree structure of MergeBlocks, this allows accelerated queries for nearest tile
409
+ * with a certain label before a given position
410
+ */
411
+ public leftmostTiles: Readonly<MapLike<Marker>>;
412
+
400
413
  isLeaf(): this is ISegment {
401
414
  return false;
402
415
  }
@@ -413,10 +426,10 @@ export class MergeBlock implements IMergeNodeCommon {
413
426
 
414
427
  public constructor(public childCount: number) {
415
428
  this.children = new Array<IMergeNode>(MaxNodesInBlock);
416
- }
417
-
418
- public hierBlock(): this is HierMergeBlock {
419
- return false;
429
+ // eslint-disable-next-line import/no-deprecated
430
+ this.rightmostTiles = createMap<Marker>();
431
+ // eslint-disable-next-line import/no-deprecated
432
+ this.leftmostTiles = createMap<Marker>();
420
433
  }
421
434
 
422
435
  public setOrdinal(child: IMergeNode, index: number) {
@@ -443,23 +456,6 @@ export class MergeBlock implements IMergeNodeCommon {
443
456
  }
444
457
  }
445
458
 
446
- export class HierMergeBlock extends MergeBlock {
447
- public rightmostTiles: MapLike<ReferencePosition>;
448
- public leftmostTiles: MapLike<ReferencePosition>;
449
-
450
- constructor(childCount: number) {
451
- super(childCount);
452
- // eslint-disable-next-line import/no-deprecated
453
- this.rightmostTiles = createMap<ReferencePosition>();
454
- // eslint-disable-next-line import/no-deprecated
455
- this.leftmostTiles = createMap<ReferencePosition>();
456
- }
457
-
458
- public hierBlock(): this is HierMergeBlock {
459
- return true;
460
- }
461
- }
462
-
463
459
  export function seqLTE(seq: number, minOrRefSeq: number) {
464
460
  return seq !== UnassignedSequenceNumber && seq <= minOrRefSeq;
465
461
  }
@@ -540,7 +536,7 @@ export abstract class BaseSegment implements ISegment {
540
536
 
541
537
  protected addSerializedProps(jseg: IJSONSegment) {
542
538
  if (this.properties) {
543
- jseg.props = this.properties;
539
+ jseg.props = { ...this.properties };
544
540
  }
545
541
  }
546
542
 
package/src/opBuilder.ts CHANGED
@@ -35,7 +35,7 @@ export function createAnnotateMarkerOp(
35
35
  }
36
36
 
37
37
  return {
38
- props,
38
+ props: { ...props },
39
39
  relativePos1: { id, before: true },
40
40
  relativePos2: { id },
41
41
  type: MergeTreeDeltaType.ANNOTATE,
@@ -59,7 +59,7 @@ export function createAnnotateRangeOp(
59
59
  return {
60
60
  pos1: start,
61
61
  pos2: end,
62
- props,
62
+ props: { ...props },
63
63
  type: MergeTreeDeltaType.ANNOTATE,
64
64
  };
65
65
  }
package/src/properties.ts CHANGED
@@ -99,10 +99,13 @@ export function clone<T>(extension: MapLike<T> | undefined) {
99
99
  * be removed in a future release.
100
100
  * @internal
101
101
  */
102
- export function addProperties(oldProps: PropertySet | undefined, newProps: PropertySet) {
102
+ export function addProperties(
103
+ oldProps: PropertySet | undefined,
104
+ newProps: PropertySet,
105
+ ): PropertySet {
103
106
  const _oldProps = oldProps ?? createMap<any>();
104
107
  extend(_oldProps, newProps);
105
- return _oldProps;
108
+ return { ..._oldProps };
106
109
  }
107
110
 
108
111
  /**
@@ -30,7 +30,7 @@ export function refTypeIncludesFlag(
30
30
  }
31
31
 
32
32
  /**
33
- * @internal
33
+ * @alpha
34
34
  */
35
35
  export const refGetTileLabels = (refPos: ReferencePosition): string[] | undefined =>
36
36
  refTypeIncludesFlag(refPos, ReferenceType.Tile) && refPos.properties
@@ -38,7 +38,7 @@ export const refGetTileLabels = (refPos: ReferencePosition): string[] | undefine
38
38
  : undefined;
39
39
 
40
40
  /**
41
- * @internal
41
+ * @alpha
42
42
  */
43
43
  export function refHasTileLabel(refPos: ReferencePosition, label: string): boolean {
44
44
  const tileLabels = refGetTileLabels(refPos);
@@ -34,16 +34,18 @@ export class PropertiesManager {
34
34
  }
35
35
 
36
36
  private decrementPendingCounts(props: PropertySet) {
37
- for (const key of Object.keys(props)) {
38
- if (this.pendingKeyUpdateCount?.[key] !== undefined) {
39
- assert(
40
- this.pendingKeyUpdateCount[key] > 0,
41
- 0x05c /* "Trying to update more annotate props than do exist!" */,
42
- );
43
- this.pendingKeyUpdateCount[key]--;
44
- if (this.pendingKeyUpdateCount?.[key] === 0) {
45
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
46
- delete this.pendingKeyUpdateCount[key];
37
+ for (const [key, value] of Object.entries(props)) {
38
+ if (value !== undefined) {
39
+ if (this.pendingKeyUpdateCount?.[key] !== undefined) {
40
+ assert(
41
+ this.pendingKeyUpdateCount[key] > 0,
42
+ 0x05c /* "Trying to update more annotate props than do exist!" */,
43
+ );
44
+ this.pendingKeyUpdateCount[key]--;
45
+ if (this.pendingKeyUpdateCount?.[key] === 0) {
46
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
47
+ delete this.pendingKeyUpdateCount[key];
48
+ }
47
49
  }
48
50
  }
49
51
  }
@@ -77,7 +79,11 @@ export class PropertiesManager {
77
79
 
78
80
  const deltas: PropertySet = {};
79
81
 
80
- for (const key of Object.keys(newProps)) {
82
+ for (const [key, newValue] of Object.entries(newProps)) {
83
+ if (newValue === undefined) {
84
+ continue;
85
+ }
86
+
81
87
  if (collaborating) {
82
88
  if (seq === UnassignedSequenceNumber) {
83
89
  if (this.pendingKeyUpdateCount?.[key] === undefined) {
@@ -92,7 +98,6 @@ export class PropertiesManager {
92
98
  const previousValue: any = oldProps[key];
93
99
  // The delta should be null if undefined, as that's how we encode delete
94
100
  deltas[key] = previousValue === undefined ? null : previousValue;
95
- const newValue = newProps[key];
96
101
  if (newValue === null) {
97
102
  // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
98
103
  delete oldProps[key];
@@ -127,8 +132,16 @@ export class PropertiesManager {
127
132
  return newProps;
128
133
  }
129
134
 
130
- public hasPendingProperties() {
131
- return Object.keys(this.pendingKeyUpdateCount!).length > 0;
135
+ /**
136
+ * @returns whether all valid (i.e. defined) entries of the property bag are pending
137
+ */
138
+ public hasPendingProperties(props: PropertySet) {
139
+ for (const [key, value] of Object.entries(props)) {
140
+ if (value !== undefined && this.pendingKeyUpdateCount?.[key] === undefined) {
141
+ return false;
142
+ }
143
+ }
144
+ return true;
132
145
  }
133
146
 
134
147
  public hasPendingProperty(key: string): boolean {