@fluidframework/tree 2.43.0-343119 → 2.43.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 (206) hide show
  1. package/CHANGELOG.md +189 -0
  2. package/api-report/tree.alpha.api.md +13 -4
  3. package/api-report/tree.beta.api.md +1 -0
  4. package/api-report/tree.legacy.alpha.api.md +1 -0
  5. package/api-report/tree.legacy.public.api.md +1 -0
  6. package/api-report/tree.public.api.md +1 -0
  7. package/dist/alpha.d.ts +1 -0
  8. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -1
  9. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/packageVersion.d.ts +1 -1
  14. package/dist/packageVersion.d.ts.map +1 -1
  15. package/dist/packageVersion.js +1 -1
  16. package/dist/packageVersion.js.map +1 -1
  17. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  18. package/dist/shared-tree/schematizingTreeView.js +3 -3
  19. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  20. package/dist/shared-tree/treeAlpha.d.ts +38 -0
  21. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  22. package/dist/shared-tree/treeAlpha.js +114 -9
  23. package/dist/shared-tree/treeAlpha.js.map +1 -1
  24. package/dist/simple-tree/api/configuration.d.ts +15 -3
  25. package/dist/simple-tree/api/configuration.d.ts.map +1 -1
  26. package/dist/simple-tree/api/configuration.js +40 -22
  27. package/dist/simple-tree/api/configuration.js.map +1 -1
  28. package/dist/simple-tree/api/index.d.ts +1 -1
  29. package/dist/simple-tree/api/index.d.ts.map +1 -1
  30. package/dist/simple-tree/api/index.js +4 -4
  31. package/dist/simple-tree/api/index.js.map +1 -1
  32. package/dist/simple-tree/api/treeNodeApi.d.ts +3 -0
  33. package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  34. package/dist/simple-tree/api/treeNodeApi.js +1 -1
  35. package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
  36. package/dist/simple-tree/core/context.d.ts +3 -3
  37. package/dist/simple-tree/core/context.d.ts.map +1 -1
  38. package/dist/simple-tree/core/context.js.map +1 -1
  39. package/dist/simple-tree/core/getOrCreateNode.d.ts +9 -0
  40. package/dist/simple-tree/core/getOrCreateNode.d.ts.map +1 -1
  41. package/dist/simple-tree/core/getOrCreateNode.js +12 -1
  42. package/dist/simple-tree/core/getOrCreateNode.js.map +1 -1
  43. package/dist/simple-tree/core/index.d.ts +2 -2
  44. package/dist/simple-tree/core/index.d.ts.map +1 -1
  45. package/dist/simple-tree/core/index.js +3 -1
  46. package/dist/simple-tree/core/index.js.map +1 -1
  47. package/dist/simple-tree/core/treeNodeKernel.js +1 -1
  48. package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
  49. package/dist/simple-tree/core/treeNodeSchema.d.ts +68 -1
  50. package/dist/simple-tree/core/treeNodeSchema.d.ts.map +1 -1
  51. package/dist/simple-tree/core/treeNodeSchema.js +24 -1
  52. package/dist/simple-tree/core/treeNodeSchema.js.map +1 -1
  53. package/dist/simple-tree/core/walkSchema.d.ts +3 -3
  54. package/dist/simple-tree/core/walkSchema.d.ts.map +1 -1
  55. package/dist/simple-tree/core/walkSchema.js +9 -5
  56. package/dist/simple-tree/core/walkSchema.js.map +1 -1
  57. package/dist/simple-tree/createContext.js +1 -1
  58. package/dist/simple-tree/createContext.js.map +1 -1
  59. package/dist/simple-tree/getTreeNodeForField.d.ts +1 -1
  60. package/dist/simple-tree/getTreeNodeForField.d.ts.map +1 -1
  61. package/dist/simple-tree/getTreeNodeForField.js +3 -3
  62. package/dist/simple-tree/getTreeNodeForField.js.map +1 -1
  63. package/dist/simple-tree/index.d.ts +5 -5
  64. package/dist/simple-tree/index.d.ts.map +1 -1
  65. package/dist/simple-tree/index.js +8 -5
  66. package/dist/simple-tree/index.js.map +1 -1
  67. package/dist/simple-tree/leafNodeSchema.d.ts +2 -1
  68. package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
  69. package/dist/simple-tree/leafNodeSchema.js +1 -0
  70. package/dist/simple-tree/leafNodeSchema.js.map +1 -1
  71. package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  72. package/dist/simple-tree/node-kinds/array/arrayNode.js +18 -15
  73. package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  74. package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  75. package/dist/simple-tree/node-kinds/map/mapNode.js +7 -3
  76. package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  77. package/dist/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  78. package/dist/simple-tree/node-kinds/object/objectNode.js +9 -6
  79. package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  80. package/dist/simple-tree/schemaTypes.d.ts +13 -27
  81. package/dist/simple-tree/schemaTypes.d.ts.map +1 -1
  82. package/dist/simple-tree/schemaTypes.js +45 -39
  83. package/dist/simple-tree/schemaTypes.js.map +1 -1
  84. package/dist/simple-tree/toStoredSchema.d.ts +2 -0
  85. package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
  86. package/dist/simple-tree/toStoredSchema.js +2 -0
  87. package/dist/simple-tree/toStoredSchema.js.map +1 -1
  88. package/dist/simple-tree/treeNodeValid.d.ts.map +1 -1
  89. package/dist/simple-tree/treeNodeValid.js +1 -2
  90. package/dist/simple-tree/treeNodeValid.js.map +1 -1
  91. package/dist/simple-tree/walkFieldSchema.d.ts.map +1 -1
  92. package/dist/simple-tree/walkFieldSchema.js +1 -1
  93. package/dist/simple-tree/walkFieldSchema.js.map +1 -1
  94. package/lib/alpha.d.ts +1 -0
  95. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -1
  96. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  97. package/lib/index.d.ts +1 -1
  98. package/lib/index.d.ts.map +1 -1
  99. package/lib/index.js.map +1 -1
  100. package/lib/packageVersion.d.ts +1 -1
  101. package/lib/packageVersion.d.ts.map +1 -1
  102. package/lib/packageVersion.js +1 -1
  103. package/lib/packageVersion.js.map +1 -1
  104. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  105. package/lib/shared-tree/schematizingTreeView.js +4 -4
  106. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  107. package/lib/shared-tree/treeAlpha.d.ts +38 -0
  108. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  109. package/lib/shared-tree/treeAlpha.js +108 -3
  110. package/lib/shared-tree/treeAlpha.js.map +1 -1
  111. package/lib/simple-tree/api/configuration.d.ts +15 -3
  112. package/lib/simple-tree/api/configuration.d.ts.map +1 -1
  113. package/lib/simple-tree/api/configuration.js +42 -24
  114. package/lib/simple-tree/api/configuration.js.map +1 -1
  115. package/lib/simple-tree/api/index.d.ts +1 -1
  116. package/lib/simple-tree/api/index.d.ts.map +1 -1
  117. package/lib/simple-tree/api/index.js +1 -1
  118. package/lib/simple-tree/api/index.js.map +1 -1
  119. package/lib/simple-tree/api/treeNodeApi.d.ts +3 -0
  120. package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  121. package/lib/simple-tree/api/treeNodeApi.js +2 -2
  122. package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
  123. package/lib/simple-tree/core/context.d.ts +3 -3
  124. package/lib/simple-tree/core/context.d.ts.map +1 -1
  125. package/lib/simple-tree/core/context.js.map +1 -1
  126. package/lib/simple-tree/core/getOrCreateNode.d.ts +9 -0
  127. package/lib/simple-tree/core/getOrCreateNode.d.ts.map +1 -1
  128. package/lib/simple-tree/core/getOrCreateNode.js +10 -0
  129. package/lib/simple-tree/core/getOrCreateNode.js.map +1 -1
  130. package/lib/simple-tree/core/index.d.ts +2 -2
  131. package/lib/simple-tree/core/index.d.ts.map +1 -1
  132. package/lib/simple-tree/core/index.js +2 -2
  133. package/lib/simple-tree/core/index.js.map +1 -1
  134. package/lib/simple-tree/core/treeNodeKernel.js +1 -1
  135. package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
  136. package/lib/simple-tree/core/treeNodeSchema.d.ts +68 -1
  137. package/lib/simple-tree/core/treeNodeSchema.d.ts.map +1 -1
  138. package/lib/simple-tree/core/treeNodeSchema.js +21 -0
  139. package/lib/simple-tree/core/treeNodeSchema.js.map +1 -1
  140. package/lib/simple-tree/core/walkSchema.d.ts +3 -3
  141. package/lib/simple-tree/core/walkSchema.d.ts.map +1 -1
  142. package/lib/simple-tree/core/walkSchema.js +9 -5
  143. package/lib/simple-tree/core/walkSchema.js.map +1 -1
  144. package/lib/simple-tree/createContext.js +1 -1
  145. package/lib/simple-tree/createContext.js.map +1 -1
  146. package/lib/simple-tree/getTreeNodeForField.d.ts +1 -1
  147. package/lib/simple-tree/getTreeNodeForField.d.ts.map +1 -1
  148. package/lib/simple-tree/getTreeNodeForField.js +1 -1
  149. package/lib/simple-tree/getTreeNodeForField.js.map +1 -1
  150. package/lib/simple-tree/index.d.ts +5 -5
  151. package/lib/simple-tree/index.d.ts.map +1 -1
  152. package/lib/simple-tree/index.js +4 -4
  153. package/lib/simple-tree/index.js.map +1 -1
  154. package/lib/simple-tree/leafNodeSchema.d.ts +2 -1
  155. package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
  156. package/lib/simple-tree/leafNodeSchema.js +2 -1
  157. package/lib/simple-tree/leafNodeSchema.js.map +1 -1
  158. package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  159. package/lib/simple-tree/node-kinds/array/arrayNode.js +10 -7
  160. package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  161. package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  162. package/lib/simple-tree/node-kinds/map/mapNode.js +9 -5
  163. package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  164. package/lib/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  165. package/lib/simple-tree/node-kinds/object/objectNode.js +11 -8
  166. package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  167. package/lib/simple-tree/schemaTypes.d.ts +13 -27
  168. package/lib/simple-tree/schemaTypes.d.ts.map +1 -1
  169. package/lib/simple-tree/schemaTypes.js +42 -35
  170. package/lib/simple-tree/schemaTypes.js.map +1 -1
  171. package/lib/simple-tree/toStoredSchema.d.ts +2 -0
  172. package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
  173. package/lib/simple-tree/toStoredSchema.js +2 -0
  174. package/lib/simple-tree/toStoredSchema.js.map +1 -1
  175. package/lib/simple-tree/treeNodeValid.d.ts.map +1 -1
  176. package/lib/simple-tree/treeNodeValid.js +1 -2
  177. package/lib/simple-tree/treeNodeValid.js.map +1 -1
  178. package/lib/simple-tree/walkFieldSchema.d.ts.map +1 -1
  179. package/lib/simple-tree/walkFieldSchema.js +1 -1
  180. package/lib/simple-tree/walkFieldSchema.js.map +1 -1
  181. package/package.json +22 -22
  182. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +1 -1
  183. package/src/index.ts +1 -0
  184. package/src/packageVersion.ts +1 -1
  185. package/src/shared-tree/schematizingTreeView.ts +8 -5
  186. package/src/shared-tree/treeAlpha.ts +188 -3
  187. package/src/simple-tree/api/configuration.ts +59 -27
  188. package/src/simple-tree/api/index.ts +3 -3
  189. package/src/simple-tree/api/treeNodeApi.ts +5 -2
  190. package/src/simple-tree/core/context.ts +3 -3
  191. package/src/simple-tree/core/getOrCreateNode.ts +14 -0
  192. package/src/simple-tree/core/index.ts +7 -1
  193. package/src/simple-tree/core/treeNodeKernel.ts +1 -1
  194. package/src/simple-tree/core/treeNodeSchema.ts +113 -1
  195. package/src/simple-tree/core/walkSchema.ts +16 -7
  196. package/src/simple-tree/createContext.ts +1 -1
  197. package/src/simple-tree/getTreeNodeForField.ts +3 -1
  198. package/src/simple-tree/index.ts +9 -5
  199. package/src/simple-tree/leafNodeSchema.ts +7 -1
  200. package/src/simple-tree/node-kinds/array/arrayNode.ts +15 -9
  201. package/src/simple-tree/node-kinds/map/mapNode.ts +10 -4
  202. package/src/simple-tree/node-kinds/object/objectNode.ts +20 -11
  203. package/src/simple-tree/schemaTypes.ts +55 -64
  204. package/src/simple-tree/toStoredSchema.ts +2 -0
  205. package/src/simple-tree/treeNodeValid.ts +1 -1
  206. package/src/simple-tree/walkFieldSchema.ts +5 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/tree",
