@fluidframework/tree 2.13.0 → 2.20.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 (303) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/api-report/tree.alpha.api.md +22 -12
  3. package/api-report/tree.beta.api.md +9 -5
  4. package/api-report/tree.legacy.alpha.api.md +9 -5
  5. package/api-report/tree.legacy.public.api.md +9 -5
  6. package/api-report/tree.public.api.md +9 -5
  7. package/assertTagging.config.mjs +14 -0
  8. package/dist/alpha.d.ts +3 -0
  9. package/dist/core/index.d.ts +2 -2
  10. package/dist/core/index.d.ts.map +1 -1
  11. package/dist/core/index.js +6 -4
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/core/rebase/index.d.ts +2 -2
  14. package/dist/core/rebase/index.d.ts.map +1 -1
  15. package/dist/core/rebase/index.js +5 -1
  16. package/dist/core/rebase/index.js.map +1 -1
  17. package/dist/core/rebase/types.d.ts +5 -4
  18. package/dist/core/rebase/types.d.ts.map +1 -1
  19. package/dist/core/rebase/types.js +29 -1
  20. package/dist/core/rebase/types.js.map +1 -1
  21. package/dist/core/rebase/utils.d.ts +10 -0
  22. package/dist/core/rebase/utils.d.ts.map +1 -1
  23. package/dist/core/rebase/utils.js +22 -1
  24. package/dist/core/rebase/utils.js.map +1 -1
  25. package/dist/core/tree/delta.d.ts +21 -26
  26. package/dist/core/tree/delta.d.ts.map +1 -1
  27. package/dist/core/tree/delta.js.map +1 -1
  28. package/dist/core/tree/deltaUtil.d.ts +1 -3
  29. package/dist/core/tree/deltaUtil.d.ts.map +1 -1
  30. package/dist/core/tree/deltaUtil.js +2 -14
  31. package/dist/core/tree/deltaUtil.js.map +1 -1
  32. package/dist/core/tree/index.d.ts +1 -1
  33. package/dist/core/tree/index.d.ts.map +1 -1
  34. package/dist/core/tree/index.js +1 -3
  35. package/dist/core/tree/index.js.map +1 -1
  36. package/dist/core/tree/visitDelta.d.ts.map +1 -1
  37. package/dist/core/tree/visitDelta.js +82 -80
  38. package/dist/core/tree/visitDelta.js.map +1 -1
  39. package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  40. package/dist/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  41. package/dist/feature-libraries/deltaUtils.d.ts.map +1 -1
  42. package/dist/feature-libraries/deltaUtils.js +13 -0
  43. package/dist/feature-libraries/deltaUtils.js.map +1 -1
  44. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  45. package/dist/feature-libraries/forest-summary/forestSummarizer.js +1 -6
  46. package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  47. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +5 -5
  48. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  49. package/dist/feature-libraries/modular-schema/crossFieldQueries.js +2 -9
  50. package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  51. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +19 -2
  52. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  53. package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  54. package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  55. package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  56. package/dist/feature-libraries/modular-schema/index.d.ts +2 -2
  57. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  58. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  59. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts +1 -1
  60. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  61. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +8 -8
  62. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  63. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +4 -4
  64. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  65. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +105 -199
  66. package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  67. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +11 -20
  68. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  69. package/dist/feature-libraries/modular-schema/modularChangeTypes.js +20 -0
  70. package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  71. package/dist/feature-libraries/optional-field/optionalField.d.ts +3 -3
  72. package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  73. package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
  74. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts +1 -1
  75. package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  76. package/dist/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  77. package/dist/feature-libraries/sequence-field/rebase.js +4 -4
  78. package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
  79. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.js +1 -1
  80. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.js.map +1 -1
  81. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js +1 -1
  82. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  83. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +2 -3
  84. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  85. package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  86. package/dist/feature-libraries/sequence-field/utils.js +36 -4
  87. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  88. package/dist/feature-libraries/treeCursorUtils.d.ts.map +1 -1
  89. package/dist/feature-libraries/treeCursorUtils.js +4 -1
  90. package/dist/feature-libraries/treeCursorUtils.js.map +1 -1
  91. package/dist/index.d.ts +26 -2
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +4 -2
  94. package/dist/index.js.map +1 -1
  95. package/dist/package.json +2 -1
  96. package/dist/packageVersion.d.ts +1 -1
  97. package/dist/packageVersion.js +1 -1
  98. package/dist/packageVersion.js.map +1 -1
  99. package/dist/shared-tree/index.d.ts +1 -1
  100. package/dist/shared-tree/index.d.ts.map +1 -1
  101. package/dist/shared-tree/index.js +4 -2
  102. package/dist/shared-tree/index.js.map +1 -1
  103. package/dist/shared-tree/sharedTree.d.ts +38 -18
  104. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  105. package/dist/shared-tree/sharedTree.js +38 -34
  106. package/dist/shared-tree/sharedTree.js.map +1 -1
  107. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  108. package/dist/shared-tree/treeCheckout.js +12 -8
  109. package/dist/shared-tree/treeCheckout.js.map +1 -1
  110. package/dist/simple-tree/api/treeNodeApi.js +1 -1
  111. package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
  112. package/dist/simple-tree/arrayNode.js +1 -1
  113. package/dist/simple-tree/arrayNode.js.map +1 -1
  114. package/dist/simple-tree/toMapTree.js +1 -1
  115. package/dist/simple-tree/toMapTree.js.map +1 -1
  116. package/dist/util/bTreeUtils.d.ts +10 -0
  117. package/dist/util/bTreeUtils.d.ts.map +1 -0
  118. package/dist/util/bTreeUtils.js +52 -0
  119. package/dist/util/bTreeUtils.js.map +1 -0
  120. package/dist/util/idAllocator.d.ts +0 -2
  121. package/dist/util/idAllocator.d.ts.map +1 -1
  122. package/dist/util/idAllocator.js +0 -2
  123. package/dist/util/idAllocator.js.map +1 -1
  124. package/dist/util/index.d.ts +2 -1
  125. package/dist/util/index.d.ts.map +1 -1
  126. package/dist/util/index.js +5 -1
  127. package/dist/util/index.js.map +1 -1
  128. package/dist/util/rangeMap.d.ts +52 -30
  129. package/dist/util/rangeMap.d.ts.map +1 -1
  130. package/dist/util/rangeMap.js +161 -117
  131. package/dist/util/rangeMap.js.map +1 -1
  132. package/dist/util/utils.d.ts +4 -1
  133. package/dist/util/utils.d.ts.map +1 -1
  134. package/dist/util/utils.js +7 -1
  135. package/dist/util/utils.js.map +1 -1
  136. package/lib/alpha.d.ts +3 -0
  137. package/lib/core/index.d.ts +2 -2
  138. package/lib/core/index.d.ts.map +1 -1
  139. package/lib/core/index.js +2 -2
  140. package/lib/core/index.js.map +1 -1
  141. package/lib/core/rebase/index.d.ts +2 -2
  142. package/lib/core/rebase/index.d.ts.map +1 -1
  143. package/lib/core/rebase/index.js +2 -2
  144. package/lib/core/rebase/index.js.map +1 -1
  145. package/lib/core/rebase/types.d.ts +5 -4
  146. package/lib/core/rebase/types.d.ts.map +1 -1
  147. package/lib/core/rebase/types.js +26 -1
  148. package/lib/core/rebase/types.js.map +1 -1
  149. package/lib/core/rebase/utils.d.ts +10 -0
  150. package/lib/core/rebase/utils.d.ts.map +1 -1
  151. package/lib/core/rebase/utils.js +20 -0
  152. package/lib/core/rebase/utils.js.map +1 -1
  153. package/lib/core/tree/delta.d.ts +21 -26
  154. package/lib/core/tree/delta.d.ts.map +1 -1
  155. package/lib/core/tree/delta.js.map +1 -1
  156. package/lib/core/tree/deltaUtil.d.ts +1 -3
  157. package/lib/core/tree/deltaUtil.d.ts.map +1 -1
  158. package/lib/core/tree/deltaUtil.js +1 -12
  159. package/lib/core/tree/deltaUtil.js.map +1 -1
  160. package/lib/core/tree/index.d.ts +1 -1
  161. package/lib/core/tree/index.d.ts.map +1 -1
  162. package/lib/core/tree/index.js +1 -1
  163. package/lib/core/tree/index.js.map +1 -1
  164. package/lib/core/tree/visitDelta.d.ts.map +1 -1
  165. package/lib/core/tree/visitDelta.js +82 -80
  166. package/lib/core/tree/visitDelta.js.map +1 -1
  167. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  168. package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  169. package/lib/feature-libraries/deltaUtils.d.ts.map +1 -1
  170. package/lib/feature-libraries/deltaUtils.js +13 -0
  171. package/lib/feature-libraries/deltaUtils.js.map +1 -1
  172. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  173. package/lib/feature-libraries/forest-summary/forestSummarizer.js +1 -6
  174. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  175. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +5 -5
  176. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  177. package/lib/feature-libraries/modular-schema/crossFieldQueries.js +2 -9
  178. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  179. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +19 -2
  180. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  181. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  182. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  183. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  184. package/lib/feature-libraries/modular-schema/index.d.ts +2 -2
  185. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  186. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  187. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts +1 -1
  188. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  189. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +4 -4
  190. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  191. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +4 -4
  192. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  193. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +74 -166
  194. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  195. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +11 -20
  196. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  197. package/lib/feature-libraries/modular-schema/modularChangeTypes.js +18 -1
  198. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  199. package/lib/feature-libraries/optional-field/optionalField.d.ts +3 -3
  200. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  201. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  202. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts +1 -1
  203. package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
  204. package/lib/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
  205. package/lib/feature-libraries/sequence-field/rebase.js +4 -4
  206. package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
  207. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.js +1 -1
  208. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.js.map +1 -1
  209. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js +1 -1
  210. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  211. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +2 -3
  212. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
  213. package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
  214. package/lib/feature-libraries/sequence-field/utils.js +36 -4
  215. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  216. package/lib/feature-libraries/treeCursorUtils.d.ts.map +1 -1
  217. package/lib/feature-libraries/treeCursorUtils.js +4 -1
  218. package/lib/feature-libraries/treeCursorUtils.js.map +1 -1
  219. package/lib/index.d.ts +26 -2
  220. package/lib/index.d.ts.map +1 -1
  221. package/lib/index.js +1 -1
  222. package/lib/index.js.map +1 -1
  223. package/lib/packageVersion.d.ts +1 -1
  224. package/lib/packageVersion.js +1 -1
  225. package/lib/packageVersion.js.map +1 -1
  226. package/lib/shared-tree/index.d.ts +1 -1
  227. package/lib/shared-tree/index.d.ts.map +1 -1
  228. package/lib/shared-tree/index.js +1 -1
  229. package/lib/shared-tree/index.js.map +1 -1
  230. package/lib/shared-tree/sharedTree.d.ts +38 -18
  231. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  232. package/lib/shared-tree/sharedTree.js +37 -33
  233. package/lib/shared-tree/sharedTree.js.map +1 -1
  234. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  235. package/lib/shared-tree/treeCheckout.js +13 -9
  236. package/lib/shared-tree/treeCheckout.js.map +1 -1
  237. package/lib/simple-tree/api/treeNodeApi.js +1 -1
  238. package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
  239. package/lib/simple-tree/arrayNode.js +1 -1
  240. package/lib/simple-tree/arrayNode.js.map +1 -1
  241. package/lib/simple-tree/toMapTree.js +1 -1
  242. package/lib/simple-tree/toMapTree.js.map +1 -1
  243. package/lib/util/bTreeUtils.d.ts +10 -0
  244. package/lib/util/bTreeUtils.d.ts.map +1 -0
  245. package/lib/util/bTreeUtils.js +47 -0
  246. package/lib/util/bTreeUtils.js.map +1 -0
  247. package/lib/util/idAllocator.d.ts +0 -2
  248. package/lib/util/idAllocator.d.ts.map +1 -1
  249. package/lib/util/idAllocator.js +0 -2
  250. package/lib/util/idAllocator.js.map +1 -1
  251. package/lib/util/index.d.ts +2 -1
  252. package/lib/util/index.d.ts.map +1 -1
  253. package/lib/util/index.js +2 -1
  254. package/lib/util/index.js.map +1 -1
  255. package/lib/util/rangeMap.d.ts +52 -30
  256. package/lib/util/rangeMap.d.ts.map +1 -1
  257. package/lib/util/rangeMap.js +160 -117
  258. package/lib/util/rangeMap.js.map +1 -1
  259. package/lib/util/utils.d.ts +4 -1
  260. package/lib/util/utils.d.ts.map +1 -1
  261. package/lib/util/utils.js +7 -1
  262. package/lib/util/utils.js.map +1 -1
  263. package/package.json +23 -23
  264. package/src/core/index.ts +5 -2
  265. package/src/core/rebase/index.ts +5 -0
  266. package/src/core/rebase/types.ts +33 -5
  267. package/src/core/rebase/utils.ts +27 -0
  268. package/src/core/tree/delta.ts +21 -26
  269. package/src/core/tree/deltaUtil.ts +1 -16
  270. package/src/core/tree/index.ts +0 -2
  271. package/src/core/tree/visitDelta.ts +108 -97
  272. package/src/feature-libraries/default-schema/defaultFieldKinds.ts +2 -2
  273. package/src/feature-libraries/deltaUtils.ts +13 -0
  274. package/src/feature-libraries/forest-summary/forestSummarizer.ts +1 -6
  275. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +12 -13
  276. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +21 -1
  277. package/src/feature-libraries/modular-schema/genericFieldKind.ts +2 -2
  278. package/src/feature-libraries/modular-schema/index.ts +2 -0
  279. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +12 -11
  280. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +138 -225
  281. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +40 -27
  282. package/src/feature-libraries/optional-field/optionalField.ts +3 -3
  283. package/src/feature-libraries/sequence-field/moveEffectTable.ts +1 -1
  284. package/src/feature-libraries/sequence-field/rebase.ts +9 -3
  285. package/src/feature-libraries/sequence-field/sequenceFieldCodecV1.ts +1 -1
  286. package/src/feature-libraries/sequence-field/sequenceFieldCodecV2.ts +1 -1
  287. package/src/feature-libraries/sequence-field/sequenceFieldToDelta.ts +3 -4
  288. package/src/feature-libraries/sequence-field/utils.ts +36 -4
  289. package/src/feature-libraries/treeCursorUtils.ts +6 -1
  290. package/src/index.ts +34 -6
  291. package/src/packageVersion.ts +1 -1
  292. package/src/shared-tree/index.ts +4 -1
  293. package/src/shared-tree/sharedTree.ts +60 -40
  294. package/src/shared-tree/treeCheckout.ts +19 -12
  295. package/src/simple-tree/api/treeNodeApi.ts +1 -1
  296. package/src/simple-tree/arrayNode.ts +1 -1
  297. package/src/simple-tree/toMapTree.ts +1 -1
  298. package/src/util/bTreeUtils.ts +60 -0
  299. package/src/util/idAllocator.ts +0 -2
  300. package/src/util/index.ts +3 -0
  301. package/src/util/rangeMap.ts +208 -143
  302. package/src/util/utils.ts +10 -3
  303. package/lib/package.json +0 -3
