@fluidframework/tree 2.1.0-276326 → 2.1.0-281041

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 (442) hide show
  1. package/.eslintrc.cjs +7 -0
  2. package/.vscode/Tree.code-workspace +7 -1
  3. package/README.md +134 -29
  4. package/api-report/tree.alpha.api.md +1 -0
  5. package/api-report/tree.beta.api.md +1 -0
  6. package/api-report/tree.public.api.md +1 -0
  7. package/beta.d.ts +1 -1
  8. package/dist/beta.d.ts +1 -1
  9. package/dist/core/forest/editableForest.d.ts +6 -3
  10. package/dist/core/forest/editableForest.d.ts.map +1 -1
  11. package/dist/core/forest/editableForest.js +14 -4
  12. package/dist/core/forest/editableForest.js.map +1 -1
  13. package/dist/core/index.d.ts +1 -1
  14. package/dist/core/index.d.ts.map +1 -1
  15. package/dist/core/index.js +3 -1
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/core/rebase/index.d.ts +1 -1
  18. package/dist/core/rebase/index.d.ts.map +1 -1
  19. package/dist/core/rebase/index.js +3 -1
  20. package/dist/core/rebase/index.js.map +1 -1
  21. package/dist/core/rebase/types.d.ts +2 -0
  22. package/dist/core/rebase/types.d.ts.map +1 -1
  23. package/dist/core/rebase/types.js +9 -1
  24. package/dist/core/rebase/types.js.map +1 -1
  25. package/dist/core/tree/visitDelta.d.ts.map +1 -1
  26. package/dist/core/tree/visitDelta.js.map +1 -1
  27. package/dist/events/events.d.ts +4 -1
  28. package/dist/events/events.d.ts.map +1 -1
  29. package/dist/events/events.js.map +1 -1
  30. package/dist/feature-libraries/default-schema/defaultEditBuilder.js +1 -1
  31. package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  32. package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  33. package/dist/feature-libraries/default-schema/defaultFieldKinds.js +1 -0
  34. package/dist/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  35. package/dist/feature-libraries/flex-map-tree/mapTreeNode.d.ts +0 -2
  36. package/dist/feature-libraries/flex-map-tree/mapTreeNode.d.ts.map +1 -1
  37. package/dist/feature-libraries/flex-map-tree/mapTreeNode.js +0 -20
  38. package/dist/feature-libraries/flex-map-tree/mapTreeNode.js.map +1 -1
  39. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +0 -38
  40. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  41. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  42. package/dist/feature-libraries/flex-tree/index.d.ts +1 -1
  43. package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
  44. package/dist/feature-libraries/flex-tree/index.js.map +1 -1
  45. package/dist/feature-libraries/flex-tree/lazyField.d.ts +0 -4
  46. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  47. package/dist/feature-libraries/flex-tree/lazyField.js +1 -14
  48. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  49. package/dist/feature-libraries/flex-tree/lazyNode.d.ts +0 -1
  50. package/dist/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  51. package/dist/feature-libraries/flex-tree/lazyNode.js +0 -3
  52. package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  53. package/dist/feature-libraries/index.d.ts +3 -3
  54. package/dist/feature-libraries/index.d.ts.map +1 -1
  55. package/dist/feature-libraries/index.js +2 -2
  56. package/dist/feature-libraries/index.js.map +1 -1
  57. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +11 -0
  58. package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  59. package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  60. package/dist/feature-libraries/modular-schema/discrepancies.d.ts +96 -0
  61. package/dist/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -0
  62. package/dist/feature-libraries/modular-schema/discrepancies.js +264 -0
  63. package/dist/feature-libraries/modular-schema/discrepancies.js.map +1 -0
  64. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +9 -2
  65. package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  66. package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  67. package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  68. package/dist/feature-libraries/modular-schema/genericFieldKind.js +3 -0
  69. package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  70. package/dist/feature-libraries/modular-schema/index.d.ts +2 -1
  71. package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
  72. package/dist/feature-libraries/modular-schema/index.js +3 -1
  73. package/dist/feature-libraries/modular-schema/index.js.map +1 -1
  74. package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  75. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +42 -26
  76. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  77. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +51 -2
  78. package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  79. package/dist/feature-libraries/modular-schema/modularChangeFamily.js +830 -245
  80. package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  81. package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
  82. package/dist/feature-libraries/modular-schema/modularChangeFormat.js +2 -0
  83. package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
  84. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +44 -1
  85. package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  86. package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  87. package/dist/feature-libraries/node-key/index.d.ts +0 -1
  88. package/dist/feature-libraries/node-key/index.d.ts.map +1 -1
  89. package/dist/feature-libraries/node-key/index.js +1 -3
  90. package/dist/feature-libraries/node-key/index.js.map +1 -1
  91. package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  92. package/dist/feature-libraries/optional-field/optionalField.js +1 -0
  93. package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
  94. package/dist/feature-libraries/sequence-field/index.d.ts +1 -1
  95. package/dist/feature-libraries/sequence-field/index.d.ts.map +1 -1
  96. package/dist/feature-libraries/sequence-field/index.js +1 -2
  97. package/dist/feature-libraries/sequence-field/index.js.map +1 -1
  98. package/dist/feature-libraries/sequence-field/invert.js +1 -1
  99. package/dist/feature-libraries/sequence-field/invert.js.map +1 -1
  100. package/dist/feature-libraries/sequence-field/rebase.js +6 -1
  101. package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
  102. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  103. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +1 -0
  104. package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  105. package/dist/feature-libraries/sequence-field/utils.d.ts +2 -17
  106. package/dist/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  107. package/dist/feature-libraries/sequence-field/utils.js +31 -39
  108. package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
  109. package/dist/feature-libraries/typed-schema/typedTreeSchema.d.ts +1 -0
  110. package/dist/feature-libraries/typed-schema/typedTreeSchema.d.ts.map +1 -1
  111. package/dist/feature-libraries/typed-schema/typedTreeSchema.js +2 -0
  112. package/dist/feature-libraries/typed-schema/typedTreeSchema.js.map +1 -1
  113. package/dist/index.d.ts +1 -1
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js.map +1 -1
  116. package/dist/packageVersion.d.ts +1 -1
  117. package/dist/packageVersion.js +1 -1
  118. package/dist/packageVersion.js.map +1 -1
  119. package/dist/public.d.ts +1 -1
  120. package/dist/shared-tree/schematizingTreeView.d.ts +4 -2
  121. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  122. package/dist/shared-tree/schematizingTreeView.js +240 -184
  123. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  124. package/dist/shared-tree/sharedTree.d.ts +3 -2
  125. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  126. package/dist/shared-tree/sharedTree.js +150 -90
  127. package/dist/shared-tree/sharedTree.js.map +1 -1
  128. package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
  129. package/dist/shared-tree/treeCheckout.js +2 -1
  130. package/dist/shared-tree/treeCheckout.js.map +1 -1
  131. package/dist/shared-tree-core/branch.d.ts.map +1 -1
  132. package/dist/shared-tree-core/branch.js +1 -0
  133. package/dist/shared-tree-core/branch.js.map +1 -1
  134. package/dist/shared-tree-core/sharedTreeCore.d.ts +4 -6
  135. package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  136. package/dist/shared-tree-core/sharedTreeCore.js +265 -209
  137. package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
  138. package/dist/simple-tree/arrayNode.d.ts +4 -0
  139. package/dist/simple-tree/arrayNode.d.ts.map +1 -1
  140. package/dist/simple-tree/arrayNode.js +36 -19
  141. package/dist/simple-tree/arrayNode.js.map +1 -1
  142. package/dist/simple-tree/leafNodeSchema.d.ts +22 -1
  143. package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
  144. package/dist/simple-tree/leafNodeSchema.js +2 -1
  145. package/dist/simple-tree/leafNodeSchema.js.map +1 -1
  146. package/dist/simple-tree/mapNode.d.ts.map +1 -1
  147. package/dist/simple-tree/mapNode.js.map +1 -1
  148. package/dist/simple-tree/objectNode.d.ts.map +1 -1
  149. package/dist/simple-tree/objectNode.js +2 -1
  150. package/dist/simple-tree/objectNode.js.map +1 -1
  151. package/dist/simple-tree/proxies.d.ts.map +1 -1
  152. package/dist/simple-tree/proxies.js +2 -4
  153. package/dist/simple-tree/proxies.js.map +1 -1
  154. package/dist/simple-tree/schemaFactory.d.ts +24 -1
  155. package/dist/simple-tree/schemaFactory.d.ts.map +1 -1
  156. package/dist/simple-tree/schemaFactory.js +40 -4
  157. package/dist/simple-tree/schemaFactory.js.map +1 -1
  158. package/dist/simple-tree/schemaTypes.d.ts +36 -1
  159. package/dist/simple-tree/schemaTypes.d.ts.map +1 -1
  160. package/dist/simple-tree/schemaTypes.js.map +1 -1
  161. package/dist/simple-tree/toFlexSchema.d.ts +2 -2
  162. package/dist/simple-tree/toFlexSchema.d.ts.map +1 -1
  163. package/dist/simple-tree/toFlexSchema.js +3 -2
  164. package/dist/simple-tree/toFlexSchema.js.map +1 -1
  165. package/dist/simple-tree/tree.d.ts +4 -1
  166. package/dist/simple-tree/tree.d.ts.map +1 -1
  167. package/dist/simple-tree/tree.js +48 -1
  168. package/dist/simple-tree/tree.js.map +1 -1
  169. package/dist/simple-tree/treeNodeApi.d.ts.map +1 -1
  170. package/dist/simple-tree/treeNodeApi.js +10 -10
  171. package/dist/simple-tree/treeNodeApi.js.map +1 -1
  172. package/dist/simple-tree/types.d.ts +22 -3
  173. package/dist/simple-tree/types.d.ts.map +1 -1
  174. package/dist/simple-tree/types.js +32 -21
  175. package/dist/simple-tree/types.js.map +1 -1
  176. package/dist/util/breakable.d.ts +83 -0
  177. package/dist/util/breakable.d.ts.map +1 -0
  178. package/dist/util/breakable.js +178 -0
  179. package/dist/util/breakable.js.map +1 -0
  180. package/dist/util/index.d.ts +3 -2
  181. package/dist/util/index.d.ts.map +1 -1
  182. package/dist/util/index.js +9 -2
  183. package/dist/util/index.js.map +1 -1
  184. package/dist/util/nestedMap.d.ts +23 -3
  185. package/dist/util/nestedMap.d.ts.map +1 -1
  186. package/dist/util/nestedMap.js +38 -7
  187. package/dist/util/nestedMap.js.map +1 -1
  188. package/dist/util/utils.d.ts +7 -0
  189. package/dist/util/utils.d.ts.map +1 -1
  190. package/dist/util/utils.js +15 -1
  191. package/dist/util/utils.js.map +1 -1
  192. package/docs/README.md +1 -1
  193. package/docs/main/compatibility.md +1 -1
  194. package/docs/main/stored-and-view-schema.md +1 -1
  195. package/internal.d.ts +1 -1
  196. package/lib/beta.d.ts +1 -1
  197. package/lib/core/forest/editableForest.d.ts +6 -3
  198. package/lib/core/forest/editableForest.d.ts.map +1 -1
  199. package/lib/core/forest/editableForest.js +15 -5
  200. package/lib/core/forest/editableForest.js.map +1 -1
  201. package/lib/core/index.d.ts +1 -1
  202. package/lib/core/index.d.ts.map +1 -1
  203. package/lib/core/index.js +1 -1
  204. package/lib/core/index.js.map +1 -1
  205. package/lib/core/rebase/index.d.ts +1 -1
  206. package/lib/core/rebase/index.d.ts.map +1 -1
  207. package/lib/core/rebase/index.js +1 -1
  208. package/lib/core/rebase/index.js.map +1 -1
  209. package/lib/core/rebase/types.d.ts +2 -0
  210. package/lib/core/rebase/types.d.ts.map +1 -1
  211. package/lib/core/rebase/types.js +7 -1
  212. package/lib/core/rebase/types.js.map +1 -1
  213. package/lib/core/tree/visitDelta.d.ts.map +1 -1
  214. package/lib/core/tree/visitDelta.js.map +1 -1
  215. package/lib/events/events.d.ts +4 -1
  216. package/lib/events/events.d.ts.map +1 -1
  217. package/lib/events/events.js.map +1 -1
  218. package/lib/feature-libraries/default-schema/defaultEditBuilder.js +1 -1
  219. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  220. package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
  221. package/lib/feature-libraries/default-schema/defaultFieldKinds.js +1 -0
  222. package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
  223. package/lib/feature-libraries/flex-map-tree/mapTreeNode.d.ts +0 -2
  224. package/lib/feature-libraries/flex-map-tree/mapTreeNode.d.ts.map +1 -1
  225. package/lib/feature-libraries/flex-map-tree/mapTreeNode.js +0 -20
  226. package/lib/feature-libraries/flex-map-tree/mapTreeNode.js.map +1 -1
  227. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +0 -38
  228. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  229. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  230. package/lib/feature-libraries/flex-tree/index.d.ts +1 -1
  231. package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
  232. package/lib/feature-libraries/flex-tree/index.js.map +1 -1
  233. package/lib/feature-libraries/flex-tree/lazyField.d.ts +0 -4
  234. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  235. package/lib/feature-libraries/flex-tree/lazyField.js +1 -14
  236. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  237. package/lib/feature-libraries/flex-tree/lazyNode.d.ts +0 -1
  238. package/lib/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  239. package/lib/feature-libraries/flex-tree/lazyNode.js +0 -3
  240. package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  241. package/lib/feature-libraries/index.d.ts +3 -3
  242. package/lib/feature-libraries/index.d.ts.map +1 -1
  243. package/lib/feature-libraries/index.js +2 -2
  244. package/lib/feature-libraries/index.js.map +1 -1
  245. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +11 -0
  246. package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
  247. package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
  248. package/lib/feature-libraries/modular-schema/discrepancies.d.ts +96 -0
  249. package/lib/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -0
  250. package/lib/feature-libraries/modular-schema/discrepancies.js +260 -0
  251. package/lib/feature-libraries/modular-schema/discrepancies.js.map +1 -0
  252. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +9 -2
  253. package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
  254. package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
  255. package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
  256. package/lib/feature-libraries/modular-schema/genericFieldKind.js +3 -0
  257. package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
  258. package/lib/feature-libraries/modular-schema/index.d.ts +2 -1
  259. package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
  260. package/lib/feature-libraries/modular-schema/index.js +1 -0
  261. package/lib/feature-libraries/modular-schema/index.js.map +1 -1
  262. package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
  263. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +42 -26
  264. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  265. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +51 -2
  266. package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
  267. package/lib/feature-libraries/modular-schema/modularChangeFamily.js +829 -247
  268. package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
  269. package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
  270. package/lib/feature-libraries/modular-schema/modularChangeFormat.js +2 -0
  271. package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
  272. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +44 -1
  273. package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
  274. package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
  275. package/lib/feature-libraries/node-key/index.d.ts +0 -1
  276. package/lib/feature-libraries/node-key/index.d.ts.map +1 -1
  277. package/lib/feature-libraries/node-key/index.js +0 -1
  278. package/lib/feature-libraries/node-key/index.js.map +1 -1
  279. package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
  280. package/lib/feature-libraries/optional-field/optionalField.js +1 -0
  281. package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
  282. package/lib/feature-libraries/sequence-field/index.d.ts +1 -1
  283. package/lib/feature-libraries/sequence-field/index.d.ts.map +1 -1
  284. package/lib/feature-libraries/sequence-field/index.js +1 -1
  285. package/lib/feature-libraries/sequence-field/index.js.map +1 -1
  286. package/lib/feature-libraries/sequence-field/invert.js +1 -1
  287. package/lib/feature-libraries/sequence-field/invert.js.map +1 -1
  288. package/lib/feature-libraries/sequence-field/rebase.js +6 -1
  289. package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
  290. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
  291. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +2 -1
  292. package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
  293. package/lib/feature-libraries/sequence-field/utils.d.ts +2 -17
  294. package/lib/feature-libraries/sequence-field/utils.d.ts.map +1 -1
  295. package/lib/feature-libraries/sequence-field/utils.js +31 -39
  296. package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
  297. package/lib/feature-libraries/typed-schema/typedTreeSchema.d.ts +1 -0
  298. package/lib/feature-libraries/typed-schema/typedTreeSchema.d.ts.map +1 -1
  299. package/lib/feature-libraries/typed-schema/typedTreeSchema.js +4 -2
  300. package/lib/feature-libraries/typed-schema/typedTreeSchema.js.map +1 -1
  301. package/lib/index.d.ts +1 -1
  302. package/lib/index.d.ts.map +1 -1
  303. package/lib/index.js.map +1 -1
  304. package/lib/packageVersion.d.ts +1 -1
  305. package/lib/packageVersion.js +1 -1
  306. package/lib/packageVersion.js.map +1 -1
  307. package/lib/public.d.ts +1 -1
  308. package/lib/shared-tree/schematizingTreeView.d.ts +4 -2
  309. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  310. package/lib/shared-tree/schematizingTreeView.js +242 -185
  311. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  312. package/lib/shared-tree/sharedTree.d.ts +3 -2
  313. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  314. package/lib/shared-tree/sharedTree.js +151 -90
  315. package/lib/shared-tree/sharedTree.js.map +1 -1
  316. package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
  317. package/lib/shared-tree/treeCheckout.js +2 -1
  318. package/lib/shared-tree/treeCheckout.js.map +1 -1
  319. package/lib/shared-tree-core/branch.d.ts.map +1 -1
  320. package/lib/shared-tree-core/branch.js +1 -0
  321. package/lib/shared-tree-core/branch.js.map +1 -1
  322. package/lib/shared-tree-core/sharedTreeCore.d.ts +4 -6
  323. package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
  324. package/lib/shared-tree-core/sharedTreeCore.js +267 -210
  325. package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
  326. package/lib/simple-tree/arrayNode.d.ts +4 -0
  327. package/lib/simple-tree/arrayNode.d.ts.map +1 -1
  328. package/lib/simple-tree/arrayNode.js +38 -21
  329. package/lib/simple-tree/arrayNode.js.map +1 -1
  330. package/lib/simple-tree/leafNodeSchema.d.ts +22 -1
  331. package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
  332. package/lib/simple-tree/leafNodeSchema.js +1 -1
  333. package/lib/simple-tree/leafNodeSchema.js.map +1 -1
  334. package/lib/simple-tree/mapNode.d.ts.map +1 -1
  335. package/lib/simple-tree/mapNode.js.map +1 -1
  336. package/lib/simple-tree/objectNode.d.ts.map +1 -1
  337. package/lib/simple-tree/objectNode.js +3 -2
  338. package/lib/simple-tree/objectNode.js.map +1 -1
  339. package/lib/simple-tree/proxies.d.ts.map +1 -1
  340. package/lib/simple-tree/proxies.js +2 -4
  341. package/lib/simple-tree/proxies.js.map +1 -1
  342. package/lib/simple-tree/schemaFactory.d.ts +24 -1
  343. package/lib/simple-tree/schemaFactory.d.ts.map +1 -1
  344. package/lib/simple-tree/schemaFactory.js +38 -3
  345. package/lib/simple-tree/schemaFactory.js.map +1 -1
  346. package/lib/simple-tree/schemaTypes.d.ts +36 -1
  347. package/lib/simple-tree/schemaTypes.d.ts.map +1 -1
  348. package/lib/simple-tree/schemaTypes.js.map +1 -1
  349. package/lib/simple-tree/toFlexSchema.d.ts +2 -2
  350. package/lib/simple-tree/toFlexSchema.d.ts.map +1 -1
  351. package/lib/simple-tree/toFlexSchema.js +3 -2
  352. package/lib/simple-tree/toFlexSchema.js.map +1 -1
  353. package/lib/simple-tree/tree.d.ts +4 -1
  354. package/lib/simple-tree/tree.d.ts.map +1 -1
  355. package/lib/simple-tree/tree.js +44 -0
  356. package/lib/simple-tree/tree.js.map +1 -1
  357. package/lib/simple-tree/treeNodeApi.d.ts.map +1 -1
  358. package/lib/simple-tree/treeNodeApi.js +11 -11
  359. package/lib/simple-tree/treeNodeApi.js.map +1 -1
  360. package/lib/simple-tree/types.d.ts +22 -3
  361. package/lib/simple-tree/types.d.ts.map +1 -1
  362. package/lib/simple-tree/types.js +32 -21
  363. package/lib/simple-tree/types.js.map +1 -1
  364. package/lib/util/breakable.d.ts +83 -0
  365. package/lib/util/breakable.d.ts.map +1 -0
  366. package/lib/util/breakable.js +171 -0
  367. package/lib/util/breakable.js.map +1 -0
  368. package/lib/util/index.d.ts +3 -2
  369. package/lib/util/index.d.ts.map +1 -1
  370. package/lib/util/index.js +3 -2
  371. package/lib/util/index.js.map +1 -1
  372. package/lib/util/nestedMap.d.ts +23 -3
  373. package/lib/util/nestedMap.d.ts.map +1 -1
  374. package/lib/util/nestedMap.js +36 -6
  375. package/lib/util/nestedMap.js.map +1 -1
  376. package/lib/util/utils.d.ts +7 -0
  377. package/lib/util/utils.d.ts.map +1 -1
  378. package/lib/util/utils.js +13 -0
  379. package/lib/util/utils.js.map +1 -1
  380. package/package.json +29 -27
  381. package/src/core/forest/editableForest.ts +17 -4
  382. package/src/core/index.ts +2 -0
  383. package/src/core/rebase/index.ts +2 -0
  384. package/src/core/rebase/types.ts +17 -0
  385. package/src/core/tree/visitDelta.ts +1 -0
  386. package/src/events/events.ts +4 -2
  387. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +1 -1
  388. package/src/feature-libraries/default-schema/defaultFieldKinds.ts +1 -0
  389. package/src/feature-libraries/flex-map-tree/mapTreeNode.ts +0 -30
  390. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +0 -43
  391. package/src/feature-libraries/flex-tree/index.ts +0 -1
  392. package/src/feature-libraries/flex-tree/lazyField.ts +1 -21
  393. package/src/feature-libraries/flex-tree/lazyNode.ts +0 -6
  394. package/src/feature-libraries/index.ts +1 -2
  395. package/src/feature-libraries/modular-schema/crossFieldQueries.ts +18 -0
  396. package/src/feature-libraries/modular-schema/discrepancies.ts +395 -0
  397. package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +10 -2
  398. package/src/feature-libraries/modular-schema/genericFieldKind.ts +3 -0
  399. package/src/feature-libraries/modular-schema/index.ts +2 -0
  400. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +81 -35
  401. package/src/feature-libraries/modular-schema/modularChangeFamily.ts +1529 -454
  402. package/src/feature-libraries/modular-schema/modularChangeFormat.ts +2 -0
  403. package/src/feature-libraries/modular-schema/modularChangeTypes.ts +51 -0
  404. package/src/feature-libraries/node-key/index.ts +0 -1
  405. package/src/feature-libraries/optional-field/optionalField.ts +1 -0
  406. package/src/feature-libraries/sequence-field/index.ts +0 -2
  407. package/src/feature-libraries/sequence-field/invert.ts +1 -1
  408. package/src/feature-libraries/sequence-field/rebase.ts +7 -1
  409. package/src/feature-libraries/sequence-field/sequenceFieldChangeHandler.ts +2 -1
  410. package/src/feature-libraries/sequence-field/utils.ts +37 -85
  411. package/src/feature-libraries/typed-schema/typedTreeSchema.ts +10 -0
  412. package/src/index.ts +0 -1
  413. package/src/packageVersion.ts +1 -1
  414. package/src/shared-tree/schematizingTreeView.ts +6 -2
  415. package/src/shared-tree/sharedTree.ts +5 -2
  416. package/src/shared-tree/treeCheckout.ts +6 -2
  417. package/src/shared-tree-core/branch.ts +1 -0
  418. package/src/shared-tree-core/sharedTreeCore.ts +18 -6
  419. package/src/simple-tree/arrayNode.ts +49 -22
  420. package/src/simple-tree/leafNodeSchema.ts +1 -1
  421. package/src/simple-tree/mapNode.ts +2 -2
  422. package/src/simple-tree/objectNode.ts +9 -3
  423. package/src/simple-tree/proxies.ts +2 -4
  424. package/src/simple-tree/schemaFactory.ts +45 -2
  425. package/src/simple-tree/schemaTypes.ts +36 -1
  426. package/src/simple-tree/toFlexSchema.ts +5 -4
  427. package/src/simple-tree/tree.ts +65 -4
  428. package/src/simple-tree/treeNodeApi.ts +15 -15
  429. package/src/simple-tree/types.ts +60 -30
  430. package/src/util/breakable.ts +214 -0
  431. package/src/util/index.ts +10 -0
  432. package/src/util/nestedMap.ts +49 -11
  433. package/src/util/utils.ts +17 -0
  434. package/dist/feature-libraries/node-key/nodeKeyIndex.d.ts +0 -41
  435. package/dist/feature-libraries/node-key/nodeKeyIndex.d.ts.map +0 -1
  436. package/dist/feature-libraries/node-key/nodeKeyIndex.js +0 -101
  437. package/dist/feature-libraries/node-key/nodeKeyIndex.js.map +0 -1
  438. package/lib/feature-libraries/node-key/nodeKeyIndex.d.ts +0 -41
  439. package/lib/feature-libraries/node-key/nodeKeyIndex.d.ts.map +0 -1
  440. package/lib/feature-libraries/node-key/nodeKeyIndex.js +0 -97
  441. package/lib/feature-libraries/node-key/nodeKeyIndex.js.map +0 -1
  442. package/src/feature-libraries/node-key/nodeKeyIndex.ts +0 -132
