@fluidframework/tree 2.41.0 → 2.42.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 (416) hide show
  1. package/.vscode/settings.json +1 -0
  2. package/CHANGELOG.md +33 -0
  3. package/api-report/tree.alpha.api.md +11 -7
  4. package/dist/alpha.d.ts +1 -0
  5. package/dist/codec/codec.d.ts +23 -3
  6. package/dist/codec/codec.d.ts.map +1 -1
  7. package/dist/codec/codec.js.map +1 -1
  8. package/dist/codec/index.d.ts +1 -1
  9. package/dist/codec/index.d.ts.map +1 -1
  10. package/dist/codec/index.js.map +1 -1
  11. package/dist/codec/versioned/codec.d.ts +35 -2
  12. package/dist/codec/versioned/codec.d.ts.map +1 -1
  13. package/dist/codec/versioned/codec.js +38 -3
  14. package/dist/codec/versioned/codec.js.map +1 -1
  15. package/dist/core/tree/detachedFieldIndex.d.ts +2 -2
  16. package/dist/core/tree/detachedFieldIndex.d.ts.map +1 -1
  17. package/dist/core/tree/detachedFieldIndex.js +5 -1
  18. package/dist/core/tree/detachedFieldIndex.js.map +1 -1
  19. package/dist/core/tree/mapTree.d.ts +2 -1
  20. package/dist/core/tree/mapTree.d.ts.map +1 -1
  21. package/dist/core/tree/mapTree.js +11 -5
  22. package/dist/core/tree/mapTree.js.map +1 -1
  23. package/dist/core/tree/visitorUtils.d.ts +2 -2
  24. package/dist/core/tree/visitorUtils.d.ts.map +1 -1
  25. package/dist/core/tree/visitorUtils.js.map +1 -1
  26. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts +3 -2
  27. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  28. package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  29. package/dist/feature-libraries/default-schema/schemaChecker.d.ts +4 -3
  30. package/dist/feature-libraries/default-schema/schemaChecker.d.ts.map +1 -1
  31. package/dist/feature-libraries/default-schema/schemaChecker.js +4 -3
  32. package/dist/feature-libraries/default-schema/schemaChecker.js.map +1 -1
  33. package/dist/feature-libraries/flex-tree/context.d.ts +14 -6
  34. package/dist/feature-libraries/flex-tree/context.d.ts.map +1 -1
  35. package/dist/feature-libraries/flex-tree/context.js.map +1 -1
  36. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +34 -14
  37. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  38. package/dist/feature-libraries/flex-tree/flexTreeTypes.js +4 -0
  39. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  40. package/dist/feature-libraries/flex-tree/index.d.ts +2 -2
  41. package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
  42. package/dist/feature-libraries/flex-tree/index.js.map +1 -1
  43. package/dist/feature-libraries/flex-tree/lazyField.d.ts +6 -6
  44. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  45. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  46. package/dist/feature-libraries/flex-tree/lazyNode.d.ts +3 -2
  47. package/dist/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  48. package/dist/feature-libraries/flex-tree/lazyNode.js +3 -0
  49. package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  50. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts +2 -2
  51. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  52. package/dist/feature-libraries/forest-summary/forestSummarizer.js +7 -7
  53. package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  54. package/dist/feature-libraries/index.d.ts +2 -2
  55. package/dist/feature-libraries/index.d.ts.map +1 -1
  56. package/dist/feature-libraries/index.js +4 -2
  57. package/dist/feature-libraries/index.js.map +1 -1
  58. package/dist/feature-libraries/mapTreeCursor.d.ts +39 -3
  59. package/dist/feature-libraries/mapTreeCursor.d.ts.map +1 -1
  60. package/dist/feature-libraries/mapTreeCursor.js +45 -7
  61. package/dist/feature-libraries/mapTreeCursor.js.map +1 -1
  62. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts +1 -1
  63. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  64. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +5 -5
  65. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  66. package/dist/feature-libraries/treeCursorUtils.d.ts +5 -1
  67. package/dist/feature-libraries/treeCursorUtils.d.ts.map +1 -1
  68. package/dist/feature-libraries/treeCursorUtils.js +8 -2
  69. package/dist/feature-libraries/treeCursorUtils.js.map +1 -1
  70. package/dist/index.d.ts +1 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/packageVersion.d.ts +1 -1
  74. package/dist/packageVersion.js +1 -1
  75. package/dist/packageVersion.js.map +1 -1
  76. package/dist/shared-tree/schematizingTreeView.d.ts +11 -1
  77. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  78. package/dist/shared-tree/schematizingTreeView.js +36 -22
  79. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  80. package/dist/shared-tree/sharedTree.d.ts +3 -3
  81. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  82. package/dist/shared-tree/sharedTree.js +1 -0
  83. package/dist/shared-tree/sharedTree.js.map +1 -1
  84. package/dist/shared-tree/tree.d.ts.map +1 -1
  85. package/dist/shared-tree/tree.js +8 -24
  86. package/dist/shared-tree/tree.js.map +1 -1
  87. package/dist/shared-tree/treeAlpha.d.ts +2 -3
  88. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  89. package/dist/shared-tree/treeAlpha.js +13 -15
  90. package/dist/shared-tree/treeAlpha.js.map +1 -1
  91. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  92. package/dist/shared-tree/treeCheckout.js +5 -2
  93. package/dist/shared-tree/treeCheckout.js.map +1 -1
  94. package/dist/simple-tree/api/configuration.d.ts +2 -2
  95. package/dist/simple-tree/api/configuration.js +1 -1
  96. package/dist/simple-tree/api/configuration.js.map +1 -1
  97. package/dist/simple-tree/api/create.d.ts +9 -4
  98. package/dist/simple-tree/api/create.d.ts.map +1 -1
  99. package/dist/simple-tree/api/create.js +29 -16
  100. package/dist/simple-tree/api/create.js.map +1 -1
  101. package/dist/simple-tree/api/customTree.d.ts +4 -0
  102. package/dist/simple-tree/api/customTree.d.ts.map +1 -1
  103. package/dist/simple-tree/api/customTree.js +9 -1
  104. package/dist/simple-tree/api/customTree.js.map +1 -1
  105. package/dist/simple-tree/api/index.d.ts +1 -1
  106. package/dist/simple-tree/api/index.d.ts.map +1 -1
  107. package/dist/simple-tree/api/index.js +1 -2
  108. package/dist/simple-tree/api/index.js.map +1 -1
  109. package/dist/simple-tree/api/schemaFactory.d.ts +10 -2
  110. package/dist/simple-tree/api/schemaFactory.d.ts.map +1 -1
  111. package/dist/simple-tree/api/schemaFactory.js +38 -9
  112. package/dist/simple-tree/api/schemaFactory.js.map +1 -1
  113. package/dist/simple-tree/api/treeNodeApi.d.ts +14 -3
  114. package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  115. package/dist/simple-tree/api/treeNodeApi.js +32 -17
  116. package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
  117. package/dist/simple-tree/api/verboseTree.d.ts.map +1 -1
  118. package/dist/simple-tree/api/verboseTree.js +12 -9
  119. package/dist/simple-tree/api/verboseTree.js.map +1 -1
  120. package/dist/simple-tree/core/getOrCreateNode.d.ts.map +1 -1
  121. package/dist/simple-tree/core/getOrCreateNode.js +2 -1
  122. package/dist/simple-tree/core/getOrCreateNode.js.map +1 -1
  123. package/dist/simple-tree/core/index.d.ts +2 -2
  124. package/dist/simple-tree/core/index.d.ts.map +1 -1
  125. package/dist/simple-tree/core/index.js +3 -4
  126. package/dist/simple-tree/core/index.js.map +1 -1
  127. package/dist/simple-tree/core/treeNodeKernel.d.ts +15 -25
  128. package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  129. package/dist/simple-tree/core/treeNodeKernel.js +26 -33
  130. package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
  131. package/dist/simple-tree/core/unhydratedFlexTree.d.ts +128 -59
  132. package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  133. package/dist/simple-tree/core/unhydratedFlexTree.js +169 -182
  134. package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  135. package/dist/simple-tree/index.d.ts +3 -3
  136. package/dist/simple-tree/index.d.ts.map +1 -1
  137. package/dist/simple-tree/index.js +5 -5
  138. package/dist/simple-tree/index.js.map +1 -1
  139. package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  140. package/dist/simple-tree/node-kinds/array/arrayNode.js +5 -6
  141. package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  142. package/dist/simple-tree/node-kinds/index.d.ts +1 -1
  143. package/dist/simple-tree/node-kinds/index.d.ts.map +1 -1
  144. package/dist/simple-tree/node-kinds/index.js +1 -2
  145. package/dist/simple-tree/node-kinds/index.js.map +1 -1
  146. package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  147. package/dist/simple-tree/node-kinds/map/mapNode.js +2 -2
  148. package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  149. package/dist/simple-tree/node-kinds/object/index.d.ts +1 -1
  150. package/dist/simple-tree/node-kinds/object/index.d.ts.map +1 -1
  151. package/dist/simple-tree/node-kinds/object/index.js +1 -2
  152. package/dist/simple-tree/node-kinds/object/index.js.map +1 -1
  153. package/dist/simple-tree/node-kinds/object/objectNode.d.ts +3 -14
  154. package/dist/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  155. package/dist/simple-tree/node-kinds/object/objectNode.js +12 -43
  156. package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  157. package/dist/simple-tree/prepareForInsertion.d.ts +20 -6
  158. package/dist/simple-tree/prepareForInsertion.d.ts.map +1 -1
  159. package/dist/simple-tree/prepareForInsertion.js +26 -19
  160. package/dist/simple-tree/prepareForInsertion.js.map +1 -1
  161. package/dist/simple-tree/schemaTypes.d.ts +8 -8
  162. package/dist/simple-tree/schemaTypes.d.ts.map +1 -1
  163. package/dist/simple-tree/schemaTypes.js.map +1 -1
  164. package/dist/simple-tree/toStoredSchema.d.ts +6 -1
  165. package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
  166. package/dist/simple-tree/toStoredSchema.js +6 -3
  167. package/dist/simple-tree/toStoredSchema.js.map +1 -1
  168. package/dist/simple-tree/{toMapTree.d.ts → unhydratedFlexTreeFromInsertable.d.ts} +12 -23
  169. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -0
  170. package/dist/simple-tree/{toMapTree.js → unhydratedFlexTreeFromInsertable.js} +103 -185
  171. package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -0
  172. package/dist/treeFactory.d.ts.map +1 -1
  173. package/dist/treeFactory.js +6 -1
  174. package/dist/treeFactory.js.map +1 -1
  175. package/dist/util/index.d.ts +1 -1
  176. package/dist/util/index.d.ts.map +1 -1
  177. package/dist/util/index.js +2 -1
  178. package/dist/util/index.js.map +1 -1
  179. package/dist/util/utils.d.ts +4 -0
  180. package/dist/util/utils.d.ts.map +1 -1
  181. package/dist/util/utils.js +8 -1
  182. package/dist/util/utils.js.map +1 -1
  183. package/docs/user-facing/schema-evolution.md +1 -1
  184. package/lib/alpha.d.ts +1 -0
  185. package/lib/codec/codec.d.ts +23 -3
  186. package/lib/codec/codec.d.ts.map +1 -1
  187. package/lib/codec/codec.js.map +1 -1
  188. package/lib/codec/index.d.ts +1 -1
  189. package/lib/codec/index.d.ts.map +1 -1
  190. package/lib/codec/index.js.map +1 -1
  191. package/lib/codec/versioned/codec.d.ts +35 -2
  192. package/lib/codec/versioned/codec.d.ts.map +1 -1
  193. package/lib/codec/versioned/codec.js +36 -2
  194. package/lib/codec/versioned/codec.js.map +1 -1
  195. package/lib/core/tree/detachedFieldIndex.d.ts +2 -2
  196. package/lib/core/tree/detachedFieldIndex.d.ts.map +1 -1
  197. package/lib/core/tree/detachedFieldIndex.js +6 -2
  198. package/lib/core/tree/detachedFieldIndex.js.map +1 -1
  199. package/lib/core/tree/mapTree.d.ts +2 -1
  200. package/lib/core/tree/mapTree.d.ts.map +1 -1
  201. package/lib/core/tree/mapTree.js +11 -5
  202. package/lib/core/tree/mapTree.js.map +1 -1
  203. package/lib/core/tree/visitorUtils.d.ts +2 -2
  204. package/lib/core/tree/visitorUtils.d.ts.map +1 -1
  205. package/lib/core/tree/visitorUtils.js.map +1 -1
  206. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts +3 -2
  207. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  208. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  209. package/lib/feature-libraries/default-schema/schemaChecker.d.ts +4 -3
  210. package/lib/feature-libraries/default-schema/schemaChecker.d.ts.map +1 -1
  211. package/lib/feature-libraries/default-schema/schemaChecker.js +4 -3
  212. package/lib/feature-libraries/default-schema/schemaChecker.js.map +1 -1
  213. package/lib/feature-libraries/flex-tree/context.d.ts +14 -6
  214. package/lib/feature-libraries/flex-tree/context.d.ts.map +1 -1
  215. package/lib/feature-libraries/flex-tree/context.js.map +1 -1
  216. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +34 -14
  217. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  218. package/lib/feature-libraries/flex-tree/flexTreeTypes.js +4 -0
  219. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  220. package/lib/feature-libraries/flex-tree/index.d.ts +2 -2
  221. package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
  222. package/lib/feature-libraries/flex-tree/index.js.map +1 -1
  223. package/lib/feature-libraries/flex-tree/lazyField.d.ts +6 -6
  224. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  225. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  226. package/lib/feature-libraries/flex-tree/lazyNode.d.ts +3 -2
  227. package/lib/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  228. package/lib/feature-libraries/flex-tree/lazyNode.js +3 -0
  229. package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  230. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts +2 -2
  231. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  232. package/lib/feature-libraries/forest-summary/forestSummarizer.js +2 -2
  233. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  234. package/lib/feature-libraries/index.d.ts +2 -2
  235. package/lib/feature-libraries/index.d.ts.map +1 -1
  236. package/lib/feature-libraries/index.js +1 -1
  237. package/lib/feature-libraries/index.js.map +1 -1
  238. package/lib/feature-libraries/mapTreeCursor.d.ts +39 -3
  239. package/lib/feature-libraries/mapTreeCursor.d.ts.map +1 -1
  240. package/lib/feature-libraries/mapTreeCursor.js +43 -7
  241. package/lib/feature-libraries/mapTreeCursor.js.map +1 -1
  242. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts +1 -1
  243. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  244. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +5 -5
  245. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  246. package/lib/feature-libraries/treeCursorUtils.d.ts +5 -1
  247. package/lib/feature-libraries/treeCursorUtils.d.ts.map +1 -1
  248. package/lib/feature-libraries/treeCursorUtils.js +8 -2
  249. package/lib/feature-libraries/treeCursorUtils.js.map +1 -1
  250. package/lib/index.d.ts +1 -1
  251. package/lib/index.d.ts.map +1 -1
  252. package/lib/index.js.map +1 -1
  253. package/lib/packageVersion.d.ts +1 -1
  254. package/lib/packageVersion.js +1 -1
  255. package/lib/packageVersion.js.map +1 -1
  256. package/lib/shared-tree/schematizingTreeView.d.ts +11 -1
  257. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  258. package/lib/shared-tree/schematizingTreeView.js +34 -21
  259. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  260. package/lib/shared-tree/sharedTree.d.ts +3 -3
  261. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  262. package/lib/shared-tree/sharedTree.js +2 -1
  263. package/lib/shared-tree/sharedTree.js.map +1 -1
  264. package/lib/shared-tree/tree.d.ts.map +1 -1
  265. package/lib/shared-tree/tree.js +2 -18
  266. package/lib/shared-tree/tree.js.map +1 -1
  267. package/lib/shared-tree/treeAlpha.d.ts +2 -3
  268. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  269. package/lib/shared-tree/treeAlpha.js +4 -6
  270. package/lib/shared-tree/treeAlpha.js.map +1 -1
  271. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  272. package/lib/shared-tree/treeCheckout.js +6 -3
  273. package/lib/shared-tree/treeCheckout.js.map +1 -1
  274. package/lib/simple-tree/api/configuration.d.ts +2 -2
  275. package/lib/simple-tree/api/configuration.js +1 -1
  276. package/lib/simple-tree/api/configuration.js.map +1 -1
  277. package/lib/simple-tree/api/create.d.ts +9 -4
  278. package/lib/simple-tree/api/create.d.ts.map +1 -1
  279. package/lib/simple-tree/api/create.js +22 -9
  280. package/lib/simple-tree/api/create.js.map +1 -1
  281. package/lib/simple-tree/api/customTree.d.ts +4 -0
  282. package/lib/simple-tree/api/customTree.d.ts.map +1 -1
  283. package/lib/simple-tree/api/customTree.js +7 -0
  284. package/lib/simple-tree/api/customTree.js.map +1 -1
  285. package/lib/simple-tree/api/index.d.ts +1 -1
  286. package/lib/simple-tree/api/index.d.ts.map +1 -1
  287. package/lib/simple-tree/api/index.js +1 -1
  288. package/lib/simple-tree/api/index.js.map +1 -1
  289. package/lib/simple-tree/api/schemaFactory.d.ts +10 -2
  290. package/lib/simple-tree/api/schemaFactory.d.ts.map +1 -1
  291. package/lib/simple-tree/api/schemaFactory.js +40 -11
  292. package/lib/simple-tree/api/schemaFactory.js.map +1 -1
  293. package/lib/simple-tree/api/treeNodeApi.d.ts +14 -3
  294. package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  295. package/lib/simple-tree/api/treeNodeApi.js +35 -20
  296. package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
  297. package/lib/simple-tree/api/verboseTree.d.ts.map +1 -1
  298. package/lib/simple-tree/api/verboseTree.js +13 -10
  299. package/lib/simple-tree/api/verboseTree.js.map +1 -1
  300. package/lib/simple-tree/core/getOrCreateNode.d.ts.map +1 -1
  301. package/lib/simple-tree/core/getOrCreateNode.js +3 -2
  302. package/lib/simple-tree/core/getOrCreateNode.js.map +1 -1
  303. package/lib/simple-tree/core/index.d.ts +2 -2
  304. package/lib/simple-tree/core/index.d.ts.map +1 -1
  305. package/lib/simple-tree/core/index.js +2 -2
  306. package/lib/simple-tree/core/index.js.map +1 -1
  307. package/lib/simple-tree/core/treeNodeKernel.d.ts +15 -25
  308. package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  309. package/lib/simple-tree/core/treeNodeKernel.js +24 -32
  310. package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
  311. package/lib/simple-tree/core/unhydratedFlexTree.d.ts +128 -59
  312. package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  313. package/lib/simple-tree/core/unhydratedFlexTree.js +166 -181
  314. package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  315. package/lib/simple-tree/index.d.ts +3 -3
  316. package/lib/simple-tree/index.d.ts.map +1 -1
  317. package/lib/simple-tree/index.js +3 -3
  318. package/lib/simple-tree/index.js.map +1 -1
  319. package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  320. package/lib/simple-tree/node-kinds/array/arrayNode.js +4 -5
  321. package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  322. package/lib/simple-tree/node-kinds/index.d.ts +1 -1
  323. package/lib/simple-tree/node-kinds/index.d.ts.map +1 -1
  324. package/lib/simple-tree/node-kinds/index.js +1 -1
  325. package/lib/simple-tree/node-kinds/index.js.map +1 -1
  326. package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  327. package/lib/simple-tree/node-kinds/map/mapNode.js +3 -3
  328. package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  329. package/lib/simple-tree/node-kinds/object/index.d.ts +1 -1
  330. package/lib/simple-tree/node-kinds/object/index.d.ts.map +1 -1
  331. package/lib/simple-tree/node-kinds/object/index.js +1 -1
  332. package/lib/simple-tree/node-kinds/object/index.js.map +1 -1
  333. package/lib/simple-tree/node-kinds/object/objectNode.d.ts +3 -14
  334. package/lib/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  335. package/lib/simple-tree/node-kinds/object/objectNode.js +3 -33
  336. package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  337. package/lib/simple-tree/prepareForInsertion.d.ts +20 -6
  338. package/lib/simple-tree/prepareForInsertion.d.ts.map +1 -1
  339. package/lib/simple-tree/prepareForInsertion.js +25 -19
  340. package/lib/simple-tree/prepareForInsertion.js.map +1 -1
  341. package/lib/simple-tree/schemaTypes.d.ts +8 -8
  342. package/lib/simple-tree/schemaTypes.d.ts.map +1 -1
  343. package/lib/simple-tree/schemaTypes.js.map +1 -1
  344. package/lib/simple-tree/toStoredSchema.d.ts +6 -1
  345. package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
  346. package/lib/simple-tree/toStoredSchema.js +4 -1
  347. package/lib/simple-tree/toStoredSchema.js.map +1 -1
  348. package/lib/simple-tree/{toMapTree.d.ts → unhydratedFlexTreeFromInsertable.d.ts} +12 -23
  349. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -0
  350. package/lib/simple-tree/{toMapTree.js → unhydratedFlexTreeFromInsertable.js} +105 -186
  351. package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -0
  352. package/lib/treeFactory.d.ts.map +1 -1
  353. package/lib/treeFactory.js +6 -1
  354. package/lib/treeFactory.js.map +1 -1
  355. package/lib/util/index.d.ts +1 -1
  356. package/lib/util/index.d.ts.map +1 -1
  357. package/lib/util/index.js +1 -1
  358. package/lib/util/index.js.map +1 -1
  359. package/lib/util/utils.d.ts +4 -0
  360. package/lib/util/utils.d.ts.map +1 -1
  361. package/lib/util/utils.js +6 -0
  362. package/lib/util/utils.js.map +1 -1
  363. package/package.json +21 -21
  364. package/src/codec/codec.ts +24 -3
  365. package/src/codec/index.ts +1 -0
  366. package/src/codec/versioned/codec.ts +42 -5
  367. package/src/core/tree/detachedFieldIndex.ts +13 -4
  368. package/src/core/tree/mapTree.ts +22 -7
  369. package/src/core/tree/visitorUtils.ts +2 -2
  370. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +3 -2
  371. package/src/feature-libraries/default-schema/schemaChecker.ts +7 -6
  372. package/src/feature-libraries/flex-tree/context.ts +17 -7
  373. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +36 -15
  374. package/src/feature-libraries/flex-tree/index.ts +4 -0
  375. package/src/feature-libraries/flex-tree/lazyField.ts +8 -6
  376. package/src/feature-libraries/flex-tree/lazyNode.ts +6 -2
  377. package/src/feature-libraries/forest-summary/forestSummarizer.ts +3 -2
  378. package/src/feature-libraries/index.ts +9 -0
  379. package/src/feature-libraries/mapTreeCursor.ts +103 -16
  380. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +9 -5
  381. package/src/feature-libraries/treeCursorUtils.ts +21 -10
  382. package/src/index.ts +1 -0
  383. package/src/packageVersion.ts +1 -1
  384. package/src/shared-tree/schematizingTreeView.ts +40 -22
  385. package/src/shared-tree/sharedTree.ts +9 -3
  386. package/src/shared-tree/tree.ts +5 -20
  387. package/src/shared-tree/treeAlpha.ts +17 -11
  388. package/src/shared-tree/treeCheckout.ts +6 -3
  389. package/src/simple-tree/api/configuration.ts +3 -3
  390. package/src/simple-tree/api/create.ts +49 -19
  391. package/src/simple-tree/api/customTree.ts +10 -0
  392. package/src/simple-tree/api/index.ts +1 -4
  393. package/src/simple-tree/api/schemaFactory.ts +62 -13
  394. package/src/simple-tree/api/treeNodeApi.ts +48 -27
  395. package/src/simple-tree/api/verboseTree.ts +15 -12
  396. package/src/simple-tree/core/getOrCreateNode.ts +4 -2
  397. package/src/simple-tree/core/index.ts +2 -3
  398. package/src/simple-tree/core/treeNodeKernel.ts +37 -54
  399. package/src/simple-tree/core/unhydratedFlexTree.ts +222 -261
  400. package/src/simple-tree/index.ts +3 -3
  401. package/src/simple-tree/node-kinds/array/arrayNode.ts +12 -13
  402. package/src/simple-tree/node-kinds/index.ts +0 -1
  403. package/src/simple-tree/node-kinds/map/mapNode.ts +6 -9
  404. package/src/simple-tree/node-kinds/object/index.ts +0 -1
  405. package/src/simple-tree/node-kinds/object/objectNode.ts +7 -49
  406. package/src/simple-tree/prepareForInsertion.ts +49 -42
  407. package/src/simple-tree/schemaTypes.ts +9 -8
  408. package/src/simple-tree/toStoredSchema.ts +7 -1
  409. package/src/simple-tree/{toMapTree.ts → unhydratedFlexTreeFromInsertable.ts} +134 -226
  410. package/src/treeFactory.ts +6 -1
  411. package/src/util/index.ts +1 -0
  412. package/src/util/utils.ts +7 -0
  413. package/dist/simple-tree/toMapTree.d.ts.map +0 -1
  414. package/dist/simple-tree/toMapTree.js.map +0 -1
  415. package/lib/simple-tree/toMapTree.d.ts.map +0 -1
  416. package/lib/simple-tree/toMapTree.js.map +0 -1
