@fluidframework/tree 2.1.0-276985 → 2.1.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 (583) hide show
  1. package/.eslintrc.cjs +7 -0
  2. package/.vscode/Tree.code-workspace +9 -2
  3. package/CHANGELOG.md +38 -0
  4. package/README.md +55 -12
  5. package/api-report/tree.alpha.api.md +2 -1
  6. package/api-report/tree.beta.api.md +2 -1
  7. package/api-report/tree.public.api.md +2 -1
  8. package/beta.d.ts +1 -1
  9. package/dist/beta.d.ts +1 -1
  10. package/dist/core/forest/editableForest.d.ts +6 -3
  11. package/dist/core/forest/editableForest.d.ts.map +1 -1
  12. package/dist/core/forest/editableForest.js +16 -4
  13. package/dist/core/forest/editableForest.js.map +1 -1
  14. package/dist/core/index.d.ts +1 -1
  15. package/dist/core/index.d.ts.map +1 -1
  16. package/dist/core/index.js +3 -1
  17. package/dist/core/index.js.map +1 -1
  18. package/dist/core/rebase/index.d.ts +1 -1
  19. package/dist/core/rebase/index.d.ts.map +1 -1
  20. package/dist/core/rebase/index.js +3 -1
  21. package/dist/core/rebase/index.js.map +1 -1
  22. package/dist/core/rebase/types.d.ts +2 -0
  23. package/dist/core/rebase/types.d.ts.map +1 -1
  24. package/dist/core/rebase/types.js +9 -1
  25. package/dist/core/rebase/types.js.map +1 -1
  26. package/dist/core/tree/anchorSet.d.ts +1 -0
  27. package/dist/core/tree/anchorSet.d.ts.map +1 -1
  28. package/dist/core/tree/anchorSet.js +13 -0
  29. package/dist/core/tree/anchorSet.js.map +1 -1
  30. package/dist/core/tree/detachedFieldIndex.d.ts +48 -11
  31. package/dist/core/tree/detachedFieldIndex.d.ts.map +1 -1
  32. package/dist/core/tree/detachedFieldIndex.js +144 -20
  33. package/dist/core/tree/detachedFieldIndex.js.map +1 -1
  34. package/dist/core/tree/detachedFieldIndexCodec.d.ts.map +1 -1
  35. package/dist/core/tree/detachedFieldIndexCodec.js +13 -4
  36. package/dist/core/tree/detachedFieldIndexCodec.js.map +1 -1
  37. package/dist/core/tree/detachedFieldIndexFormat.d.ts +1 -1
  38. package/dist/core/tree/detachedFieldIndexFormat.d.ts.map +1 -1
  39. package/dist/core/tree/detachedFieldIndexFormat.js.map +1 -1
  40. package/dist/core/tree/detachedFieldIndexTypes.d.ts +39 -4
  41. package/dist/core/tree/detachedFieldIndexTypes.d.ts.map +1 -1
  42. package/dist/core/tree/detachedFieldIndexTypes.js.map +1 -1
  43. package/dist/core/tree/index.d.ts +2 -1
  44. package/dist/core/tree/index.d.ts.map +1 -1
  45. package/dist/core/tree/index.js.map +1 -1
  46. package/dist/core/tree/visitDelta.d.ts +3 -1
  47. package/dist/core/tree/visitDelta.d.ts.map +1 -1
  48. package/dist/core/tree/visitDelta.js +31 -15
  49. package/dist/core/tree/visitDelta.js.map +1 -1
  50. package/dist/core/tree/visitorUtils.d.ts +3 -3
  51. package/dist/core/tree/visitorUtils.d.ts.map +1 -1
  52. package/dist/core/tree/visitorUtils.js +4 -4
  53. package/dist/core/tree/visitorUtils.js.map +1 -1
  54. package/dist/events/events.d.ts +4 -1
  55. package/dist/events/events.d.ts.map +1 -1
  56. package/dist/events/events.js.map +1 -1
  57. package/dist/feature-libraries/default-schema/defaultEditBuilder.js +1 -1
  58. package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  59. package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  60. package/dist/feature-libraries/default-schema/defaultFieldKinds.js +1 -0
  61. package/dist/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  62. package/dist/feature-libraries/editableTreeBinder.js +1 -1
  63. package/dist/feature-libraries/editableTreeBinder.js.map +1 -1
  64. package/dist/feature-libraries/flex-map-tree/mapTreeNode.d.ts +1 -10
  65. package/dist/feature-libraries/flex-map-tree/mapTreeNode.d.ts.map +1 -1
  66. package/dist/feature-libraries/flex-map-tree/mapTreeNode.js +0 -72
  67. package/dist/feature-libraries/flex-map-tree/mapTreeNode.js.map +1 -1
  68. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -51
  69. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  70. package/dist/feature-libraries/flex-tree/flexTreeTypes.js +0 -2
  71. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  72. package/dist/feature-libraries/flex-tree/index.d.ts +3 -2
  73. package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
  74. package/dist/feature-libraries/flex-tree/index.js +5 -1
  75. package/dist/feature-libraries/flex-tree/index.js.map +1 -1
  76. package/dist/feature-libraries/flex-tree/lazyEntity.d.ts +1 -2
  77. package/dist/feature-libraries/flex-tree/lazyEntity.d.ts.map +1 -1
  78. package/dist/feature-libraries/flex-tree/lazyEntity.js.map +1 -1
  79. package/dist/feature-libraries/flex-tree/lazyField.d.ts +1 -6
  80. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  81. package/dist/feature-libraries/flex-tree/lazyField.js +11 -32
  82. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  83. package/dist/feature-libraries/flex-tree/lazyNode.d.ts +1 -5
  84. package/dist/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  85. package/dist/feature-libraries/flex-tree/lazyNode.js +0 -30
  86. package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  87. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  88. package/dist/feature-libraries/forest-summary/forestSummarizer.js +1 -1
  89. package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  90. package/dist/feature-libraries/index.d.ts +3 -3
  91. package/dist/feature-libraries/index.d.ts.map +1 -1
  92. package/dist/feature-libraries/index.js +6 -3
  93. package/dist/feature-libraries/index.js.map +1 -1
  94. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +11 -0
  95. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  96. package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  97. package/dist/feature-libraries/modular-schema/discrepancies.d.ts +96 -0
  98. package/dist/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -0
  99. package/dist/feature-libraries/modular-schema/discrepancies.js +264 -0
  100. package/dist/feature-libraries/modular-schema/discrepancies.js.map +1 -0
  101. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +9 -2
  102. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  103. package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  104. package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  105. package/dist/feature-libraries/modular-schema/genericFieldKind.js +3 -0
  106. package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  107. package/dist/feature-libraries/modular-schema/index.d.ts +2 -1
  108. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  109. package/dist/feature-libraries/modular-schema/index.js +3 -1
  110. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  111. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  112. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +42 -26
  113. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  114. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +51 -2
  115. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  116. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +827 -245
  117. package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  118. package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
  119. package/dist/feature-libraries/modular-schema/modularChangeFormat.js +2 -0
  120. package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
  121. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +44 -1
  122. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  123. package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  124. package/dist/feature-libraries/node-key/index.d.ts +0 -1
  125. package/dist/feature-libraries/node-key/index.d.ts.map +1 -1
  126. package/dist/feature-libraries/node-key/index.js +1 -3
  127. package/dist/feature-libraries/node-key/index.js.map +1 -1
  128. package/dist/feature-libraries/object-forest/objectForest.d.ts +3 -2
  129. package/dist/feature-libraries/object-forest/objectForest.d.ts.map +1 -1
  130. package/dist/feature-libraries/object-forest/objectForest.js +5 -4
  131. package/dist/feature-libraries/object-forest/objectForest.js.map +1 -1
  132. package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  133. package/dist/feature-libraries/optional-field/optionalField.js +1 -0
  134. package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
  135. package/dist/feature-libraries/sequence-field/index.d.ts +1 -1
  136. package/dist/feature-libraries/sequence-field/index.d.ts.map +1 -1
  137. package/dist/feature-libraries/sequence-field/index.js +1 -2
  138. package/dist/feature-libraries/sequence-field/index.js.map +1 -1
  139. package/dist/feature-libraries/sequence-field/invert.js +1 -1
  140. package/dist/feature-libraries/sequence-field/invert.js.map +1 -1
  141. package/dist/feature-libraries/sequence-field/rebase.js +6 -1
  142. package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
  143. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  144. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +1 -0
  145. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  146. package/dist/feature-libraries/sequence-field/utils.d.ts +2 -17
  147. package/dist/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  148. package/dist/feature-libraries/sequence-field/utils.js +31 -39
  149. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  150. package/dist/feature-libraries/typed-schema/typedTreeSchema.d.ts +1 -0
  151. package/dist/feature-libraries/typed-schema/typedTreeSchema.d.ts.map +1 -1
  152. package/dist/feature-libraries/typed-schema/typedTreeSchema.js +2 -0
  153. package/dist/feature-libraries/typed-schema/typedTreeSchema.js.map +1 -1
  154. package/dist/index.d.ts +1 -1
  155. package/dist/index.d.ts.map +1 -1
  156. package/dist/index.js.map +1 -1
  157. package/dist/packageVersion.d.ts +1 -1
  158. package/dist/packageVersion.d.ts.map +1 -1
  159. package/dist/packageVersion.js +1 -1
  160. package/dist/packageVersion.js.map +1 -1
  161. package/dist/public.d.ts +1 -1
  162. package/dist/shared-tree/schematizingTreeView.d.ts +4 -2
  163. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  164. package/dist/shared-tree/schematizingTreeView.js +240 -184
  165. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  166. package/dist/shared-tree/sharedTree.d.ts +5 -1
  167. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  168. package/dist/shared-tree/sharedTree.js +157 -90
  169. package/dist/shared-tree/sharedTree.js.map +1 -1
  170. package/dist/shared-tree/sharedTreeChangeEnricher.js +1 -1
  171. package/dist/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
  172. package/dist/shared-tree/treeApi.js +1 -1
  173. package/dist/shared-tree/treeApi.js.map +1 -1
  174. package/dist/shared-tree/treeCheckout.d.ts +10 -1
  175. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  176. package/dist/shared-tree/treeCheckout.js +47 -3
  177. package/dist/shared-tree/treeCheckout.js.map +1 -1
  178. package/dist/shared-tree/treeView.d.ts.map +1 -1
  179. package/dist/shared-tree/treeView.js +7 -3
  180. package/dist/shared-tree/treeView.js.map +1 -1
  181. package/dist/shared-tree-core/branch.d.ts +6 -0
  182. package/dist/shared-tree-core/branch.d.ts.map +1 -1
  183. package/dist/shared-tree-core/branch.js +3 -0
  184. package/dist/shared-tree-core/branch.js.map +1 -1
  185. package/dist/shared-tree-core/sharedTreeCore.d.ts +8 -6
  186. package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  187. package/dist/shared-tree-core/sharedTreeCore.js +271 -209
  188. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  189. package/dist/simple-tree/arrayNode.d.ts +4 -0
  190. package/dist/simple-tree/arrayNode.d.ts.map +1 -1
  191. package/dist/simple-tree/arrayNode.js +36 -19
  192. package/dist/simple-tree/arrayNode.js.map +1 -1
  193. package/dist/simple-tree/index.d.ts +3 -3
  194. package/dist/simple-tree/index.d.ts.map +1 -1
  195. package/dist/simple-tree/index.js +2 -1
  196. package/dist/simple-tree/index.js.map +1 -1
  197. package/dist/simple-tree/leafNodeSchema.d.ts +22 -1
  198. package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
  199. package/dist/simple-tree/leafNodeSchema.js +2 -1
  200. package/dist/simple-tree/leafNodeSchema.js.map +1 -1
  201. package/dist/simple-tree/mapNode.d.ts.map +1 -1
  202. package/dist/simple-tree/mapNode.js.map +1 -1
  203. package/dist/simple-tree/objectNode.d.ts.map +1 -1
  204. package/dist/simple-tree/objectNode.js +2 -1
  205. package/dist/simple-tree/objectNode.js.map +1 -1
  206. package/dist/simple-tree/proxies.d.ts.map +1 -1
  207. package/dist/simple-tree/proxies.js +9 -25
  208. package/dist/simple-tree/proxies.js.map +1 -1
  209. package/dist/simple-tree/proxyBinding.d.ts +4 -0
  210. package/dist/simple-tree/proxyBinding.d.ts.map +1 -1
  211. package/dist/simple-tree/proxyBinding.js +23 -1
  212. package/dist/simple-tree/proxyBinding.js.map +1 -1
  213. package/dist/simple-tree/schemaFactory.d.ts +16 -1
  214. package/dist/simple-tree/schemaFactory.d.ts.map +1 -1
  215. package/dist/simple-tree/schemaFactory.js +32 -4
  216. package/dist/simple-tree/schemaFactory.js.map +1 -1
  217. package/dist/simple-tree/schemaTypes.d.ts +36 -1
  218. package/dist/simple-tree/schemaTypes.d.ts.map +1 -1
  219. package/dist/simple-tree/schemaTypes.js.map +1 -1
  220. package/dist/simple-tree/toFlexSchema.d.ts +2 -2
  221. package/dist/simple-tree/toFlexSchema.d.ts.map +1 -1
  222. package/dist/simple-tree/toFlexSchema.js +3 -2
  223. package/dist/simple-tree/toFlexSchema.js.map +1 -1
  224. package/dist/simple-tree/tree.d.ts +4 -1
  225. package/dist/simple-tree/tree.d.ts.map +1 -1
  226. package/dist/simple-tree/tree.js +48 -1
  227. package/dist/simple-tree/tree.js.map +1 -1
  228. package/dist/simple-tree/treeNodeApi.d.ts +2 -75
  229. package/dist/simple-tree/treeNodeApi.d.ts.map +1 -1
  230. package/dist/simple-tree/treeNodeApi.js +17 -25
  231. package/dist/simple-tree/treeNodeApi.js.map +1 -1
  232. package/dist/simple-tree/treeNodeKernel.d.ts +26 -0
  233. package/dist/simple-tree/treeNodeKernel.d.ts.map +1 -0
  234. package/dist/simple-tree/treeNodeKernel.js +83 -0
  235. package/dist/simple-tree/treeNodeKernel.js.map +1 -0
  236. package/dist/simple-tree/types.d.ts +95 -3
  237. package/dist/simple-tree/types.d.ts.map +1 -1
  238. package/dist/simple-tree/types.js +120 -21
  239. package/dist/simple-tree/types.js.map +1 -1
  240. package/dist/util/breakable.d.ts +83 -0
  241. package/dist/util/breakable.d.ts.map +1 -0
  242. package/dist/util/breakable.js +178 -0
  243. package/dist/util/breakable.js.map +1 -0
  244. package/dist/util/index.d.ts +3 -2
  245. package/dist/util/index.d.ts.map +1 -1
  246. package/dist/util/index.js +9 -2
  247. package/dist/util/index.js.map +1 -1
  248. package/dist/util/nestedMap.d.ts +17 -3
  249. package/dist/util/nestedMap.d.ts.map +1 -1
  250. package/dist/util/nestedMap.js +21 -1
  251. package/dist/util/nestedMap.js.map +1 -1
  252. package/dist/util/utils.d.ts +7 -0
  253. package/dist/util/utils.d.ts.map +1 -1
  254. package/dist/util/utils.js +15 -1
  255. package/dist/util/utils.js.map +1 -1
  256. package/internal.d.ts +1 -1
  257. package/lib/beta.d.ts +1 -1
  258. package/lib/core/forest/editableForest.d.ts +6 -3
  259. package/lib/core/forest/editableForest.d.ts.map +1 -1
  260. package/lib/core/forest/editableForest.js +17 -5
  261. package/lib/core/forest/editableForest.js.map +1 -1
  262. package/lib/core/index.d.ts +1 -1
  263. package/lib/core/index.d.ts.map +1 -1
  264. package/lib/core/index.js +1 -1
  265. package/lib/core/index.js.map +1 -1
  266. package/lib/core/rebase/index.d.ts +1 -1
  267. package/lib/core/rebase/index.d.ts.map +1 -1
  268. package/lib/core/rebase/index.js +1 -1
  269. package/lib/core/rebase/index.js.map +1 -1
  270. package/lib/core/rebase/types.d.ts +2 -0
  271. package/lib/core/rebase/types.d.ts.map +1 -1
  272. package/lib/core/rebase/types.js +7 -1
  273. package/lib/core/rebase/types.js.map +1 -1
  274. package/lib/core/tree/anchorSet.d.ts +1 -0
  275. package/lib/core/tree/anchorSet.d.ts.map +1 -1
  276. package/lib/core/tree/anchorSet.js +13 -0
  277. package/lib/core/tree/anchorSet.js.map +1 -1
  278. package/lib/core/tree/detachedFieldIndex.d.ts +48 -11
  279. package/lib/core/tree/detachedFieldIndex.d.ts.map +1 -1
  280. package/lib/core/tree/detachedFieldIndex.js +145 -21
  281. package/lib/core/tree/detachedFieldIndex.js.map +1 -1
  282. package/lib/core/tree/detachedFieldIndexCodec.d.ts.map +1 -1
  283. package/lib/core/tree/detachedFieldIndexCodec.js +13 -4
  284. package/lib/core/tree/detachedFieldIndexCodec.js.map +1 -1
  285. package/lib/core/tree/detachedFieldIndexFormat.d.ts +1 -1
  286. package/lib/core/tree/detachedFieldIndexFormat.d.ts.map +1 -1
  287. package/lib/core/tree/detachedFieldIndexFormat.js.map +1 -1
  288. package/lib/core/tree/detachedFieldIndexTypes.d.ts +39 -4
  289. package/lib/core/tree/detachedFieldIndexTypes.d.ts.map +1 -1
  290. package/lib/core/tree/detachedFieldIndexTypes.js.map +1 -1
  291. package/lib/core/tree/index.d.ts +2 -1
  292. package/lib/core/tree/index.d.ts.map +1 -1
  293. package/lib/core/tree/index.js.map +1 -1
  294. package/lib/core/tree/visitDelta.d.ts +3 -1
  295. package/lib/core/tree/visitDelta.d.ts.map +1 -1
  296. package/lib/core/tree/visitDelta.js +31 -15
  297. package/lib/core/tree/visitDelta.js.map +1 -1
  298. package/lib/core/tree/visitorUtils.d.ts +3 -3
  299. package/lib/core/tree/visitorUtils.d.ts.map +1 -1
  300. package/lib/core/tree/visitorUtils.js +4 -4
  301. package/lib/core/tree/visitorUtils.js.map +1 -1
  302. package/lib/events/events.d.ts +4 -1
  303. package/lib/events/events.d.ts.map +1 -1
  304. package/lib/events/events.js.map +1 -1
  305. package/lib/feature-libraries/default-schema/defaultEditBuilder.js +1 -1
  306. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  307. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  308. package/lib/feature-libraries/default-schema/defaultFieldKinds.js +1 -0
  309. package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  310. package/lib/feature-libraries/editableTreeBinder.js +1 -1
  311. package/lib/feature-libraries/editableTreeBinder.js.map +1 -1
  312. package/lib/feature-libraries/flex-map-tree/mapTreeNode.d.ts +1 -10
  313. package/lib/feature-libraries/flex-map-tree/mapTreeNode.d.ts.map +1 -1
  314. package/lib/feature-libraries/flex-map-tree/mapTreeNode.js +2 -74
  315. package/lib/feature-libraries/flex-map-tree/mapTreeNode.js.map +1 -1
  316. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -51
  317. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  318. package/lib/feature-libraries/flex-tree/flexTreeTypes.js +0 -2
  319. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  320. package/lib/feature-libraries/flex-tree/index.d.ts +3 -2
  321. package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
  322. package/lib/feature-libraries/flex-tree/index.js +2 -1
  323. package/lib/feature-libraries/flex-tree/index.js.map +1 -1
  324. package/lib/feature-libraries/flex-tree/lazyEntity.d.ts +1 -2
  325. package/lib/feature-libraries/flex-tree/lazyEntity.d.ts.map +1 -1
  326. package/lib/feature-libraries/flex-tree/lazyEntity.js.map +1 -1
  327. package/lib/feature-libraries/flex-tree/lazyField.d.ts +1 -6
  328. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  329. package/lib/feature-libraries/flex-tree/lazyField.js +13 -34
  330. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  331. package/lib/feature-libraries/flex-tree/lazyNode.d.ts +1 -5
  332. package/lib/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  333. package/lib/feature-libraries/flex-tree/lazyNode.js +3 -33
  334. package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  335. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  336. package/lib/feature-libraries/forest-summary/forestSummarizer.js +1 -1
  337. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  338. package/lib/feature-libraries/index.d.ts +3 -3
  339. package/lib/feature-libraries/index.d.ts.map +1 -1
  340. package/lib/feature-libraries/index.js +3 -3
  341. package/lib/feature-libraries/index.js.map +1 -1
  342. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +11 -0
  343. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  344. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  345. package/lib/feature-libraries/modular-schema/discrepancies.d.ts +96 -0
  346. package/lib/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -0
  347. package/lib/feature-libraries/modular-schema/discrepancies.js +260 -0
  348. package/lib/feature-libraries/modular-schema/discrepancies.js.map +1 -0
  349. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +9 -2
  350. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  351. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  352. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  353. package/lib/feature-libraries/modular-schema/genericFieldKind.js +3 -0
  354. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  355. package/lib/feature-libraries/modular-schema/index.d.ts +2 -1
  356. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  357. package/lib/feature-libraries/modular-schema/index.js +1 -0
  358. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  359. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  360. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +42 -26
  361. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  362. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +51 -2
  363. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  364. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +826 -247
  365. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  366. package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
  367. package/lib/feature-libraries/modular-schema/modularChangeFormat.js +2 -0
  368. package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
  369. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +44 -1
  370. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  371. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  372. package/lib/feature-libraries/node-key/index.d.ts +0 -1
  373. package/lib/feature-libraries/node-key/index.d.ts.map +1 -1
  374. package/lib/feature-libraries/node-key/index.js +0 -1
  375. package/lib/feature-libraries/node-key/index.js.map +1 -1
  376. package/lib/feature-libraries/object-forest/objectForest.d.ts +3 -2
  377. package/lib/feature-libraries/object-forest/objectForest.d.ts.map +1 -1
  378. package/lib/feature-libraries/object-forest/objectForest.js +5 -4
  379. package/lib/feature-libraries/object-forest/objectForest.js.map +1 -1
  380. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  381. package/lib/feature-libraries/optional-field/optionalField.js +1 -0
  382. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  383. package/lib/feature-libraries/sequence-field/index.d.ts +1 -1
  384. package/lib/feature-libraries/sequence-field/index.d.ts.map +1 -1
  385. package/lib/feature-libraries/sequence-field/index.js +1 -1
  386. package/lib/feature-libraries/sequence-field/index.js.map +1 -1
  387. package/lib/feature-libraries/sequence-field/invert.js +1 -1
  388. package/lib/feature-libraries/sequence-field/invert.js.map +1 -1
  389. package/lib/feature-libraries/sequence-field/rebase.js +6 -1
  390. package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
  391. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  392. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +2 -1
  393. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  394. package/lib/feature-libraries/sequence-field/utils.d.ts +2 -17
  395. package/lib/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  396. package/lib/feature-libraries/sequence-field/utils.js +31 -39
  397. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  398. package/lib/feature-libraries/typed-schema/typedTreeSchema.d.ts +1 -0
  399. package/lib/feature-libraries/typed-schema/typedTreeSchema.d.ts.map +1 -1
  400. package/lib/feature-libraries/typed-schema/typedTreeSchema.js +4 -2
  401. package/lib/feature-libraries/typed-schema/typedTreeSchema.js.map +1 -1
  402. package/lib/index.d.ts +1 -1
  403. package/lib/index.d.ts.map +1 -1
  404. package/lib/index.js.map +1 -1
  405. package/lib/packageVersion.d.ts +1 -1
  406. package/lib/packageVersion.d.ts.map +1 -1
  407. package/lib/packageVersion.js +1 -1
  408. package/lib/packageVersion.js.map +1 -1
  409. package/lib/public.d.ts +1 -1
  410. package/lib/shared-tree/schematizingTreeView.d.ts +4 -2
  411. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  412. package/lib/shared-tree/schematizingTreeView.js +242 -185
  413. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  414. package/lib/shared-tree/sharedTree.d.ts +5 -1
  415. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  416. package/lib/shared-tree/sharedTree.js +158 -90
  417. package/lib/shared-tree/sharedTree.js.map +1 -1
  418. package/lib/shared-tree/sharedTreeChangeEnricher.js +1 -1
  419. package/lib/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
  420. package/lib/shared-tree/treeApi.js +1 -1
  421. package/lib/shared-tree/treeApi.js.map +1 -1
  422. package/lib/shared-tree/treeCheckout.d.ts +10 -1
  423. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  424. package/lib/shared-tree/treeCheckout.js +47 -3
  425. package/lib/shared-tree/treeCheckout.js.map +1 -1
  426. package/lib/shared-tree/treeView.d.ts.map +1 -1
  427. package/lib/shared-tree/treeView.js +4 -0
  428. package/lib/shared-tree/treeView.js.map +1 -1
  429. package/lib/shared-tree-core/branch.d.ts +6 -0
  430. package/lib/shared-tree-core/branch.d.ts.map +1 -1
  431. package/lib/shared-tree-core/branch.js +3 -0
  432. package/lib/shared-tree-core/branch.js.map +1 -1
  433. package/lib/shared-tree-core/sharedTreeCore.d.ts +8 -6
  434. package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  435. package/lib/shared-tree-core/sharedTreeCore.js +273 -210
  436. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  437. package/lib/simple-tree/arrayNode.d.ts +4 -0
  438. package/lib/simple-tree/arrayNode.d.ts.map +1 -1
  439. package/lib/simple-tree/arrayNode.js +39 -22
  440. package/lib/simple-tree/arrayNode.js.map +1 -1
  441. package/lib/simple-tree/index.d.ts +3 -3
  442. package/lib/simple-tree/index.d.ts.map +1 -1
  443. package/lib/simple-tree/index.js +1 -1
  444. package/lib/simple-tree/index.js.map +1 -1
  445. package/lib/simple-tree/leafNodeSchema.d.ts +22 -1
  446. package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
  447. package/lib/simple-tree/leafNodeSchema.js +1 -1
  448. package/lib/simple-tree/leafNodeSchema.js.map +1 -1
  449. package/lib/simple-tree/mapNode.d.ts.map +1 -1
  450. package/lib/simple-tree/mapNode.js.map +1 -1
  451. package/lib/simple-tree/objectNode.d.ts.map +1 -1
  452. package/lib/simple-tree/objectNode.js +3 -2
  453. package/lib/simple-tree/objectNode.js.map +1 -1
  454. package/lib/simple-tree/proxies.d.ts.map +1 -1
  455. package/lib/simple-tree/proxies.js +9 -25
  456. package/lib/simple-tree/proxies.js.map +1 -1
  457. package/lib/simple-tree/proxyBinding.d.ts +4 -0
  458. package/lib/simple-tree/proxyBinding.d.ts.map +1 -1
  459. package/lib/simple-tree/proxyBinding.js +19 -0
  460. package/lib/simple-tree/proxyBinding.js.map +1 -1
  461. package/lib/simple-tree/schemaFactory.d.ts +16 -1
  462. package/lib/simple-tree/schemaFactory.d.ts.map +1 -1
  463. package/lib/simple-tree/schemaFactory.js +30 -3
  464. package/lib/simple-tree/schemaFactory.js.map +1 -1
  465. package/lib/simple-tree/schemaTypes.d.ts +36 -1
  466. package/lib/simple-tree/schemaTypes.d.ts.map +1 -1
  467. package/lib/simple-tree/schemaTypes.js.map +1 -1
  468. package/lib/simple-tree/toFlexSchema.d.ts +2 -2
  469. package/lib/simple-tree/toFlexSchema.d.ts.map +1 -1
  470. package/lib/simple-tree/toFlexSchema.js +3 -2
  471. package/lib/simple-tree/toFlexSchema.js.map +1 -1
  472. package/lib/simple-tree/tree.d.ts +4 -1
  473. package/lib/simple-tree/tree.d.ts.map +1 -1
  474. package/lib/simple-tree/tree.js +44 -0
  475. package/lib/simple-tree/tree.js.map +1 -1
  476. package/lib/simple-tree/treeNodeApi.d.ts +2 -75
  477. package/lib/simple-tree/treeNodeApi.d.ts.map +1 -1
  478. package/lib/simple-tree/treeNodeApi.js +20 -28
  479. package/lib/simple-tree/treeNodeApi.js.map +1 -1
  480. package/lib/simple-tree/treeNodeKernel.d.ts +26 -0
  481. package/lib/simple-tree/treeNodeKernel.d.ts.map +1 -0
  482. package/lib/simple-tree/treeNodeKernel.js +79 -0
  483. package/lib/simple-tree/treeNodeKernel.js.map +1 -0
  484. package/lib/simple-tree/types.d.ts +95 -3
  485. package/lib/simple-tree/types.d.ts.map +1 -1
  486. package/lib/simple-tree/types.js +121 -22
  487. package/lib/simple-tree/types.js.map +1 -1
  488. package/lib/util/breakable.d.ts +83 -0
  489. package/lib/util/breakable.d.ts.map +1 -0
  490. package/lib/util/breakable.js +171 -0
  491. package/lib/util/breakable.js.map +1 -0
  492. package/lib/util/index.d.ts +3 -2
  493. package/lib/util/index.d.ts.map +1 -1
  494. package/lib/util/index.js +3 -2
  495. package/lib/util/index.js.map +1 -1
  496. package/lib/util/nestedMap.d.ts +17 -3
  497. package/lib/util/nestedMap.d.ts.map +1 -1
  498. package/lib/util/nestedMap.js +19 -0
  499. package/lib/util/nestedMap.js.map +1 -1
  500. package/lib/util/utils.d.ts +7 -0
  501. package/lib/util/utils.d.ts.map +1 -1
  502. package/lib/util/utils.js +13 -0
  503. package/lib/util/utils.js.map +1 -1
  504. package/package.json +29 -27
  505. package/src/core/forest/editableForest.ts +25 -4
  506. package/src/core/index.ts +2 -0
  507. package/src/core/rebase/index.ts +2 -0
  508. package/src/core/rebase/types.ts +17 -0
  509. package/src/core/tree/anchorSet.ts +14 -0
  510. package/src/core/tree/detachedFieldIndex.ts +217 -35
  511. package/src/core/tree/detachedFieldIndexCodec.ts +17 -8
  512. package/src/core/tree/detachedFieldIndexFormat.ts +1 -1
  513. package/src/core/tree/detachedFieldIndexTypes.ts +41 -5
  514. package/src/core/tree/index.ts +2 -1
  515. package/src/core/tree/visitDelta.ts +58 -16
  516. package/src/core/tree/visitorUtils.ts +7 -4
  517. package/src/events/events.ts +4 -2
  518. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +1 -1
  519. package/src/feature-libraries/default-schema/defaultFieldKinds.ts +1 -0
  520. package/src/feature-libraries/editableTreeBinder.ts +1 -1
  521. package/src/feature-libraries/flex-map-tree/mapTreeNode.ts +1 -95
  522. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +0 -62
  523. package/src/feature-libraries/flex-tree/index.ts +7 -2
  524. package/src/feature-libraries/flex-tree/lazyEntity.ts +0 -3
  525. package/src/feature-libraries/flex-tree/lazyField.ts +15 -47
  526. package/src/feature-libraries/flex-tree/lazyNode.ts +1 -48
  527. package/src/feature-libraries/forest-summary/forestSummarizer.ts +1 -0
  528. package/src/feature-libraries/index.ts +4 -2
  529. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +18 -0
  530. package/src/feature-libraries/modular-schema/discrepancies.ts +395 -0
  531. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +10 -2
  532. package/src/feature-libraries/modular-schema/genericFieldKind.ts +3 -0
  533. package/src/feature-libraries/modular-schema/index.ts +2 -0
  534. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +81 -35
  535. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +1521 -444
  536. package/src/feature-libraries/modular-schema/modularChangeFormat.ts +2 -0
  537. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +51 -0
  538. package/src/feature-libraries/node-key/index.ts +0 -1
  539. package/src/feature-libraries/object-forest/objectForest.ts +7 -3
  540. package/src/feature-libraries/optional-field/optionalField.ts +1 -0
  541. package/src/feature-libraries/sequence-field/index.ts +0 -2
  542. package/src/feature-libraries/sequence-field/invert.ts +1 -1
  543. package/src/feature-libraries/sequence-field/rebase.ts +7 -1
  544. package/src/feature-libraries/sequence-field/sequenceFieldChangeHandler.ts +2 -1
  545. package/src/feature-libraries/sequence-field/utils.ts +37 -85
  546. package/src/feature-libraries/typed-schema/typedTreeSchema.ts +10 -0
  547. package/src/index.ts +0 -1
  548. package/src/packageVersion.ts +1 -1
  549. package/src/shared-tree/schematizingTreeView.ts +6 -2
  550. package/src/shared-tree/sharedTree.ts +12 -1
  551. package/src/shared-tree/sharedTreeChangeEnricher.ts +1 -1
  552. package/src/shared-tree/treeApi.ts +1 -1
  553. package/src/shared-tree/treeCheckout.ts +60 -5
  554. package/src/shared-tree/treeView.ts +5 -0
  555. package/src/shared-tree-core/branch.ts +10 -0
  556. package/src/shared-tree-core/sharedTreeCore.ts +25 -6
  557. package/src/simple-tree/arrayNode.ts +50 -23
  558. package/src/simple-tree/index.ts +3 -3
  559. package/src/simple-tree/leafNodeSchema.ts +1 -1
  560. package/src/simple-tree/mapNode.ts +2 -2
  561. package/src/simple-tree/objectNode.ts +9 -3
  562. package/src/simple-tree/proxies.ts +10 -33
  563. package/src/simple-tree/proxyBinding.ts +23 -0
  564. package/src/simple-tree/schemaFactory.ts +37 -2
  565. package/src/simple-tree/schemaTypes.ts +36 -1
  566. package/src/simple-tree/toFlexSchema.ts +5 -4
  567. package/src/simple-tree/tree.ts +68 -4
  568. package/src/simple-tree/treeNodeApi.ts +29 -111
  569. package/src/simple-tree/treeNodeKernel.ts +91 -0
  570. package/src/simple-tree/types.ts +292 -31
  571. package/src/util/breakable.ts +214 -0
  572. package/src/util/index.ts +11 -0
  573. package/src/util/nestedMap.ts +33 -3
  574. package/src/util/utils.ts +17 -0
  575. package/dist/feature-libraries/node-key/nodeKeyIndex.d.ts +0 -41
  576. package/dist/feature-libraries/node-key/nodeKeyIndex.d.ts.map +0 -1
  577. package/dist/feature-libraries/node-key/nodeKeyIndex.js +0 -101
  578. package/dist/feature-libraries/node-key/nodeKeyIndex.js.map +0 -1
  579. package/lib/feature-libraries/node-key/nodeKeyIndex.d.ts +0 -41
  580. package/lib/feature-libraries/node-key/nodeKeyIndex.d.ts.map +0 -1
  581. package/lib/feature-libraries/node-key/nodeKeyIndex.js +0 -97
  582. package/lib/feature-libraries/node-key/nodeKeyIndex.js.map +0 -1
  583. package/src/feature-libraries/node-key/nodeKeyIndex.ts +0 -132
