@fluidframework/tree 2.53.0-350190 → 2.53.1

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 (236) hide show
  1. package/.eslintrc.cjs +14 -2
  2. package/CHANGELOG.md +125 -0
  3. package/api-report/tree.alpha.api.md +11 -13
  4. package/dist/core/tree/visitDelta.d.ts +1 -1
  5. package/dist/core/tree/visitDelta.d.ts.map +1 -1
  6. package/dist/core/tree/visitDelta.js.map +1 -1
  7. package/dist/feature-libraries/chunked-forest/index.d.ts +1 -0
  8. package/dist/feature-libraries/chunked-forest/index.d.ts.map +1 -1
  9. package/dist/feature-libraries/chunked-forest/index.js +3 -1
  10. package/dist/feature-libraries/chunked-forest/index.js.map +1 -1
  11. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts +2 -4
  12. package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  13. package/dist/feature-libraries/default-schema/defaultEditBuilder.js +3 -0
  14. package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  15. package/dist/feature-libraries/default-schema/noChangeCodecs.d.ts +1 -1
  16. package/dist/feature-libraries/default-schema/noChangeCodecs.d.ts.map +1 -1
  17. package/dist/feature-libraries/default-schema/noChangeCodecs.js.map +1 -1
  18. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts +4 -0
  19. package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  20. package/dist/feature-libraries/forest-summary/forestSummarizer.js +5 -5
  21. package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  22. package/dist/feature-libraries/index.d.ts +1 -1
  23. package/dist/feature-libraries/index.d.ts.map +1 -1
  24. package/dist/feature-libraries/index.js +4 -2
  25. package/dist/feature-libraries/index.js.map +1 -1
  26. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +1 -0
  27. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  28. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.d.ts +1 -1
  29. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.d.ts.map +1 -1
  30. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV1.js.map +1 -1
  31. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +1 -1
  32. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
  33. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  34. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts +1 -1
  35. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
  36. package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
  37. package/dist/feature-libraries/sequence-field/sequenceFieldCodecs.d.ts +1 -1
  38. package/dist/feature-libraries/sequence-field/sequenceFieldCodecs.d.ts.map +1 -1
  39. package/dist/feature-libraries/sequence-field/sequenceFieldCodecs.js.map +1 -1
  40. package/dist/feature-libraries/sequence-field/types.d.ts +1 -1
  41. package/dist/feature-libraries/sequence-field/types.d.ts.map +1 -1
  42. package/dist/feature-libraries/sequence-field/types.js.map +1 -1
  43. package/dist/index.js +3 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/packageVersion.d.ts +1 -1
  46. package/dist/packageVersion.d.ts.map +1 -1
  47. package/dist/packageVersion.js +1 -1
  48. package/dist/packageVersion.js.map +1 -1
  49. package/dist/shared-tree/independentView.d.ts.map +1 -1
  50. package/dist/shared-tree/independentView.js +1 -1
  51. package/dist/shared-tree/independentView.js.map +1 -1
  52. package/dist/shared-tree/index.d.ts +0 -1
  53. package/dist/shared-tree/index.d.ts.map +1 -1
  54. package/dist/shared-tree/index.js.map +1 -1
  55. package/dist/shared-tree/schematizeTree.d.ts +23 -60
  56. package/dist/shared-tree/schematizeTree.d.ts.map +1 -1
  57. package/dist/shared-tree/schematizeTree.js +59 -151
  58. package/dist/shared-tree/schematizeTree.js.map +1 -1
  59. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  60. package/dist/shared-tree/schematizingTreeView.js +8 -8
  61. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  62. package/dist/shared-tree-core/defaultResubmitMachine.d.ts +2 -1
  63. package/dist/shared-tree-core/defaultResubmitMachine.d.ts.map +1 -1
  64. package/dist/shared-tree-core/defaultResubmitMachine.js.map +1 -1
  65. package/dist/simple-tree/core/allowedTypes.d.ts +14 -14
  66. package/dist/simple-tree/core/allowedTypes.d.ts.map +1 -1
  67. package/dist/simple-tree/core/allowedTypes.js.map +1 -1
  68. package/dist/simple-tree/core/treeNode.d.ts +0 -3
  69. package/dist/simple-tree/core/treeNode.d.ts.map +1 -1
  70. package/dist/simple-tree/core/treeNode.js +3 -3
  71. package/dist/simple-tree/core/treeNode.js.map +1 -1
  72. package/dist/simple-tree/core/treeNodeValid.d.ts.map +1 -1
  73. package/dist/simple-tree/core/treeNodeValid.js +0 -3
  74. package/dist/simple-tree/core/treeNodeValid.js.map +1 -1
  75. package/dist/simple-tree/fieldSchema.d.ts +2 -1
  76. package/dist/simple-tree/fieldSchema.d.ts.map +1 -1
  77. package/dist/simple-tree/fieldSchema.js.map +1 -1
  78. package/dist/simple-tree/index.d.ts +1 -1
  79. package/dist/simple-tree/index.d.ts.map +1 -1
  80. package/dist/simple-tree/index.js +3 -2
  81. package/dist/simple-tree/index.js.map +1 -1
  82. package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  83. package/dist/simple-tree/node-kinds/array/arrayNode.js +5 -5
  84. package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  85. package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  86. package/dist/simple-tree/node-kinds/map/mapNode.js +1 -1
  87. package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  88. package/dist/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  89. package/dist/simple-tree/node-kinds/object/objectNode.js +2 -2
  90. package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  91. package/dist/simple-tree/node-kinds/record/recordNode.d.ts.map +1 -1
  92. package/dist/simple-tree/node-kinds/record/recordNode.js +1 -1
  93. package/dist/simple-tree/node-kinds/record/recordNode.js.map +1 -1
  94. package/dist/tableSchema.d.ts +25 -32
  95. package/dist/tableSchema.d.ts.map +1 -1
  96. package/dist/tableSchema.js +10 -24
  97. package/dist/tableSchema.js.map +1 -1
  98. package/docs/.attachments/cell-ordering/C-knows-of-ABC.png +0 -0
  99. package/docs/.attachments/cell-ordering/C-knows-of-C.png +0 -0
  100. package/docs/.attachments/cell-ordering/XvsA.png +0 -0
  101. package/docs/.attachments/cell-ordering/compose-a-b.png +0 -0
  102. package/docs/.attachments/cell-ordering/compose-a-ref-p1-b-ref-p2.png +0 -0
  103. package/docs/.attachments/cell-ordering/compose-b-no-ref-to-ca.png +0 -0
  104. package/docs/.attachments/cell-ordering/rebase-ab-over-x.png +0 -0
  105. package/docs/.attachments/cell-ordering/rebase-b-over-x.png +0 -0
  106. package/docs/.attachments/cell-ordering/rebase-b2-over-x.png +0 -0
  107. package/docs/.attachments/cell-ordering/rebase-b2.png +0 -0
  108. package/docs/.attachments/cell-ordering/rebase-to-abprime.png +0 -0
  109. package/docs/.attachments/cell-ordering/rebase-to-bprime.png +0 -0
  110. package/docs/main/cell-ordering.md +638 -0
  111. package/lib/core/tree/visitDelta.d.ts +1 -1
  112. package/lib/core/tree/visitDelta.d.ts.map +1 -1
  113. package/lib/core/tree/visitDelta.js.map +1 -1
  114. package/lib/feature-libraries/chunked-forest/index.d.ts +1 -0
  115. package/lib/feature-libraries/chunked-forest/index.d.ts.map +1 -1
  116. package/lib/feature-libraries/chunked-forest/index.js +1 -0
  117. package/lib/feature-libraries/chunked-forest/index.js.map +1 -1
  118. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts +2 -4
  119. package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
  120. package/lib/feature-libraries/default-schema/defaultEditBuilder.js +4 -1
  121. package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
  122. package/lib/feature-libraries/default-schema/noChangeCodecs.d.ts +1 -1
  123. package/lib/feature-libraries/default-schema/noChangeCodecs.d.ts.map +1 -1
  124. package/lib/feature-libraries/default-schema/noChangeCodecs.js.map +1 -1
  125. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts +4 -0
  126. package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
  127. package/lib/feature-libraries/forest-summary/forestSummarizer.js +1 -1
  128. package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
  129. package/lib/feature-libraries/index.d.ts +1 -1
  130. package/lib/feature-libraries/index.d.ts.map +1 -1
  131. package/lib/feature-libraries/index.js +1 -1
  132. package/lib/feature-libraries/index.js.map +1 -1
  133. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +1 -0
  134. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  135. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.d.ts +1 -1
  136. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.d.ts.map +1 -1
  137. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.js +1 -1
  138. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV1.js.map +1 -1
  139. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +1 -1
  140. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
  141. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js +1 -1
  142. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
  143. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts +1 -1
  144. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
  145. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js +1 -1
  146. package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
  147. package/lib/feature-libraries/sequence-field/sequenceFieldCodecs.d.ts +1 -1
  148. package/lib/feature-libraries/sequence-field/sequenceFieldCodecs.d.ts.map +1 -1
  149. package/lib/feature-libraries/sequence-field/sequenceFieldCodecs.js.map +1 -1
  150. package/lib/feature-libraries/sequence-field/types.d.ts +1 -1
  151. package/lib/feature-libraries/sequence-field/types.d.ts.map +1 -1
  152. package/lib/feature-libraries/sequence-field/types.js.map +1 -1
  153. package/lib/index.js +1 -1
  154. package/lib/index.js.map +1 -1
  155. package/lib/packageVersion.d.ts +1 -1
  156. package/lib/packageVersion.d.ts.map +1 -1
  157. package/lib/packageVersion.js +1 -1
  158. package/lib/packageVersion.js.map +1 -1
  159. package/lib/shared-tree/independentView.d.ts.map +1 -1
  160. package/lib/shared-tree/independentView.js +2 -2
  161. package/lib/shared-tree/independentView.js.map +1 -1
  162. package/lib/shared-tree/index.d.ts +0 -1
  163. package/lib/shared-tree/index.d.ts.map +1 -1
  164. package/lib/shared-tree/index.js.map +1 -1
  165. package/lib/shared-tree/schematizeTree.d.ts +23 -60
  166. package/lib/shared-tree/schematizeTree.d.ts.map +1 -1
  167. package/lib/shared-tree/schematizeTree.js +60 -150
  168. package/lib/shared-tree/schematizeTree.js.map +1 -1
  169. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  170. package/lib/shared-tree/schematizingTreeView.js +11 -11
  171. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  172. package/lib/shared-tree-core/defaultResubmitMachine.d.ts +2 -1
  173. package/lib/shared-tree-core/defaultResubmitMachine.d.ts.map +1 -1
  174. package/lib/shared-tree-core/defaultResubmitMachine.js.map +1 -1
  175. package/lib/simple-tree/core/allowedTypes.d.ts +14 -14
  176. package/lib/simple-tree/core/allowedTypes.d.ts.map +1 -1
  177. package/lib/simple-tree/core/allowedTypes.js.map +1 -1
  178. package/lib/simple-tree/core/treeNode.d.ts +0 -3
  179. package/lib/simple-tree/core/treeNode.d.ts.map +1 -1
  180. package/lib/simple-tree/core/treeNode.js +3 -3
  181. package/lib/simple-tree/core/treeNode.js.map +1 -1
  182. package/lib/simple-tree/core/treeNodeValid.d.ts.map +1 -1
  183. package/lib/simple-tree/core/treeNodeValid.js +0 -3
  184. package/lib/simple-tree/core/treeNodeValid.js.map +1 -1
  185. package/lib/simple-tree/fieldSchema.d.ts +2 -1
  186. package/lib/simple-tree/fieldSchema.d.ts.map +1 -1
  187. package/lib/simple-tree/fieldSchema.js.map +1 -1
  188. package/lib/simple-tree/index.d.ts +1 -1
  189. package/lib/simple-tree/index.d.ts.map +1 -1
  190. package/lib/simple-tree/index.js +1 -1
  191. package/lib/simple-tree/index.js.map +1 -1
  192. package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
  193. package/lib/simple-tree/node-kinds/array/arrayNode.js +5 -5
  194. package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
  195. package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
  196. package/lib/simple-tree/node-kinds/map/mapNode.js +1 -1
  197. package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
  198. package/lib/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
  199. package/lib/simple-tree/node-kinds/object/objectNode.js +2 -2
  200. package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
  201. package/lib/simple-tree/node-kinds/record/recordNode.d.ts.map +1 -1
  202. package/lib/simple-tree/node-kinds/record/recordNode.js +1 -1
  203. package/lib/simple-tree/node-kinds/record/recordNode.js.map +1 -1
  204. package/lib/tableSchema.d.ts +25 -32
  205. package/lib/tableSchema.d.ts.map +1 -1
  206. package/lib/tableSchema.js +11 -25
  207. package/lib/tableSchema.js.map +1 -1
  208. package/package.json +21 -21
  209. package/src/core/tree/visitDelta.ts +3 -1
  210. package/src/feature-libraries/chunked-forest/index.ts +1 -0
  211. package/src/feature-libraries/default-schema/defaultEditBuilder.ts +12 -5
  212. package/src/feature-libraries/default-schema/noChangeCodecs.ts +1 -1
  213. package/src/feature-libraries/forest-summary/forestSummarizer.ts +1 -1
  214. package/src/feature-libraries/index.ts +2 -0
  215. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +1 -0
  216. package/src/feature-libraries/sequence-field/sequenceFieldCodecV1.ts +4 -2
  217. package/src/feature-libraries/sequence-field/sequenceFieldCodecV2.ts +4 -2
  218. package/src/feature-libraries/sequence-field/sequenceFieldCodecV3.ts +4 -2
  219. package/src/feature-libraries/sequence-field/sequenceFieldCodecs.ts +1 -1
  220. package/src/feature-libraries/sequence-field/types.ts +1 -1
  221. package/src/packageVersion.ts +1 -1
  222. package/src/shared-tree/independentView.ts +6 -2
  223. package/src/shared-tree/index.ts +0 -2
  224. package/src/shared-tree/schematizeTree.ts +83 -199
  225. package/src/shared-tree/schematizingTreeView.ts +17 -9
  226. package/src/shared-tree-core/defaultResubmitMachine.ts +2 -1
  227. package/src/simple-tree/core/allowedTypes.ts +25 -16
  228. package/src/simple-tree/core/treeNode.ts +3 -3
  229. package/src/simple-tree/core/treeNodeValid.ts +0 -3
  230. package/src/simple-tree/fieldSchema.ts +2 -1
  231. package/src/simple-tree/index.ts +1 -3
  232. package/src/simple-tree/node-kinds/array/arrayNode.ts +29 -36
  233. package/src/simple-tree/node-kinds/map/mapNode.ts +4 -1
  234. package/src/simple-tree/node-kinds/object/objectNode.ts +5 -2
  235. package/src/simple-tree/node-kinds/record/recordNode.ts +4 -1
  236. package/src/tableSchema.ts +40 -35
