@fluidframework/tree 2.74.0-365691 → 2.74.0-368706

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 (1243) 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 +90 -42
  67. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  68. package/dist/feature-libraries/default-schema/defaultEditBuilder.js +234 -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 +4 -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 +7 -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 +5 -5
  160. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  161. package/dist/feature-libraries/modular-schema/index.js +12 -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 +48 -15
  176. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  177. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +1298 -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/optionalFieldChangeTypes.d.ts +24 -33
  200. package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts.map +1 -1
  201. package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.js.map +1 -1
  202. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.d.ts +1 -1
  203. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.d.ts.map +1 -1
  204. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.js +57 -28
  205. package/dist/feature-libraries/optional-field/optionalFieldCodecV2.js.map +1 -1
  206. package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts +27 -8
  207. package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
  208. package/dist/feature-libraries/schema-index/schemaSummarizer.js +42 -16
  209. package/dist/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
  210. package/dist/feature-libraries/sequence-field/compose.d.ts +6 -7
  211. package/dist/feature-libraries/sequence-field/compose.d.ts.map +1 -1
  212. package/dist/feature-libraries/sequence-field/compose.js +80 -256
  213. package/dist/feature-libraries/sequence-field/compose.js.map +1 -1
  214. package/dist/feature-libraries/sequence-field/helperTypes.d.ts +14 -10
  215. package/dist/feature-libraries/sequence-field/helperTypes.d.ts.map +1 -1
  216. package/dist/feature-libraries/sequence-field/helperTypes.js.map +1 -1
  217. package/dist/feature-libraries/sequence-field/index.d.ts +2 -3
  218. package/dist/feature-libraries/sequence-field/index.d.ts.map +1 -1
  219. package/dist/feature-libraries/sequence-field/index.js +1 -3
  220. package/dist/feature-libraries/sequence-field/index.js.map +1 -1
  221. package/dist/feature-libraries/sequence-field/invert.d.ts +3 -3
  222. package/dist/feature-libraries/sequence-field/invert.d.ts.map +1 -1
  223. package/dist/feature-libraries/sequence-field/invert.js +65 -167
  224. package/dist/feature-libraries/sequence-field/invert.js.map +1 -1
  225. package/dist/feature-libraries/sequence-field/markQueue.d.ts +2 -2
  226. package/dist/feature-libraries/sequence-field/markQueue.d.ts.map +1 -1
  227. package/dist/feature-libraries/sequence-field/markQueue.js.map +1 -1
  228. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts +4 -56
  229. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  230. package/dist/feature-libraries/sequence-field/moveEffectTable.js +7 -86
  231. package/dist/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  232. package/dist/feature-libraries/sequence-field/rebase.d.ts +3 -3
  233. package/dist/feature-libraries/sequence-field/rebase.d.ts.map +1 -1
  234. package/dist/feature-libraries/sequence-field/rebase.js +106 -112
  235. package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
  236. package/dist/feature-libraries/sequence-field/replaceRevisions.d.ts.map +1 -1
  237. package/dist/feature-libraries/sequence-field/replaceRevisions.js +16 -33
  238. package/dist/feature-libraries/sequence-field/replaceRevisions.js.map +1 -1
  239. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  240. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +0 -2
  241. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  242. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +22 -4
  243. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
  244. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js +358 -179
  245. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  246. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
  247. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js +20 -60
  248. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
  249. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.d.ts +2 -2
  250. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.d.ts.map +1 -1
  251. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.js +10 -10
  252. package/dist/feature-libraries/sequence-field/sequenceFieldEditor.js.map +1 -1
  253. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +3 -2
  254. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  255. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js +14 -109
  256. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  257. package/dist/feature-libraries/sequence-field/types.d.ts +30 -59
  258. package/dist/feature-libraries/sequence-field/types.d.ts.map +1 -1
  259. package/dist/feature-libraries/sequence-field/types.js.map +1 -1
  260. package/dist/feature-libraries/sequence-field/utils.d.ts +15 -24
  261. package/dist/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  262. package/dist/feature-libraries/sequence-field/utils.js +111 -299
  263. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  264. package/dist/index.d.ts +1 -1
  265. package/dist/index.d.ts.map +1 -1
  266. package/dist/index.js +3 -3
  267. package/dist/index.js.map +1 -1
  268. package/dist/packageVersion.d.ts +1 -1
  269. package/dist/packageVersion.js +1 -1
  270. package/dist/packageVersion.js.map +1 -1
  271. package/dist/shared-tree/independentView.d.ts +1 -1
  272. package/dist/shared-tree/independentView.d.ts.map +1 -1
  273. package/dist/shared-tree/independentView.js.map +1 -1
  274. package/dist/shared-tree/index.d.ts +1 -1
  275. package/dist/shared-tree/index.d.ts.map +1 -1
  276. package/dist/shared-tree/index.js.map +1 -1
  277. package/dist/shared-tree/schematizeTree.d.ts +4 -4
  278. package/dist/shared-tree/schematizeTree.d.ts.map +1 -1
  279. package/dist/shared-tree/schematizeTree.js +2 -1
  280. package/dist/shared-tree/schematizeTree.js.map +1 -1
  281. package/dist/shared-tree/schematizingTreeView.d.ts +1 -5
  282. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  283. package/dist/shared-tree/schematizingTreeView.js +32 -33
  284. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  285. package/dist/shared-tree/sharedTree.d.ts +11 -5
  286. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  287. package/dist/shared-tree/sharedTree.js +14 -4
  288. package/dist/shared-tree/sharedTree.js.map +1 -1
  289. package/dist/shared-tree/sharedTreeChangeCodecs.d.ts +1 -1
  290. package/dist/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
  291. package/dist/shared-tree/sharedTreeChangeCodecs.js +1 -0
  292. package/dist/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
  293. package/dist/shared-tree/sharedTreeChangeEnricher.d.ts +20 -8
  294. package/dist/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
  295. package/dist/shared-tree/sharedTreeChangeEnricher.js +25 -11
  296. package/dist/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
  297. package/dist/shared-tree/sharedTreeChangeFamily.d.ts +4 -4
  298. package/dist/shared-tree/sharedTreeChangeFamily.d.ts.map +1 -1
  299. package/dist/shared-tree/sharedTreeChangeFamily.js +2 -2
  300. package/dist/shared-tree/sharedTreeChangeFamily.js.map +1 -1
  301. package/dist/shared-tree/sharedTreeEditBuilder.d.ts +16 -6
  302. package/dist/shared-tree/sharedTreeEditBuilder.d.ts.map +1 -1
  303. package/dist/shared-tree/sharedTreeEditBuilder.js +13 -6
  304. package/dist/shared-tree/sharedTreeEditBuilder.js.map +1 -1
  305. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  306. package/dist/shared-tree/treeAlpha.js +1 -1
  307. package/dist/shared-tree/treeAlpha.js.map +1 -1
  308. package/dist/shared-tree/treeCheckout.d.ts +12 -10
  309. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  310. package/dist/shared-tree/treeCheckout.js +66 -17
  311. package/dist/shared-tree/treeCheckout.js.map +1 -1
  312. package/dist/shared-tree-core/branch.d.ts +3 -2
  313. package/dist/shared-tree-core/branch.d.ts.map +1 -1
  314. package/dist/shared-tree-core/branch.js +4 -3
  315. package/dist/shared-tree-core/branch.js.map +1 -1
  316. package/dist/shared-tree-core/editManager.d.ts +2 -2
  317. package/dist/shared-tree-core/editManager.d.ts.map +1 -1
  318. package/dist/shared-tree-core/editManager.js +9 -9
  319. package/dist/shared-tree-core/editManager.js.map +1 -1
  320. package/dist/shared-tree-core/editManagerCodecs.d.ts +4 -0
  321. package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  322. package/dist/shared-tree-core/editManagerCodecs.js +16 -6
  323. package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
  324. package/{lib/shared-tree-core/editManagerCodecsV5.d.ts → dist/shared-tree-core/editManagerCodecsVSharedBranches.d.ts} +3 -3
  325. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.d.ts.map +1 -0
  326. package/dist/shared-tree-core/{editManagerCodecsV5.js → editManagerCodecsVSharedBranches.js} +7 -7
  327. package/dist/shared-tree-core/editManagerCodecsVSharedBranches.js.map +1 -0
  328. package/dist/shared-tree-core/editManagerFormatCommons.d.ts +20 -6
  329. package/dist/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
  330. package/dist/shared-tree-core/editManagerFormatCommons.js +22 -7
  331. package/dist/shared-tree-core/editManagerFormatCommons.js.map +1 -1
  332. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts +2 -2
  333. package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
  334. package/dist/shared-tree-core/editManagerFormatV1toV4.js +1 -0
  335. package/dist/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
  336. package/dist/shared-tree-core/{editManagerFormatV5.d.ts → editManagerFormatVSharedBranches.d.ts} +3 -3
  337. package/dist/shared-tree-core/editManagerFormatVSharedBranches.d.ts.map +1 -0
  338. package/dist/shared-tree-core/{editManagerFormatV5.js → editManagerFormatVSharedBranches.js} +2 -2
  339. package/dist/shared-tree-core/editManagerFormatVSharedBranches.js.map +1 -0
  340. package/dist/shared-tree-core/editManagerSummarizer.d.ts +29 -9
  341. package/dist/shared-tree-core/editManagerSummarizer.d.ts.map +1 -1
  342. package/dist/shared-tree-core/editManagerSummarizer.js +41 -13
  343. package/dist/shared-tree-core/editManagerSummarizer.js.map +1 -1
  344. package/dist/shared-tree-core/index.d.ts +5 -3
  345. package/dist/shared-tree-core/index.d.ts.map +1 -1
  346. package/dist/shared-tree-core/index.js +8 -1
  347. package/dist/shared-tree-core/index.js.map +1 -1
  348. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts +1 -1
  349. package/dist/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
  350. package/dist/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
  351. package/{lib/shared-tree-core/messageCodecV5.d.ts → dist/shared-tree-core/messageCodecVSharedBranches.d.ts} +2 -2
  352. package/dist/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -0
  353. package/dist/shared-tree-core/{messageCodecV5.js → messageCodecVSharedBranches.js} +6 -6
  354. package/dist/shared-tree-core/messageCodecVSharedBranches.js.map +1 -0
  355. package/dist/shared-tree-core/messageCodecs.d.ts +4 -0
  356. package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
  357. package/dist/shared-tree-core/messageCodecs.js +16 -6
  358. package/dist/shared-tree-core/messageCodecs.js.map +1 -1
  359. package/dist/shared-tree-core/messageFormat.d.ts +20 -6
  360. package/dist/shared-tree-core/messageFormat.d.ts.map +1 -1
  361. package/dist/shared-tree-core/messageFormat.js +22 -7
  362. package/dist/shared-tree-core/messageFormat.js.map +1 -1
  363. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts +3 -2
  364. package/dist/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
  365. package/dist/shared-tree-core/messageFormatV1ToV4.js +8 -1
  366. package/dist/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
  367. package/dist/shared-tree-core/{messageFormatV5.d.ts → messageFormatVSharedBranches.d.ts} +5 -7
  368. package/dist/shared-tree-core/messageFormatVSharedBranches.d.ts.map +1 -0
  369. package/dist/shared-tree-core/{messageFormatV5.js → messageFormatVSharedBranches.js} +3 -2
  370. package/dist/shared-tree-core/messageFormatVSharedBranches.js.map +1 -0
  371. package/dist/shared-tree-core/sharedTreeCore.d.ts +14 -47
  372. package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  373. package/dist/shared-tree-core/sharedTreeCore.js +30 -18
  374. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  375. package/dist/shared-tree-core/summaryTypes.d.ts +94 -0
  376. package/dist/shared-tree-core/summaryTypes.d.ts.map +1 -0
  377. package/dist/shared-tree-core/summaryTypes.js +47 -0
  378. package/dist/shared-tree-core/summaryTypes.js.map +1 -0
  379. package/dist/shared-tree-core/versionedSummarizer.d.ts +67 -0
  380. package/dist/shared-tree-core/versionedSummarizer.d.ts.map +1 -0
  381. package/dist/shared-tree-core/versionedSummarizer.js +63 -0
  382. package/dist/shared-tree-core/versionedSummarizer.js.map +1 -0
  383. package/dist/simple-tree/api/configuration.d.ts +3 -26
  384. package/dist/simple-tree/api/configuration.d.ts.map +1 -1
  385. package/dist/simple-tree/api/configuration.js +10 -21
  386. package/dist/simple-tree/api/configuration.js.map +1 -1
  387. package/dist/simple-tree/api/dirtyIndex.d.ts +11 -0
  388. package/dist/simple-tree/api/dirtyIndex.d.ts.map +1 -1
  389. package/dist/simple-tree/api/dirtyIndex.js +7 -0
  390. package/dist/simple-tree/api/dirtyIndex.js.map +1 -1
  391. package/dist/simple-tree/api/discrepancies.d.ts +1 -1
  392. package/dist/simple-tree/api/discrepancies.d.ts.map +1 -1
  393. package/dist/simple-tree/api/discrepancies.js.map +1 -1
  394. package/dist/simple-tree/api/getSimpleSchema.d.ts +3 -3
  395. package/dist/simple-tree/api/getSimpleSchema.d.ts.map +1 -1
  396. package/dist/simple-tree/api/getSimpleSchema.js +9 -3
  397. package/dist/simple-tree/api/getSimpleSchema.js.map +1 -1
  398. package/dist/simple-tree/api/incrementalAllowedTypes.d.ts +1 -1
  399. package/dist/simple-tree/api/incrementalAllowedTypes.d.ts.map +1 -1
  400. package/dist/simple-tree/api/incrementalAllowedTypes.js +7 -0
  401. package/dist/simple-tree/api/incrementalAllowedTypes.js.map +1 -1
  402. package/dist/simple-tree/api/index.d.ts +3 -4
  403. package/dist/simple-tree/api/index.d.ts.map +1 -1
  404. package/dist/simple-tree/api/index.js +4 -5
  405. package/dist/simple-tree/api/index.js.map +1 -1
  406. package/dist/simple-tree/api/schemaCompatibilityTester.d.ts +1 -1
  407. package/dist/simple-tree/api/schemaCompatibilityTester.d.ts.map +1 -1
  408. package/dist/simple-tree/api/schemaCompatibilityTester.js.map +1 -1
  409. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts +5 -5
  410. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
  411. package/dist/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
  412. package/dist/simple-tree/api/schemaFactoryRecursive.d.ts.map +1 -1
  413. package/dist/simple-tree/api/schemaFactoryRecursive.js +0 -1
  414. package/dist/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
  415. package/dist/simple-tree/api/schemaFromSimple.d.ts +6 -1
  416. package/dist/simple-tree/api/schemaFromSimple.d.ts.map +1 -1
  417. package/dist/simple-tree/api/schemaFromSimple.js +5 -0
  418. package/dist/simple-tree/api/schemaFromSimple.js.map +1 -1
  419. package/dist/simple-tree/api/schemaStatics.d.ts +12 -12
  420. package/dist/simple-tree/api/simpleSchemaCodec.d.ts +15 -3
  421. package/dist/simple-tree/api/simpleSchemaCodec.d.ts.map +1 -1
  422. package/dist/simple-tree/api/simpleSchemaCodec.js +18 -6
  423. package/dist/simple-tree/api/simpleSchemaCodec.js.map +1 -1
  424. package/dist/simple-tree/api/simpleSchemaToJsonSchema.d.ts +1 -1
  425. package/dist/simple-tree/api/simpleSchemaToJsonSchema.d.ts.map +1 -1
  426. package/dist/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
  427. package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts +8 -1
  428. package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts.map +1 -1
  429. package/dist/simple-tree/api/snapshotCompatibilityChecker.js +13 -8
  430. package/dist/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
  431. package/dist/simple-tree/api/typesUnsafe.d.ts +3 -3
  432. package/dist/simple-tree/api/typesUnsafe.d.ts.map +1 -1
  433. package/dist/simple-tree/api/typesUnsafe.js.map +1 -1
  434. package/dist/simple-tree/core/allowedTypes.d.ts +2 -2
  435. package/dist/simple-tree/core/allowedTypes.d.ts.map +1 -1
  436. package/dist/simple-tree/core/allowedTypes.js.map +1 -1
  437. package/dist/simple-tree/core/index.d.ts +1 -1
  438. package/dist/simple-tree/core/index.d.ts.map +1 -1
  439. package/dist/simple-tree/core/index.js +2 -3
  440. package/dist/simple-tree/core/index.js.map +1 -1
  441. package/dist/simple-tree/core/toStored.d.ts +17 -15
  442. package/dist/simple-tree/core/toStored.d.ts.map +1 -1
  443. package/dist/simple-tree/core/toStored.js +5 -40
  444. package/dist/simple-tree/core/toStored.js.map +1 -1
  445. package/dist/simple-tree/core/unhydratedFlexTree.d.ts +15 -15
  446. package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  447. package/dist/simple-tree/core/unhydratedFlexTree.js +59 -8
  448. package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  449. package/dist/simple-tree/core/walkSchema.d.ts.map +1 -1
  450. package/dist/simple-tree/core/walkSchema.js +4 -0
  451. package/dist/simple-tree/core/walkSchema.js.map +1 -1
  452. package/dist/simple-tree/createContext.d.ts.map +1 -1
  453. package/dist/simple-tree/createContext.js +20 -5
  454. package/dist/simple-tree/createContext.js.map +1 -1
  455. package/dist/simple-tree/fieldSchema.d.ts +7 -7
  456. package/dist/simple-tree/fieldSchema.d.ts.map +1 -1
  457. package/dist/simple-tree/fieldSchema.js.map +1 -1
  458. package/dist/simple-tree/index.d.ts +8 -7
  459. package/dist/simple-tree/index.d.ts.map +1 -1
  460. package/dist/simple-tree/index.js +15 -12
  461. package/dist/simple-tree/index.js.map +1 -1
  462. package/dist/simple-tree/leafNodeSchema.d.ts +5 -5
  463. package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
  464. package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  465. package/dist/simple-tree/node-kinds/array/arrayNode.js +5 -3
  466. package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  467. package/dist/simple-tree/node-kinds/array/arrayNodeTypes.d.ts +3 -3
  468. package/dist/simple-tree/node-kinds/array/arrayNodeTypes.d.ts.map +1 -1
  469. package/dist/simple-tree/node-kinds/array/arrayNodeTypes.js.map +1 -1
  470. package/dist/simple-tree/node-kinds/common.d.ts.map +1 -1
  471. package/dist/simple-tree/node-kinds/common.js +1 -1
  472. package/dist/simple-tree/node-kinds/common.js.map +1 -1
  473. package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  474. package/dist/simple-tree/node-kinds/map/mapNode.js +2 -2
  475. package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  476. package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts +3 -3
  477. package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
  478. package/dist/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
  479. package/dist/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  480. package/dist/simple-tree/node-kinds/object/objectNode.js +18 -18
  481. package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  482. package/dist/simple-tree/node-kinds/object/objectNodeTypes.d.ts +2 -2
  483. package/dist/simple-tree/node-kinds/object/objectNodeTypes.d.ts.map +1 -1
  484. package/dist/simple-tree/node-kinds/object/objectNodeTypes.js.map +1 -1
  485. package/dist/simple-tree/node-kinds/record/recordNode.d.ts.map +1 -1
  486. package/dist/simple-tree/node-kinds/record/recordNode.js +4 -2
  487. package/dist/simple-tree/node-kinds/record/recordNode.js.map +1 -1
  488. package/dist/simple-tree/node-kinds/record/recordNodeTypes.d.ts +3 -3
  489. package/dist/simple-tree/node-kinds/record/recordNodeTypes.d.ts.map +1 -1
  490. package/dist/simple-tree/node-kinds/record/recordNodeTypes.js.map +1 -1
  491. package/dist/simple-tree/prepareForInsertion.d.ts +54 -47
  492. package/dist/simple-tree/prepareForInsertion.d.ts.map +1 -1
  493. package/dist/simple-tree/prepareForInsertion.js +183 -125
  494. package/dist/simple-tree/prepareForInsertion.js.map +1 -1
  495. package/dist/simple-tree/simpleSchema.d.ts +55 -23
  496. package/dist/simple-tree/simpleSchema.d.ts.map +1 -1
  497. package/dist/simple-tree/simpleSchema.js +17 -0
  498. package/dist/simple-tree/simpleSchema.js.map +1 -1
  499. package/dist/simple-tree/simpleSchemaFormatV1.d.ts +1 -1
  500. package/dist/simple-tree/simpleSchemaFormatV1.d.ts.map +1 -1
  501. package/dist/simple-tree/simpleSchemaFormatV1.js +8 -1
  502. package/dist/simple-tree/simpleSchemaFormatV1.js.map +1 -1
  503. package/dist/simple-tree/toStoredSchema.d.ts +58 -11
  504. package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
  505. package/dist/simple-tree/toStoredSchema.js +205 -30
  506. package/dist/simple-tree/toStoredSchema.js.map +1 -1
  507. package/dist/simple-tree/treeSchema.d.ts +23 -0
  508. package/dist/simple-tree/treeSchema.d.ts.map +1 -0
  509. package/dist/simple-tree/treeSchema.js +25 -0
  510. package/dist/simple-tree/treeSchema.js.map +1 -0
  511. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts +13 -4
  512. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -1
  513. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js +29 -11
  514. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -1
  515. package/dist/tableSchema.d.ts +117 -63
  516. package/dist/tableSchema.d.ts.map +1 -1
  517. package/dist/tableSchema.js +159 -58
  518. package/dist/tableSchema.js.map +1 -1
  519. package/dist/treeFactory.d.ts.map +1 -1
  520. package/dist/treeFactory.js +17 -3
  521. package/dist/treeFactory.js.map +1 -1
  522. package/dist/util/index.d.ts +2 -1
  523. package/dist/util/index.d.ts.map +1 -1
  524. package/dist/util/index.js +4 -1
  525. package/dist/util/index.js.map +1 -1
  526. package/dist/util/rangeMap.d.ts +24 -12
  527. package/dist/util/rangeMap.d.ts.map +1 -1
  528. package/dist/util/rangeMap.js +46 -6
  529. package/dist/util/rangeMap.js.map +1 -1
  530. package/dist/util/readSnapshotBlob.d.ts +13 -0
  531. package/dist/util/readSnapshotBlob.d.ts.map +1 -0
  532. package/dist/util/readSnapshotBlob.js +18 -0
  533. package/dist/util/readSnapshotBlob.js.map +1 -0
  534. package/lib/alpha.d.ts +3 -2
  535. package/lib/codec/codec.d.ts +14 -1
  536. package/lib/codec/codec.d.ts.map +1 -1
  537. package/lib/codec/codec.js +11 -0
  538. package/lib/codec/codec.js.map +1 -1
  539. package/lib/codec/versioned/codec.d.ts +1 -1
  540. package/lib/codec/versioned/codec.d.ts.map +1 -1
  541. package/lib/codec/versioned/codec.js.map +1 -1
  542. package/lib/codec/versioned/format.d.ts +4 -1
  543. package/lib/codec/versioned/format.d.ts.map +1 -1
  544. package/lib/codec/versioned/format.js +4 -1
  545. package/lib/codec/versioned/format.js.map +1 -1
  546. package/lib/core/change-family/changeFamily.d.ts +4 -1
  547. package/lib/core/change-family/changeFamily.d.ts.map +1 -1
  548. package/lib/core/change-family/changeFamily.js.map +1 -1
  549. package/lib/core/change-family/index.d.ts +1 -1
  550. package/lib/core/change-family/index.d.ts.map +1 -1
  551. package/lib/core/change-family/index.js.map +1 -1
  552. package/lib/core/index.d.ts +3 -3
  553. package/lib/core/index.d.ts.map +1 -1
  554. package/lib/core/index.js +2 -2
  555. package/lib/core/index.js.map +1 -1
  556. package/lib/core/rebase/changeRebaser.d.ts +6 -1
  557. package/lib/core/rebase/changeRebaser.d.ts.map +1 -1
  558. package/lib/core/rebase/changeRebaser.js.map +1 -1
  559. package/lib/core/rebase/index.d.ts +1 -1
  560. package/lib/core/rebase/index.d.ts.map +1 -1
  561. package/lib/core/rebase/index.js +1 -1
  562. package/lib/core/rebase/index.js.map +1 -1
  563. package/lib/core/rebase/types.d.ts +2 -1
  564. package/lib/core/rebase/types.d.ts.map +1 -1
  565. package/lib/core/rebase/types.js +3 -0
  566. package/lib/core/rebase/types.js.map +1 -1
  567. package/lib/core/rebase/utils.d.ts.map +1 -1
  568. package/lib/core/rebase/utils.js +25 -7
  569. package/lib/core/rebase/utils.js.map +1 -1
  570. package/lib/core/tree/detachedFieldIndex.d.ts +40 -13
  571. package/lib/core/tree/detachedFieldIndex.d.ts.map +1 -1
  572. package/lib/core/tree/detachedFieldIndex.js +22 -13
  573. package/lib/core/tree/detachedFieldIndex.js.map +1 -1
  574. package/lib/core/tree/index.d.ts +4 -3
  575. package/lib/core/tree/index.d.ts.map +1 -1
  576. package/lib/core/tree/index.js +3 -2
  577. package/lib/core/tree/index.js.map +1 -1
  578. package/lib/core/tree/pathTree.d.ts +11 -3
  579. package/lib/core/tree/pathTree.d.ts.map +1 -1
  580. package/lib/core/tree/pathTree.js +12 -1
  581. package/lib/core/tree/pathTree.js.map +1 -1
  582. package/lib/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
  583. package/lib/feature-libraries/chunked-forest/basicChunk.js +8 -1
  584. package/lib/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
  585. package/lib/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
  586. package/lib/feature-libraries/chunked-forest/chunkTree.js +4 -1
  587. package/lib/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
  588. package/lib/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.d.ts +14 -6
  589. package/lib/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.d.ts.map +1 -1
  590. package/lib/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.js.map +1 -1
  591. package/lib/feature-libraries/chunked-forest/codec/schemaBasedEncode.js +7 -2
  592. package/lib/feature-libraries/chunked-forest/codec/schemaBasedEncode.js.map +1 -1
  593. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts +90 -42
  594. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  595. package/lib/feature-libraries/default-schema/defaultEditBuilder.js +232 -69
  596. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  597. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts +4 -4
  598. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  599. package/lib/feature-libraries/default-schema/defaultFieldKinds.js +34 -29
  600. package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  601. package/lib/feature-libraries/default-schema/index.d.ts +2 -1
  602. package/lib/feature-libraries/default-schema/index.d.ts.map +1 -1
  603. package/lib/feature-libraries/default-schema/index.js +2 -1
  604. package/lib/feature-libraries/default-schema/index.js.map +1 -1
  605. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.d.ts +36 -0
  606. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.d.ts.map +1 -0
  607. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.js +122 -0
  608. package/lib/feature-libraries/default-schema/locationBasedEditBuilder.js.map +1 -0
  609. package/lib/feature-libraries/default-schema/mappedEditBuilder.d.ts +7 -6
  610. package/lib/feature-libraries/default-schema/mappedEditBuilder.d.ts.map +1 -1
  611. package/lib/feature-libraries/default-schema/mappedEditBuilder.js +15 -0
  612. package/lib/feature-libraries/default-schema/mappedEditBuilder.js.map +1 -1
  613. package/lib/feature-libraries/deltaUtils.d.ts +1 -0
  614. package/lib/feature-libraries/deltaUtils.d.ts.map +1 -1
  615. package/lib/feature-libraries/deltaUtils.js +5 -1
  616. package/lib/feature-libraries/deltaUtils.js.map +1 -1
  617. package/lib/feature-libraries/detachedFieldIndexSummarizer.d.ts +30 -8
  618. package/lib/feature-libraries/detachedFieldIndexSummarizer.d.ts.map +1 -1
  619. package/lib/feature-libraries/detachedFieldIndexSummarizer.js +38 -8
  620. package/lib/feature-libraries/detachedFieldIndexSummarizer.js.map +1 -1
  621. package/lib/feature-libraries/flex-tree/context.d.ts +9 -0
  622. package/lib/feature-libraries/flex-tree/context.d.ts.map +1 -1
  623. package/lib/feature-libraries/flex-tree/context.js +6 -0
  624. package/lib/feature-libraries/flex-tree/context.js.map +1 -1
  625. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +6 -6
  626. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  627. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  628. package/lib/feature-libraries/flex-tree/lazyField.d.ts +8 -7
  629. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  630. package/lib/feature-libraries/flex-tree/lazyField.js +38 -9
  631. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  632. package/lib/feature-libraries/forest-summary/codec.d.ts +2 -2
  633. package/lib/feature-libraries/forest-summary/codec.d.ts.map +1 -1
  634. package/lib/feature-libraries/forest-summary/codec.js +5 -5
  635. package/lib/feature-libraries/forest-summary/codec.js.map +1 -1
  636. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts +9 -13
  637. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  638. package/lib/feature-libraries/forest-summary/forestSummarizer.js +17 -22
  639. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  640. package/lib/feature-libraries/forest-summary/format.d.ts +41 -5
  641. package/lib/feature-libraries/forest-summary/format.d.ts.map +1 -1
  642. package/lib/feature-libraries/forest-summary/format.js +3 -3
  643. package/lib/feature-libraries/forest-summary/format.js.map +1 -1
  644. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts +11 -9
  645. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.d.ts.map +1 -1
  646. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.js +13 -26
  647. package/lib/feature-libraries/forest-summary/incrementalSummaryBuilder.js.map +1 -1
  648. package/lib/feature-libraries/forest-summary/index.d.ts +2 -1
  649. package/lib/feature-libraries/forest-summary/index.d.ts.map +1 -1
  650. package/lib/feature-libraries/forest-summary/index.js +2 -1
  651. package/lib/feature-libraries/forest-summary/index.js.map +1 -1
  652. package/lib/feature-libraries/forest-summary/summaryTypes.d.ts +47 -0
  653. package/lib/feature-libraries/forest-summary/summaryTypes.d.ts.map +1 -0
  654. package/lib/feature-libraries/forest-summary/summaryTypes.js +53 -0
  655. package/lib/feature-libraries/forest-summary/summaryTypes.js.map +1 -0
  656. package/lib/feature-libraries/index.d.ts +4 -4
  657. package/lib/feature-libraries/index.d.ts.map +1 -1
  658. package/lib/feature-libraries/index.js +3 -3
  659. package/lib/feature-libraries/index.js.map +1 -1
  660. package/lib/feature-libraries/mapTreeCursor.d.ts.map +1 -1
  661. package/lib/feature-libraries/mapTreeCursor.js +2 -1
  662. package/lib/feature-libraries/mapTreeCursor.js.map +1 -1
  663. package/lib/feature-libraries/mitigatedChangeFamily.d.ts.map +1 -1
  664. package/lib/feature-libraries/mitigatedChangeFamily.js +2 -2
  665. package/lib/feature-libraries/mitigatedChangeFamily.js.map +1 -1
  666. package/lib/feature-libraries/modular-schema/comparison.d.ts +18 -2
  667. package/lib/feature-libraries/modular-schema/comparison.d.ts.map +1 -1
  668. package/lib/feature-libraries/modular-schema/comparison.js +55 -5
  669. package/lib/feature-libraries/modular-schema/comparison.js.map +1 -1
  670. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +97 -21
  671. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  672. package/lib/feature-libraries/modular-schema/crossFieldQueries.js +3 -5
  673. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  674. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +20 -52
  675. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  676. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  677. package/lib/feature-libraries/modular-schema/fieldKind.d.ts +25 -13
  678. package/lib/feature-libraries/modular-schema/fieldKind.d.ts.map +1 -1
  679. package/lib/feature-libraries/modular-schema/fieldKind.js +0 -21
  680. package/lib/feature-libraries/modular-schema/fieldKind.js.map +1 -1
  681. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  682. package/lib/feature-libraries/modular-schema/genericFieldKind.js +7 -10
  683. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  684. package/lib/feature-libraries/modular-schema/genericFieldKindCodecs.js +1 -1
  685. package/lib/feature-libraries/modular-schema/genericFieldKindCodecs.js.map +1 -1
  686. package/lib/feature-libraries/modular-schema/index.d.ts +5 -5
  687. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  688. package/lib/feature-libraries/modular-schema/index.js +4 -3
  689. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  690. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.d.ts +17 -0
  691. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.d.ts.map +1 -0
  692. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.js +384 -0
  693. package/lib/feature-libraries/modular-schema/modularChangeCodecV1.js.map +1 -0
  694. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.d.ts +17 -0
  695. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.d.ts.map +1 -0
  696. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.js +409 -0
  697. package/lib/feature-libraries/modular-schema/modularChangeCodecV2.js.map +1 -0
  698. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts +2 -2
  699. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  700. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +9 -285
  701. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  702. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +48 -15
  703. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  704. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +1284 -458
  705. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  706. package/lib/feature-libraries/modular-schema/{modularChangeFormat.d.ts → modularChangeFormatV1.d.ts} +2 -2
  707. package/lib/feature-libraries/modular-schema/modularChangeFormatV1.d.ts.map +1 -0
  708. package/lib/feature-libraries/modular-schema/{modularChangeFormat.js → modularChangeFormatV1.js} +2 -2
  709. package/lib/feature-libraries/modular-schema/modularChangeFormatV1.js.map +1 -0
  710. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.d.ts +146 -0
  711. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.d.ts.map +1 -0
  712. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.js +29 -0
  713. package/lib/feature-libraries/modular-schema/modularChangeFormatV2.js.map +1 -0
  714. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +50 -10
  715. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  716. package/lib/feature-libraries/modular-schema/modularChangeTypes.js +20 -2
  717. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  718. package/lib/feature-libraries/optional-field/index.d.ts +2 -2
  719. package/lib/feature-libraries/optional-field/index.d.ts.map +1 -1
  720. package/lib/feature-libraries/optional-field/index.js +1 -1
  721. package/lib/feature-libraries/optional-field/index.js.map +1 -1
  722. package/lib/feature-libraries/optional-field/optionalField.d.ts +5 -26
  723. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  724. package/lib/feature-libraries/optional-field/optionalField.js +217 -449
  725. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  726. package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts +24 -33
  727. package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts.map +1 -1
  728. package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.js.map +1 -1
  729. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.d.ts +1 -1
  730. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.d.ts.map +1 -1
  731. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.js +55 -26
  732. package/lib/feature-libraries/optional-field/optionalFieldCodecV2.js.map +1 -1
  733. package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts +27 -8
  734. package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
  735. package/lib/feature-libraries/schema-index/schemaSummarizer.js +38 -12
  736. package/lib/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
  737. package/lib/feature-libraries/sequence-field/compose.d.ts +6 -7
  738. package/lib/feature-libraries/sequence-field/compose.d.ts.map +1 -1
  739. package/lib/feature-libraries/sequence-field/compose.js +82 -258
  740. package/lib/feature-libraries/sequence-field/compose.js.map +1 -1
  741. package/lib/feature-libraries/sequence-field/helperTypes.d.ts +14 -10
  742. package/lib/feature-libraries/sequence-field/helperTypes.d.ts.map +1 -1
  743. package/lib/feature-libraries/sequence-field/helperTypes.js.map +1 -1
  744. package/lib/feature-libraries/sequence-field/index.d.ts +2 -3
  745. package/lib/feature-libraries/sequence-field/index.d.ts.map +1 -1
  746. package/lib/feature-libraries/sequence-field/index.js +0 -1
  747. package/lib/feature-libraries/sequence-field/index.js.map +1 -1
  748. package/lib/feature-libraries/sequence-field/invert.d.ts +3 -3
  749. package/lib/feature-libraries/sequence-field/invert.d.ts.map +1 -1
  750. package/lib/feature-libraries/sequence-field/invert.js +67 -169
  751. package/lib/feature-libraries/sequence-field/invert.js.map +1 -1
  752. package/lib/feature-libraries/sequence-field/markQueue.d.ts +2 -2
  753. package/lib/feature-libraries/sequence-field/markQueue.d.ts.map +1 -1
  754. package/lib/feature-libraries/sequence-field/markQueue.js.map +1 -1
  755. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts +4 -56
  756. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  757. package/lib/feature-libraries/sequence-field/moveEffectTable.js +6 -80
  758. package/lib/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  759. package/lib/feature-libraries/sequence-field/rebase.d.ts +3 -3
  760. package/lib/feature-libraries/sequence-field/rebase.d.ts.map +1 -1
  761. package/lib/feature-libraries/sequence-field/rebase.js +108 -114
  762. package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
  763. package/lib/feature-libraries/sequence-field/replaceRevisions.d.ts.map +1 -1
  764. package/lib/feature-libraries/sequence-field/replaceRevisions.js +16 -33
  765. package/lib/feature-libraries/sequence-field/replaceRevisions.js.map +1 -1
  766. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  767. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +0 -2
  768. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  769. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +22 -4
  770. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
  771. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js +350 -175
  772. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  773. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
  774. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js +21 -61
  775. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
  776. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.d.ts +2 -2
  777. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.d.ts.map +1 -1
  778. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.js +10 -10
  779. package/lib/feature-libraries/sequence-field/sequenceFieldEditor.js.map +1 -1
  780. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +3 -2
  781. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  782. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js +14 -109
  783. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  784. package/lib/feature-libraries/sequence-field/types.d.ts +30 -59
  785. package/lib/feature-libraries/sequence-field/types.d.ts.map +1 -1
  786. package/lib/feature-libraries/sequence-field/types.js.map +1 -1
  787. package/lib/feature-libraries/sequence-field/utils.d.ts +15 -24
  788. package/lib/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  789. package/lib/feature-libraries/sequence-field/utils.js +107 -292
  790. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  791. package/lib/index.d.ts +1 -1
  792. package/lib/index.d.ts.map +1 -1
  793. package/lib/index.js +1 -1
  794. package/lib/index.js.map +1 -1
  795. package/lib/packageVersion.d.ts +1 -1
  796. package/lib/packageVersion.js +1 -1
  797. package/lib/packageVersion.js.map +1 -1
  798. package/lib/shared-tree/independentView.d.ts +1 -1
  799. package/lib/shared-tree/independentView.d.ts.map +1 -1
  800. package/lib/shared-tree/independentView.js.map +1 -1
  801. package/lib/shared-tree/index.d.ts +1 -1
  802. package/lib/shared-tree/index.d.ts.map +1 -1
  803. package/lib/shared-tree/index.js.map +1 -1
  804. package/lib/shared-tree/schematizeTree.d.ts +4 -4
  805. package/lib/shared-tree/schematizeTree.d.ts.map +1 -1
  806. package/lib/shared-tree/schematizeTree.js +3 -2
  807. package/lib/shared-tree/schematizeTree.js.map +1 -1
  808. package/lib/shared-tree/schematizingTreeView.d.ts +1 -5
  809. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  810. package/lib/shared-tree/schematizingTreeView.js +35 -36
  811. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  812. package/lib/shared-tree/sharedTree.d.ts +11 -5
  813. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  814. package/lib/shared-tree/sharedTree.js +14 -4
  815. package/lib/shared-tree/sharedTree.js.map +1 -1
  816. package/lib/shared-tree/sharedTreeChangeCodecs.d.ts +1 -1
  817. package/lib/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
  818. package/lib/shared-tree/sharedTreeChangeCodecs.js +1 -0
  819. package/lib/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
  820. package/lib/shared-tree/sharedTreeChangeEnricher.d.ts +20 -8
  821. package/lib/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
  822. package/lib/shared-tree/sharedTreeChangeEnricher.js +25 -11
  823. package/lib/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
  824. package/lib/shared-tree/sharedTreeChangeFamily.d.ts +4 -4
  825. package/lib/shared-tree/sharedTreeChangeFamily.d.ts.map +1 -1
  826. package/lib/shared-tree/sharedTreeChangeFamily.js +3 -3
  827. package/lib/shared-tree/sharedTreeChangeFamily.js.map +1 -1
  828. package/lib/shared-tree/sharedTreeEditBuilder.d.ts +16 -6
  829. package/lib/shared-tree/sharedTreeEditBuilder.d.ts.map +1 -1
  830. package/lib/shared-tree/sharedTreeEditBuilder.js +11 -5
  831. package/lib/shared-tree/sharedTreeEditBuilder.js.map +1 -1
  832. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  833. package/lib/shared-tree/treeAlpha.js +2 -2
  834. package/lib/shared-tree/treeAlpha.js.map +1 -1
  835. package/lib/shared-tree/treeCheckout.d.ts +12 -10
  836. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  837. package/lib/shared-tree/treeCheckout.js +69 -20
  838. package/lib/shared-tree/treeCheckout.js.map +1 -1
  839. package/lib/shared-tree-core/branch.d.ts +3 -2
  840. package/lib/shared-tree-core/branch.d.ts.map +1 -1
  841. package/lib/shared-tree-core/branch.js +4 -3
  842. package/lib/shared-tree-core/branch.js.map +1 -1
  843. package/lib/shared-tree-core/editManager.d.ts +2 -2
  844. package/lib/shared-tree-core/editManager.d.ts.map +1 -1
  845. package/lib/shared-tree-core/editManager.js +9 -9
  846. package/lib/shared-tree-core/editManager.js.map +1 -1
  847. package/lib/shared-tree-core/editManagerCodecs.d.ts +4 -0
  848. package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
  849. package/lib/shared-tree-core/editManagerCodecs.js +14 -5
  850. package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
  851. package/{dist/shared-tree-core/editManagerCodecsV5.d.ts → lib/shared-tree-core/editManagerCodecsVSharedBranches.d.ts} +3 -3
  852. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.d.ts.map +1 -0
  853. package/lib/shared-tree-core/{editManagerCodecsV5.js → editManagerCodecsVSharedBranches.js} +4 -4
  854. package/lib/shared-tree-core/editManagerCodecsVSharedBranches.js.map +1 -0
  855. package/lib/shared-tree-core/editManagerFormatCommons.d.ts +20 -6
  856. package/lib/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
  857. package/lib/shared-tree-core/editManagerFormatCommons.js +22 -7
  858. package/lib/shared-tree-core/editManagerFormatCommons.js.map +1 -1
  859. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts +2 -2
  860. package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
  861. package/lib/shared-tree-core/editManagerFormatV1toV4.js +1 -0
  862. package/lib/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
  863. package/lib/shared-tree-core/{editManagerFormatV5.d.ts → editManagerFormatVSharedBranches.d.ts} +3 -3
  864. package/lib/shared-tree-core/editManagerFormatVSharedBranches.d.ts.map +1 -0
  865. package/lib/shared-tree-core/{editManagerFormatV5.js → editManagerFormatVSharedBranches.js} +2 -2
  866. package/lib/shared-tree-core/editManagerFormatVSharedBranches.js.map +1 -0
  867. package/lib/shared-tree-core/editManagerSummarizer.d.ts +29 -9
  868. package/lib/shared-tree-core/editManagerSummarizer.d.ts.map +1 -1
  869. package/lib/shared-tree-core/editManagerSummarizer.js +39 -11
  870. package/lib/shared-tree-core/editManagerSummarizer.js.map +1 -1
  871. package/lib/shared-tree-core/index.d.ts +5 -3
  872. package/lib/shared-tree-core/index.d.ts.map +1 -1
  873. package/lib/shared-tree-core/index.js +4 -2
  874. package/lib/shared-tree-core/index.js.map +1 -1
  875. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts +1 -1
  876. package/lib/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
  877. package/lib/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
  878. package/{dist/shared-tree-core/messageCodecV5.d.ts → lib/shared-tree-core/messageCodecVSharedBranches.d.ts} +2 -2
  879. package/lib/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -0
  880. package/lib/shared-tree-core/{messageCodecV5.js → messageCodecVSharedBranches.js} +3 -3
  881. package/lib/shared-tree-core/messageCodecVSharedBranches.js.map +1 -0
  882. package/lib/shared-tree-core/messageCodecs.d.ts +4 -0
  883. package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
  884. package/lib/shared-tree-core/messageCodecs.js +14 -5
  885. package/lib/shared-tree-core/messageCodecs.js.map +1 -1
  886. package/lib/shared-tree-core/messageFormat.d.ts +20 -6
  887. package/lib/shared-tree-core/messageFormat.d.ts.map +1 -1
  888. package/lib/shared-tree-core/messageFormat.js +22 -7
  889. package/lib/shared-tree-core/messageFormat.js.map +1 -1
  890. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts +3 -2
  891. package/lib/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
  892. package/lib/shared-tree-core/messageFormatV1ToV4.js +8 -1
  893. package/lib/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
  894. package/lib/shared-tree-core/{messageFormatV5.d.ts → messageFormatVSharedBranches.d.ts} +5 -7
  895. package/lib/shared-tree-core/messageFormatVSharedBranches.d.ts.map +1 -0
  896. package/lib/shared-tree-core/{messageFormatV5.js → messageFormatVSharedBranches.js} +3 -2
  897. package/lib/shared-tree-core/messageFormatVSharedBranches.js.map +1 -0
  898. package/lib/shared-tree-core/sharedTreeCore.d.ts +14 -47
  899. package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  900. package/lib/shared-tree-core/sharedTreeCore.js +28 -16
  901. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  902. package/lib/shared-tree-core/summaryTypes.d.ts +94 -0
  903. package/lib/shared-tree-core/summaryTypes.d.ts.map +1 -0
  904. package/lib/shared-tree-core/summaryTypes.js +43 -0
  905. package/lib/shared-tree-core/summaryTypes.js.map +1 -0
  906. package/lib/shared-tree-core/versionedSummarizer.d.ts +67 -0
  907. package/lib/shared-tree-core/versionedSummarizer.d.ts.map +1 -0
  908. package/lib/shared-tree-core/versionedSummarizer.js +59 -0
  909. package/lib/shared-tree-core/versionedSummarizer.js.map +1 -0
  910. package/lib/simple-tree/api/configuration.d.ts +3 -26
  911. package/lib/simple-tree/api/configuration.d.ts.map +1 -1
  912. package/lib/simple-tree/api/configuration.js +14 -25
  913. package/lib/simple-tree/api/configuration.js.map +1 -1
  914. package/lib/simple-tree/api/dirtyIndex.d.ts +11 -0
  915. package/lib/simple-tree/api/dirtyIndex.d.ts.map +1 -1
  916. package/lib/simple-tree/api/dirtyIndex.js +7 -0
  917. package/lib/simple-tree/api/dirtyIndex.js.map +1 -1
  918. package/lib/simple-tree/api/discrepancies.d.ts +1 -1
  919. package/lib/simple-tree/api/discrepancies.d.ts.map +1 -1
  920. package/lib/simple-tree/api/discrepancies.js.map +1 -1
  921. package/lib/simple-tree/api/getSimpleSchema.d.ts +3 -3
  922. package/lib/simple-tree/api/getSimpleSchema.d.ts.map +1 -1
  923. package/lib/simple-tree/api/getSimpleSchema.js +9 -3
  924. package/lib/simple-tree/api/getSimpleSchema.js.map +1 -1
  925. package/lib/simple-tree/api/incrementalAllowedTypes.d.ts +1 -1
  926. package/lib/simple-tree/api/incrementalAllowedTypes.d.ts.map +1 -1
  927. package/lib/simple-tree/api/incrementalAllowedTypes.js +8 -1
  928. package/lib/simple-tree/api/incrementalAllowedTypes.js.map +1 -1
  929. package/lib/simple-tree/api/index.d.ts +3 -4
  930. package/lib/simple-tree/api/index.d.ts.map +1 -1
  931. package/lib/simple-tree/api/index.js +2 -3
  932. package/lib/simple-tree/api/index.js.map +1 -1
  933. package/lib/simple-tree/api/schemaCompatibilityTester.d.ts +1 -1
  934. package/lib/simple-tree/api/schemaCompatibilityTester.d.ts.map +1 -1
  935. package/lib/simple-tree/api/schemaCompatibilityTester.js.map +1 -1
  936. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts +5 -5
  937. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
  938. package/lib/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
  939. package/lib/simple-tree/api/schemaFactoryRecursive.d.ts.map +1 -1
  940. package/lib/simple-tree/api/schemaFactoryRecursive.js +0 -1
  941. package/lib/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
  942. package/lib/simple-tree/api/schemaFromSimple.d.ts +6 -1
  943. package/lib/simple-tree/api/schemaFromSimple.d.ts.map +1 -1
  944. package/lib/simple-tree/api/schemaFromSimple.js +5 -0
  945. package/lib/simple-tree/api/schemaFromSimple.js.map +1 -1
  946. package/lib/simple-tree/api/schemaStatics.d.ts +12 -12
  947. package/lib/simple-tree/api/simpleSchemaCodec.d.ts +15 -3
  948. package/lib/simple-tree/api/simpleSchemaCodec.d.ts.map +1 -1
  949. package/lib/simple-tree/api/simpleSchemaCodec.js +15 -3
  950. package/lib/simple-tree/api/simpleSchemaCodec.js.map +1 -1
  951. package/lib/simple-tree/api/simpleSchemaToJsonSchema.d.ts +1 -1
  952. package/lib/simple-tree/api/simpleSchemaToJsonSchema.d.ts.map +1 -1
  953. package/lib/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
  954. package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts +8 -1
  955. package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts.map +1 -1
  956. package/lib/simple-tree/api/snapshotCompatibilityChecker.js +15 -10
  957. package/lib/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
  958. package/lib/simple-tree/api/typesUnsafe.d.ts +3 -3
  959. package/lib/simple-tree/api/typesUnsafe.d.ts.map +1 -1
  960. package/lib/simple-tree/api/typesUnsafe.js.map +1 -1
  961. package/lib/simple-tree/core/allowedTypes.d.ts +2 -2
  962. package/lib/simple-tree/core/allowedTypes.d.ts.map +1 -1
  963. package/lib/simple-tree/core/allowedTypes.js.map +1 -1
  964. package/lib/simple-tree/core/index.d.ts +1 -1
  965. package/lib/simple-tree/core/index.d.ts.map +1 -1
  966. package/lib/simple-tree/core/index.js +1 -1
  967. package/lib/simple-tree/core/index.js.map +1 -1
  968. package/lib/simple-tree/core/toStored.d.ts +17 -15
  969. package/lib/simple-tree/core/toStored.d.ts.map +1 -1
  970. package/lib/simple-tree/core/toStored.js +4 -37
  971. package/lib/simple-tree/core/toStored.js.map +1 -1
  972. package/lib/simple-tree/core/unhydratedFlexTree.d.ts +15 -15
  973. package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  974. package/lib/simple-tree/core/unhydratedFlexTree.js +58 -8
  975. package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  976. package/lib/simple-tree/core/walkSchema.d.ts.map +1 -1
  977. package/lib/simple-tree/core/walkSchema.js +5 -1
  978. package/lib/simple-tree/core/walkSchema.js.map +1 -1
  979. package/lib/simple-tree/createContext.d.ts.map +1 -1
  980. package/lib/simple-tree/createContext.js +20 -5
  981. package/lib/simple-tree/createContext.js.map +1 -1
  982. package/lib/simple-tree/fieldSchema.d.ts +7 -7
  983. package/lib/simple-tree/fieldSchema.d.ts.map +1 -1
  984. package/lib/simple-tree/fieldSchema.js.map +1 -1
  985. package/lib/simple-tree/index.d.ts +8 -7
  986. package/lib/simple-tree/index.d.ts.map +1 -1
  987. package/lib/simple-tree/index.js +6 -5
  988. package/lib/simple-tree/index.js.map +1 -1
  989. package/lib/simple-tree/leafNodeSchema.d.ts +5 -5
  990. package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
  991. package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  992. package/lib/simple-tree/node-kinds/array/arrayNode.js +6 -4
  993. package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  994. package/lib/simple-tree/node-kinds/array/arrayNodeTypes.d.ts +3 -3
  995. package/lib/simple-tree/node-kinds/array/arrayNodeTypes.d.ts.map +1 -1
  996. package/lib/simple-tree/node-kinds/array/arrayNodeTypes.js.map +1 -1
  997. package/lib/simple-tree/node-kinds/common.d.ts.map +1 -1
  998. package/lib/simple-tree/node-kinds/common.js +2 -2
  999. package/lib/simple-tree/node-kinds/common.js.map +1 -1
  1000. package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  1001. package/lib/simple-tree/node-kinds/map/mapNode.js +2 -2
  1002. package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  1003. package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts +3 -3
  1004. package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
  1005. package/lib/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
  1006. package/lib/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  1007. package/lib/simple-tree/node-kinds/object/objectNode.js +19 -19
  1008. package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  1009. package/lib/simple-tree/node-kinds/object/objectNodeTypes.d.ts +2 -2
  1010. package/lib/simple-tree/node-kinds/object/objectNodeTypes.d.ts.map +1 -1
  1011. package/lib/simple-tree/node-kinds/object/objectNodeTypes.js.map +1 -1
  1012. package/lib/simple-tree/node-kinds/record/recordNode.d.ts.map +1 -1
  1013. package/lib/simple-tree/node-kinds/record/recordNode.js +4 -2
  1014. package/lib/simple-tree/node-kinds/record/recordNode.js.map +1 -1
  1015. package/lib/simple-tree/node-kinds/record/recordNodeTypes.d.ts +3 -3
  1016. package/lib/simple-tree/node-kinds/record/recordNodeTypes.d.ts.map +1 -1
  1017. package/lib/simple-tree/node-kinds/record/recordNodeTypes.js.map +1 -1
  1018. package/lib/simple-tree/prepareForInsertion.d.ts +54 -47
  1019. package/lib/simple-tree/prepareForInsertion.d.ts.map +1 -1
  1020. package/lib/simple-tree/prepareForInsertion.js +183 -124
  1021. package/lib/simple-tree/prepareForInsertion.js.map +1 -1
  1022. package/lib/simple-tree/simpleSchema.d.ts +55 -23
  1023. package/lib/simple-tree/simpleSchema.d.ts.map +1 -1
  1024. package/lib/simple-tree/simpleSchema.js +16 -1
  1025. package/lib/simple-tree/simpleSchema.js.map +1 -1
  1026. package/lib/simple-tree/simpleSchemaFormatV1.d.ts +1 -1
  1027. package/lib/simple-tree/simpleSchemaFormatV1.d.ts.map +1 -1
  1028. package/lib/simple-tree/simpleSchemaFormatV1.js +8 -1
  1029. package/lib/simple-tree/simpleSchemaFormatV1.js.map +1 -1
  1030. package/lib/simple-tree/toStoredSchema.d.ts +58 -11
  1031. package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
  1032. package/lib/simple-tree/toStoredSchema.js +204 -31
  1033. package/lib/simple-tree/toStoredSchema.js.map +1 -1
  1034. package/lib/simple-tree/treeSchema.d.ts +23 -0
  1035. package/lib/simple-tree/treeSchema.d.ts.map +1 -0
  1036. package/lib/simple-tree/treeSchema.js +21 -0
  1037. package/lib/simple-tree/treeSchema.js.map +1 -0
  1038. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts +13 -4
  1039. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -1
  1040. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js +26 -9
  1041. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -1
  1042. package/lib/tableSchema.d.ts +117 -63
  1043. package/lib/tableSchema.d.ts.map +1 -1
  1044. package/lib/tableSchema.js +160 -59
  1045. package/lib/tableSchema.js.map +1 -1
  1046. package/lib/treeFactory.d.ts.map +1 -1
  1047. package/lib/treeFactory.js +18 -4
  1048. package/lib/treeFactory.js.map +1 -1
  1049. package/lib/util/index.d.ts +2 -1
  1050. package/lib/util/index.d.ts.map +1 -1
  1051. package/lib/util/index.js +2 -1
  1052. package/lib/util/index.js.map +1 -1
  1053. package/lib/util/rangeMap.d.ts +24 -12
  1054. package/lib/util/rangeMap.d.ts.map +1 -1
  1055. package/lib/util/rangeMap.js +44 -5
  1056. package/lib/util/rangeMap.js.map +1 -1
  1057. package/lib/util/readSnapshotBlob.d.ts +13 -0
  1058. package/lib/util/readSnapshotBlob.d.ts.map +1 -0
  1059. package/lib/util/readSnapshotBlob.js +14 -0
  1060. package/lib/util/readSnapshotBlob.js.map +1 -0
  1061. package/package.json +21 -21
  1062. package/src/codec/codec.ts +15 -1
  1063. package/src/codec/versioned/codec.ts +1 -1
  1064. package/src/codec/versioned/format.ts +4 -1
  1065. package/src/core/change-family/changeFamily.ts +5 -0
  1066. package/src/core/change-family/index.ts +1 -0
  1067. package/src/core/index.ts +7 -2
  1068. package/src/core/rebase/changeRebaser.ts +6 -1
  1069. package/src/core/rebase/index.ts +1 -0
  1070. package/src/core/rebase/types.ts +8 -1
  1071. package/src/core/rebase/utils.ts +31 -7
  1072. package/src/core/tree/detachedFieldIndex.ts +71 -14
  1073. package/src/core/tree/index.ts +9 -3
  1074. package/src/core/tree/pathTree.ts +16 -4
  1075. package/src/feature-libraries/chunked-forest/basicChunk.ts +7 -1
  1076. package/src/feature-libraries/chunked-forest/chunkTree.ts +6 -1
  1077. package/src/feature-libraries/chunked-forest/codec/incrementalEncodingPolicy.ts +15 -7
  1078. package/src/feature-libraries/chunked-forest/codec/schemaBasedEncode.ts +9 -9
  1079. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +393 -127
  1080. package/src/feature-libraries/default-schema/defaultFieldKinds.ts +35 -38
  1081. package/src/feature-libraries/default-schema/index.ts +16 -5
  1082. package/src/feature-libraries/default-schema/locationBasedEditBuilder.ts +180 -0
  1083. package/src/feature-libraries/default-schema/mappedEditBuilder.ts +35 -9
  1084. package/src/feature-libraries/deltaUtils.ts +6 -1
  1085. package/src/feature-libraries/detachedFieldIndexSummarizer.ts +62 -15
  1086. package/src/feature-libraries/flex-tree/context.ts +17 -0
  1087. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +7 -8
  1088. package/src/feature-libraries/flex-tree/lazyField.ts +66 -24
  1089. package/src/feature-libraries/forest-summary/codec.ts +8 -8
  1090. package/src/feature-libraries/forest-summary/forestSummarizer.ts +45 -37
  1091. package/src/feature-libraries/forest-summary/format.ts +4 -4
  1092. package/src/feature-libraries/forest-summary/incrementalSummaryBuilder.ts +23 -39
  1093. package/src/feature-libraries/forest-summary/index.ts +2 -1
  1094. package/src/feature-libraries/forest-summary/summaryTypes.ts +61 -0
  1095. package/src/feature-libraries/index.ts +22 -9
  1096. package/src/feature-libraries/mapTreeCursor.ts +2 -1
  1097. package/src/feature-libraries/mitigatedChangeFamily.ts +3 -1
  1098. package/src/feature-libraries/modular-schema/comparison.ts +63 -5
  1099. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +142 -44
  1100. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +36 -57
  1101. package/src/feature-libraries/modular-schema/fieldKind.ts +24 -40
  1102. package/src/feature-libraries/modular-schema/genericFieldKind.ts +10 -19
  1103. package/src/feature-libraries/modular-schema/genericFieldKindCodecs.ts +1 -1
  1104. package/src/feature-libraries/modular-schema/index.ts +21 -15
  1105. package/src/feature-libraries/modular-schema/modularChangeCodecV1.ts +732 -0
  1106. package/src/feature-libraries/modular-schema/modularChangeCodecV2.ts +790 -0
  1107. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +29 -499
  1108. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +2542 -742
  1109. package/src/feature-libraries/modular-schema/{modularChangeFormat.ts → modularChangeFormatV1.ts} +2 -1
  1110. package/src/feature-libraries/modular-schema/modularChangeFormatV2.ts +62 -0
  1111. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +98 -10
  1112. package/src/feature-libraries/optional-field/index.ts +1 -3
  1113. package/src/feature-libraries/optional-field/optionalField.ts +317 -574
  1114. package/src/feature-libraries/optional-field/optionalFieldChangeTypes.ts +24 -38
  1115. package/src/feature-libraries/optional-field/optionalFieldCodecV2.ts +89 -35
  1116. package/src/feature-libraries/schema-index/schemaSummarizer.ts +59 -18
  1117. package/src/feature-libraries/sequence-field/compose.ts +134 -519
  1118. package/src/feature-libraries/sequence-field/helperTypes.ts +34 -19
  1119. package/src/feature-libraries/sequence-field/index.ts +0 -9
  1120. package/src/feature-libraries/sequence-field/invert.ts +103 -228
  1121. package/src/feature-libraries/sequence-field/markQueue.ts +2 -2
  1122. package/src/feature-libraries/sequence-field/moveEffectTable.ts +8 -191
  1123. package/src/feature-libraries/sequence-field/rebase.ts +168 -203
  1124. package/src/feature-libraries/sequence-field/replaceRevisions.ts +31 -52
  1125. package/src/feature-libraries/sequence-field/sequenceFieldChangeHandler.ts +0 -2
  1126. package/src/feature-libraries/sequence-field/sequenceFieldCodecV2.ts +643 -220
  1127. package/src/feature-libraries/sequence-field/sequenceFieldCodecV3.ts +56 -68
  1128. package/src/feature-libraries/sequence-field/sequenceFieldEditor.ts +25 -27
  1129. package/src/feature-libraries/sequence-field/sequenceFieldToDelta.ts +19 -129
  1130. package/src/feature-libraries/sequence-field/types.ts +34 -64
  1131. package/src/feature-libraries/sequence-field/utils.ts +133 -346
  1132. package/src/index.ts +3 -2
  1133. package/src/packageVersion.ts +1 -1
  1134. package/src/shared-tree/independentView.ts +1 -1
  1135. package/src/shared-tree/index.ts +3 -2
  1136. package/src/shared-tree/schematizeTree.ts +21 -8
  1137. package/src/shared-tree/schematizingTreeView.ts +50 -68
  1138. package/src/shared-tree/sharedTree.ts +39 -12
  1139. package/src/shared-tree/sharedTreeChangeCodecs.ts +5 -1
  1140. package/src/shared-tree/sharedTreeChangeEnricher.ts +31 -11
  1141. package/src/shared-tree/sharedTreeChangeFamily.ts +7 -4
  1142. package/src/shared-tree/sharedTreeEditBuilder.ts +46 -12
  1143. package/src/shared-tree/treeAlpha.ts +2 -3
  1144. package/src/shared-tree/treeCheckout.ts +104 -31
  1145. package/src/shared-tree-core/branch.ts +8 -2
  1146. package/src/shared-tree-core/editManager.ts +16 -2
  1147. package/src/shared-tree-core/editManagerCodecs.ts +17 -5
  1148. package/src/shared-tree-core/{editManagerCodecsV5.ts → editManagerCodecsVSharedBranches.ts} +3 -3
  1149. package/src/shared-tree-core/editManagerFormatCommons.ts +22 -7
  1150. package/src/shared-tree-core/editManagerFormatV1toV4.ts +3 -1
  1151. package/src/shared-tree-core/{editManagerFormatV5.ts → editManagerFormatVSharedBranches.ts} +2 -2
  1152. package/src/shared-tree-core/editManagerSummarizer.ts +58 -16
  1153. package/src/shared-tree-core/index.ts +11 -3
  1154. package/src/shared-tree-core/messageCodecV1ToV4.ts +2 -1
  1155. package/src/shared-tree-core/{messageCodecV5.ts → messageCodecVSharedBranches.ts} +3 -3
  1156. package/src/shared-tree-core/messageCodecs.ts +17 -5
  1157. package/src/shared-tree-core/messageFormat.ts +22 -7
  1158. package/src/shared-tree-core/messageFormatV1ToV4.ts +16 -2
  1159. package/src/shared-tree-core/{messageFormatV5.ts → messageFormatVSharedBranches.ts} +4 -6
  1160. package/src/shared-tree-core/sharedTreeCore.ts +67 -76
  1161. package/src/shared-tree-core/summaryTypes.ts +122 -0
  1162. package/src/shared-tree-core/versionedSummarizer.ts +107 -0
  1163. package/src/simple-tree/api/configuration.ts +21 -68
  1164. package/src/simple-tree/api/dirtyIndex.ts +11 -0
  1165. package/src/simple-tree/api/discrepancies.ts +1 -1
  1166. package/src/simple-tree/api/getSimpleSchema.ts +13 -6
  1167. package/src/simple-tree/api/incrementalAllowedTypes.ts +15 -3
  1168. package/src/simple-tree/api/index.ts +3 -4
  1169. package/src/simple-tree/api/schemaCompatibilityTester.ts +1 -1
  1170. package/src/simple-tree/api/schemaFactoryAlpha.ts +2 -2
  1171. package/src/simple-tree/api/schemaFactoryRecursive.ts +0 -2
  1172. package/src/simple-tree/api/schemaFromSimple.ts +11 -5
  1173. package/src/simple-tree/api/simpleSchemaCodec.ts +17 -3
  1174. package/src/simple-tree/api/simpleSchemaToJsonSchema.ts +1 -1
  1175. package/src/simple-tree/api/snapshotCompatibilityChecker.ts +18 -10
  1176. package/src/simple-tree/api/typesUnsafe.ts +7 -3
  1177. package/src/simple-tree/core/allowedTypes.ts +3 -3
  1178. package/src/simple-tree/core/index.ts +2 -2
  1179. package/src/simple-tree/core/toStored.ts +22 -55
  1180. package/src/simple-tree/core/unhydratedFlexTree.ts +87 -36
  1181. package/src/simple-tree/core/walkSchema.ts +6 -0
  1182. package/src/simple-tree/createContext.ts +26 -11
  1183. package/src/simple-tree/fieldSchema.ts +16 -7
  1184. package/src/simple-tree/index.ts +12 -11
  1185. package/src/simple-tree/node-kinds/array/arrayNode.ts +12 -7
  1186. package/src/simple-tree/node-kinds/array/arrayNodeTypes.ts +3 -3
  1187. package/src/simple-tree/node-kinds/common.ts +2 -5
  1188. package/src/simple-tree/node-kinds/map/mapNode.ts +9 -6
  1189. package/src/simple-tree/node-kinds/map/mapNodeTypes.ts +3 -3
  1190. package/src/simple-tree/node-kinds/object/objectNode.ts +26 -26
  1191. package/src/simple-tree/node-kinds/object/objectNodeTypes.ts +6 -2
  1192. package/src/simple-tree/node-kinds/record/recordNode.ts +15 -11
  1193. package/src/simple-tree/node-kinds/record/recordNodeTypes.ts +3 -3
  1194. package/src/simple-tree/prepareForInsertion.ts +343 -200
  1195. package/src/simple-tree/simpleSchema.ts +79 -32
  1196. package/src/simple-tree/simpleSchemaFormatV1.ts +9 -1
  1197. package/src/simple-tree/toStoredSchema.ts +319 -61
  1198. package/src/simple-tree/treeSchema.ts +54 -0
  1199. package/src/simple-tree/unhydratedFlexTreeFromInsertable.ts +42 -14
  1200. package/src/tableSchema.ts +485 -166
  1201. package/src/treeFactory.ts +19 -5
  1202. package/src/util/index.ts +5 -0
  1203. package/src/util/rangeMap.ts +72 -18
  1204. package/src/util/readSnapshotBlob.ts +23 -0
  1205. package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +0 -1
  1206. package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +0 -1
  1207. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.d.ts +0 -9
  1208. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.d.ts.map +0 -1
  1209. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.js +0 -50
  1210. package/dist/feature-libraries/sequence-field/relevantRemovedRoots.js.map +0 -1
  1211. package/dist/shared-tree-core/editManagerCodecsV5.d.ts.map +0 -1
  1212. package/dist/shared-tree-core/editManagerCodecsV5.js.map +0 -1
  1213. package/dist/shared-tree-core/editManagerFormatV5.d.ts.map +0 -1
  1214. package/dist/shared-tree-core/editManagerFormatV5.js.map +0 -1
  1215. package/dist/shared-tree-core/messageCodecV5.d.ts.map +0 -1
  1216. package/dist/shared-tree-core/messageCodecV5.js.map +0 -1
  1217. package/dist/shared-tree-core/messageFormatV5.d.ts.map +0 -1
  1218. package/dist/shared-tree-core/messageFormatV5.js.map +0 -1
  1219. package/dist/simple-tree/api/viewSchemaToSimpleSchema.d.ts +0 -40
  1220. package/dist/simple-tree/api/viewSchemaToSimpleSchema.d.ts.map +0 -1
  1221. package/dist/simple-tree/api/viewSchemaToSimpleSchema.js +0 -177
  1222. package/dist/simple-tree/api/viewSchemaToSimpleSchema.js.map +0 -1
  1223. package/docs/main/sequence-field/move-composition.md +0 -46
  1224. package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +0 -1
  1225. package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +0 -1
  1226. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.d.ts +0 -9
  1227. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.d.ts.map +0 -1
  1228. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.js +0 -46
  1229. package/lib/feature-libraries/sequence-field/relevantRemovedRoots.js.map +0 -1
  1230. package/lib/shared-tree-core/editManagerCodecsV5.d.ts.map +0 -1
  1231. package/lib/shared-tree-core/editManagerCodecsV5.js.map +0 -1
  1232. package/lib/shared-tree-core/editManagerFormatV5.d.ts.map +0 -1
  1233. package/lib/shared-tree-core/editManagerFormatV5.js.map +0 -1
  1234. package/lib/shared-tree-core/messageCodecV5.d.ts.map +0 -1
  1235. package/lib/shared-tree-core/messageCodecV5.js.map +0 -1
  1236. package/lib/shared-tree-core/messageFormatV5.d.ts.map +0 -1
  1237. package/lib/shared-tree-core/messageFormatV5.js.map +0 -1
  1238. package/lib/simple-tree/api/viewSchemaToSimpleSchema.d.ts +0 -40
  1239. package/lib/simple-tree/api/viewSchemaToSimpleSchema.d.ts.map +0 -1
  1240. package/lib/simple-tree/api/viewSchemaToSimpleSchema.js +0 -171
  1241. package/lib/simple-tree/api/viewSchemaToSimpleSchema.js.map +0 -1
  1242. package/src/feature-libraries/sequence-field/relevantRemovedRoots.ts +0 -57
  1243. 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,69 @@ 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
