@fluidframework/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 (110) hide show
  1. package/api-report/tree.alpha.api.md +11 -9
  2. package/api-report/tree.beta.api.md +2 -0
  3. package/api-report/tree.legacy.alpha.api.md +2 -0
  4. package/api-report/tree.legacy.public.api.md +2 -0
  5. package/api-report/tree.public.api.md +2 -0
  6. package/dist/feature-libraries/chunked-forest/basicChunk.d.ts +26 -5
  7. package/dist/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  8. package/dist/feature-libraries/chunked-forest/basicChunk.js +15 -5
  9. package/dist/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  10. package/dist/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
  11. package/dist/feature-libraries/chunked-forest/chunkedForest.js +5 -0
  12. package/dist/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
  13. package/dist/feature-libraries/index.d.ts +1 -1
  14. package/dist/feature-libraries/index.d.ts.map +1 -1
  15. package/dist/feature-libraries/index.js +2 -2
  16. package/dist/feature-libraries/index.js.map +1 -1
  17. package/dist/feature-libraries/modular-schema/discrepancies.d.ts +27 -27
  18. package/dist/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -1
  19. package/dist/feature-libraries/modular-schema/discrepancies.js +152 -193
  20. package/dist/feature-libraries/modular-schema/discrepancies.js.map +1 -1
  21. package/dist/feature-libraries/modular-schema/index.d.ts +1 -1
  22. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  23. package/dist/feature-libraries/modular-schema/index.js +2 -2
  24. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  25. package/dist/packageVersion.d.ts +1 -1
  26. package/dist/packageVersion.js +1 -1
  27. package/dist/packageVersion.js.map +1 -1
  28. package/dist/shared-tree/treeApi.js +4 -1
  29. package/dist/shared-tree/treeApi.js.map +1 -1
  30. package/dist/simple-tree/api/schemaCreationUtilities.d.ts +12 -14
  31. package/dist/simple-tree/api/schemaCreationUtilities.d.ts.map +1 -1
  32. package/dist/simple-tree/api/schemaCreationUtilities.js +9 -7
  33. package/dist/simple-tree/api/schemaCreationUtilities.js.map +1 -1
  34. package/dist/simple-tree/api/schemaFactory.d.ts +2 -0
  35. package/dist/simple-tree/api/schemaFactory.d.ts.map +1 -1
  36. package/dist/simple-tree/api/schemaFactory.js +4 -1
  37. package/dist/simple-tree/api/schemaFactory.js.map +1 -1
  38. package/dist/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
  39. package/dist/simple-tree/core/treeNodeKernel.d.ts +4 -5
  40. package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  41. package/dist/simple-tree/core/treeNodeKernel.js +63 -67
  42. package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
  43. package/dist/simple-tree/objectNode.d.ts +1 -1
  44. package/dist/simple-tree/objectNode.js.map +1 -1
  45. package/dist/simple-tree/objectNodeTypes.d.ts +3 -0
  46. package/dist/simple-tree/objectNodeTypes.d.ts.map +1 -1
  47. package/dist/simple-tree/objectNodeTypes.js +3 -1
  48. package/dist/simple-tree/objectNodeTypes.js.map +1 -1
  49. package/docs/.attachments/object-merge-semantics.drawio +145 -0
  50. package/docs/user-facing/array-merge-semantics.md +344 -0
  51. package/docs/user-facing/map-merge-semantics.md +128 -0
  52. package/docs/user-facing/merge-semantics.md +7 -3
  53. package/docs/user-facing/object-merge-semantics.md +77 -0
  54. package/lib/feature-libraries/chunked-forest/basicChunk.d.ts +26 -5
  55. package/lib/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  56. package/lib/feature-libraries/chunked-forest/basicChunk.js +15 -5
  57. package/lib/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  58. package/lib/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
  59. package/lib/feature-libraries/chunked-forest/chunkedForest.js +5 -0
  60. package/lib/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
  61. package/lib/feature-libraries/index.d.ts +1 -1
  62. package/lib/feature-libraries/index.d.ts.map +1 -1
  63. package/lib/feature-libraries/index.js +1 -1
  64. package/lib/feature-libraries/index.js.map +1 -1
  65. package/lib/feature-libraries/modular-schema/discrepancies.d.ts +27 -27
  66. package/lib/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -1
  67. package/lib/feature-libraries/modular-schema/discrepancies.js +150 -191
  68. package/lib/feature-libraries/modular-schema/discrepancies.js.map +1 -1
  69. package/lib/feature-libraries/modular-schema/index.d.ts +1 -1
  70. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  71. package/lib/feature-libraries/modular-schema/index.js +1 -1
  72. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  73. package/lib/packageVersion.d.ts +1 -1
  74. package/lib/packageVersion.js +1 -1
  75. package/lib/packageVersion.js.map +1 -1
  76. package/lib/shared-tree/treeApi.js +5 -2
  77. package/lib/shared-tree/treeApi.js.map +1 -1
  78. package/lib/simple-tree/api/schemaCreationUtilities.d.ts +12 -14
  79. package/lib/simple-tree/api/schemaCreationUtilities.d.ts.map +1 -1
  80. package/lib/simple-tree/api/schemaCreationUtilities.js +9 -7
  81. package/lib/simple-tree/api/schemaCreationUtilities.js.map +1 -1
  82. package/lib/simple-tree/api/schemaFactory.d.ts +2 -0
  83. package/lib/simple-tree/api/schemaFactory.d.ts.map +1 -1
  84. package/lib/simple-tree/api/schemaFactory.js +4 -1
  85. package/lib/simple-tree/api/schemaFactory.js.map +1 -1
  86. package/lib/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
  87. package/lib/simple-tree/core/treeNodeKernel.d.ts +4 -5
  88. package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  89. package/lib/simple-tree/core/treeNodeKernel.js +64 -68
  90. package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
  91. package/lib/simple-tree/objectNode.d.ts +1 -1
  92. package/lib/simple-tree/objectNode.js.map +1 -1
  93. package/lib/simple-tree/objectNodeTypes.d.ts +3 -0
  94. package/lib/simple-tree/objectNodeTypes.d.ts.map +1 -1
  95. package/lib/simple-tree/objectNodeTypes.js +3 -1
  96. package/lib/simple-tree/objectNodeTypes.js.map +1 -1
  97. package/package.json +23 -31
  98. package/src/feature-libraries/chunked-forest/basicChunk.ts +12 -4
  99. package/src/feature-libraries/chunked-forest/chunkedForest.ts +5 -0
  100. package/src/feature-libraries/index.ts +1 -1
  101. package/src/feature-libraries/modular-schema/discrepancies.ts +202 -241
  102. package/src/feature-libraries/modular-schema/index.ts +4 -1
  103. package/src/packageVersion.ts +1 -1
  104. package/src/shared-tree/treeApi.ts +7 -5
  105. package/src/simple-tree/api/schemaCreationUtilities.ts +29 -17
  106. package/src/simple-tree/api/schemaFactory.ts +25 -18
  107. package/src/simple-tree/api/schemaFactoryRecursive.ts +1 -1
  108. package/src/simple-tree/core/treeNodeKernel.ts +62 -64
  109. package/src/simple-tree/objectNode.ts +1 -1
  110. package/src/simple-tree/objectNodeTypes.ts +3 -1
