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