@@ -4,15 +4,15 @@
4
4
  */
5
5
  import { assert } from "@fluidframework/core-utils/internal";
6
6
  import { BTree } from "@tylerbu/sorted-btree-es6";
7
- import { EditBuilder, isEmptyFieldChanges, makeAnonChange, makeDetachedNodeId, mapCursorField, revisionMetadataSourceFromInfo, } from "../../core/index.js";
8
- import { addToNestedSet, brand, deleteFromNestedMap, fail, forEachInNestedMap, getOrAddInMap, idAllocatorFromMaxId, idAllocatorFromState, nestedMapFromFlatList, nestedMapToFlatList, nestedSetContains, populateNestedMap, setInNestedMap, tryGetFromNestedMap, } from "../../util/index.js";
7
+ import { EditBuilder, isEmptyFieldChanges, makeAnonChange, makeDetachedNodeId, mapCursorField, replaceAtomRevisions, revisionMetadataSourceFromInfo, setInChangeAtomIdMap, areEqualChangeAtomIds, getFromChangeAtomIdMap, } from "../../core/index.js";
8
+ import { brand, deleteFromNestedMap, fail, forEachInNestedMap, getOrAddInMap, idAllocatorFromMaxId, idAllocatorFromState, nestedMapFromFlatList, nestedMapToFlatList, populateNestedMap, setInNestedMap, tryGetFromNestedMap, } from "../../util/index.js";
9
9
  import { chunkFieldSingle, chunkTree, defaultChunkPolicy, } from "../chunked-forest/index.js";