3
- "version": "2.43.0-343119",
3
+ "version": "2.43.0",
4
4
  "description": "Distributed tree",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -89,17 +89,17 @@
89
89
  "temp-directory": "nyc/.nyc_output"
90
90
  },
91
91
  "dependencies": {
92
- "@fluid-internal/client-utils": "2.43.0-343119",
93
- "@fluidframework/container-runtime": "2.43.0-343119",
94
- "@fluidframework/core-interfaces": "2.43.0-343119",
95
- "@fluidframework/core-utils": "2.43.0-343119",
96
- "@fluidframework/datastore-definitions": "2.43.0-343119",
97
- "@fluidframework/driver-definitions": "2.43.0-343119",
98
- "@fluidframework/id-compressor": "2.43.0-343119",
99
- "@fluidframework/runtime-definitions": "2.43.0-343119",
100
- "@fluidframework/runtime-utils": "2.43.0-343119",
101
- "@fluidframework/shared-object-base": "2.43.0-343119",
102
- "@fluidframework/telemetry-utils": "2.43.0-343119",
92
+ "@fluid-internal/client-utils": "~2.43.0",
93
+ "@fluidframework/container-runtime": "~2.43.0",
94
+ "@fluidframework/core-interfaces": "~2.43.0",
95
+ "@fluidframework/core-utils": "~2.43.0",
96
+ "@fluidframework/datastore-definitions": "~2.43.0",
97
+ "@fluidframework/driver-definitions": "~2.43.0",
98
+ "@fluidframework/id-compressor": "~2.43.0",
99
+ "@fluidframework/runtime-definitions": "~2.43.0",
100
+ "@fluidframework/runtime-utils": "~2.43.0",
101
+ "@fluidframework/shared-object-base": "~2.43.0",
102
+ "@fluidframework/telemetry-utils": "~2.43.0",
103
103
  "@sinclair/typebox": "^0.34.13",
104
104
  "@tylerbu/sorted-btree-es6": "^1.8.0",
105
105
  "@types/ungap__structured-clone": "^1.2.0",
@@ -109,19 +109,19 @@
109
109
  "devDependencies": {
110
110
  "@arethetypeswrong/cli": "^0.17.1",
111
111
  "@biomejs/biome": "~1.9.3",
112
- "@fluid-internal/mocha-test-setup": "2.43.0-343119",
113
- "@fluid-private/stochastic-test-utils": "2.43.0-343119",
114
- "@fluid-private/test-dds-utils": "2.43.0-343119",
115
- "@fluid-private/test-drivers": "2.43.0-343119",
112
+ "@fluid-internal/mocha-test-setup": "~2.43.0",
113
+ "@fluid-private/stochastic-test-utils": "~2.43.0",
114
+ "@fluid-private/test-dds-utils": "~2.43.0",
115
+ "@fluid-private/test-drivers": "~2.43.0",
116
116
  "@fluid-tools/benchmark": "^0.51.0",
117
- "@fluid-tools/build-cli": "^0.55.0",
117
+ "@fluid-tools/build-cli": "^0.56.0",
118
118
  "@fluidframework/build-common": "^2.0.3",
119
- "@fluidframework/build-tools": "^0.55.0",
120
- "@fluidframework/container-definitions": "2.43.0-343119",
121
- "@fluidframework/container-loader": "2.43.0-343119",
119
+ "@fluidframework/build-tools": "^0.56.0",
120
+ "@fluidframework/container-definitions": "~2.43.0",
121
+ "@fluidframework/container-loader": "~2.43.0",
122
122
  "@fluidframework/eslint-config-fluid": "^5.7.4",
123
- "@fluidframework/test-runtime-utils": "2.43.0-343119",
124
- "@fluidframework/test-utils": "2.43.0-343119",
123
+ "@fluidframework/test-runtime-utils": "~2.43.0",
124
+ "@fluidframework/test-utils": "~2.43.0",
125
125
  "@fluidframework/tree-previous": "npm:@fluidframework/tree@2.42.0",
126
126
  "@microsoft/api-extractor": "7.52.8",
127
127
  "@types/diff": "^3.5.1",
@@ -169,7 +169,7 @@ export interface FlexTreeNode extends FlexTreeEntity, MapTreeNodeViewGeneric<Fle
169
169
  * @remarks
170
170
  * All fields implicitly exist, so `getBoxed` can be called with any key and will always return a field.
171
171
  * Even if the field is empty, it will still be returned, and can be edited to insert content if allowed by the field kind.
172
- * See {@link FlexTreeNode.tryGetField} for a variant that does not allocate afield in the empty case.
172
+ * See {@link FlexTreeNode.tryGetField} for a variant that does not allocate a field in the empty case.
173
173
  */
174
174
  getBoxed(key: FieldKey): FlexTreeField;
175
175
 
package/src/index.ts CHANGED
@@ -158,6 +158,7 @@ export {
158
158
  type ImplicitAnnotatedFieldSchema,
159
159
  type AnnotatedAllowedType,
160
160
  type AnnotatedAllowedTypes,
161
+ type NormalizedAnnotatedAllowedTypes,
161
162
  type AllowedTypeMetadata,
162
163
  type AllowedTypesMetadata,
163
164
  type InsertableObjectFromAnnotatedSchemaRecord,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tree";
9
- export const pkgVersion = "2.43.0-343119";
9
+ export const pkgVersion = "2.43.0";
@@ -22,12 +22,11 @@ import {
22
22
  TreeStatus,
23
23
  } from "../feature-libraries/index.js";
24
24
  import {
25
- type FieldSchema,
26
25
  type ImplicitFieldSchema,
27
26
  type SchemaCompatibilityStatus,
28
27
  type TreeView,
29
28
  type TreeViewEvents,
30
- getTreeNodeForField,
29
+ tryGetTreeNodeForField,
31
30
  setField,
32
31
  normalizeFieldSchema,
33
32
  SchemaCompatibilityTester,
@@ -53,6 +52,7 @@ import {
53
52
  areImplicitFieldSchemaEqual,
54
53
  createUnknownOptionalFieldPolicy,
55
54
  prepareForInsertionContextless,
55
+ type FieldSchema,
56
56
  } from "../simple-tree/index.js";
57
57
  import {
58
58
  type Breakable,
@@ -353,7 +353,10 @@ export class SchematizingSimpleTreeView<
353
353
  );
354
354
  this.checkout.forest.anchors.slots.set(
355
355
  SimpleContextSlot,
356
- new HydratedContext(this.rootFieldSchema.allowedTypeSet, view.context),
356
+ new HydratedContext(
357
+ normalizeFieldSchema(this.rootFieldSchema).annotatedAllowedTypesNormalized,
358
+ view.context,
359
+ ),
357
360
  );
358
361
 
359
362
  const unregister = this.checkout.storedSchema.events.on("afterSchemaChange", () => {
@@ -428,7 +431,7 @@ export class SchematizingSimpleTreeView<
428
431
  );
429
432
  }
430
433
  const view = this.getView();
431
- return getTreeNodeForField(view.flexTree) as ReadableField<TRootSchema>;
434
+ return tryGetTreeNodeForField(view.flexTree) as ReadableField<TRootSchema>;
432
435
  }
433
436
 
434
437
  public set root(newRoot: InsertableField<TRootSchema>) {
@@ -525,7 +528,7 @@ export function addConstraintsToTransaction(
525
528
  `Attempted to add a "nodeInDocument" constraint${revertText}, but the node is not currently in the document. Node status: ${nodeStatus}`,
526
529
  );
527
530
  }
528
- assert(node.isHydrated(), "In document node must be hydrated.");
531
+ assert(node.isHydrated(), 0xbc2 /* In document node must be hydrated. */);
529
532
  if (constraintsOnRevert) {
530
533
  checkout.editor.addNodeExistsConstraintOnRevert(node.anchorNode);
531
534
  } else {
@@ -3,13 +3,19 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert, fail } from "@fluidframework/core-utils/internal";
6
+ import {
7
+ assert,
8
+ debugAssert,
9
+ fail,
10
+ unreachableCase,
11
+ } from "@fluidframework/core-utils/internal";
7
12
  import { createIdCompressor } from "@fluidframework/id-compressor/internal";
8
13
  import { UsageError } from "@fluidframework/telemetry-utils/internal";
9
14
  import type { IFluidHandle } from "@fluidframework/core-interfaces";
10
15
  import type { IIdCompressor } from "@fluidframework/id-compressor";
11
16
 
12
17
  import {
18
+ asIndex,
13
19
  getKernel,
14
20
  type TreeNode,
15
21
  type Unhydrated,
@@ -40,15 +46,20 @@ import {
40
46
  getIdentifierFromNode,
41
47
  unhydratedFlexTreeFromInsertable,
42
48
  getOrCreateNodeFromInnerNode,
49
+ getOrCreateNodeFromInnerUnboxedNode,
50
+ getOrCreateInnerNode,
51
+ NodeKind,
52
+ tryGetTreeNodeForField,
53
+ isObjectNodeSchema,
43
54
  } from "../simple-tree/index.js";
44
- import { extractFromOpaque, type JsonCompatible } from "../util/index.js";
55
+ import { brand, extractFromOpaque, type JsonCompatible } from "../util/index.js";
45
56
  import {
46
57
  FluidClientVersion,
47
58
  noopValidator,
48
59
  type ICodecOptions,
49
60
  type CodecWriteOptions,
50
61
  } from "../codec/index.js";
51
- import type { ITreeCursorSynchronous } from "../core/index.js";
62
+ import { EmptyKey, type ITreeCursorSynchronous } from "../core/index.js";
52
63
  import {
53
64
  cursorForMapTreeField,
54
65
  defaultSchemaPolicy,
@@ -60,6 +71,7 @@ import {
60
71
  type FieldBatchEncodingContext,
61
72
  fluidVersionToFieldBatchCodecWriteVersion,
62
73
  type LocalNodeIdentifier,
74
+ type FlexTreeSequenceField,
63
75
  } from "../feature-libraries/index.js";
64
76
  import { independentInitializedView, type ViewContent } from "./independentView.js";
65
77
  import { SchematizingSimpleTreeView, ViewSlot } from "./schematizingTreeView.js";
@@ -343,6 +355,48 @@ export interface TreeAlpha {
343
355
  * Otherwise, this returns the key of the field that it is under (a `string`).
344
356
  */
345
357
  key2(node: TreeNode): string | number | undefined;
358
+
359
+ /**
360
+ * Gets the child of the given node with the given property key if a child exists under that key.
361
+ *
362
+ * @remarks {@link SchemaFactoryObjectOptions.allowUnknownOptionalFields | Unknown optional fields} of Object nodes will not be returned by this method.
363
+ *
364
+ * @param node - The parent node whose child is being requested.
365
+ * @param key - The property key under the node under which the child is being requested.
366
+ * For Object nodes, this is the developer-facing "property key", not the "{@link SimpleObjectFieldSchema.storedKey | stored keys}".
367
+ *
368
+ * @returns The child node or leaf value under the given key, or `undefined` if no such child exists.
369
+ *
370
+ * @see {@link (TreeAlpha:interface).key2}
371
+ * @see {@link (TreeNodeApi:interface).parent}
372
+ */
373
+ child(node: TreeNode, key: string | number): TreeNode | TreeLeafValue | undefined;
374
+
375
+ /**
376
+ * Gets the children of the provided node, paired with their property keys under the node.
377
+ *
378
+ * @remarks
379
+ * No guarantees are made regarding the order of the children in the returned array.
380
+ *
381
+ * Optional properties of Object nodes with no value are not included in the result.
382
+ *
383
+ * {@link SchemaFactoryObjectOptions.allowUnknownOptionalFields | Unknown optional fields} of Object nodes are not included in the result.
384
+ *
385
+ * @param node - The node whose children are being requested.
386
+ *
387
+ * @returns
388
+ * An array of pairs of the form `[propertyKey, child]`.
389
+ *
390
+ * For Array nodes, the `propertyKey` is the index of the child in the array.
391
+ *
392
+ * For Object nodes, the returned `propertyKey`s are the developer-facing "property keys", not the "{@link SimpleObjectFieldSchema.storedKey | stored keys}".
393
+ *
394
+ * @see {@link (TreeAlpha:interface).key2}
395
+ * @see {@link (TreeNodeApi:interface).parent}
396
+ */
397
+ children(
398
+ node: TreeNode,
399
+ ): Iterable<[propertyKey: string | number, child: TreeNode | TreeLeafValue]>;
346
400
  }
347
401
 
348
402
  /**
@@ -492,6 +546,137 @@ export const TreeAlpha: TreeAlpha = {
492
546
  const parentSchema = treeNodeApi.schema(parent);
493
547
  return getPropertyKeyFromStoredKey(parentSchema, storedKey);
494
548
  },
549
+
550
+ child: (
551
+ node: TreeNode,
552
+ propertyKey: string | number,
553
+ ): TreeNode | TreeLeafValue | undefined => {
554
+ const flexNode = getOrCreateInnerNode(node);
555
+ debugAssert(
556
+ () => !flexNode.context.isDisposed() || "The provided tree node has been disposed.",
557
+ );
558
+
559
+ const schema = treeNodeApi.schema(node);
560
+
561
+ switch (schema.kind) {
562
+ case NodeKind.Array: {
563
+ const sequence = flexNode.tryGetField(EmptyKey) as FlexTreeSequenceField | undefined;
564
+
565
+ // Empty sequence - cannot have children.
566
+ if (sequence === undefined) {
567
+ return undefined;
568
+ }
569
+
570
+ const index =
571
+ typeof propertyKey === "number"
572
+ ? propertyKey
573
+ : asIndex(propertyKey, Number.POSITIVE_INFINITY);
574
+
575
+ // If the key is not a valid index, then there is no corresponding child.
576
+ if (index === undefined) {
577
+ return undefined;
578
+ }
579
+
580
+ const childFlexTree = sequence.at(index);
581
+
582
+ // No child at the given index.
583
+ if (childFlexTree === undefined) {
584
+ return undefined;
585
+ }
586
+
587
+ return getOrCreateNodeFromInnerUnboxedNode(childFlexTree);
588
+ }
589
+ case NodeKind.Map:
590
+ if (typeof propertyKey !== "string") {
591
+ // Map nodes only support string keys.
592
+ return undefined;
593
+ }
594
+ // Fall through
595
+ case NodeKind.Object: {
596
+ let storedKey: string | number = propertyKey;
597
+ if (isObjectNodeSchema(schema)) {
598
+ const fieldSchema = schema.fields.get(String(propertyKey));
599
+ if (fieldSchema === undefined) {
600
+ return undefined;
601
+ }
602
+
603
+ storedKey = fieldSchema.storedKey;
604
+ }
605
+
606
+ const field = flexNode.tryGetField(brand(String(storedKey)));
607
+ if (field !== undefined) {
608
+ return tryGetTreeNodeForField(field);
609
+ }
610
+
611
+ return undefined;
612
+ }
613
+ case NodeKind.Leaf: {
614
+ fail(0xbc3 /* Leaf schema associated with non-leaf tree node. */);
615
+ }
616
+ default: {
617
+ unreachableCase(schema.kind);
618
+ }
619
+ }
620
+ },
621
+
622
+ children(node: TreeNode): [propertyKey: string | number, child: TreeNode | TreeLeafValue][] {
623
+ const flexNode = getOrCreateInnerNode(node);
624
+ debugAssert(
625
+ () => !flexNode.context.isDisposed() || "The provided tree node has been disposed.",
626
+ );
627
+
628
+ const schema = treeNodeApi.schema(node);
629
+
630
+ const result: [string | number, TreeNode | TreeLeafValue][] = [];
631
+ switch (schema.kind) {
632
+ case NodeKind.Array: {
633
+ const sequence = flexNode.tryGetField(EmptyKey) as FlexTreeSequenceField | undefined;
634
+ if (sequence === undefined) {
635
+ break;
636
+ }
637
+
638
+ for (let index = 0; index < sequence.length; index++) {
639
+ const childFlexTree = sequence.at(index);
640
+ assert(childFlexTree !== undefined, 0xbc4 /* Sequence child was undefined. */);
641
+ const childTree = getOrCreateNodeFromInnerUnboxedNode(childFlexTree);
642
+ result.push([index, childTree]);
643
+ }
644
+ break;
645
+ }
646
+ case NodeKind.Map: {
647
+ for (const [key, flexField] of flexNode.fields) {
648
+ const childTreeNode = tryGetTreeNodeForField(flexField);
649
+ if (childTreeNode !== undefined) {
650
+ result.push([key, childTreeNode]);
651
+ }
652
+ }
653
+ break;
654
+ }
655
+ case NodeKind.Object: {
656
+ assert(isObjectNodeSchema(schema), 0xbc5 /* Expected object schema. */);
657
+ for (const [propertyKey, fieldSchema] of schema.fields) {
658
+ const storedKey = fieldSchema.storedKey;
659
+ const flexField = flexNode.tryGetField(brand(String(storedKey)));
660
+ if (flexField !== undefined) {
661
+ const childTreeNode = tryGetTreeNodeForField(flexField);
662
+ assert(
663
+ childTreeNode !== undefined,
664
+ 0xbc6 /* Expected child tree node for field. */,
665
+ );
666
+ result.push([propertyKey, childTreeNode]);
667
+ }
668
+ }
669
+ break;
670
+ }
671
+ case NodeKind.Leaf: {
672
+ fail(0xbc7 /* Leaf schema associated with non-leaf tree node. */);
673
+ }
674
+ default: {
675
+ unreachableCase(schema.kind);
676
+ }
677
+ }
678
+ return result;
679
+ },
495
680
  };