@@ -30,7 +30,6 @@ import {
30
30
  type RevisionTag,
31
31
  type TaggedChange,
32
32
  type UpPath,
33
- isEmptyFieldChanges,
34
33
  makeDetachedNodeId,
35
34
  mapCursorField,
36
35
  replaceAtomRevisions,
@@ -40,6 +39,9 @@ import {
40
39
  areEqualChangeAtomIdOpts,
41
40
  tagChange,
42
41
  makeAnonChange,
42
+ newChangeAtomIdRangeMap,
43
+ type DeltaDetachedNodeChanges,
44
+ type DeltaDetachedNodeRename,
43
45
  } from "../../core/index.js";
44
46
  import {
45
47
  type IdAllocationState,
@@ -51,6 +53,10 @@ import {
51
53
  idAllocatorFromState,
52
54
  type RangeQueryResult,
53
55
  getOrAddInMapLazy,
56
+ newTupleBTree,
57
+ mergeTupleBTrees,
58
+ type TupleBTree,
59
+ RangeMap,
54
60
  } from "../../util/index.js";
55
61
  import {
56
62
  type TreeChunk,
@@ -75,18 +81,19 @@ import {
75
81
  import { type FieldKindWithEditor, withEditor } from "./fieldKindWithEditor.js";
76
82
  import { convertGenericChange, genericFieldKind } from "./genericFieldKind.js";
77
83
  import type { GenericChangeset } from "./genericFieldKindTypes.js";
78
- import type {
79
- ChangeAtomIdBTree,
80
- CrossFieldKeyRange,
81
- CrossFieldKeyTable,
82
- FieldChange,
83
- FieldChangeMap,
84
- FieldChangeset,
85
- FieldId,
86
- ModularChangeset,
87
- NodeChangeset,
88
- NodeId,
89
- TupleBTree,
84
+ import {
85
+ type ChangeAtomIdBTree,
86
+ type CrossFieldKey,
87
+ type CrossFieldKeyRange,
88
+ type CrossFieldKeyTable,
89
+ type FieldChange,
90
+ type FieldChangeMap,
91
+ type FieldChangeset,
92
+ type FieldId,
93
+ type ModularChangeset,
94
+ newCrossFieldKeyTable,
95
+ type NodeChangeset,
96
+ type NodeId,
90
97
  } from "./modularChangeTypes.js";
91
98
  import type { IIdCompressor } from "@fluidframework/id-compressor";
92
99
 
@@ -252,7 +259,7 @@ export class ModularChangeFamily
252
259
  nodeChanges: newTupleBTree(),
253
260
  nodeToParent: newTupleBTree(),
254
261
  nodeAliases: newTupleBTree(),
255
- crossFieldKeys: newTupleBTree(),
262
+ crossFieldKeys: newCrossFieldKeyTable(),
256
263
  };
257
264
  } else if (hasConflicts(change1)) {
258
265
  return change2;
@@ -272,14 +279,14 @@ export class ModularChangeFamily
272
279
  // (since we assume that if two changesets use the same node ID they are referring to the same node),
273
280
  // therefore all collisions will be addressed when processing the intersection of the changesets.
274
281
  const composedNodeChanges: ChangeAtomIdBTree<NodeChangeset> = brand(
275
- mergeBTrees(change1.nodeChanges, change2.nodeChanges),
282
+ mergeTupleBTrees(change1.nodeChanges, change2.nodeChanges),
276
283
  );
277
284
 
278
285
  const composedNodeToParent: ChangeAtomIdBTree<FieldId> = brand(
279
- mergeBTrees(change1.nodeToParent, change2.nodeToParent),
286
+ mergeTupleBTrees(change1.nodeToParent, change2.nodeToParent),
280
287
  );
281
288
  const composedNodeAliases: ChangeAtomIdBTree<NodeId> = brand(
282
- mergeBTrees(change1.nodeAliases, change2.nodeAliases),
289
+ mergeTupleBTrees(change1.nodeAliases, change2.nodeAliases),
283
290
  );
284
291
 
285
292
  const crossFieldTable = newComposeTable(change1, change2, composedNodeToParent);
@@ -304,13 +311,16 @@ export class ModularChangeFamily
304
311
  );
305
312
 
306
313
  // Currently no field kinds require making changes to cross-field keys during composition, so we can just merge the two tables.
307
- const composedCrossFieldKeys = mergeBTrees(change1.crossFieldKeys, change2.crossFieldKeys);
314
+ const composedCrossFieldKeys = RangeMap.union(
315
+ change1.crossFieldKeys,
316
+ change2.crossFieldKeys,
317
+ );
308
318
  return {
309
319
  fieldChanges: composedFields,
310
320
  nodeChanges: composedNodeChanges,
311
321
  nodeToParent: composedNodeToParent,
312
322
  nodeAliases: composedNodeAliases,
313
- crossFieldKeys: brand(composedCrossFieldKeys),
323
+ crossFieldKeys: composedCrossFieldKeys,
314
324
  };
315
325
  }
316
326
 
@@ -902,7 +912,7 @@ export class ModularChangeFamily
902
912
  baseToRebasedNodeId: newTupleBTree(),
903
913
  rebasedFields: new Set(),
904
914
  rebasedNodeToParent: brand(change.nodeToParent.clone()),
905
- rebasedCrossFieldKeys: brand(change.crossFieldKeys.clone()),
915
+ rebasedCrossFieldKeys: change.crossFieldKeys.clone(),
906
916
  nodeIdPairs: [],
907
917
  affectedBaseFields: newTupleBTree(),
908
918
  fieldsWithUnattachedChild: new Set(),
@@ -1667,8 +1677,8 @@ export class ModularChangeFamily
1667
1677
  const keys = getChangeHandler(this.fieldKinds, fieldChange.fieldKind).getCrossFieldKeys(
1668
1678
  fieldChange.change,
1669
1679
  );
1670
- for (const key of keys) {
1671
- table.set(key, { nodeId: parent, field: fieldKey });
1680
+ for (const { key, count } of keys) {
1681
+ table.set(key, count, { nodeId: parent, field: fieldKey });
1672
1682
  }
1673
1683
  }
1674
1684
  }
@@ -1728,7 +1738,7 @@ export class ModularChangeFamily
1728
1738
  }
