@fluidframework/tree 2.74.0-365691 → 2.74.0-370705

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 (1268) hide show
  1. package/.vscode/settings.json +2 -2
  2. package/api-report/tree.alpha.api.md +119 -85
  3. package/api-report/tree.beta.api.md +0 -1
  4. package/api-report/tree.legacy.beta.api.md +0 -1
  5. package/api-report/tree.legacy.public.api.md +0 -1
  6. package/api-report/tree.public.api.md +0 -1
  7. package/dist/alpha.d.ts +3 -2
  8. package/dist/codec/codec.d.ts +14 -1
  9. package/dist/codec/codec.d.ts.map +1 -1
  10. package/dist/codec/codec.js +11 -0
  11. package/dist/codec/codec.js.map +1 -1
  12. package/dist/codec/versioned/codec.d.ts +1 -1
  13. package/dist/codec/versioned/codec.d.ts.map +1 -1
  14. package/dist/codec/versioned/codec.js.map +1 -1
  15. package/dist/codec/versioned/format.d.ts +4 -1
  16. package/dist/codec/versioned/format.d.ts.map +1 -1
  17. package/dist/codec/versioned/format.js +4 -1
  18. package/dist/codec/versioned/format.js.map +1 -1
  19. package/dist/core/change-family/changeFamily.d.ts +4 -1
  20. package/dist/core/change-family/changeFamily.d.ts.map +1 -1
  21. package/dist/core/change-family/changeFamily.js.map +1 -1
  22. package/dist/core/change-family/index.d.ts +1 -1
  23. package/dist/core/change-family/index.d.ts.map +1 -1
  24. package/dist/core/change-family/index.js.map +1 -1
  25. package/dist/core/index.d.ts +3 -3
  26. package/dist/core/index.d.ts.map +1 -1
  27. package/dist/core/index.js +7 -4
  28. package/dist/core/index.js.map +1 -1
  29. package/dist/core/rebase/changeRebaser.d.ts +6 -1
  30. package/dist/core/rebase/changeRebaser.d.ts.map +1 -1
  31. package/dist/core/rebase/changeRebaser.js.map +1 -1
  32. package/dist/core/rebase/index.d.ts +1 -1
  33. package/dist/core/rebase/index.d.ts.map +1 -1
  34. package/dist/core/rebase/index.js +2 -1
  35. package/dist/core/rebase/index.js.map +1 -1
  36. package/dist/core/rebase/types.d.ts +2 -1
  37. package/dist/core/rebase/types.d.ts.map +1 -1
  38. package/dist/core/rebase/types.js +5 -1
  39. package/dist/core/rebase/types.js.map +1 -1
  40. package/dist/core/rebase/utils.d.ts.map +1 -1
  41. package/dist/core/rebase/utils.js +25 -7
  42. package/dist/core/rebase/utils.js.map +1 -1
  43. package/dist/core/tree/detachedFieldIndex.d.ts +40 -13
  44. package/dist/core/tree/detachedFieldIndex.d.ts.map +1 -1
  45. package/dist/core/tree/detachedFieldIndex.js +21 -12
  46. package/dist/core/tree/detachedFieldIndex.js.map +1 -1
  47. package/dist/core/tree/index.d.ts +4 -3
  48. package/dist/core/tree/index.d.ts.map +1 -1
  49. package/dist/core/tree/index.js +6 -2
  50. package/dist/core/tree/index.js.map +1 -1
  51. package/dist/core/tree/pathTree.d.ts +11 -3
  52. package/dist/core/tree/pathTree.d.ts.map +1 -1
  53. package/dist/core/tree/pathTree.js +14 -2
  54. package/dist/core/tree/pathTree.js.map +1 -1
  55. package/dist/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  56. package/dist/feature-libraries/chunked-forest/basicChunk.js +7 -0
  57. package/dist/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  58. package/dist/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
  59. package/dist/feature-libraries/chunked-forest/chunkTree.js +4 -1
  60. package/dist/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
  61. package/dist/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.d.ts +14 -6
  62. package/dist/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.d.ts.map +1 -1
  63. package/dist/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.js.map +1 -1
  64. package/dist/feature-libraries/chunked-forest/codec/schemaBasedEncode.js +7 -2
  65. package/dist/feature-libraries/chunked-forest/codec/schemaBasedEncode.js.map +1 -1
  66. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts +91 -42
  67. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  68. package/dist/feature-libraries/default-schema/defaultEditBuilder.js +238 -69
  69. package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  70. package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts +4 -4
  71. package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  72. package/dist/feature-libraries/default-schema/defaultFieldKinds.js +33 -28
  73. package/dist/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  74. package/dist/feature-libraries/default-schema/index.d.ts +2 -1
  75. package/dist/feature-libraries/default-schema/index.d.ts.map +1 -1
  76. package/dist/feature-libraries/default-schema/index.js +5 -2
  77. package/dist/feature-libraries/default-schema/index.js.map +1 -1
  78. package/dist/feature-libraries/default-schema/locationBasedEditBuilder.d.ts +36 -0
  79. package/dist/feature-libraries/default-schema/locationBasedEditBuilder.d.ts.map +1 -0
  80. package/dist/feature-libraries/default-schema/locationBasedEditBuilder.js +126 -0
  81. package/dist/feature-libraries/default-schema/locationBasedEditBuilder.js.map +1 -0
  82. package/dist/feature-libraries/default-schema/mappedEditBuilder.d.ts +7 -6
  83. package/dist/feature-libraries/default-schema/mappedEditBuilder.d.ts.map +1 -1
  84. package/dist/feature-libraries/default-schema/mappedEditBuilder.js +15 -0
  85. package/dist/feature-libraries/default-schema/mappedEditBuilder.js.map +1 -1
  86. package/dist/feature-libraries/deltaUtils.d.ts +1 -0
  87. package/dist/feature-libraries/deltaUtils.d.ts.map +1 -1
  88. package/dist/feature-libraries/deltaUtils.js +6 -1
  89. package/dist/feature-libraries/deltaUtils.js.map +1 -1
  90. package/dist/feature-libraries/detachedFieldIndexSummarizer.d.ts +30 -8
  91. package/dist/feature-libraries/detachedFieldIndexSummarizer.d.ts.map +1 -1
  92. package/dist/feature-libraries/detachedFieldIndexSummarizer.js +41 -11
  93. package/dist/feature-libraries/detachedFieldIndexSummarizer.js.map +1 -1
  94. package/dist/feature-libraries/flex-tree/context.d.ts +9 -0
  95. package/dist/feature-libraries/flex-tree/context.d.ts.map +1 -1
  96. package/dist/feature-libraries/flex-tree/context.js +6 -0
  97. package/dist/feature-libraries/flex-tree/context.js.map +1 -1
  98. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +6 -6
  99. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  100. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  101. package/dist/feature-libraries/flex-tree/lazyField.d.ts +8 -7
  102. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  103. package/dist/feature-libraries/flex-tree/lazyField.js +37 -8
  104. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  105. package/dist/feature-libraries/forest-summary/codec.d.ts +2 -2
  106. package/dist/feature-libraries/forest-summary/codec.d.ts.map +1 -1
  107. package/dist/feature-libraries/forest-summary/codec.js +4 -4
  108. package/dist/feature-libraries/forest-summary/codec.js.map +1 -1
  109. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts +9 -13
  110. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  111. package/dist/feature-libraries/forest-summary/forestSummarizer.js +21 -26
  112. package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  113. package/dist/feature-libraries/forest-summary/format.d.ts +41 -5
  114. package/dist/feature-libraries/forest-summary/format.d.ts.map +1 -1
  115. package/dist/feature-libraries/forest-summary/format.js +7 -7
  116. package/dist/feature-libraries/forest-summary/format.js.map +1 -1
  117. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts +11 -9
  118. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts.map +1 -1
  119. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.js +16 -29
  120. package/dist/feature-libraries/forest-summary/incrementalSummaryBuilder.js.map +1 -1
  121. package/dist/feature-libraries/forest-summary/index.d.ts +2 -1
  122. package/dist/feature-libraries/forest-summary/index.d.ts.map +1 -1
  123. package/dist/feature-libraries/forest-summary/index.js +3 -2
  124. package/dist/feature-libraries/forest-summary/index.js.map +1 -1
  125. package/dist/feature-libraries/forest-summary/summaryTypes.d.ts +47 -0
  126. package/dist/feature-libraries/forest-summary/summaryTypes.d.ts.map +1 -0
  127. package/dist/feature-libraries/forest-summary/summaryTypes.js +57 -0
  128. package/dist/feature-libraries/forest-summary/summaryTypes.js.map +1 -0
  129. package/dist/feature-libraries/index.d.ts +4 -4
  130. package/dist/feature-libraries/index.d.ts.map +1 -1
  131. package/dist/feature-libraries/index.js +8 -3
  132. package/dist/feature-libraries/index.js.map +1 -1
  133. package/dist/feature-libraries/mapTreeCursor.d.ts.map +1 -1
  134. package/dist/feature-libraries/mapTreeCursor.js +1 -0
  135. package/dist/feature-libraries/mapTreeCursor.js.map +1 -1
  136. package/dist/feature-libraries/mitigatedChangeFamily.d.ts.map +1 -1
  137. package/dist/feature-libraries/mitigatedChangeFamily.js +2 -2
  138. package/dist/feature-libraries/mitigatedChangeFamily.js.map +1 -1
  139. package/dist/feature-libraries/modular-schema/comparison.d.ts +18 -2
  140. package/dist/feature-libraries/modular-schema/comparison.d.ts.map +1 -1
  141. package/dist/feature-libraries/modular-schema/comparison.js +54 -3
  142. package/dist/feature-libraries/modular-schema/comparison.js.map +1 -1
  143. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +97 -21
  144. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  145. package/dist/feature-libraries/modular-schema/crossFieldQueries.js +4 -7
  146. package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  147. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +20 -52
  148. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  149. package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  150. package/dist/feature-libraries/modular-schema/fieldKind.d.ts +25 -13
  151. package/dist/feature-libraries/modular-schema/fieldKind.d.ts.map +1 -1
  152. package/dist/feature-libraries/modular-schema/fieldKind.js +0 -21
  153. package/dist/feature-libraries/modular-schema/fieldKind.js.map +1 -1
  154. package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  155. package/dist/feature-libraries/modular-schema/genericFieldKind.js +7 -10
  156. package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  157. package/dist/feature-libraries/modular-schema/genericFieldKindCodecs.js +2 -2
  158. package/dist/feature-libraries/modular-schema/genericFieldKindCodecs.js.map +1 -1
  159. package/dist/feature-libraries/modular-schema/index.d.ts +6 -6
  160. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  161. package/dist/feature-libraries/modular-schema/index.js +13 -8
  162. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  163. package/dist/feature-libraries/modular-schema/modularChangeCodecV1.d.ts +17 -0
  164. package/dist/feature-libraries/modular-schema/modularChangeCodecV1.d.ts.map +1 -0
  165. package/dist/feature-libraries/modular-schema/modularChangeCodecV1.js +388 -0
  166. package/dist/feature-libraries/modular-schema/modularChangeCodecV1.js.map +1 -0
  167. package/dist/feature-libraries/modular-schema/modularChangeCodecV2.d.ts +17 -0
  168. package/dist/feature-libraries/modular-schema/modularChangeCodecV2.d.ts.map +1 -0
  169. package/dist/feature-libraries/modular-schema/modularChangeCodecV2.js +413 -0
  170. package/dist/feature-libraries/modular-schema/modularChangeCodecV2.js.map +1 -0
  171. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts +2 -2
  172. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  173. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +8 -284
  174. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  175. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +49 -15
  176. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  177. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +1306 -465
  178. package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  179. package/dist/feature-libraries/modular-schema/{modularChangeFormat.d.ts → modularChangeFormatV1.d.ts} +2 -2
  180. package/dist/feature-libraries/modular-schema/modularChangeFormatV1.d.ts.map +1 -0
  181. package/dist/feature-libraries/modular-schema/{modularChangeFormat.js → modularChangeFormatV1.js} +5 -5
  182. package/dist/feature-libraries/modular-schema/modularChangeFormatV1.js.map +1 -0
  183. package/dist/feature-libraries/modular-schema/modularChangeFormatV2.d.ts +146 -0
  184. package/dist/feature-libraries/modular-schema/modularChangeFormatV2.d.ts.map +1 -0
  185. package/dist/feature-libraries/modular-schema/modularChangeFormatV2.js +32 -0
  186. package/dist/feature-libraries/modular-schema/modularChangeFormatV2.js.map +1 -0
  187. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +50 -10
  188. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  189. package/dist/feature-libraries/modular-schema/modularChangeTypes.js +24 -3
  190. package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  191. package/dist/feature-libraries/optional-field/index.d.ts +2 -2
  192. package/dist/feature-libraries/optional-field/index.d.ts.map +1 -1
  193. package/dist/feature-libraries/optional-field/index.js +1 -2
  194. package/dist/feature-libraries/optional-field/index.js.map +1 -1
  195. package/dist/feature-libraries/optional-field/optionalField.d.ts +5 -26
  196. package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  197. package/dist/feature-libraries/optional-field/optionalField.js +217 -451
  198. package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
  199. package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts +23 -0
  200. package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts.map +1 -0
  201. package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.js +31 -0
  202. package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.js.map +1 -0
  203. package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts +24 -33
  204. package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts.map +1 -1
  205. package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.js.map +1 -1
  206. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.d.ts +1 -1
  207. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.d.ts.map +1 -1
  208. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.js +57 -28
  209. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.js.map +1 -1
  210. package/dist/feature-libraries/optional-field/optionalFieldCodecV3.d.ts +12 -0
  211. package/dist/feature-libraries/optional-field/optionalFieldCodecV3.d.ts.map +1 -0
  212. package/dist/feature-libraries/optional-field/optionalFieldCodecV3.js +57 -0
  213. package/dist/feature-libraries/optional-field/optionalFieldCodecV3.js.map +1 -0
  214. package/dist/feature-libraries/optional-field/optionalFieldCodecs.d.ts.map +1 -1
  215. package/dist/feature-libraries/optional-field/optionalFieldCodecs.js +5 -1
  216. package/dist/feature-libraries/optional-field/optionalFieldCodecs.js.map +1 -1
  217. package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts +27 -8
  218. package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
  219. package/dist/feature-libraries/schema-index/schemaSummarizer.js +42 -16
  220. package/dist/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
  221. package/dist/feature-libraries/sequence-field/compose.d.ts +6 -7
  222. package/dist/feature-libraries/sequence-field/compose.d.ts.map +1 -1
  223. package/dist/feature-libraries/sequence-field/compose.js +80 -256
  224. package/dist/feature-libraries/sequence-field/compose.js.map +1 -1
  225. package/dist/feature-libraries/sequence-field/helperTypes.d.ts +14 -10
  226. package/dist/feature-libraries/sequence-field/helperTypes.d.ts.map +1 -1
  227. package/dist/feature-libraries/sequence-field/helperTypes.js.map +1 -1
  228. package/dist/feature-libraries/sequence-field/index.d.ts +2 -3
  229. package/dist/feature-libraries/sequence-field/index.d.ts.map +1 -1
  230. package/dist/feature-libraries/sequence-field/index.js +1 -3
  231. package/dist/feature-libraries/sequence-field/index.js.map +1 -1
  232. package/dist/feature-libraries/sequence-field/invert.d.ts +3 -3
  233. package/dist/feature-libraries/sequence-field/invert.d.ts.map +1 -1
  234. package/dist/feature-libraries/sequence-field/invert.js +65 -167
  235. package/dist/feature-libraries/sequence-field/invert.js.map +1 -1
  236. package/dist/feature-libraries/sequence-field/markQueue.d.ts +2 -2
  237. package/dist/feature-libraries/sequence-field/markQueue.d.ts.map +1 -1
  238. package/dist/feature-libraries/sequence-field/markQueue.js.map +1 -1
  239. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts +4 -56
  240. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  241. package/dist/feature-libraries/sequence-field/moveEffectTable.js +7 -86
  242. package/dist/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  243. package/dist/feature-libraries/sequence-field/rebase.d.ts +3 -3
  244. package/dist/feature-libraries/sequence-field/rebase.d.ts.map +1 -1
  245. package/dist/feature-libraries/sequence-field/rebase.js +106 -112
  246. package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
  247. package/dist/feature-libraries/sequence-field/replaceRevisions.d.ts.map +1 -1
  248. package/dist/feature-libraries/sequence-field/replaceRevisions.js +16 -33
  249. package/dist/feature-libraries/sequence-field/replaceRevisions.js.map +1 -1
  250. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  251. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +0 -2
  252. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  253. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +22 -4
  254. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
  255. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js +358 -179
  256. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  257. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
  258. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js +20 -60
  259. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
  260. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.d.ts +2 -2
  261. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.d.ts.map +1 -1
  262. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.js +10 -10
  263. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.js.map +1 -1
  264. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +3 -2
  265. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  266. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js +14 -109
  267. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  268. package/dist/feature-libraries/sequence-field/types.d.ts +30 -59
  269. package/dist/feature-libraries/sequence-field/types.d.ts.map +1 -1
  270. package/dist/feature-libraries/sequence-field/types.js.map +1 -1
  271. package/dist/feature-libraries/sequence-field/utils.d.ts +15 -24
  272. package/dist/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  273. package/dist/feature-libraries/sequence-field/utils.js +111 -299
  274. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  275. package/dist/index.d.ts +1 -1
  276. package/dist/index.d.ts.map +1 -1
  277. package/dist/index.js +3 -3
  278. package/dist/index.js.map +1 -1
  279. package/dist/packageVersion.d.ts +1 -1
  280. package/dist/packageVersion.js +1 -1
  281. package/dist/packageVersion.js.map +1 -1
  282. package/dist/shared-tree/independentView.d.ts +1 -1
  283. package/dist/shared-tree/independentView.d.ts.map +1 -1
  284. package/dist/shared-tree/independentView.js.map +1 -1
  285. package/dist/shared-tree/index.d.ts +1 -1
  286. package/dist/shared-tree/index.d.ts.map +1 -1
  287. package/dist/shared-tree/index.js.map +1 -1
  288. package/dist/shared-tree/schematizeTree.d.ts +4 -4
  289. package/dist/shared-tree/schematizeTree.d.ts.map +1 -1
  290. package/dist/shared-tree/schematizeTree.js +2 -1
  291. package/dist/shared-tree/schematizeTree.js.map +1 -1
  292. package/dist/shared-tree/schematizingTreeView.d.ts +1 -5
  293. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  294. package/dist/shared-tree/schematizingTreeView.js +32 -33
  295. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  296. package/dist/shared-tree/sharedTree.d.ts +11 -5
  297. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  298. package/dist/shared-tree/sharedTree.js +14 -4
  299. package/dist/shared-tree/sharedTree.js.map +1 -1
  300. package/dist/shared-tree/sharedTreeChangeCodecs.d.ts +1 -1
  301. package/dist/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
  302. package/dist/shared-tree/sharedTreeChangeCodecs.js +1 -0
  303. package/dist/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
  304. package/dist/shared-tree/sharedTreeChangeEnricher.d.ts +20 -8
  305. package/dist/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
  306. package/dist/shared-tree/sharedTreeChangeEnricher.js +26 -12
  307. package/dist/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
  308. package/dist/shared-tree/sharedTreeChangeFamily.d.ts +5 -5
  309. package/dist/shared-tree/sharedTreeChangeFamily.d.ts.map +1 -1
  310. package/dist/shared-tree/sharedTreeChangeFamily.js +10 -4
  311. package/dist/shared-tree/sharedTreeChangeFamily.js.map +1 -1
  312. package/dist/shared-tree/sharedTreeEditBuilder.d.ts +16 -6
  313. package/dist/shared-tree/sharedTreeEditBuilder.d.ts.map +1 -1
  314. package/dist/shared-tree/sharedTreeEditBuilder.js +14 -7
  315. package/dist/shared-tree/sharedTreeEditBuilder.js.map +1 -1
  316. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  317. package/dist/shared-tree/treeAlpha.js +1 -1
  318. package/dist/shared-tree/treeAlpha.js.map +1 -1
  319. package/dist/shared-tree/treeCheckout.d.ts +12 -10
  320. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  321. package/dist/shared-tree/treeCheckout.js +66 -17
  322. package/dist/shared-tree/treeCheckout.js.map +1 -1
  323. package/dist/shared-tree-core/branch.d.ts +3 -2
  324. package/dist/shared-tree-core/branch.d.ts.map +1 -1
  325. package/dist/shared-tree-core/branch.js +4 -3
  326. package/dist/shared-tree-core/branch.js.map +1 -1
  327. package/dist/shared-tree-core/editManager.d.ts +2 -2
  328. package/dist/shared-tree-core/editManager.d.ts.map +1 -1
  329. package/dist/shared-tree-core/editManager.js +9 -9
  330. package/dist/shared-tree-core/editManager.js.map +1 -1
  331. package/dist/shared-tree-core/editManagerCodecs.d.ts +4 -0
  332. package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  333. package/dist/shared-tree-core/editManagerCodecs.js +16 -6
  334. package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
  335. package/{lib/shared-tree-core/editManagerCodecsV5.d.ts → dist/shared-tree-core/editManagerCodecsVSharedBranches.d.ts} +3 -3
  336. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.d.ts.map +1 -0
  337. package/dist/shared-tree-core/{editManagerCodecsV5.js → editManagerCodecsVSharedBranches.js} +7 -7
  338. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.js.map +1 -0
  339. package/dist/shared-tree-core/editManagerFormatCommons.d.ts +20 -6
  340. package/dist/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
  341. package/dist/shared-tree-core/editManagerFormatCommons.js +22 -7
  342. package/dist/shared-tree-core/editManagerFormatCommons.js.map +1 -1
  343. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts +2 -2
  344. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
  345. package/dist/shared-tree-core/editManagerFormatV1toV4.js +1 -0
  346. package/dist/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
  347. package/dist/shared-tree-core/{editManagerFormatV5.d.ts → editManagerFormatVSharedBranches.d.ts} +3 -3
  348. package/dist/shared-tree-core/editManagerFormatVSharedBranches.d.ts.map +1 -0
  349. package/dist/shared-tree-core/{editManagerFormatV5.js → editManagerFormatVSharedBranches.js} +2 -2
  350. package/dist/shared-tree-core/editManagerFormatVSharedBranches.js.map +1 -0
  351. package/dist/shared-tree-core/editManagerSummarizer.d.ts +29 -9
  352. package/dist/shared-tree-core/editManagerSummarizer.d.ts.map +1 -1
  353. package/dist/shared-tree-core/editManagerSummarizer.js +41 -13
  354. package/dist/shared-tree-core/editManagerSummarizer.js.map +1 -1
  355. package/dist/shared-tree-core/index.d.ts +5 -3
  356. package/dist/shared-tree-core/index.d.ts.map +1 -1
  357. package/dist/shared-tree-core/index.js +8 -1
  358. package/dist/shared-tree-core/index.js.map +1 -1
  359. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts +1 -1
  360. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
  361. package/dist/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
  362. package/{lib/shared-tree-core/messageCodecV5.d.ts → dist/shared-tree-core/messageCodecVSharedBranches.d.ts} +2 -2
  363. package/dist/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -0
  364. package/dist/shared-tree-core/{messageCodecV5.js → messageCodecVSharedBranches.js} +6 -6
  365. package/dist/shared-tree-core/messageCodecVSharedBranches.js.map +1 -0
  366. package/dist/shared-tree-core/messageCodecs.d.ts +4 -0
  367. package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
  368. package/dist/shared-tree-core/messageCodecs.js +16 -6
  369. package/dist/shared-tree-core/messageCodecs.js.map +1 -1
  370. package/dist/shared-tree-core/messageFormat.d.ts +20 -6
  371. package/dist/shared-tree-core/messageFormat.d.ts.map +1 -1
  372. package/dist/shared-tree-core/messageFormat.js +22 -7
  373. package/dist/shared-tree-core/messageFormat.js.map +1 -1
  374. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts +3 -2
  375. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
  376. package/dist/shared-tree-core/messageFormatV1ToV4.js +8 -1
  377. package/dist/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
  378. package/dist/shared-tree-core/{messageFormatV5.d.ts → messageFormatVSharedBranches.d.ts} +5 -7
  379. package/dist/shared-tree-core/messageFormatVSharedBranches.d.ts.map +1 -0
  380. package/dist/shared-tree-core/{messageFormatV5.js → messageFormatVSharedBranches.js} +3 -2
  381. package/dist/shared-tree-core/messageFormatVSharedBranches.js.map +1 -0
  382. package/dist/shared-tree-core/sharedTreeCore.d.ts +14 -47
  383. package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  384. package/dist/shared-tree-core/sharedTreeCore.js +30 -18
  385. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  386. package/dist/shared-tree-core/summaryTypes.d.ts +94 -0
  387. package/dist/shared-tree-core/summaryTypes.d.ts.map +1 -0
  388. package/dist/shared-tree-core/summaryTypes.js +47 -0
  389. package/dist/shared-tree-core/summaryTypes.js.map +1 -0
  390. package/dist/shared-tree-core/versionedSummarizer.d.ts +67 -0
  391. package/dist/shared-tree-core/versionedSummarizer.d.ts.map +1 -0
  392. package/dist/shared-tree-core/versionedSummarizer.js +63 -0
  393. package/dist/shared-tree-core/versionedSummarizer.js.map +1 -0
  394. package/dist/simple-tree/api/configuration.d.ts +3 -26
  395. package/dist/simple-tree/api/configuration.d.ts.map +1 -1
  396. package/dist/simple-tree/api/configuration.js +10 -21
  397. package/dist/simple-tree/api/configuration.js.map +1 -1
  398. package/dist/simple-tree/api/dirtyIndex.d.ts +11 -0
  399. package/dist/simple-tree/api/dirtyIndex.d.ts.map +1 -1
  400. package/dist/simple-tree/api/dirtyIndex.js +7 -0
  401. package/dist/simple-tree/api/dirtyIndex.js.map +1 -1
  402. package/dist/simple-tree/api/discrepancies.d.ts +1 -1
  403. package/dist/simple-tree/api/discrepancies.d.ts.map +1 -1
  404. package/dist/simple-tree/api/discrepancies.js.map +1 -1
  405. package/dist/simple-tree/api/getSimpleSchema.d.ts +3 -3
  406. package/dist/simple-tree/api/getSimpleSchema.d.ts.map +1 -1
  407. package/dist/simple-tree/api/getSimpleSchema.js +9 -3
  408. package/dist/simple-tree/api/getSimpleSchema.js.map +1 -1
  409. package/dist/simple-tree/api/incrementalAllowedTypes.d.ts +1 -1
  410. package/dist/simple-tree/api/incrementalAllowedTypes.d.ts.map +1 -1
  411. package/dist/simple-tree/api/incrementalAllowedTypes.js +7 -0
  412. package/dist/simple-tree/api/incrementalAllowedTypes.js.map +1 -1
  413. package/dist/simple-tree/api/index.d.ts +3 -4
  414. package/dist/simple-tree/api/index.d.ts.map +1 -1
  415. package/dist/simple-tree/api/index.js +4 -5
  416. package/dist/simple-tree/api/index.js.map +1 -1
  417. package/dist/simple-tree/api/schemaCompatibilityTester.d.ts +1 -1
  418. package/dist/simple-tree/api/schemaCompatibilityTester.d.ts.map +1 -1
  419. package/dist/simple-tree/api/schemaCompatibilityTester.js.map +1 -1
  420. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts +5 -5
  421. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
  422. package/dist/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
  423. package/dist/simple-tree/api/schemaFactoryRecursive.d.ts.map +1 -1
  424. package/dist/simple-tree/api/schemaFactoryRecursive.js +0 -1
  425. package/dist/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
  426. package/dist/simple-tree/api/schemaFromSimple.d.ts +6 -1
  427. package/dist/simple-tree/api/schemaFromSimple.d.ts.map +1 -1
  428. package/dist/simple-tree/api/schemaFromSimple.js +5 -0
  429. package/dist/simple-tree/api/schemaFromSimple.js.map +1 -1
  430. package/dist/simple-tree/api/schemaStatics.d.ts +12 -12
  431. package/dist/simple-tree/api/simpleSchemaCodec.d.ts +15 -3
  432. package/dist/simple-tree/api/simpleSchemaCodec.d.ts.map +1 -1
  433. package/dist/simple-tree/api/simpleSchemaCodec.js +18 -6
  434. package/dist/simple-tree/api/simpleSchemaCodec.js.map +1 -1
  435. package/dist/simple-tree/api/simpleSchemaToJsonSchema.d.ts +1 -1
  436. package/dist/simple-tree/api/simpleSchemaToJsonSchema.d.ts.map +1 -1
  437. package/dist/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
  438. package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts +8 -1
  439. package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts.map +1 -1
  440. package/dist/simple-tree/api/snapshotCompatibilityChecker.js +13 -8
  441. package/dist/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
  442. package/dist/simple-tree/api/typesUnsafe.d.ts +3 -3
  443. package/dist/simple-tree/api/typesUnsafe.d.ts.map +1 -1
  444. package/dist/simple-tree/api/typesUnsafe.js.map +1 -1
  445. package/dist/simple-tree/core/allowedTypes.d.ts +2 -2
  446. package/dist/simple-tree/core/allowedTypes.d.ts.map +1 -1
  447. package/dist/simple-tree/core/allowedTypes.js.map +1 -1
  448. package/dist/simple-tree/core/index.d.ts +1 -1
  449. package/dist/simple-tree/core/index.d.ts.map +1 -1
  450. package/dist/simple-tree/core/index.js +2 -3
  451. package/dist/simple-tree/core/index.js.map +1 -1
  452. package/dist/simple-tree/core/toStored.d.ts +17 -15
  453. package/dist/simple-tree/core/toStored.d.ts.map +1 -1
  454. package/dist/simple-tree/core/toStored.js +5 -40
  455. package/dist/simple-tree/core/toStored.js.map +1 -1
  456. package/dist/simple-tree/core/unhydratedFlexTree.d.ts +15 -15
  457. package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  458. package/dist/simple-tree/core/unhydratedFlexTree.js +59 -8
  459. package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  460. package/dist/simple-tree/core/walkSchema.d.ts.map +1 -1
  461. package/dist/simple-tree/core/walkSchema.js +4 -0
  462. package/dist/simple-tree/core/walkSchema.js.map +1 -1
  463. package/dist/simple-tree/createContext.d.ts.map +1 -1
  464. package/dist/simple-tree/createContext.js +20 -5
  465. package/dist/simple-tree/createContext.js.map +1 -1
  466. package/dist/simple-tree/fieldSchema.d.ts +7 -7
  467. package/dist/simple-tree/fieldSchema.d.ts.map +1 -1
  468. package/dist/simple-tree/fieldSchema.js.map +1 -1
  469. package/dist/simple-tree/index.d.ts +8 -7
  470. package/dist/simple-tree/index.d.ts.map +1 -1
  471. package/dist/simple-tree/index.js +15 -12
  472. package/dist/simple-tree/index.js.map +1 -1
  473. package/dist/simple-tree/leafNodeSchema.d.ts +5 -5
  474. package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
  475. package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  476. package/dist/simple-tree/node-kinds/array/arrayNode.js +5 -3
  477. package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  478. package/dist/simple-tree/node-kinds/array/arrayNodeTypes.d.ts +3 -3
  479. package/dist/simple-tree/node-kinds/array/arrayNodeTypes.d.ts.map +1 -1
  480. package/dist/simple-tree/node-kinds/array/arrayNodeTypes.js.map +1 -1
  481. package/dist/simple-tree/node-kinds/common.d.ts.map +1 -1
  482. package/dist/simple-tree/node-kinds/common.js +1 -1
  483. package/dist/simple-tree/node-kinds/common.js.map +1 -1
  484. package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  485. package/dist/simple-tree/node-kinds/map/mapNode.js +2 -2
  486. package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  487. package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts +3 -3
  488. package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
  489. package/dist/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
  490. package/dist/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  491. package/dist/simple-tree/node-kinds/object/objectNode.js +18 -18
  492. package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  493. package/dist/simple-tree/node-kinds/object/objectNodeTypes.d.ts +2 -2
  494. package/dist/simple-tree/node-kinds/object/objectNodeTypes.d.ts.map +1 -1
  495. package/dist/simple-tree/node-kinds/object/objectNodeTypes.js.map +1 -1
  496. package/dist/simple-tree/node-kinds/record/recordNode.d.ts.map +1 -1
  497. package/dist/simple-tree/node-kinds/record/recordNode.js +4 -2
  498. package/dist/simple-tree/node-kinds/record/recordNode.js.map +1 -1
  499. package/dist/simple-tree/node-kinds/record/recordNodeTypes.d.ts +3 -3
  500. package/dist/simple-tree/node-kinds/record/recordNodeTypes.d.ts.map +1 -1
  501. package/dist/simple-tree/node-kinds/record/recordNodeTypes.js.map +1 -1
  502. package/dist/simple-tree/prepareForInsertion.d.ts +54 -47
  503. package/dist/simple-tree/prepareForInsertion.d.ts.map +1 -1
  504. package/dist/simple-tree/prepareForInsertion.js +183 -125
  505. package/dist/simple-tree/prepareForInsertion.js.map +1 -1
  506. package/dist/simple-tree/simpleSchema.d.ts +55 -23
  507. package/dist/simple-tree/simpleSchema.d.ts.map +1 -1
  508. package/dist/simple-tree/simpleSchema.js +17 -0
  509. package/dist/simple-tree/simpleSchema.js.map +1 -1
  510. package/dist/simple-tree/simpleSchemaFormatV1.d.ts +1 -1
  511. package/dist/simple-tree/simpleSchemaFormatV1.d.ts.map +1 -1
  512. package/dist/simple-tree/simpleSchemaFormatV1.js +8 -1
  513. package/dist/simple-tree/simpleSchemaFormatV1.js.map +1 -1
  514. package/dist/simple-tree/toStoredSchema.d.ts +58 -11
  515. package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
  516. package/dist/simple-tree/toStoredSchema.js +205 -30
  517. package/dist/simple-tree/toStoredSchema.js.map +1 -1
  518. package/dist/simple-tree/treeSchema.d.ts +23 -0
  519. package/dist/simple-tree/treeSchema.d.ts.map +1 -0
  520. package/dist/simple-tree/treeSchema.js +25 -0
  521. package/dist/simple-tree/treeSchema.js.map +1 -0
  522. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts +13 -4
  523. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -1
  524. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js +29 -11
  525. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -1
  526. package/dist/tableSchema.d.ts +117 -63
  527. package/dist/tableSchema.d.ts.map +1 -1
  528. package/dist/tableSchema.js +159 -58
  529. package/dist/tableSchema.js.map +1 -1
  530. package/dist/treeFactory.d.ts.map +1 -1
  531. package/dist/treeFactory.js +17 -3
  532. package/dist/treeFactory.js.map +1 -1
  533. package/dist/util/index.d.ts +2 -1
  534. package/dist/util/index.d.ts.map +1 -1
  535. package/dist/util/index.js +4 -1
  536. package/dist/util/index.js.map +1 -1
  537. package/dist/util/rangeMap.d.ts +24 -12
  538. package/dist/util/rangeMap.d.ts.map +1 -1
  539. package/dist/util/rangeMap.js +46 -6
  540. package/dist/util/rangeMap.js.map +1 -1
  541. package/dist/util/readSnapshotBlob.d.ts +13 -0
  542. package/dist/util/readSnapshotBlob.d.ts.map +1 -0
  543. package/dist/util/readSnapshotBlob.js +18 -0
  544. package/dist/util/readSnapshotBlob.js.map +1 -0
  545. package/lib/alpha.d.ts +3 -2
  546. package/lib/codec/codec.d.ts +14 -1
  547. package/lib/codec/codec.d.ts.map +1 -1
  548. package/lib/codec/codec.js +11 -0
  549. package/lib/codec/codec.js.map +1 -1
  550. package/lib/codec/versioned/codec.d.ts +1 -1
  551. package/lib/codec/versioned/codec.d.ts.map +1 -1
  552. package/lib/codec/versioned/codec.js.map +1 -1
  553. package/lib/codec/versioned/format.d.ts +4 -1
  554. package/lib/codec/versioned/format.d.ts.map +1 -1
  555. package/lib/codec/versioned/format.js +4 -1
  556. package/lib/codec/versioned/format.js.map +1 -1
  557. package/lib/core/change-family/changeFamily.d.ts +4 -1
  558. package/lib/core/change-family/changeFamily.d.ts.map +1 -1
  559. package/lib/core/change-family/changeFamily.js.map +1 -1
  560. package/lib/core/change-family/index.d.ts +1 -1
  561. package/lib/core/change-family/index.d.ts.map +1 -1
  562. package/lib/core/change-family/index.js.map +1 -1
  563. package/lib/core/index.d.ts +3 -3
  564. package/lib/core/index.d.ts.map +1 -1
  565. package/lib/core/index.js +2 -2
  566. package/lib/core/index.js.map +1 -1
  567. package/lib/core/rebase/changeRebaser.d.ts +6 -1
  568. package/lib/core/rebase/changeRebaser.d.ts.map +1 -1
  569. package/lib/core/rebase/changeRebaser.js.map +1 -1
  570. package/lib/core/rebase/index.d.ts +1 -1
  571. package/lib/core/rebase/index.d.ts.map +1 -1
  572. package/lib/core/rebase/index.js +1 -1
  573. package/lib/core/rebase/index.js.map +1 -1
  574. package/lib/core/rebase/types.d.ts +2 -1
  575. package/lib/core/rebase/types.d.ts.map +1 -1
  576. package/lib/core/rebase/types.js +3 -0
  577. package/lib/core/rebase/types.js.map +1 -1
  578. package/lib/core/rebase/utils.d.ts.map +1 -1
  579. package/lib/core/rebase/utils.js +25 -7
  580. package/lib/core/rebase/utils.js.map +1 -1
  581. package/lib/core/tree/detachedFieldIndex.d.ts +40 -13
  582. package/lib/core/tree/detachedFieldIndex.d.ts.map +1 -1
  583. package/lib/core/tree/detachedFieldIndex.js +22 -13
  584. package/lib/core/tree/detachedFieldIndex.js.map +1 -1
  585. package/lib/core/tree/index.d.ts +4 -3
  586. package/lib/core/tree/index.d.ts.map +1 -1
  587. package/lib/core/tree/index.js +3 -2
  588. package/lib/core/tree/index.js.map +1 -1
  589. package/lib/core/tree/pathTree.d.ts +11 -3
  590. package/lib/core/tree/pathTree.d.ts.map +1 -1
  591. package/lib/core/tree/pathTree.js +12 -1
  592. package/lib/core/tree/pathTree.js.map +1 -1
  593. package/lib/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  594. package/lib/feature-libraries/chunked-forest/basicChunk.js +8 -1
  595. package/lib/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  596. package/lib/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
  597. package/lib/feature-libraries/chunked-forest/chunkTree.js +4 -1
  598. package/lib/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
  599. package/lib/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.d.ts +14 -6
  600. package/lib/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.d.ts.map +1 -1
  601. package/lib/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.js.map +1 -1
  602. package/lib/feature-libraries/chunked-forest/codec/schemaBasedEncode.js +7 -2
  603. package/lib/feature-libraries/chunked-forest/codec/schemaBasedEncode.js.map +1 -1
  604. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts +91 -42
  605. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  606. package/lib/feature-libraries/default-schema/defaultEditBuilder.js +236 -70
  607. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  608. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts +4 -4
  609. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  610. package/lib/feature-libraries/default-schema/defaultFieldKinds.js +34 -29
  611. package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  612. package/lib/feature-libraries/default-schema/index.d.ts +2 -1
  613. package/lib/feature-libraries/default-schema/index.d.ts.map +1 -1
  614. package/lib/feature-libraries/default-schema/index.js +2 -1
  615. package/lib/feature-libraries/default-schema/index.js.map +1 -1
  616. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.d.ts +36 -0
  617. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.d.ts.map +1 -0
  618. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.js +122 -0
  619. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.js.map +1 -0
  620. package/lib/feature-libraries/default-schema/mappedEditBuilder.d.ts +7 -6
  621. package/lib/feature-libraries/default-schema/mappedEditBuilder.d.ts.map +1 -1
  622. package/lib/feature-libraries/default-schema/mappedEditBuilder.js +15 -0
  623. package/lib/feature-libraries/default-schema/mappedEditBuilder.js.map +1 -1
  624. package/lib/feature-libraries/deltaUtils.d.ts +1 -0
  625. package/lib/feature-libraries/deltaUtils.d.ts.map +1 -1
  626. package/lib/feature-libraries/deltaUtils.js +5 -1
  627. package/lib/feature-libraries/deltaUtils.js.map +1 -1
  628. package/lib/feature-libraries/detachedFieldIndexSummarizer.d.ts +30 -8
  629. package/lib/feature-libraries/detachedFieldIndexSummarizer.d.ts.map +1 -1
  630. package/lib/feature-libraries/detachedFieldIndexSummarizer.js +38 -8
  631. package/lib/feature-libraries/detachedFieldIndexSummarizer.js.map +1 -1
  632. package/lib/feature-libraries/flex-tree/context.d.ts +9 -0
  633. package/lib/feature-libraries/flex-tree/context.d.ts.map +1 -1
  634. package/lib/feature-libraries/flex-tree/context.js +6 -0
  635. package/lib/feature-libraries/flex-tree/context.js.map +1 -1
  636. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +6 -6
  637. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  638. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  639. package/lib/feature-libraries/flex-tree/lazyField.d.ts +8 -7
  640. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  641. package/lib/feature-libraries/flex-tree/lazyField.js +38 -9
  642. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  643. package/lib/feature-libraries/forest-summary/codec.d.ts +2 -2
  644. package/lib/feature-libraries/forest-summary/codec.d.ts.map +1 -1
  645. package/lib/feature-libraries/forest-summary/codec.js +5 -5
  646. package/lib/feature-libraries/forest-summary/codec.js.map +1 -1
  647. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts +9 -13
  648. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  649. package/lib/feature-libraries/forest-summary/forestSummarizer.js +17 -22
  650. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  651. package/lib/feature-libraries/forest-summary/format.d.ts +41 -5
  652. package/lib/feature-libraries/forest-summary/format.d.ts.map +1 -1
  653. package/lib/feature-libraries/forest-summary/format.js +3 -3
  654. package/lib/feature-libraries/forest-summary/format.js.map +1 -1
  655. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts +11 -9
  656. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts.map +1 -1
  657. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.js +13 -26
  658. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.js.map +1 -1
  659. package/lib/feature-libraries/forest-summary/index.d.ts +2 -1
  660. package/lib/feature-libraries/forest-summary/index.d.ts.map +1 -1
  661. package/lib/feature-libraries/forest-summary/index.js +2 -1
  662. package/lib/feature-libraries/forest-summary/index.js.map +1 -1
  663. package/lib/feature-libraries/forest-summary/summaryTypes.d.ts +47 -0
  664. package/lib/feature-libraries/forest-summary/summaryTypes.d.ts.map +1 -0
  665. package/lib/feature-libraries/forest-summary/summaryTypes.js +53 -0
  666. package/lib/feature-libraries/forest-summary/summaryTypes.js.map +1 -0
  667. package/lib/feature-libraries/index.d.ts +4 -4
  668. package/lib/feature-libraries/index.d.ts.map +1 -1
  669. package/lib/feature-libraries/index.js +3 -3
  670. package/lib/feature-libraries/index.js.map +1 -1
  671. package/lib/feature-libraries/mapTreeCursor.d.ts.map +1 -1
  672. package/lib/feature-libraries/mapTreeCursor.js +2 -1
  673. package/lib/feature-libraries/mapTreeCursor.js.map +1 -1
  674. package/lib/feature-libraries/mitigatedChangeFamily.d.ts.map +1 -1
  675. package/lib/feature-libraries/mitigatedChangeFamily.js +2 -2
  676. package/lib/feature-libraries/mitigatedChangeFamily.js.map +1 -1
  677. package/lib/feature-libraries/modular-schema/comparison.d.ts +18 -2
  678. package/lib/feature-libraries/modular-schema/comparison.d.ts.map +1 -1
  679. package/lib/feature-libraries/modular-schema/comparison.js +55 -5
  680. package/lib/feature-libraries/modular-schema/comparison.js.map +1 -1
  681. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +97 -21
  682. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  683. package/lib/feature-libraries/modular-schema/crossFieldQueries.js +3 -5
  684. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  685. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +20 -52
  686. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  687. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  688. package/lib/feature-libraries/modular-schema/fieldKind.d.ts +25 -13
  689. package/lib/feature-libraries/modular-schema/fieldKind.d.ts.map +1 -1
  690. package/lib/feature-libraries/modular-schema/fieldKind.js +0 -21
  691. package/lib/feature-libraries/modular-schema/fieldKind.js.map +1 -1
  692. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  693. package/lib/feature-libraries/modular-schema/genericFieldKind.js +7 -10
  694. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  695. package/lib/feature-libraries/modular-schema/genericFieldKindCodecs.js +1 -1
  696. package/lib/feature-libraries/modular-schema/genericFieldKindCodecs.js.map +1 -1
  697. package/lib/feature-libraries/modular-schema/index.d.ts +6 -6
  698. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  699. package/lib/feature-libraries/modular-schema/index.js +5 -4
  700. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  701. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.d.ts +17 -0
  702. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.d.ts.map +1 -0
  703. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.js +384 -0
  704. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.js.map +1 -0
  705. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.d.ts +17 -0
  706. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.d.ts.map +1 -0
  707. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.js +409 -0
  708. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.js.map +1 -0
  709. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts +2 -2
  710. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  711. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +9 -285
  712. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  713. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +49 -15
  714. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  715. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +1291 -458
  716. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  717. package/lib/feature-libraries/modular-schema/{modularChangeFormat.d.ts → modularChangeFormatV1.d.ts} +2 -2
  718. package/lib/feature-libraries/modular-schema/modularChangeFormatV1.d.ts.map +1 -0
  719. package/lib/feature-libraries/modular-schema/{modularChangeFormat.js → modularChangeFormatV1.js} +2 -2
  720. package/lib/feature-libraries/modular-schema/modularChangeFormatV1.js.map +1 -0
  721. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.d.ts +146 -0
  722. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.d.ts.map +1 -0
  723. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.js +29 -0
  724. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.js.map +1 -0
  725. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +50 -10
  726. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  727. package/lib/feature-libraries/modular-schema/modularChangeTypes.js +20 -2
  728. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  729. package/lib/feature-libraries/optional-field/index.d.ts +2 -2
  730. package/lib/feature-libraries/optional-field/index.d.ts.map +1 -1
  731. package/lib/feature-libraries/optional-field/index.js +1 -1
  732. package/lib/feature-libraries/optional-field/index.js.map +1 -1
  733. package/lib/feature-libraries/optional-field/optionalField.d.ts +5 -26
  734. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  735. package/lib/feature-libraries/optional-field/optionalField.js +217 -449
  736. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  737. package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts +23 -0
  738. package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts.map +1 -0
  739. package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.js +27 -0
  740. package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.js.map +1 -0
  741. package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts +24 -33
  742. package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts.map +1 -1
  743. package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.js.map +1 -1
  744. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.d.ts +1 -1
  745. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.d.ts.map +1 -1
  746. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.js +55 -26
  747. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.js.map +1 -1
  748. package/lib/feature-libraries/optional-field/optionalFieldCodecV3.d.ts +12 -0
  749. package/lib/feature-libraries/optional-field/optionalFieldCodecV3.d.ts.map +1 -0
  750. package/lib/feature-libraries/optional-field/optionalFieldCodecV3.js +53 -0
  751. package/lib/feature-libraries/optional-field/optionalFieldCodecV3.js.map +1 -0
  752. package/lib/feature-libraries/optional-field/optionalFieldCodecs.d.ts.map +1 -1
  753. package/lib/feature-libraries/optional-field/optionalFieldCodecs.js +5 -1
  754. package/lib/feature-libraries/optional-field/optionalFieldCodecs.js.map +1 -1
  755. package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts +27 -8
  756. package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
  757. package/lib/feature-libraries/schema-index/schemaSummarizer.js +38 -12
  758. package/lib/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
  759. package/lib/feature-libraries/sequence-field/compose.d.ts +6 -7
  760. package/lib/feature-libraries/sequence-field/compose.d.ts.map +1 -1
  761. package/lib/feature-libraries/sequence-field/compose.js +82 -258
  762. package/lib/feature-libraries/sequence-field/compose.js.map +1 -1
  763. package/lib/feature-libraries/sequence-field/helperTypes.d.ts +14 -10
  764. package/lib/feature-libraries/sequence-field/helperTypes.d.ts.map +1 -1
  765. package/lib/feature-libraries/sequence-field/helperTypes.js.map +1 -1
  766. package/lib/feature-libraries/sequence-field/index.d.ts +2 -3
  767. package/lib/feature-libraries/sequence-field/index.d.ts.map +1 -1
  768. package/lib/feature-libraries/sequence-field/index.js +0 -1
  769. package/lib/feature-libraries/sequence-field/index.js.map +1 -1
  770. package/lib/feature-libraries/sequence-field/invert.d.ts +3 -3
  771. package/lib/feature-libraries/sequence-field/invert.d.ts.map +1 -1
  772. package/lib/feature-libraries/sequence-field/invert.js +67 -169
  773. package/lib/feature-libraries/sequence-field/invert.js.map +1 -1
  774. package/lib/feature-libraries/sequence-field/markQueue.d.ts +2 -2
  775. package/lib/feature-libraries/sequence-field/markQueue.d.ts.map +1 -1
  776. package/lib/feature-libraries/sequence-field/markQueue.js.map +1 -1
  777. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts +4 -56
  778. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  779. package/lib/feature-libraries/sequence-field/moveEffectTable.js +6 -80
  780. package/lib/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  781. package/lib/feature-libraries/sequence-field/rebase.d.ts +3 -3
  782. package/lib/feature-libraries/sequence-field/rebase.d.ts.map +1 -1
  783. package/lib/feature-libraries/sequence-field/rebase.js +108 -114
  784. package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
  785. package/lib/feature-libraries/sequence-field/replaceRevisions.d.ts.map +1 -1
  786. package/lib/feature-libraries/sequence-field/replaceRevisions.js +16 -33
  787. package/lib/feature-libraries/sequence-field/replaceRevisions.js.map +1 -1
  788. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  789. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +0 -2
  790. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  791. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +22 -4
  792. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
  793. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js +350 -175
  794. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  795. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
  796. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js +21 -61
  797. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
  798. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.d.ts +2 -2
  799. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.d.ts.map +1 -1
  800. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.js +10 -10
  801. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.js.map +1 -1
  802. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +3 -2
  803. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  804. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js +14 -109
  805. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  806. package/lib/feature-libraries/sequence-field/types.d.ts +30 -59
  807. package/lib/feature-libraries/sequence-field/types.d.ts.map +1 -1
  808. package/lib/feature-libraries/sequence-field/types.js.map +1 -1
  809. package/lib/feature-libraries/sequence-field/utils.d.ts +15 -24
  810. package/lib/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  811. package/lib/feature-libraries/sequence-field/utils.js +107 -292
  812. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  813. package/lib/index.d.ts +1 -1
  814. package/lib/index.d.ts.map +1 -1
  815. package/lib/index.js +1 -1
  816. package/lib/index.js.map +1 -1
  817. package/lib/packageVersion.d.ts +1 -1
  818. package/lib/packageVersion.js +1 -1
  819. package/lib/packageVersion.js.map +1 -1
  820. package/lib/shared-tree/independentView.d.ts +1 -1
  821. package/lib/shared-tree/independentView.d.ts.map +1 -1
  822. package/lib/shared-tree/independentView.js.map +1 -1
  823. package/lib/shared-tree/index.d.ts +1 -1
  824. package/lib/shared-tree/index.d.ts.map +1 -1
  825. package/lib/shared-tree/index.js.map +1 -1
  826. package/lib/shared-tree/schematizeTree.d.ts +4 -4
  827. package/lib/shared-tree/schematizeTree.d.ts.map +1 -1
  828. package/lib/shared-tree/schematizeTree.js +3 -2
  829. package/lib/shared-tree/schematizeTree.js.map +1 -1
  830. package/lib/shared-tree/schematizingTreeView.d.ts +1 -5
  831. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  832. package/lib/shared-tree/schematizingTreeView.js +35 -36
  833. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  834. package/lib/shared-tree/sharedTree.d.ts +11 -5
  835. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  836. package/lib/shared-tree/sharedTree.js +14 -4
  837. package/lib/shared-tree/sharedTree.js.map +1 -1
  838. package/lib/shared-tree/sharedTreeChangeCodecs.d.ts +1 -1
  839. package/lib/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
  840. package/lib/shared-tree/sharedTreeChangeCodecs.js +1 -0
  841. package/lib/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
  842. package/lib/shared-tree/sharedTreeChangeEnricher.d.ts +20 -8
  843. package/lib/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
  844. package/lib/shared-tree/sharedTreeChangeEnricher.js +27 -13
  845. package/lib/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
  846. package/lib/shared-tree/sharedTreeChangeFamily.d.ts +5 -5
  847. package/lib/shared-tree/sharedTreeChangeFamily.d.ts.map +1 -1
  848. package/lib/shared-tree/sharedTreeChangeFamily.js +11 -5
  849. package/lib/shared-tree/sharedTreeChangeFamily.js.map +1 -1
  850. package/lib/shared-tree/sharedTreeEditBuilder.d.ts +16 -6
  851. package/lib/shared-tree/sharedTreeEditBuilder.d.ts.map +1 -1
  852. package/lib/shared-tree/sharedTreeEditBuilder.js +12 -6
  853. package/lib/shared-tree/sharedTreeEditBuilder.js.map +1 -1
  854. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  855. package/lib/shared-tree/treeAlpha.js +2 -2
  856. package/lib/shared-tree/treeAlpha.js.map +1 -1
  857. package/lib/shared-tree/treeCheckout.d.ts +12 -10
  858. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  859. package/lib/shared-tree/treeCheckout.js +69 -20
  860. package/lib/shared-tree/treeCheckout.js.map +1 -1
  861. package/lib/shared-tree-core/branch.d.ts +3 -2
  862. package/lib/shared-tree-core/branch.d.ts.map +1 -1
  863. package/lib/shared-tree-core/branch.js +4 -3
  864. package/lib/shared-tree-core/branch.js.map +1 -1
  865. package/lib/shared-tree-core/editManager.d.ts +2 -2
  866. package/lib/shared-tree-core/editManager.d.ts.map +1 -1
  867. package/lib/shared-tree-core/editManager.js +9 -9
  868. package/lib/shared-tree-core/editManager.js.map +1 -1
  869. package/lib/shared-tree-core/editManagerCodecs.d.ts +4 -0
  870. package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  871. package/lib/shared-tree-core/editManagerCodecs.js +14 -5
  872. package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
  873. package/{dist/shared-tree-core/editManagerCodecsV5.d.ts → lib/shared-tree-core/editManagerCodecsVSharedBranches.d.ts} +3 -3
  874. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.d.ts.map +1 -0
  875. package/lib/shared-tree-core/{editManagerCodecsV5.js → editManagerCodecsVSharedBranches.js} +4 -4
  876. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.js.map +1 -0
  877. package/lib/shared-tree-core/editManagerFormatCommons.d.ts +20 -6
  878. package/lib/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
  879. package/lib/shared-tree-core/editManagerFormatCommons.js +22 -7
  880. package/lib/shared-tree-core/editManagerFormatCommons.js.map +1 -1
  881. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts +2 -2
  882. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
  883. package/lib/shared-tree-core/editManagerFormatV1toV4.js +1 -0
  884. package/lib/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
  885. package/lib/shared-tree-core/{editManagerFormatV5.d.ts → editManagerFormatVSharedBranches.d.ts} +3 -3
  886. package/lib/shared-tree-core/editManagerFormatVSharedBranches.d.ts.map +1 -0
  887. package/lib/shared-tree-core/{editManagerFormatV5.js → editManagerFormatVSharedBranches.js} +2 -2
  888. package/lib/shared-tree-core/editManagerFormatVSharedBranches.js.map +1 -0
  889. package/lib/shared-tree-core/editManagerSummarizer.d.ts +29 -9
  890. package/lib/shared-tree-core/editManagerSummarizer.d.ts.map +1 -1
  891. package/lib/shared-tree-core/editManagerSummarizer.js +39 -11
  892. package/lib/shared-tree-core/editManagerSummarizer.js.map +1 -1
  893. package/lib/shared-tree-core/index.d.ts +5 -3
  894. package/lib/shared-tree-core/index.d.ts.map +1 -1
  895. package/lib/shared-tree-core/index.js +4 -2
  896. package/lib/shared-tree-core/index.js.map +1 -1
  897. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts +1 -1
  898. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
  899. package/lib/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
  900. package/{dist/shared-tree-core/messageCodecV5.d.ts → lib/shared-tree-core/messageCodecVSharedBranches.d.ts} +2 -2
  901. package/lib/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -0
  902. package/lib/shared-tree-core/{messageCodecV5.js → messageCodecVSharedBranches.js} +3 -3
  903. package/lib/shared-tree-core/messageCodecVSharedBranches.js.map +1 -0
  904. package/lib/shared-tree-core/messageCodecs.d.ts +4 -0
  905. package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
  906. package/lib/shared-tree-core/messageCodecs.js +14 -5
  907. package/lib/shared-tree-core/messageCodecs.js.map +1 -1
  908. package/lib/shared-tree-core/messageFormat.d.ts +20 -6
  909. package/lib/shared-tree-core/messageFormat.d.ts.map +1 -1
  910. package/lib/shared-tree-core/messageFormat.js +22 -7
  911. package/lib/shared-tree-core/messageFormat.js.map +1 -1
  912. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts +3 -2
  913. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
  914. package/lib/shared-tree-core/messageFormatV1ToV4.js +8 -1
  915. package/lib/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
  916. package/lib/shared-tree-core/{messageFormatV5.d.ts → messageFormatVSharedBranches.d.ts} +5 -7
  917. package/lib/shared-tree-core/messageFormatVSharedBranches.d.ts.map +1 -0
  918. package/lib/shared-tree-core/{messageFormatV5.js → messageFormatVSharedBranches.js} +3 -2
  919. package/lib/shared-tree-core/messageFormatVSharedBranches.js.map +1 -0
  920. package/lib/shared-tree-core/sharedTreeCore.d.ts +14 -47
  921. package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  922. package/lib/shared-tree-core/sharedTreeCore.js +28 -16
  923. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  924. package/lib/shared-tree-core/summaryTypes.d.ts +94 -0
  925. package/lib/shared-tree-core/summaryTypes.d.ts.map +1 -0
  926. package/lib/shared-tree-core/summaryTypes.js +43 -0
  927. package/lib/shared-tree-core/summaryTypes.js.map +1 -0
  928. package/lib/shared-tree-core/versionedSummarizer.d.ts +67 -0
  929. package/lib/shared-tree-core/versionedSummarizer.d.ts.map +1 -0
  930. package/lib/shared-tree-core/versionedSummarizer.js +59 -0
  931. package/lib/shared-tree-core/versionedSummarizer.js.map +1 -0
  932. package/lib/simple-tree/api/configuration.d.ts +3 -26
  933. package/lib/simple-tree/api/configuration.d.ts.map +1 -1
  934. package/lib/simple-tree/api/configuration.js +14 -25
  935. package/lib/simple-tree/api/configuration.js.map +1 -1
  936. package/lib/simple-tree/api/dirtyIndex.d.ts +11 -0
  937. package/lib/simple-tree/api/dirtyIndex.d.ts.map +1 -1
  938. package/lib/simple-tree/api/dirtyIndex.js +7 -0
  939. package/lib/simple-tree/api/dirtyIndex.js.map +1 -1
  940. package/lib/simple-tree/api/discrepancies.d.ts +1 -1
  941. package/lib/simple-tree/api/discrepancies.d.ts.map +1 -1
  942. package/lib/simple-tree/api/discrepancies.js.map +1 -1
  943. package/lib/simple-tree/api/getSimpleSchema.d.ts +3 -3
  944. package/lib/simple-tree/api/getSimpleSchema.d.ts.map +1 -1
  945. package/lib/simple-tree/api/getSimpleSchema.js +9 -3
  946. package/lib/simple-tree/api/getSimpleSchema.js.map +1 -1
  947. package/lib/simple-tree/api/incrementalAllowedTypes.d.ts +1 -1
  948. package/lib/simple-tree/api/incrementalAllowedTypes.d.ts.map +1 -1
  949. package/lib/simple-tree/api/incrementalAllowedTypes.js +8 -1
  950. package/lib/simple-tree/api/incrementalAllowedTypes.js.map +1 -1
  951. package/lib/simple-tree/api/index.d.ts +3 -4
  952. package/lib/simple-tree/api/index.d.ts.map +1 -1
  953. package/lib/simple-tree/api/index.js +2 -3
  954. package/lib/simple-tree/api/index.js.map +1 -1
  955. package/lib/simple-tree/api/schemaCompatibilityTester.d.ts +1 -1
  956. package/lib/simple-tree/api/schemaCompatibilityTester.d.ts.map +1 -1
  957. package/lib/simple-tree/api/schemaCompatibilityTester.js.map +1 -1
  958. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts +5 -5
  959. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
  960. package/lib/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
  961. package/lib/simple-tree/api/schemaFactoryRecursive.d.ts.map +1 -1
  962. package/lib/simple-tree/api/schemaFactoryRecursive.js +0 -1
  963. package/lib/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
  964. package/lib/simple-tree/api/schemaFromSimple.d.ts +6 -1
  965. package/lib/simple-tree/api/schemaFromSimple.d.ts.map +1 -1
  966. package/lib/simple-tree/api/schemaFromSimple.js +5 -0
  967. package/lib/simple-tree/api/schemaFromSimple.js.map +1 -1
  968. package/lib/simple-tree/api/schemaStatics.d.ts +12 -12
  969. package/lib/simple-tree/api/simpleSchemaCodec.d.ts +15 -3
  970. package/lib/simple-tree/api/simpleSchemaCodec.d.ts.map +1 -1
  971. package/lib/simple-tree/api/simpleSchemaCodec.js +15 -3
  972. package/lib/simple-tree/api/simpleSchemaCodec.js.map +1 -1
  973. package/lib/simple-tree/api/simpleSchemaToJsonSchema.d.ts +1 -1
  974. package/lib/simple-tree/api/simpleSchemaToJsonSchema.d.ts.map +1 -1
  975. package/lib/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
  976. package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts +8 -1
  977. package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts.map +1 -1
  978. package/lib/simple-tree/api/snapshotCompatibilityChecker.js +15 -10
  979. package/lib/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
  980. package/lib/simple-tree/api/typesUnsafe.d.ts +3 -3
  981. package/lib/simple-tree/api/typesUnsafe.d.ts.map +1 -1
  982. package/lib/simple-tree/api/typesUnsafe.js.map +1 -1
  983. package/lib/simple-tree/core/allowedTypes.d.ts +2 -2
  984. package/lib/simple-tree/core/allowedTypes.d.ts.map +1 -1
  985. package/lib/simple-tree/core/allowedTypes.js.map +1 -1
  986. package/lib/simple-tree/core/index.d.ts +1 -1
  987. package/lib/simple-tree/core/index.d.ts.map +1 -1
  988. package/lib/simple-tree/core/index.js +1 -1
  989. package/lib/simple-tree/core/index.js.map +1 -1
  990. package/lib/simple-tree/core/toStored.d.ts +17 -15
  991. package/lib/simple-tree/core/toStored.d.ts.map +1 -1
  992. package/lib/simple-tree/core/toStored.js +4 -37
  993. package/lib/simple-tree/core/toStored.js.map +1 -1
  994. package/lib/simple-tree/core/unhydratedFlexTree.d.ts +15 -15
  995. package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  996. package/lib/simple-tree/core/unhydratedFlexTree.js +58 -8
  997. package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  998. package/lib/simple-tree/core/walkSchema.d.ts.map +1 -1
  999. package/lib/simple-tree/core/walkSchema.js +5 -1
  1000. package/lib/simple-tree/core/walkSchema.js.map +1 -1
  1001. package/lib/simple-tree/createContext.d.ts.map +1 -1
  1002. package/lib/simple-tree/createContext.js +20 -5
  1003. package/lib/simple-tree/createContext.js.map +1 -1
  1004. package/lib/simple-tree/fieldSchema.d.ts +7 -7
  1005. package/lib/simple-tree/fieldSchema.d.ts.map +1 -1
  1006. package/lib/simple-tree/fieldSchema.js.map +1 -1
  1007. package/lib/simple-tree/index.d.ts +8 -7
  1008. package/lib/simple-tree/index.d.ts.map +1 -1
  1009. package/lib/simple-tree/index.js +6 -5
  1010. package/lib/simple-tree/index.js.map +1 -1
  1011. package/lib/simple-tree/leafNodeSchema.d.ts +5 -5
  1012. package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
  1013. package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  1014. package/lib/simple-tree/node-kinds/array/arrayNode.js +6 -4
  1015. package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  1016. package/lib/simple-tree/node-kinds/array/arrayNodeTypes.d.ts +3 -3
  1017. package/lib/simple-tree/node-kinds/array/arrayNodeTypes.d.ts.map +1 -1
  1018. package/lib/simple-tree/node-kinds/array/arrayNodeTypes.js.map +1 -1
  1019. package/lib/simple-tree/node-kinds/common.d.ts.map +1 -1
  1020. package/lib/simple-tree/node-kinds/common.js +2 -2
  1021. package/lib/simple-tree/node-kinds/common.js.map +1 -1
  1022. package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  1023. package/lib/simple-tree/node-kinds/map/mapNode.js +2 -2
  1024. package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  1025. package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts +3 -3
  1026. package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
  1027. package/lib/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
  1028. package/lib/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  1029. package/lib/simple-tree/node-kinds/object/objectNode.js +19 -19
  1030. package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  1031. package/lib/simple-tree/node-kinds/object/objectNodeTypes.d.ts +2 -2
  1032. package/lib/simple-tree/node-kinds/object/objectNodeTypes.d.ts.map +1 -1
  1033. package/lib/simple-tree/node-kinds/object/objectNodeTypes.js.map +1 -1
  1034. package/lib/simple-tree/node-kinds/record/recordNode.d.ts.map +1 -1
  1035. package/lib/simple-tree/node-kinds/record/recordNode.js +4 -2
  1036. package/lib/simple-tree/node-kinds/record/recordNode.js.map +1 -1
  1037. package/lib/simple-tree/node-kinds/record/recordNodeTypes.d.ts +3 -3
  1038. package/lib/simple-tree/node-kinds/record/recordNodeTypes.d.ts.map +1 -1
  1039. package/lib/simple-tree/node-kinds/record/recordNodeTypes.js.map +1 -1
  1040. package/lib/simple-tree/prepareForInsertion.d.ts +54 -47
  1041. package/lib/simple-tree/prepareForInsertion.d.ts.map +1 -1
  1042. package/lib/simple-tree/prepareForInsertion.js +183 -124
  1043. package/lib/simple-tree/prepareForInsertion.js.map +1 -1
  1044. package/lib/simple-tree/simpleSchema.d.ts +55 -23
  1045. package/lib/simple-tree/simpleSchema.d.ts.map +1 -1
  1046. package/lib/simple-tree/simpleSchema.js +16 -1
  1047. package/lib/simple-tree/simpleSchema.js.map +1 -1
  1048. package/lib/simple-tree/simpleSchemaFormatV1.d.ts +1 -1
  1049. package/lib/simple-tree/simpleSchemaFormatV1.d.ts.map +1 -1
  1050. package/lib/simple-tree/simpleSchemaFormatV1.js +8 -1
  1051. package/lib/simple-tree/simpleSchemaFormatV1.js.map +1 -1
  1052. package/lib/simple-tree/toStoredSchema.d.ts +58 -11
  1053. package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
  1054. package/lib/simple-tree/toStoredSchema.js +204 -31
  1055. package/lib/simple-tree/toStoredSchema.js.map +1 -1
  1056. package/lib/simple-tree/treeSchema.d.ts +23 -0
  1057. package/lib/simple-tree/treeSchema.d.ts.map +1 -0
  1058. package/lib/simple-tree/treeSchema.js +21 -0
  1059. package/lib/simple-tree/treeSchema.js.map +1 -0
  1060. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts +13 -4
  1061. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -1
  1062. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js +26 -9
  1063. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -1
  1064. package/lib/tableSchema.d.ts +117 -63
  1065. package/lib/tableSchema.d.ts.map +1 -1
  1066. package/lib/tableSchema.js +160 -59
  1067. package/lib/tableSchema.js.map +1 -1
  1068. package/lib/treeFactory.d.ts.map +1 -1
  1069. package/lib/treeFactory.js +18 -4
  1070. package/lib/treeFactory.js.map +1 -1
  1071. package/lib/util/index.d.ts +2 -1
  1072. package/lib/util/index.d.ts.map +1 -1
  1073. package/lib/util/index.js +2 -1
  1074. package/lib/util/index.js.map +1 -1
  1075. package/lib/util/rangeMap.d.ts +24 -12
  1076. package/lib/util/rangeMap.d.ts.map +1 -1
  1077. package/lib/util/rangeMap.js +44 -5
  1078. package/lib/util/rangeMap.js.map +1 -1
  1079. package/lib/util/readSnapshotBlob.d.ts +13 -0
  1080. package/lib/util/readSnapshotBlob.d.ts.map +1 -0
  1081. package/lib/util/readSnapshotBlob.js +14 -0
  1082. package/lib/util/readSnapshotBlob.js.map +1 -0
  1083. package/package.json +21 -21
  1084. package/src/codec/codec.ts +15 -1
  1085. package/src/codec/versioned/codec.ts +1 -1
  1086. package/src/codec/versioned/format.ts +4 -1
  1087. package/src/core/change-family/changeFamily.ts +5 -0
  1088. package/src/core/change-family/index.ts +1 -0
  1089. package/src/core/index.ts +7 -2
  1090. package/src/core/rebase/changeRebaser.ts +6 -1
  1091. package/src/core/rebase/index.ts +1 -0
  1092. package/src/core/rebase/types.ts +8 -1
  1093. package/src/core/rebase/utils.ts +31 -7
  1094. package/src/core/tree/detachedFieldIndex.ts +71 -14
  1095. package/src/core/tree/index.ts +9 -3
  1096. package/src/core/tree/pathTree.ts +16 -4
  1097. package/src/feature-libraries/chunked-forest/basicChunk.ts +7 -1
  1098. package/src/feature-libraries/chunked-forest/chunkTree.ts +6 -1
  1099. package/src/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.ts +15 -7
  1100. package/src/feature-libraries/chunked-forest/codec/schemaBasedEncode.ts +9 -9
  1101. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +398 -127
  1102. package/src/feature-libraries/default-schema/defaultFieldKinds.ts +35 -38
  1103. package/src/feature-libraries/default-schema/index.ts +17 -5
  1104. package/src/feature-libraries/default-schema/locationBasedEditBuilder.ts +180 -0
  1105. package/src/feature-libraries/default-schema/mappedEditBuilder.ts +35 -9
  1106. package/src/feature-libraries/deltaUtils.ts +6 -1
  1107. package/src/feature-libraries/detachedFieldIndexSummarizer.ts +62 -15
  1108. package/src/feature-libraries/flex-tree/context.ts +17 -0
  1109. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +7 -8
  1110. package/src/feature-libraries/flex-tree/lazyField.ts +66 -24
  1111. package/src/feature-libraries/forest-summary/codec.ts +8 -8
  1112. package/src/feature-libraries/forest-summary/forestSummarizer.ts +45 -37
  1113. package/src/feature-libraries/forest-summary/format.ts +4 -4
  1114. package/src/feature-libraries/forest-summary/incrementalSummaryBuilder.ts +23 -39
  1115. package/src/feature-libraries/forest-summary/index.ts +2 -1
  1116. package/src/feature-libraries/forest-summary/summaryTypes.ts +61 -0
  1117. package/src/feature-libraries/index.ts +23 -9
  1118. package/src/feature-libraries/mapTreeCursor.ts +2 -1
  1119. package/src/feature-libraries/mitigatedChangeFamily.ts +3 -1
  1120. package/src/feature-libraries/modular-schema/comparison.ts +63 -5
  1121. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +142 -44
  1122. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +36 -57
  1123. package/src/feature-libraries/modular-schema/fieldKind.ts +24 -40
  1124. package/src/feature-libraries/modular-schema/genericFieldKind.ts +10 -19
  1125. package/src/feature-libraries/modular-schema/genericFieldKindCodecs.ts +1 -1
  1126. package/src/feature-libraries/modular-schema/index.ts +22 -15
  1127. package/src/feature-libraries/modular-schema/modularChangeCodecV1.ts +732 -0
  1128. package/src/feature-libraries/modular-schema/modularChangeCodecV2.ts +790 -0
  1129. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +29 -499
  1130. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +2547 -739
  1131. package/src/feature-libraries/modular-schema/{modularChangeFormat.ts → modularChangeFormatV1.ts} +2 -1
  1132. package/src/feature-libraries/modular-schema/modularChangeFormatV2.ts +62 -0
  1133. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +98 -10
  1134. package/src/feature-libraries/optional-field/index.ts +1 -3
  1135. package/src/feature-libraries/optional-field/optionalField.ts +317 -574
  1136. package/src/feature-libraries/optional-field/optionalFieldChangeFormatV3.ts +45 -0
  1137. package/src/feature-libraries/optional-field/optionalFieldChangeTypes.ts +24 -38
  1138. package/src/feature-libraries/optional-field/optionalFieldCodecV2.ts +89 -35
  1139. package/src/feature-libraries/optional-field/optionalFieldCodecV3.ts +94 -0
  1140. package/src/feature-libraries/optional-field/optionalFieldCodecs.ts +5 -1
  1141. package/src/feature-libraries/schema-index/schemaSummarizer.ts +59 -18
  1142. package/src/feature-libraries/sequence-field/compose.ts +134 -519
  1143. package/src/feature-libraries/sequence-field/helperTypes.ts +34 -19
  1144. package/src/feature-libraries/sequence-field/index.ts +0 -9
  1145. package/src/feature-libraries/sequence-field/invert.ts +103 -228
  1146. package/src/feature-libraries/sequence-field/markQueue.ts +2 -2
  1147. package/src/feature-libraries/sequence-field/moveEffectTable.ts +8 -191
  1148. package/src/feature-libraries/sequence-field/rebase.ts +168 -203
  1149. package/src/feature-libraries/sequence-field/replaceRevisions.ts +31 -52
  1150. package/src/feature-libraries/sequence-field/sequenceFieldChangeHandler.ts +0 -2
  1151. package/src/feature-libraries/sequence-field/sequenceFieldCodecV2.ts +643 -220
  1152. package/src/feature-libraries/sequence-field/sequenceFieldCodecV3.ts +56 -68
  1153. package/src/feature-libraries/sequence-field/sequenceFieldEditor.ts +25 -27
  1154. package/src/feature-libraries/sequence-field/sequenceFieldToDelta.ts +19 -129
  1155. package/src/feature-libraries/sequence-field/types.ts +34 -64
  1156. package/src/feature-libraries/sequence-field/utils.ts +133 -346
  1157. package/src/index.ts +3 -2
  1158. package/src/packageVersion.ts +1 -1
  1159. package/src/shared-tree/independentView.ts +1 -1
  1160. package/src/shared-tree/index.ts +3 -2
  1161. package/src/shared-tree/schematizeTree.ts +21 -8
  1162. package/src/shared-tree/schematizingTreeView.ts +50 -68
  1163. package/src/shared-tree/sharedTree.ts +39 -12
  1164. package/src/shared-tree/sharedTreeChangeCodecs.ts +5 -1
  1165. package/src/shared-tree/sharedTreeChangeEnricher.ts +33 -11
  1166. package/src/shared-tree/sharedTreeChangeFamily.ts +15 -5
  1167. package/src/shared-tree/sharedTreeEditBuilder.ts +47 -13
  1168. package/src/shared-tree/treeAlpha.ts +2 -3
  1169. package/src/shared-tree/treeCheckout.ts +104 -31
  1170. package/src/shared-tree-core/branch.ts +8 -2
  1171. package/src/shared-tree-core/editManager.ts +16 -2
  1172. package/src/shared-tree-core/editManagerCodecs.ts +17 -5
  1173. package/src/shared-tree-core/{editManagerCodecsV5.ts → editManagerCodecsVSharedBranches.ts} +3 -3
  1174. package/src/shared-tree-core/editManagerFormatCommons.ts +22 -7
  1175. package/src/shared-tree-core/editManagerFormatV1toV4.ts +3 -1
  1176. package/src/shared-tree-core/{editManagerFormatV5.ts → editManagerFormatVSharedBranches.ts} +2 -2
  1177. package/src/shared-tree-core/editManagerSummarizer.ts +58 -16
  1178. package/src/shared-tree-core/index.ts +11 -3
  1179. package/src/shared-tree-core/messageCodecV1ToV4.ts +2 -1
  1180. package/src/shared-tree-core/{messageCodecV5.ts → messageCodecVSharedBranches.ts} +3 -3
  1181. package/src/shared-tree-core/messageCodecs.ts +17 -5
  1182. package/src/shared-tree-core/messageFormat.ts +22 -7
  1183. package/src/shared-tree-core/messageFormatV1ToV4.ts +16 -2
  1184. package/src/shared-tree-core/{messageFormatV5.ts → messageFormatVSharedBranches.ts} +4 -6
  1185. package/src/shared-tree-core/sharedTreeCore.ts +67 -76
  1186. package/src/shared-tree-core/summaryTypes.ts +122 -0
  1187. package/src/shared-tree-core/versionedSummarizer.ts +107 -0
  1188. package/src/simple-tree/api/configuration.ts +21 -68
  1189. package/src/simple-tree/api/dirtyIndex.ts +11 -0
  1190. package/src/simple-tree/api/discrepancies.ts +1 -1
  1191. package/src/simple-tree/api/getSimpleSchema.ts +13 -6
  1192. package/src/simple-tree/api/incrementalAllowedTypes.ts +15 -3
  1193. package/src/simple-tree/api/index.ts +3 -4
  1194. package/src/simple-tree/api/schemaCompatibilityTester.ts +1 -1
  1195. package/src/simple-tree/api/schemaFactoryAlpha.ts +2 -2
  1196. package/src/simple-tree/api/schemaFactoryRecursive.ts +0 -2
  1197. package/src/simple-tree/api/schemaFromSimple.ts +11 -5
  1198. package/src/simple-tree/api/simpleSchemaCodec.ts +17 -3
  1199. package/src/simple-tree/api/simpleSchemaToJsonSchema.ts +1 -1
  1200. package/src/simple-tree/api/snapshotCompatibilityChecker.ts +18 -10
  1201. package/src/simple-tree/api/typesUnsafe.ts +7 -3
  1202. package/src/simple-tree/core/allowedTypes.ts +3 -3
  1203. package/src/simple-tree/core/index.ts +2 -2
  1204. package/src/simple-tree/core/toStored.ts +22 -55
  1205. package/src/simple-tree/core/unhydratedFlexTree.ts +87 -36
  1206. package/src/simple-tree/core/walkSchema.ts +6 -0
  1207. package/src/simple-tree/createContext.ts +26 -11
  1208. package/src/simple-tree/fieldSchema.ts +16 -7
  1209. package/src/simple-tree/index.ts +12 -11
  1210. package/src/simple-tree/node-kinds/array/arrayNode.ts +12 -7
  1211. package/src/simple-tree/node-kinds/array/arrayNodeTypes.ts +3 -3
  1212. package/src/simple-tree/node-kinds/common.ts +2 -5
  1213. package/src/simple-tree/node-kinds/map/mapNode.ts +9 -6
  1214. package/src/simple-tree/node-kinds/map/mapNodeTypes.ts +3 -3
  1215. package/src/simple-tree/node-kinds/object/objectNode.ts +26 -26
  1216. package/src/simple-tree/node-kinds/object/objectNodeTypes.ts +6 -2
  1217. package/src/simple-tree/node-kinds/record/recordNode.ts +15 -11
  1218. package/src/simple-tree/node-kinds/record/recordNodeTypes.ts +3 -3
  1219. package/src/simple-tree/prepareForInsertion.ts +343 -200
  1220. package/src/simple-tree/simpleSchema.ts +79 -32
  1221. package/src/simple-tree/simpleSchemaFormatV1.ts +9 -1
  1222. package/src/simple-tree/toStoredSchema.ts +319 -61
  1223. package/src/simple-tree/treeSchema.ts +54 -0
  1224. package/src/simple-tree/unhydratedFlexTreeFromInsertable.ts +42 -14
  1225. package/src/tableSchema.ts +485 -166
  1226. package/src/treeFactory.ts +19 -5
  1227. package/src/util/index.ts +5 -0
  1228. package/src/util/rangeMap.ts +72 -18
  1229. package/src/util/readSnapshotBlob.ts +23 -0
  1230. package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +0 -1
  1231. package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +0 -1
  1232. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.d.ts +0 -9
  1233. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.d.ts.map +0 -1
  1234. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.js +0 -50
  1235. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.js.map +0 -1
  1236. package/dist/shared-tree-core/editManagerCodecsV5.d.ts.map +0 -1
  1237. package/dist/shared-tree-core/editManagerCodecsV5.js.map +0 -1
  1238. package/dist/shared-tree-core/editManagerFormatV5.d.ts.map +0 -1
  1239. package/dist/shared-tree-core/editManagerFormatV5.js.map +0 -1
  1240. package/dist/shared-tree-core/messageCodecV5.d.ts.map +0 -1
  1241. package/dist/shared-tree-core/messageCodecV5.js.map +0 -1
  1242. package/dist/shared-tree-core/messageFormatV5.d.ts.map +0 -1
  1243. package/dist/shared-tree-core/messageFormatV5.js.map +0 -1
  1244. package/dist/simple-tree/api/viewSchemaToSimpleSchema.d.ts +0 -40
  1245. package/dist/simple-tree/api/viewSchemaToSimpleSchema.d.ts.map +0 -1
  1246. package/dist/simple-tree/api/viewSchemaToSimpleSchema.js +0 -177
  1247. package/dist/simple-tree/api/viewSchemaToSimpleSchema.js.map +0 -1
  1248. package/docs/main/sequence-field/move-composition.md +0 -46
  1249. package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +0 -1
  1250. package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +0 -1
  1251. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.d.ts +0 -9
  1252. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.d.ts.map +0 -1
  1253. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.js +0 -46
  1254. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.js.map +0 -1
  1255. package/lib/shared-tree-core/editManagerCodecsV5.d.ts.map +0 -1
  1256. package/lib/shared-tree-core/editManagerCodecsV5.js.map +0 -1
  1257. package/lib/shared-tree-core/editManagerFormatV5.d.ts.map +0 -1
  1258. package/lib/shared-tree-core/editManagerFormatV5.js.map +0 -1
  1259. package/lib/shared-tree-core/messageCodecV5.d.ts.map +0 -1
  1260. package/lib/shared-tree-core/messageCodecV5.js.map +0 -1
  1261. package/lib/shared-tree-core/messageFormatV5.d.ts.map +0 -1
  1262. package/lib/shared-tree-core/messageFormatV5.js.map +0 -1
  1263. package/lib/simple-tree/api/viewSchemaToSimpleSchema.d.ts +0 -40
  1264. package/lib/simple-tree/api/viewSchemaToSimpleSchema.d.ts.map +0 -1
  1265. package/lib/simple-tree/api/viewSchemaToSimpleSchema.js +0 -171
  1266. package/lib/simple-tree/api/viewSchemaToSimpleSchema.js.map +0 -1
  1267. package/src/feature-libraries/sequence-field/relevantRemovedRoots.ts +0 -57
  1268. package/src/simple-tree/api/viewSchemaToSimpleSchema.ts +0 -209
