@fluidframework/tree 2.12.0 → 2.13.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 (329) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/api-report/tree.alpha.api.md +86 -10
  3. package/api-report/tree.beta.api.md +22 -10
  4. package/api-report/tree.legacy.alpha.api.md +22 -10
  5. package/api-report/tree.legacy.public.api.md +22 -10
  6. package/api-report/tree.public.api.md +22 -10
  7. package/dist/alpha.d.ts +11 -0
  8. package/dist/beta.d.ts +2 -0
  9. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts +10 -0
  10. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  11. package/dist/feature-libraries/default-schema/defaultEditBuilder.js +3 -0
  12. package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  13. package/dist/feature-libraries/index.d.ts +0 -1
  14. package/dist/feature-libraries/index.d.ts.map +1 -1
  15. package/dist/feature-libraries/index.js +2 -4
  16. package/dist/feature-libraries/index.js.map +1 -1
  17. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +1 -1
  18. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  19. package/dist/feature-libraries/modular-schema/crossFieldQueries.js +8 -2
  20. package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  21. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +12 -5
  22. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  23. package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  24. package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  25. package/dist/feature-libraries/modular-schema/genericFieldKind.js +2 -1
  26. package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  27. package/dist/feature-libraries/modular-schema/index.d.ts +1 -1
  28. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  29. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  30. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +1 -0
  31. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  32. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +89 -25
  33. package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  34. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +12 -0
  35. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  36. package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  37. package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  38. package/dist/feature-libraries/optional-field/optionalField.js +24 -4
  39. package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
  40. package/dist/feature-libraries/sequence-field/utils.d.ts +2 -2
  41. package/dist/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  42. package/dist/feature-libraries/sequence-field/utils.js +14 -5
  43. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  44. package/dist/index.d.ts +2 -2
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +2 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/legacy.d.ts +2 -0
  49. package/dist/packageVersion.d.ts +1 -1
  50. package/dist/packageVersion.js +1 -1
  51. package/dist/packageVersion.js.map +1 -1
  52. package/dist/public.d.ts +2 -0
  53. package/dist/shared-tree/index.d.ts +2 -1
  54. package/dist/shared-tree/index.d.ts.map +1 -1
  55. package/dist/shared-tree/index.js +2 -1
  56. package/dist/shared-tree/index.js.map +1 -1
  57. package/dist/shared-tree/schematizingTreeView.d.ts +10 -1
  58. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  59. package/dist/shared-tree/schematizingTreeView.js +43 -0
  60. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  61. package/dist/shared-tree/sharedTree.d.ts +6 -3
  62. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  63. package/dist/shared-tree/sharedTree.js +3 -1
  64. package/dist/shared-tree/sharedTree.js.map +1 -1
  65. package/dist/shared-tree/transactionTypes.d.ts +105 -0
  66. package/dist/shared-tree/transactionTypes.d.ts.map +1 -0
  67. package/dist/shared-tree/transactionTypes.js +13 -0
  68. package/dist/shared-tree/transactionTypes.js.map +1 -0
  69. package/dist/shared-tree/treeApi.d.ts +1 -25
  70. package/dist/shared-tree/treeApi.d.ts.map +1 -1
  71. package/dist/shared-tree/treeApi.js +4 -8
  72. package/dist/shared-tree/treeApi.js.map +1 -1
  73. package/dist/shared-tree/treeCheckout.d.ts +4 -1
  74. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  75. package/dist/shared-tree/treeCheckout.js +130 -15
  76. package/dist/shared-tree/treeCheckout.js.map +1 -1
  77. package/dist/shared-tree-core/sharedTreeCore.js +1 -1
  78. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  79. package/dist/simple-tree/api/index.d.ts +1 -0
  80. package/dist/simple-tree/api/index.d.ts.map +1 -1
  81. package/dist/simple-tree/api/index.js +3 -1
  82. package/dist/simple-tree/api/index.js.map +1 -1
  83. package/dist/simple-tree/api/jsonSchema.d.ts +6 -0
  84. package/dist/simple-tree/api/jsonSchema.d.ts.map +1 -1
  85. package/dist/simple-tree/api/jsonSchema.js.map +1 -1
  86. package/dist/simple-tree/api/schemaFactory.d.ts +21 -12
  87. package/dist/simple-tree/api/schemaFactory.d.ts.map +1 -1
  88. package/dist/simple-tree/api/schemaFactory.js +5 -2
  89. package/dist/simple-tree/api/schemaFactory.js.map +1 -1
  90. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts +83 -0
  91. package/dist/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -0
  92. package/dist/simple-tree/api/schemaFactoryAlpha.js +90 -0
  93. package/dist/simple-tree/api/schemaFactoryAlpha.js.map +1 -0
  94. package/dist/simple-tree/api/simpleSchema.d.ts +5 -1
  95. package/dist/simple-tree/api/simpleSchema.d.ts.map +1 -1
  96. package/dist/simple-tree/api/simpleSchema.js.map +1 -1
  97. package/dist/simple-tree/api/simpleSchemaToJsonSchema.js +13 -10
  98. package/dist/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
  99. package/dist/simple-tree/api/testRecursiveDomain.d.ts +5 -5
  100. package/dist/simple-tree/api/tree.d.ts +60 -0
  101. package/dist/simple-tree/api/tree.d.ts.map +1 -1
  102. package/dist/simple-tree/api/tree.js.map +1 -1
  103. package/dist/simple-tree/api/viewSchemaToSimpleSchema.d.ts.map +1 -1
  104. package/dist/simple-tree/api/viewSchemaToSimpleSchema.js +11 -11
  105. package/dist/simple-tree/api/viewSchemaToSimpleSchema.js.map +1 -1
  106. package/dist/simple-tree/arrayNode.d.ts +2 -2
  107. package/dist/simple-tree/arrayNode.d.ts.map +1 -1
  108. package/dist/simple-tree/arrayNode.js +2 -1
  109. package/dist/simple-tree/arrayNode.js.map +1 -1
  110. package/dist/simple-tree/core/treeNodeSchema.d.ts +10 -6
  111. package/dist/simple-tree/core/treeNodeSchema.d.ts.map +1 -1
  112. package/dist/simple-tree/core/treeNodeSchema.js.map +1 -1
  113. package/dist/simple-tree/index.d.ts +2 -2
  114. package/dist/simple-tree/index.d.ts.map +1 -1
  115. package/dist/simple-tree/index.js +3 -2
  116. package/dist/simple-tree/index.js.map +1 -1
  117. package/dist/simple-tree/leafNodeSchema.d.ts +5 -5
  118. package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
  119. package/dist/simple-tree/mapNode.d.ts +2 -2
  120. package/dist/simple-tree/mapNode.d.ts.map +1 -1
  121. package/dist/simple-tree/mapNode.js +2 -1
  122. package/dist/simple-tree/mapNode.js.map +1 -1
  123. package/dist/simple-tree/objectNode.d.ts +2 -2
  124. package/dist/simple-tree/objectNode.d.ts.map +1 -1
  125. package/dist/simple-tree/objectNode.js +2 -1
  126. package/dist/simple-tree/objectNode.js.map +1 -1
  127. package/dist/simple-tree/objectNodeTypes.d.ts +2 -2
  128. package/dist/simple-tree/objectNodeTypes.d.ts.map +1 -1
  129. package/dist/simple-tree/objectNodeTypes.js.map +1 -1
  130. package/dist/simple-tree/schemaTypes.d.ts +47 -1
  131. package/dist/simple-tree/schemaTypes.d.ts.map +1 -1
  132. package/dist/simple-tree/schemaTypes.js.map +1 -1
  133. package/dist/util/index.d.ts +2 -2
  134. package/dist/util/index.d.ts.map +1 -1
  135. package/dist/util/index.js +3 -5
  136. package/dist/util/index.js.map +1 -1
  137. package/dist/util/rangeMap.d.ts +72 -42
  138. package/dist/util/rangeMap.d.ts.map +1 -1
  139. package/dist/util/rangeMap.js +161 -151
  140. package/dist/util/rangeMap.js.map +1 -1
  141. package/dist/util/utils.d.ts +22 -1
  142. package/dist/util/utils.d.ts.map +1 -1
  143. package/dist/util/utils.js +10 -1
  144. package/dist/util/utils.js.map +1 -1
  145. package/lib/alpha.d.ts +11 -0
  146. package/lib/beta.d.ts +2 -0
  147. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts +10 -0
  148. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  149. package/lib/feature-libraries/default-schema/defaultEditBuilder.js +3 -0
  150. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  151. package/lib/feature-libraries/index.d.ts +0 -1
  152. package/lib/feature-libraries/index.d.ts.map +1 -1
  153. package/lib/feature-libraries/index.js +0 -1
  154. package/lib/feature-libraries/index.js.map +1 -1
  155. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +1 -1
  156. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  157. package/lib/feature-libraries/modular-schema/crossFieldQueries.js +9 -3
  158. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  159. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +12 -5
  160. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  161. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  162. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  163. package/lib/feature-libraries/modular-schema/genericFieldKind.js +2 -1
  164. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  165. package/lib/feature-libraries/modular-schema/index.d.ts +1 -1
  166. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  167. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  168. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +1 -0
  169. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  170. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +89 -25
  171. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  172. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +12 -0
  173. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  174. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  175. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  176. package/lib/feature-libraries/optional-field/optionalField.js +24 -4
  177. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  178. package/lib/feature-libraries/sequence-field/utils.d.ts +2 -2
  179. package/lib/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  180. package/lib/feature-libraries/sequence-field/utils.js +14 -5
  181. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  182. package/lib/index.d.ts +2 -2
  183. package/lib/index.d.ts.map +1 -1
  184. package/lib/index.js +1 -1
  185. package/lib/index.js.map +1 -1
  186. package/lib/legacy.d.ts +2 -0
  187. package/lib/packageVersion.d.ts +1 -1
  188. package/lib/packageVersion.js +1 -1
  189. package/lib/packageVersion.js.map +1 -1
  190. package/lib/public.d.ts +2 -0
  191. package/lib/shared-tree/index.d.ts +2 -1
  192. package/lib/shared-tree/index.d.ts.map +1 -1
  193. package/lib/shared-tree/index.js +2 -1
  194. package/lib/shared-tree/index.js.map +1 -1
  195. package/lib/shared-tree/schematizingTreeView.d.ts +10 -1
  196. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  197. package/lib/shared-tree/schematizingTreeView.js +46 -3
  198. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  199. package/lib/shared-tree/sharedTree.d.ts +6 -3
  200. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  201. package/lib/shared-tree/sharedTree.js +3 -1
  202. package/lib/shared-tree/sharedTree.js.map +1 -1
  203. package/lib/shared-tree/transactionTypes.d.ts +105 -0
  204. package/lib/shared-tree/transactionTypes.d.ts.map +1 -0
  205. package/lib/shared-tree/transactionTypes.js +10 -0
  206. package/lib/shared-tree/transactionTypes.js.map +1 -0
  207. package/lib/shared-tree/treeApi.d.ts +1 -25
  208. package/lib/shared-tree/treeApi.d.ts.map +1 -1
  209. package/lib/shared-tree/treeApi.js +1 -5
  210. package/lib/shared-tree/treeApi.js.map +1 -1
  211. package/lib/shared-tree/treeCheckout.d.ts +4 -1
  212. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  213. package/lib/shared-tree/treeCheckout.js +130 -15
  214. package/lib/shared-tree/treeCheckout.js.map +1 -1
  215. package/lib/shared-tree-core/sharedTreeCore.js +1 -1
  216. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  217. package/lib/simple-tree/api/index.d.ts +1 -0
  218. package/lib/simple-tree/api/index.d.ts.map +1 -1
  219. package/lib/simple-tree/api/index.js +1 -0
  220. package/lib/simple-tree/api/index.js.map +1 -1
  221. package/lib/simple-tree/api/jsonSchema.d.ts +6 -0
  222. package/lib/simple-tree/api/jsonSchema.d.ts.map +1 -1
  223. package/lib/simple-tree/api/jsonSchema.js.map +1 -1
  224. package/lib/simple-tree/api/schemaFactory.d.ts +21 -12
  225. package/lib/simple-tree/api/schemaFactory.d.ts.map +1 -1
  226. package/lib/simple-tree/api/schemaFactory.js +5 -2
  227. package/lib/simple-tree/api/schemaFactory.js.map +1 -1
  228. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts +83 -0
  229. package/lib/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -0
  230. package/lib/simple-tree/api/schemaFactoryAlpha.js +86 -0
  231. package/lib/simple-tree/api/schemaFactoryAlpha.js.map +1 -0
  232. package/lib/simple-tree/api/simpleSchema.d.ts +5 -1
  233. package/lib/simple-tree/api/simpleSchema.d.ts.map +1 -1
  234. package/lib/simple-tree/api/simpleSchema.js.map +1 -1
  235. package/lib/simple-tree/api/simpleSchemaToJsonSchema.js +14 -11
  236. package/lib/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
  237. package/lib/simple-tree/api/testRecursiveDomain.d.ts +5 -5
  238. package/lib/simple-tree/api/tree.d.ts +60 -0
  239. package/lib/simple-tree/api/tree.d.ts.map +1 -1
  240. package/lib/simple-tree/api/tree.js.map +1 -1
  241. package/lib/simple-tree/api/viewSchemaToSimpleSchema.d.ts.map +1 -1
  242. package/lib/simple-tree/api/viewSchemaToSimpleSchema.js +12 -12
  243. package/lib/simple-tree/api/viewSchemaToSimpleSchema.js.map +1 -1
  244. package/lib/simple-tree/arrayNode.d.ts +2 -2
  245. package/lib/simple-tree/arrayNode.d.ts.map +1 -1
  246. package/lib/simple-tree/arrayNode.js +2 -1
  247. package/lib/simple-tree/arrayNode.js.map +1 -1
  248. package/lib/simple-tree/core/treeNodeSchema.d.ts +10 -6
  249. package/lib/simple-tree/core/treeNodeSchema.d.ts.map +1 -1
  250. package/lib/simple-tree/core/treeNodeSchema.js.map +1 -1
  251. package/lib/simple-tree/index.d.ts +2 -2
  252. package/lib/simple-tree/index.d.ts.map +1 -1
  253. package/lib/simple-tree/index.js +1 -1
  254. package/lib/simple-tree/index.js.map +1 -1
  255. package/lib/simple-tree/leafNodeSchema.d.ts +5 -5
  256. package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
  257. package/lib/simple-tree/mapNode.d.ts +2 -2
  258. package/lib/simple-tree/mapNode.d.ts.map +1 -1
  259. package/lib/simple-tree/mapNode.js +2 -1
  260. package/lib/simple-tree/mapNode.js.map +1 -1
  261. package/lib/simple-tree/objectNode.d.ts +2 -2
  262. package/lib/simple-tree/objectNode.d.ts.map +1 -1
  263. package/lib/simple-tree/objectNode.js +2 -1
  264. package/lib/simple-tree/objectNode.js.map +1 -1
  265. package/lib/simple-tree/objectNodeTypes.d.ts +2 -2
  266. package/lib/simple-tree/objectNodeTypes.d.ts.map +1 -1
  267. package/lib/simple-tree/objectNodeTypes.js.map +1 -1
  268. package/lib/simple-tree/schemaTypes.d.ts +47 -1
  269. package/lib/simple-tree/schemaTypes.d.ts.map +1 -1
  270. package/lib/simple-tree/schemaTypes.js.map +1 -1
  271. package/lib/util/index.d.ts +2 -2
  272. package/lib/util/index.d.ts.map +1 -1
  273. package/lib/util/index.js +2 -2
  274. package/lib/util/index.js.map +1 -1
  275. package/lib/util/rangeMap.d.ts +72 -42
  276. package/lib/util/rangeMap.d.ts.map +1 -1
  277. package/lib/util/rangeMap.js +159 -146
  278. package/lib/util/rangeMap.js.map +1 -1
  279. package/lib/util/utils.d.ts +22 -1
  280. package/lib/util/utils.d.ts.map +1 -1
  281. package/lib/util/utils.js +8 -0
  282. package/lib/util/utils.js.map +1 -1
  283. package/package.json +22 -22
  284. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +14 -1
  285. package/src/feature-libraries/index.ts +0 -1
  286. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +9 -9
  287. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +13 -9
  288. package/src/feature-libraries/modular-schema/genericFieldKind.ts +4 -2
  289. package/src/feature-libraries/modular-schema/index.ts +1 -0
  290. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +124 -31
  291. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +12 -0
  292. package/src/feature-libraries/optional-field/optionalField.ts +34 -5
  293. package/src/feature-libraries/sequence-field/utils.ts +18 -7
  294. package/src/index.ts +11 -0
  295. package/src/packageVersion.ts +1 -1
  296. package/src/shared-tree/index.ts +12 -2
  297. package/src/shared-tree/schematizingTreeView.ts +91 -2
  298. package/src/shared-tree/sharedTree.ts +9 -4
  299. package/src/shared-tree/transactionTypes.ts +125 -0
  300. package/src/shared-tree/treeApi.ts +1 -28
  301. package/src/shared-tree/treeCheckout.ts +147 -13
  302. package/src/shared-tree-core/sharedTreeCore.ts +1 -1
  303. package/src/simple-tree/api/index.ts +1 -0
  304. package/src/simple-tree/api/jsonSchema.ts +7 -0
  305. package/src/simple-tree/api/schemaFactory.ts +33 -6
  306. package/src/simple-tree/api/schemaFactoryAlpha.ts +253 -0
  307. package/src/simple-tree/api/simpleSchema.ts +6 -1
  308. package/src/simple-tree/api/simpleSchemaToJsonSchema.ts +22 -12
  309. package/src/simple-tree/api/tree.ts +76 -4
  310. package/src/simple-tree/api/viewSchemaToSimpleSchema.ts +19 -13
  311. package/src/simple-tree/arrayNode.ts +7 -1
  312. package/src/simple-tree/core/treeNodeSchema.ts +51 -7
  313. package/src/simple-tree/index.ts +3 -0
  314. package/src/simple-tree/mapNode.ts +7 -1
  315. package/src/simple-tree/objectNode.ts +7 -1
  316. package/src/simple-tree/objectNodeTypes.ts +4 -1
  317. package/src/simple-tree/schemaTypes.ts +50 -1
  318. package/src/util/index.ts +2 -6
  319. package/src/util/rangeMap.ts +199 -189
  320. package/src/util/utils.ts +47 -1
  321. package/dist/feature-libraries/memoizedIdRangeAllocator.d.ts +0 -38
  322. package/dist/feature-libraries/memoizedIdRangeAllocator.d.ts.map +0 -1
  323. package/dist/feature-libraries/memoizedIdRangeAllocator.js +0 -74
  324. package/dist/feature-libraries/memoizedIdRangeAllocator.js.map +0 -1
  325. package/lib/feature-libraries/memoizedIdRangeAllocator.d.ts +0 -38
  326. package/lib/feature-libraries/memoizedIdRangeAllocator.d.ts.map +0 -1
  327. package/lib/feature-libraries/memoizedIdRangeAllocator.js +0 -71
  328. package/lib/feature-libraries/memoizedIdRangeAllocator.js.map +0 -1
  329. package/src/feature-libraries/memoizedIdRangeAllocator.ts +0 -112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/tree",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "Distributed tree",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -89,17 +89,17 @@