10
10
  import { cursorForMapTreeNode, mapTreeFromCursor } from "../mapTreeCursor.js";
11
11
  import { MemoizedIdRangeAllocator } from "../memoizedIdRangeAllocator.js";
12
12
  import { CrossFieldTarget, getFirstFromCrossFieldMap, setInCrossFieldMap, } from "./crossFieldQueries.js";
13
13
  import { NodeAttachState, } from "./fieldChangeHandler.js";
14
14
  import { withEditor } from "./fieldKindWithEditor.js";
15
- import { convertGenericChange, genericFieldKind, newGenericChangeset, } from "./genericFieldKind.js";
15
+ import { convertGenericChange, genericFieldKind } from "./genericFieldKind.js";
16
16
  /**
17
17
  * Implementation of ChangeFamily which delegates work in a given field to the appropriate FieldKind
18
18
  * as determined by the schema.
@@ -34,27 +34,30 @@ export class ModularChangeFamily {
34
34
  */
35
35
  normalizeFieldChanges(change1, change2, genId, revisionMetadata) {
36
36
  // TODO: Handle the case where changes have conflicting field kinds
37
- const kind = change1 !== undefined && change1.fieldKind !== genericFieldKind.identifier
37
+ const kind = change1.fieldKind !== genericFieldKind.identifier
38
38
  ? change1.fieldKind
39
- : change2?.fieldKind ?? genericFieldKind.identifier;
39
+ : change2.fieldKind;
40
40
  if (kind === genericFieldKind.identifier) {
41
- // All the changes are generic
41
+ // Both changes are generic
42
42
  return {
43
- fieldKind: genericFieldKind,
44
- change1: change1?.change,
45
- change2: change2?.change,
43
+ fieldKind: genericFieldKind.identifier,
44
+ changeHandler: genericFieldKind.changeHandler,
45
+ change1: change1.change,
46
+ change2: change2.change,
46
47
  };
47
48
  }
48
49
  const fieldKind = getFieldKind(this.fieldKinds, kind);
49
- const handler = fieldKind.changeHandler;
50
- const normalizedChange1 = this.normalizeFieldChange(change1, handler, genId, revisionMetadata);
51
- const normalizedChange2 = this.normalizeFieldChange(change2, handler, genId, revisionMetadata);
52
- return { fieldKind, change1: normalizedChange1, change2: normalizedChange2 };
50
+ const changeHandler = fieldKind.changeHandler;
51
+ const normalizedChange1 = this.normalizeFieldChange(change1, changeHandler, genId, revisionMetadata);
52
+ const normalizedChange2 = this.normalizeFieldChange(change2, changeHandler, genId, revisionMetadata);
53
+ return {
54
+ fieldKind: kind,
55
+ changeHandler,
56
+ change1: normalizedChange1,
57
+ change2: normalizedChange2,
58
+ };
53
59
  }
