@fluidframework/tree 2.90.0-378676 → 2.90.0

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