496
681
 
497
682
  function exportConcise(
@@ -3,13 +3,15 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert, fail } from "@fluidframework/core-utils/internal";
6
+ import { assert, debugAssert, fail } from "@fluidframework/core-utils/internal";
7
7
  import { UsageError } from "@fluidframework/telemetry-utils/internal";
8
8
 
9
9
  import {
10
10
  type FieldSchemaAlpha,
11
11
  type ImplicitFieldSchema,
12
+ evaluateLazySchema,
12
13
  FieldKind,
14
+ isAnnotatedAllowedType,
13
15
  markSchemaMostDerived,
14
16
  normalizeFieldSchema,
15
17
  } from "../schemaTypes.js";
@@ -159,6 +161,11 @@ export class TreeViewConfiguration<
159
161
  */
160
162
  public readonly preventAmbiguity: boolean;
161
163
 
164
+ /**
165
+ * {@link TreeSchema.definitions} but with public types.
166
+ */
167
+ protected readonly definitionsInternal: ReadonlyMap<string, TreeNodeSchema>;
168
+
162
169
  /**
163
170
  * Construct a new {@link TreeViewConfiguration}.
164
171
  *
@@ -181,27 +188,38 @@ export class TreeViewConfiguration<
181
188
  // Ambiguity errors are lower priority to report than invalid schema errors, so collect these in an array and report them all at once.
182
189
  const ambiguityErrors: string[] = [];
183
190
 
191
+ // Eagerly perform this conversion to surface errors sooner.
192
+ // Includes detection of duplicate schema identifiers.
193
+ toStoredSchema(config.schema);
194
+
195
+ const definitions = new Map<string, SimpleNodeSchema & TreeNodeSchema>();
196
+
184
197
  walkFieldSchema(config.schema, {
185
- // Ensure all reachable schema are marked as most derived.
186
- // This ensures if multiple schema extending the same schema factory generated class are present (or have been constructed, or get constructed in the future),
187
- // an error is reported.
188
-
189
- node: (schema) => markSchemaMostDerived(schema, true),
190
- allowedTypes(types): void {
191
- if (config.preventAmbiguity) {
192
- checkUnion(types, ambiguityErrors);
193
- }
198
+ node: (schema) => {
199
+ // Ensure all reachable schema are marked as most derived.
200
+ // This ensures if multiple schema extending the same schema factory generated class are present (or have had instances of them constructed, or get instances of them constructed in the future),
201
+ // an error is reported.
202
+ markSchemaMostDerived(schema, true);
203
+
204
+ debugAssert(() => !definitions.has(schema.identifier));
205
+ definitions.set(schema.identifier, schema as SimpleNodeSchema & TreeNodeSchema);
206
+ },
207
+ allowedTypes({ types }): void {
208
+ checkUnion(
209
+ types.map((t) => evaluateLazySchema(isAnnotatedAllowedType(t) ? t.type : t)),
210
+ config.preventAmbiguity,
211
+ ambiguityErrors,
212
+ );
194
213
  },
195
214
  });
196
215
 
216
+ this.definitionsInternal = definitions;
217
+
197
218
  if (ambiguityErrors.length !== 0) {
198
219
  // Duplicate errors are common since when two types conflict, both orders error:
199
220
  const deduplicated = new Set(ambiguityErrors);
200
221
  throw new UsageError(`Ambiguous schema found:\n${[...deduplicated].join("\n")}`);
201
222
  }
202
-
203
- // Eagerly perform this conversion to surface errors sooner.
204
- toStoredSchema(config.schema);
205
223
  }
206
224
  }
207
225
 
@@ -219,20 +237,17 @@ export class TreeViewConfigurationAlpha<
219
237
  * {@inheritDoc TreeSchema.root}
220
238
  */