54
60
  normalizeFieldChange(fieldChange, handler, genId, revisionMetadata) {
55
- if (fieldChange === undefined) {
56
- return undefined;
57
- }
58
61
  if (fieldChange.fieldKind !== genericFieldKind.identifier) {
59
62
  return fieldChange.change;
60
63
  }
@@ -69,105 +72,224 @@ export class ModularChangeFamily {
69
72
  compose(changes) {
70
73
  const { revInfos, maxId } = getRevInfoFromTaggedChanges(changes);
71
74
  const idState = { maxId };
72
- return changes.reduce((change1, change2) => makeAnonChange(this.composePair(change1, change2, revInfos, idState)), makeAnonChange({ fieldChanges: new Map(), nodeChanges: new Map() })).change;
75
+ if (changes.length === 0) {
76
+ return makeModularChangeset();
77
+ }
78
+ return changes.reduce((change1, change2) => makeAnonChange(this.composePair(change1, change2, revInfos, idState))).change;
73
79
  }
74
80
  composePair(change1, change2, revInfos, idState) {
75
- const genId = idAllocatorFromState(idState);
76
- const revisionMetadata = revisionMetadataSourceFromInfo(revInfos);
77
- const crossFieldTable = newComposeTable();
78
- const composedFields = this.composeFieldMaps(getActiveFieldChanges(change1.change), getActiveFieldChanges(change2.change), genId, crossFieldTable, revisionMetadata);
79
- const composedNodeChanges = new Map();
80
- for (const [id1, id2] of crossFieldTable.nodeIdPairs) {
81
- this.composeNodesById(change1.change.nodeChanges, change2.change.nodeChanges, composedNodeChanges, id1, id2, genId, crossFieldTable, revisionMetadata);
82
- }
83
- crossFieldTable.nodeIdPairs.length = 0;
84
- while (crossFieldTable.invalidatedFields.size > 0) {
85
- const fieldsToUpdate = crossFieldTable.invalidatedFields;
86
- crossFieldTable.invalidatedFields = new Set();
87
- for (const fieldChange of fieldsToUpdate) {
88
- const context = crossFieldTable.fieldToContext.get(fieldChange);
89
- assert(context !== undefined, 0x8cc /* Should have context for every invalidated field */);
90
- const { change1: fieldChange1, change2: fieldChange2, composedChange } = context;
91
- const rebaser = getChangeHandler(this.fieldKinds, composedChange.fieldKind).rebaser;
92
- const composeNodes = (child1, child2) => {
93
- if (child2 !== undefined &&
94
- !nestedSetContains(crossFieldTable.nodeIds, child2.revision, child2.localId)) {
95
- crossFieldTable.nodeIdPairs.push([child1, child2]);
96
- if (child1 !== undefined && child2 !== undefined) {
97
- addToNestedSet(crossFieldTable.nodeIds, child2.revision, child2.localId);
98
- }
99
- }
100
- return child1 ?? child2 ?? fail("Should not compose two undefined nodes");
101
- };
102
- const amendedChange = rebaser.compose(fieldChange1, fieldChange2, composeNodes, genId, newCrossFieldManager(crossFieldTable, fieldChange, false), revisionMetadata);
103
- composedChange.change = brand(amendedChange);
104
- // Process any newly discovered nodes.
105
- for (const [taggedId1, taggedId2] of crossFieldTable.nodeIdPairs) {
106
- this.composeNodesById(change1.change.nodeChanges, change2.change.nodeChanges, composedNodeChanges, taggedId1, taggedId2, genId, crossFieldTable, revisionMetadata);
107
- }
108
- crossFieldTable.nodeIdPairs.length = 0;
109
- }
110
- }
81
+ const { fieldChanges, nodeChanges, nodeToParent, nodeAliases, crossFieldKeys } = this.composeAllFields(change1.change, change2.change, revInfos, idState);
111
82
  const { allBuilds, allDestroys, allRefreshers } = composeBuildsDestroysAndRefreshers([
112
83
  change1,
113
84
  change2,
114
85
  ]);
115
- return makeModularChangeset(this.pruneFieldMap(composedFields, composedNodeChanges), composedNodeChanges, idState.maxId, revInfos, undefined, allBuilds, allDestroys, allRefreshers);
86
+ return makeModularChangeset(this.pruneFieldMap(fieldChanges, nodeChanges), nodeChanges, nodeToParent, nodeAliases, crossFieldKeys, idState.maxId, revInfos, undefined, allBuilds, allDestroys, allRefreshers);
87
+ }
88
+ composeAllFields(change1, change2, revInfos, idState) {
89
+ if (hasConflicts(change1) && hasConflicts(change2)) {
90
+ return {
91
+ fieldChanges: new Map(),
92
+ nodeChanges: new Map(),
93
+ nodeToParent: new Map(),
94
+ nodeAliases: new Map(),
95
+ crossFieldKeys: newBTree(),
96
+ };
97
+ }
98
+ else if (hasConflicts(change1)) {
99
+ return change2;
100
+ }
101
+ else if (hasConflicts(change2)) {
102
+ return change1;
103
+ }
104
+ const genId = idAllocatorFromState(idState);
105
+ const revisionMetadata = revisionMetadataSourceFromInfo(revInfos);
106
+ const crossFieldTable = newComposeTable(change1, change2);
107
+ // We merge nodeChanges, nodeToParent, and nodeAliases from the two changesets.
108
+ // The merged tables will have correct entries for all nodes which are only referenced in one of the input changesets.
109
+ // During composeFieldMaps and processInvalidatedElements we will find all nodes referenced in both input changesets
110
+ // and adjust these tables as necessary.
111
+ // Note that when merging these tables we may encounter key collisions and will arbitrarily drop values in that case.
112
+ // A collision for a node ID means that that node is referenced in both changesets
113
+ // (since we assume that if two changesets use the same node ID they are referring to the same node),
114
+ // therefore all collisions will be addressed when processing the intersection of the changesets.
115
+ const composedNodeChanges = mergeNestedMaps(change1.nodeChanges, change2.nodeChanges);
116
+ const composedNodeToParent = mergeNestedMaps(change1.nodeToParent, change2.nodeToParent);
117
+ const composedNodeAliases = mergeNestedMaps(change1.nodeAliases, change2.nodeAliases);
118
+ const composedFields = this.composeFieldMaps(change1.fieldChanges, change2.fieldChanges, genId, crossFieldTable, revisionMetadata);
119
+ this.processInvalidatedElements(crossFieldTable, composedFields, composedNodeChanges, composedNodeToParent, composedNodeAliases, genId, revisionMetadata);
120
+ // Currently no field kinds require making changes to cross-field keys during composition, so we can just merge the two tables.
121
+ const composedCrossFieldKeys = mergeBTrees(change1.crossFieldKeys, change2.crossFieldKeys);
122
+ return {
123
+ fieldChanges: composedFields,
124
+ nodeChanges: composedNodeChanges,
125
+ nodeToParent: composedNodeToParent,
126
+ nodeAliases: composedNodeAliases,
127
+ crossFieldKeys: brand(composedCrossFieldKeys),
128
+ };
129
+ }
130
+ composeInvalidatedField(fieldChange, crossFieldTable, genId, revisionMetadata) {
131
+ const context = crossFieldTable.fieldToContext.get(fieldChange);
132
+ assert(context !== undefined, 0x8cc /* Should have context for every invalidated field */);
133
+ const { change1: fieldChange1, change2: fieldChange2, composedChange } = context;
134
+ const rebaser = getChangeHandler(this.fieldKinds, composedChange.fieldKind).rebaser;
135
+ const composeNodes = (child1, child2) => {
136
+ if (child1 !== undefined &&
137
+ child2 !== undefined &&
138
+ getFromChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2) === undefined) {
139
+ setInChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2, child1);
140
+ crossFieldTable.pendingCompositions.nodeIdsToCompose.push([child1, child2]);
141
+ }
142
+ return child1 ?? child2 ?? fail("Should not compose two undefined nodes");
143
+ };
144
+ const amendedChange = rebaser.compose(fieldChange1, fieldChange2, composeNodes, genId, new ComposeManager(crossFieldTable, fieldChange, false), revisionMetadata);
145
+ composedChange.change = brand(amendedChange);
146
+ }
147
+ /**
148
+ * Updates everything in the composed output which may no longer be valid.
149
+ * This could be due to
150
+ * - discovering that two node changesets refer to the same node (`nodeIdsToCompose`)
151
+ * - a previously composed field being invalidated by a cross field effect (`invalidatedFields`)
152
+ * - a field which was copied directly from an input changeset being invalidated by a cross field effect
153
+ * (`affectedBaseFields` and `affectedNewFields`)
154
+ *
155
+ * Updating an element may invalidate further elements. This function runs until there is no more invalidation.
156
+ */
157
+ processInvalidatedElements(table, composedFields, composedNodes, composedNodeToParent, nodeAliases, genId, metadata) {
158
+ const pending = table.pendingCompositions;
159
+ while (table.invalidatedFields.size > 0 ||
160
+ pending.nodeIdsToCompose.length > 0 ||
161
+ pending.affectedBaseFields.length > 0 ||
162
+ pending.affectedNewFields.length > 0) {
163
+ // Note that the call to `composeNodesById` can add entries to `crossFieldTable.nodeIdPairs`.
164
+ for (const [id1, id2] of pending.nodeIdsToCompose) {
165
+ this.composeNodesById(table.baseChange.nodeChanges, table.newChange.nodeChanges, composedNodes, composedNodeToParent, nodeAliases, id1, id2, genId, table, metadata);
166
+ }
167
+ pending.nodeIdsToCompose.length = 0;
168
+ this.composeAffectedFields(table, table.baseChange, true, pending.affectedBaseFields, composedFields, composedNodes, genId, metadata);
169
+ this.composeAffectedFields(table, table.newChange, false, pending.affectedNewFields, composedFields, composedNodes, genId, metadata);
170
+ this.processInvalidatedCompositions(table, genId, metadata);
171
+ }
172
+ }
173
+ processInvalidatedCompositions(table, genId, metadata) {
174
+ const fieldsToUpdate = table.invalidatedFields;
175
+ table.invalidatedFields = new Set();
176
+ for (const fieldChange of fieldsToUpdate) {
177
+ this.composeInvalidatedField(fieldChange, table, genId, metadata);
178
+ }
179
+ }
180
+ /**
181
+ * Ensures that each field in `affectedFields` has been updated in the composition output.
182
+ * Any field which has already been composed is ignored.
183
+ * All other fields are optimistically assumed to not have any changes in the other input changeset.
184
+ *
185
+ * @param change - The changeset which contains the affected fields.
186
+ * This should be one of the two changesets being composed.
187
+ * @param areBaseFields - Whether the affected fields are part of the base changeset.
188
+ * If not, they are assumed to be part of the new changeset.
189
+ * @param affectedFields - The set of fields to process.
190
+ */
191
+ composeAffectedFields(table, change, areBaseFields, affectedFields, composedFields, composedNodes, genId, metadata) {
192
+ for (const fieldIdKey of affectedFields.keys()) {
193
+ const fieldId = normalizeFieldId(fieldIdFromFieldIdKey(fieldIdKey), change.nodeAliases);
194
+ const fieldChange = fieldChangeFromId(change.fieldChanges, change.nodeChanges, fieldId);
195
+ if (table.fieldToContext.has(fieldChange) ||
196
+ table.newFieldToBaseField.has(fieldChange)) {
197
+ // This function handles fields which were not part of the intersection of the two changesets but which need to be updated anyway.
198
+ // If we've already processed this field then either it is up to date
199
+ // or there is pending inval which will be handled in processInvalidatedCompositions.
200
+ continue;
201
+ }
202
+ const emptyChange = this.createEmptyFieldChange(fieldChange.fieldKind);
203
+ const [change1, change2] = areBaseFields
204
+ ? [fieldChange, emptyChange]
205
+ : [emptyChange, fieldChange];
206
+ const composedField = this.composeFieldChanges(change1, change2, genId, table, metadata);
207
+ if (fieldId.nodeId === undefined) {
208
+ composedFields.set(fieldId.field, composedField);
209
+ continue;
210
+ }
211
+ const nodeId = getFromChangeAtomIdMap(table.newToBaseNodeId, fieldId.nodeId) ?? fieldId.nodeId;
212
+ let nodeChangeset = nodeChangeFromId(composedNodes, nodeId);
213
+ if (!table.composedNodes.has(nodeChangeset)) {
214
+ nodeChangeset = cloneNodeChangeset(nodeChangeset);
215
+ setInChangeAtomIdMap(composedNodes, nodeId, nodeChangeset);
216
+ }
217
+ if (nodeChangeset.fieldChanges === undefined) {
218
+ nodeChangeset.fieldChanges = new Map();
219
+ }
220
+ nodeChangeset.fieldChanges.set(fieldId.field, composedField);
221
+ }
222
+ affectedFields.clear();
116
223
  }