@@ -19,8 +19,10 @@ import type {
19
19
  } from "../../core/index.js";
20
20
  import { type JsonCompatibleReadOnly, type Mutable, brand } from "../../util/index.js";
21
21
  import { makeChangeAtomIdCodec } from "../changeAtomIdCodec.js";
22
- import type { FieldChangeEncodingContext } from "../index.js";
23
- import { EncodedNodeChangeset } from "../modular-schema/index.js";
22
+ import {
23
+ EncodedNodeChangeset,
24
+ type FieldChangeEncodingContext,
25
+ } from "../modular-schema/index.js";
24
26
 
25
27
  import { Changeset as ChangesetSchema, type Encoded } from "./formatV2.js";
26
28
  import type { SequenceCodecHelpers } from "./helperTypes.js";
@@ -12,8 +12,10 @@ import type {
12
12
  RevisionTag,
13
13
  } from "../../core/index.js";
14
14
  import type { JsonCompatibleReadOnly } from "../../util/index.js";
15
- import type { FieldChangeEncodingContext } from "../index.js";
16
- import { EncodedNodeChangeset } from "../modular-schema/index.js";
15
+ import {
16
+ EncodedNodeChangeset,
17
+ type FieldChangeEncodingContext,
18
+ } from "../modular-schema/index.js";
17
19
 