1729
1739
 
1730
1740
  for (const keyRange of handler.getCrossFieldKeys(fieldChange.change)) {
1731
- const fields = getFieldsForCrossFieldKey(change, keyRange);
1741
+ const fields = getFieldsForCrossFieldKey(change, keyRange.key, keyRange.count);
1732
1742
  assert(
1733
1743
  fields.length === 1 &&
1734
1744
  fields[0] !== undefined &&
@@ -1748,15 +1758,16 @@ function replaceCrossFieldKeyTableRevisions(
1748
1758
  newRevision: RevisionTag | undefined,
1749
1759
  nodeAliases: ChangeAtomIdBTree<NodeId>,
1750
1760
  ): CrossFieldKeyTable {
1751
- const updated: CrossFieldKeyTable = newTupleBTree();
1752
- table.forEachPair(([target, revision, id, count], field) => {
1753
- const updatedKey: CrossFieldKeyRange = [
1754
- target,
1755
- replaceRevision(revision, oldRevisions, newRevision),
1756
- id,
1757
- count,
1758
- ];
1761
+ const updated: CrossFieldKeyTable = newCrossFieldKeyTable();
1762
+ for (const entry of table.entries()) {
1763
+ const key = entry.start;
1764
+ const updatedKey: CrossFieldKey = {
1765
+ target: key.target,
1766
+ revision: replaceRevision(key.revision, oldRevisions, newRevision),
1767
+ localId: key.localId,
1768
+ };
1759
1769
 
1770
+ const field = entry.value;
1760
1771
  const normalizedFieldId = normalizeFieldId(field, nodeAliases);
1761
1772
  const updatedNodeId =
1762
1773
  normalizedFieldId.nodeId !== undefined
@@ -1768,8 +1779,8 @@ function replaceCrossFieldKeyTableRevisions(
1768
1779
  nodeId: updatedNodeId,
1769
1780
  };
1770
1781
 
1771
- updated.set(updatedKey, updatedValue);
1772
- });
1782
+ updated.set(updatedKey, entry.length, updatedValue);
1783
+ }
1773
1784
 
1774
1785
  return updated;
1775
1786
  }
@@ -1816,15 +1827,19 @@ function composeBuildsDestroysAndRefreshers(
1816
1827
  // composition all the changes already reflected on the tree, but that is not something we
1817
1828
  // care to support at this time.
1818
1829
  const allBuilds: ChangeAtomIdBTree<TreeChunk> = brand(
1819
- mergeBTrees(change1.builds ?? newTupleBTree(), change2.builds ?? newTupleBTree(), true),
1830
+ mergeTupleBTrees(
1831
+ change1.builds ?? newTupleBTree(),
1832
+ change2.builds ?? newTupleBTree(),
1833
+ true,
1834
+ ),
1820
1835
  );
1821
1836
 
1822
1837
  const allDestroys: ChangeAtomIdBTree<number> = brand(
1823
- mergeBTrees(change1.destroys ?? newTupleBTree(), change2.destroys ?? newTupleBTree()),
1838
+ mergeTupleBTrees(change1.destroys ?? newTupleBTree(), change2.destroys ?? newTupleBTree()),
1824
1839
  );
1825
1840
 
1826
1841
  const allRefreshers: ChangeAtomIdBTree<TreeChunk> = brand(
1827
- mergeBTrees(
1842
+ mergeTupleBTrees(
1828
1843
  change1.refreshers ?? newTupleBTree(),
1829
1844
  change2.refreshers ?? newTupleBTree(),
1830
1845
  true,
@@ -1997,6 +2012,8 @@ export function updateRefreshers(
1997
2012
  }
1998
2013
 
1999
2014
  /**
2015
+ * Converts a change into the delta format.
2016
+ *
2000
2017
  * @param change - The change to convert into a delta.
2001
2018
  * @param fieldKinds - The field kinds to delegate to.
2002
2019
  */
@@ -2006,13 +2023,27 @@ export function intoDelta(
2006
2023
  ): DeltaRoot {
2007
2024
  const change = taggedChange.change;
2008
2025
  const rootDelta: Mutable<DeltaRoot> = {};
2026
+ const global: DeltaDetachedNodeChanges[] = [];
2027
+ const rename: DeltaDetachedNodeRename[] = [];
2009
2028
 
2010
2029
  if (!hasConflicts(change)) {
2011
2030
  // If there are no constraint violations, then tree changes apply.
2012
- const fieldDeltas = intoDeltaImpl(change.fieldChanges, change.nodeChanges, fieldKinds);
2031
+ const fieldDeltas = intoDeltaImpl(
2032
+ change.fieldChanges,
2033
+ change.nodeChanges,
2034
+ fieldKinds,
2035
+ global,
2036
+ rename,
2037
+ );
2013
2038
  if (fieldDeltas.size > 0) {
2014
2039
  rootDelta.fields = fieldDeltas;
2015
2040
  }
2041
+ if (global.length > 0) {
2042
+ rootDelta.global = global;
2043
+ }
2044
+ if (rename.length > 0) {
2045
+ rootDelta.rename = rename;
2046
+ }
2016
2047
  }
2017
2048
 
2018
2049
  // Constraint violations should not prevent nodes from being built
@@ -2060,19 +2091,28 @@ function intoDeltaImpl(
2060
2091
  change: FieldChangeMap,
2061
2092
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2062
2093
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FieldKindWithEditor>,
2094
+ global: DeltaDetachedNodeChanges[],
2095
+ rename: DeltaDetachedNodeRename[],
2063
2096
  ): Map<FieldKey, DeltaFieldChanges> {
2064
2097
  const delta: Map<FieldKey, DeltaFieldChanges> = new Map();
2098
+
2065
2099
  for (const [field, fieldChange] of change) {
2066
- const deltaField = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
2100
+ const {
2101
+ local: fieldChanges,
2102
+ global: fieldGlobal,
2103
+ rename: fieldRename,
2104
+ } = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
2067
2105
  fieldChange.change,
2068
2106
  (childChange): DeltaFieldMap => {
2069
2107
  const nodeChange = nodeChangeFromId(nodeChanges, childChange);
2070
- return deltaFromNodeChange(nodeChange, nodeChanges, fieldKinds);
2108
+ return deltaFromNodeChange(nodeChange, nodeChanges, fieldKinds, global, rename);
2071
2109
  },
2072
2110
  );
2073
- if (!isEmptyFieldChanges(deltaField)) {
2074
- delta.set(field, deltaField);
2111
+ if (fieldChanges !== undefined && fieldChanges.length > 0) {
2112
+ delta.set(field, fieldChanges);
2075
2113
  }
2114
+ fieldGlobal?.forEach((c) => global.push(c));
2115
+ fieldRename?.forEach((r) => rename.push(r));
2076
2116
  }
2077
2117
  return delta;
2078
2118
  }
@@ -2081,9 +2121,11 @@ function deltaFromNodeChange(
2081
2121
  change: NodeChangeset,
2082
2122
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2083
2123
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FieldKindWithEditor>,
2124
+ global: DeltaDetachedNodeChanges[],
2125
+ rename: DeltaDetachedNodeRename[],
2084
2126
  ): DeltaFieldMap {
2085
2127
  if (change.fieldChanges !== undefined) {
2086
- return intoDeltaImpl(change.fieldChanges, nodeChanges, fieldKinds);
2128
+ return intoDeltaImpl(change.fieldChanges, nodeChanges, fieldKinds, global, rename);
2087
2129
  }
2088
2130
  // TODO: update the API to allow undefined to be returned here
2089
2131
  return new Map();
@@ -2276,10 +2318,10 @@ interface ComposeFieldContext {
2276
2318
 
2277
2319
  function newCrossFieldTable<T>(): CrossFieldTable<T> {
2278
2320
  return {
2279
- srcTable: new Map(),
2280
- dstTable: new Map(),
2281
- srcDependents: new Map(),
2282
- dstDependents: new Map(),
2321
+ srcTable: newChangeAtomIdRangeMap(),
2322
+ dstTable: newChangeAtomIdRangeMap(),
2323
+ srcDependents: newChangeAtomIdRangeMap(),
2324
+ dstDependents: newChangeAtomIdRangeMap(),
2283
2325
  invalidatedFields: new Set(),
2284
2326
  };
2285
2327
  }
@@ -2337,7 +2379,7 @@ abstract class CrossFieldManagerI<T> implements CrossFieldManager {
2337
2379
  id: ChangesetLocalId,
2338
2380
  count: number,
2339
2381
  addDependency: boolean,
2340
- ): RangeQueryResult<unknown> {
2382
+ ): RangeQueryResult<ChangeAtomId, unknown> {
2341
2383
  if (addDependency) {
2342
2384
  // We assume that if there is already an entry for this ID it is because
2343
2385
  // a field handler has called compose on the same node multiple times.
@@ -2422,24 +2464,30 @@ class RebaseManager extends CrossFieldManagerI<FieldChange> {
2422
2464
  invalidateDependents: boolean,
2423
2465
  ): void {
2424
2466
  if (invalidateDependents && this.allowInval) {
2425
- const newFieldIds = getFieldsForCrossFieldKey(this.table.newChange, [
2426
- target,
2427
- revision,
2428
- id,
2467
+ const newFieldIds = getFieldsForCrossFieldKey(
2468
+ this.table.newChange,
2469
+ {
2470
+ target,
2471
+ revision,
2472
+ localId: id,
2473
+ },
2429
2474
  count,
2430
- ]);
2475
+ );
2431
2476
 
2432
2477
  assert(
2433
2478
  newFieldIds.length === 0,
2434
2479
  0x9c6 /* TODO: Modifying a cross-field key from the new changeset is currently unsupported */,
2435
2480
  );
2436
2481
 
2437
- const baseFieldIds = getFieldsForCrossFieldKey(this.table.baseChange, [
2438
- target,
2439
- revision,
2440
- id,
2482
+ const baseFieldIds = getFieldsForCrossFieldKey(
2483
+ this.table.baseChange,
2484
+ {
2485
+ target,
2486
+ revision,
2487
+ localId: id,
2488
+ },
2441
2489
  count,
2442
- ]);
2490
+ );
2443
2491
 
2444
2492
  assert(
2445
2493
  baseFieldIds.length > 0,
@@ -2467,11 +2515,8 @@ class RebaseManager extends CrossFieldManagerI<FieldChange> {
2467
2515
  id: ChangesetLocalId,
2468
2516
  count: number,
2469
2517
  ): void {
2470
- setInCrossFieldKeyTable(
2471
- this.table.rebasedCrossFieldKeys,
2472
- target,
2473
- revision,
2474
- id,
2518
+ this.table.rebasedCrossFieldKeys.set(
2519
+ { target, revision, localId: id },
2475
2520
  count,
2476
2521
  this.fieldId,
2477
2522
  );
@@ -2502,12 +2547,15 @@ class ComposeManager extends CrossFieldManagerI<FieldChange> {
2502
2547
  invalidateDependents: boolean,
2503
2548
  ): void {
2504
2549
  if (invalidateDependents && this.allowInval) {
2505
- const newFieldIds = getFieldsForCrossFieldKey(this.table.newChange, [
2506
- target,
2507
- revision,
2508
- id,
2550
+ const newFieldIds = getFieldsForCrossFieldKey(
2551
+ this.table.newChange,
2552
+ {
2553
+ target,
2554
+ revision,
2555
+ localId: id,
2556
+ },
2509
2557
  count,
2510
- ]);
2558
+ );
2511
2559
 
2512
2560
  if (newFieldIds.length > 0) {
2513
2561
  for (const newFieldId of newFieldIds) {
@@ -2517,12 +2565,15 @@ class ComposeManager extends CrossFieldManagerI<FieldChange> {
2517
2565
  );
2518
2566
  }
2519
2567
  } else {
2520
- const baseFieldIds = getFieldsForCrossFieldKey(this.table.baseChange, [
2521
- target,
2522
- revision,
2523
- id,
2568
+ const baseFieldIds = getFieldsForCrossFieldKey(
2569
+ this.table.baseChange,
2570
+ {
2571
+ target,
2572
+ revision,
2573
+ localId: id,
2574
+ },
2524
2575
  count,
2525
- ]);
2576
+ );
2526
2577
 
2527
2578
  assert(
2528
2579
  baseFieldIds.length > 0,
@@ -2822,8 +2873,8 @@ function buildModularChangesetFromField(props: {
2822
2873
  const fieldChanges: FieldChangeMap = new Map([[path.field, fieldChange]]);
2823
2874
 
2824
2875
  if (path.parent === undefined) {
2825
- for (const key of localCrossFieldKeys) {
2826
- crossFieldKeys.set(key, { nodeId: undefined, field: path.field });
2876
+ for (const { key, count } of localCrossFieldKeys) {
2877
+ crossFieldKeys.set(key, count, { nodeId: undefined, field: path.field });
2827
2878
  }
2828
2879
 
2829
2880
  if (childId !== undefined) {
@@ -2849,8 +2900,8 @@ function buildModularChangesetFromField(props: {
2849
2900
 
2850
2901
  const parentId: NodeId = { localId: brand(idAllocator.allocate()), revision };
2851
2902
 
2852
- for (const key of localCrossFieldKeys) {
2853
- crossFieldKeys.set(key, { nodeId: parentId, field: path.field });
2903
+ for (const { key, count } of localCrossFieldKeys) {
2904
+ crossFieldKeys.set(key, count, { nodeId: parentId, field: path.field });
2854
2905
  }
2855
2906
 
2856
2907
  if (childId !== undefined) {
@@ -2975,27 +3026,6 @@ function revisionInfoFromTaggedChange(
2975
3026
  return revInfos;
2976
3027
  }
2977
3028
 
2978
- function mergeBTrees<K extends readonly unknown[], V>(
2979
- tree1: TupleBTree<K, V> | undefined,
2980
- tree2: TupleBTree<K, V> | undefined,
2981
- preferLeft = true,
2982
- ): TupleBTree<K, V> {
2983
- if (tree1 === undefined) {
2984
- return tree2 !== undefined ? brand(tree2.clone()) : newTupleBTree<K, V>();
2985
- }
2986
-
2987
- const result: TupleBTree<K, V> = brand(tree1.clone());
2988
- if (tree2 === undefined) {
2989
- return result;
2990
- }
2991
-
2992
- for (const [key, value] of tree2.entries()) {
2993
- result.set(key, value, !preferLeft);
2994
- }
2995
-
2996
- return result;
2997
- }
2998
-
2999
3029
  function fieldChangeFromId(
3000
3030
  fields: FieldChangeMap,
3001
3031
  nodes: ChangeAtomIdBTree<NodeChangeset>,
@@ -3071,104 +3101,21 @@ export function getParentFieldId(changeset: ModularChangeset, nodeId: NodeId): F
3071
3101
  return normalizeFieldId(parentId, changeset.nodeAliases);
3072
3102
  }
3073
3103
 
3074
- export function getFieldsForCrossFieldKey(
3104
+ function getFieldsForCrossFieldKey(
3075
3105
  changeset: ModularChangeset,
3076
- [target, revision, id, count]: CrossFieldKeyRange,
3077
- ): FieldId[] {
3078
- let firstLocalId: number = id;
3079
- const lastLocalId = id + count - 1;
3080
-
3081
- const fields: FieldId[] = [];
3082
-
3083
- // eslint-disable-next-line no-constant-condition
3084
- while (true) {
3085
- const entry = getFirstIntersectingCrossFieldEntry(changeset.crossFieldKeys, [
3086
- target,
3087
- revision,
3088
- brand(firstLocalId),
3089
- count,
3090
- ]);
3091
-
3092
- if (entry === undefined) {
3093
- return fields;
3094
- }
3095
-
3096
- const [[_target, _revision, entryId, entryCount], fieldId] = entry;
3097
- fields.push(normalizeFieldId(fieldId, changeset.nodeAliases));
3098
-
3099
- const entryLastId = entryId + entryCount - 1;
3100
- if (entryLastId >= lastLocalId) {
3101
- return fields;
3102
- }
3103
-
3104
- firstLocalId = entryLastId + 1;
3105
- }
3106
- }
3107
-
3108
- function getFirstIntersectingCrossFieldEntry(
3109
- table: CrossFieldKeyTable,
3110
- [target, revision, id, count]: CrossFieldKeyRange,
3111
- ): [CrossFieldKeyRange, FieldId] | undefined {
3112
- const entry = table.nextLowerPair([target, revision, id, Number.POSITIVE_INFINITY]);
3113
- if (entry === undefined) {
3114
- return undefined;
3115
- }
3116
-
3117
- const [entryTarget, entryRevision, entryId, entryCount] = entry[0];
3118
- if (entryTarget !== target || entryRevision !== revision) {
3119
- return undefined;
3120
- }
3121
-
3122
- const lastQueryId = id + count - 1;
3123
- const entryLastId = entryId + entryCount - 1;
3124
- if (entryId > lastQueryId || entryLastId < id) {
3125
- return undefined;
3126
- }
3127
-
3128
- return entry;
3129
- }
3130
-
3131
- function setInCrossFieldKeyTable(
3132
- table: CrossFieldKeyTable,
3133
- target: CrossFieldTarget,
3134
- revision: RevisionTag | undefined,
3135
- id: ChangesetLocalId,
3106
+ key: CrossFieldKey,
3136
3107
  count: number,
3137
- value: FieldId,
3138
- ): void {
3139
- let entry = getFirstIntersectingCrossFieldEntry(table, [target, revision, id, count]);
3140
- const lastQueryId = id + count - 1;
3141
- while (entry !== undefined) {
3142
- const [entryKey, entryValue] = entry;
3143
- table.delete(entryKey);
3144
-
3145
- const [_target, _revision, entryId, entryCount] = entryKey;
3146
- if (entryId < id) {
3147
- table.set([target, revision, entryId, id - entryId], entryValue);
3148
- }
3149
-
3150
- const lastEntryId = entryId + entryCount - 1;
3151
- if (lastEntryId > lastQueryId) {
3152
- table.set(
3153
- [target, revision, brand(lastQueryId + 1), lastEntryId - lastQueryId],
3154
- entryValue,
3155
- );
3156
- break;
3157
- }
3158
-
3159
- const nextId: ChangesetLocalId = brand(lastEntryId + 1);
3160
- entry = getFirstIntersectingCrossFieldEntry(table, [
3161
- target,
3162
- revision,
3163
- nextId,
3164
- lastQueryId - nextId + 1,
3165
- ]);
3166
- }
3167
-
3168
- table.set([target, revision, id, count], value);
3108
+ ): FieldId[] {
3109
+ return changeset.crossFieldKeys
3110
+ .getAll(key, count)
3111
+ .map(({ value: fieldId }) => normalizeFieldId(fieldId, changeset.nodeAliases));
3169
3112
  }
3170
3113
 
3171
- function normalizeFieldId(fieldId: FieldId, nodeAliases: ChangeAtomIdBTree<NodeId>): FieldId {
3114
+ // This is only exported for use in test utilities.
3115
+ export function normalizeFieldId(
3116
+ fieldId: FieldId,
3117
+ nodeAliases: ChangeAtomIdBTree<NodeId>,
3118
+ ): FieldId {
3172
3119
  return fieldId.nodeId !== undefined
3173
3120
  ? { ...fieldId, nodeId: normalizeNodeId(fieldId.nodeId, nodeAliases) }
3174
3121
  : fieldId;
@@ -3195,40 +3142,6 @@ function hasConflicts(change: ModularChangeset): boolean {
3195
3142
  return (change.constraintViolationCount ?? 0) > 0;
3196
3143
  }
3197
3144
 
3198
- export function newCrossFieldKeyTable(): CrossFieldKeyTable {
3199
- return newTupleBTree();
3200
- }
3201
-
3202
- export function newTupleBTree<K extends readonly unknown[], V>(
3203
- entries?: [K, V][],
3204
- ): TupleBTree<K, V> {
3205
- return brand(new BTree<K, V>(entries, compareTuples));
3206
- }
3207
-
3208
- // This assumes that the arrays are the same length.
3209
- function compareTuples(arrayA: readonly unknown[], arrayB: readonly unknown[]): number {
3210
- for (let i = 0; i < arrayA.length; i++) {
3211
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3212
- const a = arrayA[i] as any;
3213
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3214
- const b = arrayB[i] as any;
3215
-
3216
- // Less-than and greater-than always return false if either value is undefined,
3217
- // so we handle undefined separately, treating it as less than all other values.
3218
- if (a === undefined && b !== undefined) {
3219
- return -1;
3220
- } else if (b === undefined && a !== undefined) {
3221
- return 1;
3222
- } else if (a < b) {
3223
- return -1;
3224
- } else if (a > b) {
3225
- return 1;
3226
- }
3227
- }
3228
-
3229
- return 0;
3230
- }
3231
-
3232
3145
  interface ModularChangesetContent {
3233
3146
  fieldChanges: FieldChangeMap;
3234
3147
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
@@ -3,16 +3,16 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import type { BTree } from "@tylerbu/sorted-btree-es6";
7
- import type {
8
- ChangeAtomId,
9
- ChangesetLocalId,
10
- FieldKey,
11
- FieldKindIdentifier,
12
- RevisionInfo,
13
- RevisionTag,
6
+ import {
7
+ subtractChangeAtomIds,
8
+ type ChangeAtomId,
9
+ type ChangesetLocalId,
10
+ type FieldKey,
11
+ type FieldKindIdentifier,
12
+ type RevisionInfo,
13
+ type RevisionTag,
14
14
  } from "../../core/index.js";
15
- import type { Brand } from "../../util/index.js";
15
+ import { brand, RangeMap, type Brand, type TupleBTree } from "../../util/index.js";
16
16
  import type { TreeChunk } from "../chunked-forest/index.js";
17
17
  import type { CrossFieldTarget } from "./crossFieldQueries.js";
18
18
 
@@ -71,25 +71,38 @@ export interface ModularChangeset extends HasFieldChanges {
71
71
  readonly refreshers?: ChangeAtomIdBTree<TreeChunk>;
72
72
  }
73
73
 
74
- export type TupleBTree<K, V> = Brand<BTree<K, V>, "TupleBTree">;
75
74
  export type ChangeAtomIdBTree<V> = TupleBTree<[RevisionTag | undefined, ChangesetLocalId], V>;
76
- export type CrossFieldKeyTable = TupleBTree<CrossFieldKeyRange, FieldId>;
77
- export type CrossFieldKeyRange = readonly [
78
- CrossFieldTarget,
79
- RevisionTag | undefined,
80
- ChangesetLocalId,
81
- /**
82
- * The length of this range.
83
- * TODO: This does not need to be part of the key and could be part of the value instead.
84
- */
85
- number,
86
- ];
87
-
88
- export type CrossFieldKey = readonly [
89
- CrossFieldTarget,
90
- RevisionTag | undefined,
91
- ChangesetLocalId,
92
- ];
75
+
76
+ export type CrossFieldKeyTable = RangeMap<CrossFieldKey, FieldId>;
77
+
78
+ export function newCrossFieldKeyTable(): CrossFieldKeyTable {
79
+ return new RangeMap(offsetCrossFieldKey, subtractCrossFieldKeys);
80
+ }
81
+
82
+ function offsetCrossFieldKey(key: CrossFieldKey, offset: number): CrossFieldKey {
83
+ return {
84
+ ...key,
85
+ localId: brand(key.localId + offset),
86
+ };
87
+ }
88
+
89
+ function subtractCrossFieldKeys(a: CrossFieldKey, b: CrossFieldKey): number {
90
+ const cmpTarget = a.target - b.target;
91
+ if (cmpTarget !== 0) {
92
+ return cmpTarget * Number.POSITIVE_INFINITY;
93
+ }
94
+
95
+ return subtractChangeAtomIds(a, b);
96
+ }
97
+
98
+ export interface CrossFieldKey extends ChangeAtomId {
99
+ readonly target: CrossFieldTarget;
100
+ }
101
+
102
+ export interface CrossFieldKeyRange {
103
+ key: CrossFieldKey;
104
+ count: number;
105
+ }
93
106
 
94
107
  export interface FieldId {
95
108
  readonly nodeId: NodeId | undefined;