@@ -22,12 +22,10 @@ import {
22
22
  EditBuilder,
23
23
  type FieldKey,
24
24
  type FieldKindIdentifier,
25
- type FieldUpPath,
26
25
  type RevisionInfo,
27
26
  type RevisionMetadataSource,
28
27
  type RevisionTag,
29
28
  type TaggedChange,
30
- type UpPath,
31
29
  makeDetachedNodeId,
32
30
  replaceAtomRevisions,
33
31
  revisionMetadataSourceFromInfo,
@@ -36,10 +34,18 @@ import {
36
34
  areEqualChangeAtomIdOpts,
37
35
  tagChange,
38
36
  makeAnonChange,
39
- newChangeAtomIdRangeMap,
40
37
  type DeltaDetachedNodeChanges,
41
38
  type DeltaDetachedNodeRename,
42
39
  mapTaggedChange,
40
+ newChangeAtomIdRangeMap,
41
+ newChangeAtomIdTransform,
42
+ type ChangeAtomIdRangeMap,
43
+ offsetChangeAtomId,
44
+ type NormalizedUpPath,
45
+ type NormalizedFieldUpPath,
46
+ isDetachedUpPathRoot,
47
+ subtractChangeAtomIds,
48
+ makeChangeAtomId,
43
49
  } from "../../core/index.js";
44
50
  import {
45
51
  type IdAllocationState,
@@ -55,14 +61,19 @@ import {
55
61
  type TupleBTree,
56
62
  RangeMap,
57
63
  balancedReduce,
64
+ type RangeQueryEntry,
65
+ type RangeQueryResultFragment,
58
66
  } from "../../util/index.js";
59
67
  import type { TreeChunk } from "../chunked-forest/index.js";
60
68
 
61
69
  import {
62
- type CrossFieldManager,
70
+ type ComposeNodeManager,
63
71
  type CrossFieldMap,
64
72
  CrossFieldTarget,
65
- getFirstFromCrossFieldMap,
73
+ type DetachedNodeEntry,
74
+ type InvertNodeManager,
75
+ type RebaseDetachedNodeEntry,
76
+ type RebaseNodeManager,
66
77
  setInCrossFieldMap,
67
78
  } from "./crossFieldQueries.js";
68
79
  import {
@@ -74,17 +85,25 @@ import { convertGenericChange, genericFieldKind } from "./genericFieldKind.js";
74
85
  import type { GenericChangeset } from "./genericFieldKindTypes.js";
75
86
  import {
76
87
  type ChangeAtomIdBTree,
88
+ type ChangeAtomIdKey,
77
89
  type CrossFieldKey,
78
90
  type CrossFieldKeyRange,
79
91
  type CrossFieldKeyTable,
92
+ type CrossFieldRangeTable,
80
93
  type FieldChange,
81
94
  type FieldChangeMap,
82
95
  type FieldChangeset,
83
96
  type FieldId,
97
+ getFromChangeAtomIdMap,
84
98
  type ModularChangeset,
85
- newCrossFieldKeyTable,
99
+ newCrossFieldRangeTable,
86
100
  type NodeChangeset,
87
101
  type NodeId,
102
+ type NodeLocation,
103
+ rangeQueryChangeAtomIdMap,
104
+ type RebaseVersion,
105
+ type RootNodeTable,
106
+ setInChangeAtomIdMap,
88
107
  } from "./modularChangeTypes.js";
89
108
  import type { FlexFieldKind } from "./fieldKind.js";
90
109
 
@@ -171,14 +190,14 @@ export class ModularChangeFamily
171
190
  }
172
191
 
173
192
  public compose(changes: TaggedChange<ModularChangeset>[]): ModularChangeset {
174
- const { revInfos, maxId } = getRevInfoFromTaggedChanges(changes);
193
+ const { maxId } = getRevInfoFromTaggedChanges(changes);
175
194
  const idState: IdAllocationState = { maxId };
176
195
 
177
196
  const pairwiseDelegate = (
178
197
  left: ModularChangeset,
179
198
  right: ModularChangeset,
180
199
  ): ModularChangeset => {
181
- return this.composePair(left, right, revInfos, idState);
200
+ return this.composePair(left, right, idState);
182
201
  };
183
202
 
184
203
  const innerChanges = changes.map((change) => change.change);
@@ -188,10 +207,11 @@ export class ModularChangeFamily
188
207
  private composePair(
189
208
  change1: ModularChangeset,
190
209
  change2: ModularChangeset,
191
- revInfos: RevisionInfo[],
192
210
  idState: IdAllocationState,
193
211
  ): ModularChangeset {
194
- const { fieldChanges, nodeChanges, nodeToParent, nodeAliases, crossFieldKeys } =
212
+ const revInfos = composeRevInfos(change1.revisions, change2.revisions);
213
+
214
+ const { fieldChanges, nodeChanges, nodeToParent, nodeAliases, crossFieldKeys, rootNodes } =
195
215
  this.composeAllFields(change1, change2, revInfos, idState);
196
216
 
197
217
  const { allBuilds, allDestroys, allRefreshers } = composeBuildsDestroysAndRefreshers(
@@ -199,7 +219,7 @@ export class ModularChangeFamily
199
219
  change2,
200
220
  );
201
221
 
202
- return makeModularChangeset({
222
+ const composed = makeModularChangeset({
203
223
  fieldChanges,
204
224
  nodeChanges,
205
225
  nodeToParent,
@@ -207,10 +227,15 @@ export class ModularChangeFamily
207
227
  crossFieldKeys,
208
228
  maxId: idState.maxId,
209
229
  revisions: revInfos,
230
+ rootNodes,
210
231
  builds: allBuilds,
211
232
  destroys: allDestroys,
212
233
  refreshers: allRefreshers,
213
234
  });
235
+
236
+ // XXX: This is an expensive assert which should be disabled before merging.
237
+ this.validateChangeset(composed);
238
+ return composed;
214
239
  }
215
240
 
216
241
  private composeAllFields(
@@ -240,14 +265,38 @@ export class ModularChangeFamily
240
265
  mergeTupleBTrees(change1.nodeChanges, change2.nodeChanges),
241
266
  );
242
267
 
243
- const composedNodeToParent: ChangeAtomIdBTree<FieldId> = brand(
268
+ const composedNodeToParent: ChangeAtomIdBTree<NodeLocation> = brand(
244
269
  mergeTupleBTrees(change1.nodeToParent, change2.nodeToParent),
245
270
  );
246
271
  const composedNodeAliases: ChangeAtomIdBTree<NodeId> = brand(
247
272
  mergeTupleBTrees(change1.nodeAliases, change2.nodeAliases),
248
273
  );
249
274
 
250
- const crossFieldTable = newComposeTable(change1, change2, composedNodeToParent);
275
+ const pendingCompositions: PendingCompositions = {
276
+ nodeIdsToCompose: [],
277
+ affectedBaseFields: newTupleBTree(),
278
+ };
279
+
280
+ const movedCrossFieldKeys: CrossFieldKeyTable = newCrossFieldRangeTable();
281
+ const removedCrossFieldKeys: CrossFieldRangeTable<boolean> = newCrossFieldRangeTable();
282
+
283
+ const composedRoots = composeRootTables(
284
+ change1,
285
+ change2,
286
+ composedNodeToParent,
287
+ movedCrossFieldKeys,
288
+ removedCrossFieldKeys,
289
+ pendingCompositions,
290
+ );
291
+
292
+ const crossFieldTable = newComposeTable(
293
+ change1,
294
+ change2,
295
+ composedRoots,
296
+ movedCrossFieldKeys,
297
+ removedCrossFieldKeys,
298
+ pendingCompositions,
299
+ );
251
300
 
252
301
  const composedFields = this.composeFieldMaps(
253
302
  change1.fieldChanges,
@@ -268,17 +317,32 @@ export class ModularChangeFamily
268
317
  revisionMetadata,
269
318
  );
270
319
 
271
- // Currently no field kinds require making changes to cross-field keys during composition, so we can just merge the two tables.
272
- const composedCrossFieldKeys = RangeMap.union(
273
- change1.crossFieldKeys,
274
- change2.crossFieldKeys,
275
- );
320
+ for (const entry of crossFieldTable.renamesToDelete.entries()) {
321
+ deleteNodeRenameFrom(crossFieldTable.composedRootNodes, entry.start, entry.length);
322
+ }
323
+
324
+ for (const [nodeId, location] of crossFieldTable.movedNodeToParent.entries()) {
325
+ // Moved nodes are from change2.
326
+ // If there is a corresponding node in change1, then composedNodeToParent will already have the correct entry,
327
+ // because the location of the node is the same in change1 and the composed change
328
+ // (since they have the same input context).
329
+ if (crossFieldTable.newToBaseNodeId.get(nodeId) === undefined) {
330
+ composedNodeToParent.set(nodeId, location);
331
+ }
332
+ }
333
+
276
334
  return {
277
335
  fieldChanges: composedFields,
278
336
  nodeChanges: composedNodeChanges,
279
337
  nodeToParent: composedNodeToParent,
280
338
  nodeAliases: composedNodeAliases,
281
- crossFieldKeys: composedCrossFieldKeys,
339
+ crossFieldKeys: composeCrossFieldKeyTables(
340
+ change1.crossFieldKeys,
341
+ change2.crossFieldKeys,
342
+ crossFieldTable.movedCrossFieldKeys,
343
+ crossFieldTable.removedCrossFieldKeys,
344
+ ),
345
+ rootNodes: composedRoots,
282
346
  };
283
347
  }
284
348
 
@@ -290,17 +354,16 @@ export class ModularChangeFamily
290
354
  ): void {
291
355
  const context = crossFieldTable.fieldToContext.get(fieldChange);
292
356
  assert(context !== undefined, 0x8cc /* Should have context for every invalidated field */);
293
- const { fieldId, change1: fieldChange1, change2: fieldChange2, composedChange } = context;
357
+ const { change1: fieldChange1, change2: fieldChange2, composedChange } = context;
358
+
359
+ crossFieldTable.pendingCompositions.affectedBaseFields.delete(
360
+ fieldIdKeyFromFieldId(context.fieldId),
361
+ );
294
362
 
295
363
  const rebaser = getChangeHandler(this.fieldKinds, composedChange.fieldKind).rebaser;
296
364
  const composeNodes = (child1: NodeId | undefined, child2: NodeId | undefined): NodeId => {
297
- if (
298
- child1 !== undefined &&
299
- child2 !== undefined &&
300
- getFromChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2) === undefined
301
- ) {
302
- setInChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2, child1);
303
- crossFieldTable.pendingCompositions.nodeIdsToCompose.push([child1, child2]);
365
+ if (child1 !== undefined && child2 !== undefined) {
366
+ addNodesToCompose(crossFieldTable, child1, child2);
304
367
  }
305
368
 
306
369
  return child1 ?? child2 ?? fail(0xb22 /* Should not compose two undefined nodes */);
@@ -311,7 +374,7 @@ export class ModularChangeFamily
311
374
  fieldChange2,
312
375
  composeNodes,
313
376
  genId,
314
- new ComposeManager(crossFieldTable, fieldChange, fieldId, false),
377
+ new ComposeNodeManagerI(crossFieldTable, context.fieldId, false),
315
378
  revisionMetadata,
316
379
  );
317
380
  composedChange.change = brand(amendedChange);
@@ -323,7 +386,7 @@ export class ModularChangeFamily
323
386
  * - discovering that two node changesets refer to the same node (`nodeIdsToCompose`)
324
387
  * - a previously composed field being invalidated by a cross field effect (`invalidatedFields`)
325
388
  * - a field which was copied directly from an input changeset being invalidated by a cross field effect
326
- * (`affectedBaseFields` and `affectedNewFields`)
389
+ * (`affectedBaseFields`)
327
390
  *
328
391
  * Updating an element may invalidate further elements. This function runs until there is no more invalidation.
329
392
  */
@@ -331,72 +394,59 @@ export class ModularChangeFamily
331
394
  table: ComposeTable,
332
395
  composedFields: FieldChangeMap,
333
396
  composedNodes: ChangeAtomIdBTree<NodeChangeset>,
334
- composedNodeToParent: ChangeAtomIdBTree<FieldId>,
397
+ composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
335
398
  nodeAliases: ChangeAtomIdBTree<NodeId>,
336
399
  genId: IdAllocator,
337
400
  metadata: RevisionMetadataSource,
338
401
  ): void {
339
402
  const pending = table.pendingCompositions;
340
- while (
341
- table.invalidatedFields.size > 0 ||
342
- pending.nodeIdsToCompose.length > 0 ||
343
- pending.affectedBaseFields.length > 0 ||
344
- pending.affectedNewFields.length > 0
345
- ) {
346
- // Note that the call to `composeNodesById` can add entries to `crossFieldTable.nodeIdPairs`.
347
- for (const [id1, id2] of pending.nodeIdsToCompose) {
348
- this.composeNodesById(
349
- table.baseChange.nodeChanges,
350
- table.newChange.nodeChanges,
351
- composedNodes,
352
- composedNodeToParent,
353
- nodeAliases,
354
- id1,
355
- id2,
356
- genId,
357
- table,
358
- metadata,
359
- );
360
- }
361
-
362
- pending.nodeIdsToCompose.length = 0;
363
-
364
- this.composeAffectedFields(
403
+ while (pending.nodeIdsToCompose.length > 0 || pending.affectedBaseFields.length > 0) {
404
+ this.processPendingNodeCompositions(
365
405
  table,
366
- table.baseChange,
367
- true,
368
- pending.affectedBaseFields,
369
- composedFields,
370
406
  composedNodes,
407
+ composedNodeToParent,
408
+ nodeAliases,
371
409
  genId,
372
410
  metadata,
373
411
  );
374
412
 
375
413
  this.composeAffectedFields(
376
414
  table,
377
- table.newChange,
378
- false,
379
- pending.affectedNewFields,
415
+ table.baseChange,
416
+ pending.affectedBaseFields,
380
417
  composedFields,
381
418
  composedNodes,
382
419
  genId,
383
420
  metadata,
384
421
  );
385
-
386
- this.processInvalidatedCompositions(table, genId, metadata);
387
422
  }
388
423
  }
389
424
 
390
- private processInvalidatedCompositions(
425
+ private processPendingNodeCompositions(
391
426
  table: ComposeTable,
427
+ composedNodes: ChangeAtomIdBTree<NodeChangeset>,
428
+ composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
429
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
392
430
  genId: IdAllocator,
393
431
  metadata: RevisionMetadataSource,
394
432
  ): void {
395
- const fieldsToUpdate = table.invalidatedFields;
396
- table.invalidatedFields = new Set();
397
- for (const fieldChange of fieldsToUpdate) {
398
- this.composeInvalidatedField(fieldChange, table, genId, metadata);
433
+ // Note that the call to `composeNodesById` can add entries to `crossFieldTable.nodeIdPairs`.
434
+ for (const [id1, id2] of table.pendingCompositions.nodeIdsToCompose) {
435
+ this.composeNodesById(
436
+ table.baseChange,
437
+ table.newChange,
438
+ composedNodes,
439
+ composedNodeToParent,
440
+ nodeAliases,
441
+ id1,
442
+ id2,
443
+ genId,
444
+ table,
445
+ metadata,
446
+ );
399
447
  }
448
+
449
+ table.pendingCompositions.nodeIdsToCompose.length = 0;
400
450
  }
401
451
 
402
452
  /**
@@ -413,63 +463,79 @@ export class ModularChangeFamily
413
463
  private composeAffectedFields(
414
464
  table: ComposeTable,
415
465
  change: ModularChangeset,
416
- areBaseFields: boolean,
417
466
  affectedFields: BTree<FieldIdKey, true>,
418
467
  composedFields: FieldChangeMap,
419
468
  composedNodes: ChangeAtomIdBTree<NodeChangeset>,
420
469
  genId: IdAllocator,
421
470
  metadata: RevisionMetadataSource,
422
471
  ): void {
423
- for (const fieldIdKey of affectedFields.keys()) {
424
- const fieldId = normalizeFieldId(fieldIdFromFieldIdKey(fieldIdKey), change.nodeAliases);
425
- const fieldChange = fieldChangeFromId(change.fieldChanges, change.nodeChanges, fieldId);
472
+ const fieldsToProcess = affectedFields.clone();
473
+ affectedFields.clear();
474
+
475
+ for (const fieldIdKey of fieldsToProcess.keys()) {
476
+ const fieldId = fieldIdFromFieldIdKey(fieldIdKey);
477
+ const fieldChange = fieldChangeFromId(change, fieldId);
426
478
 
427
479
  if (
428
480
  table.fieldToContext.has(fieldChange) ||
429
481
  table.newFieldToBaseField.has(fieldChange)
430
482
  ) {
431
- // This function handles fields which were not part of the intersection of the two changesets but which need to be updated anyway.
432
- // If we've already processed this field then either it is up to date
433
- // or there is pending inval which will be handled in processInvalidatedCompositions.
434
- continue;
483
+ this.composeInvalidatedField(fieldChange, table, genId, metadata);
484
+ } else {
485
+ this.composeFieldWithNoNewChange(
486
+ table,
487
+ fieldChange,
488
+ fieldId,
489
+ composedFields,
490
+ composedNodes,
491
+ genId,
492
+ metadata,
493
+ );
435
494
  }
495
+ }
496
+ }
436
497
 
437
- const emptyChange = this.createEmptyFieldChange(fieldChange.fieldKind);
438
- const [change1, change2] = areBaseFields
439
- ? [fieldChange, emptyChange]
440
- : [emptyChange, fieldChange];
441
-
442
- const composedField = this.composeFieldChanges(
443
- fieldId,
444
- change1,
445
- change2,
446
- genId,
447
- table,
448
- metadata,
449
- );
498
+ private composeFieldWithNoNewChange(
499
+ table: ComposeTable,
500
+ baseFieldChange: FieldChange,
501
+ fieldId: FieldId,
502
+ composedFields: FieldChangeMap,
503
+ composedNodes: ChangeAtomIdBTree<NodeChangeset>,
504
+ genId: IdAllocator,
505
+ metadata: RevisionMetadataSource,
506
+ ): void {
507
+ const emptyChange = this.createEmptyFieldChange(baseFieldChange.fieldKind);
450
508
 
451
- if (fieldId.nodeId === undefined) {
452
- composedFields.set(fieldId.field, composedField);
453
- continue;
454
- }
509
+ const composedField = this.composeFieldChanges(
510
+ fieldId,
511
+ baseFieldChange,
512
+ emptyChange,
513
+ genId,
514
+ table,
515
+ metadata,
516
+ );
455
517
 
456
- const nodeId =
457
- getFromChangeAtomIdMap(table.newToBaseNodeId, fieldId.nodeId) ?? fieldId.nodeId;
518
+ if (fieldId.nodeId === undefined) {
519
+ composedFields.set(fieldId.field, composedField);
520
+ return;
521
+ }
458
522
 
459
- let nodeChangeset = nodeChangeFromId(composedNodes, nodeId);
460
- if (!table.composedNodes.has(nodeChangeset)) {
461
- nodeChangeset = cloneNodeChangeset(nodeChangeset);
462
- setInChangeAtomIdMap(composedNodes, nodeId, nodeChangeset);
463
- }
523
+ const nodeId = normalizeNodeId(
524
+ getFromChangeAtomIdMap(table.newToBaseNodeId, fieldId.nodeId) ?? fieldId.nodeId,
525
+ table.baseChange.nodeAliases,
526
+ );
464
527
 
465
- if (nodeChangeset.fieldChanges === undefined) {
466
- nodeChangeset.fieldChanges = new Map();
467
- }
528
+ // We clone the node changeset before mutating it, as it may be from one of the input changesets.
529
+ const nodeChangeset: Mutable<NodeChangeset> = cloneNodeChangeset(
530
+ nodeChangeFromId(composedNodes, table.baseChange.nodeAliases, nodeId),
531
+ );
532
+ setInChangeAtomIdMap(composedNodes, nodeId, nodeChangeset);
468
533
 
469
- nodeChangeset.fieldChanges.set(fieldId.field, composedField);
534
+ if (nodeChangeset.fieldChanges === undefined) {
535
+ nodeChangeset.fieldChanges = new Map();
470
536
  }
471
537
 
472
- affectedFields.clear();
538
+ nodeChangeset.fieldChanges.set(fieldId.field, composedField);
473
539
  }
474
540
 
475
541
  private composeFieldMaps(
@@ -488,6 +554,18 @@ export class ModularChangeFamily
488
554
  for (const [field, fieldChange1] of change1) {
489
555
  const fieldId: FieldId = { nodeId: parentId, field };
490
556
  const fieldChange2 = change2.get(field);
557
+
558
+ const cachedComposedFieldChange =
559
+ crossFieldTable.fieldToContext.get(fieldChange1)?.composedChange;
560
+
561
+ if (fieldChange2 === undefined && cachedComposedFieldChange !== undefined) {
562
+ // This can happen if the field was previous processed in `composeFieldWithNoNewChange`.
563
+ // If `change2` does not have a change for this field, then without this check we would
564
+ // lose the composed field change and instead simply have `change1`'s change.
565
+ composedFields.set(field, cachedComposedFieldChange);
566
+ continue;
567
+ }
568
+
491
569
  const composedField =
492
570
  fieldChange2 !== undefined
493
571
  ? this.composeFieldChanges(
@@ -519,7 +597,7 @@ export class ModularChangeFamily
519
597
  * will be added to `crossFieldTable.pendingCompositions.nodeIdsToCompose`.
520
598
  *
521
599
  * Any fields which had cross-field information sent to them as part of this field composition
522
- * will be added to either `affectedBaseFields` or `affectedNewFields` in `crossFieldTable.pendingCompositions`.
600
+ * will be added to `affectedBaseFields` in `crossFieldTable.pendingCompositions`.
523
601
  *
524
602
  * Any composed `FieldChange` which is invalidated by new cross-field information will be added to `crossFieldTable.invalidatedFields`.
525
603
  */
@@ -538,15 +616,14 @@ export class ModularChangeFamily
538
616
  change2: change2Normalized,
539
617
  } = this.normalizeFieldChanges(change1, change2);
540
618
 
541
- const manager = new ComposeManager(crossFieldTable, change1, fieldId);
619
+ const manager = new ComposeNodeManagerI(crossFieldTable, fieldId);
542
620
 
543
621
  const composedChange = changeHandler.rebaser.compose(
544
622
  change1Normalized,
545
623
  change2Normalized,
546
624
  (child1, child2) => {
547
625
  if (child1 !== undefined && child2 !== undefined) {
548
- setInChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2, child1);
549
- crossFieldTable.pendingCompositions.nodeIdsToCompose.push([child1, child2]);
626
+ addNodesToCompose(crossFieldTable, child1, child2);
550
627
  }
551
628
  return child1 ?? child2 ?? fail(0xb23 /* Should not compose two undefined nodes */);
552
629
  },
@@ -572,19 +649,19 @@ export class ModularChangeFamily
572
649
  }
573
650
 
574
651
  private composeNodesById(
575
- nodeChanges1: ChangeAtomIdBTree<NodeChangeset>,
576
- nodeChanges2: ChangeAtomIdBTree<NodeChangeset>,
652
+ change1: ModularChangeset,
653
+ change2: ModularChangeset,
577
654
  composedNodes: ChangeAtomIdBTree<NodeChangeset>,
578
- composedNodeToParent: ChangeAtomIdBTree<FieldId>,
579
- nodeAliases: ChangeAtomIdBTree<NodeId>,
655
+ composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
656
+ composedAliases: ChangeAtomIdBTree<NodeId>,
580
657
  id1: NodeId,
581
658
  id2: NodeId,
582
659
  idAllocator: IdAllocator,
583
660
  crossFieldTable: ComposeTable,
584
661
  revisionMetadata: RevisionMetadataSource,
585
662
  ): void {
586
- const nodeChangeset1 = nodeChangeFromId(nodeChanges1, id1);
587
- const nodeChangeset2 = nodeChangeFromId(nodeChanges2, id2);
663
+ const nodeChangeset1 = nodeChangeFromId(change1.nodeChanges, change1.nodeAliases, id1);
664
+ const nodeChangeset2 = nodeChangeFromId(change2.nodeChanges, change2.nodeAliases, id2);
588
665
  const composedNodeChangeset = this.composeNodeChanges(
589
666
  id1,
590
667
  nodeChangeset1,
@@ -599,13 +676,11 @@ export class ModularChangeFamily
599
676
  if (!areEqualChangeAtomIds(id1, id2)) {
600
677
  composedNodes.delete([id2.revision, id2.localId]);
601
678
  composedNodeToParent.delete([id2.revision, id2.localId]);
602
- setInChangeAtomIdMap(nodeAliases, id2, id1);
679
+ setInChangeAtomIdMap(composedAliases, id2, id1);
603
680
 
604
681
  // We need to delete id1 to avoid forming a cycle in case id1 already had an alias.
605
- nodeAliases.delete([id1.revision, id1.localId]);
682
+ composedAliases.delete([id1.revision, id1.localId]);
606
683
  }
607
-
608
- crossFieldTable.composedNodes.add(composedNodeChangeset);
609
684
  }
610
685
 
611
686
  private composeNodeChanges(
@@ -640,7 +715,7 @@ export class ModularChangeFamily
640
715
  revisionMetadata,
641
716
  );
642
717
 
643
- const composedNodeChange: NodeChangeset = {};
718
+ const composedNodeChange: Mutable<NodeChangeset> = {};
644
719
 
645
720
  if (composedFieldChanges.size > 0) {
646
721
  composedNodeChange.fieldChanges = composedFieldChanges;
@@ -692,9 +767,14 @@ export class ModularChangeFamily
692
767
  const genId: IdAllocator = idAllocatorFromMaxId(change.change.maxId ?? -1);
693
768
 
694
769
  const crossFieldTable: InvertTable = {
695
- ...newCrossFieldTable<FieldChange>(),
770
+ change: change.change,
771
+ entries: newChangeAtomIdRangeMap(),
696
772
  originalFieldToContext: new Map(),
773
+ invertRevision: revisionForInvert,
697
774
  invertedNodeToParent: brand(change.change.nodeToParent.clone()),
775
+ invalidatedFields: new Set(),
776
+ invertedRoots: invertRootTable(change.change, isRollback),
777
+ attachToDetachId: newChangeAtomIdTransform(),
698
778
  };
699
779
  const { revInfos: oldRevInfos } = getRevInfoFromTaggedChanges([change]);
700
780
  const revisionMetadata = revisionMetadataSourceFromInfo(oldRevInfos);
@@ -735,7 +815,7 @@ export class ModularChangeFamily
735
815
  context !== undefined,
736
816
  0x851 /* Should have context for every invalidated field */,
737
817
  );
738
- const { invertedField, fieldId } = context;
818
+ const { invertedField } = context;
739
819
 
740
820
  const amendedChange = getChangeHandler(
741
821
  this.fieldKinds,
@@ -745,7 +825,7 @@ export class ModularChangeFamily
745
825
  isRollback,
746
826
  genId,
747
827
  revisionForInvert,
748
- new InvertManager(crossFieldTable, fieldChange, fieldId),
828
+ new InvertNodeManagerI(crossFieldTable, context.fieldId),
749
829
  revisionMetadata,
750
830
  );
751
831
  invertedField.change = brand(amendedChange);
@@ -754,10 +834,13 @@ export class ModularChangeFamily
754
834
 
755
835
  const crossFieldKeys = this.makeCrossFieldKeyTable(invertedFields, invertedNodes);
756
836
 
837
+ this.processInvertRenames(crossFieldTable);
838
+
757
839
  return makeModularChangeset({
758
840
  fieldChanges: invertedFields,
759
841
  nodeChanges: invertedNodes,
760
842
  nodeToParent: crossFieldTable.invertedNodeToParent,
843
+ rootNodes: crossFieldTable.invertedRoots,
761
844
  nodeAliases: change.change.nodeAliases,
762
845
  crossFieldKeys,
763
846
  maxId: genId.getMaxId(),
@@ -781,7 +864,7 @@ export class ModularChangeFamily
781
864
 
782
865
  for (const [field, fieldChange] of changes) {
783
866
  const fieldId = { nodeId: parentId, field };
784
- const manager = new InvertManager(crossFieldTable, fieldChange, fieldId);
867
+ const manager = new InvertNodeManagerI(crossFieldTable, fieldId);
785
868
  const invertedChange = getChangeHandler(
786
869
  this.fieldKinds,
787
870
  fieldChange.fieldKind,
@@ -818,7 +901,7 @@ export class ModularChangeFamily
818
901
  revisionMetadata: RevisionMetadataSource,
819
902
  revisionForInvert: RevisionTag,
820
903
  ): NodeChangeset {
821
- const inverse: NodeChangeset = {};
904
+ const inverse: Mutable<NodeChangeset> = {};
822
905
 
823
906
  // If the node has a constraint, it should be inverted to a node-exist-on-revert constraint. This ensure that if
824
907
  // the inverse is inverted again, the original input constraint will be restored.
@@ -848,6 +931,17 @@ export class ModularChangeFamily
848
931
  return inverse;
849
932
  }
850
933
 
934
+ private processInvertRenames(table: InvertTable): void {
935
+ for (const {
936
+ start: newAttachId,
937
+ value: originalDetachId,
938
+ length,
939
+ } of table.attachToDetachId.entries()) {
940
+ // Note that the detach location is already set in `invertDetach`.
941
+ addNodeRename(table.invertedRoots, originalDetachId, newAttachId, length, undefined);
942
+ }
943
+ }
944
+
851
945
  public rebase(
852
946
  taggedChange: TaggedChange<ModularChangeset>,
853
947
  potentiallyConflictedOver: TaggedChange<ModularChangeset>,
@@ -867,17 +961,41 @@ export class ModularChangeFamily
867
961
  const idState: IdAllocationState = { maxId };
868
962
  const genId: IdAllocator = idAllocatorFromState(idState);
869
963
 
964
+ const affectedBaseFields: TupleBTree<FieldIdKey, boolean> = newTupleBTree();
965
+ const nodesToRebase: [newChangeset: NodeId, baseChangeset: NodeId][] = [];
966
+
967
+ const rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation> = brand(
968
+ change.nodeToParent.clone(),
969
+ );
970
+
971
+ const rebaseVersion = Math.max(
972
+ change.rebaseVersion,
973
+ over.change.rebaseVersion,
974
+ ) as RebaseVersion;
975
+
976
+ const rebasedRootNodes = rebaseRoots(
977
+ change,
978
+ over.change,
979
+ affectedBaseFields,
980
+ nodesToRebase,
981
+ rebasedNodeToParent,
982
+ rebaseVersion,
983
+ );
870
984
  const crossFieldTable: RebaseTable = {
871
- ...newCrossFieldTable<FieldChange>(),
985
+ rebaseVersion,
986
+ entries: newDetachedEntryMap(),
872
987
  newChange: change,
873
988
  baseChange: over.change,
874
989
  baseFieldToContext: new Map(),
990
+ baseRoots: over.change.rootNodes,
991
+ rebasedRootNodes,
875
992
  baseToRebasedNodeId: newTupleBTree(),
876
993
  rebasedFields: new Set(),
877
- rebasedNodeToParent: brand(change.nodeToParent.clone()),
878
- rebasedCrossFieldKeys: change.crossFieldKeys.clone(),
994
+ rebasedNodeToParent,
995
+ rebasedDetachLocations: newChangeAtomIdRangeMap(),
996
+ movedDetaches: newChangeAtomIdRangeMap(),
879
997
  nodeIdPairs: [],
880
- affectedBaseFields: newTupleBTree(),
998
+ affectedBaseFields,
881
999
  fieldsWithUnattachedChild: new Set(),
882
1000
  };
883
1001
 
@@ -893,13 +1011,14 @@ export class ModularChangeFamily
893
1011
  const rebasedNodes: ChangeAtomIdBTree<NodeChangeset> = brand(change.nodeChanges.clone());
894
1012
 
895
1013
  const rebasedFields = this.rebaseIntersectingFields(
1014
+ nodesToRebase,
896
1015
  crossFieldTable,
897
1016
  rebasedNodes,
898
1017
  genId,
899
1018
  rebaseMetadata,
900
1019
  );
901
1020
 
902
- this.rebaseInvalidatedElements(
1021
+ this.rebaseInvalidatedFields(
903
1022
  rebasedFields,
904
1023
  rebasedNodes,
905
1024
  crossFieldTable,
@@ -907,25 +1026,59 @@ export class ModularChangeFamily
907
1026
  genId,
908
1027
  );
909
1028
 
1029
+ fixupRebasedDetachLocations(crossFieldTable);
1030
+
910
1031
  const constraintState = newConstraintState(change.constraintViolationCount ?? 0);
911
1032
  const revertConstraintState = newConstraintState(
912
1033
  change.constraintViolationCountOnRevert ?? 0,
913
1034
  );
914
- this.updateConstraintsForFields(
1035
+
1036
+ this.updateConstraints(
915
1037
  rebasedFields,
916
- NodeAttachState.Attached,
917
- NodeAttachState.Attached,
1038
+ rebasedNodes,
1039
+ rebasedRootNodes,
918
1040
  constraintState,
919
1041
  revertConstraintState,
920
- rebasedNodes,
1042
+ );
1043
+
1044
+ const fieldsWithRootMoves = getFieldsWithRootMoves(
1045
+ crossFieldTable.rebasedRootNodes,
1046
+ change.nodeAliases,
1047
+ );
1048
+
1049
+ const fieldToRootChanges = getFieldToRootChanges(
1050
+ crossFieldTable.rebasedRootNodes,
1051
+ change.nodeAliases,
921
1052
  );
922
1053
 
923
1054
  const rebased = makeModularChangeset({
924
- fieldChanges: this.pruneFieldMap(rebasedFields, rebasedNodes),
1055
+ fieldChanges: this.pruneFieldMap(
1056
+ rebasedFields,
1057
+ undefined,
1058
+ rebasedNodes,
1059
+ crossFieldTable.rebasedNodeToParent,
1060
+ change.nodeAliases,
1061
+ crossFieldTable.rebasedRootNodes,
1062
+ fieldsWithRootMoves,
1063
+ fieldToRootChanges,
1064
+ ),
925
1065
  nodeChanges: rebasedNodes,
926
1066
  nodeToParent: crossFieldTable.rebasedNodeToParent,
1067
+ rootNodes: this.pruneRoots(
1068
+ crossFieldTable.rebasedRootNodes,
1069
+ rebasedNodes,
1070
+ crossFieldTable.rebasedNodeToParent,
1071
+ change.nodeAliases,
1072
+ fieldsWithRootMoves,
1073
+ fieldToRootChanges,
1074
+ ),
1075
+ // TODO: Do we need to include aliases for node changesets added during rebasing?
927
1076
  nodeAliases: change.nodeAliases,
928
- crossFieldKeys: crossFieldTable.rebasedCrossFieldKeys,
1077
+ crossFieldKeys: rebaseCrossFieldKeys(
1078
+ change.crossFieldKeys,
1079
+ crossFieldTable.movedDetaches,
1080
+ crossFieldTable.rebasedDetachLocations,
1081
+ ),
929
1082
  maxId: idState.maxId,
930
1083
  revisions: change.revisions,
931
1084
  constraintViolationCount: constraintState.violationCount,
@@ -933,14 +1086,18 @@ export class ModularChangeFamily
933
1086
  builds: change.builds,
934
1087
  destroys: change.destroys,
935
1088
  refreshers: change.refreshers,
1089
+ rebaseVersion,
936
1090
  });
937
1091
 
1092
+ // XXX: This is an expensive assert which should be disabled before merging.
1093
+ this.validateChangeset(rebased);
938
1094
  return rebased;
939
1095
  }
940
1096
 
941
1097
  // This performs a first pass on all fields which have both new and base changes.
942
1098
  // TODO: Can we also handle additional passes in this method?
943
1099
  private rebaseIntersectingFields(
1100
+ rootChanges: [newChangeset: NodeId, baseChangeset: NodeId][],
944
1101
  crossFieldTable: RebaseTable,
945
1102
  rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
946
1103
  genId: IdAllocator,
@@ -957,6 +1114,18 @@ export class ModularChangeFamily
957
1114
  metadata,
958
1115
  );
959
1116
 
1117
+ for (const [newChildChange, baseChildChange] of rootChanges) {
1118
+ const rebasedNode = this.rebaseNodeChange(
1119
+ newChildChange,
1120
+ baseChildChange,
1121
+ genId,
1122
+ crossFieldTable,
1123
+ metadata,
1124
+ );
1125
+
1126
+ setInChangeAtomIdMap(rebasedNodes, newChildChange, rebasedNode);
1127
+ }
1128
+
960
1129
  // This loop processes all fields which have both base and new changes.
961
1130
  // Note that the call to `rebaseNodeChange` can add entries to `crossFieldTable.nodeIdPairs`.
962
1131
  for (const [newId, baseId, _attachState] of crossFieldTable.nodeIdPairs) {
@@ -974,146 +1143,150 @@ export class ModularChangeFamily
974
1143
  return rebasedFields;
975
1144
  }
976
1145
 
977
- // This processes fields which have no new changes but have been invalidated by another field.
978
- private rebaseFieldsWithoutNewChanges(
1146
+ private rebaseFieldWithoutNewChanges(
1147
+ baseFieldChange: FieldChange,
1148
+ baseFieldId: FieldId,
1149
+ crossFieldTable: RebaseTable,
979
1150
  rebasedFields: FieldChangeMap,
980
1151
  rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
981
- crossFieldTable: RebaseTable,
982
1152
  genId: IdAllocator,
983
1153
  metadata: RebaseRevisionMetadata,
1154
+
1155
+ /**
1156
+ * The ID of a node in `baseFieldChange` which should be included in the rebased field change.
1157
+ */
1158
+ baseNodeId?: NodeId,
984
1159
  ): void {
985
- const baseChange = crossFieldTable.baseChange;
986
- for (const [revision, localId, fieldKey] of crossFieldTable.affectedBaseFields.keys()) {
987
- const baseNodeId =
988
- localId !== undefined
989
- ? normalizeNodeId({ revision, localId }, baseChange.nodeAliases)
990
- : undefined;
1160
+ // This field has no changes in the new changeset, otherwise it would have been added to
1161
+ // `crossFieldTable.baseFieldToContext` when processing fields with both base and new changes.
1162
+ const rebaseChild = (
1163
+ child: NodeId | undefined,
1164
+ baseChild: NodeId | undefined,
1165
+ stateChange: NodeAttachState | undefined,
1166
+ ): NodeId | undefined => {
1167
+ assert(child === undefined, 0x9c3 /* There should be no new changes in this field */);
1168
+ if (baseChild === undefined || baseNodeId === undefined) {
1169
+ return undefined;
1170
+ }
991
1171
 
992
- const baseFieldChange = fieldMapFromNodeId(
993
- baseChange.fieldChanges,
994
- baseChange.nodeChanges,
1172
+ return areEqualChangeAtomIds(
1173
+ normalizeNodeId(baseChild, crossFieldTable.baseChange.nodeAliases),
995
1174
  baseNodeId,
996
- ).get(fieldKey);
997
-
998
- assert(
999
- baseFieldChange !== undefined,
1000
- 0x9c2 /* Cross field key registered for empty field */,
1001
- );
1002
- if (crossFieldTable.baseFieldToContext.has(baseFieldChange)) {
1003
- // This field has already been processed because there were changes to rebase.
1004
- continue;
1005
- }
1175
+ )
1176
+ ? baseNodeId
1177
+ : undefined;
1178
+ };
1006
1179
 
1007
- // This field has no changes in the new changeset, otherwise it would have been added to
1008
- // `crossFieldTable.baseFieldToContext` when processing fields with both base and new changes.
1009
- const rebaseChild = (
1010
- child: NodeId | undefined,
1011
- baseChild: NodeId | undefined,
1012
- stateChange: NodeAttachState | undefined,
1013
- ): NodeId | undefined => {
1014
- assert(child === undefined, 0x9c3 /* There should be no new changes in this field */);
1015
- return undefined;
1016
- };
1180
+ const handler = getChangeHandler(this.fieldKinds, baseFieldChange.fieldKind);
1181
+ const fieldChange: FieldChange = {
1182
+ ...baseFieldChange,
1183
+ change: brand(handler.createEmpty()),
1184
+ };
1017
1185
 
1018
- const handler = getChangeHandler(this.fieldKinds, baseFieldChange.fieldKind);
1019
- const fieldChange: FieldChange = {
1020
- ...baseFieldChange,
1021
- change: brand(handler.createEmpty()),
1022
- };
1186
+ const rebasedNodeId =
1187
+ baseFieldId.nodeId !== undefined
1188
+ ? rebasedNodeIdFromBaseNodeId(crossFieldTable, baseFieldId.nodeId)
1189
+ : undefined;
1023
1190
 
1024
- const rebasedNodeId =
1025
- baseNodeId !== undefined
1026
- ? rebasedNodeIdFromBaseNodeId(crossFieldTable, baseNodeId)
1027
- : undefined;
1191
+ const fieldId: FieldId = { nodeId: rebasedNodeId, field: baseFieldId.field };
1028
1192
 
1029
- const fieldId: FieldId = { nodeId: rebasedNodeId, field: fieldKey };
1030
- const rebasedField: unknown = handler.rebaser.rebase(
1031
- fieldChange.change,
1032
- baseFieldChange.change,
1033
- rebaseChild,
1034
- genId,
1035
- new RebaseManager(crossFieldTable, baseFieldChange, fieldId),
1036
- metadata,
1037
- );
1193
+ const rebasedField: unknown = handler.rebaser.rebase(
1194
+ fieldChange.change,
1195
+ baseFieldChange.change,
1196
+ rebaseChild,
1197
+ genId,
1198
+ new RebaseNodeManagerI(crossFieldTable, fieldId),
1199
+ metadata,
1200
+ crossFieldTable.rebaseVersion,
1201
+ );
1038
1202
 
1039
- const rebasedFieldChange: FieldChange = {
1040
- ...baseFieldChange,
1041
- change: brand(rebasedField),
1042
- };
1203
+ const rebasedFieldChange: FieldChange = {
1204
+ ...baseFieldChange,
1205
+ change: brand(rebasedField),
1206
+ };
1043
1207
 
1044
- // TODO: Deduplicate
1045
- crossFieldTable.baseFieldToContext.set(baseFieldChange, {
1046
- newChange: fieldChange,
1047
- baseChange: baseFieldChange,
1048
- rebasedChange: rebasedFieldChange,
1049
- fieldId,
1050
- baseNodeIds: [],
1051
- });
1052
- crossFieldTable.rebasedFields.add(rebasedFieldChange);
1208
+ const context: RebaseFieldContext = {
1209
+ newChange: fieldChange,
1210
+ baseChange: baseFieldChange,
1211
+ rebasedChange: rebasedFieldChange,
1212
+ fieldId,
1213
+ baseNodeIds: newTupleBTree(),
1214
+ };
1053
1215
 
1054
- this.attachRebasedField(
1055
- rebasedFields,
1056
- rebasedNodes,
1057
- crossFieldTable,
1058
- rebasedFieldChange,
1059
- fieldId,
1060
- genId,
1061
- metadata,
1062
- );
1216
+ if (baseNodeId !== undefined) {
1217
+ setInChangeAtomIdMap(context.baseNodeIds, baseNodeId, true);
1063
1218
  }
1064
- }
1065
1219
 
1066
- private rebaseInvalidatedElements(
1067
- rebasedFields: FieldChangeMap,
1068
- rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
1069
- table: RebaseTable,
1070
- metadata: RebaseRevisionMetadata,
1071
- idAllocator: IdAllocator,
1072
- ): void {
1073
- this.rebaseFieldsWithoutNewChanges(
1220
+ crossFieldTable.baseFieldToContext.set(baseFieldChange, context);
1221
+
1222
+ crossFieldTable.rebasedFields.add(rebasedFieldChange);
1223
+
1224
+ this.attachRebasedField(
1074
1225
  rebasedFields,
1075
1226
  rebasedNodes,
1076
- table,
1077
- idAllocator,
1227
+ crossFieldTable,
1228
+ rebasedFieldChange,
1229
+ fieldId,
1230
+ genId,
1078
1231
  metadata,
1079
1232
  );
1080
-
1081
- this.rebaseFieldsWithUnattachedChild(table, metadata, idAllocator);
1082
- this.rebaseInvalidatedFields(table, metadata, idAllocator);
1083
1233
  }
1084
1234
 
1085
1235
  private rebaseInvalidatedFields(
1236
+ rebasedFields: FieldChangeMap,
1237
+ rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
1086
1238
  crossFieldTable: RebaseTable,
1087
1239
  rebaseMetadata: RebaseRevisionMetadata,
1088
1240
  genId: IdAllocator,
1089
1241
  ): void {
1090
- const fieldsToUpdate = crossFieldTable.invalidatedFields;
1091
- crossFieldTable.invalidatedFields = new Set();
1092
- for (const field of fieldsToUpdate) {
1093
- this.rebaseInvalidatedField(field, crossFieldTable, rebaseMetadata, genId);
1094
- }
1095
- }
1242
+ while (crossFieldTable.affectedBaseFields.size > 0) {
1243
+ const baseFields = crossFieldTable.affectedBaseFields.clone();
1244
+ crossFieldTable.affectedBaseFields.clear();
1245
+
1246
+ for (const baseFieldIdKey of baseFields.keys()) {
1247
+ const baseFieldId = normalizeFieldId(
1248
+ fieldIdFromFieldIdKey(baseFieldIdKey),
1249
+ crossFieldTable.baseChange.nodeAliases,
1250
+ );
1096
1251
 
1097
- private rebaseFieldsWithUnattachedChild(
1098
- table: RebaseTable,
1099
- metadata: RebaseRevisionMetadata,
1100
- idAllocator: IdAllocator,
1101
- ): void {
1102
- for (const field of table.fieldsWithUnattachedChild) {
1103
- table.invalidatedFields.delete(field);
1104
- this.rebaseInvalidatedField(field, table, metadata, idAllocator, true);
1252
+ const baseField = fieldChangeFromId(crossFieldTable.baseChange, baseFieldId);
1253
+
1254
+ assert(
1255
+ baseField !== undefined,
1256
+ 0x9c2 /* Cross field key registered for empty field */,
1257
+ );
1258
+
1259
+ const context = crossFieldTable.baseFieldToContext.get(baseField);
1260
+ if (context === undefined) {
1261
+ this.rebaseFieldWithoutNewChanges(
1262
+ baseField,
1263
+ baseFieldId,
1264
+ crossFieldTable,
1265
+ rebasedFields,
1266
+ rebasedNodes,
1267
+ genId,
1268
+ rebaseMetadata,
1269
+ );
1270
+ } else {
1271
+ this.rebaseInvalidatedField(
1272
+ baseField,
1273
+ crossFieldTable,
1274
+ context,
1275
+ rebaseMetadata,
1276
+ genId,
1277
+ );
1278
+ }
1279
+ }
1105
1280
  }
1106
1281
  }
1107
1282
 
1108
1283
  private rebaseInvalidatedField(
1109
1284
  baseField: FieldChange,
1110
1285
  crossFieldTable: RebaseTable,
1286
+ context: RebaseFieldContext,
1111
1287
  rebaseMetadata: RebaseRevisionMetadata,
1112
1288
  genId: IdAllocator,
1113
- allowInval = false,
1114
1289
  ): void {
1115
- const context = crossFieldTable.baseFieldToContext.get(baseField);
1116
- assert(context !== undefined, 0x852 /* Every field should have a context */);
1117
1290
  const {
1118
1291
  changeHandler,
1119
1292
  change1: fieldChangeset,
@@ -1128,25 +1301,28 @@ export class ModularChangeFamily
1128
1301
  return curr;
1129
1302
  }
1130
1303
 
1131
- if (base !== undefined) {
1132
- for (const id of context.baseNodeIds) {
1133
- if (areEqualChangeAtomIds(base, id)) {
1134
- return base;
1135
- }
1136
- }
1304
+ if (base !== undefined && getFromChangeAtomIdMap(context.baseNodeIds, base) === true) {
1305
+ return base;
1137
1306
  }
1138
1307
 
1139
1308
  return undefined;
1140
1309
  };
1141
1310
 
1311
+ let allowInval = false;
1312
+ if (crossFieldTable.fieldsWithUnattachedChild.has(baseField)) {
1313
+ crossFieldTable.fieldsWithUnattachedChild.delete(baseField);
1314
+ allowInval = true;
1315
+ }
1316
+
1142
1317
  context.rebasedChange.change = brand(
1143
1318
  changeHandler.rebaser.rebase(
1144
1319
  fieldChangeset,
1145
1320
  baseChangeset,
1146
1321
  rebaseChild,
1147
1322
  genId,
1148
- new RebaseManager(crossFieldTable, baseField, context.fieldId, allowInval),
1323
+ new RebaseNodeManagerI(crossFieldTable, context.fieldId, allowInval),
1149
1324
  rebaseMetadata,
1325
+ crossFieldTable.rebaseVersion,
1150
1326
  ),
1151
1327
  );
1152
1328
  }
@@ -1166,13 +1342,19 @@ export class ModularChangeFamily
1166
1342
  }
1167
1343
  const rebasedNode = getFromChangeAtomIdMap(rebasedNodes, nodeId);
1168
1344
  if (rebasedNode !== undefined) {
1169
- if (rebasedNode.fieldChanges === undefined) {
1170
- rebasedNode.fieldChanges = new Map([[fieldKey, rebasedField]]);
1345
+ const updatedRebasedNode: Mutable<NodeChangeset> = cloneNodeChangeset(rebasedNode);
1346
+ setInChangeAtomIdMap(rebasedNodes, nodeId, updatedRebasedNode);
1347
+
1348
+ if (updatedRebasedNode.fieldChanges === undefined) {
1349
+ updatedRebasedNode.fieldChanges = new Map([[fieldKey, rebasedField]]);
1171
1350
  return;
1172
1351
  }
1173
1352
 
1174
- assert(!rebasedNode.fieldChanges.has(fieldKey), 0x9c4 /* Expected an empty field */);
1175
- rebasedNode.fieldChanges.set(fieldKey, rebasedField);
1353
+ assert(
1354
+ !updatedRebasedNode.fieldChanges.has(fieldKey),
1355
+ 0x9c4 /* Expected an empty field */,
1356
+ );
1357
+ updatedRebasedNode.fieldChanges.set(fieldKey, rebasedField);
1176
1358
  return;
1177
1359
  }
1178
1360
 
@@ -1183,14 +1365,14 @@ export class ModularChangeFamily
1183
1365
  setInChangeAtomIdMap(rebasedNodes, nodeId, newNode);
1184
1366
  setInChangeAtomIdMap(table.baseToRebasedNodeId, nodeId, nodeId);
1185
1367
 
1186
- const parentFieldId = getParentFieldId(table.baseChange, nodeId);
1368
+ const parentBase = getNodeParent(table.baseChange, nodeId);
1187
1369
 
1188
1370
  this.attachRebasedNode(
1189
1371
  rebasedFields,
1190
1372
  rebasedNodes,
1191
1373
  table,
1192
1374
  nodeId,
1193
- parentFieldId,
1375
+ parentBase,
1194
1376
  idAllocator,
1195
1377
  metadata,
1196
1378
  );
@@ -1201,65 +1383,100 @@ export class ModularChangeFamily
1201
1383
  rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
1202
1384
  table: RebaseTable,
1203
1385
  baseNodeId: NodeId,
1204
- parentFieldIdBase: FieldId,
1386
+ parentBase: NodeLocation,
1205
1387
  idAllocator: IdAllocator,
1206
1388
  metadata: RebaseRevisionMetadata,
1207
1389
  ): void {
1208
- const baseFieldChange = fieldChangeFromId(
1209
- table.baseChange.fieldChanges,
1210
- table.baseChange.nodeChanges,
1211
- parentFieldIdBase,
1212
- );
1213
-
1214
- const rebasedFieldId = rebasedFieldIdFromBaseId(table, parentFieldIdBase);
1215
- setInChangeAtomIdMap(table.rebasedNodeToParent, baseNodeId, rebasedFieldId);
1390
+ if (parentBase.root !== undefined) {
1391
+ const renamedRoot = firstAttachIdFromDetachId(
1392
+ table.baseChange.rootNodes,
1393
+ parentBase.root,
1394
+ 1,
1395
+ ).value;
1396
+
1397
+ const attachField = table.baseChange.crossFieldKeys.getFirst(
1398
+ { ...renamedRoot, target: CrossFieldTarget.Destination },
1399
+ 1,
1400
+ ).value;
1401
+
1402
+ if (attachField !== undefined) {
1403
+ // The base change inserts this node into `attachField`, so the rebased change should represent this node there.
1404
+ const normalizedAttachField = normalizeFieldId(
1405
+ attachField,
1406
+ table.baseChange.nodeAliases,
1407
+ );
1408
+
1409
+ const entry: DetachedNodeEntry = table.entries.getFirst(renamedRoot, 1).value ?? {};
1410
+ table.entries.set(renamedRoot, 1, { ...entry, nodeChange: baseNodeId });
1411
+ table.affectedBaseFields.set(fieldIdKeyFromFieldId(normalizedAttachField), true);
1412
+ this.attachRebasedNode(
1413
+ rebasedFields,
1414
+ rebasedNodes,
1415
+ table,
1416
+ baseNodeId,
1417
+ { field: normalizedAttachField },
1418
+ idAllocator,
1419
+ metadata,
1420
+ );
1421
+ } else {
1422
+ const baseDetachLocation = table.baseChange.rootNodes.detachLocations.getFirst(
1423
+ parentBase.root,
1424
+ 1,
1425
+ ).value;
1426
+
1427
+ assignRootChange(
1428
+ table.rebasedRootNodes,
1429
+ table.rebasedNodeToParent,
1430
+ renamedRoot,
1431
+ baseNodeId,
1432
+ baseDetachLocation,
1433
+ table.rebaseVersion,
1434
+ );
1435
+
1436
+ // We need to make sure the rebased changeset includes the detach location,
1437
+ // so we add that field to `affectedBaseFields` unless it's already been processed.
1438
+ if (
1439
+ baseDetachLocation !== undefined &&
1440
+ !table.baseFieldToContext.has(
1441
+ fieldChangeFromId(table.baseChange, baseDetachLocation),
1442
+ )
1443
+ ) {
1444
+ table.affectedBaseFields.set(fieldIdKeyFromFieldId(baseDetachLocation), true);
1445
+ }
1446
+ }
1216
1447
 
1217
- const context = table.baseFieldToContext.get(baseFieldChange);
1218
- if (context !== undefined) {
1219
- // We've already processed this field.
1220
- // The new child node will be attached in rebaseFieldsWithUnattachedChild.
1221
- context.baseNodeIds.push(baseNodeId);
1222
- table.fieldsWithUnattachedChild.add(baseFieldChange);
1223
1448
  return;
1224
1449
  }
1225
1450
 
1226
- const handler = getChangeHandler(this.fieldKinds, baseFieldChange.fieldKind);
1227
-
1228
- const fieldChange: FieldChange = {
1229
- ...baseFieldChange,
1230
- change: brand(handler.createEmpty()),
1231
- };
1451
+ const parentFieldIdBase = parentBase.field;
1452
+ const baseFieldChange = fieldChangeFromId(table.baseChange, parentFieldIdBase);
1232
1453
 
1233
- const rebasedChangeset = handler.rebaser.rebase(
1234
- handler.createEmpty(),
1235
- baseFieldChange.change,
1236
- (_idNew, idBase) =>
1237
- idBase !== undefined && areEqualChangeAtomIds(idBase, baseNodeId)
1238
- ? baseNodeId
1239
- : undefined,
1240
- idAllocator,
1241
- new RebaseManager(table, baseFieldChange, rebasedFieldId),
1242
- metadata,
1243
- );
1454
+ const rebasedFieldId = rebasedFieldIdFromBaseId(table, parentFieldIdBase);
1455
+ setInChangeAtomIdMap(table.rebasedNodeToParent, baseNodeId, { field: rebasedFieldId });
1244
1456
 
1245
- const rebasedField: FieldChange = { ...baseFieldChange, change: brand(rebasedChangeset) };
1246
- table.rebasedFields.add(rebasedField);
1247
- table.baseFieldToContext.set(baseFieldChange, {
1248
- newChange: fieldChange,
1249
- baseChange: baseFieldChange,
1250
- rebasedChange: rebasedField,
1251
- fieldId: rebasedFieldId,
1252
- baseNodeIds: [],
1253
- });
1457
+ const context = table.baseFieldToContext.get(baseFieldChange);
1458
+ if (context !== undefined) {
1459
+ // We've already processed this field.
1460
+ // The new child node will be attached in the next pass.
1461
+ // Note that adding to `fieldsWithUnattachedChild` allows that field to generate new invalidations,
1462
+ // so to avoid invalidation cycles we make sure we only add to it once per new unattached child.
1463
+ // This is done by checking whether `context.baseNodeIds` already contained `baseNodeId`.
1464
+ if (setInChangeAtomIdMap(context.baseNodeIds, baseNodeId, true)) {
1465
+ table.fieldsWithUnattachedChild.add(baseFieldChange);
1466
+ table.affectedBaseFields.set(fieldIdKeyFromFieldId(parentFieldIdBase), true);
1467
+ }
1468
+ return;
1469
+ }
1254
1470
 
1255
- this.attachRebasedField(
1471
+ this.rebaseFieldWithoutNewChanges(
1472
+ baseFieldChange,
1473
+ parentFieldIdBase,
1474
+ table,
1256
1475
  rebasedFields,
1257
1476
  rebasedNodes,
1258
- table,
1259
- rebasedField,
1260
- rebasedFieldId,
1261
1477
  idAllocator,
1262
1478
  metadata,
1479
+ baseNodeId,
1263
1480
  );
1264
1481
  }
1265
1482
 
@@ -1298,7 +1515,7 @@ export class ModularChangeFamily
1298
1515
  change2: baseChangeset,
1299
1516
  } = this.normalizeFieldChanges(fieldChange, baseChange);
1300
1517
 
1301
- const manager = new RebaseManager(crossFieldTable, baseChange, fieldId);
1518
+ const manager = new RebaseNodeManagerI(crossFieldTable, fieldId);
1302
1519
 
1303
1520
  const rebasedField = changeHandler.rebaser.rebase(
1304
1521
  fieldChangeset,
@@ -1307,6 +1524,7 @@ export class ModularChangeFamily
1307
1524
  genId,
1308
1525
  manager,
1309
1526
  revisionMetadata,
1527
+ crossFieldTable.rebaseVersion,
1310
1528
  );
1311
1529
 
1312
1530
  const rebasedFieldChange: FieldChange = {
@@ -1321,7 +1539,7 @@ export class ModularChangeFamily
1321
1539
  newChange: fieldChange,
1322
1540
  rebasedChange: rebasedFieldChange,
1323
1541
  fieldId,
1324
- baseNodeIds: [],
1542
+ baseNodeIds: newTupleBTree(),
1325
1543
  });
1326
1544
 
1327
1545
  crossFieldTable.rebasedFields.add(rebasedFieldChange);
@@ -1337,8 +1555,16 @@ export class ModularChangeFamily
1337
1555
  crossFieldTable: RebaseTable,
1338
1556
  revisionMetadata: RebaseRevisionMetadata,
1339
1557
  ): NodeChangeset {
1340
- const change = nodeChangeFromId(crossFieldTable.newChange.nodeChanges, newId);
1341
- const over = nodeChangeFromId(crossFieldTable.baseChange.nodeChanges, baseId);
1558
+ const change = nodeChangeFromId(
1559
+ crossFieldTable.newChange.nodeChanges,
1560
+ crossFieldTable.newChange.nodeAliases,
1561
+ newId,
1562
+ );
1563
+ const over = nodeChangeFromId(
1564
+ crossFieldTable.baseChange.nodeChanges,
1565
+ crossFieldTable.baseChange.nodeAliases,
1566
+ baseId,
1567
+ );
1342
1568
 
1343
1569
  const baseMap: FieldChangeMap = over?.fieldChanges ?? new Map();
1344
1570
 
@@ -1354,7 +1580,7 @@ export class ModularChangeFamily
1354
1580
  )
1355
1581
  : change.fieldChanges;
1356
1582
 
1357
- const rebasedChange: NodeChangeset = {};
1583
+ const rebasedChange: Mutable<NodeChangeset> = {};
1358
1584
 
1359
1585
  if (fieldChanges !== undefined && fieldChanges.size > 0) {
1360
1586
  rebasedChange.fieldChanges = fieldChanges;
@@ -1372,6 +1598,37 @@ export class ModularChangeFamily
1372
1598
  return rebasedChange;
1373
1599
  }
1374
1600
 
1601
+ private updateConstraints(
1602
+ rebasedFields: FieldChangeMap,
1603
+ rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
1604
+ rebasedRoots: RootNodeTable,
1605
+ constraintState: ConstraintState,
1606
+ revertConstraintState: ConstraintState,
1607
+ ): void {
1608
+ this.updateConstraintsForFields(
1609
+ rebasedFields,
1610
+ NodeAttachState.Attached,
1611
+ NodeAttachState.Attached,
1612
+ constraintState,
1613
+ revertConstraintState,
1614
+ rebasedNodes,
1615
+ );
1616
+
1617
+ for (const [_detachId, nodeId] of rebasedRoots.nodeChanges.entries()) {
1618
+ // XXX: This is incorrect if the rebased changeset attaches the node.
1619
+ // Efficiently computing whether the changeset attaches the node would require maintaining a mapping from node ID to attach ID.
1620
+ const detachedInOutput = true;
1621
+ this.updateConstraintsForNode(
1622
+ nodeId,
1623
+ NodeAttachState.Detached,
1624
+ detachedInOutput ? NodeAttachState.Detached : NodeAttachState.Attached,
1625
+ rebasedNodes,
1626
+ constraintState,
1627
+ revertConstraintState,
1628
+ );
1629
+ }
1630
+ }
1631
+
1375
1632
  private updateConstraintsForFields(
1376
1633
  fields: FieldChangeMap,
1377
1634
  parentInputAttachState: NodeAttachState,
@@ -1382,20 +1639,18 @@ export class ModularChangeFamily
1382
1639
  ): void {
1383
1640
  for (const field of fields.values()) {
1384
1641
  const handler = getChangeHandler(this.fieldKinds, field.fieldKind);
1385
- for (const [nodeId, inputIndex, outputIndex] of handler.getNestedChanges(field.change)) {
1386
- const isInputDetached = inputIndex === undefined;
1387
- const inputAttachState =
1388
- parentInputAttachState === NodeAttachState.Detached || isInputDetached
1389
- ? NodeAttachState.Detached
1390
- : NodeAttachState.Attached;
1391
- const isOutputDetached = outputIndex === undefined;
1642
+ for (const [nodeId] of handler.getNestedChanges(field.change)) {
1643
+ // XXX: This is incorrect if the rebased changeset detaches this node.
1644
+ // Efficiently computing whether the changeset detaches the node would require maintaining a mapping from node ID to detach ID.
1645
+ const isOutputDetached = false;
1392
1646
  const outputAttachState =
1393
1647
  parentOutputAttachState === NodeAttachState.Detached || isOutputDetached
1394
1648
  ? NodeAttachState.Detached
1395
1649
  : NodeAttachState.Attached;
1650
+
1396
1651
  this.updateConstraintsForNode(
1397
1652
  nodeId,
1398
- inputAttachState,
1653
+ parentInputAttachState,
1399
1654
  outputAttachState,
1400
1655
  nodes,
1401
1656
  constraintState,
@@ -1413,12 +1668,15 @@ export class ModularChangeFamily
1413
1668
  constraintState: ConstraintState,
1414
1669
  revertConstraintState: ConstraintState,
1415
1670
  ): void {
1416
- const node =
1417
- nodes.get([nodeId.revision, nodeId.localId]) ?? fail(0xb24 /* Unknown node ID */);
1671
+ const node = getFromChangeAtomIdMap(nodes, nodeId) ?? fail(0xb24 /* Unknown node ID */);
1672
+
1673
+ const updatedNode: Mutable<NodeChangeset> = { ...node };
1674
+ setInChangeAtomIdMap(nodes, nodeId, updatedNode);
1675
+
1418
1676
  if (node.nodeExistsConstraint !== undefined) {
1419
1677
  const isNowViolated = inputAttachState === NodeAttachState.Detached;
1420
1678
  if (node.nodeExistsConstraint.violated !== isNowViolated) {
1421
- node.nodeExistsConstraint = {
1679
+ updatedNode.nodeExistsConstraint = {
1422
1680
  ...node.nodeExistsConstraint,
1423
1681
  violated: isNowViolated,
1424
1682
  };
@@ -1428,7 +1686,7 @@ export class ModularChangeFamily
1428
1686
  if (node.nodeExistsConstraintOnRevert !== undefined) {
1429
1687
  const isNowViolated = outputAttachState === NodeAttachState.Detached;
1430
1688
  if (node.nodeExistsConstraintOnRevert.violated !== isNowViolated) {
1431
- node.nodeExistsConstraintOnRevert = {
1689
+ updatedNode.nodeExistsConstraintOnRevert = {
1432
1690
  ...node.nodeExistsConstraintOnRevert,
1433
1691
  violated: isNowViolated,
1434
1692
  };
@@ -1450,7 +1708,13 @@ export class ModularChangeFamily
1450
1708
 
1451
1709
  private pruneFieldMap(
1452
1710
  changeset: FieldChangeMap | undefined,
1711
+ parentId: NodeId | undefined,
1453
1712
  nodeMap: ChangeAtomIdBTree<NodeChangeset>,
1713
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>,
1714
+ aliases: ChangeAtomIdBTree<NodeId>,
1715
+ roots: RootNodeTable,
1716
+ fieldsWithRootMoves: TupleBTree<FieldIdKey, boolean>,
1717
+ fieldsToRootChanges: TupleBTree<FieldIdKey, ChangeAtomId[]>,
1454
1718
  ): FieldChangeMap | undefined {
1455
1719
  if (changeset === undefined) {
1456
1720
  return undefined;
@@ -1461,10 +1725,48 @@ export class ModularChangeFamily
1461
1725
  const handler = getChangeHandler(this.fieldKinds, fieldChange.fieldKind);
1462
1726
 
1463
1727
  const prunedFieldChangeset = handler.rebaser.prune(fieldChange.change, (nodeId) =>
1464
- this.pruneNodeChange(nodeId, nodeMap),
1728
+ this.pruneNodeChange(
1729
+ nodeId,
1730
+ nodeMap,
1731
+ nodeToParent,
1732
+ aliases,
1733
+ roots,
1734
+ fieldsWithRootMoves,
1735
+ fieldsToRootChanges,
1736
+ ),
1465
1737
  );
1466
1738
 
1467
- if (!handler.isEmpty(prunedFieldChangeset)) {
1739
+ const fieldId: FieldId = { nodeId: parentId, field };
1740
+ const fieldIdKey = fieldIdKeyFromFieldId(fieldId);
1741
+ const rootsWithChanges = fieldsToRootChanges.get(fieldIdKey) ?? [];
1742
+ let hasRootWithNodeChange = false;
1743
+ for (const rootId of rootsWithChanges) {
1744
+ const nodeId =
1745
+ getFromChangeAtomIdMap(roots.nodeChanges, rootId) ?? fail("No root change found");
1746
+
1747
+ const isRootChangeEmpty =
1748
+ this.pruneNodeChange(
1749
+ nodeId,
1750
+ nodeMap,
1751
+ nodeToParent,
1752
+ aliases,
1753
+ roots,
1754
+ fieldsWithRootMoves,
1755
+ fieldsToRootChanges,
1756
+ ) === undefined;
1757
+
1758
+ if (isRootChangeEmpty) {
1759
+ roots.nodeChanges.delete([rootId.revision, rootId.localId]);
1760
+ tryRemoveDetachLocation(roots, rootId, 1);
1761
+ } else {
1762
+ hasRootWithNodeChange = true;
1763
+ }
1764
+ }
1765
+
1766
+ const hasRootChanges =
1767
+ hasRootWithNodeChange || fieldsWithRootMoves.get(fieldIdKey) === true;
1768
+
1769
+ if (!handler.isEmpty(prunedFieldChangeset) || hasRootChanges) {
1468
1770
  prunedChangeset.set(field, { ...fieldChange, change: brand(prunedFieldChangeset) });
1469
1771
  }
1470
1772
  }
@@ -1472,14 +1774,64 @@ export class ModularChangeFamily
1472
1774
  return prunedChangeset.size > 0 ? prunedChangeset : undefined;
1473
1775
  }
1474
1776
 
1777
+ private pruneRoots(
1778
+ roots: RootNodeTable,
1779
+ nodeMap: ChangeAtomIdBTree<NodeChangeset>,
1780
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>,
1781
+ aliases: ChangeAtomIdBTree<NodeId>,
1782
+ fieldsWithRootMoves: TupleBTree<FieldIdKey, boolean>,
1783
+ fieldsToRootChanges: TupleBTree<FieldIdKey, ChangeAtomId[]>,
1784
+ ): RootNodeTable {
1785
+ const pruned: RootNodeTable = { ...roots, nodeChanges: newTupleBTree() };
1786
+ for (const [rootIdKey, nodeId] of roots.nodeChanges.entries()) {
1787
+ const rootId: ChangeAtomId = { revision: rootIdKey[0], localId: rootIdKey[1] };
1788
+ const hasDetachLocation = roots.detachLocations.getFirst(rootId, 1).value !== undefined;
1789
+
1790
+ // If the root has a detach location it should be pruned by recursion when pruning the field it was detached from.
1791
+ const prunedId = hasDetachLocation
1792
+ ? nodeId
1793
+ : this.pruneNodeChange(
1794
+ nodeId,
1795
+ nodeMap,
1796
+ nodeToParent,
1797
+ aliases,
1798
+ roots,
1799
+ fieldsWithRootMoves,
1800
+ fieldsToRootChanges,
1801
+ );
1802
+
1803
+ if (prunedId !== undefined) {
1804
+ pruned.nodeChanges.set(rootIdKey, prunedId);
1805
+ }
1806
+
1807
+ tryRemoveDetachLocation(pruned, rootId, 1);
1808
+ }
1809
+
1810
+ return pruned;
1811
+ }
1812
+
1475
1813
  private pruneNodeChange(
1476
1814
  nodeId: NodeId,
1477
- nodeMap: ChangeAtomIdBTree<NodeChangeset>,
1815
+ nodes: ChangeAtomIdBTree<NodeChangeset>,
1816
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>,
1817
+ aliases: ChangeAtomIdBTree<NodeId>,
1818
+ roots: RootNodeTable,
1819
+ fieldsWithRootMoves: TupleBTree<FieldIdKey, boolean>,
1820
+ fieldsToRootChanges: TupleBTree<FieldIdKey, ChangeAtomId[]>,
1478
1821
  ): NodeId | undefined {
1479
- const changeset = nodeChangeFromId(nodeMap, nodeId);
1822
+ const changeset = nodeChangeFromId(nodes, aliases, nodeId);
1480
1823
  const prunedFields =
1481
1824
  changeset.fieldChanges !== undefined
1482
- ? this.pruneFieldMap(changeset.fieldChanges, nodeMap)
1825
+ ? this.pruneFieldMap(
1826
+ changeset.fieldChanges,
1827
+ nodeId,
1828
+ nodes,
1829
+ nodeToParent,
1830
+ aliases,
1831
+ roots,
1832
+ fieldsWithRootMoves,
1833
+ fieldsToRootChanges,
1834
+ )
1483
1835
  : undefined;
1484
1836
 
1485
1837
  const prunedChange = { ...changeset, fieldChanges: prunedFields };
@@ -1488,10 +1840,14 @@ export class ModularChangeFamily
1488
1840
  }
1489
1841
 
1490
1842
  if (isEmptyNodeChangeset(prunedChange)) {
1491
- nodeMap.delete([nodeId.revision, nodeId.localId]);
1843
+ const nodeIdKey: ChangeAtomIdKey = [nodeId.revision, nodeId.localId];
1844
+
1845
+ // TODO: Shouldn't we also delete all aliases associated with this node?
1846
+ nodes.delete(nodeIdKey);
1847
+ nodeToParent.delete(nodeIdKey);
1492
1848
  return undefined;
1493
1849
  } else {
1494
- setInChangeAtomIdMap(nodeMap, nodeId, prunedChange);
1850
+ setInChangeAtomIdMap(nodes, nodeId, prunedChange);
1495
1851
  return nodeId;
1496
1852
  }
1497
1853
  }
@@ -1520,12 +1876,12 @@ export class ModularChangeFamily
1520
1876
  );
1521
1877
  }
1522
1878
 
1523
- const updatedNodeToParent: ChangeAtomIdBTree<FieldId> = newTupleBTree();
1524
- for (const [[revision, id], fieldId] of change.nodeToParent.entries()) {
1879
+ const updatedNodeToParent: ChangeAtomIdBTree<NodeLocation> = newTupleBTree();
1880
+ for (const [[revision, id], location] of change.nodeToParent.entries()) {
1525
1881
  updatedNodeToParent.set(
1526
1882
  [replaceRevision(revision, oldRevisions, newRevision), id],
1527
- replaceFieldIdRevision(
1528
- normalizeFieldId(fieldId, change.nodeAliases),
1883
+ replaceNodeLocationRevision(
1884
+ normalizeNodeLocation(location, change.nodeAliases),
1529
1885
  oldRevisions,
1530
1886
  newRevision,
1531
1887
  ),
@@ -1537,15 +1893,24 @@ export class ModularChangeFamily
1537
1893
  fieldChanges: updatedFields,
1538
1894
  nodeChanges: updatedNodes,
1539
1895
  nodeToParent: updatedNodeToParent,
1540
-
1541
- // We've updated all references to old node IDs, so we no longer need an alias table.
1542
- nodeAliases: newTupleBTree(),
1543
- crossFieldKeys: replaceCrossFieldKeyTableRevisions(
1544
- change.crossFieldKeys,
1896
+ rootNodes: replaceRootTableRevision(
1897
+ change.rootNodes,
1545
1898
  oldRevisions,
1546
1899
  newRevision,
1547
1900
  change.nodeAliases,
1548
1901
  ),
1902
+
1903
+ // We've updated all references to old node IDs, so we no longer need an alias table.
1904
+ nodeAliases: newTupleBTree(),
1905
+ crossFieldKeys: change.crossFieldKeys.mapEntries(
1906
+ (key) => replaceCrossFieldKeyRevision(key, oldRevisions, newRevision),
1907
+ (id) =>
1908
+ replaceFieldIdRevision(
1909
+ normalizeFieldId(id, change.nodeAliases),
1910
+ oldRevisions,
1911
+ newRevision,
1912
+ ),
1913
+ ),
1549
1914
  };
1550
1915
 
1551
1916
  if (change.builds !== undefined) {
@@ -1613,7 +1978,7 @@ export class ModularChangeFamily
1613
1978
  fields: FieldChangeMap,
1614
1979
  nodes: ChangeAtomIdBTree<NodeChangeset>,
1615
1980
  ): CrossFieldKeyTable {
1616
- const keys: CrossFieldKeyTable = newCrossFieldKeyTable();
1981
+ const keys: CrossFieldKeyTable = newCrossFieldRangeTable();
1617
1982
  this.populateCrossFieldKeyTableForFieldMap(keys, fields, undefined);
1618
1983
  nodes.forEachPair(([revision, localId], node) => {
1619
1984
  if (node.fieldChanges !== undefined) {
@@ -1654,60 +2019,102 @@ export class ModularChangeFamily
1654
2019
  }
1655
2020
 
1656
2021
  public validateChangeset(change: ModularChangeset): void {
1657
- let numNodes = this.validateFieldChanges(change, change.fieldChanges, undefined);
2022
+ const unreachableNodes: ChangeAtomIdBTree<NodeLocation> = brand(
2023
+ change.nodeToParent.clone(),
2024
+ );
2025
+
2026
+ const unreachableCFKs = change.crossFieldKeys.clone();
2027
+
2028
+ this.validateFieldChanges(
2029
+ change,
2030
+ change.fieldChanges,
2031
+ undefined,
2032
+ unreachableNodes,
2033
+ unreachableCFKs,
2034
+ );
1658
2035
 
1659
2036
  for (const [[revision, localId], node] of change.nodeChanges.entries()) {
1660
2037
  if (node.fieldChanges === undefined) {
1661
2038
  continue;
1662
2039
  }
1663
2040
 
1664
- const nodeId: NodeId = { revision, localId };
1665
- const numChildren = this.validateFieldChanges(change, node.fieldChanges, nodeId);
2041
+ const nodeId = normalizeNodeId({ revision, localId }, change.nodeAliases);
2042
+ this.validateFieldChanges(
2043
+ change,
2044
+ node.fieldChanges,
2045
+ nodeId,
2046
+ unreachableNodes,
2047
+ unreachableCFKs,
2048
+ );
2049
+ }
2050
+
2051
+ for (const [detachIdKey, nodeId] of change.rootNodes.nodeChanges.entries()) {
2052
+ const detachId: ChangeAtomId = { revision: detachIdKey[0], localId: detachIdKey[1] };
2053
+ const location = getNodeParent(change, nodeId);
2054
+ assert(areEqualChangeAtomIdOpts(location.root, detachId), "Inconsistent node location");
1666
2055
 
1667
- numNodes += numChildren;
2056
+ const normalizedNodeId = normalizeNodeId(nodeId, change.nodeAliases);
2057
+ unreachableNodes.delete([normalizedNodeId.revision, normalizedNodeId.localId]);
2058
+
2059
+ const fieldChanges = nodeChangeFromId(
2060
+ change.nodeChanges,
2061
+ change.nodeAliases,
2062
+ nodeId,
2063
+ ).fieldChanges;
2064
+
2065
+ if (fieldChanges !== undefined) {
2066
+ this.validateFieldChanges(
2067
+ change,
2068
+ fieldChanges,
2069
+ normalizedNodeId,
2070
+ unreachableNodes,
2071
+ unreachableCFKs,
2072
+ );
2073
+ }
1668
2074
  }
1669
2075
 
1670
- assert(
1671
- numNodes === change.nodeChanges.size,
1672
- 0xa4d /* Node table contains unparented nodes */,
1673
- );
2076
+ assert(unreachableNodes.size === 0, "Unreachable nodes found");
2077
+ assert(unreachableCFKs.entries().length === 0, "Unreachable cross-field keys found");
1674
2078
  }
1675
2079
 
1676
2080
  /**
1677
- * Asserts that each child and cross field key in each field has a correct entry in
1678
- * `nodeToParent` or `crossFieldKeyTable`.
2081
+ * Asserts that each node has a correct entry in `change.nodeToParent`,
2082
+ * and each cross field key has a correct entry in `change.crossFieldKeys`.
1679
2083
  * @returns the number of children found.
1680
2084
  */
1681
2085
  private validateFieldChanges(
1682
2086
  change: ModularChangeset,
1683
2087
  fieldChanges: FieldChangeMap,
1684
2088
  nodeParent: NodeId | undefined,
1685
- ): number {
1686
- let numChildren = 0;
2089
+ unreachableNodes: ChangeAtomIdBTree<NodeLocation>,
2090
+ unreachableCFKs: CrossFieldRangeTable<FieldId>,
2091
+ ): void {
1687
2092
  for (const [field, fieldChange] of fieldChanges.entries()) {
1688
2093
  const fieldId = { nodeId: nodeParent, field };
1689
2094
  const handler = getChangeHandler(this.fieldKinds, fieldChange.fieldKind);
1690
2095
  for (const [child, _index] of handler.getNestedChanges(fieldChange.change)) {
1691
- const parentFieldId = getParentFieldId(change, child);
2096
+ const parentFieldId = getNodeParent(change, child);
1692
2097
  assert(
1693
- areEqualFieldIds(parentFieldId, fieldId),
2098
+ parentFieldId.field !== undefined && areEqualFieldIds(parentFieldId.field, fieldId),
1694
2099
  0xa4e /* Inconsistent node parentage */,
1695
2100
  );
1696
- numChildren += 1;
2101
+
2102
+ unreachableNodes.delete([child.revision, child.localId]);
1697
2103
  }
1698
2104
 
1699
2105
  for (const keyRange of handler.getCrossFieldKeys(fieldChange.change)) {
1700
2106
  const fields = getFieldsForCrossFieldKey(change, keyRange.key, keyRange.count);
1701
- assert(
1702
- fields.length === 1 &&
1703
- fields[0] !== undefined &&
1704
- areEqualFieldIds(fields[0], fieldId),
1705
- 0xa4f /* Inconsistent cross field keys */,
1706
- );
2107
+ assert(fields.length > 0, "Unregistered cross-field key");
2108
+ for (const fieldFromLookup of fields) {
2109
+ assert(
2110
+ areEqualFieldIds(fieldFromLookup, fieldId),
2111
+ 0xa4f /* Inconsistent cross field keys */,
2112
+ );
2113
+ }
2114
+
2115
+ unreachableCFKs.delete(keyRange.key, keyRange.count);
1707
2116
  }
1708
2117
  }
1709
-
1710
- return numChildren;
1711
2118
  }
1712
2119
 
1713
2120
  private getEffectiveChange(change: ModularChangeset): ModularChangeset {
@@ -1723,7 +2130,8 @@ export class ModularChangeFamily
1723
2130
  private muteChange(change: ModularChangeset): ModularChangeset {
1724
2131
  const muted: Mutable<ModularChangeset> = {
1725
2132
  ...change,
1726
- crossFieldKeys: newCrossFieldKeyTable(),
2133
+ rootNodes: muteRootChanges(change.rootNodes),
2134
+ crossFieldKeys: newCrossFieldRangeTable(),
1727
2135
  fieldChanges: this.muteFieldChanges(change.fieldChanges),
1728
2136
  nodeChanges: brand(change.nodeChanges.mapValues((v) => this.muteNodeChange(v))),
1729
2137
  };
@@ -1755,37 +2163,16 @@ export class ModularChangeFamily
1755
2163
  }
1756
2164
  }
1757
2165
 
1758
- function replaceCrossFieldKeyTableRevisions(
1759
- table: CrossFieldKeyTable,
2166
+ function replaceCrossFieldKeyRevision(
2167
+ key: CrossFieldKey,
1760
2168
  oldRevisions: Set<RevisionTag | undefined>,
1761
2169
  newRevision: RevisionTag | undefined,
1762
- nodeAliases: ChangeAtomIdBTree<NodeId>,
1763
- ): CrossFieldKeyTable {
1764
- const updated: CrossFieldKeyTable = newCrossFieldKeyTable();
1765
- for (const entry of table.entries()) {
1766
- const key = entry.start;
1767
- const updatedKey: CrossFieldKey = {
1768
- target: key.target,
1769
- revision: replaceRevision(key.revision, oldRevisions, newRevision),
1770
- localId: key.localId,
1771
- };
1772
-
1773
- const field = entry.value;
1774
- const normalizedFieldId = normalizeFieldId(field, nodeAliases);
1775
- const updatedNodeId =
1776
- normalizedFieldId.nodeId !== undefined
1777
- ? replaceAtomRevisions(normalizedFieldId.nodeId, oldRevisions, newRevision)
1778
- : undefined;
1779
-
1780
- const updatedValue: FieldId = {
1781
- ...normalizedFieldId,
1782
- nodeId: updatedNodeId,
1783
- };
1784
-
1785
- updated.set(updatedKey, entry.length, updatedValue);
1786
- }
1787
-
1788
- return updated;
2170
+ ): CrossFieldKey {
2171
+ return {
2172
+ target: key.target,
2173
+ revision: replaceRevision(key.revision, oldRevisions, newRevision),
2174
+ localId: key.localId,
2175
+ };
1789
2176
  }
1790
2177
 
1791
2178
  function replaceRevision(
@@ -1879,6 +2266,20 @@ function composeBuildsDestroysAndRefreshers(
1879
2266
  }
1880
2267
  }
1881
2268
 
2269
+ // It's possible to have a build and a refresher for the same root because an attach operation need not be performed in the same changeset as the corresponding build.
2270
+ if (change1.builds !== undefined && change2.refreshers !== undefined) {
2271
+ for (const [key, chunk] of change2.refreshers.entries()) {
2272
+ assert(chunk.topLevelLength === 1, "Expected refresher chunk to have length 1");
2273
+ const match = change1.builds.getPairOrNextLower(key);
2274
+ if (match !== undefined) {
2275
+ const [buildKey, buildChunk] = match;
2276
+ if (buildKey[0] === key[0] && buildKey[1] + buildChunk.topLevelLength > key[1]) {
2277
+ allRefreshers.delete(key);
2278
+ }
2279
+ }
2280
+ }
2281
+ }
2282
+
1882
2283
  return { allBuilds, allDestroys, allRefreshers };
1883
2284
  }
1884
2285
 
@@ -1910,27 +2311,77 @@ export function* relevantRemovedRoots(
1910
2311
  change: ModularChangeset,
1911
2312
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
1912
2313
  ): Iterable<DeltaDetachedNodeId> {
1913
- yield* relevantRemovedRootsFromFields(change.fieldChanges, change.nodeChanges, fieldKinds);
2314
+ const rootIds: ChangeAtomIdRangeMap<boolean> = newChangeAtomIdRangeMap();
2315
+ addAttachesToSet(change, rootIds);
2316
+ addRenamesToSet(change, rootIds);
2317
+
2318
+ for (const [[revision, localId]] of change.rootNodes.nodeChanges.entries()) {
2319
+ rootIds.set({ revision, localId }, 1, true);
2320
+ }
2321
+
2322
+ for (const entry of rootIds.entries()) {
2323
+ for (let offset = 0; offset < entry.length; offset++) {
2324
+ const detachId = offsetChangeAtomId(entry.start, offset);
2325
+ yield makeDetachedNodeId(detachId.revision, detachId.localId);
2326
+ }
2327
+ }
1914
2328
  }
1915
2329
 
1916
- function* relevantRemovedRootsFromFields(
1917
- change: FieldChangeMap,
1918
- nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
1919
- fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
1920
- ): Iterable<DeltaDetachedNodeId> {
1921
- for (const [_, fieldChange] of change) {
1922
- const handler = getChangeHandler(fieldKinds, fieldChange.fieldKind);
1923
- const delegate = function* (node: NodeId): Iterable<DeltaDetachedNodeId> {
1924
- const nodeChangeset = nodeChangeFromId(nodeChanges, node);
1925
- if (nodeChangeset.fieldChanges !== undefined) {
1926
- yield* relevantRemovedRootsFromFields(
1927
- nodeChangeset.fieldChanges,
1928
- nodeChanges,
1929
- fieldKinds,
1930
- );
2330
+ export function* getBuildIds(change: ModularChangeset): Iterable<DeltaDetachedNodeId> {
2331
+ if (change.builds !== undefined) {
2332
+ for (const [[revision, localId]] of change.builds.entries()) {
2333
+ yield makeDetachedNodeId(revision, localId);
2334
+ }
2335
+ }
2336
+ }
2337
+
2338
+ function addAttachesToSet(
2339
+ change: ModularChangeset,
2340
+ rootIds: ChangeAtomIdRangeMap<boolean>,
2341
+ ): void {
2342
+ // This includes each attach which does not have a corresponding detach.
2343
+ for (const entry of change.crossFieldKeys.entries()) {
2344
+ if (entry.start.target !== CrossFieldTarget.Destination) {
2345
+ continue;
2346
+ }
2347
+
2348
+ for (const detachIdEntry of change.rootNodes.newToOldId.getAll2(
2349
+ entry.start,
2350
+ entry.length,
2351
+ )) {
2352
+ const detachId =
2353
+ detachIdEntry.value ?? offsetChangeAtomId(entry.start, detachIdEntry.offset);
2354
+ for (const detachEntry of change.crossFieldKeys.getAll2(
2355
+ { ...detachId, target: CrossFieldTarget.Source },
2356
+ detachIdEntry.length,
2357
+ )) {
2358
+ if (detachEntry.value === undefined) {
2359
+ rootIds.set(
2360
+ offsetChangeAtomId(detachId, detachEntry.offset),
2361
+ detachEntry.length,
2362
+ true,
2363
+ );
2364
+ }
1931
2365
  }
1932
- };
1933
- yield* handler.relevantRemovedRoots(fieldChange.change, delegate);
2366
+ }
2367
+ }
2368
+ }
2369
+
2370
+ function addRenamesToSet(
2371
+ change: ModularChangeset,
2372
+ rootIds: ChangeAtomIdRangeMap<boolean>,
2373
+ ): void {
2374
+ for (const renameEntry of change.rootNodes.oldToNewId.entries()) {
2375
+ for (const detachEntry of change.crossFieldKeys.getAll2(
2376
+ { ...renameEntry.start, target: CrossFieldTarget.Source },
2377
+ renameEntry.length,
2378
+ )) {
2379
+ // We only want to include renames of nodes which are detached in the input context of the changeset.
2380
+ // So if there is a detach for the node, the rename is not relevant.
2381
+ if (detachEntry.value === undefined) {
2382
+ rootIds.set(renameEntry.start, renameEntry.length, true);
2383
+ }
2384
+ }
1934
2385
  }
1935
2386
  }
1936
2387
 
@@ -2003,6 +2454,7 @@ export function updateRefreshers(
2003
2454
  nodeChanges,
2004
2455
  nodeToParent: change.nodeToParent,
2005
2456
  nodeAliases: change.nodeAliases,
2457
+ rootNodes: change.rootNodes,
2006
2458
  crossFieldKeys: change.crossFieldKeys,
2007
2459
  maxId: maxId as number,
2008
2460
  revisions,
@@ -2026,18 +2478,42 @@ export function intoDelta(
2026
2478
  ): DeltaRoot {
2027
2479
  const change = taggedChange.change;
2028
2480
  const rootDelta: Mutable<DeltaRoot> = {};
2029
- const global: DeltaDetachedNodeChanges[] = [];
2030
- const rename: DeltaDetachedNodeRename[] = [];
2031
2481
 
2032
2482
  if (!hasConflicts(change)) {
2033
2483
  // If there are no constraint violations, then tree changes apply.
2034
2484
  const fieldDeltas = intoDeltaImpl(
2035
2485
  change.fieldChanges,
2036
2486
  change.nodeChanges,
2487
+ change.nodeAliases,
2037
2488
  fieldKinds,
2038
- global,
2039
- rename,
2040
2489
  );
2490
+
2491
+ const global: DeltaDetachedNodeChanges[] = [];
2492
+ for (const [[major, minor], nodeId] of change.rootNodes.nodeChanges.entries()) {
2493
+ global.push({
2494
+ id: { major, minor },
2495
+ fields: deltaFromNodeChange(
2496
+ nodeChangeFromId(change.nodeChanges, change.nodeAliases, nodeId),
2497
+ change.nodeChanges,
2498
+ change.nodeAliases,
2499
+ fieldKinds,
2500
+ ),
2501
+ });
2502
+ }
2503
+
2504
+ const rename: DeltaDetachedNodeRename[] = [];
2505
+ for (const {
2506
+ start: oldId,
2507
+ value: newId,
2508
+ length,
2509
+ } of change.rootNodes.oldToNewId.entries()) {
2510
+ rename.push({
2511
+ count: length,
2512
+ oldId: makeDetachedNodeId(oldId.revision, oldId.localId),
2513
+ newId: makeDetachedNodeId(newId.revision, newId.localId),
2514
+ });
2515
+ }
2516
+
2041
2517
  if (fieldDeltas.size > 0) {
2042
2518
  rootDelta.fields = fieldDeltas;
2043
2519
  }
@@ -2066,6 +2542,7 @@ export function intoDelta(
2066
2542
  if (change.refreshers && change.refreshers.size > 0) {
2067
2543
  rootDelta.refreshers = copyDetachedNodes(change.refreshers);
2068
2544
  }
2545
+
2069
2546
  return rootDelta;
2070
2547
  }
2071
2548
 
@@ -2091,29 +2568,22 @@ function copyDetachedNodes(
2091
2568
  function intoDeltaImpl(
2092
2569
  change: FieldChangeMap,
2093
2570
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2571
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
2094
2572
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
2095
- global: DeltaDetachedNodeChanges[],
2096
- rename: DeltaDetachedNodeRename[],
2097
2573
  ): Map<FieldKey, DeltaFieldChanges> {
2098
2574
  const delta: Map<FieldKey, DeltaFieldChanges> = new Map();
2099
2575
 
2100
2576
  for (const [field, fieldChange] of change) {
2101
- const {
2102
- local: fieldChanges,
2103
- global: fieldGlobal,
2104
- rename: fieldRename,
2105
- } = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
2577
+ const fieldDelta = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
2106
2578
  fieldChange.change,
2107
2579
  (childChange): DeltaFieldMap => {
2108
- const nodeChange = nodeChangeFromId(nodeChanges, childChange);
2109
- return deltaFromNodeChange(nodeChange, nodeChanges, fieldKinds, global, rename);
2580
+ const nodeChange = nodeChangeFromId(nodeChanges, nodeAliases, childChange);
2581
+ return deltaFromNodeChange(nodeChange, nodeChanges, nodeAliases, fieldKinds);
2110
2582
  },
2111
2583
  );
2112
- if (fieldChanges !== undefined && fieldChanges.length > 0) {
2113
- delta.set(field, fieldChanges);
2584
+ if (fieldDelta !== undefined && fieldDelta.length > 0) {
2585
+ delta.set(field, fieldDelta);
2114
2586
  }
2115
- fieldGlobal?.forEach((c) => global.push(c));
2116
- fieldRename?.forEach((r) => rename.push(r));
2117
2587
  }
2118
2588
  return delta;
2119
2589
  }
@@ -2121,12 +2591,11 @@ function intoDeltaImpl(
2121
2591
  function deltaFromNodeChange(
2122
2592
  change: NodeChangeset,
2123
2593
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2594
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
2124
2595
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
2125
- global: DeltaDetachedNodeChanges[],
2126
- rename: DeltaDetachedNodeRename[],
2127
2596
  ): DeltaFieldMap {
2128
2597
  if (change.fieldChanges !== undefined) {
2129
- return intoDeltaImpl(change.fieldChanges, nodeChanges, fieldKinds, global, rename);
2598
+ return intoDeltaImpl(change.fieldChanges, nodeChanges, nodeAliases, fieldKinds);
2130
2599
  }
2131
2600
  // TODO: update the API to allow undefined to be returned here
2132
2601
  return new Map();
@@ -2191,19 +2660,21 @@ export function getChangeHandler(
2191
2660
  return getFieldKind(fieldKinds, kind).changeHandler;
2192
2661
  }
2193
2662
 
2194
- // TODO: TFieldData could instead just be a numeric ID generated by the CrossFieldTable
2195
- // The CrossFieldTable could have a generic field ID to context table
2196
- interface CrossFieldTable<TFieldData> {
2197
- srcTable: CrossFieldMap<unknown>;
2198
- dstTable: CrossFieldMap<unknown>;
2199
- srcDependents: CrossFieldMap<TFieldData>;
2200
- dstDependents: CrossFieldMap<TFieldData>;
2201
- invalidatedFields: Set<TFieldData>;
2202
- }
2663
+ interface InvertTable {
2664
+ change: ModularChangeset;
2203
2665
 
2204
- interface InvertTable extends CrossFieldTable<FieldChange> {
2666
+ // Entries are keyed on attach ID
2667
+ entries: CrossFieldMap<NodeId>;
2205
2668
  originalFieldToContext: Map<FieldChange, InvertContext>;
2206
- invertedNodeToParent: ChangeAtomIdBTree<FieldId>;
2669
+ invertedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
2670
+ invertRevision: RevisionTag;
2671
+ invalidatedFields: Set<FieldChange>;
2672
+ invertedRoots: RootNodeTable;
2673
+
2674
+ /**
2675
+ * Maps from attach ID in the inverted changeset to the corresponding detach ID in the base changeset.
2676
+ */
2677
+ attachToDetachId: ChangeAtomIdRangeMap<ChangeAtomId>;
2207
2678
  }
2208
2679
 
2209
2680
  interface InvertContext {
@@ -2211,7 +2682,11 @@ interface InvertContext {
2211
2682
  invertedField: FieldChange;
2212
2683
  }
2213
2684
 
2214
- interface RebaseTable extends CrossFieldTable<FieldChange> {
2685
+ interface RebaseTable {
2686
+ readonly rebaseVersion: RebaseVersion;
2687
+
2688
+ // Entries are keyed on attach ID
2689
+ readonly entries: CrossFieldMap<RebaseDetachedNodeEntry>;
2215
2690
  readonly baseChange: ModularChangeset;
2216
2691
  readonly newChange: ModularChangeset;
2217
2692
 
@@ -2220,10 +2695,13 @@ interface RebaseTable extends CrossFieldTable<FieldChange> {
2220
2695
  * to the context for the field.
2221
2696
  */
2222
2697
  readonly baseFieldToContext: Map<FieldChange, RebaseFieldContext>;
2698
+ readonly baseRoots: RootNodeTable;
2223
2699
  readonly baseToRebasedNodeId: ChangeAtomIdBTree<NodeId>;
2224
2700
  readonly rebasedFields: Set<FieldChange>;
2225
- readonly rebasedNodeToParent: ChangeAtomIdBTree<FieldId>;
2226
- readonly rebasedCrossFieldKeys: CrossFieldKeyTable;
2701
+ readonly rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
2702
+ readonly rebasedDetachLocations: ChangeAtomIdRangeMap<FieldId>;
2703
+ readonly movedDetaches: ChangeAtomIdRangeMap<boolean>;
2704
+ readonly rebasedRootNodes: RootNodeTable;
2227
2705
 
2228
2706
  /**
2229
2707
  * List of unprocessed (newId, baseId) pairs encountered so far.
@@ -2237,7 +2715,7 @@ interface RebaseTable extends CrossFieldTable<FieldChange> {
2237
2715
  readonly fieldsWithUnattachedChild: Set<FieldChange>;
2238
2716
  }
2239
2717
 
2240
- type FieldIdKey = [RevisionTag | undefined, ChangesetLocalId | undefined, FieldKey];
2718
+ export type FieldIdKey = [RevisionTag | undefined, ChangesetLocalId | undefined, FieldKey];
2241
2719
 
2242
2720
  interface RebaseFieldContext {
2243
2721
  baseChange: FieldChange;
@@ -2249,32 +2727,43 @@ interface RebaseFieldContext {
2249
2727
  * The set of node IDs in the base changeset which should be included in the rebased field,
2250
2728
  * even if there is no corresponding node changeset in the new change.
2251
2729
  */
2252
- baseNodeIds: NodeId[];
2730
+ baseNodeIds: ChangeAtomIdBTree<boolean>;
2253
2731
  }
2254
2732
 
2255
2733
  function newComposeTable(
2256
2734
  baseChange: ModularChangeset,
2257
2735
  newChange: ModularChangeset,
2258
- composedNodeToParent: ChangeAtomIdBTree<FieldId>,
2736
+ composedRootNodes: RootNodeTable,
2737
+ movedCrossFieldKeys: CrossFieldKeyTable,
2738
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
2739
+ pendingCompositions: PendingCompositions,
2259
2740
  ): ComposeTable {
2260
2741
  return {
2261
- ...newCrossFieldTable<FieldChange>(),
2742
+ rebaseVersion: Math.max(
2743
+ baseChange.rebaseVersion,
2744
+ newChange.rebaseVersion,
2745
+ ) as RebaseVersion,
2746
+ entries: newDetachedEntryMap(),
2262
2747
  baseChange,
2263
2748
  newChange,
2264
2749
  fieldToContext: new Map(),
2265
2750
  newFieldToBaseField: new Map(),
2266
2751
  newToBaseNodeId: newTupleBTree(),
2267
2752
  composedNodes: new Set(),
2268
- composedNodeToParent,
2269
- pendingCompositions: {
2270
- nodeIdsToCompose: [],
2271
- affectedBaseFields: newTupleBTree(),
2272
- affectedNewFields: newTupleBTree(),
2273
- },
2753
+ movedNodeToParent: newTupleBTree(),
2754
+ composedRootNodes,
2755
+ movedCrossFieldKeys,
2756
+ removedCrossFieldKeys,
2757
+ renamesToDelete: newChangeAtomIdRangeMap(),
2758
+ pendingCompositions,
2274
2759
  };
2275
2760
  }
2276
2761
 
2277
- interface ComposeTable extends CrossFieldTable<FieldChange> {
2762
+ interface ComposeTable {
2763
+ readonly rebaseVersion: RebaseVersion;
2764
+
2765
+ // Entries are keyed on detach ID
2766
+ readonly entries: ChangeAtomIdRangeMap<DetachedNodeEntry>;
2278
2767
  readonly baseChange: ModularChangeset;
2279
2768
  readonly newChange: ModularChangeset;
2280
2769
 
@@ -2285,7 +2774,11 @@ interface ComposeTable extends CrossFieldTable<FieldChange> {
2285
2774
  readonly newFieldToBaseField: Map<FieldChange, FieldChange>;
2286
2775
  readonly newToBaseNodeId: ChangeAtomIdBTree<NodeId>;
2287
2776
  readonly composedNodes: Set<NodeChangeset>;
2288
- readonly composedNodeToParent: ChangeAtomIdBTree<FieldId>;
2777
+ readonly movedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
2778
+ readonly composedRootNodes: RootNodeTable;
2779
+ readonly movedCrossFieldKeys: CrossFieldKeyTable;
2780
+ readonly removedCrossFieldKeys: CrossFieldRangeTable<boolean>;
2781
+ readonly renamesToDelete: ChangeAtomIdRangeMap<boolean>;
2289
2782
  readonly pendingCompositions: PendingCompositions;
2290
2783
  }
2291
2784
 
@@ -2300,11 +2793,6 @@ interface PendingCompositions {
2300
2793
  * The set of fields in the base changeset which have been affected by a cross field effect.
2301
2794
  */
2302
2795
  readonly affectedBaseFields: BTree<FieldIdKey, true>;
2303
-
2304
- /**
2305
- * The set of fields in the new changeset which have been affected by a cross field effect.
2306
- */
2307
- readonly affectedNewFields: BTree<FieldIdKey, true>;
2308
2796
  }
2309
2797
 
2310
2798
  interface ComposeFieldContext {
@@ -2317,16 +2805,6 @@ interface ComposeFieldContext {
2317
2805
  composedChange: FieldChange;
2318
2806
  }
2319
2807
 
2320
- function newCrossFieldTable<T>(): CrossFieldTable<T> {
2321
- return {
2322
- srcTable: newChangeAtomIdRangeMap(),
2323
- dstTable: newChangeAtomIdRangeMap(),
2324
- srcDependents: newChangeAtomIdRangeMap(),
2325
- dstDependents: newChangeAtomIdRangeMap(),
2326
- invalidatedFields: new Set(),
2327
- };
2328
- }
2329
-
2330
2808
  interface ConstraintState {
2331
2809
  violationCount: number;
2332
2810
  }
@@ -2337,283 +2815,697 @@ function newConstraintState(violationCount: number): ConstraintState {
2337
2815
  };
2338
2816
  }
2339
2817
 
2340
- abstract class CrossFieldManagerI<T> implements CrossFieldManager {
2818
+ class InvertNodeManagerI implements InvertNodeManager {
2341
2819
  public constructor(
2342
- protected readonly crossFieldTable: CrossFieldTable<T>,
2343
- private readonly currentFieldKey: T,
2344
- protected readonly allowInval = true,
2820
+ private readonly table: InvertTable,
2821
+ private readonly fieldId: FieldId,
2345
2822
  ) {}
2346
2823
 
2347
- public set(
2348
- target: CrossFieldTarget,
2349
- revision: RevisionTag | undefined,
2350
- id: ChangesetLocalId,
2824
+ public invertDetach(
2825
+ detachId: ChangeAtomId,
2351
2826
  count: number,
2352
- newValue: unknown,
2353
- invalidateDependents: boolean,
2827
+ nodeChange: NodeId | undefined,
2828
+ newAttachId: ChangeAtomId,
2354
2829
  ): void {
2355
- if (invalidateDependents && this.allowInval) {
2356
- const lastChangedId = (id as number) + count - 1;
2357
- let firstId = id;
2358
- while (firstId <= lastChangedId) {
2359
- const dependentEntry = getFirstFromCrossFieldMap(
2360
- this.getDependents(target),
2361
- revision,
2362
- firstId,
2363
- lastChangedId - firstId + 1,
2364
- );
2365
- if (dependentEntry.value !== undefined) {
2366
- this.crossFieldTable.invalidatedFields.add(dependentEntry.value);
2367
- }
2830
+ if (nodeChange !== undefined) {
2831
+ assert(count === 1, "A node change should only affect one node");
2832
+
2833
+ const attachEntry = firstAttachIdFromDetachId(
2834
+ this.table.change.rootNodes,
2835
+ detachId,
2836
+ count,
2837
+ );
2368
2838
 
2369
- firstId = brand(firstId + dependentEntry.length);
2839
+ const attachFieldEntry = this.table.change.crossFieldKeys.getFirst(
2840
+ { target: CrossFieldTarget.Destination, ...attachEntry.value },
2841
+ count,
2842
+ );
2843
+
2844
+ if (attachFieldEntry.value !== undefined) {
2845
+ setInCrossFieldMap(this.table.entries, attachEntry.value, count, nodeChange);
2846
+ this.table.invalidatedFields.add(
2847
+ fieldChangeFromId(this.table.change, attachFieldEntry.value),
2848
+ );
2849
+ } else {
2850
+ assignRootChange(
2851
+ this.table.invertedRoots,
2852
+ this.table.invertedNodeToParent,
2853
+ attachEntry.value,
2854
+ nodeChange,
2855
+ this.fieldId,
2856
+ this.table.change.rebaseVersion,
2857
+ );
2370
2858
  }
2371
2859
  }
2372
- setInCrossFieldMap(this.getMap(target), revision, id, count, newValue);
2373
- }
2374
2860
 
2375
- public get(
2376
- target: CrossFieldTarget,
2377
- revision: RevisionTag | undefined,
2378
- id: ChangesetLocalId,
2379
- count: number,
2380
- addDependency: boolean,
2381
- ): RangeQueryResult<ChangeAtomId, unknown> {
2382
- if (addDependency) {
2383
- // We assume that if there is already an entry for this ID it is because
2384
- // a field handler has called compose on the same node multiple times.
2385
- // In this case we only want to update the latest version, so we overwrite the dependency.
2386
- setInCrossFieldMap(
2387
- this.getDependents(target),
2388
- revision,
2389
- id,
2861
+ if (!areEqualChangeAtomIds(detachId, newAttachId)) {
2862
+ for (const entry of doesChangeAttachNodes(
2863
+ this.table.change.crossFieldKeys,
2864
+ detachId,
2390
2865
  count,
2391
- this.currentFieldKey,
2392
- );
2866
+ )) {
2867
+ if (!entry.value) {
2868
+ this.table.attachToDetachId.set(newAttachId, count, detachId);
2869
+ this.table.invertedRoots.detachLocations.set(detachId, count, this.fieldId);
2870
+ }
2871
+ }
2393
2872
  }
2394
- return getFirstFromCrossFieldMap(this.getMap(target), revision, id, count);
2395
2873
  }
2396
2874
 
2397
- public abstract onMoveIn(id: NodeId): void;
2398
-
2399
- public abstract moveKey(
2400
- target: CrossFieldTarget,
2401
- revision: RevisionTag | undefined,
2402
- id: ChangesetLocalId,
2875
+ public invertAttach(
2876
+ attachId: ChangeAtomId,
2403
2877
  count: number,
2404
- ): void;
2878
+ ): RangeQueryResult<DetachedNodeEntry> {
2879
+ let countToProcess = count;
2405
2880
 
2406
- private getMap(target: CrossFieldTarget): CrossFieldMap<unknown> {
2407
- return target === CrossFieldTarget.Source
2408
- ? this.crossFieldTable.srcTable
2409
- : this.crossFieldTable.dstTable;
2410
- }
2881
+ const detachIdEntry = firstDetachIdFromAttachId(
2882
+ this.table.change.rootNodes,
2883
+ attachId,
2884
+ countToProcess,
2885
+ );
2411
2886
 
2412
- private getDependents(target: CrossFieldTarget): CrossFieldMap<T> {
2413
- return target === CrossFieldTarget.Source
2414
- ? this.crossFieldTable.srcDependents
2415
- : this.crossFieldTable.dstDependents;
2416
- }
2417
- }
2887
+ countToProcess = detachIdEntry.length;
2418
2888
 
2419
- class InvertManager extends CrossFieldManagerI<FieldChange> {
2420
- public constructor(
2421
- table: InvertTable,
2422
- field: FieldChange,
2423
- private readonly fieldId: FieldId,
2424
- allowInval = true,
2425
- ) {
2426
- super(table, field, allowInval);
2427
- }
2889
+ const detachEntry = getFirstFieldForCrossFieldKey(
2890
+ this.table.change,
2891
+ { target: CrossFieldTarget.Source, ...detachIdEntry.value },
2892
+ countToProcess,
2893
+ );
2894
+ countToProcess = detachEntry.length;
2428
2895
 
2429
- public override onMoveIn(id: ChangeAtomId): void {
2430
- setInChangeAtomIdMap(this.table.invertedNodeToParent, id, this.fieldId);
2431
- }
2896
+ let result: RangeQueryResult<DetachedNodeEntry>;
2897
+ if (detachEntry.value !== undefined) {
2898
+ const moveEntry = this.table.entries.getFirst(attachId, countToProcess);
2899
+ result = { ...moveEntry, value: { nodeChange: moveEntry.value } };
2900
+ } else {
2901
+ // This node is detached in the input context of the original change.
2902
+ const nodeIdEntry = rangeQueryChangeAtomIdMap(
2903
+ this.table.change.rootNodes.nodeChanges,
2904
+ detachIdEntry.value,
2905
+ countToProcess,
2906
+ );
2432
2907
 
2433
- public override moveKey(
2434
- target: CrossFieldTarget,
2435
- revision: RevisionTag | undefined,
2436
- id: ChangesetLocalId,
2437
- count: number,
2438
- ): void {
2439
- assert(false, 0x9c5 /* Keys should not be moved manually during invert */);
2440
- }
2908
+ countToProcess = nodeIdEntry.length;
2909
+ result = {
2910
+ value: { nodeChange: nodeIdEntry.value, detachId: detachIdEntry.value },
2911
+ length: countToProcess,
2912
+ };
2913
+ }
2441
2914
 
2442
- private get table(): InvertTable {
2443
- return this.crossFieldTable as InvertTable;
2915
+ if (result.value?.nodeChange !== undefined) {
2916
+ setInChangeAtomIdMap(this.table.invertedNodeToParent, result.value.nodeChange, {
2917
+ field: this.fieldId,
2918
+ });
2919
+ }
2920
+ return result;
2444
2921
  }
2445
2922
  }
2446
2923
 
2447
- class RebaseManager extends CrossFieldManagerI<FieldChange> {
2924
+ class RebaseNodeManagerI implements RebaseNodeManager {
2448
2925
  public constructor(
2449
- table: RebaseTable,
2450
- currentField: FieldChange,
2926
+ private readonly table: RebaseTable,
2451
2927
  private readonly fieldId: FieldId,
2452
- allowInval = true,
2453
- ) {
2454
- super(table, currentField, allowInval);
2455
- }
2928
+ private readonly allowInval: boolean = true,
2929
+ ) {}
2456
2930
 
2457
- public override set(
2458
- target: CrossFieldTarget,
2459
- revision: RevisionTag | undefined,
2460
- id: ChangesetLocalId,
2931
+ public getNewChangesForBaseAttach(
2932
+ baseAttachId: ChangeAtomId,
2461
2933
  count: number,
2462
- newValue: unknown,
2463
- invalidateDependents: boolean,
2464
- ): void {
2465
- if (invalidateDependents && this.allowInval) {
2466
- const newFieldIds = getFieldsForCrossFieldKey(
2467
- this.table.newChange,
2468
- {
2469
- target,
2470
- revision,
2471
- localId: id,
2472
- },
2473
- count,
2474
- );
2934
+ ): RangeQueryResult<RebaseDetachedNodeEntry | undefined> {
2935
+ let countToProcess = count;
2475
2936
 
2476
- assert(
2477
- newFieldIds.length === 0,
2478
- 0x9c6 /* TODO: Modifying a cross-field key from the new changeset is currently unsupported */,
2479
- );
2937
+ const detachEntry = firstDetachIdFromAttachId(
2938
+ this.table.baseChange.rootNodes,
2939
+ baseAttachId,
2940
+ countToProcess,
2941
+ );
2480
2942
 
2481
- const baseFieldIds = getFieldsForCrossFieldKey(
2482
- this.table.baseChange,
2483
- {
2484
- target,
2485
- revision,
2486
- localId: id,
2487
- },
2488
- count,
2489
- );
2943
+ countToProcess = detachEntry.length;
2490
2944
 
2491
- assert(
2492
- baseFieldIds.length > 0,
2493
- 0x9c7 /* Cross field key not registered in base or new change */,
2494
- );
2945
+ const nodeEntry = rangeQueryChangeAtomIdMap(
2946
+ this.table.newChange.rootNodes.nodeChanges,
2947
+ detachEntry.value,
2948
+ countToProcess,
2949
+ );
2495
2950
 
2496
- for (const baseFieldId of baseFieldIds) {
2497
- this.table.affectedBaseFields.set(
2498
- [baseFieldId.nodeId?.revision, baseFieldId.nodeId?.localId, baseFieldId.field],
2499
- true,
2951
+ countToProcess = nodeEntry.length;
2952
+ const newNodeId = nodeEntry.value;
2953
+
2954
+ const newRenameEntry = this.table.newChange.rootNodes.oldToNewId.getFirst(
2955
+ detachEntry.value,
2956
+ countToProcess,
2957
+ );
2958
+
2959
+ countToProcess = newRenameEntry.length;
2960
+
2961
+ let result: RangeQueryResult<DetachedNodeEntry | undefined>;
2962
+ // eslint-disable-next-line unicorn/prefer-ternary
2963
+ if (newNodeId !== undefined || newRenameEntry.value !== undefined) {
2964
+ result = {
2965
+ ...newRenameEntry,
2966
+ value: { detachId: newRenameEntry.value, nodeChange: newNodeId },
2967
+ };
2968
+ } else {
2969
+ // This handles the case where the base changeset has moved these nodes,
2970
+ // meaning they were attached in the input context of the base changeset.
2971
+ result = this.table.entries.getFirst(baseAttachId, countToProcess);
2972
+ }
2973
+
2974
+ // TODO: Consider moving these two checks into a separate method so that this function has no side effects.
2975
+ if (result.value?.detachId !== undefined) {
2976
+ this.table.rebasedDetachLocations.set(
2977
+ result.value.detachId,
2978
+ result.length,
2979
+ this.fieldId,
2980
+ );
2981
+ }
2982
+
2983
+ if (result.value?.nodeChange !== undefined) {
2984
+ setInChangeAtomIdMap(this.table.rebasedNodeToParent, result.value.nodeChange, {
2985
+ field: this.fieldId,
2986
+ });
2987
+ }
2988
+
2989
+ return result;
2990
+ }
2991
+
2992
+ public rebaseOverDetach(
2993
+ baseDetachId: ChangeAtomId,
2994
+ count: number,
2995
+ newDetachId: ChangeAtomId | undefined,
2996
+ nodeChange: NodeId | undefined,
2997
+ cellRename?: ChangeAtomId,
2998
+ ): void {
2999
+ let countToProcess = count;
3000
+ const attachIdEntry = firstAttachIdFromDetachId(
3001
+ this.table.baseRoots,
3002
+ baseDetachId,
3003
+ countToProcess,
3004
+ );
3005
+ const baseAttachId = attachIdEntry.value;
3006
+ countToProcess = attachIdEntry.length;
3007
+
3008
+ const attachFieldEntry = getFirstFieldForCrossFieldKey(
3009
+ this.table.baseChange,
3010
+ { ...baseAttachId, target: CrossFieldTarget.Destination },
3011
+ countToProcess,
3012
+ );
3013
+ countToProcess = attachFieldEntry.length;
3014
+
3015
+ const detachedMoveEntry = this.table.baseChange.rootNodes.outputDetachLocations.getFirst(
3016
+ baseDetachId,
3017
+ countToProcess,
3018
+ );
3019
+ countToProcess = detachedMoveEntry.length;
3020
+
3021
+ const destinationField = attachFieldEntry.value ?? detachedMoveEntry.value;
3022
+ if (destinationField !== undefined) {
3023
+ // The base detach is part of a move (or move of detach location) in the base changeset.
3024
+ setInCrossFieldMap(this.table.entries, baseAttachId, countToProcess, {
3025
+ nodeChange,
3026
+ detachId: newDetachId,
3027
+ cellRename,
3028
+ });
3029
+
3030
+ if (nodeChange !== undefined || newDetachId !== undefined) {
3031
+ this.invalidateBaseFields([destinationField]);
3032
+ }
3033
+ }
3034
+
3035
+ if (attachFieldEntry.value === undefined) {
3036
+ // These nodes are detached in the output context of the base changeset.
3037
+ if (nodeChange !== undefined) {
3038
+ assignRootChange(
3039
+ this.table.rebasedRootNodes,
3040
+ this.table.rebasedNodeToParent,
3041
+ baseAttachId,
3042
+ nodeChange,
3043
+ this.fieldId,
3044
+ this.table.rebaseVersion,
3045
+ );
3046
+ }
3047
+
3048
+ if (newDetachId !== undefined) {
3049
+ addNodeRename(
3050
+ this.table.rebasedRootNodes,
3051
+ baseAttachId,
3052
+ newDetachId,
3053
+ countToProcess,
3054
+ this.fieldId,
2500
3055
  );
2501
3056
  }
2502
3057
  }
2503
3058
 
2504
- super.set(target, revision, id, count, newValue, invalidateDependents);
3059
+ if (newDetachId !== undefined) {
3060
+ this.table.movedDetaches.set(newDetachId, countToProcess, true);
3061
+ }
3062
+
3063
+ if (countToProcess < count) {
3064
+ const remainingCount = count - countToProcess;
3065
+
3066
+ const nextDetachId =
3067
+ newDetachId !== undefined
3068
+ ? offsetChangeAtomId(newDetachId, countToProcess)
3069
+ : undefined;
3070
+
3071
+ this.rebaseOverDetach(
3072
+ offsetChangeAtomId(baseDetachId, countToProcess),
3073
+ remainingCount,
3074
+ nextDetachId,
3075
+ nodeChange,
3076
+ );
3077
+ }
3078
+ }
3079
+
3080
+ public addDetach(id: ChangeAtomId, count: number): void {
3081
+ this.table.rebasedDetachLocations.set(id, count, this.fieldId);
2505
3082
  }
2506
3083
 
2507
- public override onMoveIn(id: ChangeAtomId): void {
2508
- setInChangeAtomIdMap(this.table.rebasedNodeToParent, id, this.fieldId);
3084
+ public removeDetach(id: ChangeAtomId, count: number): void {
3085
+ this.table.movedDetaches.set(id, count, true);
2509
3086
  }
2510
3087
 
2511
- public override moveKey(
2512
- target: CrossFieldTarget,
2513
- revision: RevisionTag | undefined,
2514
- id: ChangesetLocalId,
3088
+ public doesBaseAttachNodes(
3089
+ id: ChangeAtomId,
2515
3090
  count: number,
2516
- ): void {
2517
- this.table.rebasedCrossFieldKeys.set(
2518
- { target, revision, localId: id },
2519
- count,
2520
- this.fieldId,
3091
+ ): RangeQueryEntry<ChangeAtomId, boolean> {
3092
+ let countToProcess = count;
3093
+ const attachEntry = getFirstAttachField(
3094
+ this.table.baseChange.crossFieldKeys,
3095
+ id,
3096
+ countToProcess,
3097
+ );
3098
+
3099
+ countToProcess = attachEntry.length;
3100
+ return { start: id, value: attachEntry.value !== undefined, length: countToProcess };
3101
+ }
3102
+
3103
+ public getBaseRename(
3104
+ id: ChangeAtomId,
3105
+ count: number,
3106
+ ): RangeQueryResult<ChangeAtomId | undefined> {
3107
+ return this.table.baseChange.rootNodes.oldToNewId.getFirst(id, count);
3108
+ }
3109
+
3110
+ public getNewRenameForBaseRename(
3111
+ baseRenameTo: ChangeAtomId,
3112
+ count: number,
3113
+ ): RangeQueryResult<ChangeAtomId | undefined> {
3114
+ let countToProcess = count;
3115
+ const inputEntry = firstDetachIdFromAttachId(
3116
+ this.table.baseChange.rootNodes,
3117
+ baseRenameTo,
3118
+ countToProcess,
3119
+ );
3120
+
3121
+ const attachEntry = getFirstAttachField(
3122
+ this.table.baseChange.crossFieldKeys,
3123
+ baseRenameTo,
3124
+ countToProcess,
2521
3125
  );
3126
+
3127
+ countToProcess = attachEntry.length;
3128
+ if (attachEntry.value !== undefined) {
3129
+ // These nodes are attached in the output context of the base changeset.
3130
+ return { value: undefined, length: countToProcess };
3131
+ }
3132
+
3133
+ countToProcess = inputEntry.length;
3134
+ const inputId = inputEntry.value;
3135
+
3136
+ const moveEntry = this.table.entries.getFirst(inputId, countToProcess);
3137
+
3138
+ countToProcess = moveEntry.length;
3139
+ if (moveEntry.value !== undefined) {
3140
+ return { ...moveEntry, value: moveEntry.value.cellRename ?? moveEntry.value.detachId };
3141
+ }
3142
+
3143
+ return this.table.newChange.rootNodes.oldToNewId.getFirst(inputId, countToProcess);
3144
+ }
3145
+
3146
+ private invalidateBaseFields(fields: FieldId[]): void {
3147
+ if (this.allowInval) {
3148
+ for (const fieldId of fields) {
3149
+ this.table.affectedBaseFields.set(fieldIdKeyFromFieldId(fieldId), true);
3150
+ }
3151
+ }
2522
3152
  }
3153
+ }
3154
+
3155
+ function assignRootChange(
3156
+ table: RootNodeTable,
3157
+ nodeToParent: ChangeAtomIdBTree<NodeLocation> | undefined,
3158
+ detachId: ChangeAtomId,
3159
+ nodeId: NodeId,
3160
+ detachLocation: FieldId | undefined,
3161
+ rebaseVersion: RebaseVersion,
3162
+ ): void {
3163
+ assert(
3164
+ rebaseVersion >= 2 || detachLocation !== undefined,
3165
+ "All root changes need a detach location to support compatibility with older client versions",
3166
+ );
3167
+
3168
+ setInChangeAtomIdMap(table.nodeChanges, detachId, nodeId);
2523
3169
 
2524
- private get table(): RebaseTable {
2525
- return this.crossFieldTable as RebaseTable;
3170
+ if (nodeToParent !== undefined) {
3171
+ setInChangeAtomIdMap(nodeToParent, nodeId, { root: detachId });
2526
3172
  }
3173
+
3174
+ table.detachLocations.set(detachId, 1, detachLocation);
2527
3175
  }
2528
3176
 
2529
- // TODO: Deduplicate this with RebaseTable
2530
- class ComposeManager extends CrossFieldManagerI<FieldChange> {
3177
+ class ComposeNodeManagerI implements ComposeNodeManager {
2531
3178
  public constructor(
2532
- table: ComposeTable,
2533
- currentField: FieldChange,
3179
+ private readonly table: ComposeTable,
2534
3180
  private readonly fieldId: FieldId,
2535
- allowInval = true,
2536
- ) {
2537
- super(table, currentField, allowInval);
3181
+ private readonly allowInval: boolean = true,
3182
+ ) {}
3183
+
3184
+ public getNewChangesForBaseDetach(
3185
+ baseDetachId: ChangeAtomId,
3186
+ count: number,
3187
+ ): RangeQueryResult<DetachedNodeEntry | undefined> {
3188
+ let countToProcess = count;
3189
+
3190
+ const baseAttachEntry = getFirstFieldForCrossFieldKey(
3191
+ this.table.baseChange,
3192
+ { target: CrossFieldTarget.Destination, ...baseDetachId },
3193
+ countToProcess,
3194
+ );
3195
+
3196
+ countToProcess = baseAttachEntry.length;
3197
+
3198
+ let result: RangeQueryResult<DetachedNodeEntry | undefined>;
3199
+ if (baseAttachEntry.value !== undefined) {
3200
+ // The base detach was part of a move.
3201
+ // We check if we've previously seen a node change at the move destination.
3202
+ const entry = this.table.entries.getFirst(baseDetachId, countToProcess);
3203
+ result = { value: entry.value, length: entry.length };
3204
+ } else {
3205
+ // The detached nodes are still detached in the new change's input context.
3206
+ const rootEntry = rangeQueryChangeAtomIdMap(
3207
+ this.table.newChange.rootNodes.nodeChanges,
3208
+ baseDetachId,
3209
+ countToProcess,
3210
+ );
3211
+
3212
+ countToProcess = rootEntry.length;
3213
+
3214
+ const newRenameEntry = this.table.newChange.rootNodes.oldToNewId.getFirst(
3215
+ baseDetachId,
3216
+ countToProcess,
3217
+ );
3218
+
3219
+ countToProcess = newRenameEntry.length;
3220
+
3221
+ result = {
3222
+ value: { nodeChange: rootEntry.value, detachId: newRenameEntry.value },
3223
+ length: countToProcess,
3224
+ };
3225
+ }
3226
+
3227
+ // TODO: Consider moving this to a separate method so that this method can be side-effect free.
3228
+ if (result.value?.nodeChange !== undefined) {
3229
+ setInChangeAtomIdMap(this.table.movedNodeToParent, result.value.nodeChange, {
3230
+ field: this.fieldId,
3231
+ });
3232
+ }
3233
+
3234
+ return result;
2538
3235
  }
2539
3236
 
2540
- public override set(
2541
- target: CrossFieldTarget,
2542
- revision: RevisionTag | undefined,
2543
- id: ChangesetLocalId,
3237
+ public composeAttachDetach(
3238
+ baseAttachId: ChangeAtomId,
3239
+ newDetachId: ChangeAtomId,
2544
3240
  count: number,
2545
- newValue: unknown,
2546
- invalidateDependents: boolean,
2547
3241
  ): void {
2548
- if (invalidateDependents && this.allowInval) {
2549
- const newFieldIds = getFieldsForCrossFieldKey(
2550
- this.table.newChange,
2551
- {
2552
- target,
2553
- revision,
2554
- localId: id,
2555
- },
2556
- count,
3242
+ let countToProcess = count;
3243
+
3244
+ const newAttachEntry = getFirstAttachField(
3245
+ this.table.newChange.crossFieldKeys,
3246
+ newDetachId,
3247
+ countToProcess,
3248
+ );
3249
+
3250
+ countToProcess = newAttachEntry.length;
3251
+
3252
+ // Both changes can have the same ID if they came from inverse changesets.
3253
+ // If the new detach is part of a move,
3254
+ // then both input changesets contain the attach cross-field key for this ID.
3255
+ // The new attach may still exist in the composed changeset so we do not remove it here.
3256
+ // The new attach will typically cancel with a base detach,
3257
+ // in which case the cross-field key will be removed in `composeDetachAttach`.
3258
+ const hasNewAttachWithBaseAttachId =
3259
+ areEqualChangeAtomIds(baseAttachId, newDetachId) && newAttachEntry.value !== undefined;
3260
+
3261
+ if (!hasNewAttachWithBaseAttachId) {
3262
+ this.table.removedCrossFieldKeys.set(
3263
+ { ...baseAttachId, target: CrossFieldTarget.Destination },
3264
+ countToProcess,
3265
+ true,
2557
3266
  );
3267
+ }
2558
3268
 
2559
- if (newFieldIds.length > 0) {
2560
- for (const newFieldId of newFieldIds) {
2561
- this.table.pendingCompositions.affectedNewFields.set(
2562
- [newFieldId.nodeId?.revision, newFieldId.nodeId?.localId, newFieldId.field],
2563
- true,
2564
- );
2565
- }
2566
- } else {
2567
- const baseFieldIds = getFieldsForCrossFieldKey(
2568
- this.table.baseChange,
2569
- {
2570
- target,
2571
- revision,
2572
- localId: id,
2573
- },
2574
- count,
3269
+ const baseDetachEntry = getFirstDetachField(
3270
+ this.table.baseChange.crossFieldKeys,
3271
+ baseAttachId,
3272
+ countToProcess,
3273
+ );
3274
+
3275
+ countToProcess = baseDetachEntry.length;
3276
+
3277
+ const baseRootIdEntry = firstDetachIdFromAttachId(
3278
+ this.table.baseChange.rootNodes,
3279
+ baseAttachId,
3280
+ countToProcess,
3281
+ );
3282
+ countToProcess = baseRootIdEntry.length;
3283
+
3284
+ const baseDetachId = baseRootIdEntry.value;
3285
+
3286
+ if (baseDetachEntry.value !== undefined) {
3287
+ // The base change moves these nodes.
3288
+ const prevEntry =
3289
+ this.table.entries.getFirst(baseAttachId, baseDetachEntry.length).value ?? {};
3290
+
3291
+ this.table.entries.set(baseAttachId, baseDetachEntry.length, {
3292
+ ...prevEntry,
3293
+ detachId: newDetachId,
3294
+ });
3295
+
3296
+ // The new detach will replace the base detach, so we remove the key for the base detach, unless they have the same ID.
3297
+ if (!areEqualChangeAtomIds(baseAttachId, newDetachId)) {
3298
+ this.table.removedCrossFieldKeys.set(
3299
+ { ...baseAttachId, target: CrossFieldTarget.Source },
3300
+ countToProcess,
3301
+ true,
2575
3302
  );
3303
+ }
2576
3304
 
2577
- assert(
2578
- baseFieldIds.length > 0,
2579
- 0x9c8 /* Cross field key not registered in base or new change */,
3305
+ this.table.movedCrossFieldKeys.set(
3306
+ { ...newDetachId, target: CrossFieldTarget.Source },
3307
+ countToProcess,
3308
+ baseDetachEntry.value,
3309
+ );
3310
+
3311
+ this.invalidateBaseFields([baseDetachEntry.value]);
3312
+ } else {
3313
+ const baseDetachLocationEntry = this.table.baseChange.rootNodes.detachLocations.getFirst(
3314
+ baseDetachId,
3315
+ countToProcess,
3316
+ );
3317
+ countToProcess = baseDetachLocationEntry.length;
3318
+
3319
+ // These nodes were detached in the base change's input context,
3320
+ // so the net effect of the two changes is a rename.
3321
+ appendNodeRename(
3322
+ this.table.composedRootNodes,
3323
+ baseAttachId,
3324
+ newDetachId,
3325
+ baseDetachEntry.length,
3326
+ this.table.baseChange.rootNodes,
3327
+ baseDetachLocationEntry.value ?? this.fieldId,
3328
+ );
3329
+
3330
+ this.table.removedCrossFieldKeys.set(
3331
+ { ...newDetachId, target: CrossFieldTarget.Source },
3332
+ countToProcess,
3333
+ true,
3334
+ );
3335
+ }
3336
+
3337
+ if (newAttachEntry.value === undefined) {
3338
+ const newOutputDetachLocationEntry =
3339
+ this.table.newChange.rootNodes.outputDetachLocations.getFirst(
3340
+ newDetachId,
3341
+ countToProcess,
2580
3342
  );
2581
3343
 
2582
- for (const baseFieldId of baseFieldIds) {
2583
- this.table.pendingCompositions.affectedBaseFields.set(
2584
- [baseFieldId.nodeId?.revision, baseFieldId.nodeId?.localId, baseFieldId.field],
2585
- true,
2586
- );
2587
- }
2588
- }
3344
+ countToProcess = newOutputDetachLocationEntry.length;
3345
+
3346
+ this.table.composedRootNodes.outputDetachLocations.set(
3347
+ newDetachId,
3348
+ countToProcess,
3349
+ newOutputDetachLocationEntry.value ?? this.fieldId,
3350
+ );
3351
+ }
3352
+
3353
+ if (countToProcess < count) {
3354
+ const remainingCount = count - countToProcess;
3355
+ this.composeAttachDetach(
3356
+ offsetChangeAtomId(baseAttachId, countToProcess),
3357
+ offsetChangeAtomId(newDetachId, countToProcess),
3358
+ remainingCount,
3359
+ );
2589
3360
  }
3361
+ }
3362
+
3363
+ public sendNewChangesToBaseSourceLocation(
3364
+ baseAttachId: ChangeAtomId,
3365
+ newChanges: NodeId,
3366
+ ): void {
3367
+ const { value: baseDetachId } = firstDetachIdFromAttachId(
3368
+ this.table.baseChange.rootNodes,
3369
+ baseAttachId,
3370
+ 1,
3371
+ );
3372
+
3373
+ const detachFields = getFieldsForCrossFieldKey(
3374
+ this.table.baseChange,
3375
+ {
3376
+ ...baseDetachId,
3377
+ target: CrossFieldTarget.Source,
3378
+ },
3379
+ 1,
3380
+ );
3381
+
3382
+ if (detachFields.length > 0) {
3383
+ // The base attach is part of a move in the base changeset.
3384
+ const prevEntry = this.table.entries.getFirst(baseDetachId, 1).value ?? {};
3385
+ this.table.entries.set(baseDetachId, 1, { ...prevEntry, nodeChange: newChanges });
2590
3386
 
2591
- super.set(target, revision, id, count, newValue, invalidateDependents);
3387
+ if (newChanges !== undefined) {
3388
+ this.invalidateBaseFields(detachFields);
3389
+ }
3390
+ } else {
3391
+ const baseNodeId = getFromChangeAtomIdMap(
3392
+ this.table.baseChange.rootNodes.nodeChanges,
3393
+ baseDetachId,
3394
+ );
3395
+
3396
+ if (baseNodeId !== undefined) {
3397
+ addNodesToCompose(this.table, baseNodeId, newChanges);
3398
+ } else {
3399
+ assignRootChange(
3400
+ this.table.composedRootNodes,
3401
+ this.table.movedNodeToParent,
3402
+ baseDetachId,
3403
+ newChanges,
3404
+ this.fieldId,
3405
+ this.table.rebaseVersion,
3406
+ );
3407
+ }
3408
+ }
2592
3409
  }
2593
3410
 
2594
- public override onMoveIn(id: ChangeAtomId): void {
2595
- setInChangeAtomIdMap(this.table.composedNodeToParent, id, this.fieldId);
3411
+ private areSameNodes(
3412
+ baseDetachId: ChangeAtomId,
3413
+ newAttachId: ChangeAtomId,
3414
+ count: number,
3415
+ ): RangeQueryResult<boolean> {
3416
+ const renamedDetachEntry = firstAttachIdFromDetachId(
3417
+ this.table.composedRootNodes,
3418
+ baseDetachId,
3419
+ count,
3420
+ );
3421
+
3422
+ const isReattachOfSameNodes = areEqualChangeAtomIds(renamedDetachEntry.value, newAttachId);
3423
+ return { ...renamedDetachEntry, value: isReattachOfSameNodes };
2596
3424
  }
2597
3425
 
2598
- public override moveKey(
2599
- target: CrossFieldTarget,
2600
- revision: RevisionTag | undefined,
2601
- id: ChangesetLocalId,
3426
+ public composeDetachAttach(
3427
+ baseDetachId: ChangeAtomId,
3428
+ newAttachId: ChangeAtomId,
2602
3429
  count: number,
3430
+ composeToPin: boolean,
2603
3431
  ): void {
2604
- throw new Error("Moving cross-field keys during compose is currently unsupported");
3432
+ const areSameEntry = this.areSameNodes(baseDetachId, newAttachId, count);
3433
+
3434
+ const countToProcess = areSameEntry.length;
3435
+ if (areSameEntry.value) {
3436
+ // These nodes have been moved back to their original location, so the composed changeset should not have any renames for them.
3437
+ // Note that deleting the rename from `this.table.composedRootNodes` would change the result of this method
3438
+ // if it were rerun due to the field being invalidated, so we instead record that the rename should be deleted later.
3439
+ this.table.renamesToDelete.set(baseDetachId, countToProcess, true);
3440
+ }
3441
+
3442
+ if (composeToPin) {
3443
+ this.table.movedCrossFieldKeys.set(
3444
+ { target: CrossFieldTarget.Source, ...newAttachId },
3445
+ countToProcess,
3446
+ this.fieldId,
3447
+ );
3448
+
3449
+ if (!areEqualChangeAtomIds(baseDetachId, newAttachId)) {
3450
+ // The pin will have `newAttachId` as both its detach and attach ID.
3451
+ // So we remove `baseDetachId` unless that is equal to the pin's detach ID.
3452
+ this.table.removedCrossFieldKeys.set(
3453
+ { target: CrossFieldTarget.Source, ...baseDetachId },
3454
+ countToProcess,
3455
+ true,
3456
+ );
3457
+ }
3458
+
3459
+ // Note that while change2 should already have this key, change1 may have a rollback for the same ID in a different location.
3460
+ // In that case, change1's attach should be canceled out by a detach from change2.
3461
+ // Here we make sure that the composed change has the correct location (this field) for the attach ID.
3462
+ this.table.movedCrossFieldKeys.set(
3463
+ { target: CrossFieldTarget.Destination, ...newAttachId },
3464
+ countToProcess,
3465
+ this.fieldId,
3466
+ );
3467
+ } else {
3468
+ this.table.removedCrossFieldKeys.set(
3469
+ { target: CrossFieldTarget.Source, ...baseDetachId },
3470
+ countToProcess,
3471
+ true,
3472
+ );
3473
+
3474
+ this.table.removedCrossFieldKeys.set(
3475
+ { target: CrossFieldTarget.Destination, ...newAttachId },
3476
+ countToProcess,
3477
+ true,
3478
+ );
3479
+ }
3480
+
3481
+ if (countToProcess < count) {
3482
+ this.composeAttachDetach(
3483
+ offsetChangeAtomId(baseDetachId, countToProcess),
3484
+ offsetChangeAtomId(newAttachId, countToProcess),
3485
+ count - countToProcess,
3486
+ );
3487
+ }
2605
3488
  }
2606
3489
 
2607
- private get table(): ComposeTable {
2608
- return this.crossFieldTable as ComposeTable;
3490
+ private invalidateBaseFields(fields: FieldId[]): void {
3491
+ if (this.allowInval) {
3492
+ for (const fieldId of fields) {
3493
+ this.table.pendingCompositions.affectedBaseFields.set(
3494
+ fieldIdKeyFromFieldId(fieldId),
3495
+ true,
3496
+ );
3497
+ }
3498
+ }
2609
3499
  }
2610
3500
  }
2611
3501
 
2612
3502
  function makeModularChangeset(
2613
3503
  props: {
3504
+ rebaseVersion?: RebaseVersion;
2614
3505
  fieldChanges?: FieldChangeMap;
2615
3506
  nodeChanges?: ChangeAtomIdBTree<NodeChangeset>;
2616
- nodeToParent?: ChangeAtomIdBTree<FieldId>;
3507
+ rootNodes?: RootNodeTable;
3508
+ nodeToParent?: ChangeAtomIdBTree<NodeLocation>;
2617
3509
  nodeAliases?: ChangeAtomIdBTree<NodeId>;
2618
3510
  crossFieldKeys?: CrossFieldKeyTable;
2619
3511
  maxId: number;
@@ -2628,11 +3520,13 @@ function makeModularChangeset(
2628
3520
  },
2629
3521
  ): ModularChangeset {
2630
3522
  const changeset: Mutable<ModularChangeset> = {
3523
+ rebaseVersion: props.rebaseVersion ?? 1,
2631
3524
  fieldChanges: props.fieldChanges ?? new Map(),
2632
3525
  nodeChanges: props.nodeChanges ?? newTupleBTree(),
3526
+ rootNodes: props.rootNodes ?? newRootTable(),
2633
3527
  nodeToParent: props.nodeToParent ?? newTupleBTree(),
2634
3528
  nodeAliases: props.nodeAliases ?? newTupleBTree(),
2635
- crossFieldKeys: props.crossFieldKeys ?? newCrossFieldKeyTable(),
3529
+ crossFieldKeys: props.crossFieldKeys ?? newCrossFieldRangeTable(),
2636
3530
  };
2637
3531
 
2638
3532
  if (props.revisions !== undefined && props.revisions.length > 0) {
@@ -2659,6 +3553,7 @@ function makeModularChangeset(
2659
3553
  if (props.refreshers !== undefined && props.refreshers.size > 0) {
2660
3554
  changeset.refreshers = props.refreshers;
2661
3555
  }
3556
+
2662
3557
  return changeset;
2663
3558
  }
2664
3559
 
@@ -2675,6 +3570,10 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2675
3570
  this.idAllocator = idAllocatorFromMaxId();
2676
3571
  }
2677
3572
 
3573
+ public isInTransaction(): boolean {
3574
+ return this.transactionDepth > 0;
3575
+ }
3576
+
2678
3577
  public override enterTransaction(): void {
2679
3578
  this.transactionDepth += 1;
2680
3579
  if (this.transactionDepth === 1) {
@@ -2729,7 +3628,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2729
3628
  * @param revision - the revision of the change
2730
3629
  */
2731
3630
  public submitChange(
2732
- field: FieldUpPath,
3631
+ field: NormalizedFieldUpPath,
2733
3632
  fieldKind: FieldKindIdentifier,
2734
3633
  change: FieldChangeset,
2735
3634
  revision: RevisionTag,
@@ -2743,7 +3642,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2743
3642
  fieldChange: { fieldKind, change },
2744
3643
  nodeChanges: newTupleBTree(),
2745
3644
  nodeToParent: newTupleBTree(),
2746
- crossFieldKeys: newCrossFieldKeyTable(),
3645
+ crossFieldKeys: newCrossFieldRangeTable(),
3646
+ rootNodes: newRootTable(),
2747
3647
  idAllocator: this.idAllocator,
2748
3648
  localCrossFieldKeys,
2749
3649
  revision,
@@ -2765,6 +3665,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2765
3665
  ? makeModularChangeset({
2766
3666
  maxId: this.idAllocator.getMaxId(),
2767
3667
  builds: change.builds,
3668
+ rootNodes: renameTableFromRenameDescriptions(change.renames ?? []),
2768
3669
  revisions: [{ revision: change.revision }],
2769
3670
  })
2770
3671
  : buildModularChangesetFromField({
@@ -2775,7 +3676,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2775
3676
  },
2776
3677
  nodeChanges: newTupleBTree(),
2777
3678
  nodeToParent: newTupleBTree(),
2778
- crossFieldKeys: newCrossFieldKeyTable(),
3679
+ crossFieldKeys: newCrossFieldRangeTable(),
3680
+ rootNodes: newRootTable(),
2779
3681
  idAllocator: this.idAllocator,
2780
3682
  localCrossFieldKeys: getChangeHandler(
2781
3683
  this.fieldKinds,
@@ -2802,7 +3704,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2802
3704
  return brand(this.idAllocator.allocate(count));
2803
3705
  }
2804
3706
 
2805
- public addNodeExistsConstraint(path: UpPath, revision: RevisionTag): void {
3707
+ public addNodeExistsConstraint(path: NormalizedUpPath, revision: RevisionTag): void {
2806
3708
  const nodeChange: NodeChangeset = {
2807
3709
  nodeExistsConstraint: { violated: false },
2808
3710
  };
@@ -2814,7 +3716,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2814
3716
  nodeChange,
2815
3717
  nodeChanges: newTupleBTree(),
2816
3718
  nodeToParent: newTupleBTree(),
2817
- crossFieldKeys: newCrossFieldKeyTable(),
3719
+ crossFieldKeys: newCrossFieldRangeTable(),
3720
+ rootNodes: newRootTable(),
2818
3721
  idAllocator: this.idAllocator,
2819
3722
  revision,
2820
3723
  }),
@@ -2823,7 +3726,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2823
3726
  );
2824
3727
  }
2825
3728
 
2826
- public addNodeExistsConstraintOnRevert(path: UpPath, revision: RevisionTag): void {
3729
+ public addNodeExistsConstraintOnRevert(path: NormalizedUpPath, revision: RevisionTag): void {
2827
3730
  const nodeChange: NodeChangeset = {
2828
3731
  nodeExistsConstraintOnRevert: { violated: false },
2829
3732
  };
@@ -2835,7 +3738,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2835
3738
  nodeChange,
2836
3739
  nodeChanges: newTupleBTree(),
2837
3740
  nodeToParent: newTupleBTree(),
2838
- crossFieldKeys: newCrossFieldKeyTable(),
3741
+ crossFieldKeys: newCrossFieldRangeTable(),
3742
+ rootNodes: newRootTable(),
2839
3743
  idAllocator: this.idAllocator,
2840
3744
  revision,
2841
3745
  }),
@@ -2845,12 +3749,13 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2845
3749
  }
2846
3750
  }
2847
3751
 
2848
- function buildModularChangesetFromField(props: {
2849
- path: FieldUpPath;
3752
+ export function buildModularChangesetFromField(props: {
3753
+ path: NormalizedFieldUpPath;
2850
3754
  fieldChange: FieldChange;
2851
3755
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
2852
- nodeToParent: ChangeAtomIdBTree<FieldId>;
3756
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>;
2853
3757
  crossFieldKeys: CrossFieldKeyTable;
3758
+ rootNodes: RootNodeTable;
2854
3759
  localCrossFieldKeys?: CrossFieldKeyRange[];
2855
3760
  revision: RevisionTag;
2856
3761
  idAllocator?: IdAllocator;
@@ -2862,6 +3767,7 @@ function buildModularChangesetFromField(props: {
2862
3767
  nodeChanges,
2863
3768
  nodeToParent,
2864
3769
  crossFieldKeys,
3770
+ rootNodes,
2865
3771
  idAllocator = idAllocatorFromMaxId(),
2866
3772
  localCrossFieldKeys = [],
2867
3773
  childId,
@@ -2870,14 +3776,17 @@ function buildModularChangesetFromField(props: {
2870
3776
  const fieldChanges: FieldChangeMap = new Map([[path.field, fieldChange]]);
2871
3777
 
2872
3778
  if (path.parent === undefined) {
3779
+ const field = { nodeId: undefined, field: path.field };
2873
3780
  for (const { key, count } of localCrossFieldKeys) {
2874
- crossFieldKeys.set(key, count, { nodeId: undefined, field: path.field });
3781
+ crossFieldKeys.set(key, count, field);
2875
3782
  }
2876
3783
 
2877
3784
  if (childId !== undefined) {
2878
3785
  setInChangeAtomIdMap(nodeToParent, childId, {
2879
- nodeId: undefined,
2880
- field: path.field,
3786
+ field: {
3787
+ nodeId: undefined,
3788
+ field: path.field,
3789
+ },
2881
3790
  });
2882
3791
  }
2883
3792
 
@@ -2886,6 +3795,7 @@ function buildModularChangesetFromField(props: {
2886
3795
  nodeChanges,
2887
3796
  nodeToParent,
2888
3797
  crossFieldKeys,
3798
+ rootNodes,
2889
3799
  maxId: idAllocator.getMaxId(),
2890
3800
  revisions: [{ revision }],
2891
3801
  });
@@ -2896,6 +3806,7 @@ function buildModularChangesetFromField(props: {
2896
3806
  };
2897
3807
 
2898
3808
  const parentId: NodeId = { localId: brand(idAllocator.allocate()), revision };
3809
+ const fieldId = { nodeId: parentId, field: path.field };
2899
3810
 
2900
3811
  for (const { key, count } of localCrossFieldKeys) {
2901
3812
  crossFieldKeys.set(key, count, { nodeId: parentId, field: path.field });
@@ -2903,8 +3814,7 @@ function buildModularChangesetFromField(props: {
2903
3814
 
2904
3815
  if (childId !== undefined) {
2905
3816
  setInChangeAtomIdMap(nodeToParent, childId, {
2906
- nodeId: parentId,
2907
- field: path.field,
3817
+ field: fieldId,
2908
3818
  });
2909
3819
  }
2910
3820
 
@@ -2914,6 +3824,7 @@ function buildModularChangesetFromField(props: {
2914
3824
  nodeChanges,
2915
3825
  nodeToParent,
2916
3826
  crossFieldKeys,
3827
+ rootNodes,
2917
3828
  idAllocator,
2918
3829
  revision,
2919
3830
  nodeId: parentId,
@@ -2921,11 +3832,12 @@ function buildModularChangesetFromField(props: {
2921
3832
  }
2922
3833
 
2923
3834
  function buildModularChangesetFromNode(props: {
2924
- path: UpPath;
3835
+ path: NormalizedUpPath;
2925
3836
  nodeChange: NodeChangeset;
2926
3837
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
2927
- nodeToParent: ChangeAtomIdBTree<FieldId>;
3838
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>;
2928
3839
  crossFieldKeys: CrossFieldKeyTable;
3840
+ rootNodes: RootNodeTable;
2929
3841
  idAllocator: IdAllocator;
2930
3842
  revision: RevisionTag;
2931
3843
  nodeId?: NodeId;
@@ -2935,27 +3847,43 @@ function buildModularChangesetFromNode(props: {
2935
3847
  nodeId = { localId: brand(props.idAllocator.allocate()), revision: props.revision },
2936
3848
  } = props;
2937
3849
  setInChangeAtomIdMap(props.nodeChanges, nodeId, props.nodeChange);
2938
- const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChanges([
2939
- [path.parentIndex, nodeId],
2940
- ]);
2941
3850
 
2942
- const fieldChange: FieldChange = {
2943
- fieldKind: genericFieldKind.identifier,
2944
- change: fieldChangeset,
2945
- };
3851
+ if (isDetachedUpPathRoot(path)) {
3852
+ props.rootNodes.nodeChanges.set(
3853
+ [path.detachedNodeId.major, brand(path.detachedNodeId.minor)],
3854
+ nodeId,
3855
+ );
3856
+ return makeModularChangeset({
3857
+ rootNodes: props.rootNodes,
3858
+ nodeChanges: props.nodeChanges,
3859
+ nodeToParent: props.nodeToParent,
3860
+ crossFieldKeys: props.crossFieldKeys,
3861
+ maxId: props.idAllocator.getMaxId(),
3862
+ revisions: [{ revision: props.revision }],
3863
+ });
3864
+ } else {
3865
+ const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChanges([
3866
+ [path.parentIndex, nodeId],
3867
+ ]);
2946
3868
 
2947
- return buildModularChangesetFromField({
2948
- ...props,
2949
- path: { parent: path.parent, field: path.parentField },
2950
- fieldChange,
2951
- localCrossFieldKeys: [],
2952
- childId: nodeId,
2953
- });
3869
+ const fieldChange: FieldChange = {
3870
+ fieldKind: genericFieldKind.identifier,
3871
+ change: fieldChangeset,
3872
+ };
3873
+
3874
+ return buildModularChangesetFromField({
3875
+ ...props,
3876
+ path: { parent: path.parent, field: path.parentField },
3877
+ fieldChange,
3878
+ localCrossFieldKeys: [],
3879
+ childId: nodeId,
3880
+ });
3881
+ }
2954
3882
  }
2955
3883
 
2956
3884
  export interface FieldEditDescription {
2957
3885
  type: "field";
2958
- field: FieldUpPath;
3886
+ field: NormalizedFieldUpPath;
2959
3887
  fieldKind: FieldKindIdentifier;
2960
3888
  change: FieldChangeset;
2961
3889
  revision: RevisionTag;
@@ -2965,6 +3893,23 @@ export interface GlobalEditDescription {
2965
3893
  type: "global";
2966
3894
  revision: RevisionTag;
2967
3895
  builds?: ChangeAtomIdBTree<TreeChunk>;
3896
+ renames?: RenameDescription[];
3897
+ }
3898
+
3899
+ export interface RenameDescription {
3900
+ count: number;
3901
+ oldId: ChangeAtomId;
3902
+ newId: ChangeAtomId;
3903
+ detachLocation: FieldId | undefined;
3904
+ }
3905
+
3906
+ function renameTableFromRenameDescriptions(renames: RenameDescription[]): RootNodeTable {
3907
+ const table = newRootTable();
3908
+ for (const rename of renames) {
3909
+ addNodeRename(table, rename.oldId, rename.newId, rename.count, rename.detachLocation);
3910
+ }
3911
+
3912
+ return table;
2968
3913
  }
2969
3914
 
2970
3915
  export type EditDescription = FieldEditDescription | GlobalEditDescription;
@@ -2981,22 +3926,6 @@ function getRevInfoFromTaggedChanges(changes: TaggedChange<ModularChangeset>[]):
2981
3926
  revInfos.push(...revisionInfoFromTaggedChange(taggedChange));
2982
3927
  }
2983
3928
 
2984
- const revisions = new Set<RevisionTag>();
2985
- const rolledBackRevisions: RevisionTag[] = [];
2986
- for (const info of revInfos) {
2987
- revisions.add(info.revision);
2988
- if (info.rollbackOf !== undefined) {
2989
- rolledBackRevisions.push(info.rollbackOf);
2990
- }
2991
- }
2992
-
2993
- rolledBackRevisions.reverse();
2994
- for (const revision of rolledBackRevisions) {
2995
- if (!revisions.has(revision)) {
2996
- revInfos.push({ revision });
2997
- }
2998
- }
2999
-
3000
3929
  return { maxId: brand(maxId), revInfos };
3001
3930
  }
3002
3931
 
@@ -3016,25 +3945,28 @@ function revisionInfoFromTaggedChange(
3016
3945
  return revInfos;
3017
3946
  }
3018
3947
 
3019
- function fieldChangeFromId(
3020
- fields: FieldChangeMap,
3021
- nodes: ChangeAtomIdBTree<NodeChangeset>,
3022
- id: FieldId,
3023
- ): FieldChange {
3024
- const fieldMap = fieldMapFromNodeId(fields, nodes, id.nodeId);
3948
+ function fieldChangeFromId(change: ModularChangeset, id: FieldId): FieldChange {
3949
+ const fieldId = normalizeFieldId(id, change.nodeAliases);
3950
+ const fieldMap = fieldMapFromNodeId(
3951
+ change.fieldChanges,
3952
+ change.nodeChanges,
3953
+ change.nodeAliases,
3954
+ fieldId.nodeId,
3955
+ );
3025
3956
  return fieldMap.get(id.field) ?? fail(0xb25 /* No field exists for the given ID */);
3026
3957
  }
3027
3958
 
3028
3959
  function fieldMapFromNodeId(
3029
3960
  rootFieldMap: FieldChangeMap,
3030
3961
  nodes: ChangeAtomIdBTree<NodeChangeset>,
3962
+ aliases: ChangeAtomIdBTree<NodeId>,
3031
3963
  nodeId: NodeId | undefined,
3032
3964
  ): FieldChangeMap {
3033
3965
  if (nodeId === undefined) {
3034
3966
  return rootFieldMap;
3035
3967
  }
3036
3968
 
3037
- const node = nodeChangeFromId(nodes, nodeId);
3969
+ const node = nodeChangeFromId(nodes, aliases, nodeId);
3038
3970
  assert(node.fieldChanges !== undefined, 0x9c9 /* Expected node to have field changes */);
3039
3971
  return node.fieldChanges;
3040
3972
  }
@@ -3051,8 +3983,13 @@ function rebasedNodeIdFromBaseNodeId(table: RebaseTable, baseId: NodeId): NodeId
3051
3983
  return getFromChangeAtomIdMap(table.baseToRebasedNodeId, baseId) ?? baseId;
3052
3984
  }
3053
3985
 
3054
- function nodeChangeFromId(nodes: ChangeAtomIdBTree<NodeChangeset>, id: NodeId): NodeChangeset {
3055
- const node = getFromChangeAtomIdMap(nodes, id);
3986
+ function nodeChangeFromId(
3987
+ nodes: ChangeAtomIdBTree<NodeChangeset>,
3988
+ aliases: ChangeAtomIdBTree<NodeId>,
3989
+ id: NodeId,
3990
+ ): NodeChangeset {
3991
+ const normalizedId = normalizeNodeId(id, aliases);
3992
+ const node = getFromChangeAtomIdMap(nodes, normalizedId);
3056
3993
  assert(node !== undefined, 0x9ca /* Unknown node ID */);
3057
3994
  return node;
3058
3995
  }
@@ -3062,6 +3999,10 @@ function fieldIdFromFieldIdKey([revision, localId, field]: FieldIdKey): FieldId
3062
3999
  return { nodeId, field };
3063
4000
  }
3064
4001
 
4002
+ function fieldIdKeyFromFieldId(fieldId: FieldId): FieldIdKey {
4003
+ return [fieldId.nodeId?.revision, fieldId.nodeId?.localId, fieldId.field];
4004
+ }
4005
+
3065
4006
  function cloneNodeChangeset(nodeChangeset: NodeChangeset): NodeChangeset {
3066
4007
  if (nodeChangeset.fieldChanges !== undefined) {
3067
4008
  return { ...nodeChangeset, fieldChanges: new Map(nodeChangeset.fieldChanges) };
@@ -3070,6 +4011,16 @@ function cloneNodeChangeset(nodeChangeset: NodeChangeset): NodeChangeset {
3070
4011
  return { ...nodeChangeset };
3071
4012
  }
3072
4013
 
4014
+ function replaceNodeLocationRevision(
4015
+ location: NodeLocation,
4016
+ oldRevisions: Set<RevisionTag | undefined>,
4017
+ newRevision: RevisionTag | undefined,
4018
+ ): NodeLocation {
4019
+ return location.field !== undefined
4020
+ ? { field: replaceFieldIdRevision(location.field, oldRevisions, newRevision) }
4021
+ : { root: replaceAtomRevisions(location.root, oldRevisions, newRevision) };
4022
+ }
4023
+
3073
4024
  function replaceFieldIdRevision(
3074
4025
  fieldId: FieldId,
3075
4026
  oldRevisions: Set<RevisionTag | undefined>,
@@ -3085,10 +4036,16 @@ function replaceFieldIdRevision(
3085
4036
  };
3086
4037
  }
3087
4038
 
3088
- export function getParentFieldId(changeset: ModularChangeset, nodeId: NodeId): FieldId {
3089
- const parentId = getFromChangeAtomIdMap(changeset.nodeToParent, nodeId);
3090
- assert(parentId !== undefined, 0x9cb /* Parent field should be defined */);
3091
- return normalizeFieldId(parentId, changeset.nodeAliases);
4039
+ export function getNodeParent(changeset: ModularChangeset, nodeId: NodeId): NodeLocation {
4040
+ const normalizedNodeId = normalizeNodeId(nodeId, changeset.nodeAliases);
4041
+ const location = getFromChangeAtomIdMap(changeset.nodeToParent, normalizedNodeId);
4042
+ assert(location !== undefined, 0x9cb /* Parent field should be defined */);
4043
+
4044
+ if (location.field !== undefined) {
4045
+ return { field: normalizeFieldId(location.field, changeset.nodeAliases) };
4046
+ }
4047
+
4048
+ return location;
3092
4049
  }
3093
4050
 
3094
4051
  function getFieldsForCrossFieldKey(
@@ -3101,6 +4058,30 @@ function getFieldsForCrossFieldKey(
3101
4058
  .map(({ value: fieldId }) => normalizeFieldId(fieldId, changeset.nodeAliases));
3102
4059
  }
3103
4060
 
4061
+ function getFirstFieldForCrossFieldKey(
4062
+ changeset: ModularChangeset,
4063
+ key: CrossFieldKey,
4064
+ count: number,
4065
+ ): RangeQueryResult<FieldId | undefined> {
4066
+ const result = changeset.crossFieldKeys.getFirst(key, count);
4067
+ if (result.value === undefined) {
4068
+ return result;
4069
+ }
4070
+
4071
+ return { ...result, value: normalizeFieldId(result.value, changeset.nodeAliases) };
4072
+ }
4073
+
4074
+ function normalizeNodeLocation(
4075
+ location: NodeLocation,
4076
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4077
+ ): NodeLocation {
4078
+ if (location.field !== undefined) {
4079
+ return { field: normalizeFieldId(location.field, nodeAliases) };
4080
+ }
4081
+
4082
+ return location;
4083
+ }
4084
+
3104
4085
  // This is only exported for use in test utilities.
3105
4086
  export function normalizeFieldId(
3106
4087
  fieldId: FieldId,
@@ -3114,8 +4095,12 @@ export function normalizeFieldId(
3114
4095
  /**
3115
4096
  * @returns The canonical form of nodeId, according to nodeAliases
3116
4097
  */
3117
- function normalizeNodeId(nodeId: NodeId, nodeAliases: ChangeAtomIdBTree<NodeId>): NodeId {
4098
+ export function normalizeNodeId(
4099
+ nodeId: NodeId,
4100
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4101
+ ): NodeId {
3118
4102
  let currentId = nodeId;
4103
+ let cycleProbeId: NodeId | undefined = nodeId;
3119
4104
 
3120
4105
  // eslint-disable-next-line no-constant-condition
3121
4106
  while (true) {
@@ -3125,6 +4110,16 @@ function normalizeNodeId(nodeId: NodeId, nodeAliases: ChangeAtomIdBTree<NodeId>)
3125
4110
  }
3126
4111
 
3127
4112
  currentId = dealiased;
4113
+
4114
+ if (cycleProbeId !== undefined) {
4115
+ cycleProbeId = getFromChangeAtomIdMap(nodeAliases, cycleProbeId);
4116
+ }
4117
+
4118
+ if (cycleProbeId !== undefined) {
4119
+ cycleProbeId = getFromChangeAtomIdMap(nodeAliases, cycleProbeId);
4120
+ }
4121
+
4122
+ assert(!areEqualChangeAtomIdOpts(cycleProbeId, currentId), "Alias cycle detected");
3128
4123
  }
3129
4124
  }
3130
4125
 
@@ -3135,22 +4130,835 @@ function hasConflicts(change: ModularChangeset): boolean {
3135
4130
  interface ModularChangesetContent {
3136
4131
  fieldChanges: FieldChangeMap;
3137
4132
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
3138
- nodeToParent: ChangeAtomIdBTree<FieldId>;
4133
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>;
4134
+ rootNodes: RootNodeTable;
3139
4135
  nodeAliases: ChangeAtomIdBTree<NodeId>;
3140
4136
  crossFieldKeys: CrossFieldKeyTable;
3141
4137
  }
3142
4138
 
3143
- function getFromChangeAtomIdMap<T>(
3144
- map: ChangeAtomIdBTree<T>,
3145
- id: ChangeAtomId,
3146
- ): T | undefined {
3147
- return map.get([id.revision, id.localId]);
4139
+ function areEqualFieldIds(a: FieldId, b: FieldId): boolean {
4140
+ return areEqualChangeAtomIdOpts(a.nodeId, b.nodeId) && a.field === b.field;
3148
4141
  }
3149
4142
 
3150
- function setInChangeAtomIdMap<T>(map: ChangeAtomIdBTree<T>, id: ChangeAtomId, value: T): void {
3151
- map.set([id.revision, id.localId], value);
4143
+ function firstAttachIdFromDetachId(
4144
+ roots: RootNodeTable,
4145
+ detachId: ChangeAtomId,
4146
+ count: number,
4147
+ ): RangeQueryResult<ChangeAtomId> {
4148
+ const result = roots.oldToNewId.getFirst(detachId, count);
4149
+ return { ...result, value: result.value ?? detachId };
3152
4150
  }
3153
4151
 
3154
- function areEqualFieldIds(a: FieldId, b: FieldId): boolean {
3155
- return areEqualChangeAtomIdOpts(a.nodeId, b.nodeId) && a.field === b.field;
4152
+ function firstDetachIdFromAttachId(
4153
+ roots: RootNodeTable,
4154
+ attachId: ChangeAtomId,
4155
+ count: number,
4156
+ ): RangeQueryEntry<ChangeAtomId, ChangeAtomId> {
4157
+ const result = roots.newToOldId.getFirst(attachId, count);
4158
+ return { ...result, start: attachId, value: result.value ?? attachId };
4159
+ }
4160
+
4161
+ function rebaseCrossFieldKeys(
4162
+ sourceTable: CrossFieldKeyTable,
4163
+ movedDetaches: ChangeAtomIdRangeMap<boolean>,
4164
+ newDetachLocations: ChangeAtomIdRangeMap<FieldId>,
4165
+ ): CrossFieldKeyTable {
4166
+ const rebasedTable = sourceTable.clone();
4167
+ for (const entry of movedDetaches.entries()) {
4168
+ rebasedTable.delete({ ...entry.start, target: CrossFieldTarget.Source }, entry.length);
4169
+ }
4170
+
4171
+ for (const entry of newDetachLocations.entries()) {
4172
+ rebasedTable.set(
4173
+ { ...entry.start, target: CrossFieldTarget.Source },
4174
+ entry.length,
4175
+ entry.value,
4176
+ );
4177
+ }
4178
+
4179
+ return rebasedTable;
4180
+ }
4181
+
4182
+ export function newRootTable(): RootNodeTable {
4183
+ return {
4184
+ newToOldId: newChangeAtomIdTransform(),
4185
+ oldToNewId: newChangeAtomIdTransform(),
4186
+ nodeChanges: newTupleBTree(),
4187
+ detachLocations: newChangeAtomIdRangeMap(),
4188
+ outputDetachLocations: newChangeAtomIdRangeMap(),
4189
+ };
4190
+ }
4191
+
4192
+ function rebaseRoots(
4193
+ change: ModularChangeset,
4194
+ base: ModularChangeset,
4195
+ affectedBaseFields: TupleBTree<FieldIdKey, boolean>,
4196
+ nodesToRebase: [newChangeset: NodeId, baseChangeset: NodeId][],
4197
+ rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
4198
+ rebaseVersion: RebaseVersion,
4199
+ ): RootNodeTable {
4200
+ const rebasedRoots = newRootTable();
4201
+ for (const renameEntry of change.rootNodes.oldToNewId.entries()) {
4202
+ rebaseRename(change.rootNodes, rebasedRoots, renameEntry, base, affectedBaseFields);
4203
+ }
4204
+
4205
+ for (const [detachIdKey, nodeId] of change.rootNodes.nodeChanges.entries()) {
4206
+ const changes = base.rootNodes.nodeChanges.get(detachIdKey);
4207
+ if (changes !== undefined) {
4208
+ nodesToRebase.push([nodeId, changes]);
4209
+ }
4210
+
4211
+ const detachId = makeChangeAtomId(detachIdKey[1], detachIdKey[0]);
4212
+ const attachId = firstAttachIdFromDetachId(base.rootNodes, detachId, 1).value;
4213
+ const baseAttachEntry = base.crossFieldKeys.getFirst(
4214
+ { target: CrossFieldTarget.Destination, ...attachId },
4215
+ 1,
4216
+ );
4217
+ if (baseAttachEntry.value !== undefined) {
4218
+ affectedBaseFields.set(fieldIdKeyFromFieldId(baseAttachEntry.value), true);
4219
+ rebasedNodeToParent.delete(detachIdKey);
4220
+ } else {
4221
+ const renamedDetachId = firstAttachIdFromDetachId(base.rootNodes, detachId, 1).value;
4222
+ const baseOutputDetachLocation = base.rootNodes.outputDetachLocations.getFirst(
4223
+ renamedDetachId,
4224
+ 1,
4225
+ ).value;
4226
+
4227
+ if (baseOutputDetachLocation !== undefined) {
4228
+ affectedBaseFields.set(fieldIdKeyFromFieldId(baseOutputDetachLocation), true);
4229
+ }
4230
+
4231
+ const detachLocation =
4232
+ baseOutputDetachLocation ??
4233
+ change.rootNodes.detachLocations.getFirst(detachId, 1).value;
4234
+
4235
+ // Note that `baseOutputDetachLocation` may contain a node ID from the base changeset.
4236
+ // We will replace the detach location entry with the node ID from the rebased changeset in `fixupRebasedDetachLocations`
4237
+ assignRootChange(
4238
+ rebasedRoots,
4239
+ rebasedNodeToParent,
4240
+ renamedDetachId,
4241
+ nodeId,
4242
+ detachLocation,
4243
+ rebaseVersion,
4244
+ );
4245
+ }
4246
+ }
4247
+
4248
+ for (const entry of change.rootNodes.outputDetachLocations.entries()) {
4249
+ rebasedRoots.outputDetachLocations.set(entry.start, entry.length, entry.value);
4250
+ }
4251
+
4252
+ return rebasedRoots;
4253
+ }
4254
+
4255
+ function rebaseRename(
4256
+ newRoots: RootNodeTable,
4257
+ rebasedRoots: RootNodeTable,
4258
+ renameEntry: RangeQueryEntry<ChangeAtomId, ChangeAtomId>,
4259
+ base: ModularChangeset,
4260
+ affectedBaseFields: TupleBTree<FieldIdKey, boolean>,
4261
+ ): void {
4262
+ let count = renameEntry.length;
4263
+ const baseRenameEntry = firstAttachIdFromDetachId(base.rootNodes, renameEntry.start, count);
4264
+ count = baseRenameEntry.length;
4265
+
4266
+ const baseAttachEntry = base.crossFieldKeys.getFirst(
4267
+ {
4268
+ ...baseRenameEntry.value,
4269
+ target: CrossFieldTarget.Destination,
4270
+ },
4271
+ count,
4272
+ );
4273
+
4274
+ count = baseAttachEntry.length;
4275
+
4276
+ if (baseAttachEntry.value !== undefined) {
4277
+ // This rename represents an intention to detach these nodes.
4278
+ // The rebased change should have a detach in the field where the base change attaches the nodes,
4279
+ // so we need to ensure that field is processed.
4280
+ affectedBaseFields.set(
4281
+ fieldIdKeyFromFieldId(normalizeFieldId(baseAttachEntry.value, base.nodeAliases)),
4282
+ true,
4283
+ );
4284
+ } else {
4285
+ const baseOutputDetachLocation = base.rootNodes.outputDetachLocations.getFirst(
4286
+ baseRenameEntry.value,
4287
+ 1,
4288
+ ).value;
4289
+
4290
+ if (baseOutputDetachLocation !== undefined) {
4291
+ affectedBaseFields.set(fieldIdKeyFromFieldId(baseOutputDetachLocation), true);
4292
+ }
4293
+
4294
+ const detachEntry = newRoots.detachLocations.getFirst(renameEntry.start, count);
4295
+ count = detachEntry.length;
4296
+
4297
+ const detachLocation = baseOutputDetachLocation ?? detachEntry.value;
4298
+
4299
+ // Note that `baseOutputDetachLocation` may contain a node ID from the base changeset.
4300
+ // We will replace the detach location entry with the node ID from the rebased changeset in `fixupRebasedDetachLocations`
4301
+ addNodeRename(
4302
+ rebasedRoots,
4303
+ baseRenameEntry.value,
4304
+ renameEntry.value,
4305
+ count,
4306
+ detachLocation,
4307
+ );
4308
+ }
4309
+
4310
+ const countRemaining = renameEntry.length - count;
4311
+ if (countRemaining > 0) {
4312
+ rebaseRename(
4313
+ newRoots,
4314
+ rebasedRoots,
4315
+ {
4316
+ start: offsetChangeAtomId(renameEntry.start, count),
4317
+ value: offsetChangeAtomId(renameEntry.value, count),
4318
+ length: countRemaining,
4319
+ },
4320
+ base,
4321
+ affectedBaseFields,
4322
+ );
4323
+ }
4324
+ }
4325
+
4326
+ /**
4327
+ * For each root detach location, replaces any node ID from the base changeset
4328
+ * with the corresponding ID in the new changeset.
4329
+ */
4330
+ function fixupRebasedDetachLocations(table: RebaseTable): void {
4331
+ for (const {
4332
+ start,
4333
+ length,
4334
+ value: detachLocation,
4335
+ } of table.rebasedRootNodes.detachLocations.entries()) {
4336
+ const normalizedDetachLocation = normalizeFieldId(
4337
+ detachLocation,
4338
+ table.baseChange.nodeAliases,
4339
+ );
4340
+
4341
+ if (normalizedDetachLocation.nodeId !== undefined) {
4342
+ const rebasedNodeId = getFromChangeAtomIdMap(
4343
+ table.baseToRebasedNodeId,
4344
+ normalizedDetachLocation.nodeId,
4345
+ );
4346
+
4347
+ if (rebasedNodeId !== undefined) {
4348
+ table.rebasedRootNodes.detachLocations.set(start, length, {
4349
+ ...normalizedDetachLocation,
4350
+ nodeId: rebasedNodeId,
4351
+ });
4352
+ }
4353
+ }
4354
+ }
4355
+ }
4356
+
4357
+ function addNodesToCompose(table: ComposeTable, id1: NodeId, id2: NodeId): void {
4358
+ const normalizedId1 = normalizeNodeId(id1, table.baseChange.nodeAliases);
4359
+ const normalizedId2 = normalizeNodeId(id2, table.newChange.nodeAliases);
4360
+ if (getFromChangeAtomIdMap(table.newToBaseNodeId, normalizedId2) === undefined) {
4361
+ setInChangeAtomIdMap(table.newToBaseNodeId, normalizedId2, normalizedId1);
4362
+ table.pendingCompositions.nodeIdsToCompose.push([normalizedId1, normalizedId2]);
4363
+ }
4364
+ }
4365
+
4366
+ function composeRevInfos(
4367
+ revisions1: readonly RevisionInfo[] | undefined,
4368
+ revisions2: readonly RevisionInfo[] | undefined,
4369
+ ): RevisionInfo[] {
4370
+ const result: RevisionInfo[] = [...(revisions1 ?? []), ...(revisions2 ?? [])];
4371
+ return result;
4372
+ }
4373
+
4374
+ function composeCrossFieldKeyTables(
4375
+ table1: CrossFieldKeyTable,
4376
+ table2: CrossFieldKeyTable,
4377
+ movedCrossFieldKeys: CrossFieldKeyTable,
4378
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
4379
+ ): CrossFieldKeyTable {
4380
+ const composedTable = RangeMap.union(table1, table2);
4381
+ for (const entry of movedCrossFieldKeys.entries()) {
4382
+ composedTable.set(entry.start, entry.length, entry.value);
4383
+ }
4384
+
4385
+ for (const entry of removedCrossFieldKeys.entries()) {
4386
+ composedTable.delete(entry.start, entry.length);
4387
+ }
4388
+
4389
+ return composedTable;
4390
+ }
4391
+
4392
+ function composeRootTables(
4393
+ change1: ModularChangeset,
4394
+ change2: ModularChangeset,
4395
+ composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
4396
+ movedCrossFieldKeys: CrossFieldKeyTable,
4397
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
4398
+ pendingCompositions: PendingCompositions,
4399
+ ): RootNodeTable {
4400
+ const composedTable = cloneRootTable(change1.rootNodes);
4401
+
4402
+ for (const renameEntry of change2.rootNodes.oldToNewId.entries()) {
4403
+ composeRename(
4404
+ change1,
4405
+ change2,
4406
+ composedTable,
4407
+ renameEntry.start,
4408
+ renameEntry.value,
4409
+ renameEntry.length,
4410
+ movedCrossFieldKeys,
4411
+ removedCrossFieldKeys,
4412
+ pendingCompositions,
4413
+ );
4414
+ }
4415
+
4416
+ for (const [[revision2, id2], nodeId2] of change2.rootNodes.nodeChanges.entries()) {
4417
+ const detachId2 = { revision: revision2, localId: id2 };
4418
+ const detachId1 = firstDetachIdFromAttachId(change1.rootNodes, detachId2, 1).value;
4419
+ const nodeId1 = getFromChangeAtomIdMap(change1.rootNodes.nodeChanges, detachId1);
4420
+
4421
+ if (nodeId1 !== undefined) {
4422
+ pendingCompositions.nodeIdsToCompose.push([nodeId1, nodeId2]);
4423
+ } else {
4424
+ const fieldId = getFieldsForCrossFieldKey(
4425
+ change1,
4426
+ { ...detachId1, target: CrossFieldTarget.Source },
4427
+ 1,
4428
+ )[0];
4429
+
4430
+ if (fieldId !== undefined) {
4431
+ // In this case, this node is attached in the input context of change1,
4432
+ // and is represented in detachFieldId.
4433
+ pendingCompositions.affectedBaseFields.set(
4434
+ [fieldId.nodeId?.revision, fieldId.nodeId?.localId, fieldId.field],
4435
+ true,
4436
+ );
4437
+ } else {
4438
+ assignRootChange(
4439
+ composedTable,
4440
+ composedNodeToParent,
4441
+ detachId1,
4442
+ nodeId2,
4443
+ change1.rootNodes.detachLocations.getFirst(detachId1, 1).value ??
4444
+ change2.rootNodes.detachLocations.getFirst(detachId2, 1).value,
4445
+ Math.max(change1.rebaseVersion, change2.rebaseVersion) as RebaseVersion,
4446
+ );
4447
+ }
4448
+ }
4449
+ }
4450
+
4451
+ for (const outputDetachEntry of change1.rootNodes.outputDetachLocations.entries()) {
4452
+ composeOutputDetachLocation(
4453
+ outputDetachEntry.start,
4454
+ outputDetachEntry.length,
4455
+ outputDetachEntry.value,
4456
+ change2,
4457
+ composedTable,
4458
+ );
4459
+ }
4460
+
4461
+ for (const entry of change2.rootNodes.outputDetachLocations.entries()) {
4462
+ composedTable.outputDetachLocations.set(entry.start, entry.length, entry.value);
4463
+ }
4464
+
4465
+ return composedTable;
4466
+ }
4467
+
4468
+ function composeOutputDetachLocation(
4469
+ outputDetachId1: ChangeAtomId,
4470
+ count: number,
4471
+ detachLocation: FieldId,
4472
+ change2: ModularChangeset,
4473
+ composedTable: RootNodeTable,
4474
+ ): void {
4475
+ let countToProcess = count;
4476
+ const renameEntry = firstAttachIdFromDetachId(
4477
+ change2.rootNodes,
4478
+ outputDetachId1,
4479
+ countToProcess,
4480
+ );
4481
+ countToProcess = renameEntry.length;
4482
+
4483
+ const attachEntry = getFirstAttachField(
4484
+ change2.crossFieldKeys,
4485
+ renameEntry.value,
4486
+ countToProcess,
4487
+ );
4488
+ countToProcess = attachEntry.length;
4489
+
4490
+ composedTable.outputDetachLocations.delete(outputDetachId1, countToProcess);
4491
+
4492
+ if (attachEntry.value === undefined) {
4493
+ // We update the key for the detach location to the renamed ID of the root in the composed output context.
4494
+ composedTable.outputDetachLocations.set(renameEntry.value, countToProcess, detachLocation);
4495
+ } else {
4496
+ // These nodes are attached by `change2` and thus attached in the composed output context,
4497
+ // so there should be no output detach location.
4498
+ }
4499
+
4500
+ const countRemaining = count - countToProcess;
4501
+ if (countRemaining > 0) {
4502
+ composeOutputDetachLocation(
4503
+ offsetChangeAtomId(outputDetachId1, countToProcess),
4504
+ countRemaining,
4505
+ detachLocation,
4506
+ change2,
4507
+ composedTable,
4508
+ );
4509
+ }
4510
+ }
4511
+
4512
+ function composeRename(
4513
+ change1: ModularChangeset,
4514
+ change2: ModularChangeset,
4515
+ mergedTable: RootNodeTable,
4516
+ oldId: ChangeAtomId,
4517
+ newId: ChangeAtomId,
4518
+ count: number,
4519
+ movedCrossFieldKeys: CrossFieldKeyTable,
4520
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
4521
+ pendingCompositions: PendingCompositions,
4522
+ ): void {
4523
+ let countToProcess = count;
4524
+ const detachEntry = getFirstDetachField(change1.crossFieldKeys, oldId, countToProcess);
4525
+ countToProcess = detachEntry.length;
4526
+
4527
+ if (detachEntry.value !== undefined) {
4528
+ // `change1` detached these nodes,
4529
+ // so we invalidate the detach location so that the detach's ID can be replaced with the new ID.
4530
+ pendingCompositions.affectedBaseFields.set(fieldIdKeyFromFieldId(detachEntry.value), true);
4531
+
4532
+ if (!areEqualChangeAtomIds(oldId, newId)) {
4533
+ // `change1`'s detach will be replaced by `change2`'s detach, so we update the cross-field keys.
4534
+ removedCrossFieldKeys.set(
4535
+ { ...oldId, target: CrossFieldTarget.Source },
4536
+ countToProcess,
4537
+ true,
4538
+ );
4539
+ }
4540
+
4541
+ movedCrossFieldKeys.set(
4542
+ { ...newId, target: CrossFieldTarget.Source },
4543
+ countToProcess,
4544
+ detachEntry.value,
4545
+ );
4546
+ } else {
4547
+ // `change1` may also have a rename to `renameEntry.value`, in which case it must refer to a different node.
4548
+ // That node must have been attached by `change1` and detached by `change2`.
4549
+ // The final rename for that node will be created in `composeAttachDetach`.
4550
+ // We delete any such rename for now to avoid colliding with the rename currently being processed.
4551
+ deleteNodeRenameTo(mergedTable, newId, countToProcess);
4552
+
4553
+ // The nodes were detached before `change`, so we append this rename.
4554
+ appendNodeRename(
4555
+ mergedTable,
4556
+ oldId,
4557
+ newId,
4558
+ countToProcess,
4559
+ change1.rootNodes,
4560
+ change2.rootNodes.detachLocations.getFirst(oldId, countToProcess).value,
4561
+ );
4562
+ }
4563
+
4564
+ if (countToProcess < count) {
4565
+ composeRename(
4566
+ change1,
4567
+ change2,
4568
+ mergedTable,
4569
+ offsetChangeAtomId(oldId, countToProcess),
4570
+ offsetChangeAtomId(newId, countToProcess),
4571
+ count - countToProcess,
4572
+ movedCrossFieldKeys,
4573
+ removedCrossFieldKeys,
4574
+ pendingCompositions,
4575
+ );
4576
+ }
4577
+ }
4578
+
4579
+ export function cloneRootTable(table: RootNodeTable): RootNodeTable {
4580
+ return {
4581
+ oldToNewId: table.oldToNewId.clone(),
4582
+ newToOldId: table.newToOldId.clone(),
4583
+ nodeChanges: brand(table.nodeChanges.clone()),
4584
+ detachLocations: table.detachLocations.clone(),
4585
+ outputDetachLocations: table.outputDetachLocations.clone(),
4586
+ };
4587
+ }
4588
+
4589
+ function invertRootTable(change: ModularChangeset, isRollback: boolean): RootNodeTable {
4590
+ const invertedRoots: RootNodeTable = newRootTable();
4591
+ for (const [[revision, localId], nodeId] of change.rootNodes.nodeChanges.entries()) {
4592
+ const detachId: ChangeAtomId = { revision, localId };
4593
+ const renamedId = firstAttachIdFromDetachId(change.rootNodes, detachId, 1).value;
4594
+
4595
+ // This checks whether `change` attaches this node.
4596
+ // If it does, the node is not detached in the input context of the inverse, and so should not be included in the root table.
4597
+ if (
4598
+ change.crossFieldKeys.getFirst({ ...renamedId, target: CrossFieldTarget.Destination }, 1)
4599
+ .value === undefined
4600
+ ) {
4601
+ assignRootChange(
4602
+ invertedRoots,
4603
+ undefined,
4604
+ renamedId,
4605
+ nodeId,
4606
+ change.rootNodes.detachLocations.getFirst(detachId, 1).value,
4607
+ change.rebaseVersion,
4608
+ );
4609
+ }
4610
+ }
4611
+
4612
+ if (isRollback) {
4613
+ // We only invert renames of nodes which are not attached or detached by this changeset.
4614
+ // When we invert an attach we will create a detach which incorporates the rename.
4615
+ for (const {
4616
+ start: oldId,
4617
+ value: newId,
4618
+ length,
4619
+ } of change.rootNodes.oldToNewId.entries()) {
4620
+ invertRename(change, invertedRoots, oldId, newId, length);
4621
+ }
4622
+ }
4623
+
4624
+ return invertedRoots;
4625
+ }
4626
+
4627
+ function invertRename(
4628
+ change: ModularChangeset,
4629
+ invertedRoots: RootNodeTable,
4630
+ oldId: ChangeAtomId,
4631
+ newId: ChangeAtomId,
4632
+ length: number,
4633
+ ): void {
4634
+ for (const detachEntry of doesChangeDetachNodes(change.crossFieldKeys, newId, length)) {
4635
+ assert(
4636
+ !detachEntry.value,
4637
+ "A changeset should not have a rename and detach for the same node.",
4638
+ );
4639
+ }
4640
+
4641
+ let countProcessed = length;
4642
+ const attachEntry = getFirstAttachField(change.crossFieldKeys, newId, countProcessed);
4643
+ countProcessed = attachEntry.length;
4644
+ if (attachEntry.value === undefined) {
4645
+ const outputDetachEntry = change.rootNodes.outputDetachLocations.getFirst(
4646
+ newId,
4647
+ countProcessed,
4648
+ );
4649
+ countProcessed = outputDetachEntry.length;
4650
+
4651
+ const inputDetachEntry = change.rootNodes.detachLocations.getFirst(oldId, countProcessed);
4652
+ countProcessed = inputDetachEntry.length;
4653
+
4654
+ addNodeRename(
4655
+ invertedRoots,
4656
+ newId,
4657
+ oldId,
4658
+ countProcessed,
4659
+ outputDetachEntry.value ?? inputDetachEntry.value,
4660
+ );
4661
+ }
4662
+
4663
+ if (countProcessed < length) {
4664
+ invertRename(
4665
+ change,
4666
+ invertedRoots,
4667
+ offsetChangeAtomId(oldId, countProcessed),
4668
+ offsetChangeAtomId(newId, countProcessed),
4669
+ length - countProcessed,
4670
+ );
4671
+ }
4672
+ }
4673
+
4674
+ function doesChangeAttachNodes(
4675
+ table: CrossFieldKeyTable,
4676
+ id: ChangeAtomId,
4677
+ count: number,
4678
+ ): RangeQueryResultFragment<boolean>[] {
4679
+ return table
4680
+ .getAll2({ ...id, target: CrossFieldTarget.Destination }, count)
4681
+ .map((entry) => ({ ...entry, value: entry.value !== undefined }));
4682
+ }
4683
+
4684
+ function doesChangeDetachNodes(
4685
+ table: CrossFieldKeyTable,
4686
+ id: ChangeAtomId,
4687
+ count: number,
4688
+ ): RangeQueryResultFragment<boolean>[] {
4689
+ return table
4690
+ .getAll2({ ...id, target: CrossFieldTarget.Source }, count)
4691
+ .map((entry) => ({ ...entry, value: entry.value !== undefined }));
4692
+ }
4693
+
4694
+ export function getFirstDetachField(
4695
+ table: CrossFieldKeyTable,
4696
+ id: ChangeAtomId,
4697
+ count: number,
4698
+ ): RangeQueryResult<FieldId | undefined> {
4699
+ return table.getFirst({ target: CrossFieldTarget.Source, ...id }, count);
4700
+ }
4701
+
4702
+ export function getFirstAttachField(
4703
+ table: CrossFieldKeyTable,
4704
+ id: ChangeAtomId,
4705
+ count: number,
4706
+ ): RangeQueryResult<FieldId | undefined> {
4707
+ return table.getFirst({ target: CrossFieldTarget.Destination, ...id }, count);
4708
+ }
4709
+
4710
+ export function addNodeRename(
4711
+ table: RootNodeTable,
4712
+ oldId: ChangeAtomId,
4713
+ newId: ChangeAtomId,
4714
+ count: number,
4715
+ detachLocation: FieldId | undefined,
4716
+ ): void {
4717
+ if (areEqualChangeAtomIds(oldId, newId)) {
4718
+ return;
4719
+ }
4720
+
4721
+ for (const entry of table.oldToNewId.getAll2(oldId, count)) {
4722
+ assert(
4723
+ entry.value === undefined ||
4724
+ areEqualChangeAtomIds(entry.value, offsetChangeAtomId(newId, entry.offset)),
4725
+ "Rename collision detected",
4726
+ );
4727
+ }
4728
+
4729
+ for (const entry of table.newToOldId.getAll2(newId, count)) {
4730
+ assert(
4731
+ entry.value === undefined ||
4732
+ areEqualChangeAtomIds(entry.value, offsetChangeAtomId(oldId, entry.offset)),
4733
+ "Rename collision detected",
4734
+ );
4735
+ }
4736
+
4737
+ table.oldToNewId.set(oldId, count, newId);
4738
+ table.newToOldId.set(newId, count, oldId);
4739
+
4740
+ if (detachLocation !== undefined) {
4741
+ table.detachLocations.set(oldId, count, detachLocation);
4742
+ }
4743
+ }
4744
+
4745
+ /**
4746
+ * Deletes any renames from `id`.
4747
+ */
4748
+ function deleteNodeRenameFrom(roots: RootNodeTable, id: ChangeAtomId, count: number): void {
4749
+ for (const entry of roots.oldToNewId.getAll(id, count)) {
4750
+ deleteNodeRenameEntry(roots, entry.start, entry.value, entry.length);
4751
+ }
4752
+ }
4753
+
4754
+ /**
4755
+ * Deletes any renames to `id`.
4756
+ */
4757
+ function deleteNodeRenameTo(roots: RootNodeTable, id: ChangeAtomId, count: number): void {
4758
+ for (const entry of roots.newToOldId.getAll(id, count)) {
4759
+ deleteNodeRenameEntry(roots, entry.value, entry.start, entry.length);
4760
+ }
4761
+ }
4762
+
4763
+ function appendNodeRename(
4764
+ composedTable: RootNodeTable,
4765
+ oldId: ChangeAtomId,
4766
+ newId: ChangeAtomId,
4767
+ count: number,
4768
+ change1Table: RootNodeTable,
4769
+ detachLocation: FieldId | undefined,
4770
+ ): void {
4771
+ let countToProcess = count;
4772
+ const rename1Entry = change1Table.newToOldId.getFirst(oldId, countToProcess);
4773
+ countToProcess = rename1Entry.length;
4774
+
4775
+ if (rename1Entry.value !== undefined) {
4776
+ deleteNodeRenameFrom(composedTable, rename1Entry.value, countToProcess);
4777
+ }
4778
+
4779
+ addNodeRename(
4780
+ composedTable,
4781
+ rename1Entry.value ?? oldId,
4782
+ newId,
4783
+ countToProcess,
4784
+ detachLocation,
4785
+ );
4786
+
4787
+ tryRemoveDetachLocation(composedTable, newId, countToProcess);
4788
+
4789
+ if (countToProcess < count) {
4790
+ const countRemaining = count - countToProcess;
4791
+ appendNodeRename(
4792
+ composedTable,
4793
+ offsetChangeAtomId(oldId, countToProcess),
4794
+ offsetChangeAtomId(newId, countToProcess),
4795
+ countRemaining,
4796
+ change1Table,
4797
+ detachLocation,
4798
+ );
4799
+ }
4800
+ }
4801
+
4802
+ function tryRemoveDetachLocation(
4803
+ roots: RootNodeTable,
4804
+ rootId: ChangeAtomId,
4805
+ count: number,
4806
+ ): void {
4807
+ let countProcessed = count;
4808
+ const renameEntry = roots.oldToNewId.getFirst(rootId, countProcessed);
4809
+ countProcessed = renameEntry.length;
4810
+
4811
+ const outputDetachEntry = roots.outputDetachLocations.getFirst(rootId, countProcessed);
4812
+ countProcessed = outputDetachEntry.length;
4813
+
4814
+ const nodeChangeEntry = rangeQueryChangeAtomIdMap(roots.nodeChanges, rootId, countProcessed);
4815
+ countProcessed = nodeChangeEntry.length;
4816
+
4817
+ if (
4818
+ nodeChangeEntry.value === undefined &&
4819
+ renameEntry.value === undefined &&
4820
+ outputDetachEntry.value === undefined
4821
+ ) {
4822
+ roots.detachLocations.delete(rootId, countProcessed);
4823
+ }
4824
+
4825
+ const countRemaining = count - countProcessed;
4826
+ if (countRemaining > 0) {
4827
+ tryRemoveDetachLocation(roots, offsetChangeAtomId(rootId, countProcessed), countRemaining);
4828
+ }
4829
+ }
4830
+
4831
+ /**
4832
+ * Deletes the entry renaming the ID range of length `count` from `oldId` to `newId`.
4833
+ * This function assumes that such an entry exists.
4834
+ */
4835
+ function deleteNodeRenameEntry(
4836
+ roots: RootNodeTable,
4837
+ oldId: ChangeAtomId,
4838
+ newId: ChangeAtomId,
4839
+ count: number,
4840
+ ): void {
4841
+ roots.oldToNewId.delete(oldId, count);
4842
+ roots.newToOldId.delete(newId, count);
4843
+ }
4844
+
4845
+ function replaceRootTableRevision(
4846
+ table: RootNodeTable,
4847
+ oldRevisions: Set<RevisionTag | undefined>,
4848
+ newRevision: RevisionTag | undefined,
4849
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4850
+ ): RootNodeTable {
4851
+ const oldToNewId = table.oldToNewId.mapEntries(
4852
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4853
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4854
+ );
4855
+
4856
+ const newToOldId = table.newToOldId.mapEntries(
4857
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4858
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4859
+ );
4860
+
4861
+ const nodeChanges: ChangeAtomIdBTree<NodeId> = newTupleBTree(
4862
+ [...table.nodeChanges.entries()].map(([[revision, id], nodeId]) => [
4863
+ [oldRevisions.has(revision) ? newRevision : revision, id],
4864
+ replaceAtomRevisions(normalizeNodeId(nodeId, nodeAliases), oldRevisions, newRevision),
4865
+ ]),
4866
+ );
4867
+
4868
+ const detachLocations = table.detachLocations.mapEntries(
4869
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4870
+ (fieldId) =>
4871
+ replaceFieldIdRevision(
4872
+ normalizeFieldId(fieldId, nodeAliases),
4873
+ oldRevisions,
4874
+ newRevision,
4875
+ ),
4876
+ );
4877
+
4878
+ const outputDetachLocations = table.outputDetachLocations.mapEntries(
4879
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4880
+ (fieldId) =>
4881
+ replaceFieldIdRevision(
4882
+ normalizeFieldId(fieldId, nodeAliases),
4883
+ oldRevisions,
4884
+ newRevision,
4885
+ ),
4886
+ );
4887
+
4888
+ return { oldToNewId, newToOldId, nodeChanges, detachLocations, outputDetachLocations };
4889
+ }
4890
+
4891
+ function newDetachedEntryMap(): ChangeAtomIdRangeMap<DetachedNodeEntry> {
4892
+ return new RangeMap(offsetChangeAtomId, subtractChangeAtomIds, offsetDetachedNodeEntry);
4893
+ }
4894
+
4895
+ function offsetDetachedNodeEntry(entry: DetachedNodeEntry, count: number): DetachedNodeEntry {
4896
+ assert(
4897
+ count <= 1 || entry.nodeChange === undefined,
4898
+ "Cannot split an entry with a node change",
4899
+ );
4900
+
4901
+ return entry.detachId !== undefined
4902
+ ? { ...entry, detachId: offsetChangeAtomId(entry.detachId, count) }
4903
+ : entry;
4904
+ }
4905
+
4906
+ function getFieldsWithRootMoves(
4907
+ roots: RootNodeTable,
4908
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4909
+ ): TupleBTree<FieldIdKey, boolean> {
4910
+ const fields: TupleBTree<FieldIdKey, boolean> = newTupleBTree();
4911
+ for (const { start: rootId, value: fieldId, length } of roots.detachLocations.entries()) {
4912
+ let isRootMoved = false;
4913
+ for (const renameEntry of roots.oldToNewId.getAll2(rootId, length)) {
4914
+ if (renameEntry.value !== undefined) {
4915
+ isRootMoved = true;
4916
+ }
4917
+ }
4918
+
4919
+ for (const outputDetachEntry of roots.outputDetachLocations.getAll2(rootId, length)) {
4920
+ if (outputDetachEntry.value !== undefined) {
4921
+ isRootMoved = true;
4922
+ }
4923
+ }
4924
+
4925
+ if (isRootMoved) {
4926
+ fields.set(fieldIdKeyFromFieldId(normalizeFieldId(fieldId, nodeAliases)), true);
4927
+ }
4928
+ }
4929
+
4930
+ return fields;
4931
+ }
4932
+
4933
+ function getFieldToRootChanges(
4934
+ roots: RootNodeTable,
4935
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4936
+ ): TupleBTree<FieldIdKey, ChangeAtomId[]> {
4937
+ const fields: TupleBTree<FieldIdKey, ChangeAtomId[]> = newTupleBTree();
4938
+ for (const rootIdKey of roots.nodeChanges.keys()) {
4939
+ const rootId: ChangeAtomId = { revision: rootIdKey[0], localId: rootIdKey[1] };
4940
+ const detachLocation = roots.detachLocations.getFirst(rootId, 1).value;
4941
+ if (detachLocation !== undefined) {
4942
+ const fieldIdKey = fieldIdKeyFromFieldId(normalizeFieldId(detachLocation, nodeAliases));
4943
+ let rootsInField = fields.get(fieldIdKey);
4944
+ if (rootsInField === undefined) {
4945
+ rootsInField = [];
4946
+ fields.set(fieldIdKey, rootsInField);
4947
+ }
4948
+
4949
+ rootsInField.push(rootId);
4950
+ }
4951
+ }
4952
+
4953
+ return fields;
4954
+ }
4955
+
4956
+ function muteRootChanges(roots: RootNodeTable): RootNodeTable {
4957
+ return {
4958
+ oldToNewId: newChangeAtomIdTransform(),
4959
+ newToOldId: newChangeAtomIdTransform(),
4960
+ nodeChanges: brand(roots.nodeChanges.clone()),
4961
+ detachLocations: roots.detachLocations.clone(),
4962
+ outputDetachLocations: newChangeAtomIdRangeMap(),
4963
+ };
3156
4964
  }