18
20
  import { Changeset as ChangesetSchema, type Encoded } from "./formatV3.js";
19
21
  import { makeV2CodecHelpers } from "./sequenceFieldCodecV2.js";
@@ -9,7 +9,7 @@ import type {
9
9
  EncodedRevisionTag,
10
10
  RevisionTag,
11
11
  } from "../../core/index.js";
12
- import type { FieldChangeEncodingContext } from "../index.js";
12
+ import type { FieldChangeEncodingContext } from "../modular-schema/index.js";
13
13
 
14
14
  import { makeV1Codec } from "./sequenceFieldCodecV1.js";
15
15
  import { makeV2Codec } from "./sequenceFieldCodecV2.js";
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { ChangeAtomId, ChangesetLocalId, RevisionTag } from "../../core/index.js";
7
- import type { NodeId } from "../index.js";
7
+ import type { NodeId } from "../modular-schema/index.js";
8
8
 
9
9
  export type CellCount = number;
10
10
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tree";
9
- export const pkgVersion = "2.53.0-350190";
9
+ export const pkgVersion = "2.53.1";
@@ -42,7 +42,7 @@ import {
42
42
  } from "./sharedTree.js";
43
43
  import { createTreeCheckout } from "./treeCheckout.js";
44
44
  import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
45
- import { initialize } from "./schematizeTree.js";
45
+ import { initialize, initializerFromChunk } from "./schematizeTree.js";
46
46
 