89
89
  "temp-directory": "nyc/.nyc_output"
90
90
  },
91
91
  "dependencies": {
92
- "@fluid-internal/client-utils": "~2.12.0",
93
- "@fluidframework/container-runtime": "~2.12.0",
94
- "@fluidframework/core-interfaces": "~2.12.0",
95
- "@fluidframework/core-utils": "~2.12.0",
96
- "@fluidframework/datastore-definitions": "~2.12.0",
97
- "@fluidframework/driver-definitions": "~2.12.0",
98
- "@fluidframework/id-compressor": "~2.12.0",
99
- "@fluidframework/runtime-definitions": "~2.12.0",
100
- "@fluidframework/runtime-utils": "~2.12.0",
101
- "@fluidframework/shared-object-base": "~2.12.0",
102
- "@fluidframework/telemetry-utils": "~2.12.0",
92
+ "@fluid-internal/client-utils": "~2.13.0",
93
+ "@fluidframework/container-runtime": "~2.13.0",
94
+ "@fluidframework/core-interfaces": "~2.13.0",
95
+ "@fluidframework/core-utils": "~2.13.0",
96
+ "@fluidframework/datastore-definitions": "~2.13.0",
97
+ "@fluidframework/driver-definitions": "~2.13.0",
98
+ "@fluidframework/id-compressor": "~2.13.0",
99
+ "@fluidframework/runtime-definitions": "~2.13.0",
100
+ "@fluidframework/runtime-utils": "~2.13.0",
101
+ "@fluidframework/shared-object-base": "~2.13.0",
102
+ "@fluidframework/telemetry-utils": "~2.13.0",
103
103
  "@sinclair/typebox": "^0.32.29",
104
104
  "@tylerbu/sorted-btree-es6": "^1.8.0",
105
105
  "@types/ungap__structured-clone": "^1.2.0",
@@ -109,24 +109,24 @@
109
109
  "devDependencies": {
110
110
  "@arethetypeswrong/cli": "^0.17.1",
111
111
  "@biomejs/biome": "~1.9.3",
112
- "@fluid-internal/mocha-test-setup": "~2.12.0",
113
- "@fluid-private/stochastic-test-utils": "~2.12.0",
114
- "@fluid-private/test-dds-utils": "~2.12.0",
115
- "@fluid-private/test-drivers": "~2.12.0",
112
+ "@fluid-internal/mocha-test-setup": "~2.13.0",
113
+ "@fluid-private/stochastic-test-utils": "~2.13.0",
114
+ "@fluid-private/test-dds-utils": "~2.13.0",
115
+ "@fluid-private/test-drivers": "~2.13.0",
116
116
  "@fluid-tools/benchmark": "^0.50.0",
117
117
  "@fluid-tools/build-cli": "^0.51.0",
118
118
  "@fluidframework/build-common": "^2.0.3",
119
119
  "@fluidframework/build-tools": "^0.51.0",
120
- "@fluidframework/container-definitions": "~2.12.0",
121
- "@fluidframework/container-loader": "~2.12.0",
120
+ "@fluidframework/container-definitions": "~2.13.0",
121
+ "@fluidframework/container-loader": "~2.13.0",
122
122
  "@fluidframework/eslint-config-fluid": "^5.6.0",
123
- "@fluidframework/test-runtime-utils": "~2.12.0",
124
- "@fluidframework/test-utils": "~2.12.0",
125
- "@fluidframework/tree-previous": "npm:@fluidframework/tree@2.11.0",
123
+ "@fluidframework/test-runtime-utils": "~2.13.0",
124
+ "@fluidframework/test-utils": "~2.13.0",
125
+ "@fluidframework/tree-previous": "npm:@fluidframework/tree@2.12.0",
126
126
  "@microsoft/api-extractor": "7.47.8",
127
127
  "@types/diff": "^3.5.1",
128
128
  "@types/easy-table": "^0.0.32",
129
- "@types/mocha": "^9.1.1",
129
+ "@types/mocha": "^10.0.10",
130
130
  "@types/node": "^18.19.0",
131
131
  "@types/uuid": "^9.0.2",
132
132
  "ajv": "^8.12.0",
@@ -160,8 +160,17 @@ export interface IDefaultEditBuilder {
160
160
  destinationIndex: number,
161
161
  ): void;
162
162
 
163
- // TODO: document
163
+ /**
164
+ * Add a constraint that the node at the given path must exist.
165
+ * @param path - The path to the node that must exist.
166
+ */
164
167
  addNodeExistsConstraint(path: UpPath): void;
168
+
169
+ /**
170
+ * Add a constraint that the node at the given path must exist when reverting a change.
171
+ * @param path - The path to the node that must exist when reverting a change.
172
+ */
173
+ addNodeExistsConstraintOnRevert(path: UpPath): void;
165
174
  }
166
175
 
167
176
  /**
@@ -191,6 +200,10 @@ export class DefaultEditBuilder implements ChangeFamilyEditor, IDefaultEditBuild
191
200
  this.modularBuilder.addNodeExistsConstraint(path, this.mintRevisionTag());
192
201
  }
193
202
 
203
+ public addNodeExistsConstraintOnRevert(path: UpPath): void {
204
+ this.modularBuilder.addNodeExistsConstraintOnRevert(path, this.mintRevisionTag());
205
+ }
206
+
194
207
  public valueField(field: FieldUpPath): ValueFieldEditBuilder<ITreeCursorSynchronous> {
195
208
  return {
196
209
  set: (newContent: ITreeCursorSynchronous): void => {
@@ -16,7 +16,6 @@ export {
16
16
  mapTreeFromCursor,
17
17
  mapTreeFieldFromCursor,
18
18
  } from "./mapTreeCursor.js";
19
- export { MemoizedIdRangeAllocator, type IdRange } from "./memoizedIdRangeAllocator.js";
20
19
  export { buildForest } from "./object-forest/index.js";
21
20
  export { SchemaSummarizer, encodeTreeSchema, makeSchemaCodec } from "./schema-index/index.js";
22
21
  export {
@@ -4,13 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { ChangesetLocalId, RevisionTag } from "../../core/index.js";
7
- import {
8
- type RangeMap,
9
- type RangeQueryResult,
10
- getFromRangeMap,
11
- getOrAddInMap,
12
- setInRangeMap,
13
- } from "../../util/index.js";
7
+ import { RangeMap, type RangeQueryResult } from "../../util/index.js";
14
8
  import type { NodeId } from "./modularChangeTypes.js";
15
9
 
16
10
  export type CrossFieldMap<T> = Map<RevisionTag | undefined, RangeMap<T>>;
@@ -32,7 +26,12 @@ export function setInCrossFieldMap<T>(
32
26
  count: number,
33
27
  value: T,
34
28
  ): void {
35
- setInRangeMap(getOrAddInMap(map, revision, []), id, count, value);
29
+ let rangeMap = map.get(revision);
30
+ if (rangeMap === undefined) {
31
+ rangeMap = new RangeMap();
32
+ map.set(revision, rangeMap);
33
+ }
34
+ rangeMap.set(id, count, value);
36
35
  }
37
36
 
38
37
  export function getFirstFromCrossFieldMap<T>(
@@ -41,7 +40,8 @@ export function getFirstFromCrossFieldMap<T>(
41
40
  id: ChangesetLocalId,
42
41
  count: number,
43
42
  ): RangeQueryResult<T> {
44
- return getFromRangeMap(map.get(revision) ?? [], id, count);
43
+ const rangeMap = map.has(revision) ? (map.get(revision) as RangeMap<T>) : new RangeMap<T>();
44
+ return rangeMap.get(id, count);
45
45
  }
46
46
 
47
47
  /**
@@ -14,12 +14,17 @@ import type {
14
14
  RevisionTag,
15
15
  } from "../../core/index.js";
16
16
  import type { IdAllocator, Invariant } from "../../util/index.js";
17
- import type { MemoizedIdRangeAllocator } from "../memoizedIdRangeAllocator.js";
18
17
 
19
18
  import type { CrossFieldManager } from "./crossFieldQueries.js";
20
19
  import type { CrossFieldKeyRange, NodeId } from "./modularChangeTypes.js";
21
20
  import type { EncodedNodeChangeset } from "./modularChangeFormat.js";
22
21
 
22
+ export type NestedChangesIndices = [
23
+ NodeId,
24
+ number | undefined /* inputIndex */,
25
+ number | undefined /* outputIndex */,
26
+ ][];
27
+
23
28
  /**
24
29
  * Functionality provided by a field kind which will be composed with other `FieldChangeHandler`s to
25
30
  * implement a unified ChangeFamily supporting documents with multiple field kinds.
@@ -39,11 +44,7 @@ export interface FieldChangeHandler<
39
44
  >,
40
45
  ) => ICodecFamily<TChangeset, FieldChangeEncodingContext>;
41
46
  readonly editor: TEditor;
42
- intoDelta(
43
- change: TChangeset,
44
- deltaFromChild: ToDelta,
45
- idAllocator: MemoizedIdRangeAllocator,
46
- ): DeltaFieldChanges;
47
+ intoDelta(change: TChangeset, deltaFromChild: ToDelta): DeltaFieldChanges;
47
48
  /**
48
49
  * Returns the set of removed roots that should be in memory for the given change to be applied.
49
50
  * A removed root is relevant if any of the following is true:
@@ -75,13 +76,16 @@ export interface FieldChangeHandler<
75
76
  * @param change - The field change to get the child changes from.
76
77
  *
77
78
  * @returns The set of `NodeId`s that correspond to nested changes in the given `change`.
78
- * Each `NodeId` is associated with the index of the node in the field in the input context of the changeset
79
- * (or `undefined` if the node is not attached in the input context).
79
+ * Each `NodeId` is associated with the following:
80
+ * - index of the node in the field in the input context of the changeset (or `undefined` if the node is not
81
+ * attached in the input context).
82
+ * - index of the node in the field in the output context of the changeset (or `undefined` if the node is not
83
+ * attached in the output context).
80
84
  * For all returned entries where the index is defined,
81
85
  * the indices are are ordered from smallest to largest (with no duplicates).
82
86
  * The returned array is owned by the caller.
83
87
  */