221
239
  public readonly root: FieldSchemaAlpha;
240
+
222
241
  /**
223
242
  * {@inheritDoc TreeSchema.definitions}
224
243
  */
225
- public readonly definitions: ReadonlyMap<string, SimpleNodeSchema & TreeNodeSchema>;
244
+ public get definitions(): ReadonlyMap<string, SimpleNodeSchema & TreeNodeSchema> {
245
+ return this.definitionsInternal as ReadonlyMap<string, SimpleNodeSchema & TreeNodeSchema>;
246
+ }
226
247
 
227
248
  public constructor(props: ITreeViewConfiguration<TSchema>) {
228
249
  super(props);
229
250
  this.root = normalizeFieldSchema(props.schema);
230
- const definitions = new Map<string, SimpleNodeSchema & TreeNodeSchema>();
231
- walkFieldSchema(props.schema, {
232
- node: (schema) =>
233
- definitions.set(schema.identifier, schema as SimpleNodeSchema & TreeNodeSchema),
234
- });
235
- this.definitions = definitions;
236
251
  }
237
252
  }
238
253
 
@@ -262,9 +277,21 @@ function formatTypes(allowed: Iterable<TreeNodeSchema>): string {
262
277
  }
263
278
 
264
279
  /**
265
- * Detect cases documented in {@link ITreeConfigurationOptions.preventAmbiguity}.
280
+ * Check if union contents are valid (shallowly).
281
+ *
282
+ * @param union - The union of {@link TreeNodeSchema} to check.
283
+ * @param preventAmbiguity - If true, detect cases documented in {@link ITreeConfigurationOptions.preventAmbiguity}, reporting them to `ambiguityErrors`.
284
+ * @param ambiguityErrors - An array into which this function inserts any ambiguity errors, see {@link ITreeConfigurationOptions.preventAmbiguity}.
285
+ *
286
+ * @remarks
287
+ * Includes checks for non-ambiguity errors as well: such as duplicate schemas in the union.
288
+ * Any non-ambiguity errors are thrown as exceptions: `UsageError`s if causable by incorrect API use, and asserts if violating internal invariants.
266
289
  */