@@ -0,0 +1,145 @@
1
+ <mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
2
+ <diagram id="-6H5wynXqOOyBtFPYk5a" name="Page-1">
3
+ <mxGraphModel dx="1058" dy="-74" grid="1" gridSize="10" guides="1" tooltips="1" connect="0" arrows="0" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" background="#ffffff" math="0" shadow="0">
4
+ <root>
5
+ <mxCell id="0" />
6
+ <mxCell id="1" parent="0" />
7
+ <mxCell id="ug50JPKoQ96zgBhktdCE-255" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
8
+ <mxGeometry x="894.68" y="1500" width="640" height="120" as="geometry" />
9
+ </mxCell>
10
+ <mxCell id="ug50JPKoQ96zgBhktdCE-256" value="" style="group" parent="1" vertex="1" connectable="0">
11
+ <mxGeometry x="936.0312457912456" y="1510" width="558.6531986531986" height="88.0383333333333" as="geometry" />
12
+ </mxCell>
13
+ <mxCell id="ug50JPKoQ96zgBhktdCE-257" value="" style="group" parent="ug50JPKoQ96zgBhktdCE-256" vertex="1" connectable="0">
14
+ <mxGeometry y="39.99666666666667" width="558.6531986531986" height="48.04166666666663" as="geometry" />
15
+ </mxCell>
16
+ <mxCell id="ug50JPKoQ96zgBhktdCE-258" value="Period of time where a client&#39;s local state shows the sticky note with a &lt;font color=&quot;#ffd966&quot;&gt;&lt;b&gt;yellow&lt;/b&gt;&lt;/font&gt; backgound" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeWidth=2;labelPosition=center;verticalLabelPosition=middle;" parent="ug50JPKoQ96zgBhktdCE-257" vertex="1">
17
+ <mxGeometry x="58.65319865319864" width="500" height="30" as="geometry" />
18
+ </mxCell>
19
+ <mxCell id="ug50JPKoQ96zgBhktdCE-259" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFD966;strokeColor=none;points=[];" parent="ug50JPKoQ96zgBhktdCE-257" vertex="1">
20
+ <mxGeometry y="12.708333333333336" width="38.35016835016835" height="4.583333333333333" as="geometry" />
21
+ </mxCell>
22
+ <mxCell id="ug50JPKoQ96zgBhktdCE-260" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FF6666;strokeColor=#b85450;points=[];strokeWidth=0;" parent="ug50JPKoQ96zgBhktdCE-257" vertex="1">
23
+ <mxGeometry x="1.77635683940025e-15" y="30.749999999999957" width="38.35016835016835" height="4.583333333333333" as="geometry" />
24
+ </mxCell>
25
+ <mxCell id="ug50JPKoQ96zgBhktdCE-261" value="Period of time where a client&#39;s local state shows the sticky note with a &lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#ff6666&quot;&gt;red&lt;/font&gt;&lt;/b&gt;&amp;nbsp;backgound" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeWidth=2;labelPosition=center;verticalLabelPosition=middle;" parent="ug50JPKoQ96zgBhktdCE-257" vertex="1">
26
+ <mxGeometry x="58.65319865319864" y="18.04166666666663" width="480" height="30" as="geometry" />
27
+ </mxCell>
28
+ <mxCell id="ug50JPKoQ96zgBhktdCE-262" value="edit" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;size=20;position=0.5;base=10;strokeWidth=2;" parent="ug50JPKoQ96zgBhktdCE-256" vertex="1">
29
+ <mxGeometry x="39.998754208754235" width="45.12" height="35.83" as="geometry" />
30
+ </mxCell>
31
+ <mxCell id="ug50JPKoQ96zgBhktdCE-263" value="An edit being initiated" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeWidth=2;" parent="ug50JPKoQ96zgBhktdCE-256" vertex="1">
32
+ <mxGeometry x="85.11424242424255" y="0.3125" width="140" height="30" as="geometry" />
33
+ </mxCell>
34
+ <mxCell id="ug50JPKoQ96zgBhktdCE-264" value="An edit being transmitted" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeWidth=2;" parent="ug50JPKoQ96zgBhktdCE-256" vertex="1">
35
+ <mxGeometry x="349.39525252525254" y="0.3158333333333303" width="150" height="20" as="geometry" />
36
+ </mxCell>
37
+ <mxCell id="ug50JPKoQ96zgBhktdCE-265" value="" style="endArrow=classic;html=1;strokeWidth=2;" parent="ug50JPKoQ96zgBhktdCE-256" edge="1">
38
+ <mxGeometry x="1294.4444444444443" y="400" width="45.11784511784512" height="45.833333333333336" as="geometry">
39
+ <mxPoint x="302.94875420875405" y="9" as="sourcePoint" />
40
+ <mxPoint x="349.03989898989903" y="9.482500000000073" as="targetPoint" />
41
+ </mxGeometry>
42
+ </mxCell>
43
+ <mxCell id="ug50JPKoQ96zgBhktdCE-266" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#3399FF;strokeColor=#b85450;points=[];strokeWidth=0;" parent="1" vertex="1">
44
+ <mxGeometry x="936.0312457912456" y="1598.7066666666667" width="38.35016835016835" height="4.583333333333333" as="geometry" />
45
+ </mxCell>
46
+ <mxCell id="ug50JPKoQ96zgBhktdCE-267" value="Period of time where a client&#39;s local state shows the sticky note with a &lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#3399ff&quot;&gt;blue&lt;/font&gt;&lt;/b&gt;&amp;nbsp;backgound" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeWidth=2;labelPosition=center;verticalLabelPosition=middle;" parent="1" vertex="1">
47
+ <mxGeometry x="994.6844444444442" y="1585.9983333333334" width="490" height="30" as="geometry" />
48
+ </mxCell>
49
+ <mxCell id="ug50JPKoQ96zgBhktdCE-140" value="" style="endArrow=none;html=1;exitX=0.875;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=2;" parent="1" edge="1">
50
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
51
+ <mxPoint x="936.5" y="1440.5" as="sourcePoint" />
52
+ <mxPoint x="1559" y="1441" as="targetPoint" />
53
+ </mxGeometry>
54
+ </mxCell>
55
+ <mxCell id="ug50JPKoQ96zgBhktdCE-142" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#3399FF;strokeColor=#b85450;points=[];strokeWidth=0;" parent="1" vertex="1">
56
+ <mxGeometry x="1079" y="1441" width="481" height="5" as="geometry" />
57
+ </mxCell>
58
+ <mxCell id="ug50JPKoQ96zgBhktdCE-143" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFD966;strokeColor=none;points=[];" parent="1" vertex="1">
59
+ <mxGeometry x="936.5" y="1441" width="142.5" height="5" as="geometry" />
60
+ </mxCell>
61
+ <mxCell id="ug50JPKoQ96zgBhktdCE-144" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#3399ff;strokeColor=#b85450;points=[];strokeWidth=0;" parent="1" vertex="1">
62
+ <mxGeometry x="1319" y="1281" width="240" height="5" as="geometry" />
63
+ </mxCell>
64
+ <mxCell id="ug50JPKoQ96zgBhktdCE-145" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FF6666;strokeColor=#b85450;points=[];strokeWidth=0;" parent="1" vertex="1">
65
+ <mxGeometry x="1000" y="1281" width="319" height="5" as="geometry" />
66
+ </mxCell>
67
+ <mxCell id="ug50JPKoQ96zgBhktdCE-146" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFD966;strokeColor=none;points=[];" parent="1" vertex="1">
68
+ <mxGeometry x="941.5" y="1281" width="58.5" height="5" as="geometry" />
69
+ </mxCell>
70
+ <mxCell id="ug50JPKoQ96zgBhktdCE-179" value="&lt;div&gt;Alice&lt;/div&gt;" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;strokeWidth=2;" parent="1" vertex="1">
71
+ <mxGeometry x="891.5" y="1251" width="25" height="50" as="geometry" />
72
+ </mxCell>
73
+ <mxCell id="ug50JPKoQ96zgBhktdCE-180" value="&lt;div&gt;Bob&lt;/div&gt;" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;strokeWidth=2;" parent="1" vertex="1">
74
+ <mxGeometry x="891.5" y="1411" width="25" height="50" as="geometry" />
75
+ </mxCell>
76
+ <mxCell id="ug50JPKoQ96zgBhktdCE-181" value="Service" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;strokeWidth=2;" parent="1" vertex="1">
77
+ <mxGeometry x="869" y="1331" width="70" height="60" as="geometry" />
78
+ </mxCell>
79
+ <mxCell id="ug50JPKoQ96zgBhktdCE-182" value="" style="endArrow=none;html=1;exitX=0.875;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=2;" parent="1" edge="1">
80
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
81
+ <mxPoint x="941.5" y="1280" as="sourcePoint" />
82
+ <mxPoint x="1559" y="1281" as="targetPoint" />
83
+ </mxGeometry>
84
+ </mxCell>
85
+ <mxCell id="ug50JPKoQ96zgBhktdCE-183" value="" style="endArrow=none;html=1;exitX=0.875;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;strokeWidth=2;" parent="1" edge="1">
86
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
87
+ <mxPoint x="936.5" y="1360.5" as="sourcePoint" />
88
+ <mxPoint x="1559" y="1361" as="targetPoint" />
89
+ </mxGeometry>
90
+ </mxCell>
91
+ <mxCell id="ug50JPKoQ96zgBhktdCE-184" value="Set color to red" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;size=20;position=0.5;base=10;strokeWidth=2;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
92
+ <mxGeometry x="956" y="1241" width="90" height="40" as="geometry" />
93
+ </mxCell>
94
+ <mxCell id="ug50JPKoQ96zgBhktdCE-185" value="" style="endArrow=classic;html=1;exitX=0;exitY=0;exitDx=40;exitDy=40;exitPerimeter=0;fillColor=#f8cecc;strokeColor=#b85450;strokeWidth=2;" parent="1" edge="1">
95
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
96
+ <mxPoint x="999" y="1281" as="sourcePoint" />
97
+ <mxPoint x="1119" y="1360" as="targetPoint" />
98
+ </mxGeometry>
99
+ </mxCell>
100
+ <mxCell id="ug50JPKoQ96zgBhktdCE-187" value="" style="endArrow=classic;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;strokeWidth=2;exitX=0.5;exitY=1.025;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="ug50JPKoQ96zgBhktdCE-189" edge="1">
101
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
102
+ <mxPoint x="1079" y="1481" as="sourcePoint" />
103
+ <mxPoint x="1199" y="1361" as="targetPoint" />
104
+ </mxGeometry>
105
+ </mxCell>
106
+ <mxCell id="ug50JPKoQ96zgBhktdCE-188" value="" style="endArrow=classic;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;strokeWidth=2;" parent="1" edge="1">
107
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
108
+ <mxPoint x="1199" y="1360" as="sourcePoint" />
109
+ <mxPoint x="1319" y="1281" as="targetPoint" />
110
+ </mxGeometry>
111
+ </mxCell>
112
+ <mxCell id="ug50JPKoQ96zgBhktdCE-189" value="" style="shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;size=20;position=0.5;base=10;strokeWidth=2;rotation=-180;flipH=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
113
+ <mxGeometry x="1030" y="1441" width="100" height="40" as="geometry" />
114
+ </mxCell>
115
+ <mxCell id="ug50JPKoQ96zgBhktdCE-190" value="Set color to blue" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeWidth=2;" parent="1" vertex="1">
116
+ <mxGeometry x="1025" y="1456" width="110" height="30" as="geometry" />
117
+ </mxCell>
118
+ <mxCell id="ug50JPKoQ96zgBhktdCE-206" value="A" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontStyle=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
119
+ <mxGeometry x="1230" y="1411" width="20" height="20" as="geometry" />
120
+ </mxCell>
121
+ <mxCell id="ug50JPKoQ96zgBhktdCE-186" value="" style="endArrow=classic;html=1;exitX=0;exitY=0;exitDx=40;exitDy=40;exitPerimeter=0;fillColor=#f8cecc;strokeColor=#b85450;strokeWidth=2;" parent="1" edge="1">
122
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
123
+ <mxPoint x="1119" y="1361" as="sourcePoint" />
124
+ <mxPoint x="1240" y="1440" as="targetPoint" />
125
+ </mxGeometry>
126
+ </mxCell>
127
+ <mxCell id="S-uX2zywk3RNg50cfgGr-1" value="" style="endArrow=classic;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;strokeWidth=2;" edge="1" parent="1">
128
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
129
+ <mxPoint x="1200" y="1361" as="sourcePoint" />
130
+ <mxPoint x="1320" y="1440" as="targetPoint" />
131
+ </mxGeometry>
132
+ </mxCell>
133
+ <mxCell id="S-uX2zywk3RNg50cfgGr-2" value="" style="endArrow=classic;html=1;fillColor=#f8cecc;strokeColor=#b85450;strokeWidth=2;" edge="1" parent="1">
134
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
135
+ <mxPoint x="1119" y="1360" as="sourcePoint" />
136
+ <mxPoint x="1239" y="1281" as="targetPoint" />
137
+ </mxGeometry>
138
+ </mxCell>
139
+ <mxCell id="S-uX2zywk3RNg50cfgGr-5" value="B" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fontStyle=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" vertex="1" parent="1">
140
+ <mxGeometry x="1309.5" y="1290" width="20" height="20" as="geometry" />
141
+ </mxCell>
142
+ </root>
143
+ </mxGraphModel>
144
+ </diagram>
145
+ </mxfile>
@@ -0,0 +1,344 @@
1
+ # Merge Semantics of Edits on Array Nodes
2
+
3
+ This document describes the semantics of edits that can be performed on array nodes.
4
+
5
+ Target audience: `SharedTree` users and maintainers.
6
+
7
+ > While this document is self-contained, we recommend reading about [SharedTree's approach to merge semantics](merge-semantics) first.
8
+
9
+ Each edit's merge semantics are defined in terms of the edit's preconditions and postconditions.
10
+ A precondition defines a requirement that must be met for the edit to be valid.
11
+ A postcondition defines a guarantee that is made about the effect of the edit.
12
+ (Invalid edits are ignored along with all other edits in the same transaction, and postconditions do not hold).
13
+
14
+ ## Key Challenges and Solutions
15
+
16
+ Before delving into the set editing operations supported by ShardTree arrays,
17
+ it's helpful to understand the key challenges that come up when users are allowed to concurrently edit the same array,
18
+ and how ShardTree arrays address these challenges.
19
+
20
+ ### Specifying the Location of Inserted Items
21
+
22
+ #### The Problem
23
+
24
+ Array operations that insert (or move in) array items take an integer that describes where in the array the new item(s) should be added.
25
+ For example, we can call `insertAt(1, "o")` to insert the value `"o"` in the array `["c", "a", "t"]` thus changing it to `["c", "o", "a", "t"]`.
26
+
27
+ In a collaborative editing environment,
28
+ it's possible for the state of the array to change between the time the edit is first created and the time it is applied.
29
+ Consider what would happen if the argument that describes the destination of the insert were to be treated as a fixed integer index:
30
+
31
+ Example 1:
32
+ * Starting state: `["c", "a", "t"]`
33
+ * Alice's edit: `insertAt(0, "r", "e", "d", " ")` with the expectation of getting `["r", "e", "d", " ", "c", "a", "t"]`.
34
+ * Bob's edit: `insertAt(1, "o")` with the expectation of getting `["c", "o", "a", "t"]`.
35
+
36
+ If Alice and Bob's edits are concurrent, and Alice's edit is sequenced first,
37
+ then inserting `"o"` at index 1 would yield `["r", "o", "e", "d", " ", "c", "a", "t"]`.
38
+ This would not truly match the intention of Bob,
39
+ who would likely have wanted to get `["r", "e", "d", " ", "c", "o", "a", "t"]` instead.
40
+
41
+ Example 2:
42
+ * Starting state: `["r", "e", "d", " ", "c", "a", "t"]`
43
+ * Alice's edit: `removeRange(0, 4)` with the expectation of getting `["c", "a", "t"]`.
44
+ * Bob's edit: `insertAt(5, "o")` with the expectation of getting `["r", "e", "d", " ", "c", "o", "a", "t"]`.
45
+
46
+ If Alice and Bob's edits are concurrent, and Alice's edit is sequenced first,
47
+ then inserting `"o"` at index 5 would either crash or yield `["c", "a", "t", "o"]`.
48
+ This would not truly match the intention of Bob,
49
+ who would likely have wanted to get `["c", "o", "a", "t"]` instead.
50
+
51
+ #### The Solution: Inserting in Gaps
52
+
53
+ Instead of treating the destination parameter of insert and move operations as a fixed insertion index,
54
+ SharedTree's array implementation interprets that parameter as referring to a gap in the array.
55
+
56
+ For example, in an array with two items `[A, B]` there are three gaps:
57
+ one before A, one between A and B, and one after C.
58
+ If we represented gaps with the `_` character, then would describe the array `[A, B]` as `[ _ A _ B _ ]`.
59
+ (More generally, an array with `K` items has `K+1` gaps.)
60
+
61
+ This means that calling `insertAt(1, "o")` on an array with initial state `["c", "a", "t"]`
62
+ singles out the following gap as the location to perform the insert: `["c" _ "a" "t"]`.
63
+ This conversion from index 1 to the corresponding gap is done at the time the edit is first created.
64
+ SharedTree's array implementation then keeps track of that gap's position when reconciling this insertion against concurrent edits.
65
+ Reusing the scenario from example 1 in the previous section,
66
+ the gap's position after reconciling with the concurrent edit from Alice (`insertAt(0, "r", "e", "d", " ")`)
67
+ is as follows: `["r" "e" "d" " " "c" _ "a" "t"]`,
68
+ thus yielding the adequate result after inserting "o" `["r", "e", "d", " ", "c", "o", "a", "t"]`.
69
+
70
+ #### Tie-Breaking
71
+
72
+ Note that multiple edits may concurrently attempt to insert or move in items into the same gap.
73
+ When that's the case,
74
+ the items end up ordered such that the items inserted by the edit that is sequenced earlier will appear after the items inserted by the edits that is sequenced later.
75
+
76
+ Example:
77
+ * Starting state: `[]`
78
+ * Edit 1: (concurrently to edits 2 and 3) insert items A and B (this changes the state from `[]` to `[A, B]`)
79
+ * Edit 2: (concurrently to edits 1 and 3) insert items R and S (this changes the state from `[]` to `[R, S]`)
80
+ * Edit 3: (concurrently to edits 1 and 2) insert items X and Y (this changes the state from `[]` to `[X, Y]`)
81
+
82
+ If the edits are sequenced in increasing order (i.e., edit 1, edit 2, edit 3),
83
+ then the resulting state will be `[X, Y, R, S, A, B]`.
84
+
85
+ #### Noteworthy Implications
86
+
87
+ Creating an edit that inserts items before or after an existing item in an array will not necessarily insert next to that item.
88
+ For example, inserting item X at the start of array `[Y, Z]` does not guarantee that X and Y will both appear together (in that order)
89
+ if other users make concurrent edits to the array.
90
+
91
+ Example 1: concurrent insert
92
+ * Starting state: `[Y, Z]`
93
+ * Alice's edit: insert A at the start of the array.
94
+ * Bob's edit: insert X at the start of the array.
95
+ If Alice's edit is sequenced before Bob's,
96
+ then the result will be `[X, A, Y, Z]`.
97
+
98
+ Example 2: concurrent remove
99
+ * Starting state: `[Y, Z]`
100
+ * Alice's edit: remove Y.
101
+ * Bob's edit: insert X at the start of the array.
102
+ No matter the order in which these edits are sequenced,
103
+ the result will be `[X, Z]`.
104
+
105
+ Example 3: concurrent move
106
+ * Starting state: `[Y, Z]`
107
+ * Alice's edit: move Y after Z.
108
+ * Bob's edit: insert X at the start of the array.
109
+ No matter the order in which these edits are sequenced,
110
+ the result will be `[X, Z, Y]`
111
+ as opposed to `[Z, X, Y]` which one might have expected if they thought of the insertion as happening "before Y".
112
+
113
+ The takeaway from these examples is that while it's tempting to think of an insertion as occurring before or after an existing item,
114
+ that doesn't quite match the merge semantics we have implemented.
115
+ If you find yourself wishing for different merge semantics please reach out to the Fluid team.
116
+
117
+ ### Specifying the Set of (Re)Moved Items
118
+
119
+ Each move or remove operations affects a specific set of array items.
120
+ When a single item is targeted,
121
+ the item can be specified using its index in the current state.
122
+ For example, removing the `"o"` from `["c", "o", "a", "t"]` with `removeAt(1)`.
123
+
124
+ When targeting multiple contiguous items,
125
+ it is possible specify them as a range.
126
+ For example, `"o"` and `"a"` from `["c", "o", "a", "t"]` with `removeRange(1, 3)`.
127
+
128
+ From the point of view of merge semantics,
129
+ calling `removeRange(1, 3)` is equivalent to individually removing each of the two middle letters in one transaction.
130
+ Using the range-based API is typically more convenient.
131
+ It is also optimized to have less overhead than making separate calls for each individual item.
132
+
133
+ The same is true for `moveRange` compared to `moveAt`,
134
+ with the additional property that `moveRange` preserves the order that the items are in at the time the edit is created.
135
+
136
+ Example:
137
+ * Starting state `[A, B, C]`
138
+ * Edit 1: `moveRange(0, 1, 2)` (move B in the gap before A, yielding `[B, A, C]`)
139
+ * Edit 2: `moveRange(3, 0, 2)` (move A and B in the gap after C, yielding `[C, A, B]`)
140
+
141
+ If edit 1 is sequenced first, then, when edit 2 is finally applied,
142
+ the state will change from `[B, A, C]` to `[C, A, B]`.
143
+ If edit 2 is sequenced first, then, when edit 1 is finally applied,
144
+ the state will change from `[C, A, B]`to `[B, C, A]`.
145
+
146
+ #### The Problem
147
+
148
+ In a collaborative editing environment,
149
+ it's possible for the state of the array to change between the time the edit is first created and the time it is applied.
150
+ Consider what would happen if the arguments that describe the affected items were to be treated as fixed integer indexes:
151
+ * Starting state: `["c", "o", "a", "t"]`
152
+ * Alice's edit: `insertAt(0, "r", "e", "d", " ")` with the expectation of getting `["r", "e", "d", " ", "c", "o", "a", "t"]`.
153
+ * Bob's edit: `removeAt(1)` with the expectation of getting `["c", "a", "t"]`.
154
+
155
+ If Alice and Bob's edits are concurrent, and Alice's edit is sequenced first,
156
+ then removing the item at index 1 would yield `["r", "d", " ", "c", "o", "a", "t"]`.
157
+ This would not truly match the intention of Bob,
158
+ who would likely have wanted to get `["r", "e", "d", " ", "c", "a", "t"]` instead.
159
+
160
+ #### The Solution: Targeting Items
161
+
162
+ Instead of treating the parameters of move and remove as a fixed index to detach items at,
163
+ SharedTree's array implementation interprets these parameter as referring to the items themselves.
164
+ In other words, `removeAt(1)` doesn't mean "remove whichever item happens to be at index 1 when the edit is applied".
165
+ Instead, it means "remove the specific item that is currently at index 1, no matter what index that item it at when the edit is applied".
166
+
167
+ #### Noteworthy Implications
168
+
169
+ Inserting items within a range that is concurrently being moved has no impact on the set of moved items.
170
+ For example, if one user moves items A and B to the end of array `[A, B, C]` by using a `sourceStart` of 0 and a `sourceEnd` of 2,
171
+ and some other user concurrently inserts some item X between A and B (thus changing the state to `[A, X, B, C]`),
172
+ then the move will still affect items A and B (and only these), thus yielding `[X, C, A, B]`.
173
+ This is true no matter how the concurrent edits are ordered.
174
+
175
+ If multiple users concurrently attempt to move the same item, the conflict is resolved in a last-write-wins fashion.
176
+ For example, if one user moves item B leftward to the start of array `[A, B, C]`,
177
+ and some other user concurrently moves item B rightward to the end of the array,
178
+ then the item will be affected by each successive move in sequencing order:
179
+ * If the leftward move is sequenced before the rightward move
180
+ then A will first be moved to the start (thus yielding `[B, A, C]`)
181
+ then moved to the end (thus yielding `[A, C, B]`).
182
+ * If the rightward move is sequenced before the leftward move
183
+ then A will first be moved to the end (thus yielding `[A, C, B]`)
184
+ then moved to the start (thus yielding `[B, A, C]`).
185
+
186
+ A removed item may be restored as a result of a concurrent move operation
187
+ and a moved item may be removed as a result of a concurrent remove operation.
188
+ For example, if one user moves item A to the end of array `[A, B, C]`,
189
+ and some other user concurrently removes item A,
190
+ then the item will be affected by each successive operation in sequencing order:
191
+ * If the move is sequenced before the remove
192
+ then A will first be moved to the end of the array (thus yielding `[C, B, A]`)
193
+ then removed (thus yielding `[C, B]`).
194
+ * If the remove is sequenced before the move
195
+ then A will first be removed (thus yielding `[C, B]`)
196
+ then moved (thus yielding `[C, B, A]`).
197
+
198
+ ## Core Editing Operations
199
+
200
+ ### `insertAt(gapIndex: number, ...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void`
201
+
202
+ Inserts new items at the location described by `gapIndex`.
203
+
204
+ Preconditions:
205
+ * There is no concurrent schema change edit that is sequenced before this one.
206
+ * The inserted values must have status `TreeStatus.New` or be primitives.
207
+ (This precondition will be removed soon)
208
+
209
+ Postconditions:
210
+ * The values are inserted in the targeted [gap](#location-of-inserted-items).
211
+
212
+ ### `moveRangeToIndex(destinationGap: number, sourceStart: number, sourceEnd: number, source: TMoveFrom): void`
213
+
214
+ Moves the specified items from the given source array to the desired location within the array.
215
+
216
+ Preconditions:
217
+ * There is no concurrent schema change edit that is sequenced before this one.
218
+
219
+ Postconditions:
220
+ * The [specified items](#specifying-the-set-of-removed-items) are moved to the targeted [gap](#location-of-inserted-items).
221
+
222
+ If multiple clients concurrently move an item,
223
+ then that item will be moved to the destination indicated by the move of the client whose edit is sequenced last.
224
+
225
+ ### `removeRange(start?: number, end?: number): void`
226
+
227
+ Removes the items between the specified indices.
228
+
229
+ Preconditions:
230
+ * There is no concurrent schema change edit that is sequenced before this one.
231
+
232
+ Postconditions:
233
+ * The [specified items](#specifying-the-set-of-removed-items) are removed.
234
+
235
+ Removed items are saved internally for a time in case they need to be restored as a result of an undo operation.
236
+ Changes made to them by concurrent edits will apply despite their removed status.
237
+
238
+ ## Other Operations
239
+
240
+ The following operations are just syntactic sugar:
241
+
242
+ `insertAtStart(...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void`
243
+ equates to `array.insertAt(0, ...value)`.
244
+
245
+ `insertAtEnd(...value: readonly (TNew | IterableTreeArrayContent<TNew>)[]): void`
246
+ equates to `array.insertAt(array.length, ...value)`.
247
+
248
+ `moveRangeToIndex(destinationGap: number, sourceStart: number, sourceEnd: number): void`
249
+ equates to `array.moveRangeToIndex(destinationGap, sourceStart, sourceEnd, array)`.
250
+
251
+ `moveRangeToStart(sourceStart: number, sourceEnd: number, source: TMoveFrom): void`
252
+ equates to `array.moveRangeToIndex(0, sourceStart, sourceEnd, source)`.
253
+
254
+ `moveRangeToStart(sourceStart: number, sourceEnd: number): void`
255
+ equates to `array.moveRangeToIndex(0, sourceStart, sourceEnd, array)`.
256
+
257
+ `moveToIndex(destinationGap: number, sourceIndex: number, source: TMoveFrom): void`
258
+ equates to `array.moveRangeToIndex(destinationGap, sourceIndex, sourceIndex+1, source)`.
259
+
260
+ `moveToIndex(destinationGap: number, sourceIndex: number): void`
261
+ equates to `array.moveRangeToIndex(destinationGap, sourceIndex, sourceIndex+1, array)`.
262
+
263
+ `moveToStart(sourceIndex: number, source: TMoveFrom): void`
264
+ equates to `array.moveRangeToIndex(0, sourceIndex, sourceIndex + 1, source)`.
265
+
266
+ `moveToStart(sourceIndex: number): void`
267
+ equates to `array.moveRangeToIndex(0, sourceIndex, sourceIndex + 1, array)`.
268
+
269
+ `moveRangeToEnd(sourceStart: number, sourceEnd: number, source: TMoveFrom): void`
270
+ equates to `array.moveRangeToIndex(array.length, sourceStart, sourceEnd, source)`.
271
+
272
+ `moveRangeToEnd(sourceStart: number, sourceEnd: number): void`
273
+ equates to `array.moveRangeToIndex(array.length, sourceStart, sourceEnd, array)`.
274
+
275
+ `moveToEnd(sourceIndex: number, source: TMoveFrom): void`
276
+ equates to `array.moveRangeToIndex(array.length, sourceIndex, sourceIndex + 1, source)`.
277
+
278
+ `moveToEnd(sourceIndex: number): void`
279
+ equates to `array.moveRangeToIndex(array.length, sourceIndex, sourceIndex + 1, array)`.
280
+
281
+ `removeAt(index: number): void`
282
+ equates to `array.removeRange(index, index + 1)`
283
+
284
+ ## Additional Notes
285
+
286
+ ### Operations on Removed Arrays
287
+
288
+ All of the above operations are effective even when the targeted array has been moved or removed.
289
+
290
+ ### Removing and Re-inserting Items
291
+
292
+ When dealing with plain JavaScript arrays,
293
+ it is possible to move items around by removing them and adding them back in.
294
+ For example, the item C can be moved to the start of the array `[A, B, C]` performing the following operations:
295
+ ```typescript
296
+ const C = array.pop(); // Remove C -> [A, B]
297
+ array.unshift(C); // Insert C at the start -> [C, A, B]
298
+ ```
299
+
300
+ As of October 2024, SharedTree arrays do not support this pattern because it would require (re)inserting item C, which has previously been inserted.
301
+ Instead, it is necessary to use the move operation:
302
+ ```typescript
303
+ array.moveToStart(2);
304
+ ```
305
+ Work is underway to address this lack of flexibility.
306
+
307
+ ### Replacing Items
308
+
309
+ When dealing with plain JavaScript arrays, it is possible to replace items.
310
+ For example, in array `[A, B, C]`,
311
+ the item B can be replaced with item X with [the `splice` method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice):
312
+ ```typescript
313
+ array.splice(1, 1, X);
314
+ ```
315
+ ...or simply by using the `=` operator:
316
+ ```typescript
317
+ array[1] = X;
318
+ ```
319
+
320
+ As of October 2024, SharedTree arrays do not support either of these approaches.
321
+ The closest alternative is to remove and insert items in two separate calls:
322
+ ```typescript
323
+ array.removeAt(1);
324
+ array.insertAt(1, X);
325
+ ```
326
+
327
+ Note that this approach may not yield ideal merge outcomes when it comes to concurrent insertions.
328
+
329
+ Example:
330
+ * Starting state: `["gold", "bronze"]`
331
+ * User 1: replace "gold" and "bronze" with "1st place" and "3rd place":
332
+ * `removeRange(0, 2)`
333
+ * `insertAt(0, "1st place", "3rd place")`
334
+ * User 2: insert "2nd place" between "gold" and "bronze":
335
+ * `insertAt(1, "2nd place")`
336
+ * Merge outcome: `["1st place", "3rd place", "2nd place"]`
337
+
338
+ This outcome is not consistent with the idea of replacement
339
+ which would have yielded `["1st place", "2nd place", "3rd place"]` instead.
340
+ This is because removing and inserting does not update the original items in place.
341
+ So we effectively end up with `["1st place", "3rd place", `~~`"gold"`~~`, "2nd place", `~~`"bronze"`~~`]`.
342
+
343
+ If in-place replacement is critical to you application's needs,
344
+ please reach out to the Fluid team.
@@ -0,0 +1,128 @@
1
+ # Merge Semantics of Edits on Map Nodes
2
+
3
+ This document describes the semantics of edits that can be performed on map nodes.
4
+
5
+ Target audience: `SharedTree` users and maintainers.
6
+
7
+ > While this document is self-contained, we recommend reading about [SharedTree's approach to merge semantics](merge-semantics) first.
8
+
9
+ Each edit's merge semantics are defined in terms of the edit's preconditions and postconditions.
10
+ A precondition defines a requirement that must be met for the edit to be valid.
11
+ A postcondition defines a guarantee that is made about the effect of the edit.
12
+ (Invalid edits are ignored along with all other edits in the same transaction, and postconditions do not hold).
13
+
14
+ ## `set(key: string, value: T): void`
15
+
16
+ Updates the value associated with the given key.
17
+
18
+ Examples:
19
+ ```typescript
20
+ users.set("bob", new User({ id: "bob", email: "bob@contoso.com" });
21
+ ```
22
+
23
+ ```typescript
24
+ partCounts.set("bolts", 42);
25
+ ```
26
+
27
+ Preconditions:
28
+ * There is no concurrent schema change edit that is sequenced before the `set` edit.
29
+ * The value on the right side of the `=` operator must have status `TreeStatus.New` or be a primitive.
30
+ (This precondition will be removed soon)
31
+
32
+ Postconditions:
33
+ * The given value is now associated with the given key.
34
+ * The value (if any) that was associated with the given key immediately prior to the application of the edit is removed (its status becomes `TreeStatus.Removed`).
35
+
36
+ ## `delete(key: string): void`
37
+
38
+ Clears any value associated with the given key.
39
+
40
+ ```typescript
41
+ users.delete("bob");
42
+ ```
43
+
44
+ Preconditions:
45
+ * There is no concurrent schema change edit that is sequenced before the `delete` edit.
46
+
47
+ Postconditions:
48
+ * There is no longer any value associated with the given key.
49
+ The value (if any) that was associated with the given key immediately prior to the application of the edit is removed (its status becomes `TreeStatus.Removed`).
50
+ Note: this will remove whatever value is associated with the key,
51
+ even if that value was changed by concurrent edits that were sequenced earlier.
52
+
53
+ Removed items are saved internally for a time in case they need to be restored as a result of an undo operation.
54
+ Changes made to them will apply despite their removed status.
55
+
56
+ ## Additional Notes
57
+
58
+ ### Operations on Removed Maps
59
+
60
+ All of the above operations are effective even when the targeted map has been moved or removed.
61
+
62
+ ### Last-Write-Wins Semantics
63
+
64
+ If multiple edits concurrently set the same key, then the key's final value will be that of the edit that is sequenced last.
65
+ In other words, the `set` operation has last-write-wins semantics.
66
+
67
+ Note that this means one user may overwrite a value set by another user without realizing it.
68
+ This is identical to the semantics of the `=` operator on object nodes.
69
+ Refer to its [Last-Write-Wins Semantics section](./object-merge-semantics.md#last-write-wins-semantics) for more details.
70
+
71
+ ### Delete Clears Whichever Value is Present
72
+
73
+ If user A calls `map.set("key", 42)` and user B concurrently calls `map.delete("key", 42)` on same map node,
74
+ then the outcome depends on the arbitrary ordering that is imposed by the sequencing service:
75
+ If the `delete` call is ordered before the `set` call, then the `set` will win out, setting the new associated value for that key.
76
+ If the `set` call is ordered before the `delete` call, then the `delete` will win out, clearing the associated value for that key.
77
+
78
+ This last point means that one user may end up deleting a value they have never seen.
79
+ Consider the following scenario:
80
+ * Starting state: `map.get("key")` is equal to `"foo"`
81
+ * Client A wants to replace the value `"foo"` with the value `"bar"` so they call `map.set("key", "bar")`.
82
+ * Client B wants to delete the value `"foo"` so they call `map.delete("key")`.
83
+
84
+ If these two edits are made concurrently,
85
+ and if client A's edit is sequenced before client B's edit,
86
+ then client B's edit will end up removing the value `"bar"`.
87
+ This is typically acceptable, but in cases where it proves problematic,
88
+ it's possible to put the `delete` operation in a transaction with a constraint that ensures the value to be deleted is still in the tree.
89
+
90
+ ### Removing and Re-inserting Nodes
91
+
92
+ When dealing with plain JavaScript maps,
93
+ it is possible to move items around by removing them and adding them back in.
94
+ For example, if some node N needs to be moved from `mapA` to `mapB`,
95
+ that can accomplished with the following operations:
96
+ ```typescript
97
+ const N = mapA.get(key);
98
+ mapA.delete(key); // Remove node N from mapA
99
+ mapB.set(key, N); // Insert node N into mapB
100
+ ```
101
+
102
+ Similarly, plain JavaScript maps allow moving a value from one key to another within the same map:
103
+ ```typescript
104
+ const N = mapA.get("foo");
105
+ mapA.delete("foo"); // Remove node N from mapA/key "foo"
106
+ mapA.set("bar", N); // Insert node N into mapA/key "bar"
107
+ ```
108
+
109
+ As of October 2024, SharedTree maps do not support these patterns because it would require (re)inserting node N, which has previously been inserted.
110
+ Note that even without this restriction, the above would not perform the desired change if some other user concurrently moved N from `mapA` to some other `mapC`.
111
+ If that were the case...
112
+ * Node N may no longer be in `mapA` by the time the edit `mapA.delete(key)` is applied.
113
+ At best that edit would have no effect, and at worst it may inadvertently remove some other node.
114
+ * Node N may still be in `mapC` by the time the edit `mapB.set(key, N)` is applied.
115
+ If so, this would lead to an error since a single node cannot reside in multiple maps at the same time.
116
+ (This would violate the requirement that the document remains tree-shaped).
117
+
118
+ Work is underway to address this lack of flexibility.
119
+
120
+ ### Clearing The Map
121
+
122
+ As of October 2024, there is no support for clearing the whole map in one operation.
123
+ If you find yourself wishing for such an operation, please reach out to the Fluid team.
124
+
125
+ Note that one client can, in a transaction, iterate through all existing key and use the `delete` operation on each of them.
126
+ This does not however guarantee that the map will be empty after the transaction is applied
127
+ because other users may have concurrently added entries to new keys.
128
+ This approach is also much less efficient than a `clear` operation would be since it needs to transmit the set of existing key over the network.
@@ -358,7 +358,7 @@ By contrast, `SharedTree`'s move semantics ensure that Bob's edit will be visibl
358
358
  In choosing the merge semantics of the set of edits initially supported by `SharedTree`,
359
359
  we have strived to keep the preconditions of those edits minimal.
360
360
  At this time, with the exception of [schema changes](#schema-changes), which have more preconditions,
361
- all supported edits have the same single precondition:
361
+ most supported edits have the same single precondition:
362
362
  the document schema must not have been concurrently changed.
363
363
 
364
364
  As illustrated [above](#preconditions),
@@ -428,7 +428,7 @@ A conditional postcondition is a postcondition of the form "If \<condition\> the
428
428
  (with any number of "else if" branches).
429
429
  For example, a remove edit that was designed not to affect concurrently moved nodes would be characterized as
430
430
  "If the node was concurrently moved then the node is unaffected, otherwise, the node is removed".
431
- After an edit with such a conditional postcondition is applied, it is not certain whether the targeted no will be removed or not.
431
+ After an edit with such a conditional postcondition is applied, it is not certain whether the targeted node will be removed or not.
432
432
 
433
433
  None of `SharedTree`'s currently supported edits have conditional postconditions.
434
434
  This means that every edit, so long as its preconditions are met, is guaranteed to always have the same effect.
@@ -526,4 +526,8 @@ The merge semantics will be improved in the future to be less conservative.
526
526
 
527
527
  ## Merge Semantics by Node Kind
528
528
 
529
- TODO: add a separate document for each node kind and link to them from here.
529
+ For specifics on the merge semantics of individual edits operations for each node type,
530
+
531
+ [Object Node](object-merge-semantics.md)
532
+ [Map Node](map-merge-semantics.md)
533
+ [Array Node](array-merge-semantics.md)