@@ -19,6 +19,7 @@ import {
19
19
  getOrCreateMapTreeNode,
20
20
  getSchemaAndPolicy,
21
21
  isMapTreeNode,
22
+ isFlexTreeNode,
22
23
  } from "../feature-libraries/index.js";
23
24
  import {
24
25
  type InsertableContent,
@@ -39,7 +40,12 @@ import {
39
40
  normalizeFieldSchema,
40
41
  } from "./schemaTypes.js";
41
42
  import { mapTreeFromNodeData } from "./toMapTree.js";
42
- import { type TreeNode, TreeNodeValid } from "./types.js";
43
+ import {
44
+ type TreeNode,
45
+ TreeNodeValid,
46
+ type InternalTreeNode,
47
+ type MostDerivedData,
48
+ } from "./types.js";
43
49
  import { fail } from "../util/index.js";
44
50
  import { getFlexSchema } from "./toFlexSchema.js";
45
51
  import { UsageError } from "@fluidframework/telemetry-utils/internal";
@@ -215,6 +221,11 @@ export interface TreeArrayNodeBase<out T, in TNew, in TMoveFrom>
215
221
  sourceEnd: number,
216
222
  source: TMoveFrom,
217
223
  ): void;
224
+
225
+ /**
226
+ * Returns a custom IterableIterator which throws usage errors if concurrent editing and iteration occurs.
227
+ */
228
+ values(): IterableIterator<T>;
218
229
  }