+ function addAttachesToSet(
2331
+ change: ModularChangeset,
2332
+ rootIds: ChangeAtomIdRangeMap<boolean>,
2333
+ ): void {
2334
+ // This includes each attach which does not have a corresponding detach.
2335
+ for (const entry of change.crossFieldKeys.entries()) {
2336
+ if (entry.start.target !== CrossFieldTarget.Destination) {
2337
+ continue;
2338
+ }
2339
+
2340
+ for (const detachIdEntry of change.rootNodes.newToOldId.getAll2(
2341
+ entry.start,
2342
+ entry.length,
2343
+ )) {
2344
+ const detachId =
2345
+ detachIdEntry.value ?? offsetChangeAtomId(entry.start, detachIdEntry.offset);
2346
+ for (const detachEntry of change.crossFieldKeys.getAll2(
2347
+ { ...detachId, target: CrossFieldTarget.Source },
2348
+ detachIdEntry.length,
2349
+ )) {
2350
+ if (detachEntry.value === undefined) {
2351
+ rootIds.set(
2352
+ offsetChangeAtomId(detachId, detachEntry.offset),
2353
+ detachEntry.length,
2354
+ true,
2355
+ );
2356
+ }
1931
2357
  }
1932
- };
1933
- yield* handler.relevantRemovedRoots(fieldChange.change, delegate);
2358
+ }
2359
+ }
2360
+ }
2361
+
2362
+ function addRenamesToSet(
2363
+ change: ModularChangeset,
2364
+ rootIds: ChangeAtomIdRangeMap<boolean>,
2365
+ ): void {
2366
+ for (const renameEntry of change.rootNodes.oldToNewId.entries()) {
2367
+ for (const detachEntry of change.crossFieldKeys.getAll2(
2368
+ { ...renameEntry.start, target: CrossFieldTarget.Source },
2369
+ renameEntry.length,
2370
+ )) {
2371
+ // We only want to include renames of nodes which are detached in the input context of the changeset.
2372
+ // So if there is a detach for the node, the rename is not relevant.
2373
+ if (detachEntry.value === undefined) {
2374
+ rootIds.set(renameEntry.start, renameEntry.length, true);
2375
+ }
2376
+ }
1934
2377
  }
1935
2378
  }