@@ -10,19 +10,18 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal";
10
10
 
11
11
  import {
12
12
  type AnchorEvents,
13
- type AnchorNode,
14
13
  EmptyKey,
15
- type ExclusiveMapTree,
16
14
  type FieldKey,
17
15
  type FieldKindIdentifier,
18
16
  forbiddenFieldKindIdentifier,
19
17
  type ITreeCursorSynchronous,
20
- type MapTree,
18
+ type NodeData,
21
19
  type NormalizedFieldUpPath,
22
20
  type SchemaPolicy,
23
21
  type TreeNodeSchemaIdentifier,
24
22
  type TreeNodeStoredSchema,
25
23
  type TreeStoredSchema,
24
+ type TreeValue,
26
25
  type Value,
27
26
  } from "../../core/index.js";
28
27
  import {
@@ -42,21 +41,23 @@ import {
42
41
  FieldKinds,
43
42
  type SequenceFieldEditBuilder,
44
43
  cursorForMapTreeNode,
44
+ type OptionalFieldEditBuilder,
45
+ type ValueFieldEditBuilder,
46
+ type FlexibleNodeContent,
47
+ type FlexTreeHydratedContextMinimal,
48
+ type FlexibleFieldContent,
49
+ type MapTreeFieldViewGeneric,
50
+ type MapTreeNodeViewGeneric,
51
+ type HydratedFlexTreeNode,
45
52
  } from "../../feature-libraries/index.js";
46
- import { brand, getOrCreate, mapIterable } from "../../util/index.js";
53
+ import { brand, filterIterable, getOrCreate } from "../../util/index.js";
47
54
 
48
55
  import type { Context } from "./context.js";
56
+ import type { ContextualFieldProvider } from "../schemaTypes.js";
57
+ import type { TreeNode } from "./treeNode.js";
49
58
 
50
59
  interface UnhydratedTreeSequenceFieldEditBuilder
51
- extends SequenceFieldEditBuilder<ExclusiveMapTree[]> {
52
- /**
53
- * Issues a change which removes `count` elements starting at the given `index`.
54
- * @param index - The index of the first removed element.
55
- * @param count - The number of elements to remove.
56
- * @returns the MapTrees that were removed
57
- */
58
- remove(index: number, count: number): ExclusiveMapTree[];
59
- }
60
+ extends SequenceFieldEditBuilder<FlexibleFieldContent, UnhydratedFlexTreeNode[]> {}
60
61
 
61
62
  type UnhydratedFlexTreeNodeEvents = Pick<AnchorEvents, "childrenChangedAfterBatch">;
62
63
 
@@ -67,24 +68,33 @@ interface LocationInField {
67
68
  }
68
69
 
69
70
  /**
70
- * An unhydrated implementation of {@link FlexTreeNode} which wraps a {@link MapTree}.
71
- * @remarks
72
- * MapTreeNodes are unconditionally cached -
73
- * when retrieved via {@link getOrCreateNodeFromInnerNode}, the same {@link MapTree} object will always produce the same `UnhydratedFlexTreeNode` object.
74
- *
75
- * Create a `UnhydratedFlexTreeNode` by calling {@link getOrCreate}.
71
+ * The {@link Unhydrated} implementation of {@link FlexTreeNode}.
76
72
  */
77
- export class UnhydratedFlexTreeNode implements FlexTreeNode {
78
- public get schema(): TreeNodeSchemaIdentifier {
79
- return this.mapTree.type;
73
+ export class UnhydratedFlexTreeNode
74
+ implements FlexTreeNode, MapTreeNodeViewGeneric<UnhydratedFlexTreeNode>
75
+ {
76
+ public isHydrated(): this is HydratedFlexTreeNode {
77
+ return false;
80
78
  }
81
79
 
80
+ private location = unparentedLocation;
81
+
82
82
  public get storedSchema(): TreeNodeStoredSchema {
83
83
  return (
84
- this.context.schema.nodeSchema.get(this.mapTree.type) ?? fail(0xb46 /* missing schema */)
84
+ this.context.schema.nodeSchema.get(this.data.type) ?? fail(0xb46 /* missing schema */)
85
85
  );
86
86
  }
87
87
 
88
+ /**
89
+ * Cache storing the {@link TreeNode} for this inner node.
90
+ * @remarks
91
+ * When creating a `TreeNode` for this `UnhydratedFlexTreeNode`, cache the `TreeNode` in this property.
92
+ * Currently this is done by {@link TreeNodeKernel}.
93
+ *
94
+ * See {@link getOrCreateNodeFromInnerNode} how to get the `TreeNode`, even if not already created, regardless of hydration status.
95
+ */
96
+ public treeNode: TreeNode | undefined;
97
+
88
98
  public readonly [flexTreeMarker] = FlexTreeEntityKind.Node as const;
89
99
 
90
100
  private readonly _events = createEmitter<UnhydratedFlexTreeNodeEvents>();
@@ -92,52 +102,77 @@ export class UnhydratedFlexTreeNode implements FlexTreeNode {
92
102
  return this._events;
93
103
  }
94
104
 
95
- /**
96
- * Create a {@link UnhydratedFlexTreeNode} that wraps the given {@link MapTree}, or get the node that already exists for that {@link MapTree} if there is one.
97
- * @param nodeSchema - the {@link FlexTreeNodeSchema | schema} that the node conforms to
98
- * @param mapTree - the {@link MapTree} containing the data for this node.
99
- * @remarks It must conform to the `nodeSchema`.
100
- */
101
- public static getOrCreate(
102
- context: Context,
103
- mapTree: ExclusiveMapTree,
104
- ): UnhydratedFlexTreeNode {
105
- return nodeCache.get(mapTree) ?? new UnhydratedFlexTreeNode(context, mapTree, undefined);
106
- }
107
-
108
105
  public get context(): FlexTreeContext {
109
106
  return this.simpleContext.flexContext;
110
107
  }
111
108
 
112
109
  /**
113
110
  * Create a new UnhydratedFlexTreeNode.
114
- * @param location - the parentage of this node, if it is being created underneath an existing node and field, or undefined if not
115
- * @remarks This class (and its subclasses) should not be directly constructed outside of this module.
116
- * Instead, use {@link getOrCreateNodeFromInnerNode} to create a UnhydratedFlexTreeNode from a {@link MapTree}.
117
- * A `UnhydratedFlexTreeNode` may never be constructed more than once for the same {@link MapTree} object.
118
- * Instead, it should always be acquired via {@link getOrCreateNodeFromInnerNode}.
119
111
  */
120
112
  public constructor(
113
+ /**
114
+ * The {@link NodeData} for this node.
115
+ */
116
+ public readonly data: NodeData,
117
+ /**
118
+ * All {@link UnhydratedFlexTreeField} for this node that have been created so far.
119
+ * @remarks
120
+ * This includes all non-empty fields, but also any empty fields which have been previously requested.
121
+ */
122
+ private readonly fieldsAll: Map<FieldKey, UnhydratedFlexTreeField>,
123
+ /**
124
+ * The {@link Context} for this node.
125
+ * @remarks
126
+ * Provides access to all schema reachable from this node.
127
+ * See {@link getUnhydratedContext}.
128
+ */
121
129
  public readonly simpleContext: Context,
122
- /** The underlying {@link MapTree} that this `UnhydratedFlexTreeNode` reads its data from */
123
- public readonly mapTree: ExclusiveMapTree,
124
- private location = unparentedLocation,
125
130
  ) {
126
- assert(!nodeCache.has(mapTree), 0x98b /* A node already exists for the given MapTree */);
127
- nodeCache.set(mapTree, this);
131
+ for (const [_key, field] of this.fieldsAll) {
132
+ field.parent = this;
133
+ }
134
+ }
128
135
 
129
- // Fully demand the tree to ensure that parent pointers are present and accurate on all nodes.
130
- // When a UnhydratedFlexTreeNode is constructed, its MapTree may contain nodes (anywhere below) that map (via the `nodeCache`) to pre-existing UnhydratedFlexTreeNodes.
131
- // Put another way, for a given MapTree, some ancestor UnhydratedFlexTreeNode can be created after any number of its descendant UnhydratedFlexTreeNodes already exist.
132
- // In such a case, the spine of nodes between the descendant and ancestor need to exist in order for the ancestor to be able to walk upwards via the `parentField` property.
133
- // This needs to happen for all UnhydratedFlexTreeNodes that are descendants of the ancestor UnhydratedFlexTreeNode.
134
- // Demanding the entire tree is overkill to solve this problem since not all descendant MapTree nodes will have corresponding UnhydratedFlexTreeNodes.
135
- // However, demanding the full tree also lets us eagerly validate that there are no duplicate MapTrees (i.e. same MapTree object) anywhere in the tree.
136
- this.walkTree();
136
+ /**
137
+ * The non-empty fields on this node.
138
+ * @remarks
139
+ * This is needed to implement {@link MapTreeNodeViewGeneric.fields}, which must omit empty fields.
140
+ * Due to having to detect if a field is empty, this forces the evaluation of any pending defaults in the fields.
141
+ * Use {@link allFieldsLazy} to avoid evaluating pending defaults.
142
+ */
143
+ public readonly fields: Pick<
144
+ Map<FieldKey, UnhydratedFlexTreeField>,
145
+ typeof Symbol.iterator | "get"
146
+ > = {
147
+ get: (key: FieldKey): UnhydratedFlexTreeField | undefined => this.tryGetField(key),
148
+ [Symbol.iterator]: (): IterableIterator<[FieldKey, UnhydratedFlexTreeField]> =>
149
+ filterIterable(this.fieldsAll, ([, field]) => field.length > 0),
150
+ };
151
+
152
+ /**
153
+ * Gets all fields, without filtering out empty ones.
154
+ * @remarks
155
+ * This avoids forcing the evaluating of pending defaults in the fields, and also saves a copy on access.
156
+ */
157
+ public get allFieldsLazy(): ReadonlyMap<FieldKey, UnhydratedFlexTreeField> {
158
+ return this.fieldsAll;
137
159
  }
138
160
 
139
161
  public get type(): TreeNodeSchemaIdentifier {
140
- return this.mapTree.type;
162
+ return this.data.type;
163
+ }
164
+
165
+ public get schema(): TreeNodeSchemaIdentifier {
166
+ return this.data.type;
167
+ }
168
+
169
+ private getOrCreateField(key: FieldKey): UnhydratedFlexTreeField {
170
+ return getOrCreate(this.fieldsAll, key, () => {
171
+ const stored = this.storedSchema.getFieldSchema(key).kind;
172
+ const field = createField(this.context, stored, key, []);
173
+ field.parent = this;
174
+ return field;
175
+ });
141
176
  }
142
177
 
143
178
  /**
@@ -153,7 +188,7 @@ export class UnhydratedFlexTreeNode implements FlexTreeNode {
153
188
  if (parent !== undefined) {
154
189
  assert(index !== undefined, 0xa08 /* Expected index */);
155
190
  if (this.location !== unparentedLocation) {
156
- throw new UsageError("A node may not be inserted if it's already in a tree");
191
+ throw new UsageError("A node may not be in more than one place in the tree");
157
192
  }
158
193
  let unhydratedNode: UnhydratedFlexTreeNode | undefined = parent.parent;
159
194
  while (unhydratedNode !== undefined) {
@@ -188,78 +223,35 @@ export class UnhydratedFlexTreeNode implements FlexTreeNode {
188
223
  }
189
224
 
190
225
  public borrowCursor(): ITreeCursorSynchronous {
191
- return cursorForMapTreeNode(this.mapTree);
226
+ return cursorForMapTreeNode<MapTreeNodeViewGeneric<UnhydratedFlexTreeNode>>(this);
192
227
  }
193
228
 
194
229
  public tryGetField(key: FieldKey): UnhydratedFlexTreeField | undefined {
195
- const field = this.mapTree.fields.get(key);
230
+ const field = this.fieldsAll.get(key);
196
231
  // Only return the field if it is not empty, in order to fulfill the contract of `tryGetField`.
197
232
  if (field !== undefined && field.length > 0) {
198
- return getOrCreateField(this, key, this.storedSchema.getFieldSchema(key).kind, () =>
199
- this.emitChangedEvent(key),
200
- );
233
+ return field;
201
234
  }
202
235
  }
203
236
 
204
- public getBoxed(key: string): FlexTreeField {
237
+ public getBoxed(key: string): UnhydratedFlexTreeField {
205
238
  const fieldKey: FieldKey = brand(key);
206
- return getOrCreateField(
207
- this,
208
- fieldKey,
209
- this.storedSchema.getFieldSchema(fieldKey).kind,
210
- () => this.emitChangedEvent(fieldKey),
211
- );
239
+ return this.getOrCreateField(fieldKey);
212
240
  }
213
241
 
214
242
  public boxedIterator(): IterableIterator<FlexTreeField> {
215
- return mapIterable(this.mapTree.fields.entries(), ([key]) =>
216
- getOrCreateField(this, key, this.storedSchema.getFieldSchema(key).kind, () =>
217
- this.emitChangedEvent(key),
218
- ),
219
- );
243
+ return Array.from(this.fields, ([key, field]) => field)[Symbol.iterator]();
220
244
  }
221
245
 
222
246
  public keys(): IterableIterator<FieldKey> {
223
- // TODO: how this should handle missing defaults (and empty keys if they end up being allowed) needs to be determined.
224
- return this.mapTree.fields.keys();
247
+ return Array.from(this.fields, ([key]) => key)[Symbol.iterator]();
225
248
  }
226
249
 
227
250
  public get value(): Value {
228
- return this.mapTree.value;
229
- }
230
-
231
- public get anchorNode(): AnchorNode {
232
- // This API is relevant to `LazyTreeNode`s, but not `UnhydratedFlexTreeNode`s.
233
- // TODO: Refactor the FlexTreeNode interface so that stubbing this out isn't necessary.
234
- return fail(0xb47 /* UnhydratedFlexTreeNode does not implement anchorNode */);
235
- }
236
-
237
- private walkTree(): void {
238
- for (const [key, mapTrees] of this.mapTree.fields) {
239
- const field = getOrCreateField(
240
- this,
241
- key,
242
- this.storedSchema.getFieldSchema(key).kind,
243
- () => this.emitChangedEvent(key),
244
- );
245
- for (let index = 0; index < field.length; index++) {
246
- const child = getOrCreateChild(this.simpleContext, mapTrees[index] ?? oob(), {
247
- parent: field,
248
- index,
249
- });
250
- // These next asserts detect the case where `getOrCreateChild` gets a cache hit of a different node than the one we're trying to create
251
- assert(child.location !== undefined, 0x98d /* Expected node to have parent */);
252
- assert(
253
- child.location.parent.parent === this,
254
- 0x98e /* Node may not be multi-parented */,
255
- );
256
- assert(child.location.index === index, 0x98f /* Node may not be multi-parented */);
257
- child.walkTree();
258
- }
259
- }
251
+ return this.data.value;
260
252
  }
261
253
 
262
- private emitChangedEvent(key: FieldKey): void {
254
+ public emitChangedEvent(key: FieldKey): void {
263
255
  this._events.emit("childrenChangedAfterBatch", { changedFields: new Set([key]) });
264
256
  }
265
257
  }
@@ -323,59 +315,82 @@ const unparentedLocation: LocationInField = {
323
315
  index: -1,
324
316
  };
325
317
 
326
- class UnhydratedFlexTreeField implements FlexTreeField {
318
+ /**
319
+ * The {@link Unhydrated} implementation of {@link FlexTreeField}.
320
+ */
321
+ export class UnhydratedFlexTreeField
322
+ implements FlexTreeField, MapTreeFieldViewGeneric<UnhydratedFlexTreeNode>
323
+ {
327
324
  public [flexTreeMarker] = FlexTreeEntityKind.Field as const;
328
325
 
329
- public get context(): FlexTreeContext {
330
- return this.simpleContext.flexContext;
331
- }
326
+ public parent: UnhydratedFlexTreeNode | undefined = undefined;
332
327
 
333
328
  public constructor(
334
- public readonly simpleContext: Context,
329
+ public readonly context: FlexTreeContext,
335
330
  public readonly schema: FieldKindIdentifier,
336
331
  public readonly key: FieldKey,
337
- public readonly parent: UnhydratedFlexTreeNode,
338
- public readonly onEdit?: () => void,
332
+ /**
333
+ * The children of this field.
334
+ * @remarks
335
+ * This is either an array of {@link UnhydratedFlexTreeNode}s or a {@link ContextualFieldProvider} that will be used to populate the children lazily (after which it will become an array).
336
+ * See {@link fillPendingDefaults}.
337
+ * Note that any fields using a {@link ConstantFieldProvider} should be evaluated before constructing the UnhydratedFlexTreeField.
338
+ */
339
+ private lazyChildren: UnhydratedFlexTreeNode[] | ContextualFieldProvider,
339
340
  ) {
340
- const fieldKeyCache = getFieldKeyCache(parent);
341
- assert(!fieldKeyCache.has(key), 0x990 /* A field already exists for the given MapTrees */);
342
- fieldKeyCache.set(key, this);
343
-
344
341
  // When this field is created (which only happens one time, because it is cached), all the children become parented for the first time.
345
342
  // "Adopt" each child by updating its parent information to point to this field.
346
- for (const [i, mapTree] of this.mapTrees.entries()) {
347
- const mapTreeNodeChild = nodeCache.get(mapTree);
348
- if (mapTreeNodeChild !== undefined) {
349
- if (mapTreeNodeChild.parentField !== unparentedLocation) {
350
- throw new UsageError("A node may not be in more than one place in the tree");
351
- }
352
- mapTreeNodeChild.adoptBy(this, i);
343
+ if (Array.isArray(lazyChildren)) {
344
+ for (const [i, child] of lazyChildren.entries()) {
345
+ child.adoptBy(this, i);
353
346
  }
354
347
  }
355
348
  }
356
349
 
357
- public get mapTrees(): readonly ExclusiveMapTree[] {
358
- return this.parent.mapTree.fields.get(this.key) ?? [];
350
+ private getPendingDefault(): ContextualFieldProvider | undefined {
351
+ return !Array.isArray(this.lazyChildren) ? this.lazyChildren : undefined;
352
+ }
353
+
354
+ /**
355
+ * Populate pending default (if present) using the provided context.
356
+ * @remarks
357
+ * This apply to just this field: caller will likely want to recursively walk the tree.
358
+ * @see {@link pendingDefault}.
359
+ */
360
+ public fillPendingDefaults(context: FlexTreeHydratedContextMinimal): void {
361
+ const provider = this.getPendingDefault();
362
+ if (provider) {
363
+ const content = provider(context);
364
+ this.lazyChildren = content;
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Returns true if this field has a pending default due to defined defined using a {@link ContextualFieldProvider}.
370
+ */
371
+ public get pendingDefault(): boolean {
372
+ return this.getPendingDefault() !== undefined;
373
+ }
374
+
375
+ public get children(): UnhydratedFlexTreeNode[] {
376
+ const provider = this.getPendingDefault();
377
+ if (provider) {
378
+ const content = provider("UseGlobalContext");
379
+ this.lazyChildren = content;
380
+ }
381
+ return this.lazyChildren as UnhydratedFlexTreeNode[];
359
382
  }
360
383
 
361
384
  public get length(): number {
362
- return this.mapTrees.length;
385
+ return this.children.length;
363
386
  }
364
387
 
365
388
  public is<TKind2 extends FlexFieldKind>(kind: TKind2): this is FlexTreeTypedField<TKind2> {
366
389
  return this.schema === kind.identifier;
367
390
  }
368
391
 
369
- public boxedIterator(): IterableIterator<FlexTreeNode> {
370
- return this.mapTrees
371
- .map(
372
- (m, index) =>
373
- getOrCreateChild(this.simpleContext, m, {
374
- parent: this,
375
- index,
376
- }) as FlexTreeNode,
377
- )
378
- .values();
392
+ public boxedIterator(): IterableIterator<UnhydratedFlexTreeNode> {
393
+ return this.children[Symbol.iterator]();
379
394
  }
380
395
 
381
396
  public boxedAt(index: number): FlexTreeNode | undefined {
@@ -383,13 +398,12 @@ class UnhydratedFlexTreeField implements FlexTreeField {
383
398
  if (i === undefined) {
384
399
  return undefined;
385
400
  }
386
- const m = this.mapTrees[i];
387
- if (m !== undefined) {
388
- return getOrCreateChild(this.simpleContext, m, {
389
- parent: this,
390
- index: i,
391
- }) as FlexTreeNode;
392
- }
401
+ const m = this.children[i];
402
+ return m;
403
+ }
404
+
405
+ public [Symbol.iterator](): IterableIterator<UnhydratedFlexTreeNode> {
406
+ return this.boxedIterator();
393
407
  }
394
408
 
395
409
  /**
@@ -400,16 +414,22 @@ class UnhydratedFlexTreeField implements FlexTreeField {
400
414
  * @remarks All edits to the field (i.e. mutations of the field's MapTrees) should be directed through this function.
401
415
  * This function ensures that the parent MapTree has no empty fields (which is an invariant of `MapTree`) after the mutation.
402
416
  */
403
- protected edit(edit: (mapTrees: ExclusiveMapTree[]) => void | ExclusiveMapTree[]): void {
404
- const oldMapTrees = this.parent.mapTree.fields.get(this.key) ?? [];
405
- const newMapTrees = edit(oldMapTrees) ?? oldMapTrees;
406
- if (newMapTrees.length > 0) {
407
- this.parent.mapTree.fields.set(this.key, newMapTrees);
408
- } else {
409
- this.parent.mapTree.fields.delete(this.key);
417
+ protected edit(
418
+ edit: (mapTrees: UnhydratedFlexTreeNode[]) => void | UnhydratedFlexTreeNode[],
419
+ ): void {
420
+ // Clear parents for all old map trees.
421
+ for (const tree of this.children) {
422
+ tree.adoptBy(undefined);
410
423
  }
411
424
 
412
- this.onEdit?.();
425
+ this.lazyChildren = edit(this.children) ?? this.children;
426
+
427
+ // Set parents for all new map trees.
428
+ for (const [index, tree] of this.children.entries()) {
429
+ tree.adoptBy(this, index);
430
+ }
431
+
432
+ this.parent?.emitChangedEvent(this.key);
413
433
  }
414
434
 
415
435
  public getFieldPath(): NormalizedFieldUpPath {
@@ -417,31 +437,30 @@ class UnhydratedFlexTreeField implements FlexTreeField {
417
437
  }
418
438
 
419
439
  /** Unboxes leaf nodes to their values */
420
- protected unboxed(index: number): FlexTreeUnknownUnboxed {
421
- const mapTree: ExclusiveMapTree = this.mapTrees[index] ?? oob();
422
- const value = mapTree.value;
440
+ protected unboxed(index: number): TreeValue | UnhydratedFlexTreeNode {
441
+ const child = this.children[index] ?? oob();
442
+ const value = child.value;
423
443
  if (value !== undefined) {
424
444
  return value;
425
445
  }
426
-
427
- return getOrCreateChild(this.simpleContext, mapTree, { parent: this, index });
446
+ return child;
428
447
  }
429
448
  }
430
449
 
431
- class EagerMapTreeOptionalField
450
+ /**
451
+ * The {@link Unhydrated} implementation of {@link FlexTreeOptionalField}.
452
+ */
453
+ export class UnhydratedOptionalField
432
454
  extends UnhydratedFlexTreeField
433
455
  implements FlexTreeOptionalField
434
456
  {
435
457
  public readonly editor = {
436
- set: (newContent: ExclusiveMapTree | undefined): void => {
437
- // If the new content is a UnhydratedFlexTreeNode, it needs to have its parent pointer updated
458
+ set: (newContent: FlexibleNodeContent | undefined): void => {
438
459
  if (newContent !== undefined) {
439
- nodeCache.get(newContent)?.adoptBy(this, 0);
440
- }
441
- // If the old content is a UnhydratedFlexTreeNode, it needs to have its parent pointer unset
442
- const oldContent = this.mapTrees[0];
443
- if (oldContent !== undefined) {
444
- nodeCache.get(oldContent)?.adoptBy(undefined);
460
+ assert(
461
+ newContent instanceof UnhydratedFlexTreeNode,
462
+ 0xbb7 /* Expected unhydrated node */,
463
+ );
445
464
  }
446
465
 
447
466
  this.edit((mapTrees) => {
@@ -452,10 +471,11 @@ class EagerMapTreeOptionalField
452
471
  }
453
472
  });
454
473
  },
455
- };
474
+ } satisfies OptionalFieldEditBuilder<FlexibleNodeContent> &
475
+ ValueFieldEditBuilder<FlexibleNodeContent>;
456
476
 
457
477
  public get content(): FlexTreeUnknownUnboxed | undefined {
458
- const value = this.mapTrees[0];
478
+ const value = this.children[0];
459
479
  if (value !== undefined) {
460
480
  return this.unboxed(0);
461
481
  }
@@ -464,8 +484,8 @@ class EagerMapTreeOptionalField
464
484
  }
465
485
  }
466
486
 
467
- class EagerMapTreeRequiredField
468
- extends EagerMapTreeOptionalField
487
+ class UnhydratedRequiredField
488
+ extends UnhydratedOptionalField
469
489
  implements FlexTreeRequiredField
470
490
  {
471
491
  public override get content(): FlexTreeUnknownUnboxed {
@@ -478,40 +498,42 @@ class EagerMapTreeRequiredField
478
498
  }
479
499
  }
480
500
 
481
- export class UnhydratedTreeSequenceField
501
+ /**
502
+ * The {@link Unhydrated} implementation of {@link FlexTreeSequenceField}.
503
+ */
504
+ export class UnhydratedSequenceField
482
505
  extends UnhydratedFlexTreeField
483
506
  implements FlexTreeSequenceField
484
507
  {
485
- public readonly editor: UnhydratedTreeSequenceFieldEditBuilder = {
508
+ public readonly editor = {
486
509
  insert: (index, newContent): void => {
487
- for (let i = 0; i < newContent.length; i++) {
488
- const c = newContent[i];
510
+ for (const c of newContent) {
489
511
  assert(c !== undefined, 0xa0a /* Unexpected sparse array content */);
490
- nodeCache.get(c)?.adoptBy(this, index + i);
512
+ assert(c instanceof UnhydratedFlexTreeNode, 0xbb8 /* Expected unhydrated node */);
491
513
  }
514
+ const newContentChecked = newContent as readonly UnhydratedFlexTreeNode[];
492
515
  this.edit((mapTrees) => {
493
516
  if (newContent.length < 1000) {
494
517
  // For "smallish arrays" (`1000` is not empirically derived), the `splice` function is appropriate...
495
- mapTrees.splice(index, 0, ...newContent);
518
+ mapTrees.splice(index, 0, ...newContentChecked);
496
519
  } else {
497
520
  // ...but we avoid using `splice` + spread for very large input arrays since there is a limit on how many elements can be spread (too many will overflow the stack).
498
- return mapTrees.slice(0, index).concat(newContent, mapTrees.slice(index));
521
+ return mapTrees.slice(0, index).concat(newContentChecked, mapTrees.slice(index));
499
522
  }
500
523
  });
501
524
  },
502
- remove: (index, count): ExclusiveMapTree[] => {
525
+ remove: (index, count): UnhydratedFlexTreeNode[] => {
503
526
  for (let i = index; i < index + count; i++) {
504
- const c = this.mapTrees[i];
527
+ const c = this.children[i];
505
528
  assert(c !== undefined, 0xa0b /* Unexpected sparse array */);
506
- nodeCache.get(c)?.adoptBy(undefined);
507
529
  }
508
- let removed: ExclusiveMapTree[] | undefined;
530
+ let removed: UnhydratedFlexTreeNode[] | undefined;
509
531
  this.edit((mapTrees) => {
510
532
  removed = mapTrees.splice(index, count);
511
533
  });
512
534
  return removed ?? fail(0xb4a /* Expected removed to be set by edit */);
513
535
  },
514
- };
536
+ } satisfies UnhydratedTreeSequenceFieldEditBuilder;
515
537
 
516
538
  public at(index: number): FlexTreeUnknownUnboxed | undefined {
517
539
  const i = indexForAt(index, this.length);
@@ -523,91 +545,30 @@ export class UnhydratedTreeSequenceField
523
545
  public map<U>(callbackfn: (value: FlexTreeUnknownUnboxed, index: number) => U): U[] {
524
546
  return Array.from(this, callbackfn);
525
547
  }
526
-
527
- public *[Symbol.iterator](): IterableIterator<FlexTreeUnknownUnboxed> {
528
- for (const [i] of this.mapTrees.entries()) {
529
- yield this.unboxed(i);
530
- }
531
- }
532
548
  }
533
549
 
534
550
  // #endregion Fields
535
551
 
536
- // #region Caching and unboxing utilities
537
-
538
- const nodeCache = new WeakMap<MapTree, UnhydratedFlexTreeNode>();
539
- /** Node Parent -\> Field Key -\> Field */
540
- const fieldCache = new WeakMap<
541
- UnhydratedFlexTreeNode,
542
- Map<FieldKey, UnhydratedFlexTreeField>
543
- >();
544
- function getFieldKeyCache(
545
- parent: UnhydratedFlexTreeNode,
546
- ): WeakMap<FieldKey, UnhydratedFlexTreeField> {
547
- return getOrCreate(fieldCache, parent, () => new Map());
548
- }
549
-
550
- /**
551
- * If there exists a {@link UnhydratedFlexTreeNode} for the given {@link MapTree}, returns it, otherwise returns `undefined`.
552
- * @remarks {@link UnhydratedFlexTreeNode | UnhydratedFlexTreeNodes} are created via {@link getOrCreateNodeFromInnerNode}.
553
- */
554
- export function tryUnhydratedFlexTreeNode(
555
- mapTree: MapTree,
556
- ): UnhydratedFlexTreeNode | undefined {
557
- return nodeCache.get(mapTree);
558
- }
559
-
560
- /** Helper for creating a `UnhydratedFlexTreeNode` given the parent field (e.g. when "walking down") */
561
- function getOrCreateChild(
562
- context: Context,
563
- mapTree: ExclusiveMapTree,
564
- parent: LocationInField | undefined,
565
- ): UnhydratedFlexTreeNode {
566
- const cached = nodeCache.get(mapTree);
567
- if (cached !== undefined) {
568
- return cached;
569
- }
570
-
571
- return new UnhydratedFlexTreeNode(context, mapTree, parent);
572
- }
573
-
574
- /** Creates a field with the given attributes, or returns a cached field if there is one */
575
- function getOrCreateField(
576
- parent: UnhydratedFlexTreeNode,
577
- key: FieldKey,
578
- schema: FieldKindIdentifier,
579
- onEdit?: () => void,
552
+ /** Creates a field with the given attributes */
553
+ export function createField(
554
+ ...args: ConstructorParameters<typeof UnhydratedFlexTreeField>
580
555
  ): UnhydratedFlexTreeField {
581
- const cached = getFieldKeyCache(parent).get(key);
582
- if (cached !== undefined) {
583
- return cached;
584
- }
585
-
586
- if (
587
- schema === FieldKinds.required.identifier ||
588
- schema === FieldKinds.identifier.identifier
589
- ) {
590
- return new EagerMapTreeRequiredField(parent.simpleContext, schema, key, parent, onEdit);
591
- }
592
-
593
- if (schema === FieldKinds.optional.identifier) {
594
- return new EagerMapTreeOptionalField(parent.simpleContext, schema, key, parent, onEdit);
556
+ switch (args[1]) {
557
+ case FieldKinds.required.identifier:
558
+ case FieldKinds.identifier.identifier:
559
+ return new UnhydratedRequiredField(...args);
560
+ case FieldKinds.optional.identifier:
561
+ return new UnhydratedOptionalField(...args);
562
+ case FieldKinds.sequence.identifier:
563
+ return new UnhydratedSequenceField(...args);
564
+ case FieldKinds.forbidden.identifier:
565
+ // TODO: this seems to used by unknown optional fields. They should probably use "optional" not "Forbidden" schema.
566
+ return new UnhydratedFlexTreeField(...args);
567
+ default:
568
+ return fail(0xb9d /* unsupported field kind */);
595
569
  }
596
-
597
- if (schema === FieldKinds.sequence.identifier) {
598
- return new UnhydratedTreeSequenceField(parent.simpleContext, schema, key, parent, onEdit);
599
- }
600
-
601
- // TODO: this seems to used by unknown optional fields. They should probably use "optional" not "Forbidden" schema.
602
- if (schema === FieldKinds.forbidden.identifier) {
603
- return new UnhydratedFlexTreeField(parent.simpleContext, schema, key, parent, onEdit);
604
- }
605
-
606
- return fail(0xb9d /* unsupported field kind */);
607
570
  }
608
571
 
609
- // #endregion Caching and unboxing utilities
610
-
611
572
  export function unsupportedUsageError(message?: string): Error {
612
573
  return new UsageError(
613
574
  `${