84
- getNestedChanges(change: TChangeset): [NodeId, number | undefined][];
88
+ getNestedChanges(change: TChangeset): NestedChangesIndices;
85
89
 
86
90
  /**
87
91
  * @returns A list of all cross-field keys contained in the change.
@@ -17,6 +17,7 @@ import { assert } from "@fluidframework/core-utils/internal";
17
17
  import type { CrossFieldManager } from "./crossFieldQueries.js";
18
18
  import type {
19
19
  FieldChangeHandler,
20
+ NestedChangesIndices,
20
21
  NodeChangeComposer,
21
22
  NodeChangePruner,
22
23
  NodeChangeRebaser,
@@ -82,8 +83,9 @@ function compose(
82
83
  return composed;
83
84
  }
84
85
 
85
- function getNestedChanges(change: GenericChangeset): [NodeId, number | undefined][] {
86
- return change.toArray().map(([index, nodeChange]) => [nodeChange, index]);
86
+ function getNestedChanges(change: GenericChangeset): NestedChangesIndices {
87
+ // For generic changeset, the indices in the input and output contexts are the same.
88
+ return change.toArray().map(([index, nodeChange]) => [nodeChange, index, index]);
87
89
  }
88
90
 
89
91
  function rebaseGenericChange(
@@ -41,6 +41,7 @@ export {
41
41
  type ToDelta,
42
42
  NodeAttachState,
43
43
  type FieldChangeEncodingContext,
44
+ type NestedChangesIndices,
44
45
  } from "./fieldChangeHandler.js";
45
46
  export type {
46
47
  CrossFieldKeyRange,
@@ -59,7 +59,6 @@ import {
59
59
  defaultChunkPolicy,
60
60
  } from "../chunked-forest/index.js";
61
61
  import { cursorForMapTreeNode, mapTreeFromCursor } from "../mapTreeCursor.js";
62
- import { MemoizedIdRangeAllocator } from "../memoizedIdRangeAllocator.js";
63
62
 
64
63
  import {
65
64
  type CrossFieldManager,
@@ -649,8 +648,21 @@ export class ModularChangeFamily
649
648
  crossFieldTable: ComposeTable,
650
649
  revisionMetadata: RevisionMetadataSource,
651
650
  ): NodeChangeset {
651
+ // WARNING: this composition logic assumes that we never make compositions of the following form:
652
+ // change1: a changeset that impact the existence of a node
653
+ // change2: a node-exists constraint on that node.
654
+ // This is currently enforced by the fact that constraints which apply to the input context are included first in the composition.
655
+ // If that weren't the case, we would need to rebase the status of the constraint backward over the changes from change1.
652
656
  const nodeExistsConstraint = change1.nodeExistsConstraint ?? change2.nodeExistsConstraint;
653
657
 
658
+ // WARNING: this composition logic assumes that we never make compositions of the following form:
659
+ // change1: a node-exists-on-revert constraint on a node
660
+ // change2: a changeset that impacts the existence of that node
661
+ // This is currently enforced by the fact that constraints which apply to the revert are included last in the composition.
662
+ // If that weren't the case, we would need to rebase the status of the constraint forward over the changes from change2.
663
+ const nodeExistsConstraintOnRevert =
664
+ change1.nodeExistsConstraintOnRevert ?? change2.nodeExistsConstraintOnRevert;
665
+
654
666
  const composedFieldChanges = this.composeFieldMaps(
655
667
  change1.fieldChanges,
656
668
  change2.fieldChanges,
@@ -670,6 +682,10 @@ export class ModularChangeFamily
670
682
  composedNodeChange.nodeExistsConstraint = nodeExistsConstraint;
671
683
  }
672
684
 
685
+ if (nodeExistsConstraintOnRevert !== undefined) {
686
+ composedNodeChange.nodeExistsConstraintOnRevert = nodeExistsConstraintOnRevert;
687
+ }
688
+
673
689
  return composedNodeChange;
674
690
  }
675
691
 
@@ -778,7 +794,8 @@ export class ModularChangeFamily
778
794
  crossFieldKeys,
779
795
  maxId: genId.getMaxId(),
780
796
  revisions: revInfos,
781
- constraintViolationCount: change.change.constraintViolationCount,
797
+ constraintViolationCount: change.change.constraintViolationCountOnRevert,
798
+ constraintViolationCountOnRevert: change.change.constraintViolationCount,
782
799
  destroys,
783
800
  });
784
801
  }
@@ -835,6 +852,19 @@ export class ModularChangeFamily
835
852
  ): NodeChangeset {
836
853
  const inverse: NodeChangeset = {};
837
854
 
855
+ // If the node has a constraint, it should be inverted to a node-exist-on-revert constraint. This ensure that if
856
+ // the inverse is inverted again, the original input constraint will be restored.
857
+ if (change.nodeExistsConstraint !== undefined) {
858
+ inverse.nodeExistsConstraintOnRevert = change.nodeExistsConstraint;
859
+ }
860
+
861
+ // The node-exist-on-revert constraint of a node is the constraint that should apply when the a change is reverted.
862
+ // So, it should become the constraint in the inverse. If this constraint is violated when applying the inverse,
863
+ // it will be discarded.
864
+ if (change.nodeExistsConstraintOnRevert !== undefined) {
865
+ inverse.nodeExistsConstraint = change.nodeExistsConstraintOnRevert;
866
+ }
867
+
838
868
  if (change.fieldChanges !== undefined) {
839
869
  inverse.fieldChanges = this.invertFieldMap(
840
870
  change.fieldChanges,
@@ -878,8 +908,6 @@ export class ModularChangeFamily
878
908
  fieldsWithUnattachedChild: new Set(),
879
909
  };
880
910
 
881
- const constraintState = newConstraintState(change.constraintViolationCount ?? 0);
882
-
883
911
  const getBaseRevisions = (): RevisionTag[] =>
884
912
  revisionInfoFromTaggedChange(over).map((info) => info.revision);
885
913
 
@@ -895,7 +923,6 @@ export class ModularChangeFamily
895
923
  crossFieldTable,
896
924
  rebasedNodes,
897
925
  genId,
898
- constraintState,
899
926
  rebaseMetadata,
900
927
  );
901
928
 
@@ -907,10 +934,16 @@ export class ModularChangeFamily
907
934
  genId,
908
935
  );
909
936
 
937
+ const constraintState = newConstraintState(change.constraintViolationCount ?? 0);
938
+ const revertConstraintState = newConstraintState(
939
+ change.constraintViolationCountOnRevert ?? 0,
940
+ );
910
941
  this.updateConstraintsForFields(
911
942
  rebasedFields,
912
943
  NodeAttachState.Attached,
944
+ NodeAttachState.Attached,
913
945
  constraintState,
946
+ revertConstraintState,
914
947
  rebasedNodes,
915
948
  );
916
949
 
@@ -923,6 +956,7 @@ export class ModularChangeFamily
923
956
  maxId: idState.maxId,
924
957
  revisions: change.revisions,
925
958
  constraintViolationCount: constraintState.violationCount,
959
+ constraintViolationCountOnRevert: revertConstraintState.violationCount,
926
960
  builds: change.builds,
927
961
  destroys: change.destroys,
928
962
  refreshers: change.refreshers,
@@ -937,7 +971,6 @@ export class ModularChangeFamily
937
971
  crossFieldTable: RebaseTable,
938
972
  rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
939
973
  genId: IdAllocator,
940
- constraintState: ConstraintState,
941
974
  metadata: RebaseRevisionMetadata,
942
975
  ): FieldChangeMap {
943
976
  const change = crossFieldTable.newChange;
@@ -960,7 +993,6 @@ export class ModularChangeFamily
960
993
  genId,
961
994
  crossFieldTable,
962
995
  metadata,
963
- constraintState,
964
996
  );
965
997
 
966
998
  setInChangeAtomIdMap(rebasedNodes, newId, rebasedNode);
@@ -1336,7 +1368,6 @@ export class ModularChangeFamily
1336
1368
  genId: IdAllocator,
1337
1369
  crossFieldTable: RebaseTable,
1338
1370
  revisionMetadata: RebaseRevisionMetadata,
1339
- constraintState: ConstraintState,
1340
1371
  ): NodeChangeset {
1341
1372
  const change = nodeChangeFromId(crossFieldTable.newChange.nodeChanges, newId);
1342
1373
  const over = nodeChangeFromId(crossFieldTable.baseChange.nodeChanges, baseId);
@@ -1365,38 +1396,58 @@ export class ModularChangeFamily
1365
1396
  rebasedChange.nodeExistsConstraint = change.nodeExistsConstraint;
1366
1397
  }
1367
1398
 
1399
+ if (change?.nodeExistsConstraintOnRevert !== undefined) {
1400
+ rebasedChange.nodeExistsConstraintOnRevert = change.nodeExistsConstraintOnRevert;
1401
+ }
1402
+
1368
1403
  setInChangeAtomIdMap(crossFieldTable.baseToRebasedNodeId, baseId, newId);
1369
1404
  return rebasedChange;
1370
1405
  }
1371
1406
 
1372
1407
  private updateConstraintsForFields(
1373
1408
  fields: FieldChangeMap,
1374
- parentAttachState: NodeAttachState,
1409
+ parentInputAttachState: NodeAttachState,
1410
+ parentOutputAttachState: NodeAttachState,
1375
1411
  constraintState: ConstraintState,
1412
+ revertConstraintState: ConstraintState,
1376
1413
  nodes: ChangeAtomIdBTree<NodeChangeset>,
1377
1414
  ): void {
1378
1415
  for (const field of fields.values()) {
1379
1416
  const handler = getChangeHandler(this.fieldKinds, field.fieldKind);
1380
- for (const [nodeId, index] of handler.getNestedChanges(field.change)) {
1381
- const isDetached = index === undefined;
1382
- const attachState =
1383
- parentAttachState === NodeAttachState.Detached || isDetached
1417
+ for (const [nodeId, inputIndex, outputIndex] of handler.getNestedChanges(field.change)) {
1418
+ const isInputDetached = inputIndex === undefined;
1419
+ const inputAttachState =
1420
+ parentInputAttachState === NodeAttachState.Detached || isInputDetached
1384
1421
  ? NodeAttachState.Detached
1385
1422
  : NodeAttachState.Attached;
1386
- this.updateConstraintsForNode(nodeId, attachState, constraintState, nodes);
1423
+ const isOutputDetached = outputIndex === undefined;
1424
+ const outputAttachState =
1425
+ parentOutputAttachState === NodeAttachState.Detached || isOutputDetached
1426
+ ? NodeAttachState.Detached
1427
+ : NodeAttachState.Attached;
1428
+ this.updateConstraintsForNode(
1429
+ nodeId,
1430
+ inputAttachState,
1431
+ outputAttachState,
1432
+ nodes,
1433
+ constraintState,
1434
+ revertConstraintState,
1435
+ );
1387
1436
  }
1388
1437
  }
1389
1438
  }
1390
1439
 
1391
1440
  private updateConstraintsForNode(
1392
1441
  nodeId: NodeId,
1393
- attachState: NodeAttachState,
1394
- constraintState: ConstraintState,
1442
+ inputAttachState: NodeAttachState,
1443
+ outputAttachState: NodeAttachState,
1395
1444
  nodes: ChangeAtomIdBTree<NodeChangeset>,
1445
+ constraintState: ConstraintState,
1446
+ revertConstraintState: ConstraintState,
1396
1447
  ): void {
1397
1448
  const node = nodes.get([nodeId.revision, nodeId.localId]) ?? fail("Unknown node ID");
1398
1449
  if (node.nodeExistsConstraint !== undefined) {
1399
- const isNowViolated = attachState === NodeAttachState.Detached;
1450
+ const isNowViolated = inputAttachState === NodeAttachState.Detached;
1400
1451
  if (node.nodeExistsConstraint.violated !== isNowViolated) {
1401
1452
  node.nodeExistsConstraint = {
1402
1453
  ...node.nodeExistsConstraint,
@@ -1405,9 +1456,26 @@ export class ModularChangeFamily
1405
1456
  constraintState.violationCount += isNowViolated ? 1 : -1;
1406
1457
  }
1407
1458
  }
1459
+ if (node.nodeExistsConstraintOnRevert !== undefined) {
1460
+ const isNowViolated = outputAttachState === NodeAttachState.Detached;
1461
+ if (node.nodeExistsConstraintOnRevert.violated !== isNowViolated) {
1462
+ node.nodeExistsConstraintOnRevert = {
1463
+ ...node.nodeExistsConstraintOnRevert,
1464
+ violated: isNowViolated,
1465
+ };
1466
+ revertConstraintState.violationCount += isNowViolated ? 1 : -1;
1467
+ }
1468
+ }
1408
1469
 
1409
1470
  if (node.fieldChanges !== undefined) {
1410
- this.updateConstraintsForFields(node.fieldChanges, attachState, constraintState, nodes);
1471
+ this.updateConstraintsForFields(
1472
+ node.fieldChanges,
1473
+ inputAttachState,
1474
+ outputAttachState,
1475
+ constraintState,
1476
+ revertConstraintState,
1477
+ nodes,
1478
+ );
1411
1479
  }
1412
1480
  }
1413
1481
 
@@ -1907,6 +1975,7 @@ export function updateRefreshers(
1907
1975
  maxId,
1908
1976
  revisions,
1909
1977
  constraintViolationCount,
1978
+ constraintViolationCountOnRevert,
1910
1979
  builds,
1911
1980
  destroys,
1912
1981
  } = change;
@@ -1920,6 +1989,7 @@ export function updateRefreshers(
1920
1989
  maxId: maxId as number,
1921
1990
  revisions,
1922
1991
  constraintViolationCount,
1992
+ constraintViolationCountOnRevert,
1923
1993
  builds,
1924
1994
  destroys,
1925
1995
  refreshers,
@@ -1935,17 +2005,11 @@ export function intoDelta(
1935
2005
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FieldKindWithEditor>,
1936
2006
  ): DeltaRoot {
1937
2007
  const change = taggedChange.change;
1938
- const idAllocator = MemoizedIdRangeAllocator.fromNextId();
1939
2008
  const rootDelta: Mutable<DeltaRoot> = {};
1940
2009
 
1941
2010
  if (!hasConflicts(change)) {
1942
2011
  // If there are no constraint violations, then tree changes apply.
1943
- const fieldDeltas = intoDeltaImpl(
1944
- change.fieldChanges,
1945
- change.nodeChanges,
1946
- idAllocator,
1947
- fieldKinds,
1948
- );
2012
+ const fieldDeltas = intoDeltaImpl(change.fieldChanges, change.nodeChanges, fieldKinds);
1949
2013
  if (fieldDeltas.size > 0) {
1950
2014
  rootDelta.fields = fieldDeltas;
1951
2015
  }
@@ -1995,7 +2059,6 @@ function copyDetachedNodes(
1995
2059
  function intoDeltaImpl(
1996
2060
  change: FieldChangeMap,
1997
2061
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
1998
- idAllocator: MemoizedIdRangeAllocator,
1999
2062
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FieldKindWithEditor>,
2000
2063
  ): Map<FieldKey, DeltaFieldChanges> {
2001
2064
  const delta: Map<FieldKey, DeltaFieldChanges> = new Map();
@@ -2004,9 +2067,8 @@ function intoDeltaImpl(
2004
2067
  fieldChange.change,
2005
2068
  (childChange): DeltaFieldMap => {
2006
2069
  const nodeChange = nodeChangeFromId(nodeChanges, childChange);
2007
- return deltaFromNodeChange(nodeChange, nodeChanges, idAllocator, fieldKinds);
2070
+ return deltaFromNodeChange(nodeChange, nodeChanges, fieldKinds);
2008
2071
  },
2009
- idAllocator,
2010
2072
  );
2011
2073
  if (!isEmptyFieldChanges(deltaField)) {
2012
2074
  delta.set(field, deltaField);
@@ -2018,11 +2080,10 @@ function intoDeltaImpl(
2018
2080
  function deltaFromNodeChange(
2019
2081
  change: NodeChangeset,
2020
2082
  nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
2021
- idAllocator: MemoizedIdRangeAllocator,
2022
2083
  fieldKinds: ReadonlyMap<FieldKindIdentifier, FieldKindWithEditor>,
2023
2084
  ): DeltaFieldMap {
2024
2085
  if (change.fieldChanges !== undefined) {
2025
- return intoDeltaImpl(change.fieldChanges, nodeChanges, idAllocator, fieldKinds);
2086
+ return intoDeltaImpl(change.fieldChanges, nodeChanges, fieldKinds);
2026
2087
  }
2027
2088
  // TODO: update the API to allow undefined to be returned here
2028
2089
  return new Map();
@@ -2061,7 +2122,11 @@ export function rebaseRevisionMetadataFromInfo(
2061
2122
  }
2062
2123
 
2063
2124
  function isEmptyNodeChangeset(change: NodeChangeset): boolean {
2064
- return change.fieldChanges === undefined && change.nodeExistsConstraint === undefined;
2125
+ return (
2126
+ change.fieldChanges === undefined &&
2127
+ change.nodeExistsConstraint === undefined &&
2128
+ change.nodeExistsConstraintOnRevert === undefined
2129
+ );
2065
2130
  }
2066
2131
 
2067
2132
  export function getFieldKind(
@@ -2504,6 +2569,7 @@ function makeModularChangeset(
2504
2569
  maxId: number;
2505
2570
  revisions?: readonly RevisionInfo[];
2506
2571
  constraintViolationCount?: number;
2572
+ constraintViolationCountOnRevert?: number;
2507
2573
  builds?: ChangeAtomIdBTree<TreeChunk>;
2508
2574
  destroys?: ChangeAtomIdBTree<number>;
2509
2575
  refreshers?: ChangeAtomIdBTree<TreeChunk>;
@@ -2528,6 +2594,12 @@ function makeModularChangeset(
2528
2594
  if (props.constraintViolationCount !== undefined && props.constraintViolationCount > 0) {
2529
2595
  changeset.constraintViolationCount = props.constraintViolationCount;
2530
2596
  }
2597
+ if (
2598
+ props.constraintViolationCountOnRevert !== undefined &&
2599
+ props.constraintViolationCountOnRevert > 0
2600
+ ) {
2601
+ changeset.constraintViolationCountOnRevert = props.constraintViolationCountOnRevert;
2602
+ }
2531
2603
  if (props.builds !== undefined && props.builds.size > 0) {
2532
2604
  changeset.builds = props.builds;
2533
2605
  }
@@ -2702,6 +2774,27 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
2702
2774
  ),
2703
2775
  );
2704
2776
  }
2777
+
2778
+ public addNodeExistsConstraintOnRevert(path: UpPath, revision: RevisionTag): void {
2779
+ const nodeChange: NodeChangeset = {
2780
+ nodeExistsConstraintOnRevert: { violated: false },
2781
+ };
2782
+
2783
+ this.applyChange(
2784
+ tagChange(
2785
+ buildModularChangesetFromNode({
2786
+ path,
2787
+ nodeChange,
2788
+ nodeChanges: newTupleBTree(),
2789
+ nodeToParent: newTupleBTree(),
2790
+ crossFieldKeys: newCrossFieldKeyTable(),
2791
+ idAllocator: this.idAllocator,
2792
+ revision,
2793
+ }),
2794
+ revision,
2795
+ ),
2796
+ );
2797
+ }
2705
2798
  }
2706
2799
 
2707
2800
  function buildModularChangesetFromField(props: {
@@ -56,7 +56,16 @@ export interface ModularChangeset extends HasFieldChanges {
56
56
  */