1936
2379
 
@@ -2003,6 +2446,7 @@ export function updateRefreshers(
2003
2446
  nodeChanges,
2004
2447
  nodeToParent: change.nodeToParent,
2005
2448
  nodeAliases: change.nodeAliases,
2449
+ rootNodes: change.rootNodes,
2006
2450
  crossFieldKeys: change.crossFieldKeys,
2007
2451
  maxId: maxId as number,
2008
2452
  revisions,
@@ -2026,18 +2470,42 @@ export function intoDelta(
2026
2470
  ): DeltaRoot {
2027
2471
  const change = taggedChange.change;
2028
2472
  const rootDelta: Mutable<DeltaRoot> = {};
2029
- const global: DeltaDetachedNodeChanges[] = [];
2030
- const rename: DeltaDetachedNodeRename[] = [];
2031
2473
 
2032
2474
  if (!hasConflicts(change)) {
2033
2475
  // If there are no constraint violations, then tree changes apply.
2034
2476
  const fieldDeltas = intoDeltaImpl(
2035
2477
  change.fieldChanges,
2036
2478
  change.nodeChanges,
2479
+ change.nodeAliases,
2037
2480
  fieldKinds,
2038
- global,
2039
- rename,
2040
2481
  );
2482
+
2483
+ const global: DeltaDetachedNodeChanges[] = [];
2484
+ for (const [[major, minor], nodeId] of change.rootNodes.nodeChanges.entries()) {
2485
+ global.push({
2486
+ id: { major, minor },
2487
+ fields: deltaFromNodeChange(
2488
+ nodeChangeFromId(change.nodeChanges, change.nodeAliases, nodeId),
2489
+ change.nodeChanges,
2490
+ change.nodeAliases,
2491
+ fieldKinds,
2492
+ ),
2493
+ });
2494
+ }
2495
+
2496
+ const rename: DeltaDetachedNodeRename[] = [];
2497
+ for (const {
2498
+ start: oldId,
2499
+ value: newId,
2500
+ length,
2501
+ } of change.rootNodes.oldToNewId.entries()) {
2502
+ rename.push({
2503
+ count: length,
2504
+ oldId: makeDetachedNodeId(oldId.revision, oldId.localId),
2505
+ newId: makeDetachedNodeId(newId.revision, newId.localId),
2506
+ });
2507
+ }
2508
+
2041
2509
  if (fieldDeltas.size > 0) {
2042
2510
  rootDelta.fields = fieldDeltas;
2043
2511
  }
@@ -2066,6 +2534,7 @@ export function intoDelta(
2066
2534
  if (change.refreshers && change.refreshers.size > 0) {
2067
2535
  rootDelta.refreshers = copyDetachedNodes(change.refreshers);
2068
2536
  }
2537
+
2069
2538
  return rootDelta;
2070
2539
  }
2071
2540
 
@@ -2091,29 +2560,22 @@ function copyDetachedNodes(
2091
2560
  function intoDeltaImpl(
2092
2561
  change: FieldChangeMap,
2093
2562
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2563
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
2094
2564
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
2095
- global: DeltaDetachedNodeChanges[],
2096
- rename: DeltaDetachedNodeRename[],
2097
2565
  ): Map<FieldKey, DeltaFieldChanges> {
2098
2566
  const delta: Map<FieldKey, DeltaFieldChanges> = new Map();
2099
2567
 
2100
2568
  for (const [field, fieldChange] of change) {
2101
- const {
2102
- local: fieldChanges,
2103
- global: fieldGlobal,
2104
- rename: fieldRename,
2105
- } = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
2569
+ const fieldDelta = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
2106
2570
  fieldChange.change,
2107
2571
  (childChange): DeltaFieldMap => {
2108
- const nodeChange = nodeChangeFromId(nodeChanges, childChange);
2109
- return deltaFromNodeChange(nodeChange, nodeChanges, fieldKinds, global, rename);
2572
+ const nodeChange = nodeChangeFromId(nodeChanges, nodeAliases, childChange);
2573
+ return deltaFromNodeChange(nodeChange, nodeChanges, nodeAliases, fieldKinds);
2110
2574
  },
2111
2575
  );
2112
- if (fieldChanges !== undefined && fieldChanges.length > 0) {
2113
- delta.set(field, fieldChanges);
2576
+ if (fieldDelta !== undefined && fieldDelta.length > 0) {
2577
+ delta.set(field, fieldDelta);
2114
2578
  }
2115
- fieldGlobal?.forEach((c) => global.push(c));
2116
- fieldRename?.forEach((r) => rename.push(r));
2117
2579
  }
2118
2580
  return delta;
2119
2581
  }
@@ -2121,12 +2583,11 @@ function intoDeltaImpl(
2121
2583
  function deltaFromNodeChange(
2122
2584
  change: NodeChangeset,
2123
2585
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2586
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
2124
2587
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
2125
- global: DeltaDetachedNodeChanges[],
2126
- rename: DeltaDetachedNodeRename[],
2127
2588
  ): DeltaFieldMap {
2128
2589
  if (change.fieldChanges !== undefined) {
2129
- return intoDeltaImpl(change.fieldChanges, nodeChanges, fieldKinds, global, rename);
2590
+ return intoDeltaImpl(change.fieldChanges, nodeChanges, nodeAliases, fieldKinds);
2130
2591
  }
2131
2592
  // TODO: update the API to allow undefined to be returned here
2132
2593
  return new Map();
@@ -2191,19 +2652,21 @@ export function getChangeHandler(
2191
2652
  return getFieldKind(fieldKinds, kind).changeHandler;
2192
2653
  }
2193
2654
 
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
- }
2655
+ interface InvertTable {
2656
+ change: ModularChangeset;
2203
2657
 
2204
- interface InvertTable extends CrossFieldTable<FieldChange> {
2658
+ // Entries are keyed on attach ID
2659
+ entries: CrossFieldMap<NodeId>;
2205
2660
  originalFieldToContext: Map<FieldChange, InvertContext>;
2206
- invertedNodeToParent: ChangeAtomIdBTree<FieldId>;
2661
+ invertedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
2662
+ invertRevision: RevisionTag;
2663
+ invalidatedFields: Set<FieldChange>;
2664
+ invertedRoots: RootNodeTable;
2665
+
2666
+ /**
2667
+ * Maps from attach ID in the inverted changeset to the corresponding detach ID in the base changeset.
2668
+ */
2669
+ attachToDetachId: ChangeAtomIdRangeMap<ChangeAtomId>;
2207
2670
  }
2208
2671
 
2209
2672
  interface InvertContext {
@@ -2211,7 +2674,11 @@ interface InvertContext {
2211
2674
  invertedField: FieldChange;
2212
2675
  }
2213
2676
 
2214
- interface RebaseTable extends CrossFieldTable<FieldChange> {
2677
+ interface RebaseTable {
2678
+ readonly rebaseVersion: RebaseVersion;
2679
+
2680
+ // Entries are keyed on attach ID
2681
+ readonly entries: CrossFieldMap<RebaseDetachedNodeEntry>;
2215
2682
  readonly baseChange: ModularChangeset;
2216
2683
  readonly newChange: ModularChangeset;
2217
2684
 
@@ -2220,10 +2687,13 @@ interface RebaseTable extends CrossFieldTable<FieldChange> {
2220
2687
  * to the context for the field.
2221
2688
  */
2222
2689
  readonly baseFieldToContext: Map<FieldChange, RebaseFieldContext>;
2690
+ readonly baseRoots: RootNodeTable;
2223
2691
  readonly baseToRebasedNodeId: ChangeAtomIdBTree<NodeId>;
2224
2692
  readonly rebasedFields: Set<FieldChange>;
2225
- readonly rebasedNodeToParent: ChangeAtomIdBTree<FieldId>;
2226
- readonly rebasedCrossFieldKeys: CrossFieldKeyTable;
2693
+ readonly rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
2694
+ readonly rebasedDetachLocations: ChangeAtomIdRangeMap<FieldId>;
2695
+ readonly movedDetaches: ChangeAtomIdRangeMap<boolean>;
2696
+ readonly rebasedRootNodes: RootNodeTable;
2227
2697
 
2228
2698
  /**
2229
2699
  * List of unprocessed (newId, baseId) pairs encountered so far.
@@ -2237,7 +2707,7 @@ interface RebaseTable extends CrossFieldTable<FieldChange> {
2237
2707
  readonly fieldsWithUnattachedChild: Set<FieldChange>;
2238
2708
  }
2239
2709
 
2240
- type FieldIdKey = [RevisionTag | undefined, ChangesetLocalId | undefined, FieldKey];
2710
+ export type FieldIdKey = [RevisionTag | undefined, ChangesetLocalId | undefined, FieldKey];
2241
2711
 
2242
2712
  interface RebaseFieldContext {
2243
2713
  baseChange: FieldChange;
@@ -2249,32 +2719,43 @@ interface RebaseFieldContext {
2249
2719
  * The set of node IDs in the base changeset which should be included in the rebased field,
2250
2720
  * even if there is no corresponding node changeset in the new change.
2251
2721
  */
2252
- baseNodeIds: NodeId[];
2722
+ baseNodeIds: ChangeAtomIdBTree<boolean>;
2253
2723
  }
2254
2724
 
2255
2725
  function newComposeTable(
2256
2726
  baseChange: ModularChangeset,
2257
2727
  newChange: ModularChangeset,
2258
- composedNodeToParent: ChangeAtomIdBTree<FieldId>,
2728
+ composedRootNodes: RootNodeTable,
2729
+ movedCrossFieldKeys: CrossFieldKeyTable,
2730
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
2731
+ pendingCompositions: PendingCompositions,
2259
2732
  ): ComposeTable {
2260
2733
  return {
2261
- ...newCrossFieldTable<FieldChange>(),
2734
+ rebaseVersion: Math.max(
2735
+ baseChange.rebaseVersion,
2736
+ newChange.rebaseVersion,
2737
+ ) as RebaseVersion,
2738
+ entries: newDetachedEntryMap(),
2262
2739
  baseChange,
2263
2740
  newChange,
2264
2741
  fieldToContext: new Map(),
2265
2742
  newFieldToBaseField: new Map(),
2266
2743
  newToBaseNodeId: newTupleBTree(),
2267
2744
  composedNodes: new Set(),
2268
- composedNodeToParent,
2269
- pendingCompositions: {
2270
- nodeIdsToCompose: [],
2271
- affectedBaseFields: newTupleBTree(),
2272
- affectedNewFields: newTupleBTree(),
2273
- },
2745
+ movedNodeToParent: newTupleBTree(),
2746
+ composedRootNodes,
2747
+ movedCrossFieldKeys,
2748
+ removedCrossFieldKeys,
2749
+ renamesToDelete: newChangeAtomIdRangeMap(),
2750
+ pendingCompositions,
2274
2751
  };
2275
2752
  }
2276
2753
 
2277
- interface ComposeTable extends CrossFieldTable<FieldChange> {
2754
+ interface ComposeTable {
2755
+ readonly rebaseVersion: RebaseVersion;
2756
+
2757
+ // Entries are keyed on detach ID
2758
+ readonly entries: ChangeAtomIdRangeMap<DetachedNodeEntry>;
2278
2759
  readonly baseChange: ModularChangeset;
2279
2760
  readonly newChange: ModularChangeset;
2280
2761
 
@@ -2285,7 +2766,11 @@ interface ComposeTable extends CrossFieldTable<FieldChange> {
2285
2766
  readonly newFieldToBaseField: Map<FieldChange, FieldChange>;
2286
2767
  readonly newToBaseNodeId: ChangeAtomIdBTree<NodeId>;
2287
2768
  readonly composedNodes: Set<NodeChangeset>;
2288
- readonly composedNodeToParent: ChangeAtomIdBTree<FieldId>;
2769
+ readonly movedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
2770
+ readonly composedRootNodes: RootNodeTable;
2771
+ readonly movedCrossFieldKeys: CrossFieldKeyTable;
2772
+ readonly removedCrossFieldKeys: CrossFieldRangeTable<boolean>;
2773
+ readonly renamesToDelete: ChangeAtomIdRangeMap<boolean>;
2289
2774
  readonly pendingCompositions: PendingCompositions;
2290
2775
  }
2291
2776
 
@@ -2300,11 +2785,6 @@ interface PendingCompositions {
2300
2785
  * The set of fields in the base changeset which have been affected by a cross field effect.
2301
2786
  */
2302
2787
  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
2788
  }
2309
2789
 
2310
2790
  interface ComposeFieldContext {
@@ -2317,16 +2797,6 @@ interface ComposeFieldContext {
2317
2797
  composedChange: FieldChange;
2318
2798
  }
2319
2799
 
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
2800
  interface ConstraintState {
2331
2801
  violationCount: number;
2332
2802
  }
@@ -2337,283 +2807,697 @@ function newConstraintState(violationCount: number): ConstraintState {
2337
2807
  };
2338
2808
  }
2339
2809
 
2340
- abstract class CrossFieldManagerI<T> implements CrossFieldManager {
2810
+ class InvertNodeManagerI implements InvertNodeManager {
2341
2811
  public constructor(
2342
- protected readonly crossFieldTable: CrossFieldTable<T>,
2343
- private readonly currentFieldKey: T,
2344
- protected readonly allowInval = true,
2812
+ private readonly table: InvertTable,
2813
+ private readonly fieldId: FieldId,
2345
2814
  ) {}
2346
2815
 
2347
- public set(
2348
- target: CrossFieldTarget,
2349
- revision: RevisionTag | undefined,
2350
- id: ChangesetLocalId,
2816
+ public invertDetach(
2817
+ detachId: ChangeAtomId,
2351
2818
  count: number,
2352
- newValue: unknown,
2353
- invalidateDependents: boolean,
2819
+ nodeChange: NodeId | undefined,
2820
+ newAttachId: ChangeAtomId,
2354
2821
  ): 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
- }
2822
+ if (nodeChange !== undefined) {
2823
+ assert(count === 1, "A node change should only affect one node");
2824
+
2825
+ const attachEntry = firstAttachIdFromDetachId(
2826
+ this.table.change.rootNodes,
2827
+ detachId,
2828
+ count,
2829
+ );
2830
+
2831
+ const attachFieldEntry = this.table.change.crossFieldKeys.getFirst(
2832
+ { target: CrossFieldTarget.Destination, ...attachEntry.value },
2833
+ count,
2834
+ );
2368
2835
 
2369
- firstId = brand(firstId + dependentEntry.length);
2836
+ if (attachFieldEntry.value !== undefined) {
2837
+ setInCrossFieldMap(this.table.entries, attachEntry.value, count, nodeChange);
2838
+ this.table.invalidatedFields.add(
2839
+ fieldChangeFromId(this.table.change, attachFieldEntry.value),
2840
+ );
2841
+ } else {
2842
+ assignRootChange(
2843
+ this.table.invertedRoots,
2844
+ this.table.invertedNodeToParent,
2845
+ attachEntry.value,
2846
+ nodeChange,
2847
+ this.fieldId,
2848
+ this.table.change.rebaseVersion,
2849
+ );
2370
2850
  }
2371
2851
  }
2372
- setInCrossFieldMap(this.getMap(target), revision, id, count, newValue);
2373
- }
2374
2852
 
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,
2853
+ if (!areEqualChangeAtomIds(detachId, newAttachId)) {
2854
+ for (const entry of doesChangeAttachNodes(
2855
+ this.table.change.crossFieldKeys,
2856
+ detachId,
2390
2857
  count,
2391
- this.currentFieldKey,
2392
- );
2858
+ )) {
2859
+ if (!entry.value) {
2860
+ this.table.attachToDetachId.set(newAttachId, count, detachId);
2861
+ this.table.invertedRoots.detachLocations.set(detachId, count, this.fieldId);
2862
+ }
2863
+ }
2393
2864
  }
2394
- return getFirstFromCrossFieldMap(this.getMap(target), revision, id, count);
2395
2865
  }
2396
2866
 
2397
- public abstract onMoveIn(id: NodeId): void;
2398
-
2399
- public abstract moveKey(
2400
- target: CrossFieldTarget,
2401
- revision: RevisionTag | undefined,
2402
- id: ChangesetLocalId,
2867
+ public invertAttach(
2868
+ attachId: ChangeAtomId,
2403
2869
  count: number,
2404
- ): void;
2870
+ ): RangeQueryResult<DetachedNodeEntry> {
2871
+ let countToProcess = count;
2405
2872
 
2406
- private getMap(target: CrossFieldTarget): CrossFieldMap<unknown> {
2407
- return target === CrossFieldTarget.Source
2408
- ? this.crossFieldTable.srcTable
2409
- : this.crossFieldTable.dstTable;
2410
- }
2873
+ const detachIdEntry = firstDetachIdFromAttachId(
2874
+ this.table.change.rootNodes,
2875
+ attachId,
2876
+ countToProcess,
2877
+ );
2411
2878
 
2412
- private getDependents(target: CrossFieldTarget): CrossFieldMap<T> {
2413
- return target === CrossFieldTarget.Source
2414
- ? this.crossFieldTable.srcDependents
2415
- : this.crossFieldTable.dstDependents;
2416
- }
2417
- }
2879
+ countToProcess = detachIdEntry.length;
2418
2880
 
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
- }
2881
+ const detachEntry = getFirstFieldForCrossFieldKey(
2882
+ this.table.change,
2883
+ { target: CrossFieldTarget.Source, ...detachIdEntry.value },
2884
+ countToProcess,
2885
+ );
2886
+ countToProcess = detachEntry.length;
2428
2887
 
2429
- public override onMoveIn(id: ChangeAtomId): void {
2430
- setInChangeAtomIdMap(this.table.invertedNodeToParent, id, this.fieldId);
2431
- }
2888
+ let result: RangeQueryResult<DetachedNodeEntry>;
2889
+ if (detachEntry.value !== undefined) {
2890
+ const moveEntry = this.table.entries.getFirst(attachId, countToProcess);
2891
+ result = { ...moveEntry, value: { nodeChange: moveEntry.value } };
2892
+ } else {
2893
+ // This node is detached in the input context of the original change.
2894
+ const nodeIdEntry = rangeQueryChangeAtomIdMap(
2895
+ this.table.change.rootNodes.nodeChanges,
2896
+ detachIdEntry.value,
2897
+ countToProcess,
2898
+ );
2432
2899
 
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
- }
2900
+ countToProcess = nodeIdEntry.length;
2901
+ result = {
2902
+ value: { nodeChange: nodeIdEntry.value, detachId: detachIdEntry.value },
2903
+ length: countToProcess,
2904
+ };
2905
+ }
2441
2906
 
2442
- private get table(): InvertTable {
2443
- return this.crossFieldTable as InvertTable;
2907
+ if (result.value?.nodeChange !== undefined) {
2908
+ setInChangeAtomIdMap(this.table.invertedNodeToParent, result.value.nodeChange, {
2909
+ field: this.fieldId,
2910
+ });
2911
+ }
2912
+ return result;
2444
2913
  }
2445
2914
  }
2446
2915
 
2447
- class RebaseManager extends CrossFieldManagerI<FieldChange> {
2916
+ class RebaseNodeManagerI implements RebaseNodeManager {
2448
2917
  public constructor(
2449
- table: RebaseTable,
2450
- currentField: FieldChange,
2918
+ private readonly table: RebaseTable,
2451
2919
  private readonly fieldId: FieldId,
2452
- allowInval = true,
2453
- ) {
2454
- super(table, currentField, allowInval);
2455
- }
2920
+ private readonly allowInval: boolean = true,
2921
+ ) {}
2456
2922
 
2457
- public override set(
2458
- target: CrossFieldTarget,
2459
- revision: RevisionTag | undefined,
2460
- id: ChangesetLocalId,
2923
+ public getNewChangesForBaseAttach(
2924
+ baseAttachId: ChangeAtomId,
2461
2925
  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
- );
2926
+ ): RangeQueryResult<RebaseDetachedNodeEntry | undefined> {
2927
+ let countToProcess = count;
2475
2928
 
2476
- assert(
2477
- newFieldIds.length === 0,
2478
- 0x9c6 /* TODO: Modifying a cross-field key from the new changeset is currently unsupported */,
2479
- );
2929
+ const detachEntry = firstDetachIdFromAttachId(
2930
+ this.table.baseChange.rootNodes,
2931
+ baseAttachId,
2932
+ countToProcess,
2933
+ );
2480
2934
 
2481
- const baseFieldIds = getFieldsForCrossFieldKey(
2482
- this.table.baseChange,
2483
- {
2484
- target,
2485
- revision,
2486
- localId: id,
2487
- },
2488
- count,
2489
- );
2935
+ countToProcess = detachEntry.length;
2490
2936
 
2491
- assert(
2492
- baseFieldIds.length > 0,
2493
- 0x9c7 /* Cross field key not registered in base or new change */,
2494
- );
2937
+ const nodeEntry = rangeQueryChangeAtomIdMap(
2938
+ this.table.newChange.rootNodes.nodeChanges,
2939
+ detachEntry.value,
2940
+ countToProcess,
2941
+ );
2495
2942
 
2496
- for (const baseFieldId of baseFieldIds) {
2497
- this.table.affectedBaseFields.set(
2498
- [baseFieldId.nodeId?.revision, baseFieldId.nodeId?.localId, baseFieldId.field],
2499
- true,
2500
- );
2501
- }
2502
- }
2943
+ countToProcess = nodeEntry.length;
2944
+ const newNodeId = nodeEntry.value;
2503
2945
 
2504
- super.set(target, revision, id, count, newValue, invalidateDependents);
2505
- }
2946
+ const newRenameEntry = this.table.newChange.rootNodes.oldToNewId.getFirst(
2947
+ detachEntry.value,
2948
+ countToProcess,
2949
+ );
2950
+
2951
+ countToProcess = newRenameEntry.length;
2952
+
2953
+ let result: RangeQueryResult<DetachedNodeEntry | undefined>;
2954
+ // eslint-disable-next-line unicorn/prefer-ternary
2955
+ if (newNodeId !== undefined || newRenameEntry.value !== undefined) {
2956
+ result = {
2957
+ ...newRenameEntry,
2958
+ value: { detachId: newRenameEntry.value, nodeChange: newNodeId },
2959
+ };
2960
+ } else {
2961
+ // This handles the case where the base changeset has moved these nodes,
2962
+ // meaning they were attached in the input context of the base changeset.
2963
+ result = this.table.entries.getFirst(baseAttachId, countToProcess);
2964
+ }
2965
+
2966
+ // TODO: Consider moving these two checks into a separate method so that this function has no side effects.
2967
+ if (result.value?.detachId !== undefined) {
2968
+ this.table.rebasedDetachLocations.set(
2969
+ result.value.detachId,
2970
+ result.length,
2971
+ this.fieldId,
2972
+ );
2973
+ }
2974
+
2975
+ if (result.value?.nodeChange !== undefined) {
2976
+ setInChangeAtomIdMap(this.table.rebasedNodeToParent, result.value.nodeChange, {
2977
+ field: this.fieldId,
2978
+ });
2979
+ }
2506
2980
 
2507
- public override onMoveIn(id: ChangeAtomId): void {
2508
- setInChangeAtomIdMap(this.table.rebasedNodeToParent, id, this.fieldId);
2981
+ return result;
2509
2982
  }
2510
2983
 
2511
- public override moveKey(
2512
- target: CrossFieldTarget,
2513
- revision: RevisionTag | undefined,
2514
- id: ChangesetLocalId,
2984
+ public rebaseOverDetach(
2985
+ baseDetachId: ChangeAtomId,
2515
2986
  count: number,
2987
+ newDetachId: ChangeAtomId | undefined,
2988
+ nodeChange: NodeId | undefined,
2989
+ cellRename?: ChangeAtomId,
2516
2990
  ): void {
2517
- this.table.rebasedCrossFieldKeys.set(
2518
- { target, revision, localId: id },
2519
- count,
2520
- this.fieldId,
2991
+ let countToProcess = count;
2992
+ const attachIdEntry = firstAttachIdFromDetachId(
2993
+ this.table.baseRoots,
2994
+ baseDetachId,
2995
+ countToProcess,
2996
+ );
2997
+ const baseAttachId = attachIdEntry.value;
2998
+ countToProcess = attachIdEntry.length;
2999
+
3000
+ const attachFieldEntry = getFirstFieldForCrossFieldKey(
3001
+ this.table.baseChange,
3002
+ { ...baseAttachId, target: CrossFieldTarget.Destination },
3003
+ countToProcess,
3004
+ );
3005
+ countToProcess = attachFieldEntry.length;
3006
+
3007
+ const detachedMoveEntry = this.table.baseChange.rootNodes.outputDetachLocations.getFirst(
3008
+ baseDetachId,
3009
+ countToProcess,
3010
+ );
3011
+ countToProcess = detachedMoveEntry.length;
3012
+
3013
+ const destinationField = attachFieldEntry.value ?? detachedMoveEntry.value;
3014
+ if (destinationField !== undefined) {
3015
+ // The base detach is part of a move (or move of detach location) in the base changeset.
3016
+ setInCrossFieldMap(this.table.entries, baseAttachId, countToProcess, {
3017
+ nodeChange,
3018
+ detachId: newDetachId,
3019
+ cellRename,
3020
+ });
3021
+
3022
+ if (nodeChange !== undefined || newDetachId !== undefined) {
3023
+ this.invalidateBaseFields([destinationField]);
3024
+ }
3025
+ }
3026
+
3027
+ if (attachFieldEntry.value === undefined) {
3028
+ // These nodes are detached in the output context of the base changeset.
3029
+ if (nodeChange !== undefined) {
3030
+ assignRootChange(
3031
+ this.table.rebasedRootNodes,
3032
+ this.table.rebasedNodeToParent,
3033
+ baseAttachId,
3034
+ nodeChange,
3035
+ this.fieldId,
3036
+ this.table.rebaseVersion,
3037
+ );
3038
+ }
3039
+
3040
+ if (newDetachId !== undefined) {
3041
+ addNodeRename(
3042
+ this.table.rebasedRootNodes,
3043
+ baseAttachId,
3044
+ newDetachId,
3045
+ countToProcess,
3046
+ this.fieldId,
3047
+ );
3048
+ }
3049
+ }
3050
+
3051
+ if (newDetachId !== undefined) {
3052
+ this.table.movedDetaches.set(newDetachId, countToProcess, true);
3053
+ }
3054
+
3055
+ if (countToProcess < count) {
3056
+ const remainingCount = count - countToProcess;
3057
+
3058
+ const nextDetachId =
3059
+ newDetachId !== undefined
3060
+ ? offsetChangeAtomId(newDetachId, countToProcess)
3061
+ : undefined;
3062
+
3063
+ this.rebaseOverDetach(
3064
+ offsetChangeAtomId(baseDetachId, countToProcess),
3065
+ remainingCount,
3066
+ nextDetachId,
3067
+ nodeChange,
3068
+ );
3069
+ }
3070
+ }
3071
+
3072
+ public addDetach(id: ChangeAtomId, count: number): void {
3073
+ this.table.rebasedDetachLocations.set(id, count, this.fieldId);
3074
+ }
3075
+
3076
+ public removeDetach(id: ChangeAtomId, count: number): void {
3077
+ this.table.movedDetaches.set(id, count, true);
3078
+ }
3079
+
3080
+ public doesBaseAttachNodes(
3081
+ id: ChangeAtomId,
3082
+ count: number,
3083
+ ): RangeQueryEntry<ChangeAtomId, boolean> {
3084
+ let countToProcess = count;
3085
+ const attachEntry = getFirstAttachField(
3086
+ this.table.baseChange.crossFieldKeys,
3087
+ id,
3088
+ countToProcess,
3089
+ );
3090
+
3091
+ countToProcess = attachEntry.length;
3092
+ return { start: id, value: attachEntry.value !== undefined, length: countToProcess };
3093
+ }
3094
+
3095
+ public getBaseRename(
3096
+ id: ChangeAtomId,
3097
+ count: number,
3098
+ ): RangeQueryResult<ChangeAtomId | undefined> {
3099
+ return this.table.baseChange.rootNodes.oldToNewId.getFirst(id, count);
3100
+ }
3101
+
3102
+ public getNewRenameForBaseRename(
3103
+ baseRenameTo: ChangeAtomId,
3104
+ count: number,
3105
+ ): RangeQueryResult<ChangeAtomId | undefined> {
3106
+ let countToProcess = count;
3107
+ const inputEntry = firstDetachIdFromAttachId(
3108
+ this.table.baseChange.rootNodes,
3109
+ baseRenameTo,
3110
+ countToProcess,
3111
+ );
3112
+
3113
+ const attachEntry = getFirstAttachField(
3114
+ this.table.baseChange.crossFieldKeys,
3115
+ baseRenameTo,
3116
+ countToProcess,
2521
3117
  );
3118
+
3119
+ countToProcess = attachEntry.length;
3120
+ if (attachEntry.value !== undefined) {
3121
+ // These nodes are attached in the output context of the base changeset.
3122
+ return { value: undefined, length: countToProcess };
3123
+ }
3124
+
3125
+ countToProcess = inputEntry.length;
3126
+ const inputId = inputEntry.value;
3127
+
3128
+ const moveEntry = this.table.entries.getFirst(inputId, countToProcess);
3129
+
3130
+ countToProcess = moveEntry.length;
3131
+ if (moveEntry.value !== undefined) {
3132
+ return { ...moveEntry, value: moveEntry.value.cellRename ?? moveEntry.value.detachId };
3133
+ }
3134
+
3135
+ return this.table.newChange.rootNodes.oldToNewId.getFirst(inputId, countToProcess);
3136
+ }
3137
+
3138
+ private invalidateBaseFields(fields: FieldId[]): void {
3139
+ if (this.allowInval) {
3140
+ for (const fieldId of fields) {
3141
+ this.table.affectedBaseFields.set(fieldIdKeyFromFieldId(fieldId), true);
3142
+ }
3143
+ }
2522
3144
  }
3145
+ }
2523
3146
 
2524
- private get table(): RebaseTable {
2525
- return this.crossFieldTable as RebaseTable;
3147
+ function assignRootChange(
3148
+ table: RootNodeTable,
3149
+ nodeToParent: ChangeAtomIdBTree<NodeLocation> | undefined,
3150
+ detachId: ChangeAtomId,
3151
+ nodeId: NodeId,
3152
+ detachLocation: FieldId | undefined,
3153
+ rebaseVersion: RebaseVersion,
3154
+ ): void {
3155
+ assert(
3156
+ rebaseVersion >= 2 || detachLocation !== undefined,
3157
+ "All root changes need a detach location to support compatibility with older client versions",
3158
+ );
3159
+
3160
+ setInChangeAtomIdMap(table.nodeChanges, detachId, nodeId);
3161
+
3162
+ if (nodeToParent !== undefined) {
3163
+ setInChangeAtomIdMap(nodeToParent, nodeId, { root: detachId });
2526
3164
  }
3165
+
3166
+ table.detachLocations.set(detachId, 1, detachLocation);
2527
3167
  }
2528
3168
 
2529
- // TODO: Deduplicate this with RebaseTable
2530
- class ComposeManager extends CrossFieldManagerI<FieldChange> {
3169
+ class ComposeNodeManagerI implements ComposeNodeManager {
2531
3170
  public constructor(
2532
- table: ComposeTable,
2533
- currentField: FieldChange,
3171
+ private readonly table: ComposeTable,
2534
3172
  private readonly fieldId: FieldId,
2535
- allowInval = true,
2536
- ) {
2537
- super(table, currentField, allowInval);
3173
+ private readonly allowInval: boolean = true,
3174
+ ) {}
3175
+
3176
+ public getNewChangesForBaseDetach(
3177
+ baseDetachId: ChangeAtomId,
3178
+ count: number,
3179
+ ): RangeQueryResult<DetachedNodeEntry | undefined> {
3180
+ let countToProcess = count;
3181
+
3182
+ const baseAttachEntry = getFirstFieldForCrossFieldKey(
3183
+ this.table.baseChange,
3184
+ { target: CrossFieldTarget.Destination, ...baseDetachId },
3185
+ countToProcess,
3186
+ );
3187
+
3188
+ countToProcess = baseAttachEntry.length;
3189
+
3190
+ let result: RangeQueryResult<DetachedNodeEntry | undefined>;
3191
+ if (baseAttachEntry.value !== undefined) {
3192
+ // The base detach was part of a move.
3193
+ // We check if we've previously seen a node change at the move destination.
3194
+ const entry = this.table.entries.getFirst(baseDetachId, countToProcess);
3195
+ result = { value: entry.value, length: entry.length };
3196
+ } else {
3197
+ // The detached nodes are still detached in the new change's input context.
3198
+ const rootEntry = rangeQueryChangeAtomIdMap(
3199
+ this.table.newChange.rootNodes.nodeChanges,
3200
+ baseDetachId,
3201
+ countToProcess,
3202
+ );
3203
+
3204
+ countToProcess = rootEntry.length;
3205
+
3206
+ const newRenameEntry = this.table.newChange.rootNodes.oldToNewId.getFirst(
3207
+ baseDetachId,
3208
+ countToProcess,
3209
+ );
3210
+
3211
+ countToProcess = newRenameEntry.length;
3212
+
3213
+ result = {
3214
+ value: { nodeChange: rootEntry.value, detachId: newRenameEntry.value },
3215
+ length: countToProcess,
3216
+ };
3217
+ }
3218
+
3219
+ // TODO: Consider moving this to a separate method so that this method can be side-effect free.
3220
+ if (result.value?.nodeChange !== undefined) {
3221
+ setInChangeAtomIdMap(this.table.movedNodeToParent, result.value.nodeChange, {
3222
+ field: this.fieldId,
3223
+ });
3224
+ }
3225
+
3226
+ return result;
2538
3227
  }
2539
3228
 
2540
- public override set(
2541
- target: CrossFieldTarget,
2542
- revision: RevisionTag | undefined,
2543
- id: ChangesetLocalId,
3229
+ public composeAttachDetach(
3230
+ baseAttachId: ChangeAtomId,
3231
+ newDetachId: ChangeAtomId,
2544
3232
  count: number,
2545
- newValue: unknown,
2546
- invalidateDependents: boolean,
2547
3233
  ): 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,
3234
+ let countToProcess = count;
3235
+
3236
+ const newAttachEntry = getFirstAttachField(
3237
+ this.table.newChange.crossFieldKeys,
3238
+ newDetachId,
3239
+ countToProcess,
3240
+ );
3241
+
3242
+ countToProcess = newAttachEntry.length;
3243
+
3244
+ // Both changes can have the same ID if they came from inverse changesets.
3245
+ // If the new detach is part of a move,
3246
+ // then both input changesets contain the attach cross-field key for this ID.
3247
+ // The new attach may still exist in the composed changeset so we do not remove it here.
3248
+ // The new attach will typically cancel with a base detach,
3249
+ // in which case the cross-field key will be removed in `composeDetachAttach`.
3250
+ const hasNewAttachWithBaseAttachId =
3251
+ areEqualChangeAtomIds(baseAttachId, newDetachId) && newAttachEntry.value !== undefined;
3252
+
3253
+ if (!hasNewAttachWithBaseAttachId) {
3254
+ this.table.removedCrossFieldKeys.set(
3255
+ { ...baseAttachId, target: CrossFieldTarget.Destination },
3256
+ countToProcess,
3257
+ true,
2557
3258
  );
3259
+ }
2558
3260
 
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,
3261
+ const baseDetachEntry = getFirstDetachField(
3262
+ this.table.baseChange.crossFieldKeys,
3263
+ baseAttachId,
3264
+ countToProcess,
3265
+ );
3266
+
3267
+ countToProcess = baseDetachEntry.length;
3268
+
3269
+ const baseRootIdEntry = firstDetachIdFromAttachId(
3270
+ this.table.baseChange.rootNodes,
3271
+ baseAttachId,
3272
+ countToProcess,
3273
+ );
3274
+ countToProcess = baseRootIdEntry.length;
3275
+
3276
+ const baseDetachId = baseRootIdEntry.value;
3277
+
3278
+ if (baseDetachEntry.value !== undefined) {
3279
+ // The base change moves these nodes.
3280
+ const prevEntry =
3281
+ this.table.entries.getFirst(baseAttachId, baseDetachEntry.length).value ?? {};
3282
+
3283
+ this.table.entries.set(baseAttachId, baseDetachEntry.length, {
3284
+ ...prevEntry,
3285
+ detachId: newDetachId,
3286
+ });
3287
+
3288
+ // The new detach will replace the base detach, so we remove the key for the base detach, unless they have the same ID.
3289
+ if (!areEqualChangeAtomIds(baseAttachId, newDetachId)) {
3290
+ this.table.removedCrossFieldKeys.set(
3291
+ { ...baseAttachId, target: CrossFieldTarget.Source },
3292
+ countToProcess,
3293
+ true,
2575
3294
  );
3295
+ }
2576
3296
 
2577
- assert(
2578
- baseFieldIds.length > 0,
2579
- 0x9c8 /* Cross field key not registered in base or new change */,
3297
+ this.table.movedCrossFieldKeys.set(
3298
+ { ...newDetachId, target: CrossFieldTarget.Source },
3299
+ countToProcess,
3300
+ baseDetachEntry.value,
3301
+ );
3302
+
3303
+ this.invalidateBaseFields([baseDetachEntry.value]);
3304
+ } else {
3305
+ const baseDetachLocationEntry = this.table.baseChange.rootNodes.detachLocations.getFirst(
3306
+ baseDetachId,
3307
+ countToProcess,
3308
+ );
3309
+ countToProcess = baseDetachLocationEntry.length;
3310
+
3311
+ // These nodes were detached in the base change's input context,
3312
+ // so the net effect of the two changes is a rename.
3313
+ appendNodeRename(
3314
+ this.table.composedRootNodes,
3315
+ baseAttachId,
3316
+ newDetachId,
3317
+ baseDetachEntry.length,
3318
+ this.table.baseChange.rootNodes,
3319
+ baseDetachLocationEntry.value ?? this.fieldId,
3320
+ );
3321
+
3322
+ this.table.removedCrossFieldKeys.set(
3323
+ { ...newDetachId, target: CrossFieldTarget.Source },
3324
+ countToProcess,
3325
+ true,
3326
+ );
3327
+ }
3328
+
3329
+ if (newAttachEntry.value === undefined) {
3330
+ const newOutputDetachLocationEntry =
3331
+ this.table.newChange.rootNodes.outputDetachLocations.getFirst(
3332
+ newDetachId,
3333
+ countToProcess,
2580
3334
  );
2581
3335
 
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
- }
3336
+ countToProcess = newOutputDetachLocationEntry.length;
3337
+
3338
+ this.table.composedRootNodes.outputDetachLocations.set(
3339
+ newDetachId,
3340
+ countToProcess,
3341
+ newOutputDetachLocationEntry.value ?? this.fieldId,
3342
+ );
3343
+ }
3344
+
3345
+ if (countToProcess < count) {
3346
+ const remainingCount = count - countToProcess;
3347
+ this.composeAttachDetach(
3348
+ offsetChangeAtomId(baseAttachId, countToProcess),
3349
+ offsetChangeAtomId(newDetachId, countToProcess),
3350
+ remainingCount,
3351
+ );
2589
3352
  }
3353
+ }
3354
+
3355
+ public sendNewChangesToBaseSourceLocation(
3356
+ baseAttachId: ChangeAtomId,
3357
+ newChanges: NodeId,
3358
+ ): void {
3359
+ const { value: baseDetachId } = firstDetachIdFromAttachId(
3360
+ this.table.baseChange.rootNodes,
3361
+ baseAttachId,
3362
+ 1,
3363
+ );
3364
+
3365
+ const detachFields = getFieldsForCrossFieldKey(
3366
+ this.table.baseChange,
3367
+ {
3368
+ ...baseDetachId,
3369
+ target: CrossFieldTarget.Source,
3370
+ },
3371
+ 1,
3372
+ );
2590
3373
 
2591
- super.set(target, revision, id, count, newValue, invalidateDependents);
3374
+ if (detachFields.length > 0) {
3375
+ // The base attach is part of a move in the base changeset.
3376
+ const prevEntry = this.table.entries.getFirst(baseDetachId, 1).value ?? {};
3377
+ this.table.entries.set(baseDetachId, 1, { ...prevEntry, nodeChange: newChanges });
3378
+
3379
+ if (newChanges !== undefined) {
3380
+ this.invalidateBaseFields(detachFields);
3381
+ }
3382
+ } else {
3383
+ const baseNodeId = getFromChangeAtomIdMap(
3384
+ this.table.baseChange.rootNodes.nodeChanges,
3385
+ baseDetachId,
3386
+ );
3387
+
3388
+ if (baseNodeId !== undefined) {
3389
+ addNodesToCompose(this.table, baseNodeId, newChanges);
3390
+ } else {
3391
+ assignRootChange(
3392
+ this.table.composedRootNodes,
3393
+ this.table.movedNodeToParent,
3394
+ baseDetachId,
3395
+ newChanges,
3396
+ this.fieldId,
3397
+ this.table.rebaseVersion,
3398
+ );
3399
+ }
3400
+ }
2592
3401
  }
2593
3402
 
2594
- public override onMoveIn(id: ChangeAtomId): void {
2595
- setInChangeAtomIdMap(this.table.composedNodeToParent, id, this.fieldId);
3403
+ private areSameNodes(
3404
+ baseDetachId: ChangeAtomId,
3405
+ newAttachId: ChangeAtomId,
3406
+ count: number,
3407
+ ): RangeQueryResult<boolean> {
3408
+ const renamedDetachEntry = firstAttachIdFromDetachId(
3409
+ this.table.composedRootNodes,
3410
+ baseDetachId,
3411
+ count,
3412
+ );
3413
+
3414
+ const isReattachOfSameNodes = areEqualChangeAtomIds(renamedDetachEntry.value, newAttachId);
3415
+ return { ...renamedDetachEntry, value: isReattachOfSameNodes };
2596
3416
  }
2597
3417
 
2598
- public override moveKey(
2599
- target: CrossFieldTarget,
2600
- revision: RevisionTag | undefined,
2601
- id: ChangesetLocalId,
3418
+ public composeDetachAttach(
3419
+ baseDetachId: ChangeAtomId,
3420
+ newAttachId: ChangeAtomId,
2602
3421
  count: number,
3422
+ composeToPin: boolean,
2603
3423
  ): void {
2604
- throw new Error("Moving cross-field keys during compose is currently unsupported");
3424
+ const areSameEntry = this.areSameNodes(baseDetachId, newAttachId, count);
3425
+
3426
+ const countToProcess = areSameEntry.length;
3427
+ if (areSameEntry.value) {
3428
+ // These nodes have been moved back to their original location, so the composed changeset should not have any renames for them.
3429
+ // Note that deleting the rename from `this.table.composedRootNodes` would change the result of this method
3430
+ // if it were rerun due to the field being invalidated, so we instead record that the rename should be deleted later.
3431
+ this.table.renamesToDelete.set(baseDetachId, countToProcess, true);
3432
+ }
3433
+
3434
+ if (composeToPin) {
3435
+ this.table.movedCrossFieldKeys.set(
3436
+ { target: CrossFieldTarget.Source, ...newAttachId },
3437
+ countToProcess,
3438
+ this.fieldId,
3439
+ );
3440
+
3441
+ if (!areEqualChangeAtomIds(baseDetachId, newAttachId)) {
3442
+ // The pin will have `newAttachId` as both its detach and attach ID.
3443
+ // So we remove `baseDetachId` unless that is equal to the pin's detach ID.
3444
+ this.table.removedCrossFieldKeys.set(
3445
+ { target: CrossFieldTarget.Source, ...baseDetachId },
3446
+ countToProcess,
3447
+ true,
3448
+ );
3449
+ }
3450
+
3451
+ // Note that while change2 should already have this key, change1 may have a rollback for the same ID in a different location.
3452
+ // In that case, change1's attach should be canceled out by a detach from change2.
3453
+ // Here we make sure that the composed change has the correct location (this field) for the attach ID.
3454
+ this.table.movedCrossFieldKeys.set(
3455
+ { target: CrossFieldTarget.Destination, ...newAttachId },
3456
+ countToProcess,
3457
+ this.fieldId,
3458
+ );
3459
+ } else {
3460
+ this.table.removedCrossFieldKeys.set(
3461
+ { target: CrossFieldTarget.Source, ...baseDetachId },
3462
+ countToProcess,
3463
+ true,
3464
+ );
3465
+
3466
+ this.table.removedCrossFieldKeys.set(
3467
+ { target: CrossFieldTarget.Destination, ...newAttachId },
3468
+ countToProcess,
3469
+ true,
3470
+ );
3471
+ }
3472
+
3473
+ if (countToProcess < count) {
3474
+ this.composeAttachDetach(
3475
+ offsetChangeAtomId(baseDetachId, countToProcess),
3476
+ offsetChangeAtomId(newAttachId, countToProcess),
3477
+ count - countToProcess,
3478
+ );
3479
+ }
2605
3480
  }
2606
3481
 
2607
- private get table(): ComposeTable {
2608
- return this.crossFieldTable as ComposeTable;
3482
+ private invalidateBaseFields(fields: FieldId[]): void {
3483
+ if (this.allowInval) {
3484
+ for (const fieldId of fields) {
3485
+ this.table.pendingCompositions.affectedBaseFields.set(
3486
+ fieldIdKeyFromFieldId(fieldId),
3487
+ true,
3488
+ );
3489
+ }
3490
+ }
2609
3491
  }
2610
3492
  }
2611
3493
 
2612
3494
  function makeModularChangeset(
2613
3495
  props: {
3496
+ rebaseVersion?: RebaseVersion;
2614
3497
  fieldChanges?: FieldChangeMap;
2615
3498
  nodeChanges?: ChangeAtomIdBTree<NodeChangeset>;
2616
- nodeToParent?: ChangeAtomIdBTree<FieldId>;
3499
+ rootNodes?: RootNodeTable;
3500
+ nodeToParent?: ChangeAtomIdBTree<NodeLocation>;
2617
3501
  nodeAliases?: ChangeAtomIdBTree<NodeId>;
2618
3502
  crossFieldKeys?: CrossFieldKeyTable;
2619
3503
  maxId: number;
@@ -2628,11 +3512,13 @@ function makeModularChangeset(
2628
3512
  },
2629
3513
  ): ModularChangeset {
2630
3514
  const changeset: Mutable<ModularChangeset> = {
3515
+ rebaseVersion: props.rebaseVersion ?? 1,
2631
3516
  fieldChanges: props.fieldChanges ?? new Map(),
2632
3517
  nodeChanges: props.nodeChanges ?? newTupleBTree(),
3518
+ rootNodes: props.rootNodes ?? newRootTable(),
2633
3519
  nodeToParent: props.nodeToParent ?? newTupleBTree(),
2634
3520
  nodeAliases: props.nodeAliases ?? newTupleBTree(),
2635
- crossFieldKeys: props.crossFieldKeys ?? newCrossFieldKeyTable(),
3521
+ crossFieldKeys: props.crossFieldKeys ?? newCrossFieldRangeTable(),
2636
3522
  };
2637
3523
 
2638
3524
  if (props.revisions !== undefined && props.revisions.length > 0) {
@@ -2659,6 +3545,7 @@ function makeModularChangeset(
2659
3545
  if (props.refreshers !== undefined && props.refreshers.size > 0) {
2660
3546
  changeset.refreshers = props.refreshers;
2661
3547
  }
3548
+
2662
3549
  return changeset;
2663
3550
  }
2664
3551
 
@@ -2675,6 +3562,10 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2675
3562
  this.idAllocator = idAllocatorFromMaxId();
2676
3563
  }
2677
3564
 
3565
+ public isInTransaction(): boolean {
3566
+ return this.transactionDepth > 0;
3567
+ }
3568
+
2678
3569
  public override enterTransaction(): void {
2679
3570
  this.transactionDepth += 1;
2680
3571
  if (this.transactionDepth === 1) {
@@ -2729,7 +3620,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2729
3620
  * @param revision - the revision of the change
2730
3621
  */
2731
3622
  public submitChange(
2732
- field: FieldUpPath,
3623
+ field: NormalizedFieldUpPath,
2733
3624
  fieldKind: FieldKindIdentifier,
2734
3625
  change: FieldChangeset,
2735
3626
  revision: RevisionTag,
@@ -2743,7 +3634,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2743
3634
  fieldChange: { fieldKind, change },
2744
3635
  nodeChanges: newTupleBTree(),
2745
3636
  nodeToParent: newTupleBTree(),
2746
- crossFieldKeys: newCrossFieldKeyTable(),
3637
+ crossFieldKeys: newCrossFieldRangeTable(),
3638
+ rootNodes: newRootTable(),
2747
3639
  idAllocator: this.idAllocator,
2748
3640
  localCrossFieldKeys,
2749
3641
  revision,
@@ -2765,6 +3657,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2765
3657
  ? makeModularChangeset({
2766
3658
  maxId: this.idAllocator.getMaxId(),
2767
3659
  builds: change.builds,
3660
+ rootNodes: renameTableFromRenameDescriptions(change.renames ?? []),
2768
3661
  revisions: [{ revision: change.revision }],
2769
3662
  })
2770
3663
  : buildModularChangesetFromField({
@@ -2775,7 +3668,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2775
3668
  },
2776
3669
  nodeChanges: newTupleBTree(),
2777
3670
  nodeToParent: newTupleBTree(),
2778
- crossFieldKeys: newCrossFieldKeyTable(),
3671
+ crossFieldKeys: newCrossFieldRangeTable(),
3672
+ rootNodes: newRootTable(),
2779
3673
  idAllocator: this.idAllocator,
2780
3674
  localCrossFieldKeys: getChangeHandler(
2781
3675
  this.fieldKinds,
@@ -2802,7 +3696,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2802
3696
  return brand(this.idAllocator.allocate(count));
2803
3697
  }
2804
3698
 
2805
- public addNodeExistsConstraint(path: UpPath, revision: RevisionTag): void {
3699
+ public addNodeExistsConstraint(path: NormalizedUpPath, revision: RevisionTag): void {
2806
3700
  const nodeChange: NodeChangeset = {
2807
3701
  nodeExistsConstraint: { violated: false },
2808
3702
  };
@@ -2814,7 +3708,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2814
3708
  nodeChange,
2815
3709
  nodeChanges: newTupleBTree(),
2816
3710
  nodeToParent: newTupleBTree(),
2817
- crossFieldKeys: newCrossFieldKeyTable(),
3711
+ crossFieldKeys: newCrossFieldRangeTable(),
3712
+ rootNodes: newRootTable(),
2818
3713
  idAllocator: this.idAllocator,
2819
3714
  revision,
2820
3715
  }),
@@ -2823,7 +3718,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2823
3718
  );
2824
3719
  }
2825
3720
 
2826
- public addNodeExistsConstraintOnRevert(path: UpPath, revision: RevisionTag): void {
3721
+ public addNodeExistsConstraintOnRevert(path: NormalizedUpPath, revision: RevisionTag): void {
2827
3722
  const nodeChange: NodeChangeset = {
2828
3723
  nodeExistsConstraintOnRevert: { violated: false },
2829
3724
  };
@@ -2835,7 +3730,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2835
3730
  nodeChange,
2836
3731
  nodeChanges: newTupleBTree(),
2837
3732
  nodeToParent: newTupleBTree(),
2838
- crossFieldKeys: newCrossFieldKeyTable(),
3733
+ crossFieldKeys: newCrossFieldRangeTable(),
3734
+ rootNodes: newRootTable(),
2839
3735
  idAllocator: this.idAllocator,
2840
3736
  revision,
2841
3737
  }),
@@ -2845,12 +3741,13 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2845
3741
  }
2846
3742
  }
2847
3743
 
2848
- function buildModularChangesetFromField(props: {
2849
- path: FieldUpPath;
3744
+ export function buildModularChangesetFromField(props: {
3745
+ path: NormalizedFieldUpPath;
2850
3746
  fieldChange: FieldChange;
2851
3747
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
2852
- nodeToParent: ChangeAtomIdBTree<FieldId>;
3748
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>;
2853
3749
  crossFieldKeys: CrossFieldKeyTable;
3750
+ rootNodes: RootNodeTable;
2854
3751
  localCrossFieldKeys?: CrossFieldKeyRange[];
2855
3752
  revision: RevisionTag;
2856
3753
  idAllocator?: IdAllocator;
@@ -2862,6 +3759,7 @@ function buildModularChangesetFromField(props: {
2862
3759
  nodeChanges,
2863
3760
  nodeToParent,
2864
3761
  crossFieldKeys,
3762
+ rootNodes,
2865
3763
  idAllocator = idAllocatorFromMaxId(),
2866
3764
  localCrossFieldKeys = [],
2867
3765
  childId,
@@ -2870,14 +3768,17 @@ function buildModularChangesetFromField(props: {
2870
3768
  const fieldChanges: FieldChangeMap = new Map([[path.field, fieldChange]]);
2871
3769
 
2872
3770
  if (path.parent === undefined) {
3771
+ const field = { nodeId: undefined, field: path.field };
2873
3772
  for (const { key, count } of localCrossFieldKeys) {
2874
- crossFieldKeys.set(key, count, { nodeId: undefined, field: path.field });
3773
+ crossFieldKeys.set(key, count, field);
2875
3774
  }
2876
3775
 
2877
3776
  if (childId !== undefined) {
2878
3777
  setInChangeAtomIdMap(nodeToParent, childId, {
2879
- nodeId: undefined,
2880
- field: path.field,
3778
+ field: {
3779
+ nodeId: undefined,
3780
+ field: path.field,
3781
+ },
2881
3782
  });
2882
3783
  }
2883
3784
 
@@ -2886,6 +3787,7 @@ function buildModularChangesetFromField(props: {
2886
3787
  nodeChanges,
2887
3788
  nodeToParent,
2888
3789
  crossFieldKeys,
3790
+ rootNodes,
2889
3791
  maxId: idAllocator.getMaxId(),
2890
3792
  revisions: [{ revision }],
2891
3793
  });
@@ -2896,6 +3798,7 @@ function buildModularChangesetFromField(props: {
2896
3798
  };
2897
3799
 
2898
3800
  const parentId: NodeId = { localId: brand(idAllocator.allocate()), revision };
3801
+ const fieldId = { nodeId: parentId, field: path.field };
2899
3802
 
2900
3803
  for (const { key, count } of localCrossFieldKeys) {
2901
3804
  crossFieldKeys.set(key, count, { nodeId: parentId, field: path.field });
@@ -2903,8 +3806,7 @@ function buildModularChangesetFromField(props: {
2903
3806
 
2904
3807
  if (childId !== undefined) {
2905
3808
  setInChangeAtomIdMap(nodeToParent, childId, {
2906
- nodeId: parentId,
2907
- field: path.field,
3809
+ field: fieldId,
2908
3810
  });
2909
3811
  }
2910
3812
 
@@ -2914,6 +3816,7 @@ function buildModularChangesetFromField(props: {
2914
3816
  nodeChanges,
2915
3817
  nodeToParent,
2916
3818
  crossFieldKeys,
3819
+ rootNodes,
2917
3820
  idAllocator,
2918
3821
  revision,
2919
3822
  nodeId: parentId,
@@ -2921,11 +3824,12 @@ function buildModularChangesetFromField(props: {
2921
3824
  }
2922
3825
 
2923
3826
  function buildModularChangesetFromNode(props: {
2924
- path: UpPath;
3827
+ path: NormalizedUpPath;
2925
3828
  nodeChange: NodeChangeset;
2926
3829
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
2927
- nodeToParent: ChangeAtomIdBTree<FieldId>;
3830
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>;
2928
3831
  crossFieldKeys: CrossFieldKeyTable;
3832
+ rootNodes: RootNodeTable;
2929
3833
  idAllocator: IdAllocator;
2930
3834
  revision: RevisionTag;
2931
3835
  nodeId?: NodeId;
@@ -2935,27 +3839,43 @@ function buildModularChangesetFromNode(props: {
2935
3839
  nodeId = { localId: brand(props.idAllocator.allocate()), revision: props.revision },
2936
3840
  } = props;
2937
3841
  setInChangeAtomIdMap(props.nodeChanges, nodeId, props.nodeChange);
2938
- const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChanges([
2939
- [path.parentIndex, nodeId],
2940
- ]);
2941
3842
 
2942
- const fieldChange: FieldChange = {
2943
- fieldKind: genericFieldKind.identifier,
2944
- change: fieldChangeset,
2945
- };
3843
+ if (isDetachedUpPathRoot(path)) {
3844
+ props.rootNodes.nodeChanges.set(
3845
+ [path.detachedNodeId.major, brand(path.detachedNodeId.minor)],
3846
+ nodeId,
3847
+ );
3848
+ return makeModularChangeset({
3849
+ rootNodes: props.rootNodes,
3850
+ nodeChanges: props.nodeChanges,
3851
+ nodeToParent: props.nodeToParent,
3852
+ crossFieldKeys: props.crossFieldKeys,
3853
+ maxId: props.idAllocator.getMaxId(),
3854
+ revisions: [{ revision: props.revision }],
3855
+ });
3856
+ } else {
3857
+ const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChanges([
3858
+ [path.parentIndex, nodeId],
3859
+ ]);
2946
3860
 
2947
- return buildModularChangesetFromField({
2948
- ...props,
2949
- path: { parent: path.parent, field: path.parentField },
2950
- fieldChange,
2951
- localCrossFieldKeys: [],
2952
- childId: nodeId,
2953
- });
3861
+ const fieldChange: FieldChange = {
3862
+ fieldKind: genericFieldKind.identifier,
3863
+ change: fieldChangeset,
3864
+ };
3865
+
3866
+ return buildModularChangesetFromField({
3867
+ ...props,
3868
+ path: { parent: path.parent, field: path.parentField },
3869
+ fieldChange,
3870
+ localCrossFieldKeys: [],
3871
+ childId: nodeId,
3872
+ });
3873
+ }
2954
3874
  }
2955
3875
 
2956
3876
  export interface FieldEditDescription {
2957
3877
  type: "field";
2958
- field: FieldUpPath;
3878
+ field: NormalizedFieldUpPath;
2959
3879
  fieldKind: FieldKindIdentifier;
2960
3880
  change: FieldChangeset;
2961
3881
  revision: RevisionTag;
@@ -2965,6 +3885,23 @@ export interface GlobalEditDescription {
2965
3885
  type: "global";
2966
3886
  revision: RevisionTag;
2967
3887
  builds?: ChangeAtomIdBTree<TreeChunk>;
3888
+ renames?: RenameDescription[];
3889
+ }
3890
+
3891
+ export interface RenameDescription {
3892
+ count: number;
3893
+ oldId: ChangeAtomId;
3894
+ newId: ChangeAtomId;
3895
+ detachLocation: FieldId | undefined;
3896
+ }
3897
+
3898
+ function renameTableFromRenameDescriptions(renames: RenameDescription[]): RootNodeTable {
3899
+ const table = newRootTable();
3900
+ for (const rename of renames) {
3901
+ addNodeRename(table, rename.oldId, rename.newId, rename.count, rename.detachLocation);
3902
+ }
3903
+
3904
+ return table;
2968
3905
  }
2969
3906
 
2970
3907
  export type EditDescription = FieldEditDescription | GlobalEditDescription;
@@ -2981,22 +3918,6 @@ function getRevInfoFromTaggedChanges(changes: TaggedChange<ModularChangeset>[]):
2981
3918
  revInfos.push(...revisionInfoFromTaggedChange(taggedChange));
2982
3919
  }
2983
3920
 
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
3921
  return { maxId: brand(maxId), revInfos };
3001
3922
  }
3002
3923
 
@@ -3016,25 +3937,28 @@ function revisionInfoFromTaggedChange(
3016
3937
  return revInfos;
3017
3938
  }
3018
3939
 
3019
- function fieldChangeFromId(
3020
- fields: FieldChangeMap,
3021
- nodes: ChangeAtomIdBTree<NodeChangeset>,
3022
- id: FieldId,
3023
- ): FieldChange {
3024
- const fieldMap = fieldMapFromNodeId(fields, nodes, id.nodeId);
3940
+ function fieldChangeFromId(change: ModularChangeset, id: FieldId): FieldChange {
3941
+ const fieldId = normalizeFieldId(id, change.nodeAliases);
3942
+ const fieldMap = fieldMapFromNodeId(
3943
+ change.fieldChanges,
3944
+ change.nodeChanges,
3945
+ change.nodeAliases,
3946
+ fieldId.nodeId,
3947
+ );
3025
3948
  return fieldMap.get(id.field) ?? fail(0xb25 /* No field exists for the given ID */);
3026
3949
  }
3027
3950
 
3028
3951
  function fieldMapFromNodeId(
3029
3952
  rootFieldMap: FieldChangeMap,
3030
3953
  nodes: ChangeAtomIdBTree<NodeChangeset>,
3954
+ aliases: ChangeAtomIdBTree<NodeId>,
3031
3955
  nodeId: NodeId | undefined,
3032
3956
  ): FieldChangeMap {
3033
3957
  if (nodeId === undefined) {
3034
3958
  return rootFieldMap;
3035
3959
  }
3036
3960
 
3037
- const node = nodeChangeFromId(nodes, nodeId);
3961
+ const node = nodeChangeFromId(nodes, aliases, nodeId);
3038
3962
  assert(node.fieldChanges !== undefined, 0x9c9 /* Expected node to have field changes */);
3039
3963
  return node.fieldChanges;
3040
3964
  }
@@ -3051,8 +3975,13 @@ function rebasedNodeIdFromBaseNodeId(table: RebaseTable, baseId: NodeId): NodeId
3051
3975
  return getFromChangeAtomIdMap(table.baseToRebasedNodeId, baseId) ?? baseId;
3052
3976
  }
3053
3977
 
3054
- function nodeChangeFromId(nodes: ChangeAtomIdBTree<NodeChangeset>, id: NodeId): NodeChangeset {
3055
- const node = getFromChangeAtomIdMap(nodes, id);
3978
+ function nodeChangeFromId(
3979
+ nodes: ChangeAtomIdBTree<NodeChangeset>,
3980
+ aliases: ChangeAtomIdBTree<NodeId>,
3981
+ id: NodeId,
3982
+ ): NodeChangeset {
3983
+ const normalizedId = normalizeNodeId(id, aliases);
3984
+ const node = getFromChangeAtomIdMap(nodes, normalizedId);
3056
3985
  assert(node !== undefined, 0x9ca /* Unknown node ID */);
3057
3986
  return node;
3058
3987
  }
@@ -3062,6 +3991,10 @@ function fieldIdFromFieldIdKey([revision, localId, field]: FieldIdKey): FieldId
3062
3991
  return { nodeId, field };
3063
3992
  }
3064
3993
 
3994
+ function fieldIdKeyFromFieldId(fieldId: FieldId): FieldIdKey {
3995
+ return [fieldId.nodeId?.revision, fieldId.nodeId?.localId, fieldId.field];
3996
+ }
3997
+
3065
3998
  function cloneNodeChangeset(nodeChangeset: NodeChangeset): NodeChangeset {
3066
3999
  if (nodeChangeset.fieldChanges !== undefined) {
3067
4000
  return { ...nodeChangeset, fieldChanges: new Map(nodeChangeset.fieldChanges) };
@@ -3070,6 +4003,16 @@ function cloneNodeChangeset(nodeChangeset: NodeChangeset): NodeChangeset {
3070
4003
  return { ...nodeChangeset };
3071
4004
  }
3072
4005
 
4006
+ function replaceNodeLocationRevision(
4007
+ location: NodeLocation,
4008
+ oldRevisions: Set<RevisionTag | undefined>,
4009
+ newRevision: RevisionTag | undefined,
4010
+ ): NodeLocation {
4011
+ return location.field !== undefined
4012
+ ? { field: replaceFieldIdRevision(location.field, oldRevisions, newRevision) }
4013
+ : { root: replaceAtomRevisions(location.root, oldRevisions, newRevision) };
4014
+ }
4015
+
3073
4016
  function replaceFieldIdRevision(
3074
4017
  fieldId: FieldId,
3075
4018
  oldRevisions: Set<RevisionTag | undefined>,
@@ -3085,10 +4028,16 @@ function replaceFieldIdRevision(
3085
4028
  };
3086
4029
  }
3087
4030
 
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);
4031
+ export function getNodeParent(changeset: ModularChangeset, nodeId: NodeId): NodeLocation {
4032
+ const normalizedNodeId = normalizeNodeId(nodeId, changeset.nodeAliases);
4033
+ const location = getFromChangeAtomIdMap(changeset.nodeToParent, normalizedNodeId);
4034
+ assert(location !== undefined, 0x9cb /* Parent field should be defined */);
4035
+
4036
+ if (location.field !== undefined) {
4037
+ return { field: normalizeFieldId(location.field, changeset.nodeAliases) };
4038
+ }
4039
+
4040
+ return location;
3092
4041
  }
3093
4042
 
3094
4043
  function getFieldsForCrossFieldKey(
@@ -3101,6 +4050,30 @@ function getFieldsForCrossFieldKey(
3101
4050
  .map(({ value: fieldId }) => normalizeFieldId(fieldId, changeset.nodeAliases));
3102
4051
  }
3103
4052
 
4053
+ function getFirstFieldForCrossFieldKey(
4054
+ changeset: ModularChangeset,
4055
+ key: CrossFieldKey,
4056
+ count: number,
4057
+ ): RangeQueryResult<FieldId | undefined> {
4058
+ const result = changeset.crossFieldKeys.getFirst(key, count);
4059
+ if (result.value === undefined) {
4060
+ return result;
4061
+ }
4062
+
4063
+ return { ...result, value: normalizeFieldId(result.value, changeset.nodeAliases) };
4064
+ }
4065
+
4066
+ function normalizeNodeLocation(
4067
+ location: NodeLocation,
4068
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4069
+ ): NodeLocation {
4070
+ if (location.field !== undefined) {
4071
+ return { field: normalizeFieldId(location.field, nodeAliases) };
4072
+ }
4073
+
4074
+ return location;
4075
+ }
4076
+
3104
4077
  // This is only exported for use in test utilities.
3105
4078
  export function normalizeFieldId(
3106
4079
  fieldId: FieldId,
@@ -3114,8 +4087,12 @@ export function normalizeFieldId(
3114
4087
  /**
3115
4088
  * @returns The canonical form of nodeId, according to nodeAliases
3116
4089
  */
3117
- function normalizeNodeId(nodeId: NodeId, nodeAliases: ChangeAtomIdBTree<NodeId>): NodeId {
4090
+ export function normalizeNodeId(
4091
+ nodeId: NodeId,
4092
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4093
+ ): NodeId {
3118
4094
  let currentId = nodeId;
4095
+ let cycleProbeId: NodeId | undefined = nodeId;
3119
4096
 
3120
4097
  // eslint-disable-next-line no-constant-condition
3121
4098
  while (true) {
@@ -3125,6 +4102,16 @@ function normalizeNodeId(nodeId: NodeId, nodeAliases: ChangeAtomIdBTree<NodeId>)
3125
4102
  }
3126
4103
 
3127
4104
  currentId = dealiased;
4105
+
4106
+ if (cycleProbeId !== undefined) {
4107
+ cycleProbeId = getFromChangeAtomIdMap(nodeAliases, cycleProbeId);
4108
+ }
4109
+
4110
+ if (cycleProbeId !== undefined) {
4111
+ cycleProbeId = getFromChangeAtomIdMap(nodeAliases, cycleProbeId);
4112
+ }
4113
+
4114
+ assert(!areEqualChangeAtomIdOpts(cycleProbeId, currentId), "Alias cycle detected");
3128
4115
  }
3129
4116
  }
3130
4117
 
@@ -3135,22 +4122,835 @@ function hasConflicts(change: ModularChangeset): boolean {
3135
4122
  interface ModularChangesetContent {
3136
4123
  fieldChanges: FieldChangeMap;
3137
4124
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
3138
- nodeToParent: ChangeAtomIdBTree<FieldId>;
4125
+ nodeToParent: ChangeAtomIdBTree<NodeLocation>;
4126
+ rootNodes: RootNodeTable;
3139
4127
  nodeAliases: ChangeAtomIdBTree<NodeId>;
3140
4128
  crossFieldKeys: CrossFieldKeyTable;
3141
4129
  }
3142
4130
 
3143
- function getFromChangeAtomIdMap<T>(
3144
- map: ChangeAtomIdBTree<T>,
3145
- id: ChangeAtomId,
3146
- ): T | undefined {
3147
- return map.get([id.revision, id.localId]);
4131
+ function areEqualFieldIds(a: FieldId, b: FieldId): boolean {
4132
+ return areEqualChangeAtomIdOpts(a.nodeId, b.nodeId) && a.field === b.field;
3148
4133
  }
3149
4134
 
3150
- function setInChangeAtomIdMap<T>(map: ChangeAtomIdBTree<T>, id: ChangeAtomId, value: T): void {
3151
- map.set([id.revision, id.localId], value);
4135
+ function firstAttachIdFromDetachId(
4136
+ roots: RootNodeTable,
4137
+ detachId: ChangeAtomId,
4138
+ count: number,
4139
+ ): RangeQueryResult<ChangeAtomId> {
4140
+ const result = roots.oldToNewId.getFirst(detachId, count);
4141
+ return { ...result, value: result.value ?? detachId };
3152
4142
  }
3153
4143
 
3154
- function areEqualFieldIds(a: FieldId, b: FieldId): boolean {
3155
- return areEqualChangeAtomIdOpts(a.nodeId, b.nodeId) && a.field === b.field;
4144
+ function firstDetachIdFromAttachId(
4145
+ roots: RootNodeTable,
4146
+ attachId: ChangeAtomId,
4147
+ count: number,
4148
+ ): RangeQueryEntry<ChangeAtomId, ChangeAtomId> {
4149
+ const result = roots.newToOldId.getFirst(attachId, count);
4150
+ return { ...result, start: attachId, value: result.value ?? attachId };
4151
+ }
4152
+
4153
+ function rebaseCrossFieldKeys(
4154
+ sourceTable: CrossFieldKeyTable,
4155
+ movedDetaches: ChangeAtomIdRangeMap<boolean>,
4156
+ newDetachLocations: ChangeAtomIdRangeMap<FieldId>,
4157
+ ): CrossFieldKeyTable {
4158
+ const rebasedTable = sourceTable.clone();
4159
+ for (const entry of movedDetaches.entries()) {
4160
+ rebasedTable.delete({ ...entry.start, target: CrossFieldTarget.Source }, entry.length);
4161
+ }
4162
+
4163
+ for (const entry of newDetachLocations.entries()) {
4164
+ rebasedTable.set(
4165
+ { ...entry.start, target: CrossFieldTarget.Source },
4166
+ entry.length,
4167
+ entry.value,
4168
+ );
4169
+ }
4170
+
4171
+ return rebasedTable;
4172
+ }
4173
+
4174
+ export function newRootTable(): RootNodeTable {
4175
+ return {
4176
+ newToOldId: newChangeAtomIdTransform(),
4177
+ oldToNewId: newChangeAtomIdTransform(),
4178
+ nodeChanges: newTupleBTree(),
4179
+ detachLocations: newChangeAtomIdRangeMap(),
4180
+ outputDetachLocations: newChangeAtomIdRangeMap(),
4181
+ };
4182
+ }
4183
+
4184
+ function rebaseRoots(
4185
+ change: ModularChangeset,
4186
+ base: ModularChangeset,
4187
+ affectedBaseFields: TupleBTree<FieldIdKey, boolean>,
4188
+ nodesToRebase: [newChangeset: NodeId, baseChangeset: NodeId][],
4189
+ rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
4190
+ rebaseVersion: RebaseVersion,
4191
+ ): RootNodeTable {
4192
+ const rebasedRoots = newRootTable();
4193
+ for (const renameEntry of change.rootNodes.oldToNewId.entries()) {
4194
+ rebaseRename(change.rootNodes, rebasedRoots, renameEntry, base, affectedBaseFields);
4195
+ }
4196
+
4197
+ for (const [detachIdKey, nodeId] of change.rootNodes.nodeChanges.entries()) {
4198
+ const changes = base.rootNodes.nodeChanges.get(detachIdKey);
4199
+ if (changes !== undefined) {
4200
+ nodesToRebase.push([nodeId, changes]);
4201
+ }
4202
+
4203
+ const detachId = makeChangeAtomId(detachIdKey[1], detachIdKey[0]);
4204
+ const attachId = firstAttachIdFromDetachId(base.rootNodes, detachId, 1).value;
4205
+ const baseAttachEntry = base.crossFieldKeys.getFirst(
4206
+ { target: CrossFieldTarget.Destination, ...attachId },
4207
+ 1,
4208
+ );
4209
+ if (baseAttachEntry.value !== undefined) {
4210
+ affectedBaseFields.set(fieldIdKeyFromFieldId(baseAttachEntry.value), true);
4211
+ rebasedNodeToParent.delete(detachIdKey);
4212
+ } else {
4213
+ const renamedDetachId = firstAttachIdFromDetachId(base.rootNodes, detachId, 1).value;
4214
+ const baseOutputDetachLocation = base.rootNodes.outputDetachLocations.getFirst(
4215
+ renamedDetachId,
4216
+ 1,
4217
+ ).value;
4218
+
4219
+ if (baseOutputDetachLocation !== undefined) {
4220
+ affectedBaseFields.set(fieldIdKeyFromFieldId(baseOutputDetachLocation), true);
4221
+ }
4222
+
4223
+ const detachLocation =
4224
+ baseOutputDetachLocation ??
4225
+ change.rootNodes.detachLocations.getFirst(detachId, 1).value;
4226
+
4227
+ // Note that `baseOutputDetachLocation` may contain a node ID from the base changeset.
4228
+ // We will replace the detach location entry with the node ID from the rebased changeset in `fixupRebasedDetachLocations`
4229
+ assignRootChange(
4230
+ rebasedRoots,
4231
+ rebasedNodeToParent,
4232
+ renamedDetachId,
4233
+ nodeId,
4234
+ detachLocation,
4235
+ rebaseVersion,
4236
+ );
4237
+ }
4238
+ }
4239
+
4240
+ for (const entry of change.rootNodes.outputDetachLocations.entries()) {
4241
+ rebasedRoots.outputDetachLocations.set(entry.start, entry.length, entry.value);
4242
+ }
4243
+
4244
+ return rebasedRoots;
4245
+ }
4246
+
4247
+ function rebaseRename(
4248
+ newRoots: RootNodeTable,
4249
+ rebasedRoots: RootNodeTable,
4250
+ renameEntry: RangeQueryEntry<ChangeAtomId, ChangeAtomId>,
4251
+ base: ModularChangeset,
4252
+ affectedBaseFields: TupleBTree<FieldIdKey, boolean>,
4253
+ ): void {
4254
+ let count = renameEntry.length;
4255
+ const baseRenameEntry = firstAttachIdFromDetachId(base.rootNodes, renameEntry.start, count);
4256
+ count = baseRenameEntry.length;
4257
+
4258
+ const baseAttachEntry = base.crossFieldKeys.getFirst(
4259
+ {
4260
+ ...baseRenameEntry.value,
4261
+ target: CrossFieldTarget.Destination,
4262
+ },
4263
+ count,
4264
+ );
4265
+
4266
+ count = baseAttachEntry.length;
4267
+
4268
+ if (baseAttachEntry.value !== undefined) {
4269
+ // This rename represents an intention to detach these nodes.
4270
+ // The rebased change should have a detach in the field where the base change attaches the nodes,
4271
+ // so we need to ensure that field is processed.
4272
+ affectedBaseFields.set(
4273
+ fieldIdKeyFromFieldId(normalizeFieldId(baseAttachEntry.value, base.nodeAliases)),
4274
+ true,
4275
+ );
4276
+ } else {
4277
+ const baseOutputDetachLocation = base.rootNodes.outputDetachLocations.getFirst(
4278
+ baseRenameEntry.value,
4279
+ 1,
4280
+ ).value;
4281
+
4282
+ if (baseOutputDetachLocation !== undefined) {
4283
+ affectedBaseFields.set(fieldIdKeyFromFieldId(baseOutputDetachLocation), true);
4284
+ }
4285
+
4286
+ const detachEntry = newRoots.detachLocations.getFirst(renameEntry.start, count);
4287
+ count = detachEntry.length;
4288
+
4289
+ const detachLocation = baseOutputDetachLocation ?? detachEntry.value;
4290
+
4291
+ // Note that `baseOutputDetachLocation` may contain a node ID from the base changeset.
4292
+ // We will replace the detach location entry with the node ID from the rebased changeset in `fixupRebasedDetachLocations`
4293
+ addNodeRename(
4294
+ rebasedRoots,
4295
+ baseRenameEntry.value,
4296
+ renameEntry.value,
4297
+ count,
4298
+ detachLocation,
4299
+ );
4300
+ }
4301
+
4302
+ const countRemaining = renameEntry.length - count;
4303
+ if (countRemaining > 0) {
4304
+ rebaseRename(
4305
+ newRoots,
4306
+ rebasedRoots,
4307
+ {
4308
+ start: offsetChangeAtomId(renameEntry.start, count),
4309
+ value: offsetChangeAtomId(renameEntry.value, count),
4310
+ length: countRemaining,
4311
+ },
4312
+ base,
4313
+ affectedBaseFields,
4314
+ );
4315
+ }
4316
+ }
4317
+
4318
+ /**
4319
+ * For each root detach location, replaces any node ID from the base changeset
4320
+ * with the corresponding ID in the new changeset.
4321
+ */
4322
+ function fixupRebasedDetachLocations(table: RebaseTable): void {
4323
+ for (const {
4324
+ start,
4325
+ length,
4326
+ value: detachLocation,
4327
+ } of table.rebasedRootNodes.detachLocations.entries()) {
4328
+ const normalizedDetachLocation = normalizeFieldId(
4329
+ detachLocation,
4330
+ table.baseChange.nodeAliases,
4331
+ );
4332
+
4333
+ if (normalizedDetachLocation.nodeId !== undefined) {
4334
+ const rebasedNodeId = getFromChangeAtomIdMap(
4335
+ table.baseToRebasedNodeId,
4336
+ normalizedDetachLocation.nodeId,
4337
+ );
4338
+
4339
+ if (rebasedNodeId !== undefined) {
4340
+ table.rebasedRootNodes.detachLocations.set(start, length, {
4341
+ ...normalizedDetachLocation,
4342
+ nodeId: rebasedNodeId,
4343
+ });
4344
+ }
4345
+ }
4346
+ }
4347
+ }
4348
+
4349
+ function addNodesToCompose(table: ComposeTable, id1: NodeId, id2: NodeId): void {
4350
+ const normalizedId1 = normalizeNodeId(id1, table.baseChange.nodeAliases);
4351
+ const normalizedId2 = normalizeNodeId(id2, table.newChange.nodeAliases);
4352
+ if (getFromChangeAtomIdMap(table.newToBaseNodeId, normalizedId2) === undefined) {
4353
+ setInChangeAtomIdMap(table.newToBaseNodeId, normalizedId2, normalizedId1);
4354
+ table.pendingCompositions.nodeIdsToCompose.push([normalizedId1, normalizedId2]);
4355
+ }
4356
+ }
4357
+
4358
+ function composeRevInfos(
4359
+ revisions1: readonly RevisionInfo[] | undefined,
4360
+ revisions2: readonly RevisionInfo[] | undefined,
4361
+ ): RevisionInfo[] {
4362
+ const result: RevisionInfo[] = [...(revisions1 ?? []), ...(revisions2 ?? [])];
4363
+ return result;
4364
+ }
4365
+
4366
+ function composeCrossFieldKeyTables(
4367
+ table1: CrossFieldKeyTable,
4368
+ table2: CrossFieldKeyTable,
4369
+ movedCrossFieldKeys: CrossFieldKeyTable,
4370
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
4371
+ ): CrossFieldKeyTable {
4372
+ const composedTable = RangeMap.union(table1, table2);
4373
+ for (const entry of movedCrossFieldKeys.entries()) {
4374
+ composedTable.set(entry.start, entry.length, entry.value);
4375
+ }
4376
+
4377
+ for (const entry of removedCrossFieldKeys.entries()) {
4378
+ composedTable.delete(entry.start, entry.length);
4379
+ }
4380
+
4381
+ return composedTable;
4382
+ }
4383
+
4384
+ function composeRootTables(
4385
+ change1: ModularChangeset,
4386
+ change2: ModularChangeset,
4387
+ composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
4388
+ movedCrossFieldKeys: CrossFieldKeyTable,
4389
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
4390
+ pendingCompositions: PendingCompositions,
4391
+ ): RootNodeTable {
4392
+ const composedTable = cloneRootTable(change1.rootNodes);
4393
+
4394
+ for (const renameEntry of change2.rootNodes.oldToNewId.entries()) {
4395
+ composeRename(
4396
+ change1,
4397
+ change2,
4398
+ composedTable,
4399
+ renameEntry.start,
4400
+ renameEntry.value,
4401
+ renameEntry.length,
4402
+ movedCrossFieldKeys,
4403
+ removedCrossFieldKeys,
4404
+ pendingCompositions,
4405
+ );
4406
+ }
4407
+
4408
+ for (const [[revision2, id2], nodeId2] of change2.rootNodes.nodeChanges.entries()) {
4409
+ const detachId2 = { revision: revision2, localId: id2 };
4410
+ const detachId1 = firstDetachIdFromAttachId(change1.rootNodes, detachId2, 1).value;
4411
+ const nodeId1 = getFromChangeAtomIdMap(change1.rootNodes.nodeChanges, detachId1);
4412
+
4413
+ if (nodeId1 !== undefined) {
4414
+ pendingCompositions.nodeIdsToCompose.push([nodeId1, nodeId2]);
4415
+ } else {
4416
+ const fieldId = getFieldsForCrossFieldKey(
4417
+ change1,
4418
+ { ...detachId1, target: CrossFieldTarget.Source },
4419
+ 1,
4420
+ )[0];
4421
+
4422
+ if (fieldId !== undefined) {
4423
+ // In this case, this node is attached in the input context of change1,
4424
+ // and is represented in detachFieldId.
4425
+ pendingCompositions.affectedBaseFields.set(
4426
+ [fieldId.nodeId?.revision, fieldId.nodeId?.localId, fieldId.field],
4427
+ true,
4428
+ );
4429
+ } else {
4430
+ assignRootChange(
4431
+ composedTable,
4432
+ composedNodeToParent,
4433
+ detachId1,
4434
+ nodeId2,
4435
+ change1.rootNodes.detachLocations.getFirst(detachId1, 1).value ??
4436
+ change2.rootNodes.detachLocations.getFirst(detachId2, 1).value,
4437
+ Math.max(change1.rebaseVersion, change2.rebaseVersion) as RebaseVersion,
4438
+ );
4439
+ }
4440
+ }
4441
+ }
4442
+
4443
+ for (const outputDetachEntry of change1.rootNodes.outputDetachLocations.entries()) {
4444
+ composeOutputDetachLocation(
4445
+ outputDetachEntry.start,
4446
+ outputDetachEntry.length,
4447
+ outputDetachEntry.value,
4448
+ change2,
4449
+ composedTable,
4450
+ );
4451
+ }
4452
+
4453
+ for (const entry of change2.rootNodes.outputDetachLocations.entries()) {
4454
+ composedTable.outputDetachLocations.set(entry.start, entry.length, entry.value);
4455
+ }
4456
+
4457
+ return composedTable;
4458
+ }
4459
+
4460
+ function composeOutputDetachLocation(
4461
+ outputDetachId1: ChangeAtomId,
4462
+ count: number,
4463
+ detachLocation: FieldId,
4464
+ change2: ModularChangeset,
4465
+ composedTable: RootNodeTable,
4466
+ ): void {
4467
+ let countToProcess = count;
4468
+ const renameEntry = firstAttachIdFromDetachId(
4469
+ change2.rootNodes,
4470
+ outputDetachId1,
4471
+ countToProcess,
4472
+ );
4473
+ countToProcess = renameEntry.length;
4474
+
4475
+ const attachEntry = getFirstAttachField(
4476
+ change2.crossFieldKeys,
4477
+ renameEntry.value,
4478
+ countToProcess,
4479
+ );
4480
+ countToProcess = attachEntry.length;
4481
+
4482
+ composedTable.outputDetachLocations.delete(outputDetachId1, countToProcess);
4483
+
4484
+ if (attachEntry.value === undefined) {
4485
+ // We update the key for the detach location to the renamed ID of the root in the composed output context.
4486
+ composedTable.outputDetachLocations.set(renameEntry.value, countToProcess, detachLocation);
4487
+ } else {
4488
+ // These nodes are attached by `change2` and thus attached in the composed output context,
4489
+ // so there should be no output detach location.
4490
+ }
4491
+
4492
+ const countRemaining = count - countToProcess;
4493
+ if (countRemaining > 0) {
4494
+ composeOutputDetachLocation(
4495
+ offsetChangeAtomId(outputDetachId1, countToProcess),
4496
+ countRemaining,
4497
+ detachLocation,
4498
+ change2,
4499
+ composedTable,
4500
+ );
4501
+ }
4502
+ }
4503
+
4504
+ function composeRename(
4505
+ change1: ModularChangeset,
4506
+ change2: ModularChangeset,
4507
+ mergedTable: RootNodeTable,
4508
+ oldId: ChangeAtomId,
4509
+ newId: ChangeAtomId,
4510
+ count: number,
4511
+ movedCrossFieldKeys: CrossFieldKeyTable,
4512
+ removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
4513
+ pendingCompositions: PendingCompositions,
4514
+ ): void {
4515
+ let countToProcess = count;
4516
+ const detachEntry = getFirstDetachField(change1.crossFieldKeys, oldId, countToProcess);
4517
+ countToProcess = detachEntry.length;
4518
+
4519
+ if (detachEntry.value !== undefined) {
4520
+ // `change1` detached these nodes,
4521
+ // so we invalidate the detach location so that the detach's ID can be replaced with the new ID.
4522
+ pendingCompositions.affectedBaseFields.set(fieldIdKeyFromFieldId(detachEntry.value), true);
4523
+
4524
+ if (!areEqualChangeAtomIds(oldId, newId)) {
4525
+ // `change1`'s detach will be replaced by `change2`'s detach, so we update the cross-field keys.
4526
+ removedCrossFieldKeys.set(
4527
+ { ...oldId, target: CrossFieldTarget.Source },
4528
+ countToProcess,
4529
+ true,
4530
+ );
4531
+ }
4532
+
4533
+ movedCrossFieldKeys.set(
4534
+ { ...newId, target: CrossFieldTarget.Source },
4535
+ countToProcess,
4536
+ detachEntry.value,
4537
+ );
4538
+ } else {
4539
+ // `change1` may also have a rename to `renameEntry.value`, in which case it must refer to a different node.
4540
+ // That node must have been attached by `change1` and detached by `change2`.
4541
+ // The final rename for that node will be created in `composeAttachDetach`.
4542
+ // We delete any such rename for now to avoid colliding with the rename currently being processed.
4543
+ deleteNodeRenameTo(mergedTable, newId, countToProcess);
4544
+
4545
+ // The nodes were detached before `change`, so we append this rename.
4546
+ appendNodeRename(
4547
+ mergedTable,
4548
+ oldId,
4549
+ newId,
4550
+ countToProcess,
4551
+ change1.rootNodes,
4552
+ change2.rootNodes.detachLocations.getFirst(oldId, countToProcess).value,
4553
+ );
4554
+ }
4555
+
4556
+ if (countToProcess < count) {
4557
+ composeRename(
4558
+ change1,
4559
+ change2,
4560
+ mergedTable,
4561
+ offsetChangeAtomId(oldId, countToProcess),
4562
+ offsetChangeAtomId(newId, countToProcess),
4563
+ count - countToProcess,
4564
+ movedCrossFieldKeys,
4565
+ removedCrossFieldKeys,
4566
+ pendingCompositions,
4567
+ );
4568
+ }
4569
+ }
4570
+
4571
+ export function cloneRootTable(table: RootNodeTable): RootNodeTable {
4572
+ return {
4573
+ oldToNewId: table.oldToNewId.clone(),
4574
+ newToOldId: table.newToOldId.clone(),
4575
+ nodeChanges: brand(table.nodeChanges.clone()),
4576
+ detachLocations: table.detachLocations.clone(),
4577
+ outputDetachLocations: table.outputDetachLocations.clone(),
4578
+ };
4579
+ }
4580
+
4581
+ function invertRootTable(change: ModularChangeset, isRollback: boolean): RootNodeTable {
4582
+ const invertedRoots: RootNodeTable = newRootTable();
4583
+ for (const [[revision, localId], nodeId] of change.rootNodes.nodeChanges.entries()) {
4584
+ const detachId: ChangeAtomId = { revision, localId };
4585
+ const renamedId = firstAttachIdFromDetachId(change.rootNodes, detachId, 1).value;
4586
+
4587
+ // This checks whether `change` attaches this node.
4588
+ // 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.
4589
+ if (
4590
+ change.crossFieldKeys.getFirst({ ...renamedId, target: CrossFieldTarget.Destination }, 1)
4591
+ .value === undefined
4592
+ ) {
4593
+ assignRootChange(
4594
+ invertedRoots,
4595
+ undefined,
4596
+ renamedId,
4597
+ nodeId,
4598
+ change.rootNodes.detachLocations.getFirst(detachId, 1).value,
4599
+ change.rebaseVersion,
4600
+ );
4601
+ }
4602
+ }
4603
+
4604
+ if (isRollback) {
4605
+ // We only invert renames of nodes which are not attached or detached by this changeset.
4606
+ // When we invert an attach we will create a detach which incorporates the rename.
4607
+ for (const {
4608
+ start: oldId,
4609
+ value: newId,
4610
+ length,
4611
+ } of change.rootNodes.oldToNewId.entries()) {
4612
+ invertRename(change, invertedRoots, oldId, newId, length);
4613
+ }
4614
+ }
4615
+
4616
+ return invertedRoots;
4617
+ }
4618
+
4619
+ function invertRename(
4620
+ change: ModularChangeset,
4621
+ invertedRoots: RootNodeTable,
4622
+ oldId: ChangeAtomId,
4623
+ newId: ChangeAtomId,
4624
+ length: number,
4625
+ ): void {
4626
+ for (const detachEntry of doesChangeDetachNodes(change.crossFieldKeys, newId, length)) {
4627
+ assert(
4628
+ !detachEntry.value,
4629
+ "A changeset should not have a rename and detach for the same node.",
4630
+ );
4631
+ }
4632
+
4633
+ let countProcessed = length;
4634
+ const attachEntry = getFirstAttachField(change.crossFieldKeys, newId, countProcessed);
4635
+ countProcessed = attachEntry.length;
4636
+ if (attachEntry.value === undefined) {
4637
+ const outputDetachEntry = change.rootNodes.outputDetachLocations.getFirst(
4638
+ newId,
4639
+ countProcessed,
4640
+ );
4641
+ countProcessed = outputDetachEntry.length;
4642
+
4643
+ const inputDetachEntry = change.rootNodes.detachLocations.getFirst(oldId, countProcessed);
4644
+ countProcessed = inputDetachEntry.length;
4645
+
4646
+ addNodeRename(
4647
+ invertedRoots,
4648
+ newId,
4649
+ oldId,
4650
+ countProcessed,
4651
+ outputDetachEntry.value ?? inputDetachEntry.value,
4652
+ );
4653
+ }
4654
+
4655
+ if (countProcessed < length) {
4656
+ invertRename(
4657
+ change,
4658
+ invertedRoots,
4659
+ offsetChangeAtomId(oldId, countProcessed),
4660
+ offsetChangeAtomId(newId, countProcessed),
4661
+ length - countProcessed,
4662
+ );
4663
+ }
4664
+ }
4665
+
4666
+ function doesChangeAttachNodes(
4667
+ table: CrossFieldKeyTable,
4668
+ id: ChangeAtomId,
4669
+ count: number,
4670
+ ): RangeQueryResultFragment<boolean>[] {
4671
+ return table
4672
+ .getAll2({ ...id, target: CrossFieldTarget.Destination }, count)
4673
+ .map((entry) => ({ ...entry, value: entry.value !== undefined }));
4674
+ }
4675
+
4676
+ function doesChangeDetachNodes(
4677
+ table: CrossFieldKeyTable,
4678
+ id: ChangeAtomId,
4679
+ count: number,
4680
+ ): RangeQueryResultFragment<boolean>[] {
4681
+ return table
4682
+ .getAll2({ ...id, target: CrossFieldTarget.Source }, count)
4683
+ .map((entry) => ({ ...entry, value: entry.value !== undefined }));
4684
+ }
4685
+
4686
+ export function getFirstDetachField(
4687
+ table: CrossFieldKeyTable,
4688
+ id: ChangeAtomId,
4689
+ count: number,
4690
+ ): RangeQueryResult<FieldId | undefined> {
4691
+ return table.getFirst({ target: CrossFieldTarget.Source, ...id }, count);
4692
+ }
4693
+
4694
+ export function getFirstAttachField(
4695
+ table: CrossFieldKeyTable,
4696
+ id: ChangeAtomId,
4697
+ count: number,
4698
+ ): RangeQueryResult<FieldId | undefined> {
4699
+ return table.getFirst({ target: CrossFieldTarget.Destination, ...id }, count);
4700
+ }
4701
+
4702
+ export function addNodeRename(
4703
+ table: RootNodeTable,
4704
+ oldId: ChangeAtomId,
4705
+ newId: ChangeAtomId,
4706
+ count: number,
4707
+ detachLocation: FieldId | undefined,
4708
+ ): void {
4709
+ if (areEqualChangeAtomIds(oldId, newId)) {
4710
+ return;
4711
+ }
4712
+
4713
+ for (const entry of table.oldToNewId.getAll2(oldId, count)) {
4714
+ assert(
4715
+ entry.value === undefined ||
4716
+ areEqualChangeAtomIds(entry.value, offsetChangeAtomId(newId, entry.offset)),
4717
+ "Rename collision detected",
4718
+ );
4719
+ }
4720
+
4721
+ for (const entry of table.newToOldId.getAll2(newId, count)) {
4722
+ assert(
4723
+ entry.value === undefined ||
4724
+ areEqualChangeAtomIds(entry.value, offsetChangeAtomId(oldId, entry.offset)),
4725
+ "Rename collision detected",
4726
+ );
4727
+ }
4728
+
4729
+ table.oldToNewId.set(oldId, count, newId);
4730
+ table.newToOldId.set(newId, count, oldId);
4731
+
4732
+ if (detachLocation !== undefined) {
4733
+ table.detachLocations.set(oldId, count, detachLocation);
4734
+ }
4735
+ }
4736
+
4737
+ /**
4738
+ * Deletes any renames from `id`.
4739
+ */
4740
+ function deleteNodeRenameFrom(roots: RootNodeTable, id: ChangeAtomId, count: number): void {
4741
+ for (const entry of roots.oldToNewId.getAll(id, count)) {
4742
+ deleteNodeRenameEntry(roots, entry.start, entry.value, entry.length);
4743
+ }
4744
+ }
4745
+
4746
+ /**
4747
+ * Deletes any renames to `id`.
4748
+ */
4749
+ function deleteNodeRenameTo(roots: RootNodeTable, id: ChangeAtomId, count: number): void {
4750
+ for (const entry of roots.newToOldId.getAll(id, count)) {
4751
+ deleteNodeRenameEntry(roots, entry.value, entry.start, entry.length);
4752
+ }
4753
+ }
4754
+
4755
+ function appendNodeRename(
4756
+ composedTable: RootNodeTable,
4757
+ oldId: ChangeAtomId,
4758
+ newId: ChangeAtomId,
4759
+ count: number,
4760
+ change1Table: RootNodeTable,
4761
+ detachLocation: FieldId | undefined,
4762
+ ): void {
4763
+ let countToProcess = count;
4764
+ const rename1Entry = change1Table.newToOldId.getFirst(oldId, countToProcess);
4765
+ countToProcess = rename1Entry.length;
4766
+
4767
+ if (rename1Entry.value !== undefined) {
4768
+ deleteNodeRenameFrom(composedTable, rename1Entry.value, countToProcess);
4769
+ }
4770
+
4771
+ addNodeRename(
4772
+ composedTable,
4773
+ rename1Entry.value ?? oldId,
4774
+ newId,
4775
+ countToProcess,
4776
+ detachLocation,
4777
+ );
4778
+
4779
+ tryRemoveDetachLocation(composedTable, newId, countToProcess);
4780
+
4781
+ if (countToProcess < count) {
4782
+ const countRemaining = count - countToProcess;
4783
+ appendNodeRename(
4784
+ composedTable,
4785
+ offsetChangeAtomId(oldId, countToProcess),
4786
+ offsetChangeAtomId(newId, countToProcess),
4787
+ countRemaining,
4788
+ change1Table,
4789
+ detachLocation,
4790
+ );
4791
+ }
4792
+ }
4793
+
4794
+ function tryRemoveDetachLocation(
4795
+ roots: RootNodeTable,
4796
+ rootId: ChangeAtomId,
4797
+ count: number,
4798
+ ): void {
4799
+ let countProcessed = count;
4800
+ const renameEntry = roots.oldToNewId.getFirst(rootId, countProcessed);
4801
+ countProcessed = renameEntry.length;
4802
+
4803
+ const outputDetachEntry = roots.outputDetachLocations.getFirst(rootId, countProcessed);
4804
+ countProcessed = outputDetachEntry.length;
4805
+
4806
+ const nodeChangeEntry = rangeQueryChangeAtomIdMap(roots.nodeChanges, rootId, countProcessed);
4807
+ countProcessed = nodeChangeEntry.length;
4808
+
4809
+ if (
4810
+ nodeChangeEntry.value === undefined &&
4811
+ renameEntry.value === undefined &&
4812
+ outputDetachEntry.value === undefined
4813
+ ) {
4814
+ roots.detachLocations.delete(rootId, countProcessed);
4815
+ }
4816
+
4817
+ const countRemaining = count - countProcessed;
4818
+ if (countRemaining > 0) {
4819
+ tryRemoveDetachLocation(roots, offsetChangeAtomId(rootId, countProcessed), countRemaining);
4820
+ }
4821
+ }
4822
+
4823
+ /**
4824
+ * Deletes the entry renaming the ID range of length `count` from `oldId` to `newId`.
4825
+ * This function assumes that such an entry exists.
4826
+ */
4827
+ function deleteNodeRenameEntry(
4828
+ roots: RootNodeTable,
4829
+ oldId: ChangeAtomId,
4830
+ newId: ChangeAtomId,
4831
+ count: number,
4832
+ ): void {
4833
+ roots.oldToNewId.delete(oldId, count);
4834
+ roots.newToOldId.delete(newId, count);
4835
+ }
4836
+
4837
+ function replaceRootTableRevision(
4838
+ table: RootNodeTable,
4839
+ oldRevisions: Set<RevisionTag | undefined>,
4840
+ newRevision: RevisionTag | undefined,
4841
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4842
+ ): RootNodeTable {
4843
+ const oldToNewId = table.oldToNewId.mapEntries(
4844
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4845
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4846
+ );
4847
+
4848
+ const newToOldId = table.newToOldId.mapEntries(
4849
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4850
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4851
+ );
4852
+
4853
+ const nodeChanges: ChangeAtomIdBTree<NodeId> = newTupleBTree(
4854
+ [...table.nodeChanges.entries()].map(([[revision, id], nodeId]) => [
4855
+ [oldRevisions.has(revision) ? newRevision : revision, id],
4856
+ replaceAtomRevisions(normalizeNodeId(nodeId, nodeAliases), oldRevisions, newRevision),
4857
+ ]),
4858
+ );
4859
+
4860
+ const detachLocations = table.detachLocations.mapEntries(
4861
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4862
+ (fieldId) =>
4863
+ replaceFieldIdRevision(
4864
+ normalizeFieldId(fieldId, nodeAliases),
4865
+ oldRevisions,
4866
+ newRevision,
4867
+ ),
4868
+ );
4869
+
4870
+ const outputDetachLocations = table.outputDetachLocations.mapEntries(
4871
+ (id) => replaceAtomRevisions(id, oldRevisions, newRevision),
4872
+ (fieldId) =>
4873
+ replaceFieldIdRevision(
4874
+ normalizeFieldId(fieldId, nodeAliases),
4875
+ oldRevisions,
4876
+ newRevision,
4877
+ ),
4878
+ );
4879
+
4880
+ return { oldToNewId, newToOldId, nodeChanges, detachLocations, outputDetachLocations };
4881
+ }
4882
+
4883
+ function newDetachedEntryMap(): ChangeAtomIdRangeMap<DetachedNodeEntry> {
4884
+ return new RangeMap(offsetChangeAtomId, subtractChangeAtomIds, offsetDetachedNodeEntry);
4885
+ }
4886
+
4887
+ function offsetDetachedNodeEntry(entry: DetachedNodeEntry, count: number): DetachedNodeEntry {
4888
+ assert(
4889
+ count <= 1 || entry.nodeChange === undefined,
4890
+ "Cannot split an entry with a node change",
4891
+ );
4892
+
4893
+ return entry.detachId !== undefined
4894
+ ? { ...entry, detachId: offsetChangeAtomId(entry.detachId, count) }
4895
+ : entry;
4896
+ }
4897
+
4898
+ function getFieldsWithRootMoves(
4899
+ roots: RootNodeTable,
4900
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4901
+ ): TupleBTree<FieldIdKey, boolean> {
4902
+ const fields: TupleBTree<FieldIdKey, boolean> = newTupleBTree();
4903
+ for (const { start: rootId, value: fieldId, length } of roots.detachLocations.entries()) {
4904
+ let isRootMoved = false;
4905
+ for (const renameEntry of roots.oldToNewId.getAll2(rootId, length)) {
4906
+ if (renameEntry.value !== undefined) {
4907
+ isRootMoved = true;
4908
+ }
4909
+ }
4910
+
4911
+ for (const outputDetachEntry of roots.outputDetachLocations.getAll2(rootId, length)) {
4912
+ if (outputDetachEntry.value !== undefined) {
4913
+ isRootMoved = true;
4914
+ }
4915
+ }
4916
+
4917
+ if (isRootMoved) {
4918
+ fields.set(fieldIdKeyFromFieldId(normalizeFieldId(fieldId, nodeAliases)), true);
4919
+ }
4920
+ }
4921
+
4922
+ return fields;
4923
+ }
4924
+
4925
+ function getFieldToRootChanges(
4926
+ roots: RootNodeTable,
4927
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
4928
+ ): TupleBTree<FieldIdKey, ChangeAtomId[]> {
4929
+ const fields: TupleBTree<FieldIdKey, ChangeAtomId[]> = newTupleBTree();
4930
+ for (const rootIdKey of roots.nodeChanges.keys()) {
4931
+ const rootId: ChangeAtomId = { revision: rootIdKey[0], localId: rootIdKey[1] };
4932
+ const detachLocation = roots.detachLocations.getFirst(rootId, 1).value;
4933
+ if (detachLocation !== undefined) {
4934
+ const fieldIdKey = fieldIdKeyFromFieldId(normalizeFieldId(detachLocation, nodeAliases));
4935
+ let rootsInField = fields.get(fieldIdKey);
4936
+ if (rootsInField === undefined) {
4937
+ rootsInField = [];
4938
+ fields.set(fieldIdKey, rootsInField);
4939
+ }
4940
+
4941
+ rootsInField.push(rootId);
4942
+ }
4943
+ }
4944
+
4945
+ return fields;
4946
+ }
4947
+
4948
+ function muteRootChanges(roots: RootNodeTable): RootNodeTable {
4949
+ return {
4950
+ oldToNewId: newChangeAtomIdTransform(),
4951
+ newToOldId: newChangeAtomIdTransform(),
4952
+ nodeChanges: brand(roots.nodeChanges.clone()),
4953
+ detachLocations: roots.detachLocations.clone(),
4954
+ outputDetachLocations: newChangeAtomIdRangeMap(),
4955
+ };
3156
4956
  }