47
47
  /**
48
48
  * Create an uninitialized {@link TreeView} that is not tied to any {@link ITree} instance.
@@ -152,7 +152,11 @@ export function independentInitializedViewInternal<const TSchema extends Implici
152
152
  breaker,
153
153
  });
154
154
 
155
- initialize(checkout, { schema, initialTree: rootFieldCursor });
155
+ initialize(
156
+ checkout,
157
+ schema,
158
+ initializerFromChunk(checkout, () => checkout.forest.chunkField(rootFieldCursor)),
159
+ );
156
160
  return new SchematizingSimpleTreeView<TSchema>(
157
161
  checkout,
158
162
  config,
@@ -35,8 +35,6 @@ export {
35
35
  type TreeBranchFork,
36
36
  } from "./treeCheckout.js";
37
37
 
38
- export { type TreeStoredContent } from "./schematizeTree.js";
39
-
40
38
  export { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
41
39
 
42
40
  export type {
@@ -3,240 +3,124 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert, unreachableCase, fail } from "@fluidframework/core-utils/internal";
6
+ import { assert } from "@fluidframework/core-utils/internal";
7
7
 
8
- import {
9
- CursorLocationType,
10
- type ITreeCursorSynchronous,
11
- type TreeStoredSchema,
12
- rootFieldKey,
13
- schemaDataIsEmpty,
14
- } from "../core/index.js";
8
+ import { type TreeStoredSchema, rootFieldKey, schemaDataIsEmpty } from "../core/index.js";
15
9
  import {
16
10
  FieldKinds,
17
11
  allowsRepoSuperset,
18
- cursorForMapTreeField,
19
12
  defaultSchemaPolicy,
20
- mapTreeFromCursor,
13
+ type IDefaultEditBuilder,
14
+ type TreeChunk,
21
15
  } from "../feature-libraries/index.js";
22
- import { toUpgradeSchema, type SchemaCompatibilityTester } from "../simple-tree/index.js";
23
- import { isReadonlyArray } from "../util/index.js";
24
16
 
25
17
  import type { ITreeCheckout } from "./treeCheckout.js";
26
18
 
19
+ export function canInitialize(checkout: ITreeCheckout): boolean {
20
+ // Check for empty.
21
+ return checkout.forest.isEmpty && schemaDataIsEmpty(checkout.storedSchema);
22
+ }
23
+
27
24
  /**
28
- * Modify `storedSchema` and invoke `setInitialTree` when it's time to set the tree content.
29
- *
30
- * Requires `storedSchema` to be in its default/empty state.
31
- *
32
- * This is done in such a way that if the content (implicitly assumed to start empty)
33
- * is never out of schema.
34
- * This means that if the root field of the new schema requires content (like a value field),
35
- * a temporary intermediate schema is used so the initial empty state is not out of schema.
25
+ * Initialize a checkout with a schema and tree content.
26
+ * This function should only be called when the tree is uninitialized (no schema or content).
36
27
  *
37
- * Since this makes multiple changes, callers may want to wrap it in a transaction.
28
+ * @param checkout - The tree checkout to initialize.
29
+ * @param newSchema - The new schema to apply.
30
+ * @param contentFactory - A function that sets the initial tree content.
31
+ * Invoked after a schema containing all nodes from newSchema is applied.
32
+ * Note that the final root field schema may not have been applied yet: if the root is required, it will be optional at this time
33
+ * (so the root being empty before the insertion is not out of schema).
34
+ * @remarks
35
+ * If `newSchema` is not compatible with the empty tree, this function handles it using an intermediate schema
36
+ * which supports the empty tree as well as the final tree content.
37
+ * @privateRemarks
38
+ * This takes in a checkout using a subset of the checkout interface to enable easier unit testing.
38
39
  */