267
- export function checkUnion(union: Iterable<TreeNodeSchema>, errors: string[]): void {
290
+ export function checkUnion(
291
+ union: Iterable<TreeNodeSchema>,
292
+ preventAmbiguity: boolean,
293
+ ambiguityErrors: string[],
294
+ ): void {
268
295
  const checked: Set<TreeNodeSchema> = new Set();
269
296
  const maps: TreeNodeSchema[] = [];
270
297
  const arrays: TreeNodeSchema[] = [];
@@ -294,26 +321,31 @@ export function checkUnion(union: Iterable<TreeNodeSchema>, errors: string[]): v
294
321
  }
295
322
  }
296
323
 
324
+ if (!preventAmbiguity) {
325
+ // All remaining checks are for the preventAmbiguity case, so skip them if not enabled.
326
+ return;
327
+ }
328
+
297
329
  if (arrays.length > 1) {
298
- errors.push(
330
+ ambiguityErrors.push(
299
331
  `More than one kind of array allowed within union (${formatTypes(arrays)}). This would require type disambiguation which is not supported by arrays during import or export.`,
300
332
  );
301
333
  }
302
334
 
303
335
  if (maps.length > 1) {
304
- errors.push(
336
+ ambiguityErrors.push(
305
337
  `More than one kind of map allowed within union (${formatTypes(maps)}). This would require type disambiguation which is not supported by maps during import or export.`,
306
338
  );
307
339
  }
308
340
 
309
341
  if (maps.length > 0 && arrays.length > 0) {
310
- errors.push(
342
+ ambiguityErrors.push(
311
343
  `Both a map and an array allowed within union (${formatTypes([...arrays, ...maps])}). Both can be implicitly constructed from iterables like arrays, which are ambiguous when the array is empty.`,
312
344
  );
313
345
  }
314
346
 
315
347
  if (objects.length > 0 && maps.length > 0) {
316
- errors.push(
348
+ ambiguityErrors.push(
317
349
  `Both a object and a map allowed within union (${formatTypes([...objects, ...maps])}). Both can be constructed from objects and can be ambiguous.`,
318
350
  );
319
351
  }
@@ -345,7 +377,7 @@ export function checkUnion(union: Iterable<TreeNodeSchema>, errors: string[]): v
345
377
  // Consider separating unambiguous implicit construction format from constructor arguments at type level, allowing constructor to superset the implicit construction options (ex: optional constant fields).
346
378
  // The policy here however must remain at least as conservative as shallowCompatibilityTest in src/simple-tree/unhydratedFlexTreeFromInsertable.ts.
347
379
 
348
- errors.push(
380
+ ambiguityErrors.push(
349
381
  `The required fields of ${JSON.stringify(schema.identifier)} are insufficient to differentiate it from the following types: ${formatTypes(possiblyAmbiguous)}. For objects to be considered unambiguous, each must have required fields that do not all occur on any other object in the union.`,
350
382
  );
351
383
  }
@@ -45,12 +45,12 @@ export {
45
45
  singletonSchema,
46
46
  } from "./schemaCreationUtilities.js";
47
47
  export {
48
+ getIdentifierFromNode,
49
+ getPropertyKeyFromStoredKey,
50
+ getStoredKey,
48
51
  treeNodeApi,
49
52
  type TreeNodeApi,
50
53
  tryGetSchema,
51
- getStoredKey,
52
- getPropertyKeyFromStoredKey,
53
- getIdentifierFromNode,
54
54
  } from "./treeNodeApi.js";
55
55
  export { createFromCursor } from "./create.js";
56
56
  export {
@@ -39,7 +39,7 @@ import {
39
39
  } from "../core/index.js";
40
40
  import type { TreeChangeEvents } from "./treeChangeEvents.js";
41
41
  import { isObjectNodeSchema } from "../node-kinds/index.js";
42
- import { getTreeNodeForField } from "../getTreeNodeForField.js";
42
+ import { tryGetTreeNodeForField } from "../getTreeNodeForField.js";
43
43
 
44
44
  /**
45
45
  * Provides various functions for analyzing {@link TreeNode}s.
@@ -83,6 +83,9 @@ export interface TreeNodeApi {
83
83
  * Return the node under which this node resides in the tree (or undefined if this is a root node of the tree).
84
84
  *
85
85
  * @throws A {@link @fluidframework/telemetry-utils#UsageError} if the node has been {@link TreeStatus.Deleted | deleted}.
86
+ *
87
+ * @see {@link (TreeAlpha:interface).child}
88
+ * @see {@link (TreeAlpha:interface).children}
86
89
  */
87
90
  parent(node: TreeNode): TreeNode | undefined;
88
91
 
@@ -316,7 +319,7 @@ export function getIdentifierFromNode(
316
319
  const key = identifierFieldKeys[0] ?? oob();
317
320
  const identifierField = flexNode.tryGetField(key);
318
321
  assert(identifierField !== undefined, 0xbb5 /* missing identifier field */);
319
- const identifierValue = getTreeNodeForField(identifierField);
322
+ const identifierValue = tryGetTreeNodeForField(identifierField);
320
323
  assert(typeof identifierValue === "string", 0xbb6 /* identifier not a string */);
321
324
 
322
325
  const context = flexNode.context;
@@ -10,7 +10,7 @@ import type {
10
10
  } from "../../feature-libraries/index.js";
11
11
  import { brand } from "../../util/index.js";
12
12
 
13
- import type { TreeNodeSchema } from "./treeNodeSchema.js";
13
+ import type { NormalizedAnnotatedAllowedTypes, TreeNodeSchema } from "./treeNodeSchema.js";
14
14
  import { walkAllowedTypes } from "./walkSchema.js";
15
15
 
16
16
  /**
@@ -52,7 +52,7 @@ export class Context {
52
52
  * Since this walks the schema, it must not be invoked during schema declaration or schema forward references could fail to be resolved.
53
53
  */
54
54
  public constructor(
55
- rootSchema: Iterable<TreeNodeSchema>,
55
+ rootSchema: NormalizedAnnotatedAllowedTypes,
56
56
  public readonly flexContext: FlexTreeContext,
57
57
  ) {
58
58
  const schema: Map<TreeNodeSchemaIdentifier, TreeNodeSchema> = new Map();
@@ -71,7 +71,7 @@ export class Context {
71
71
  */
72
72
  export class HydratedContext extends Context {
73
73
  public constructor(
74
- rootSchema: Iterable<TreeNodeSchema>,
74
+ rootSchema: NormalizedAnnotatedAllowedTypes,
75
75
  public override readonly flexContext: FlexTreeHydratedContext,
76
76
  ) {
77
77
  super(rootSchema, flexContext);
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import type { TreeValue } from "../../core/index.js";
7
+ import { isFlexTreeNode, type FlexTreeUnknownUnboxed } from "../../feature-libraries/index.js";
8
+ import type { TreeLeafValue } from "../schemaTypes.js";
7
9
 
8
10
  import type { TreeNode } from "./treeNode.js";
9
11
  import {
@@ -34,3 +36,15 @@ export function getOrCreateNodeFromInnerNode(flexNode: InnerNode): TreeNode | Tr
34
36
 
35
37
  return createTreeNodeFromInner(flexNode);
36
38
  }
39
+
40
+ /**
41
+ * Returns the TreeNode or TreeValue for the provided {@link FlexTreeUnknownUnboxed}.
42
+ * This will allocate a new one if needed, and otherwise return one from cache.
43
+ * @remarks
44
+ * This supports both hydrated and unhydrated nodes.
45
+ */
46
+ export function getOrCreateNodeFromInnerUnboxedNode(
47
+ flexTree: FlexTreeUnknownUnboxed,
48
+ ): TreeNode | TreeLeafValue {
49
+ return isFlexTreeNode(flexTree) ? getOrCreateNodeFromInnerNode(flexTree) : flexTree;
50
+ }
@@ -31,10 +31,16 @@ export {
31
31
  type TreeNodeSchemaNonClass,
32
32
  type TreeNodeSchemaCore,
33
33
  type TreeNodeSchemaBoth,
34
+ type AnnotatedAllowedType,
35
+ type NormalizedAnnotatedAllowedTypes,
36
+ isAnnotatedAllowedTypes,
34
37
  } from "./treeNodeSchema.js";
35
38
  export { walkAllowedTypes, type SchemaVisitor } from "./walkSchema.js";
36
39
  export { Context, HydratedContext, SimpleContextSlot } from "./context.js";
37
- export { getOrCreateNodeFromInnerNode } from "./getOrCreateNode.js";
40
+ export {
41
+ getOrCreateNodeFromInnerNode,
42
+ getOrCreateNodeFromInnerUnboxedNode,
43
+ } from "./getOrCreateNode.js";
38
44
  export {
39
45
  UnhydratedFlexTreeNode,
40
46
  UnhydratedSequenceField,