117
224
  composeFieldMaps(change1, change2, genId, crossFieldTable, revisionMetadata) {
118
225
  const composedFields = new Map();
119
- const fields = new Set();
120
- for (const field of change1?.keys() ?? []) {
121
- fields.add(field);
122
- }
123
- for (const field of change2?.keys() ?? []) {
124
- fields.add(field);
125
- }
126
- for (const field of fields) {
127
- const fieldChange1 = change1?.get(field);
128
- const fieldChange2 = change2?.get(field);
129
- const { fieldKind, change1: normalizedFieldChange1, change2: normalizedFieldChange2, } = this.normalizeFieldChanges(fieldChange1, fieldChange2, genId, revisionMetadata);
130
- const manager = newCrossFieldManager(crossFieldTable, fieldChange1 ?? fieldChange2);
131
- const change1Normalized = normalizedFieldChange1 ?? fieldKind.changeHandler.createEmpty();
132
- const change2Normalized = normalizedFieldChange2 ?? fieldKind.changeHandler.createEmpty();
133
- const composedChange = fieldKind.changeHandler.rebaser.compose(change1Normalized, change2Normalized, (child1, child2) => {
134
- crossFieldTable.nodeIdPairs.push([child1, child2]);
135
- if (child2 !== undefined) {
136
- addToNestedSet(crossFieldTable.nodeIds, child2.revision, child2.localId);
137
- }
138
- return child1 ?? child2 ?? fail("Should not compose two undefined nodes");
139
- }, genId, manager, revisionMetadata);
140
- const composedField = {
141
- fieldKind: fieldKind.identifier,
142
- change: brand(composedChange),
143
- };
144
- const fieldKey = fieldChange1 ?? fieldChange2 ?? fail("At least one field should have changes");
145
- crossFieldTable.fieldToContext.set(fieldKey, {
146
- change1: change1Normalized,
147
- change2: change2Normalized,
148
- composedChange: composedField,
149
- });
150
- // TODO: Could optimize by checking that composedField is non-empty
226
+ if (change1 === undefined || change2 === undefined) {
227
+ return change1 ?? change2 ?? composedFields;
228
+ }
229
+ for (const [field, fieldChange1] of change1) {
230
+ const fieldChange2 = change2.get(field);
231
+ const composedField = fieldChange2 !== undefined
232
+ ? this.composeFieldChanges(fieldChange1, fieldChange2, genId, crossFieldTable, revisionMetadata)
233
+ : fieldChange1;
151
234
  composedFields.set(field, composedField);
152
235
  }
236
+ for (const [field, fieldChange2] of change2) {
237
+ if (change1 === undefined || !change1.has(field)) {
238
+ composedFields.set(field, fieldChange2);
239
+ }
240
+ }
153
241
  return composedFields;
154
242
  }
155
- composeNodesById(nodeChanges1, nodeChanges2, composedNodeChanges, id1, id2, idAllocator, crossFieldTable, revisionMetadata) {
156
- const nodeChangeset1 = id1 !== undefined
157
- ? tryGetFromNestedMap(nodeChanges1, id1.revision, id1.localId) ??
158
- fail("Unknown node ID")
159
- : {};
160
- const nodeChangeset2 = id2 !== undefined
161
- ? tryGetFromNestedMap(nodeChanges2, id2.revision, id2.localId) ??
162
- fail("Unknown node ID")
163
- : {};
243
+ /**
244
+ * Returns the composition of the two input fields.
245
+ *
246
+ * Any nodes in this field which were modified by both changesets
247
+ * will be added to `crossFieldTable.pendingCompositions.nodeIdsToCompose`.
248
+ *
249
+ * Any fields which had cross-field information sent to them as part of this field composition
250
+ * will be added to either `affectedBaseFields` or `affectedNewFields` in `crossFieldTable.pendingCompositions`.
251
+ *
252
+ * Any composed `FieldChange` which is invalidated by new cross-field information will be added to `crossFieldTable.invalidatedFields`.
253
+ */
254
+ composeFieldChanges(change1, change2, idAllocator, crossFieldTable, revisionMetadata) {
255
+ const { fieldKind, changeHandler, change1: change1Normalized, change2: change2Normalized, } = this.normalizeFieldChanges(change1, change2, idAllocator, revisionMetadata);
256
+ const manager = new ComposeManager(crossFieldTable, change1);
257
+ const composedChange = changeHandler.rebaser.compose(change1Normalized, change2Normalized, (child1, child2) => {
258
+ if (child1 !== undefined && child2 !== undefined) {
259
+ setInChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2, child1);
260
+ crossFieldTable.pendingCompositions.nodeIdsToCompose.push([child1, child2]);
261
+ }
262
+ return child1 ?? child2 ?? fail("Should not compose two undefined nodes");
263
+ }, idAllocator, manager, revisionMetadata);
264
+ const composedField = {
265
+ fieldKind,
266
+ change: brand(composedChange),
267
+ };
268
+ crossFieldTable.fieldToContext.set(change1, {
269
+ change1: change1Normalized,
270
+ change2: change2Normalized,
271
+ composedChange: composedField,
272
+ });
273
+ crossFieldTable.newFieldToBaseField.set(change2, change1);
274
+ return composedField;
275
+ }
276
+ composeNodesById(nodeChanges1, nodeChanges2, composedNodes, composedNodeToParent, nodeAliases, id1, id2, idAllocator, crossFieldTable, revisionMetadata) {
277
+ const nodeChangeset1 = nodeChangeFromId(nodeChanges1, id1);
278
+ const nodeChangeset2 = nodeChangeFromId(nodeChanges2, id2);
164
279
  const composedNodeChangeset = this.composeNodeChanges(nodeChangeset1, nodeChangeset2, idAllocator, crossFieldTable, revisionMetadata);
165
- const nodeId = id1 ?? id2 ?? fail("Should not compose two undefined node IDs");
166
- setInNestedMap(composedNodeChanges, nodeId.revision, nodeId.localId, composedNodeChangeset);
280
+ setInChangeAtomIdMap(composedNodes, id1, composedNodeChangeset);
281
+ if (!areEqualChangeAtomIds(id1, id2)) {
282
+ deleteFromNestedMap(composedNodes, id2.revision, id2.localId);
283
+ deleteFromNestedMap(composedNodeToParent, id2.revision, id2.localId);
284
+ setInChangeAtomIdMap(nodeAliases, id2, id1);
285
+ // We need to delete id1 to avoid forming a cycle in case id1 already had an alias.
286
+ deleteFromNestedMap(nodeAliases, id1.revision, id1.localId);
287
+ }
288
+ crossFieldTable.composedNodes.add(composedNodeChangeset);
167
289
  }
168
290
  composeNodeChanges(change1, change2, genId, crossFieldTable, revisionMetadata) {
169
- const nodeExistsConstraint = change1?.nodeExistsConstraint ?? change2?.nodeExistsConstraint;
170
- const composedFieldChanges = this.composeFieldMaps(change1?.fieldChanges, change2?.fieldChanges, genId, crossFieldTable, revisionMetadata);
291
+ const nodeExistsConstraint = change1.nodeExistsConstraint ?? change2.nodeExistsConstraint;
292
+ const composedFieldChanges = this.composeFieldMaps(change1.fieldChanges, change2.fieldChanges, genId, crossFieldTable, revisionMetadata);
171
293
  const composedNodeChange = {};
172
294
  if (composedFieldChanges.size > 0) {
173
295
  composedNodeChange.fieldChanges = composedFieldChanges;
@@ -190,23 +312,21 @@ export class ModularChangeFamily {
190
312
  // Destroys only occur in rollback changesets, which are never inverted.
191
313
  assert(change.change.destroys === undefined, 0x89a /* Unexpected destroys in change to invert */);
192
314
  if ((change.change.constraintViolationCount ?? 0) > 0) {
193
- return makeModularChangeset(undefined, undefined, change.change.maxId, [], undefined, undefined, destroys);
315
+ return makeModularChangeset(undefined, undefined, undefined, undefined, undefined, change.change.maxId, [], undefined, undefined, destroys);
194
316
  }
195
- const idState = { maxId: change.change.maxId ?? -1 };
196
- // This idState is used for the whole of the IdAllocator's lifetime, which allows
197
- // this function to read the updated idState.maxId after more IDs are allocated.
198
- // TODO: add a getMax function to IdAllocator to make for a clearer contract.
199
- const genId = idAllocatorFromState(idState);
317
+ const genId = idAllocatorFromMaxId(change.change.maxId ?? -1);
318
+ const invertedNodeToParent = cloneNestedMap(change.change.nodeToParent);
200
319
  const crossFieldTable = {
201
320
  ...newCrossFieldTable(),
202
321
  originalFieldToContext: new Map(),
322
+ invertedNodeToParent,
203
323
  };
204
324
  const { revInfos } = getRevInfoFromTaggedChanges([change]);
205
325
  const revisionMetadata = revisionMetadataSourceFromInfo(revInfos);
206
- const invertedFields = this.invertFieldMap(change.change.fieldChanges, isRollback, genId, crossFieldTable, revisionMetadata);
326
+ const invertedFields = this.invertFieldMap(change.change.fieldChanges, undefined, isRollback, genId, crossFieldTable, revisionMetadata);
207
327
  const invertedNodes = new Map();
208
328
  forEachInNestedMap(change.change.nodeChanges, (nodeChangeset, revision, localId) => {
209
- setInNestedMap(invertedNodes, revision, localId, this.invertNodeChange(nodeChangeset, isRollback, genId, crossFieldTable, revisionMetadata));
329
+ setInNestedMap(invertedNodes, revision, localId, this.invertNodeChange(nodeChangeset, { revision, localId }, isRollback, genId, crossFieldTable, revisionMetadata));
210
330
  });
211
331
  if (crossFieldTable.invalidatedFields.size > 0) {
212
332
  const fieldsToUpdate = crossFieldTable.invalidatedFields;
@@ -215,17 +335,19 @@ export class ModularChangeFamily {
215
335
  const originalFieldChange = fieldChange.change;
216
336
  const context = crossFieldTable.originalFieldToContext.get(fieldChange);
217
337
  assert(context !== undefined, 0x851 /* Should have context for every invalidated field */);
218
- const { invertedField } = context;
219
- const amendedChange = getChangeHandler(this.fieldKinds, fieldChange.fieldKind).rebaser.invert(originalFieldChange, isRollback, genId, newCrossFieldManager(crossFieldTable, fieldChange), revisionMetadata);
338
+ const { invertedField, fieldId } = context;
339
+ const amendedChange = getChangeHandler(this.fieldKinds, fieldChange.fieldKind).rebaser.invert(originalFieldChange, isRollback, genId, new InvertManager(crossFieldTable, fieldChange, fieldId), revisionMetadata);
220
340
  invertedField.change = brand(amendedChange);
221
341
  }
222
342
  }
223
- return makeModularChangeset(invertedFields, invertedNodes, idState.maxId, [], change.change.constraintViolationCount, undefined, destroys);
343
+ const crossFieldKeys = this.makeCrossFieldKeyTable(invertedFields, invertedNodes);
344
+ return makeModularChangeset(invertedFields, invertedNodes, invertedNodeToParent, change.change.nodeAliases, crossFieldKeys, genId.getMaxId(), [], change.change.constraintViolationCount, undefined, destroys);
224
345
  }
225
- invertFieldMap(changes, isRollback, genId, crossFieldTable, revisionMetadata) {
346
+ invertFieldMap(changes, parentId, isRollback, genId, crossFieldTable, revisionMetadata) {
226
347
  const invertedFields = new Map();
227
348
  for (const [field, fieldChange] of changes) {
228
- const manager = newCrossFieldManager(crossFieldTable, fieldChange);
349
+ const fieldId = { nodeId: parentId, field };
350
+ const manager = new InvertManager(crossFieldTable, fieldChange, fieldId);
229
351
  const invertedChange = getChangeHandler(this.fieldKinds, fieldChange.fieldKind).rebaser.invert(fieldChange.change, isRollback, genId, manager, revisionMetadata);
230
352
  const invertedFieldChange = {
231
353
  ...fieldChange,
@@ -233,15 +355,16 @@ export class ModularChangeFamily {
233
355
  };
234
356
  invertedFields.set(field, invertedFieldChange);
235
357
  crossFieldTable.originalFieldToContext.set(fieldChange, {
358
+ fieldId,
236
359
  invertedField: invertedFieldChange,
237
360
  });
238
361
  }
239
362
  return invertedFields;
240
363
  }
241
- invertNodeChange(change, isRollback, genId, crossFieldTable, revisionMetadata) {
364
+ invertNodeChange(change, id, isRollback, genId, crossFieldTable, revisionMetadata) {
242
365
  const inverse = {};
243
366
  if (change.fieldChanges !== undefined) {
244
- inverse.fieldChanges = this.invertFieldMap(change.fieldChanges, isRollback, genId, crossFieldTable, revisionMetadata);
367
+ inverse.fieldChanges = this.invertFieldMap(change.fieldChanges, id, isRollback, genId, crossFieldTable, revisionMetadata);
245
368
  }
246
369
  return inverse;
247
370
  }
@@ -252,9 +375,15 @@ export class ModularChangeFamily {
252
375
  const genId = idAllocatorFromState(idState);
253
376
  const crossFieldTable = {
254
377
  ...newCrossFieldTable(),
255
- fieldToContext: new Map(),
256
- rebasedNodeCache: new Map(),
378
+ newChange: change,
379
+ baseChange: over.change,
380
+ baseFieldToContext: new Map(),
381
+ baseToRebasedNodeId: new Map(),
382
+ rebasedFields: new Set(),
383
+ rebasedNodeToParent: cloneNestedMap(change.nodeToParent),
384
+ rebasedCrossFieldKeys: brand(change.crossFieldKeys.clone()),
257
385
  nodeIdPairs: [],
386
+ affectedBaseFields: newBTree(),
258
387
  };
259
388
  let constraintState = newConstraintState(change.constraintViolationCount ?? 0);
260
389
  const getBaseRevisions = () => revisionInfoFromTaggedChange(over).map((info) => info.revision);
@@ -263,108 +392,198 @@ export class ModularChangeFamily {
263
392
  getRevisionToRebase: () => taggedChange.revision,
264
393
  getBaseRevisions,
265
394
  };
266
- const rebasedFields = this.rebaseFieldMap(change.fieldChanges, over.change.fieldChanges, genId, crossFieldTable, rebaseMetadata);
267
- const rebasedNodes = new Map();
268
- for (const [newId, baseId] of crossFieldTable.nodeIdPairs) {
269
- const newNodeChange = newId !== undefined
270
- ? tryGetFromNestedMap(change.nodeChanges, newId.revision, newId.localId)
271
- : undefined;
272
- const baseNodeChange = baseId !== undefined
273
- ? tryGetFromNestedMap(over.change.nodeChanges, baseId.revision, baseId.localId) ??
274
- fail("Unknown node ID")
275
- : {};
276
- const rebasedNode = this.rebaseNodeChange(newNodeChange, baseNodeChange, genId, crossFieldTable, rebaseMetadata);
277
- if (rebasedNode !== undefined) {
278
- const nodeId = newId ?? baseId ?? fail("Should not have two undefined IDs");
279
- setInNestedMap(rebasedNodes, nodeId.revision, nodeId.localId, rebasedNode);
280
- }
281
- }
395
+ const rebasedNodes = cloneNestedMap(change.nodeChanges);
396
+ const rebasedFields = this.rebaseIntersectingFields(crossFieldTable, rebasedNodes, genId, constraintState, rebaseMetadata);
397
+ this.rebaseFieldsWithoutNewChanges(rebasedFields, rebasedNodes, crossFieldTable, genId, rebaseMetadata);
282
398
  if (crossFieldTable.invalidatedFields.size > 0) {
283
399
  const fieldsToUpdate = crossFieldTable.invalidatedFields;
284
400
  crossFieldTable.invalidatedFields = new Set();
285
401
  constraintState = newConstraintState(change.constraintViolationCount ?? 0);
286
402
  for (const field of fieldsToUpdate) {
287
- // TODO: Should we copy the context table out before this loop?
288
- const context = crossFieldTable.fieldToContext.get(field);
403
+ const context = crossFieldTable.baseFieldToContext.get(field);
289
404
  assert(context !== undefined, 0x852 /* Every field should have a context */);
290
- const { fieldKind, change1: fieldChangeset, change2: baseChangeset, } = this.normalizeFieldChanges(context.newChange, context.baseChange, genId, revisionMetadata);
291
- context.rebasedChange.change = fieldKind.changeHandler.rebaser.rebase(fieldChangeset, baseChangeset, (curr, base, existenceState) => curr ?? base, genId, newCrossFieldManager(crossFieldTable, field), rebaseMetadata);
405
+ const { changeHandler, change1: fieldChangeset, change2: baseChangeset, } = this.normalizeFieldChanges(context.newChange, context.baseChange, genId, revisionMetadata);
406
+ const rebaseChild = (curr, base) => {
407
+ if (curr !== undefined) {
408
+ return curr;
409
+ }
410
+ if (base !== undefined) {
411
+ for (const id of context.baseNodeIds) {
412
+ if (areEqualChangeAtomIds(base, id)) {
413
+ return base;
414
+ }
415
+ }
416
+ }
417
+ return undefined;
418
+ };
419
+ context.rebasedChange.change = brand(changeHandler.rebaser.rebase(fieldChangeset, baseChangeset, rebaseChild, genId, new RebaseManager(crossFieldTable, field, context.fieldId), rebaseMetadata));
292
420
  }
293
421
  }
294
422
  this.updateConstraintsForFields(rebasedFields, NodeAttachState.Attached, constraintState, rebasedNodes);
295
- return makeModularChangeset(this.pruneFieldMap(rebasedFields, rebasedNodes), rebasedNodes, idState.maxId, change.revisions, constraintState.violationCount, change.builds, change.destroys, change.refreshers);
423
+ return makeModularChangeset(this.pruneFieldMap(rebasedFields, rebasedNodes), rebasedNodes, crossFieldTable.rebasedNodeToParent, change.nodeAliases, crossFieldTable.rebasedCrossFieldKeys, idState.maxId, change.revisions, constraintState.violationCount, change.builds, change.destroys, change.refreshers);
296
424
  }
297
- rebaseFieldMap(change, over, genId, crossFieldTable, revisionMetadata) {
298
- const rebasedFields = new Map();
299
- // Rebase fields contained in the base changeset
300
- for (const [field, baseChanges] of over) {
301
- const fieldChange = change.get(field) ?? {
302
- fieldKind: genericFieldKind.identifier,
303
- change: brand(newGenericChangeset()),
425
+ // This performs a first pass on all fields which have both new and base changes.
426
+ // TODO: Can we also handle additional passes in this method?
427
+ rebaseIntersectingFields(crossFieldTable, rebasedNodes, genId, constraintState, metadata) {
428
+ const change = crossFieldTable.newChange;
429
+ const baseChange = crossFieldTable.baseChange;
430
+ const rebasedFields = this.rebaseFieldMap(change.fieldChanges, baseChange.fieldChanges, undefined, genId, crossFieldTable, metadata);
431
+ // This loop processes all fields which have both base and new changes.
432
+ // Note that the call to `rebaseNodeChange` can add entries to `crossFieldTable.nodeIdPairs`.
433
+ for (const [newId, baseId, _attachState] of crossFieldTable.nodeIdPairs) {
434
+ const rebasedNode = this.rebaseNodeChange(newId, baseId, genId, crossFieldTable, metadata, constraintState);
435
+ setInChangeAtomIdMap(rebasedNodes, newId, rebasedNode);
436
+ }
437
+ return rebasedFields;
438
+ }
439
+ // This processes fields which have no new changes but have been invalidated by another field.
440
+ rebaseFieldsWithoutNewChanges(rebasedFields, rebasedNodes, crossFieldTable, genId, metadata) {
441
+ const baseChange = crossFieldTable.baseChange;
442
+ for (const [revision, localId, fieldKey] of crossFieldTable.affectedBaseFields.keys()) {
443
+ const baseNodeId = localId !== undefined
444
+ ? normalizeNodeId({ revision, localId }, baseChange.nodeAliases)
445
+ : undefined;
446
+ const baseFieldChange = fieldMapFromNodeId(baseChange.fieldChanges, baseChange.nodeChanges, baseNodeId).get(fieldKey);
447
+ assert(baseFieldChange !== undefined, 0x9c2 /* Cross field key registered for empty field */);
448
+ if (crossFieldTable.baseFieldToContext.has(baseFieldChange)) {
449
+ // This field has already been processed because there were changes to rebase.
450
+ continue;
451
+ }
452
+ // This field has no changes in the new changeset, otherwise it would have been added to
453
+ // `crossFieldTable.baseFieldToContext` when processing fields with both base and new changes.
454
+ const rebaseChild = (child, baseChild, stateChange) => {
455
+ assert(child === undefined, 0x9c3 /* There should be no new changes in this field */);
456
+ return undefined;
304
457
  };
305
- const { fieldKind, change1: fieldChangeset, change2: baseChangeset, } = this.normalizeFieldChanges(fieldChange, baseChanges, genId, revisionMetadata);
306
- const manager = newCrossFieldManager(crossFieldTable, fieldChange);
307
- const rebaseChild = (child, baseChild, _attachState) => {
308
- crossFieldTable.nodeIdPairs.push([child, baseChild]);
309
- return (child ??
310
- // The fact `child` is undefined means that the changeset to rebase does not include changes for
311
- // this node or its descendants. However, it's possible that it will after rebasing.
312
- // In that case, we will need a NodeId to represent these changes under in the rebased changeset.
313
- // We adopt `baseChild` for this purpose.
314
- baseChild ??
315
- fail("Should not have two undefined node IDs"));
458
+ const handler = getChangeHandler(this.fieldKinds, baseFieldChange.fieldKind);
459
+ const fieldChange = {
460
+ ...baseFieldChange,
461
+ change: brand(handler.createEmpty()),
316
462
  };
317
- const rebasedField = fieldKind.changeHandler.rebaser.rebase(fieldChangeset, baseChangeset, rebaseChild, genId, manager, revisionMetadata);
463
+ const rebasedNodeId = baseNodeId !== undefined
464
+ ? rebasedNodeIdFromBaseNodeId(crossFieldTable, baseNodeId)
465
+ : undefined;
466
+ const fieldId = { nodeId: rebasedNodeId, field: fieldKey };
467
+ const rebasedField = handler.rebaser.rebase(fieldChange.change, baseFieldChange.change, rebaseChild, genId, new RebaseManager(crossFieldTable, baseFieldChange, fieldId), metadata);
318
468
  const rebasedFieldChange = {
319
- fieldKind: fieldKind.identifier,
469
+ ...baseFieldChange,
320
470
  change: brand(rebasedField),
321
471
  };
322
- rebasedFields.set(field, rebasedFieldChange);
323
- crossFieldTable.fieldToContext.set(fieldChange, {
324
- baseChange: baseChanges,
472
+ // TODO: Deduplicate
473
+ crossFieldTable.baseFieldToContext.set(baseFieldChange, {
325
474
  newChange: fieldChange,
475
+ baseChange: baseFieldChange,
326
476
  rebasedChange: rebasedFieldChange,
477
+ fieldId,
478
+ baseNodeIds: [],
327
479
  });
480
+ crossFieldTable.rebasedFields.add(rebasedFieldChange);
481
+ this.attachRebasedField(rebasedFields, rebasedNodes, crossFieldTable, rebasedFieldChange, fieldId, genId, metadata);
482
+ }
483
+ }
484
+ attachRebasedField(rebasedFields, rebasedNodes, table, rebasedField, { nodeId, field: fieldKey }, idAllocator, metadata) {
485
+ if (nodeId === undefined) {
486
+ rebasedFields.set(fieldKey, rebasedField);
487
+ return;
488
+ }
489
+ const rebasedNode = getFromChangeAtomIdMap(rebasedNodes, nodeId);
490
+ if (rebasedNode !== undefined) {
491
+ if (rebasedNode.fieldChanges === undefined) {
492
+ rebasedNode.fieldChanges = new Map([[fieldKey, rebasedField]]);
493
+ return;
494
+ }
495
+ assert(!rebasedNode.fieldChanges.has(fieldKey), 0x9c4 /* Expected an empty field */);
496
+ rebasedNode.fieldChanges.set(fieldKey, rebasedField);
497
+ return;
328
498
  }
329
- // Rebase the fields of the new changeset which don't have a corresponding base field.
499
+ const newNode = {
500
+ fieldChanges: new Map([[fieldKey, rebasedField]]),
501
+ };
502
+ setInChangeAtomIdMap(rebasedNodes, nodeId, newNode);
503
+ setInChangeAtomIdMap(table.baseToRebasedNodeId, nodeId, nodeId);
504
+ const parentFieldId = getParentFieldId(table.baseChange, nodeId);
505
+ this.attachRebasedNode(rebasedFields, rebasedNodes, table, nodeId, parentFieldId, idAllocator, metadata);
506
+ }
507
+ attachRebasedNode(rebasedFields, rebasedNodes, table, baseNodeId, parentFieldIdBase, idAllocator, metadata) {
508
+ const baseFieldChange = fieldChangeFromId(table.baseChange.fieldChanges, table.baseChange.nodeChanges, parentFieldIdBase);
509
+ const rebasedFieldId = rebasedFieldIdFromBaseId(table, parentFieldIdBase);
510
+ setInChangeAtomIdMap(table.rebasedNodeToParent, baseNodeId, rebasedFieldId);
511
+ const context = table.baseFieldToContext.get(baseFieldChange);
512
+ if (context !== undefined) {
513
+ // We've already processed this field.
514
+ // The new child node can be attached when processing invalidated fields.
515
+ context.baseNodeIds.push(baseNodeId);
516
+ table.invalidatedFields.add(baseFieldChange);
517
+ return;
518
+ }
519
+ const handler = getChangeHandler(this.fieldKinds, baseFieldChange.fieldKind);
520
+ const fieldChange = {
521
+ ...baseFieldChange,
522
+ change: brand(handler.createEmpty()),
523
+ };
524
+ const rebasedChangeset = handler.rebaser.rebase(handler.createEmpty(), baseFieldChange.change, (_idNew, idBase) => idBase !== undefined && areEqualChangeAtomIds(idBase, baseNodeId)
525
+ ? baseNodeId
526
+ : undefined, idAllocator, new RebaseManager(table, baseFieldChange, rebasedFieldId), metadata);
527
+ const rebasedField = { ...baseFieldChange, change: brand(rebasedChangeset) };
528
+ table.rebasedFields.add(rebasedField);
529
+ table.baseFieldToContext.set(baseFieldChange, {
530
+ newChange: fieldChange,
531
+ baseChange: baseFieldChange,
532
+ rebasedChange: rebasedField,
533
+ fieldId: rebasedFieldId,
534
+ baseNodeIds: [],
535
+ });
536
+ this.attachRebasedField(rebasedFields, rebasedNodes, table, rebasedField, rebasedFieldId, idAllocator, metadata);
537
+ }
538
+ rebaseFieldMap(change, over, parentId, genId, crossFieldTable, revisionMetadata) {
539
+ const rebasedFields = new Map();
540
+ const rebaseChild = (child, baseChild, stateChange) => {
541
+ if (child !== undefined && baseChild !== undefined) {
542
+ crossFieldTable.nodeIdPairs.push([child, baseChild, stateChange]);
543
+ }
544
+ return child;
545
+ };
330
546
  for (const [field, fieldChange] of change) {
331
- if (!over?.has(field)) {
332
- const baseChanges = {
333
- fieldKind: genericFieldKind.identifier,
334
- change: brand(newGenericChangeset()),
335
- };
336
- const { fieldKind, change1: fieldChangeset, change2: baseChangeset, } = this.normalizeFieldChanges(fieldChange, baseChanges, genId, revisionMetadata);
337
- // TODO: Don't we need to add an entry in the context table?
338
- const manager = newCrossFieldManager(crossFieldTable, fieldChange);
339
- const rebasedChangeset = fieldKind.changeHandler.rebaser.rebase(fieldChangeset, baseChangeset, (child, baseChild) => {
340
- assert(baseChild === undefined, 0x5b6 /* This field should not have any base changes */);
341
- crossFieldTable.nodeIdPairs.push([child, undefined]);
342
- return child;
343
- }, genId, manager, revisionMetadata);
344
- const rebasedFieldChange = {
345
- fieldKind: fieldKind.identifier,
346
- change: brand(rebasedChangeset),
347
- };
348
- rebasedFields.set(field, rebasedFieldChange);
547
+ const fieldId = { nodeId: parentId, field };
548
+ const baseChange = over.get(field);
549
+ if (baseChange === undefined) {
550
+ rebasedFields.set(field, fieldChange);
551
+ continue;
349
552
  }
553
+ const { fieldKind, changeHandler, change1: fieldChangeset, change2: baseChangeset, } = this.normalizeFieldChanges(fieldChange, baseChange, genId, revisionMetadata);
554
+ const manager = new RebaseManager(crossFieldTable, baseChange, fieldId);
555
+ const rebasedField = changeHandler.rebaser.rebase(fieldChangeset, baseChangeset, rebaseChild, genId, manager, revisionMetadata);
556
+ const rebasedFieldChange = {
557
+ fieldKind,
558
+ change: brand(rebasedField),
559
+ };
560
+ rebasedFields.set(field, rebasedFieldChange);
561
+ crossFieldTable.baseFieldToContext.set(baseChange, {
562
+ baseChange,
563
+ newChange: fieldChange,
564
+ rebasedChange: rebasedFieldChange,
565
+ fieldId,
566
+ baseNodeIds: [],
567
+ });
568
+ crossFieldTable.rebasedFields.add(rebasedFieldChange);
350
569
  }
351
570
  return rebasedFields;
352
571
  }
353
- rebaseNodeChange(change, over, genId, crossFieldTable, revisionMetadata) {
354
- const key = change ?? over;
355
- if (key === undefined) {
356
- return undefined;
357
- }
572
+ rebaseNodeChange(newId, baseId, genId, crossFieldTable, revisionMetadata, constraintState) {
573
+ const change = nodeChangeFromId(crossFieldTable.newChange.nodeChanges, newId);
574
+ const over = nodeChangeFromId(crossFieldTable.baseChange.nodeChanges, baseId);
358
575
  const baseMap = over?.fieldChanges ?? new Map();
359
- const fieldChanges = this.rebaseFieldMap(change?.fieldChanges ?? new Map(), baseMap, genId, crossFieldTable, revisionMetadata);
576
+ const fieldChanges = change.fieldChanges !== undefined && over.fieldChanges !== undefined
577
+ ? this.rebaseFieldMap(change?.fieldChanges ?? new Map(), baseMap, newId, genId, crossFieldTable, revisionMetadata)
578
+ : change.fieldChanges;
360
579
  const rebasedChange = {};
361
- if (fieldChanges.size > 0) {
580
+ if (fieldChanges !== undefined && fieldChanges.size > 0) {
362
581
  rebasedChange.fieldChanges = fieldChanges;
363
582
  }
364
583
  if (change?.nodeExistsConstraint !== undefined) {
365
584
  rebasedChange.nodeExistsConstraint = change.nodeExistsConstraint;
366
585
  }
367
- crossFieldTable.rebasedNodeCache.set(key, rebasedChange);
586
+ setInChangeAtomIdMap(crossFieldTable.baseToRebasedNodeId, baseId, newId);
368
587
  return rebasedChange;
369
588
  }
370
589
  updateConstraintsForFields(fields, parentAttachState, constraintState, nodes) {
@@ -396,6 +615,9 @@ export class ModularChangeFamily {
396
615
  }
397
616
  }
398
617
  pruneFieldMap(changeset, nodeMap) {
618
+ if (changeset === undefined) {
619
+ return undefined;
620
+ }
399
621
  const prunedChangeset = new Map();
400
622
  for (const [field, fieldChange] of changeset) {
401
623
  const handler = getChangeHandler(this.fieldKinds, fieldChange.fieldKind);
@@ -407,8 +629,7 @@ export class ModularChangeFamily {
407
629
  return prunedChangeset.size > 0 ? prunedChangeset : undefined;
408
630
  }
409
631
  pruneNodeChange(nodeId, nodeMap) {
410
- const changeset = tryGetFromNestedMap(nodeMap, nodeId.revision, nodeId.localId);
411
- assert(changeset !== undefined, 0x930 /* Unknown node ID */);
632
+ const changeset = nodeChangeFromId(nodeMap, nodeId);
412
633
  const prunedFields = changeset.fieldChanges !== undefined
413
634
  ? this.pruneFieldMap(changeset.fieldChanges, nodeMap)
414
635
  : undefined;
@@ -421,7 +642,7 @@ export class ModularChangeFamily {
421
642
  return undefined;
422
643
  }
423
644
  else {
424
- setInNestedMap(nodeMap, nodeId.revision, nodeId.localId, prunedChange);
645
+ setInChangeAtomIdMap(nodeMap, nodeId, prunedChange);
425
646
  return nodeId;
426
647
  }
427
648
  }
@@ -435,10 +656,19 @@ export class ModularChangeFamily {
435
656
  id,
436
657
  this.replaceNodeChangesetRevisions(nodeChangeset, oldRevisions, newRevision),
437
658
  ]));
659
+ const updatedNodeToParent = nestedMapFromFlatList(nestedMapToFlatList(change.nodeToParent).map(([revision, id, fieldId]) => [
660
+ replaceRevision(revision, oldRevisions, newRevision),
661
+ id,
662
+ replaceFieldIdRevision(normalizeFieldId(fieldId, change.nodeAliases), oldRevisions, newRevision),
663
+ ]));
438
664
  const updated = {
439
665
  ...change,
440
666
  fieldChanges: updatedFields,
441
667
  nodeChanges: updatedNodes,
668
+ nodeToParent: updatedNodeToParent,
669
+ // We've updated all references to old node IDs, so we no longer need an alias table.
670
+ nodeAliases: new Map(),
671
+ crossFieldKeys: replaceCrossFieldKeyTableRevisions(change.crossFieldKeys, oldRevisions, newRevision, change.nodeAliases),
442
672
  };
443
673
  if (change.builds !== undefined) {
444
674
  updated.builds = replaceIdMapRevisions(change.builds, oldRevisions, newRevision);
@@ -471,16 +701,62 @@ export class ModularChangeFamily {
471
701
  replaceFieldMapRevisions(fields, oldRevisions, newRevision) {
472
702
  const updatedFields = new Map();
473
703
  for (const [field, fieldChange] of fields) {
474
- const updatedFieldChange = getFieldKind(this.fieldKinds, fieldChange.fieldKind).changeHandler.rebaser.replaceRevisions(fieldChange.change, oldRevisions, newRevision);
475
- updatedFields.set(field, { ...fieldChange, change: updatedFieldChange });
704
+ const updatedFieldChange = getChangeHandler(this.fieldKinds, fieldChange.fieldKind).rebaser.replaceRevisions(fieldChange.change, oldRevisions, newRevision);
705
+ updatedFields.set(field, { ...fieldChange, change: brand(updatedFieldChange) });
476
706
  }
477
707
  return updatedFields;
478
708
  }
709
+ makeCrossFieldKeyTable(fields, nodes) {
710
+ const keys = newCrossFieldKeyTable();
711
+ this.populateCrossFieldKeyTableForFieldMap(keys, fields, undefined);
712
+ forEachInNestedMap(nodes, (node, revision, localId) => {
713
+ if (node.fieldChanges !== undefined) {
714
+ this.populateCrossFieldKeyTableForFieldMap(keys, node.fieldChanges, {
715
+ revision,
716
+ localId,
717
+ });
718
+ }
719
+ });
720
+ return keys;
721
+ }
722
+ populateCrossFieldKeyTableForFieldMap(table, fields, parent) {
723
+ for (const [fieldKey, fieldChange] of fields) {
724
+ const keys = getChangeHandler(this.fieldKinds, fieldChange.fieldKind).getCrossFieldKeys(fieldChange.change);
725
+ for (const key of keys) {
726
+ table.set(key, { nodeId: parent, field: fieldKey });
727
+ }
728
+ }
729
+ }
479
730
  buildEditor(changeReceiver) {
480
- return new ModularEditBuilder(this, changeReceiver);
731
+ return new ModularEditBuilder(this, this.fieldKinds, changeReceiver);
732
+ }
733
+ createEmptyFieldChange(fieldKind) {
734
+ const emptyChange = getChangeHandler(this.fieldKinds, fieldKind).createEmpty();
735
+ return { fieldKind, change: brand(emptyChange) };
481
736
  }
482
737
  }
483
738
  ModularChangeFamily.emptyChange = makeModularChangeset();
739
+ function replaceCrossFieldKeyTableRevisions(table, oldRevisions, newRevision, nodeAliases) {
740
+ const updated = newBTree();
741
+ table.forEachPair(([target, revision, id, count], field) => {
742
+ const updatedKey = [
743
+ target,
744
+ replaceRevision(revision, oldRevisions, newRevision),
745
+ id,
746
+ count,
747
+ ];
748
+ const normalizedFieldId = normalizeFieldId(field, nodeAliases);
749
+ const updatedNodeId = normalizedFieldId.nodeId !== undefined
750
+ ? replaceAtomRevisions(normalizedFieldId.nodeId, oldRevisions, newRevision)
751
+ : undefined;
752
+ const updatedValue = {
753
+ ...normalizedFieldId,
754
+ nodeId: updatedNodeId,
755
+ };
756
+ updated.set(updatedKey, updatedValue);
757
+ });
758
+ return updated;
759
+ }
484
760
  function replaceRevision(revision, oldRevisions, newRevision) {
485
761
  return oldRevisions.has(revision) ? newRevision : revision;
486
762
  }
@@ -595,8 +871,7 @@ function* relevantRemovedRootsFromFields(change, nodeChanges, fieldKinds) {
595
871
  for (const [_, fieldChange] of change) {
596
872
  const handler = getChangeHandler(fieldKinds, fieldChange.fieldKind);
597
873
  const delegate = function* (node) {
598
- const nodeChangeset = tryGetFromNestedMap(nodeChanges, node.revision, node.localId);
599
- assert(nodeChangeset !== undefined, 0x931 /* Unknown node ID */);
874
+ const nodeChangeset = nodeChangeFromId(nodeChanges, node);
600
875
  if (nodeChangeset.fieldChanges !== undefined) {
601
876
  yield* relevantRemovedRootsFromFields(nodeChangeset.fieldChanges, nodeChanges, fieldKinds);
602
877
  }
@@ -650,7 +925,7 @@ export function updateRefreshers(change, getDetachedNode, removedRoots, requireR
650
925
  }
651
926
  }
652
927
  const { fieldChanges, nodeChanges, maxId, revisions, constraintViolationCount, builds, destroys, } = change;
653
- return makeModularChangeset(fieldChanges, nodeChanges, maxId, revisions, constraintViolationCount, builds, destroys, refreshers);
928
+ return makeModularChangeset(fieldChanges, nodeChanges, change.nodeToParent, change.nodeAliases, change.crossFieldKeys, maxId, revisions, constraintViolationCount, builds, destroys, refreshers);
654
929
  }
655
930
  /**
656
931
  * @param change - The change to convert into a delta.
@@ -706,8 +981,7 @@ function intoDeltaImpl(change, nodeChanges, idAllocator, fieldKinds) {
706
981
  const delta = new Map();
707
982
  for (const [field, fieldChange] of change) {
708
983
  const deltaField = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(fieldChange.change, (childChange) => {
709
- const nodeChange = tryGetFromNestedMap(nodeChanges, childChange.revision, childChange.localId);
710
- assert(nodeChange !== undefined, 0x932 /* Unknown node ID */);
984
+ const nodeChange = nodeChangeFromId(nodeChanges, childChange);
711
985
  return deltaFromNodeChange(nodeChange, nodeChanges, idAllocator, fieldKinds);
712
986
  }, idAllocator);
713
987
  if (!isEmptyFieldChanges(deltaField)) {
@@ -764,12 +1038,20 @@ export function getFieldKind(fieldKinds, kind) {
764
1038
  export function getChangeHandler(fieldKinds, kind) {
765
1039
  return getFieldKind(fieldKinds, kind).changeHandler;
766
1040
  }
767
- function newComposeTable() {
1041
+ function newComposeTable(baseChange, newChange) {
768
1042
  return {
769
1043
  ...newCrossFieldTable(),
1044
+ baseChange,
1045
+ newChange,
770
1046
  fieldToContext: new Map(),
771
- nodeIds: new Map(),
772
- nodeIdPairs: [],
1047
+ newFieldToBaseField: new Map(),
1048
+ newToBaseNodeId: new Map(),
1049
+ composedNodes: new Set(),
1050
+ pendingCompositions: {
1051
+ nodeIdsToCompose: [],
1052
+ affectedBaseFields: newBTree(),
1053
+ affectedNewFields: newBTree(),
1054
+ },
773
1055
  };
774
1056
  }
775
1057
  function newCrossFieldTable() {
@@ -786,43 +1068,148 @@ function newConstraintState(violationCount) {
786
1068
  violationCount,
787
1069
  };
788
1070
  }
789
- function newCrossFieldManager(crossFieldTable, currentFieldKey, allowInval = true) {
790
- const getMap = (target) => target === CrossFieldTarget.Source ? crossFieldTable.srcTable : crossFieldTable.dstTable;
791
- const getDependents = (target) => target === CrossFieldTarget.Source
792
- ? crossFieldTable.srcDependents
793
- : crossFieldTable.dstDependents;
794
- const manager = {
795
- table: crossFieldTable,
796
- set: (target, revision, id, count, newValue, invalidateDependents) => {
797
- if (invalidateDependents && allowInval) {
798
- const lastChangedId = id + count - 1;
799
- let firstId = id;
800
- while (firstId <= lastChangedId) {
801
- const dependentEntry = getFirstFromCrossFieldMap(getDependents(target), revision, firstId, lastChangedId - firstId + 1);
802
- if (dependentEntry.value !== undefined) {
803
- crossFieldTable.invalidatedFields.add(dependentEntry.value);
804
- }
805
- firstId = brand(firstId + dependentEntry.length);
1071
+ class CrossFieldManagerI {
1072
+ constructor(crossFieldTable, currentFieldKey, allowInval = true) {
1073
+ this.crossFieldTable = crossFieldTable;
1074
+ this.currentFieldKey = currentFieldKey;
1075
+ this.allowInval = allowInval;
1076
+ }
1077
+ set(target, revision, id, count, newValue, invalidateDependents) {
1078
+ if (invalidateDependents && this.allowInval) {
1079
+ const lastChangedId = id + count - 1;
1080
+ let firstId = id;
1081
+ while (firstId <= lastChangedId) {
1082
+ const dependentEntry = getFirstFromCrossFieldMap(this.getDependents(target), revision, firstId, lastChangedId - firstId + 1);
1083
+ if (dependentEntry.value !== undefined) {
1084
+ this.crossFieldTable.invalidatedFields.add(dependentEntry.value);
806
1085
  }
1086
+ firstId = brand(firstId + dependentEntry.length);
807
1087
  }
808
- setInCrossFieldMap(getMap(target), revision, id, count, newValue);
809
- },
810
- get: (target, revision, id, count, addDependency) => {
811
- if (addDependency) {
812
- // We assume that if there is already an entry for this ID it is because
813
- // a field handler has called compose on the same node multiple times.
814
- // In this case we only want to update the latest version, so we overwrite the dependency.
815
- setInCrossFieldMap(getDependents(target), revision, id, count, currentFieldKey);
1088
+ }
1089
+ setInCrossFieldMap(this.getMap(target), revision, id, count, newValue);
1090
+ }
1091
+ get(target, revision, id, count, addDependency) {
1092
+ if (addDependency) {
1093
+ // We assume that if there is already an entry for this ID it is because
1094
+ // a field handler has called compose on the same node multiple times.
1095
+ // In this case we only want to update the latest version, so we overwrite the dependency.
1096
+ setInCrossFieldMap(this.getDependents(target), revision, id, count, this.currentFieldKey);
1097
+ }
1098
+ return getFirstFromCrossFieldMap(this.getMap(target), revision, id, count);
1099
+ }
1100
+ getMap(target) {
1101
+ return target === CrossFieldTarget.Source
1102
+ ? this.crossFieldTable.srcTable
1103
+ : this.crossFieldTable.dstTable;
1104
+ }
1105
+ getDependents(target) {
1106
+ return target === CrossFieldTarget.Source
1107
+ ? this.crossFieldTable.srcDependents
1108
+ : this.crossFieldTable.dstDependents;
1109
+ }
1110
+ }
1111
+ class InvertManager extends CrossFieldManagerI {
1112
+ constructor(table, field, fieldId, allowInval = true) {
1113
+ super(table, field, allowInval);
1114
+ this.fieldId = fieldId;
1115
+ }
1116
+ onMoveIn(id) {
1117
+ setInChangeAtomIdMap(this.table.invertedNodeToParent, id, this.fieldId);
1118
+ }
1119
+ moveKey(target, revision, id, count) {
1120
+ assert(false, 0x9c5 /* Keys should not be moved manually during invert */);
1121
+ }
1122
+ get table() {
1123
+ return this.crossFieldTable;
1124
+ }
1125
+ }
1126
+ class RebaseManager extends CrossFieldManagerI {
1127
+ constructor(table, currentField, fieldId, allowInval = true) {
1128
+ super(table, currentField, allowInval);
1129
+ this.fieldId = fieldId;
1130
+ }
1131
+ set(target, revision, id, count, newValue, invalidateDependents) {
1132
+ if (invalidateDependents && this.allowInval) {
1133
+ const newFieldIds = getFieldsForCrossFieldKey(this.table.newChange, [
1134
+ target,
1135
+ revision,
1136
+ id,
1137
+ count,
1138
+ ]);
1139
+ assert(newFieldIds.length === 0, 0x9c6 /* TODO: Modifying a cross-field key from the new changeset is currently unsupported */);
1140
+ const baseFieldIds = getFieldsForCrossFieldKey(this.table.baseChange, [
1141
+ target,
1142
+ revision,
1143
+ id,
1144
+ count,
1145
+ ]);
1146
+ assert(baseFieldIds.length > 0, 0x9c7 /* Cross field key not registered in base or new change */);
1147
+ for (const baseFieldId of baseFieldIds) {
1148
+ this.table.affectedBaseFields.set([baseFieldId.nodeId?.revision, baseFieldId.nodeId?.localId, baseFieldId.field], true);
816
1149
  }
817
- return getFirstFromCrossFieldMap(getMap(target), revision, id, count);
818
- },
819
- };
820
- return manager;
1150
+ }
1151
+ super.set(target, revision, id, count, newValue, invalidateDependents);
1152
+ }
1153
+ onMoveIn(id) {
1154
+ setInChangeAtomIdMap(this.table.rebasedNodeToParent, id, this.fieldId);
1155
+ }
1156
+ moveKey(target, revision, id, count) {
1157
+ setInCrossFieldKeyTable(this.table.rebasedCrossFieldKeys, target, revision, id, count, this.fieldId);
1158
+ }
1159
+ get table() {
1160
+ return this.crossFieldTable;
1161
+ }
1162
+ }
1163
+ // TODO: Deduplicate this with RebaseTable
1164
+ class ComposeManager extends CrossFieldManagerI {
1165
+ constructor(table, currentField, allowInval = true) {
1166
+ super(table, currentField, allowInval);
1167
+ }
1168
+ set(target, revision, id, count, newValue, invalidateDependents) {
1169
+ if (invalidateDependents && this.allowInval) {
1170
+ const newFieldIds = getFieldsForCrossFieldKey(this.table.newChange, [
1171
+ target,
1172
+ revision,
1173
+ id,
1174
+ count,
1175
+ ]);
1176
+ if (newFieldIds.length > 0) {
1177
+ for (const newFieldId of newFieldIds) {
1178
+ this.table.pendingCompositions.affectedNewFields.set([newFieldId.nodeId?.revision, newFieldId.nodeId?.localId, newFieldId.field], true);
1179
+ }
1180
+ }
1181
+ else {
1182
+ const baseFieldIds = getFieldsForCrossFieldKey(this.table.baseChange, [
1183
+ target,
1184
+ revision,
1185
+ id,
1186
+ count,
1187
+ ]);
1188
+ assert(baseFieldIds.length > 0, 0x9c8 /* Cross field key not registered in base or new change */);
1189
+ for (const baseFieldId of baseFieldIds) {
1190
+ this.table.pendingCompositions.affectedBaseFields.set([baseFieldId.nodeId?.revision, baseFieldId.nodeId?.localId, baseFieldId.field], true);
1191
+ }
1192
+ }
1193
+ }
1194
+ super.set(target, revision, id, count, newValue, invalidateDependents);
1195
+ }
1196
+ onMoveIn(id) {
1197
+ throw new Error("Method not implemented.");
1198
+ }
1199
+ moveKey(target, revision, id, count) {
1200
+ throw new Error("Method not implemented.");
1201
+ }
1202
+ get table() {
1203
+ return this.crossFieldTable;
1204
+ }
821
1205
  }
822
- function makeModularChangeset(fieldChanges = undefined, nodeChanges = undefined, maxId = -1, revisions = undefined, constraintViolationCount = undefined, builds, destroys, refreshers) {
1206
+ function makeModularChangeset(fieldChanges = undefined, nodeChanges = undefined, nodeToParent = undefined, nodeAliases = undefined, crossFieldKeys = undefined, maxId = -1, revisions = undefined, constraintViolationCount = undefined, builds, destroys, refreshers) {
823
1207
  const changeset = {
824
1208
  fieldChanges: fieldChanges ?? new Map(),
825
1209
  nodeChanges: nodeChanges ?? new Map(),
1210
+ nodeToParent: nodeToParent ?? new Map(),
1211
+ nodeAliases: nodeAliases ?? new Map(),
1212
+ crossFieldKeys: crossFieldKeys ?? newCrossFieldKeyTable(),
826
1213
  };
827
1214
  if (revisions !== undefined && revisions.length > 0) {
828
1215
  changeset.revisions = revisions;
@@ -845,8 +1232,9 @@ function makeModularChangeset(fieldChanges = undefined, nodeChanges = undefined,
845
1232
  return changeset;
846
1233
  }
847
1234
  export class ModularEditBuilder extends EditBuilder {
848
- constructor(family, changeReceiver) {
1235
+ constructor(family, fieldKinds, changeReceiver) {
849
1236
  super(family, changeReceiver);
1237
+ this.fieldKinds = fieldKinds;
850
1238
  this.transactionDepth = 0;
851
1239
  this.idAllocator = idAllocatorFromMaxId();
852
1240
  }
@@ -892,7 +1280,8 @@ export class ModularEditBuilder extends EditBuilder {
892
1280
  * @param maxId - the highest `ChangesetLocalId` used in this change
893
1281
  */
894
1282
  submitChange(field, fieldKind, change) {
895
- const modularChange = buildModularChangesetFromField(field, { fieldKind, change }, new Map(), this.idAllocator);
1283
+ const crossFieldKeys = getChangeHandler(this.fieldKinds, fieldKind).getCrossFieldKeys(change);
1284
+ const modularChange = buildModularChangesetFromField(field, { fieldKind, change }, new Map(), new Map(), newCrossFieldKeyTable(), this.idAllocator, crossFieldKeys);
896
1285
  this.applyChange(modularChange);
897
1286
  }
898
1287
  submitChanges(changes) {
@@ -901,11 +1290,11 @@ export class ModularEditBuilder extends EditBuilder {
901
1290
  }
902
1291
  buildChanges(changes) {
903
1292
  const changeMaps = changes.map((change) => makeAnonChange(change.type === "global"
904
- ? makeModularChangeset(undefined, undefined, this.idAllocator.getMaxId(), undefined, undefined, change.builds)
1293
+ ? makeModularChangeset(undefined, undefined, undefined, undefined, undefined, this.idAllocator.getMaxId(), undefined, undefined, change.builds)
905
1294
  : buildModularChangesetFromField(change.field, {
906
1295
  fieldKind: change.fieldKind,
907
1296
  change: change.change,
908
- }, new Map(), this.idAllocator)));
1297
+ }, new Map(), new Map(), newCrossFieldKeyTable(), this.idAllocator, getChangeHandler(this.fieldKinds, change.fieldKind).getCrossFieldKeys(change.change))));
909
1298
  const composedChange = this.changeFamily.rebaser.compose(changeMaps);
910
1299
  const maxId = brand(this.idAllocator.getMaxId());
911
1300
  if (maxId >= 0) {
@@ -920,28 +1309,46 @@ export class ModularEditBuilder extends EditBuilder {
920
1309
  const nodeChange = {
921
1310
  nodeExistsConstraint: { violated: false },
922
1311
  };
923
- this.applyChange(buildModularChangesetFromNode(path, nodeChange, new Map(), this.idAllocator));
1312
+ this.applyChange(buildModularChangesetFromNode(path, nodeChange, new Map(), new Map(), newCrossFieldKeyTable(), this.idAllocator));
924
1313
  }
925
1314
  }
926
- function buildModularChangesetFromField(path, fieldChange, nodeChanges, idAllocator = idAllocatorFromMaxId()) {
1315
+ function buildModularChangesetFromField(path, fieldChange, nodeChanges, nodeToParent, crossFieldKeys, idAllocator = idAllocatorFromMaxId(), localCrossFieldKeys = [], childId = undefined) {
927
1316
  const fieldChanges = new Map([[path.field, fieldChange]]);
928
1317
  if (path.parent === undefined) {
929
- return makeModularChangeset(fieldChanges, nodeChanges, idAllocator.getMaxId());
1318
+ for (const key of localCrossFieldKeys) {
1319
+ crossFieldKeys.set(key, { nodeId: undefined, field: path.field });
1320
+ }
1321
+ if (childId !== undefined) {
1322
+ setInChangeAtomIdMap(nodeToParent, childId, {
1323
+ nodeId: undefined,
1324
+ field: path.field,
1325
+ });
1326
+ }
1327
+ return makeModularChangeset(fieldChanges, nodeChanges, nodeToParent, undefined, crossFieldKeys, idAllocator.getMaxId());
930
1328
  }
931
1329
  const nodeChangeset = {
932
1330
  fieldChanges,
933
1331
  };
934
- return buildModularChangesetFromNode(path.parent, nodeChangeset, nodeChanges, idAllocator);
1332
+ const parentId = { localId: brand(idAllocator.allocate()) };
1333
+ for (const key of localCrossFieldKeys) {
1334
+ crossFieldKeys.set(key, { nodeId: parentId, field: path.field });
1335
+ }
1336
+ if (childId !== undefined) {
1337
+ setInChangeAtomIdMap(nodeToParent, childId, {
1338
+ nodeId: parentId,
1339
+ field: path.field,
1340
+ });
1341
+ }
1342
+ return buildModularChangesetFromNode(path.parent, nodeChangeset, nodeChanges, nodeToParent, crossFieldKeys, idAllocator, parentId);
935
1343
  }
936
- function buildModularChangesetFromNode(path, nodeChange, nodeChanges, idAllocator) {
937
- const nodeId = { localId: brand(idAllocator.allocate()) };
938
- setInNestedMap(nodeChanges, nodeId.revision, nodeId.localId, nodeChange);
1344
+ function buildModularChangesetFromNode(path, nodeChange, nodeChanges, nodeToParent, crossFieldKeys, idAllocator, nodeId = { localId: brand(idAllocator.allocate()) }) {
1345
+ setInChangeAtomIdMap(nodeChanges, nodeId, nodeChange);
939
1346
  const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChange(path.parentIndex, nodeId);
940
1347
  const fieldChange = {
941
1348
  fieldKind: genericFieldKind.identifier,
942
1349
  change: fieldChangeset,
943
1350
  };
944
- return buildModularChangesetFromField({ parent: path.parent, field: path.parentField }, fieldChange, nodeChanges, idAllocator);
1351
+ return buildModularChangesetFromField({ parent: path.parent, field: path.parentField }, fieldChange, nodeChanges, nodeToParent, crossFieldKeys, idAllocator, [], nodeId);
945
1352
  }
946
1353
  function getRevInfoFromTaggedChanges(changes) {
947
1354
  let maxId = -1;
@@ -990,9 +1397,181 @@ function revisionFromRevInfos(revInfos) {
990
1397
  }
991
1398
  return revInfos[0].revision;
992
1399
  }
993
- function getActiveFieldChanges(changes) {
994
- return (changes.constraintViolationCount ?? 0) === 0
995
- ? changes.fieldChanges
996
- : new Map();
1400
+ function mergeBTrees(tree1, tree2) {
1401
+ const result = tree1.clone();
1402
+ tree2.forEachPair((k, v) => {
1403
+ result.set(k, v);
1404
+ });
1405
+ return result;
1406
+ }
1407
+ function mergeNestedMaps(map1, map2) {
1408
+ const merged = new Map();
1409
+ populateNestedMap(map1, merged, true);
1410
+ populateNestedMap(map2, merged, true);
1411
+ return merged;
1412
+ }
1413
+ function fieldChangeFromId(fields, nodes, id) {
1414
+ const fieldMap = fieldMapFromNodeId(fields, nodes, id.nodeId);
1415
+ return fieldMap.get(id.field) ?? fail("No field exists for the given ID");
1416
+ }
1417
+ function fieldMapFromNodeId(rootFieldMap, nodes, nodeId) {
1418
+ if (nodeId === undefined) {
1419
+ return rootFieldMap;
1420
+ }
1421
+ const node = nodeChangeFromId(nodes, nodeId);
1422
+ assert(node.fieldChanges !== undefined, 0x9c9 /* Expected node to have field changes */);
1423
+ return node.fieldChanges;
1424
+ }
1425
+ function rebasedFieldIdFromBaseId(table, baseId) {
1426
+ if (baseId.nodeId === undefined) {
1427
+ return baseId;
1428
+ }
1429
+ return { ...baseId, nodeId: rebasedNodeIdFromBaseNodeId(table, baseId.nodeId) };
1430
+ }
1431
+ function rebasedNodeIdFromBaseNodeId(table, baseId) {
1432
+ return getFromChangeAtomIdMap(table.baseToRebasedNodeId, baseId) ?? baseId;
1433
+ }
1434
+ function nodeChangeFromId(nodes, id) {
1435
+ const node = getFromChangeAtomIdMap(nodes, id);
1436
+ assert(node !== undefined, 0x9ca /* Unknown node ID */);
1437
+ return node;
1438
+ }
1439
+ function fieldIdFromFieldIdKey([revision, localId, field]) {
1440
+ const nodeId = localId !== undefined ? { revision, localId } : undefined;
1441
+ return { nodeId, field };
1442
+ }
1443
+ function cloneNodeChangeset(nodeChangeset) {
1444
+ if (nodeChangeset.fieldChanges !== undefined) {
1445
+ return { ...nodeChangeset, fieldChanges: new Map(nodeChangeset.fieldChanges) };
1446
+ }
1447
+ return { ...nodeChangeset };
1448
+ }
1449
+ function replaceFieldIdRevision(fieldId, oldRevisions, newRevision) {
1450
+ if (fieldId.nodeId === undefined) {
1451
+ return fieldId;
1452
+ }
1453
+ return {
1454
+ ...fieldId,
1455
+ nodeId: replaceAtomRevisions(fieldId.nodeId, oldRevisions, newRevision),
1456
+ };
1457
+ }
1458
+ export function getParentFieldId(changeset, nodeId) {
1459
+ const parentId = getFromChangeAtomIdMap(changeset.nodeToParent, nodeId);
1460
+ assert(parentId !== undefined, 0x9cb /* Parent field should be defined */);
1461
+ return normalizeFieldId(parentId, changeset.nodeAliases);
1462
+ }
1463
+ export function getFieldsForCrossFieldKey(changeset, [target, revision, id, count]) {
1464
+ let firstLocalId = id;
1465
+ const lastLocalId = id + count - 1;
1466
+ const fields = [];
1467
+ // eslint-disable-next-line no-constant-condition
1468
+ while (true) {
1469
+ const entry = getFirstIntersectingCrossFieldEntry(changeset.crossFieldKeys, [
1470
+ target,
1471
+ revision,
1472
+ brand(firstLocalId),
1473
+ count,
1474
+ ]);
1475
+ if (entry === undefined) {
1476
+ return fields;
1477
+ }
1478
+ const [[_target, _revision, entryId, entryCount], fieldId] = entry;
1479
+ fields.push(normalizeFieldId(fieldId, changeset.nodeAliases));
1480
+ const entryLastId = entryId + entryCount - 1;
1481
+ if (entryLastId >= lastLocalId) {
1482
+ return fields;
1483
+ }
1484
+ firstLocalId = entryLastId + 1;
1485
+ }
1486
+ }
1487
+ function getFirstIntersectingCrossFieldEntry(table, [target, revision, id, count]) {
1488
+ const entry = table.nextLowerPair([target, revision, id, Infinity]);
1489
+ if (entry === undefined) {
1490
+ return undefined;
1491
+ }
1492
+ const [entryTarget, entryRevision, entryId, entryCount] = entry[0];
1493
+ if (entryTarget !== target || entryRevision !== revision) {
1494
+ return undefined;
1495
+ }
1496
+ const lastQueryId = id + count - 1;
1497
+ const entryLastId = entryId + entryCount - 1;
1498
+ if (entryId > lastQueryId || entryLastId < id) {
1499
+ return undefined;
1500
+ }
1501
+ return entry;
1502
+ }
1503
+ function setInCrossFieldKeyTable(table, target, revision, id, count, value) {
1504
+ let entry = getFirstIntersectingCrossFieldEntry(table, [target, revision, id, count]);
1505
+ const lastQueryId = id + count - 1;
1506
+ while (entry !== undefined) {
1507
+ const [entryKey, entryValue] = entry;
1508
+ table.delete(entryKey);
1509
+ const [_target, _revision, entryId, entryCount] = entryKey;
1510
+ if (entryId < id) {
1511
+ table.set([target, revision, entryId, id - entryId], entryValue);
1512
+ }
1513
+ const lastEntryId = entryId + entryCount - 1;
1514
+ if (lastEntryId > lastQueryId) {
1515
+ table.set([target, revision, brand(lastQueryId + 1), lastEntryId - lastQueryId], entryValue);
1516
+ break;
1517
+ }
1518
+ const nextId = brand(lastEntryId + 1);
1519
+ entry = getFirstIntersectingCrossFieldEntry(table, [
1520
+ target,
1521
+ revision,
1522
+ nextId,
1523
+ lastQueryId - nextId + 1,
1524
+ ]);
1525
+ }
1526
+ table.set([target, revision, id, count], value);
1527
+ }
1528
+ function normalizeFieldId(fieldId, nodeAliases) {
1529
+ return fieldId.nodeId !== undefined
1530
+ ? { ...fieldId, nodeId: normalizeNodeId(fieldId.nodeId, nodeAliases) }
1531
+ : fieldId;
1532
+ }
1533
+ /**
1534
+ * @returns The canonical form of nodeId, according to nodeAliases
1535
+ */
1536
+ function normalizeNodeId(nodeId, nodeAliases) {
1537
+ let currentId = nodeId;
1538
+ // eslint-disable-next-line no-constant-condition
1539
+ while (true) {
1540
+ const dealiased = getFromChangeAtomIdMap(nodeAliases, currentId);
1541
+ if (dealiased === undefined) {
1542
+ return currentId;
1543
+ }
1544
+ currentId = dealiased;
1545
+ }
1546
+ }
1547
+ function hasConflicts(change) {
1548
+ return (change.constraintViolationCount ?? 0) > 0;
1549
+ }
1550
+ export function newCrossFieldKeyTable() {
1551
+ return newBTree();
1552
+ }
1553
+ function newBTree() {
1554
+ return brand(new BTree(undefined, compareTuples));
1555
+ }
1556
+ // This assumes that the arrays are the same length.
1557
+ function compareTuples(arrayA, arrayB) {
1558
+ for (let i = 0; i < arrayA.length; i++) {
1559
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1560
+ const a = arrayA[i];
1561
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1562
+ const b = arrayB[i];
1563
+ if (a < b) {
1564
+ return -1;
1565
+ }
1566
+ else if (a > b) {
1567
+ return 1;
1568
+ }
1569
+ }
1570
+ return 0;
1571
+ }
1572
+ function cloneNestedMap(map) {
1573
+ const cloned = new Map();
1574
+ populateNestedMap(map, cloned, true);
1575
+ return cloned;
997
1576
  }
998
1577
  //# sourceMappingURL=modularChangeFamily.js.map