219
230
 
220
231
  /**
@@ -315,7 +326,6 @@ const arrayPrototypeKeys = [
315
326
  "some",
316
327
  "toLocaleString",
317
328
  "toString",
318
- "values",
319
329
 
320
330
  // "copyWithin",
321
331
  // "fill",
@@ -489,7 +499,6 @@ declare abstract class NodeWithArrayFeatures<Input, T>
489
499
  ): boolean;
490
500
  toLocaleString(): string;
491
501
  toString(): string;
492
- values(): IterableIterator<T>;
493
502
  }
494
503
  /* eslint-enable @typescript-eslint/explicit-member-accessibility, @typescript-eslint/no-explicit-any */
495
504
 
@@ -554,16 +563,8 @@ function createArrayNodeProxy(
554
563
  return Reflect.get(dispatchTarget, key, receiver) as unknown;
555
564
  }
556
565
 
557
- const value = field.boxedAt(maybeIndex);
558
-
559
- if (value === undefined) {
560
- return undefined;
561
- }
562
-
563
- // TODO: Ideally, we would return leaves without first boxing them. However, this is not
564
- // as simple as calling '.content' since this skips the node and returns the FieldNode's
565
- // inner field.
566
- return getOrCreateNodeProxy(value);
566
+ const maybeContent = field.at(maybeIndex);
567
+ return isFlexTreeNode(maybeContent) ? getOrCreateNodeProxy(maybeContent) : maybeContent;
567
568
  },