57
57
  readonly nodeAliases: ChangeAtomIdBTree<NodeId>;
58
58
  readonly crossFieldKeys: CrossFieldKeyTable;
59
+ /**
60
+ * The number of constraint violations that apply to the input context of the changeset, i.e., before this change is applied.
61
+ * If this count is greater than 0, it will prevent the changeset from being applied.
62
+ */
59
63
  readonly constraintViolationCount?: number;
64
+ /**
65
+ * The number of constraint violations that apply to the revert of the changeset. If this count is greater than 0, it will
66
+ * prevent the changeset from being reverted or undone.
67
+ */
68
+ readonly constraintViolationCountOnRevert?: number;
60
69
  readonly builds?: ChangeAtomIdBTree<TreeChunk>;
61
70
  readonly destroys?: ChangeAtomIdBTree<number>;
62
71
  readonly refreshers?: ChangeAtomIdBTree<TreeChunk>;
@@ -97,7 +106,10 @@ export interface NodeExistsConstraint {
97
106
  * Changeset for a subtree rooted at a specific node.
98
107
  */
99
108
  export interface NodeChangeset extends HasFieldChanges {
109
+ /** Keeps track of whether node exists constraint has been violated by this change */
100
110
  nodeExistsConstraint?: NodeExistsConstraint;
111
+ /** Keeps track of whether node exists constraint will be violated when this change is reverted */
112
+ nodeExistsConstraintOnRevert?: NodeExistsConstraint;
101
113
  }
102
114
 
103
115
  export type NodeId = ChangeAtomId;
@@ -39,6 +39,7 @@ import {
39
39
  type NodeId,
40
40
  type RelevantRemovedRootsFromChild,
41
41
  type ToDelta,
42
+ type NestedChangesIndices,
42
43
  } from "../modular-schema/index.js";
43
44
 
44
45
  import type {
@@ -536,6 +537,16 @@ function areEqualRegisterIds(id1: RegisterId, id2: RegisterId): boolean {
536
537
  return id1 === "self" || id2 === "self" ? id1 === id2 : areEqualChangeAtomIds(id1, id2);
537
538
  }
538
539
 
540
+ function areEqualRegisterIdsOpt(
541
+ id1: RegisterId | undefined,
542
+ id2: RegisterId | undefined,
543
+ ): boolean {
544
+ if (id1 === undefined || id2 === undefined) {
545
+ return id1 === id2;
546
+ }
547
+ return areEqualRegisterIds(id1, id2);
548
+ }
549
+
539
550
  function getBidirectionalMaps(moves: OptionalChangeset["moves"]): {
540
551
  srcToDst: ChangeAtomIdMap<ChangeAtomId>;
541
552
  dstToSrc: ChangeAtomIdMap<ChangeAtomId>;
@@ -720,11 +731,29 @@ export const optionalChangeHandler: FieldChangeHandler<
720
731
  getCrossFieldKeys: (_change) => [],
721
732
  };
722
733
 
723
- function getNestedChanges(change: OptionalChangeset): [NodeId, number | undefined][] {
724
- return change.childChanges.map(([register, nodeId]) => [
725
- nodeId,
726
- register === "self" ? 0 : undefined,
727
- ]);
734
+ function getNestedChanges(change: OptionalChangeset): NestedChangesIndices {
735
+ // True iff the content of the field changes in some way
736
+ const isFieldContentChanged =
737
+ change.valueReplace !== undefined && change.valueReplace.src !== "self";
738
+
739
+ // The node that is moved into the field (if any).
740
+ const nodeMovedIntoField = change.valueReplace?.src;
741
+
742
+ return change.childChanges.map(([register, nodeId]) => {
743
+ // The node is removed in the input context iif register is not self.
744
+ const inputIndex = register === "self" ? 0 : undefined;
745
+ const outputIndex =
746
+ register === "self"
747
+ ? // If the node starts out as not-removed, it is removed in the output context iff the field content is changed
748
+ isFieldContentChanged
749
+ ? undefined
750
+ : 0
751
+ : // If the node starts out as removed, then it remains removed in the output context iff it is not the node that is moved into the field
752
+ !areEqualRegisterIdsOpt(register, nodeMovedIntoField)
753
+ ? undefined
754
+ : 0;
755
+ return [nodeId, inputIndex, outputIndex];
756
+ });
728
757
  }
729
758
 
730
759
  function* relevantRemovedRoots(