39
- export function initializeContent(
40
- schemaRepository: {
41
- storedSchema: ITreeCheckout["storedSchema"];
42
- updateSchema: ITreeCheckout["updateSchema"];
43
- },
40
+ export function initialize(
41
+ checkout: Pick<ITreeCheckout, "storedSchema" | "updateSchema">,
44
42
  newSchema: TreeStoredSchema,
45
43
  setInitialTree: () => void,
46
44
  ): void {
47
45
  assert(
48
- schemaDataIsEmpty(schemaRepository.storedSchema),
46
+ schemaDataIsEmpty(checkout.storedSchema),
49
47
  0x743 /* cannot initialize after a schema is set */,
50
48
  );
51
49
 
52
- const rootSchema = newSchema.rootFieldSchema;
53
- const rootKind = rootSchema.kind;
54
-
55
50
  // To keep the data in schema during the update, first define a schema that tolerates the current (empty) tree as well as the final (initial) tree.
56
- let incrementalSchemaUpdate: TreeStoredSchema;
57
- if (
58
- rootKind === FieldKinds.sequence.identifier ||
59
- rootKind === FieldKinds.optional.identifier
60
- ) {
61
- // These kinds are known to tolerate empty, so use the schema as is:
62
- incrementalSchemaUpdate = newSchema;
63
- } else {
64
- assert(rootKind === FieldKinds.required.identifier, 0x5c8 /* Unexpected kind */);
65
- // Replace value kind with optional kind in root field schema:
66
- incrementalSchemaUpdate = {
67
- nodeSchema: newSchema.nodeSchema,
68
- rootFieldSchema: {
69
- kind: FieldKinds.optional.identifier,
70
- types: rootSchema.types,
71
- persistedMetadata: rootSchema.persistedMetadata,
72
- },
73
- };
51
+ let intermediateSchema: TreeStoredSchema;
52
+ {
53
+ const rootSchema = newSchema.rootFieldSchema;
54
+ const rootKind = rootSchema.kind;
55
+ if (
56
+ rootKind === FieldKinds.sequence.identifier ||
57
+ rootKind === FieldKinds.optional.identifier
58
+ ) {
59
+ // These kinds are known to tolerate empty, so use the schema as is:
60
+ intermediateSchema = newSchema;
61
+ } else {
62
+ assert(rootKind === FieldKinds.required.identifier, 0x5c8 /* Unexpected kind */);
63
+ // Replace value kind with optional kind in root field schema:
64
+ intermediateSchema = {
65
+ nodeSchema: newSchema.nodeSchema,
66
+ rootFieldSchema: {
67
+ kind: FieldKinds.optional.identifier,
68
+ types: rootSchema.types,
69
+ persistedMetadata: rootSchema.persistedMetadata,
70
+ },
71
+ };
72
+ }
74
73
  }
75
74
 
76
75
  assert(
77
- allowsRepoSuperset(defaultSchemaPolicy, newSchema, incrementalSchemaUpdate),
76
+ allowsRepoSuperset(defaultSchemaPolicy, newSchema, intermediateSchema),
78
77
  0x5c9 /* Incremental Schema during update should allow a superset of the final schema */,
79
78
  );
80
- // Update to intermediate schema
81
- schemaRepository.updateSchema(incrementalSchemaUpdate);
82
- // Insert initial tree
79
+
80
+ checkout.updateSchema(intermediateSchema);
83
81
  setInitialTree();
84
82
 
85
83
  // If intermediate schema is not final desired schema, update to the final schema:
86
- if (incrementalSchemaUpdate !== newSchema) {
84
+ if (intermediateSchema !== newSchema) {
87
85
  // This makes the root more strict, so set allowNonSupersetSchema to true.
88
- schemaRepository.updateSchema(newSchema, true);
86
+ checkout.updateSchema(newSchema, true);
89
87
  }
90
88
  }
91
89
 
92
- export enum UpdateType {
93
- /**
94
- * Already compatible, no update needed.
95
- */
96
- None,
97
- /**
98
- * Schema can be upgraded leaving tree as is.
99
- */
100
- SchemaCompatible,
101
- /**
102
- * No update currently supported.
103
- */
104
- Incompatible,
105
- }
106
-
107
90
  /**
108
- * Returns how compatible updating checkout's schema is with the viewSchema.
109
- */
110
- export function evaluateUpdate(
111
- viewSchema: SchemaCompatibilityTester,
112
- checkout: ITreeCheckout,
113
- ): UpdateType {
114
- const compatibility = viewSchema.checkCompatibility(checkout.storedSchema);
115
-
116
- if (compatibility.canUpgrade && compatibility.canView) {
117
- // Compatible as is
118
- return UpdateType.None;
119
- }
120
-
121
- if (!compatibility.canUpgrade) {
122
- // Existing stored schema permits trees which are incompatible with the view schema, so schema can not be updated
123
- return UpdateType.Incompatible;
124
- }
125
-
126
- assert(!compatibility.canView, 0x8bd /* unexpected case */);
127
- assert(compatibility.canUpgrade, 0x8be /* unexpected case */);
128
-
129
- return UpdateType.SchemaCompatible;
130
- }
131
-
132
- export function canInitialize(checkout: ITreeCheckout): boolean {
133
- // Check for empty.
134
- return checkout.forest.isEmpty && schemaDataIsEmpty(checkout.storedSchema);
135
- }
136
-
137
- function normalizeNewFieldContent(
138
- content: readonly ITreeCursorSynchronous[] | ITreeCursorSynchronous | undefined,
139
- ): ITreeCursorSynchronous {
140
- if (content === undefined) {
141
- return cursorForMapTreeField([]);
142
- }
143
-
144
- if (isReadonlyArray(content)) {
145
- return cursorForMapTreeField(content.map((c) => mapTreeFromCursor(c)));
146
- }
147
-
148
- if (content.mode === CursorLocationType.Fields) {
149
- return content;
150
- }
151
-
152
- return cursorForMapTreeField([mapTreeFromCursor(content)]);
153
- }
154
-
155
- /**
156
- * Initialize a checkout with a schema and tree content.
157
- * This function should only be called when the tree is uninitialized (no schema or content).
158
- * @remarks
159
- *
160
- * If the proposed schema (from `treeContent`) is not compatible with the empty tree, this function handles using an intermediate schema
161
- * which supports the empty tree as well as the final tree content.
162
- */
163
- export function initialize(checkout: ITreeCheckout, treeContent: TreeStoredContent): void {
164
- checkout.transaction.start();
165
- try {
166
- initializeContent(checkout, treeContent.schema, () => {
167
- const field = { field: rootFieldKey, parent: undefined };
168
- const content = normalizeNewFieldContent(treeContent.initialTree);
169
- const contentChunk = checkout.forest.chunkField(content);
170
-
171
- switch (checkout.storedSchema.rootFieldSchema.kind) {
172
- case FieldKinds.optional.identifier: {
173
- const fieldEditor = checkout.editor.optionalField(field);
174
- assert(
175
- content.getFieldLength() <= 1,
176
- 0x7f4 /* optional field content should normalize at most one item */,
177
- );
178
- fieldEditor.set(contentChunk.topLevelLength === 0 ? undefined : contentChunk, true);
179
- break;
180
- }
181
- case FieldKinds.sequence.identifier: {
182
- const fieldEditor = checkout.editor.sequenceField(field);
183
- // TODO: should do an idempotent edit here.
184
- fieldEditor.insert(0, contentChunk);
185
- break;
186
- }
187
- default: {
188
- fail(0xac7 /* unexpected root field kind during initialize */);
189
- }
190
- }
191
- });
192
- } finally {
193
- checkout.transaction.commit();
194
- }
195
- }
196
-
197
- /**
198
- * Ensure a {@link ITreeCheckout} can be used with a given {@link SchemaCompatibilityTester}.
199
- *
91
+ * Construct a general purpose `setInitialTree` for use with {@link initialize} from a function that returns a chunk.
92
+ * @param contentFactory - A function that returns the initial tree content as a chunk.
93
+ * Invoked after a schema containing all nodes from newSchema is applied.
94
+ * Note that the final root field schema may not have been applied yet: if the root is required, it will be optional at this time
95
+ * (so the root being empty before the insertion is not out of schema).
200
96
  * @remarks
201
- * It is up to the caller to ensure that compatibility is reevaluated if the checkout's stored schema is edited in the future.
202
- *
203
- * @param viewSchema - View schema that `checkout` should be made compatible with.
204
- * @param allowedSchemaModifications - Flags enum describing the ways this is allowed to modify `checkout`.
205
- * @param checkout - To be modified as needed to be compatible with `viewSchema`.
206
- * @param treeContent - Content to be used to initialize `checkout`'s the tree if needed and allowed.
207
- * @returns true iff checkout now is compatible with `viewSchema`.
97
+ * This does not support sequence roots as they are not allowed in the public API surface.
98
+ * A test utility for them can be found as `initializeSequenceRoot` for testing internal logic which uses a sequence root.
208
99
  */
209
- export function ensureSchema(
210
- viewSchema: SchemaCompatibilityTester,
211
- checkout: ITreeCheckout,
212
- ): boolean {
213
- const updatedNeeded = evaluateUpdate(viewSchema, checkout);
214
- switch (updatedNeeded) {
215
- case UpdateType.None: {
216
- return true;
217
- }
218
- case UpdateType.Incompatible: {
219
- return false;
220
- }
221
- case UpdateType.SchemaCompatible: {
222
- checkout.updateSchema(toUpgradeSchema(viewSchema.viewSchema.root));
223
- return true;
224
- }
225
- default: {
226
- unreachableCase(updatedNeeded);
227
- }
228
- }
100
+ export function initializerFromChunk(
101
+ checkout: Pick<ITreeCheckout, "storedSchema"> & {
102
+ readonly editor: IDefaultEditBuilder;
103
+ },
104
+ contentFactory: () => TreeChunk,
105
+ ): () => void {
106
+ return () => initializeFromChunk(checkout, contentFactory());
229
107
  }
230
108
 
231
- /**
232
- * Content that can populate a `SharedTree`.
233
- */
234
- export interface TreeStoredContent {
235
- readonly schema: TreeStoredSchema;
236
-
237
- /**
238
- * Default tree content to initialize the tree with iff the tree is uninitialized
239
- * (meaning it does not even have any schema set at all).
240
- */
241
- readonly initialTree: readonly ITreeCursorSynchronous[] | ITreeCursorSynchronous | undefined;
109
+ function initializeFromChunk(
110
+ checkout: Pick<ITreeCheckout, "storedSchema"> & {
111
+ readonly editor: IDefaultEditBuilder;
112
+ },
113
+ contentChunk: TreeChunk,
114
+ ): void {
115
+ const field = { field: rootFieldKey, parent: undefined };
116
+ assert(
117
+ checkout.storedSchema.rootFieldSchema.kind === FieldKinds.optional.identifier,
118
+ 0xc11 /* initializerFromChunk only supports optional roots */,
119
+ );
120
+ const fieldEditor = checkout.editor.optionalField(field);
121
+ assert(
122
+ contentChunk.topLevelLength <= 1,
123
+ 0x7f4 /* optional field content should normalize at most one item */,
124
+ );
125
+ fieldEditor.set(contentChunk.topLevelLength === 0 ? undefined : contentChunk, true);
242
126
  }
@@ -16,7 +16,7 @@ import { anchorSlot } from "../core/index.js";
16
16
  import {
17
17
  type NodeIdentifierManager,
18
18
  defaultSchemaPolicy,
19
- cursorForMapTreeNode,
19
+ cursorForMapTreeField,
20
20
  TreeStatus,
21
21
  Context,
22
22
  } from "../feature-libraries/index.js";
@@ -55,6 +55,7 @@ import {
55
55
  FieldSchemaAlpha,
56
56
  TreeViewConfigurationAlpha,
57
57
  toInitialSchema,
58
+ toUpgradeSchema,
58
59
  } from "../simple-tree/index.js";
59
60
  import {
60
61
  type Breakable,
@@ -63,7 +64,7 @@ import {
63
64
  type WithBreakable,
64
65
  } from "../util/index.js";
65
66
 
66
- import { canInitialize, ensureSchema, initialize } from "./schematizeTree.js";
67
+ import { canInitialize, initialize, initializerFromChunk } from "./schematizeTree.js";
67
68
  import type { ITreeCheckout, TreeCheckout } from "./treeCheckout.js";
68
69
 
69
70
  /**
@@ -184,10 +185,19 @@ export class SchematizingSimpleTreeView<
184
185
  schema.rootFieldSchema,
185
186
  );
186
187
 
187
- initialize(this.checkout, {
188
+ this.checkout.transaction.start();
189
+
190
+ initialize(
191
+ this.checkout,
188
192
  schema,
189
- initialTree: mapTree === undefined ? undefined : cursorForMapTreeNode(mapTree),
190
- });
193
+ initializerFromChunk(this.checkout, () => {
194
+ // This must be done after initial schema is set!
195
+ return this.checkout.forest.chunkField(
196
+ cursorForMapTreeField(mapTree === undefined ? [] : [mapTree]),
197
+ );
198
+ }),
199
+ );
200
+ this.checkout.transaction.commit();
191
201
  });
192
202
  }
193
203
 
@@ -206,10 +216,8 @@ export class SchematizingSimpleTreeView<
206
216
  );
207
217
  }
208
218
 
209
- this.runSchemaEdit(() => {
210
- const result = ensureSchema(this.viewSchema, this.checkout);
211
- assert(result, 0x8bf /* Schema upgrade should always work if canUpgrade is set. */);
212
- });
219
+ const newSchema = toUpgradeSchema(this.viewSchema.viewSchema.root);
220
+ this.runSchemaEdit(() => this.checkout.updateSchema(newSchema));
213
221
  }
214
222
 
215
223
  /**
@@ -14,7 +14,8 @@ import {
14
14
  import type { GraphCommit, TaggedChange } from "../core/index.js";
15
15
  import { disposeSymbol, hasSome } from "../util/index.js";
16
16
 
17
- import type { ChangeEnricherReadonlyCheckout, ResubmitMachine } from "./index.js";
17
+ import type { ChangeEnricherReadonlyCheckout } from "./changeEnricher.js";
18
+ import type { ResubmitMachine } from "./resubmitMachine.js";
18
19
 
19
20
  interface PendingChange<TChange> {
20
21
  commit: GraphCommit<TChange>;
@@ -47,7 +47,10 @@ export type AllowedTypes = readonly LazyItem<TreeNodeSchema>[];
47
47
 
48
48
  /**
49
49
  * Stores annotations for an individual allowed type.
50
+ * @remarks
51
+ * Create using APIs on {@link SchemaFactoryAlpha}, like {@link SchemaStaticsAlpha.staged}.
50
52
  * @alpha
53
+ * @sealed
51
54
  */
52
55
  export interface AnnotatedAllowedType<T = LazyItem<TreeNodeSchema>> {
53
56
  /**
@@ -61,19 +64,12 @@ export interface AnnotatedAllowedType<T = LazyItem<TreeNodeSchema>> {
61
64
  }
62
65
 
63
66
  /**
64
- * Stores annotations for a set of evaluated annotated allowed types.
67
+ * {@link AnnotatedAllowedTypes} but with the lazy schema references eagerly evaluated.
68
+ * @sealed
65
69
  * @alpha
66
70
  */
67
- export interface NormalizedAnnotatedAllowedTypes {
68
- /**
69
- * Annotations that apply to a set of allowed types.
70
- */
71
- readonly metadata: AllowedTypesMetadata;
72
- /**
73
- * All the evaluated allowed types that the annotations apply to. The types themselves are also individually annotated.
74
- */
75
- readonly types: readonly AnnotatedAllowedType<TreeNodeSchema>[];
76
- }
71
+ export interface NormalizedAnnotatedAllowedTypes
72
+ extends AnnotatedAllowedTypes<TreeNodeSchema> {}
77
73
 
78
74
  /**
79
75
  * Checks if the input is an {@link AnnotatedAllowedTypes}.
@@ -91,8 +87,9 @@ export function isAnnotatedAllowedTypes(
91
87
  /**
92
88
  * Stores annotations for a set of allowed types.
93
89
  * @alpha
90
+ * @sealed
94
91
  */
95
- export interface AnnotatedAllowedTypes {
92
+ export interface AnnotatedAllowedTypes<T = LazyItem<TreeNodeSchema>> {
96
93
  /**
97
94
  * Annotations that apply to a set of allowed types.
98
95
  */
@@ -100,7 +97,7 @@ export interface AnnotatedAllowedTypes {
100
97
  /**
101
98
  * All the allowed types that the annotations apply to. The types themselves may also have individual annotations.
102
99
  */
103
- readonly types: readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[];
100
+ readonly types: readonly AnnotatedAllowedType<T>[];
104
101
  }
105
102
 
106
103
  /**
@@ -108,6 +105,7 @@ export interface AnnotatedAllowedTypes {
108
105
  * @remarks
109
106
  * Additional optionals may be added to this as non-breaking changes, so implementations of it should be simple object literals with no unlisted members.
110
107
  * @alpha
108
+ * @input
111
109
  */
112
110
  export interface AllowedTypesMetadata {
113
111
  /**
@@ -132,6 +130,7 @@ export function isAnnotatedAllowedType(
132
130
  * @remarks
133
131
  * Additional optionals may be added to this as non-breaking changes, so implementations of it should be simple object literals with no unlisted members.
134
132
  * @alpha
133
+ * @input
135
134
  */
136
135
  export interface AllowedTypeMetadata {
137
136
  /**
@@ -208,6 +207,7 @@ export type ImplicitAllowedTypes = AllowedTypes | TreeNodeSchema;
208
207
  * Types of {@link TreeNode|TreeNodes} or {@link TreeLeafValue|TreeLeafValues} allowed at a location in a tree with
209
208
  * additional metadata associated with the location they're allowed at.
210
209
  * @alpha
210
+ * @input
211
211
  */
212
212
  export type ImplicitAnnotatedAllowedTypes =
213
213
  | TreeNodeSchema
@@ -226,9 +226,18 @@ export type UnannotateImplicitAllowedTypes<T extends ImplicitAnnotatedAllowedTyp
226
226
  ? UnannotateAllowedTypesList<[T]>
227
227
  : T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]
228
228
  ? UnannotateAllowedTypesList<T>
229
- : T extends TreeNodeSchema
229
+ : // This should able to just return `T` here, however doing so breaks generic code in ArrayNode.
230
+ T extends TreeNodeSchema
230
231
  ? T
231
- : never;
232
+ : // Ideally this case would not be hit as it should be impossible.
233
+ // Due to limitations of TypeScript some generic code does depend on this case,
234
+ // so return a valid nonspecific schema in this otherwise unreachable case.
235
+ // This ensures that when this case is hit, the type system can still reason about it.
236
+ // It also ensures that if bugs cause this to matter in other cases, they will err on the side of restricting the API
237
+ // (due to non-specific schema) rather than being unsafe.
238
+ // This helps any such bugs be noticed more easily, be less likely to lead to runtime errors,
239
+ // and be more likely to be fixable as non-breaking changes.
240
+ ImplicitAllowedTypes;
232
241
 
233
242
  /**
234
243
  * Removes annotations from a list of allowed types that may contain annotations.
@@ -395,7 +404,7 @@ export function evaluateLazySchema<T extends TreeNodeSchema>(value: LazyItem<T>)
395
404
  * Throws a UsageError if the provided schema is undefined, most likely due to being used before it was initialized.
396
405
  */
397
406
  export function checkForUninitializedSchema(
398
- schema: ImplicitAnnotatedAllowedTypes | LazyItem<TreeNodeSchema>,
407
+ schema: ImplicitAnnotatedAllowedTypes | LazyItem<TreeNodeSchema> | AnnotatedAllowedType,
399
408
  ): void {
400
409
  if (schema === undefined) {
401
410
  throw new UsageError(
@@ -10,6 +10,7 @@ import { tryGetTreeNodeSchema } from "./treeNodeKernel.js";
10
10
  import { NodeKind, type TreeNodeSchemaClass } from "./treeNodeSchema.js";
11
11
  // eslint-disable-next-line import/no-deprecated
12
12
  import { type WithType, typeNameSymbol, type typeSchemaSymbol } from "./withType.js";
13
+ import { markEager } from "./flexList.js";
13
14
 
14
15
  /**
15
16
  * A non-{@link NodeKind.Leaf|leaf} SharedTree node. Includes objects, arrays, and maps.
@@ -37,13 +38,10 @@ import { type WithType, typeNameSymbol, type typeSchemaSymbol } from "./withType
37
38
  * @privateRemarks
38
39
  * This is a class not an interface to enable stricter type checking (see {@link TreeNode.#brand})
39
40
  * and some runtime enforcement of schema class policy (see the the validation in the constructor).
40
- * This class is however only `type` exported not value exported, preventing the class object from being used,
41
- * similar to how interfaces work.
42
41
  *
43
42
  * Not all node implementations include this in their prototype chain (some hide it with a proxy),
44
43
  * and thus cause the default/built in `instanceof` to return false despite our type checking and all other APIs treating them as TreeNodes.
45
44
  * This class provides a custom `Symbol.hasInstance` to fix `instanceof` for this class and all classes extending it.
46
- * For now the type-only export prevents use of `instanceof` on this class (but allows it in subclasses like schema classes).
47
45
  * @sealed @public
48
46
  */
49
47
  export abstract class TreeNode implements WithType {
@@ -138,6 +136,8 @@ export abstract class TreeNode implements WithType {
138
136
  }
139
137
  }
140
138
  }
139
+ // Class objects are functions (callable), so we need a strong way to distinguish between `schema` and `() => schema` when used as a `LazyItem`.
140
+ markEager(TreeNode);
141
141
 
142
142
  /**
143
143
  * `token` to pass to {@link TreeNode}'s constructor used to detect invalid subclasses.
@@ -8,7 +8,6 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal";
8
8
 
9
9
  import { type FlexTreeNode, isFlexTreeNode } from "../../feature-libraries/index.js";
10
10
 
11
- import { markEager } from "./flexList.js";
12
11
  import { inPrototypeChain, privateToken, TreeNode } from "./treeNode.js";
13
12
  import { UnhydratedFlexTreeNode } from "./unhydratedFlexTree.js";
14
13
  import {
@@ -209,8 +208,6 @@ export abstract class TreeNodeValid<TInput> extends TreeNode {
209
208
  return result;
210
209
  }
211
210
  }
212
- // Class objects are functions (callable), so we need a strong way to distinguish between `schema` and `() => schema` when used as a `LazyItem`.
213
- markEager(TreeNodeValid);
214
211
 
215
212
  /**
216
213
  * Data cached about the most derived type in a schema's class hierarchy.
@@ -620,8 +620,9 @@ function arePersistedMetadataEqual(
620
620
  export type ImplicitFieldSchema = FieldSchema | ImplicitAllowedTypes;
621
621
 
622
622
  /**
623
- * Annotated schema for a field of a tree node.
623
+ * {@link ImplicitFieldSchema} which supports {@link AnnotatedAllowedTypes | annotations} on the allowed types.
624
624
  * @alpha
625
+ * @input
625
626
  */
626
627
  export type ImplicitAnnotatedFieldSchema = FieldSchema | ImplicitAnnotatedAllowedTypes;
627
628
 
@@ -14,9 +14,7 @@ export {
14
14
  type TreeNodeSchemaClass,
15
15
  type TreeNodeSchemaNonClass,
16
16
  type TreeNodeSchemaCore,
17
- // TreeNode is only type exported, which prevents use of the class object for unsupported use-cases like direct sub-classing and instanceof.
18
- // See docs on TreeNode for more details.
19
- type TreeNode,
17
+ TreeNode,
20
18
  type Unhydrated,
21
19
  type InternalTreeNode,
22
20
  isTreeNode,