568
569
  set: (target, key, newValue, receiver) => {
569
570
  if (key === "length") {
@@ -590,7 +591,7 @@ function createArrayNodeProxy(
590
591
  "Cannot set indexed properties on array nodes. Use array node mutation APIs to alter the array.",
591
592
  );
592
593
  }
593
- return allowAdditionalProperties ? Reflect.set(target, key, newValue) : false;
594
+ return allowAdditionalProperties ? Reflect.set(target, key, newValue, receiver) : false;
594
595
  },
595
596
  has: (target, key) => {
596
597
  const field = getSequenceField(proxy);
@@ -672,6 +673,21 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
672
673
 
673
674
  protected abstract get simpleSchema(): T;
674
675
 
676
+ /**
677
+ * Generation number which is incremented any time we have an edit on the node.
678
+ * Used during iteration to make sure there has been no edits that were concurrently made.
679
+ */
680
+ #generationNumber: number = 0;
681
+
682
+ public constructor(
683
+ input: Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>> | InternalTreeNode,
684
+ ) {
685
+ super(input);
686
+ getFlexNode(this).on("nodeChanged", () => {
687
+ this.#generationNumber += 1;
688
+ });
689
+ }
690
+
675
691
  #cursorFromFieldData(value: Insertable<T>): ITreeCursorSynchronous {
676
692
  if (isMapTreeNode(getFlexNode(this))) {
677
693
  throw new UsageError(`An array cannot be mutated before being inserted into the tree`);
@@ -827,13 +843,7 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
827
843
  const destinationField = getSequenceField(this);
828
844
  validateIndex(destinationIndex, destinationField, "moveRangeToIndex", true);
829
845
  validateIndexRange(sourceStart, sourceEnd, source ?? destinationField, "moveRangeToIndex");
830
- const sourceField =
831
- source !== undefined
832
- ? destinationField.isSameAs(getSequenceField(source))
833
- ? destinationField
834
- : getSequenceField(source)
835
- : destinationField;
836
-
846
+ const sourceField = source !== undefined ? getSequenceField(source) : destinationField;
837
847
  // TODO: determine support for move across different sequence types
838
848
  if (destinationField.schema.types !== undefined && sourceField !== destinationField) {
839
849
  for (let i = sourceStart; i < sourceEnd; i++) {
@@ -855,6 +865,23 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
855
865
  destinationIndex,
856
866
  );
857
867
  }
868
+
869
+ public values(): IterableIterator<TreeNodeFromImplicitAllowedTypes<T>> {
870
+ return this.generateValues(this.#generationNumber);
871
+ }
872
+ private *generateValues(
873
+ initialLastUpdatedStamp: number,
874
+ ): Generator<TreeNodeFromImplicitAllowedTypes<T>> {
875
+ if (initialLastUpdatedStamp !== this.#generationNumber) {
876
+ throw new UsageError(`Concurrent editing and iteration is not allowed.`);
877
+ }
878
+ for (let i = 0; i < this.length; i++) {
879
+ yield this.at(i) ?? fail("Index is out of bounds");
880
+ if (initialLastUpdatedStamp !== this.#generationNumber) {
881
+ throw new UsageError(`Concurrent editing and iteration is not allowed.`);
882
+ }
883
+ }
884
+ }
858
885
  }
859
886
 
860
887
  /**
@@ -921,7 +948,7 @@ export function arraySchema<
921
948
  );
922
949
  }
923
950
 
924
- protected static override constructorCached: typeof TreeNodeValid | undefined = undefined;
951
+ protected static override constructorCached: MostDerivedData | undefined = undefined;
925
952
 
926
953
  protected static override oneTimeSetup<T2>(this: typeof TreeNodeValid<T2>): void {
927
954
  flexSchema = getFlexSchema(this as unknown as TreeNodeSchema) as FlexFieldNodeSchema;
@@ -32,7 +32,7 @@ type UnbrandedName<T extends FlexLeafNodeSchema> = T["name"] extends TreeNodeSch
32
32
  * @privateRemarks
33
33
  * This class refers to the underlying flex tree schema in its constructor, so this class can't be included in the package API.
34
34
  */
35
- class LeafNodeSchema<T extends FlexLeafNodeSchema>
35
+ export class LeafNodeSchema<T extends FlexLeafNodeSchema>
36
36
  implements TreeNodeSchemaNonClass<UnbrandedName<T>, NodeKind.Leaf, TreeValue<T["info"]>>
37
37
  {
38
38
  public readonly identifier: UnbrandedName<T>;
@@ -32,7 +32,7 @@ import {
32
32
  typeNameSymbol,
33
33
  } from "./schemaTypes.js";
34
34
  import { mapTreeFromNodeData } from "./toMapTree.js";
35
- import { type TreeNode, TreeNodeValid } from "./types.js";
35
+ import { type MostDerivedData, type TreeNode, TreeNodeValid } from "./types.js";
36
36
  import { getFlexSchema } from "./toFlexSchema.js";
37
37
  import { UsageError } from "@fluidframework/telemetry-utils/internal";
38
38
 
@@ -246,7 +246,7 @@ export function mapSchema<
246
246
  );
247
247
  }
248
248
 
249
- protected static override constructorCached: typeof TreeNodeValid | undefined = undefined;
249
+ protected static override constructorCached: MostDerivedData | undefined = undefined;
250
250
 
251
251
  protected static override oneTimeSetup<T2>(this: typeof TreeNodeValid<T2>): void {
252
252
  flexSchema = getFlexSchema(this as unknown as TreeNodeSchema) as FlexMapNodeSchema;
@@ -44,7 +44,12 @@ import {
44
44
  FieldKind,
45
45
  } from "./schemaTypes.js";
46
46
  import { mapTreeFromNodeData } from "./toMapTree.js";
47
- import { type InternalTreeNode, type TreeNode, TreeNodeValid } from "./types.js";
47
+ import {
48
+ type InternalTreeNode,
49
+ type MostDerivedData,
50
+ type TreeNode,
51
+ TreeNodeValid,
52
+ } from "./types.js";
48
53
  import { type RestrictiveReadonlyRecord, fail, type FlattenKeys } from "../util/index.js";
49
54
  import { getFlexSchema } from "./toFlexSchema.js";
50
55
 
@@ -187,7 +192,8 @@ function createProxyHandler(
187
192
  set(target, viewKey, value: InsertableContent | undefined, proxy) {
188
193
  const fieldInfo = flexKeyMap.get(viewKey);
189
194
  if (fieldInfo === undefined) {
190
- return allowAdditionalProperties ? Reflect.set(target, viewKey, value) : false;
195
+ // Pass the proxy as the receiver here, so that setters on the prototype receive `proxy` as `this`.
196
+ return allowAdditionalProperties ? Reflect.set(target, viewKey, value, proxy) : false;
191
197
  }
192
198
 
193
199
  const flexNode = getFlexNode(proxy);
@@ -359,7 +365,7 @@ export function objectSchema<
359
365
  );
360
366
  }
361
367
 
362
- protected static override constructorCached: typeof TreeNodeValid | undefined = undefined;
368
+ protected static override constructorCached: MostDerivedData | undefined = undefined;
363
369
 
364
370
  protected static override oneTimeSetup<T2>(this: typeof TreeNodeValid<T2>): void {
365
371
  // One time initialization that required knowing the most derived type (from this.constructor) and thus has to be lazy.
@@ -61,10 +61,8 @@ export function getProxyForField(field: FlexTreeField): TreeNode | TreeValue | u
61
61
  FlexFieldSchema<typeof FieldKinds.required | typeof FieldKinds.optional>
62
62
  >,
63
63
  ): TreeNode | TreeValue | undefined {
64
- const maybeUnboxedContent = flexField.content;
65
- return isFlexTreeNode(maybeUnboxedContent)
66
- ? getOrCreateNodeProxy(maybeUnboxedContent)
67
- : maybeUnboxedContent;
64
+ const maybeContent = flexField.content;
65
+ return isFlexTreeNode(maybeContent) ? getOrCreateNodeProxy(maybeContent) : maybeContent;
68
66
  }
69
67
  switch (field.schema.kind) {
70
68
  case FieldKinds.required: {
@@ -8,6 +8,8 @@ import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
8
8
  // which degrades the API-Extractor report quality since API-Extractor can not tell the inline import is the same as the non-inline one.
9
9
  // eslint-disable-next-line unused-imports/no-unused-imports
10
10
  import type { IFluidHandle as _dummyImport } from "@fluidframework/core-interfaces";
11
+ import { UsageError } from "@fluidframework/telemetry-utils/internal";
12
+ import { isFluidHandle } from "@fluidframework/runtime-utils/internal";
11
13
 
12
14
  import type { TreeValue } from "../core/index.js";
13
15
  import { type NodeKeyManager, type Unenforced, isLazy } from "../feature-libraries/index.js";
@@ -20,6 +22,7 @@ import {
20
22
  import {
21
23
  booleanSchema,
22
24
  handleSchema,
25
+ LeafNodeSchema,
23
26
  nullSchema,
24
27
  numberSchema,
25
28
  stringSchema,
@@ -40,7 +43,6 @@ import {
40
43
  getDefaultProvider,
41
44
  } from "./schemaTypes.js";
42
45
  import { type TreeArrayNode, arraySchema } from "./arrayNode.js";
43
- import { isFluidHandle } from "@fluidframework/runtime-utils/internal";
44
46
  import {
45
47
  type InsertableObjectFromSchemaRecord,
46
48
  type TreeObjectNode,
@@ -64,6 +66,7 @@ import type {
64
66
  TreeObjectNodeUnsafe,
65
67
  } from "./typesUnsafe.js";
66
68
  import { createFieldSchemaUnsafe } from "./schemaFactoryRecursive.js";
69
+ import { inPrototypeChain, TreeNodeValid } from "./types.js";
67
70
  /**
68
71
  * Gets the leaf domain schema compatible with a given {@link TreeValue}.
69
72
  */
@@ -161,9 +164,24 @@ export class SchemaFactory<
161
164
  out TScope extends string | undefined = string | undefined,
162
165
  TName extends number | string = string,
163
166
  > {
167
+ /**
168
+ * TODO:
169
+ * If users of this generate the same name because two different schema with the same identifier were used,
170
+ * the second use can get a cache hit, and reference the wrong schema.
171
+ * Such usage should probably return a distinct type or error but currently does not.
172
+ * The use of markSchemaMostDerived in structuralName at least ensure an error in the case where the collision is from two types extending the same schema factor class.
173
+ */
164
174
  private readonly structuralTypes: Map<string, TreeNodeSchema> = new Map();
165
175
 
166
176
  /**
177
+ * Construct a SchemaFactory with a given scope.
178
+ * @remarks
179
+ * There are no restrictions on mixing schema from different schema factories:
180
+ * this is encouraged when a single schema references schema from different libraries.
181
+ * If each library exporting schema picks its own globally unique scope for its SchemaFactory,
182
+ * then all schema an application might depend on, directly or transitively,
183
+ * will end up with a unique fully qualified name which is required to refer to it in persisted data and errors.
184
+ *
167
185
  * @param scope - Prefix appended to the identifiers of all {@link TreeNodeSchema} produced by this builder.
168
186
  * Use of [Reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation) or a UUIDv4 is recommended to avoid collisions.
169
187
  * You may opt out of using a scope by passing `undefined`, but note that this increases the risk of collisions.
@@ -228,7 +246,7 @@ export class SchemaFactory<
228
246
  public readonly handle = handleSchema;
229
247
 
230
248
  /**
231
- * Define a {@link TreeNodeSchema} for a {@link TreeObjectNode}.
249
+ * Define a {@link TreeNodeSchemaClass} for a {@link TreeObjectNode}.
232
250
  *
233
251
  * @param name - Unique identifier for this schema within this factory's scope.
234
252
  * @param fields - Schema for fields of the object node's schema. Defines what children can be placed under each key.
@@ -721,6 +739,7 @@ export function structuralName<const T extends string>(
721
739
  const names = allowedTypes.map((t): string => {
722
740
  // Ensure that lazy types (functions) don't slip through here.
723
741
  assert(!isLazy(t), 0x83d /* invalid type provided */);
742
+ markSchemaMostDerived(t);
724
743
  return t.identifier;
725
744
  });
726
745
  // Ensure name is order independent
@@ -732,3 +751,27 @@ export function structuralName<const T extends string>(
732
751
  }
733
752
  return `${collectionName}<${inner}>`;
734
753
  }
754
+
755
+ /**
756
+ * Indicates that a schema is the "most derived" version which is allowed to be used, see {@link MostDerivedData}.
757
+ * Calling helps with error messages about invalid schema usage (using more than one type from single schema factor produced type,
758
+ * and thus calling this for one than one subclass).
759
+ * @remarks
760
+ * Helper for invoking {@link TreeNodeValid.markMostDerived} for any {@link TreeNodeSchema} if it needed.
761
+ */
762
+ export function markSchemaMostDerived(schema: TreeNodeSchema): void {
763
+ if (schema instanceof LeafNodeSchema) {
764
+ return;
765
+ }
766
+
767
+ if (!inPrototypeChain(schema, TreeNodeValid)) {
768
+ // Use JSON.stringify to quote and escape identifier string.
769
+ throw new UsageError(
770
+ `Schema for ${JSON.stringify(
771
+ schema.identifier,
772
+ )} does not extend a SchemaFactory generated class. This is invalid.`,
773
+ );
774
+ }
775
+
776
+ (schema as typeof TreeNodeValid & TreeNodeSchema).markMostDerived();
777
+ }
@@ -67,6 +67,41 @@ export interface TreeNodeSchemaNonClass<
67
67
  *
68
68
  * Using classes in this way allows introducing a named type and a named value at the same time, helping keep the runtime and compile time information together and easy to refer to un a uniform way.
69
69
  * Additionally, this works around https://github.com/microsoft/TypeScript/issues/55832 which causes similar patterns with less explicit types to infer "any" in the d.ts file.
70
+ *
71
+ * When sub-classing a a `TreeNodeSchemaClass`, some extra rules must be followed:
72
+ *
73
+ * - Only ever use a single class from the schema's class hierarchy within a document and its schema.
74
+ * For example, if using {@link SchemaFactory.object} you can do:
75
+ * ```typescript
76
+ * // Recommended "customizable" object schema pattern.
77
+ * class Good extends schemaFactory.object("A", {
78
+ * exampleField: schemaFactory.number,
79
+ * }) {
80
+ * public exampleCustomMethod(): void {
81
+ * this.exampleField++;
82
+ * }
83
+ * }
84
+ * ```
85
+ * But should avoid:
86
+ * ```typescript
87
+ * // This by itself is ok, and opts into "POJO mode".
88
+ * const base = schemaFactory.object("A", {});
89
+ * // This is a bad pattern since it leaves two classes in scope which derive from the same SchemaFactory defined class.
90
+ * // If both get used, its an error!
91
+ * class Invalid extends base {}
92
+ * ```
93
+ * - Do not modify the constructor input parameter types or values:
94
+ * ```typescript
95
+ * class Invalid extends schemaFactory.object("A", {
96
+ * exampleField: schemaFactory.number,
97
+ * }) {
98
+ * // This Modifies the type of the constructor input.
99
+ * // This is unsupported due to programmatic access to the constructor being used internally.
100
+ * public constructor(a: number) {
101
+ * super({ exampleField: a });
102
+ * }
103
+ * }
104
+ * ```
70
105
  * @sealed @public
71
106
  */
72
107
  export interface TreeNodeSchemaClass<
@@ -81,7 +116,7 @@ export interface TreeNodeSchemaClass<
81
116
  * Constructs an {@link Unhydrated} node with this schema.
82
117
  * @remarks
83
118
  * This constructor is also used internally to construct hydrated nodes with a different parameter type.
84
- * Therefor overriding this constructor is not type-safe and is not supported.
119
+ * Therefore, overriding this constructor with different argument types is not type-safe and is not supported.
85
120
  * @sealed
86
121
  */
87
122
  new (data: TInsertable | InternalTreeNode): Unhydrated<TNode>;
@@ -5,6 +5,7 @@
5
5
 
6
6
  /* eslint-disable import/no-internal-modules */
7
7
  import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
8
+ import { UsageError } from "@fluidframework/telemetry-utils/internal";
8
9
 
9
10
  import type {
10
11
  ITreeCursorSynchronous,
@@ -75,8 +76,8 @@ export function cursorFromUnhydratedRoot(
75
76
  }
76
77
 
77
78
  interface SchemaInfo {
78
- toFlex: () => FlexTreeNodeSchema;
79
- original: TreeNodeSchema;
79
+ readonly toFlex: () => FlexTreeNodeSchema;
80
+ readonly original: TreeNodeSchema;
80
81
  }
81
82
 
82
83
  type SchemaMap = Map<TreeNodeSchemaIdentifier, SchemaInfo>;
@@ -180,8 +181,8 @@ export function convertNodeSchema(
180
181
  const fromMap = schemaMap.get(brand(schema.identifier));
181
182
  if (fromMap !== undefined) {
182
183
  if (fromMap.original !== schema) {
183
- // Use JSON.stringify to quote and escape string.
184
- throw new Error(
184
+ // Use JSON.stringify to quote and escape identifier string.
185
+ throw new UsageError(
185
186
  `Multiple schema encountered with the identifier ${JSON.stringify(
186
187
  schema.identifier,
187
188
  )}. Remove or rename them to avoid the collision.`,
@@ -9,11 +9,20 @@ import type { CommitMetadata } from "../core/index.js";
9
9
  import type { Listenable } from "../events/index.js";
10
10
  import type { RevertibleFactory } from "../shared-tree/index.js";
11
11
 
12
- import type {
13
- ImplicitFieldSchema,
14
- InsertableTreeFieldFromImplicitField,
15
- TreeFieldFromImplicitField,
12
+ import {
13
+ type ImplicitAllowedTypes,
14
+ NodeKind,
15
+ normalizeFieldSchema,
16
+ type ImplicitFieldSchema,
17
+ type InsertableTreeFieldFromImplicitField,
18
+ type TreeFieldFromImplicitField,
19
+ type TreeNodeSchema,
16
20
  } from "./schemaTypes.js";
21
+ import { toFlexSchema } from "./toFlexSchema.js";
22
+ import { LeafNodeSchema } from "./leafNodeSchema.js";
23
+ import { assert } from "@fluidframework/core-utils/internal";
24
+ import { isObjectNodeSchema } from "./objectNode.js";
25
+ import { markSchemaMostDerived } from "./schemaFactory.js";
17
26
 
18
27
  /**
19
28
  * Channel for a Fluid Tree DDS.
@@ -130,6 +139,58 @@ export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = Implici
130
139
  const config = { ...defaultTreeConfigurationOptions, ...props };
131
140
  this.schema = config.schema;
132
141
  this.enableSchemaValidation = config.enableSchemaValidation;
142
+
143
+ // Ensure all reachable schema are marked as most derived.
144
+ // This ensures if multiple schema extending the same schema factory generated class are present (or have been constructed, or get constructed in the future),
145
+ // an error is reported.
146
+ walkFieldSchema(config.schema, markSchemaMostDerived);
147
+ // Eagerly perform this conversion to surface errors sooner.
148
+ toFlexSchema(config.schema);
149
+ }
150
+ }
151
+
152
+ export function walkNodeSchema(
153
+ schema: TreeNodeSchema,
154
+ visitor: (schema: TreeNodeSchema) => void,
155
+ visitedSet: Set<TreeNodeSchema>,
156
+ ): void {
157
+ if (visitedSet.has(schema)) {
158
+ return;
159
+ }
160
+ visitedSet.add(schema);
161
+ if (schema instanceof LeafNodeSchema) {
162
+ // nothing to do
163
+ } else if (isObjectNodeSchema(schema)) {
164
+ for (const field of schema.fields.values()) {
165
+ walkAllowedTypes(field.allowedTypeSet, visitor, visitedSet);
166
+ }
167
+ } else {
168
+ assert(schema.kind === NodeKind.Array || schema.kind === NodeKind.Map, "invalid schema");
169
+ const childTypes = schema.info as ImplicitAllowedTypes;
170
+ walkFieldSchema(childTypes, visitor, visitedSet);
171
+ }
172
+ // This visit is done at the end so the traversal order is most inner types first.
173
+ // This was picked since when fixing errors,
174
+ // working from the inner types out to the types that use them will probably go better than the reverse.
175
+ // This does not however ensure all types referenced by a type are visited before it, since in recursive cases thats impossible.
176
+ visitor(schema);
177
+ }
178
+
179
+ export function walkFieldSchema(
180
+ schema: ImplicitFieldSchema,
181
+ visitor: (schema: TreeNodeSchema) => void,
182
+ visitedSet: Set<TreeNodeSchema> = new Set(),
183
+ ): void {
184
+ walkAllowedTypes(normalizeFieldSchema(schema).allowedTypeSet, visitor, visitedSet);
185
+ }
186
+
187
+ export function walkAllowedTypes(
188
+ allowedTypes: Iterable<TreeNodeSchema>,
189
+ visitor: (schema: TreeNodeSchema) => void,
190
+ visitedSet: Set<TreeNodeSchema>,
191
+ ): void {
192
+ for (const childType of allowedTypes) {
193
+ walkNodeSchema(childType, visitor, visitedSet);
133
194
  }
134
195
  }
135
196
 
@@ -7,11 +7,11 @@ import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
7
7
 
8
8
  import { Multiplicity, rootFieldKey } from "../core/index.js";
9
9
  import {
10
- FieldKinds,
11
10
  type LazyItem,
12
11
  type TreeStatus,
13
12
  isLazy,
14
13
  isTreeValue,
14
+ FlexObjectNodeSchema,
15
15
  } from "../feature-libraries/index.js";
16
16
  import { fail, extractFromOpaque, isReadonlyArray } from "../util/index.js";
17
17
 
@@ -201,26 +201,26 @@ export const treeNodeApi: TreeNodeApi = {
201
201
  },
202
202
  shortId(node: TreeNode): number | string | undefined {
203
203
  const flexNode = getFlexNode(node);
204
- let shortId: number | string | undefined;
205
- for (const field of flexNode.boxedIterator()) {
206
- if (field.schema.kind === FieldKinds.identifier) {
207
- if (shortId !== undefined) {
208
- throw new UsageError(
209
- "shortId() may not be called on a node with more than one identifier. Consider converting extraneous identifier fields to string fields.",
210
- );
211
- }
212
- const identifier = field.boxedAt(0);
204
+ const flexSchema = flexNode.schema;
205
+ const identifierFieldKeys =
206
+ flexSchema instanceof FlexObjectNodeSchema ? flexSchema.identifierFieldKeys : [];
207
+
208
+ switch (identifierFieldKeys.length) {
209
+ case 0:
210
+ return undefined;
211
+ case 1: {
212
+ const identifier = flexNode.tryGetField(identifierFieldKeys[0])?.boxedAt(0);
213
213
  assert(identifier !== undefined, 0x927 /* The identifier must exist */);
214
214
  const identifierValue = identifier.value as string;
215
215
  const localNodeKey =
216
216
  identifier.context.nodeKeyManager.tryLocalizeNodeKey(identifierValue);
217
-
218
- shortId =
219
- localNodeKey !== undefined ? extractFromOpaque(localNodeKey) : identifierValue;
217
+ return localNodeKey !== undefined ? extractFromOpaque(localNodeKey) : identifierValue;
220
218
  }
219
+ default:
220
+ throw new UsageError(
221
+ "shortId() may not be called on a node with more than one identifier. Consider converting extraneous identifier fields to string fields.",
222
+ );
221
223
  }
222
-
223
- return shortId;
224
224
  },
225
225
  };
226
226
 
@@ -208,51 +208,65 @@ export abstract class TreeNodeValid<TInput> extends TreeNode {
208
208
  * Also used to detect if oneTimeSetup has run.
209
209
  *
210
210
  * @privateRemarks
211
- * This defaults to TreeNodeValid, which is used to trigger an error if not overridden in the derived class.
211
+ * This defaults to "default", which is used to trigger an error if not overridden in the derived class.
212
212
  *
213
213
  * The value of this on TreeNodeValid must only be overridden by base classes and never modified.
214
214
  * Ways to enforce this immutability prevent it from being overridden,
215
215
  * so code modifying constructorCached should be extra careful to avoid accidentally modifying the base/inherited value.
216
216
  */
217
- protected static constructorCached: typeof TreeNodeValid | undefined = TreeNodeValid;
217
+ protected static constructorCached: MostDerivedData | "default" | undefined = "default";
218
+
219
+ /**
220
+ * Indicate that `this` is the most derived version of a schema, and thus the only one allowed to be used (other than by being subclassed a single time).
221
+ */
222
+ public static markMostDerived(this: typeof TreeNodeValid & TreeNodeSchema): MostDerivedData {
223
+ assert(this.constructorCached !== "default", 0x95f /* invalid schema class */);
224
+
225
+ if (this.constructorCached === undefined) {
226
+ // Set the constructorCached on the layer of the prototype chain that declared it.
227
+ // This is necessary to ensure there is only one subclass of that type used:
228
+ // if constructorCached was simply set on `schema`,
229
+ // then a base classes between `schema` (exclusive) and where `constructorCached` is set (inclusive) and other subclasses of them
230
+ // would not see the stored `constructorCached`, and the validation above against multiple derived classes would not work.
231
+
232
+ // This is not just an alias of `this`, but a reference to the item in the prototype chain being walked, which happens to start at `this`.
233
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
234
+ let schemaBase: typeof TreeNodeValid = this;
235
+ while (!Object.prototype.hasOwnProperty.call(schemaBase, "constructorCached")) {
236
+ schemaBase = Reflect.getPrototypeOf(schemaBase) as typeof TreeNodeValid;
237
+ }
238
+ assert(schemaBase.constructorCached === undefined, 0x962 /* overwriting wrong cache */);
239
+ schemaBase.constructorCached = { constructor: this, oneTimeInitialized: false };
240
+ assert(
241
+ this.constructorCached === schemaBase.constructorCached,
242
+ "Inheritance should work",
243
+ );
244
+ return this.constructorCached;
245
+ } else if (this.constructorCached.constructor === this) {
246
+ return this.constructorCached;
247
+ }
248
+
249
+ throw new UsageError(
250
+ `Two schema classes were used (${this.name} and ${
251
+ this.constructorCached.constructor.name
252
+ }) which derived from the same SchemaFactory generated class (${JSON.stringify(
253
+ this.identifier,
254
+ )}). This is invalid.`,
255
+ );
256
+ }
218
257
 
219
258
  public constructor(input: TInput | InternalTreeNode) {
220
259
  super();
221
260
  const schema = this.constructor as typeof TreeNodeValid & TreeNodeSchema;
222
- assert("constructorCached" in schema, 0x95f /* invalid schema class */);
223
- if (schema.constructorCached !== schema) {
224
- if (schema.constructorCached !== undefined) {
225
- assert(
226
- schema.constructorCached !== TreeNodeValid,
227
- 0x960 /* Schema class schema must override static constructorCached member */,
228
- );
229
- throw new UsageError(
230
- `Two schema classes were instantiated (${schema.name} and ${schema.constructorCached.name}) which derived from the same SchemaFactory generated class. This is invalid`,
231
- );
232
- }
233
-
261
+ const cache = schema.markMostDerived();
262
+ if (!cache.oneTimeInitialized) {
234
263
  const flexSchema = getFlexSchema(schema);
235
264
  assert(
236
265
  tryGetSimpleNodeSchema(flexSchema) === schema,
237
266
  0x961 /* Schema class not properly configured */,
238
267
  );
239
268
  schema.oneTimeSetup();
240
- // Set the constructorCached on the layer of the prototype chain that declared it.
241
- // This is necessary to ensure there is only one subclass of that type used:
242
- // if constructorCached was simply set on `schema`,
243
- // then a base classes between `schema` (exclusive) and where `constructorCached` is set (inclusive) and other subclasses of them
244
- // would not see the stored `constructorCached`, and the validation above against multiple derived classes would not work.
245
- {
246
- let schemaBase: typeof TreeNodeValid = schema;
247
- while (!Object.prototype.hasOwnProperty.call(schemaBase, "constructorCached")) {
248
- schemaBase = Reflect.getPrototypeOf(schemaBase) as typeof TreeNodeValid;
249
- }
250
- assert(
251
- schemaBase.constructorCached === undefined,
252
- 0x962 /* overwriting wrong cache */,
253
- );
254
- schemaBase.constructorCached = schema;
255
- }
269
+ cache.oneTimeInitialized = true;
256
270
  }
257
271
 
258
272
  if (isTreeNode(input)) {
@@ -278,6 +292,22 @@ export abstract class TreeNodeValid<TInput> extends TreeNode {
278
292
  // Class objects are functions (callable), so we need a strong way to distinguish between `schema` and `() => schema` when used as a `LazyItem`.
279
293
  markEager(TreeNodeValid);
280
294
 
295
+ /**
296
+ * Data cached about the most derived type in a schema's class hierarchy.
297
+ * @remarks
298
+ * The most derived type is the only one allowed to be referenced by other schema or constructed as a node.
299
+ * It has to be discovered lazily (when a node is constructed or when a {@link TreeViewConfiguration} is made),
300
+ * since JavaScript provides no way to find derived classes, or inject static class initialization time logic into base classes.
301
+ * Additionally since schema can reference other schema through lazy references which might be forward or recursive references,
302
+ * this can not be evaluated for one schema when referenced by another schema.
303
+ *
304
+ * See {@link TreeNodeValid.constructorCached} and {@link TreeNodeValid.markMostDerived}.
305
+ */
306
+ export interface MostDerivedData {
307
+ readonly constructor: typeof TreeNodeValid & TreeNodeSchema;
308
+ oneTimeInitialized: boolean;
309
+ }
310
+
281
311
  /**
282
312
  * A node type internal to `@fluidframework/tree`.
283
313
  * @remarks