@fluidframework/tree 2.41.0-337492 → 2.41.0-338186

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 (180) hide show
  1. package/api-report/tree.alpha.api.md +1 -1
  2. package/dist/feature-libraries/flex-tree/context.d.ts +16 -14
  3. package/dist/feature-libraries/flex-tree/context.d.ts.map +1 -1
  4. package/dist/feature-libraries/flex-tree/context.js +12 -18
  5. package/dist/feature-libraries/flex-tree/context.js.map +1 -1
  6. package/dist/feature-libraries/flex-tree/index.d.ts +1 -1
  7. package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
  8. package/dist/feature-libraries/flex-tree/index.js +1 -2
  9. package/dist/feature-libraries/flex-tree/index.js.map +1 -1
  10. package/dist/feature-libraries/flex-tree/lazyField.d.ts +1 -5
  11. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  12. package/dist/feature-libraries/flex-tree/lazyField.js +2 -16
  13. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  14. package/dist/feature-libraries/flex-tree/utilities.d.ts +6 -6
  15. package/dist/feature-libraries/flex-tree/utilities.d.ts.map +1 -1
  16. package/dist/feature-libraries/flex-tree/utilities.js +6 -7
  17. package/dist/feature-libraries/flex-tree/utilities.js.map +1 -1
  18. package/dist/feature-libraries/index.d.ts +1 -1
  19. package/dist/feature-libraries/index.d.ts.map +1 -1
  20. package/dist/feature-libraries/index.js +1 -2
  21. package/dist/feature-libraries/index.js.map +1 -1
  22. package/dist/packageVersion.d.ts +1 -1
  23. package/dist/packageVersion.js +1 -1
  24. package/dist/packageVersion.js.map +1 -1
  25. package/dist/shared-tree/checkoutFlexTreeView.d.ts +7 -3
  26. package/dist/shared-tree/checkoutFlexTreeView.d.ts.map +1 -1
  27. package/dist/shared-tree/checkoutFlexTreeView.js +11 -2
  28. package/dist/shared-tree/checkoutFlexTreeView.js.map +1 -1
  29. package/dist/shared-tree/schematizingTreeView.d.ts +3 -0
  30. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  31. package/dist/shared-tree/schematizingTreeView.js +10 -5
  32. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  33. package/dist/shared-tree/treeAlpha.d.ts +1 -4
  34. package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
  35. package/dist/shared-tree/treeAlpha.js +6 -1
  36. package/dist/shared-tree/treeAlpha.js.map +1 -1
  37. package/dist/simple-tree/api/create.d.ts +5 -1
  38. package/dist/simple-tree/api/create.d.ts.map +1 -1
  39. package/dist/simple-tree/api/create.js +10 -11
  40. package/dist/simple-tree/api/create.js.map +1 -1
  41. package/dist/simple-tree/api/index.d.ts +2 -2
  42. package/dist/simple-tree/api/index.d.ts.map +1 -1
  43. package/dist/simple-tree/api/index.js +2 -2
  44. package/dist/simple-tree/api/index.js.map +1 -1
  45. package/dist/simple-tree/api/storedSchema.d.ts +1 -8
  46. package/dist/simple-tree/api/storedSchema.d.ts.map +1 -1
  47. package/dist/simple-tree/api/storedSchema.js +3 -14
  48. package/dist/simple-tree/api/storedSchema.js.map +1 -1
  49. package/dist/simple-tree/arrayNode.d.ts.map +1 -1
  50. package/dist/simple-tree/arrayNode.js +3 -9
  51. package/dist/simple-tree/arrayNode.js.map +1 -1
  52. package/dist/simple-tree/core/unhydratedFlexTree.d.ts +4 -4
  53. package/dist/simple-tree/core/unhydratedFlexTree.js +4 -4
  54. package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  55. package/dist/simple-tree/index.d.ts +3 -2
  56. package/dist/simple-tree/index.d.ts.map +1 -1
  57. package/dist/simple-tree/index.js +6 -4
  58. package/dist/simple-tree/index.js.map +1 -1
  59. package/dist/simple-tree/mapNode.d.ts.map +1 -1
  60. package/dist/simple-tree/mapNode.js +17 -20
  61. package/dist/simple-tree/mapNode.js.map +1 -1
  62. package/dist/simple-tree/objectNode.d.ts.map +1 -1
  63. package/dist/simple-tree/objectNode.js +2 -4
  64. package/dist/simple-tree/objectNode.js.map +1 -1
  65. package/dist/simple-tree/prepareForInsertion.d.ts +30 -0
  66. package/dist/simple-tree/prepareForInsertion.d.ts.map +1 -0
  67. package/dist/simple-tree/prepareForInsertion.js +137 -0
  68. package/dist/simple-tree/prepareForInsertion.js.map +1 -0
  69. package/dist/simple-tree/proxies.d.ts +1 -12
  70. package/dist/simple-tree/proxies.d.ts.map +1 -1
  71. package/dist/simple-tree/proxies.js +10 -106
  72. package/dist/simple-tree/proxies.js.map +1 -1
  73. package/dist/simple-tree/toMapTree.d.ts +1 -1
  74. package/dist/simple-tree/toMapTree.js +1 -1
  75. package/dist/simple-tree/toMapTree.js.map +1 -1
  76. package/dist/tableSchema.d.ts +93 -43
  77. package/dist/tableSchema.d.ts.map +1 -1
  78. package/dist/tableSchema.js +72 -22
  79. package/dist/tableSchema.js.map +1 -1
  80. package/lib/feature-libraries/flex-tree/context.d.ts +16 -14
  81. package/lib/feature-libraries/flex-tree/context.d.ts.map +1 -1
  82. package/lib/feature-libraries/flex-tree/context.js +11 -16
  83. package/lib/feature-libraries/flex-tree/context.js.map +1 -1
  84. package/lib/feature-libraries/flex-tree/index.d.ts +1 -1
  85. package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
  86. package/lib/feature-libraries/flex-tree/index.js +1 -1
  87. package/lib/feature-libraries/flex-tree/index.js.map +1 -1
  88. package/lib/feature-libraries/flex-tree/lazyField.d.ts +1 -5
  89. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  90. package/lib/feature-libraries/flex-tree/lazyField.js +1 -14
  91. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  92. package/lib/feature-libraries/flex-tree/utilities.d.ts +6 -6
  93. package/lib/feature-libraries/flex-tree/utilities.d.ts.map +1 -1
  94. package/lib/feature-libraries/flex-tree/utilities.js +6 -7
  95. package/lib/feature-libraries/flex-tree/utilities.js.map +1 -1
  96. package/lib/feature-libraries/index.d.ts +1 -1
  97. package/lib/feature-libraries/index.d.ts.map +1 -1
  98. package/lib/feature-libraries/index.js +1 -1
  99. package/lib/feature-libraries/index.js.map +1 -1
  100. package/lib/packageVersion.d.ts +1 -1
  101. package/lib/packageVersion.js +1 -1
  102. package/lib/packageVersion.js.map +1 -1
  103. package/lib/shared-tree/checkoutFlexTreeView.d.ts +7 -3
  104. package/lib/shared-tree/checkoutFlexTreeView.d.ts.map +1 -1
  105. package/lib/shared-tree/checkoutFlexTreeView.js +12 -3
  106. package/lib/shared-tree/checkoutFlexTreeView.js.map +1 -1
  107. package/lib/shared-tree/schematizingTreeView.d.ts +3 -0
  108. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  109. package/lib/shared-tree/schematizingTreeView.js +11 -6
  110. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  111. package/lib/shared-tree/treeAlpha.d.ts +1 -4
  112. package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
  113. package/lib/shared-tree/treeAlpha.js +7 -2
  114. package/lib/shared-tree/treeAlpha.js.map +1 -1
  115. package/lib/simple-tree/api/create.d.ts +5 -1
  116. package/lib/simple-tree/api/create.d.ts.map +1 -1
  117. package/lib/simple-tree/api/create.js +8 -10
  118. package/lib/simple-tree/api/create.js.map +1 -1
  119. package/lib/simple-tree/api/index.d.ts +2 -2
  120. package/lib/simple-tree/api/index.d.ts.map +1 -1
  121. package/lib/simple-tree/api/index.js +2 -2
  122. package/lib/simple-tree/api/index.js.map +1 -1
  123. package/lib/simple-tree/api/storedSchema.d.ts +1 -8
  124. package/lib/simple-tree/api/storedSchema.d.ts.map +1 -1
  125. package/lib/simple-tree/api/storedSchema.js +2 -12
  126. package/lib/simple-tree/api/storedSchema.js.map +1 -1
  127. package/lib/simple-tree/arrayNode.d.ts.map +1 -1
  128. package/lib/simple-tree/arrayNode.js +4 -10
  129. package/lib/simple-tree/arrayNode.js.map +1 -1
  130. package/lib/simple-tree/core/unhydratedFlexTree.d.ts +4 -4
  131. package/lib/simple-tree/core/unhydratedFlexTree.js +4 -4
  132. package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  133. package/lib/simple-tree/index.d.ts +3 -2
  134. package/lib/simple-tree/index.d.ts.map +1 -1
  135. package/lib/simple-tree/index.js +3 -2
  136. package/lib/simple-tree/index.js.map +1 -1
  137. package/lib/simple-tree/mapNode.d.ts.map +1 -1
  138. package/lib/simple-tree/mapNode.js +3 -6
  139. package/lib/simple-tree/mapNode.js.map +1 -1
  140. package/lib/simple-tree/objectNode.d.ts.map +1 -1
  141. package/lib/simple-tree/objectNode.js +4 -6
  142. package/lib/simple-tree/objectNode.js.map +1 -1
  143. package/lib/simple-tree/prepareForInsertion.d.ts +30 -0
  144. package/lib/simple-tree/prepareForInsertion.d.ts.map +1 -0
  145. package/lib/simple-tree/prepareForInsertion.js +131 -0
  146. package/lib/simple-tree/prepareForInsertion.js.map +1 -0
  147. package/lib/simple-tree/proxies.d.ts +1 -12
  148. package/lib/simple-tree/proxies.d.ts.map +1 -1
  149. package/lib/simple-tree/proxies.js +1 -96
  150. package/lib/simple-tree/proxies.js.map +1 -1
  151. package/lib/simple-tree/toMapTree.d.ts +1 -1
  152. package/lib/simple-tree/toMapTree.js +1 -1
  153. package/lib/simple-tree/toMapTree.js.map +1 -1
  154. package/lib/tableSchema.d.ts +93 -43
  155. package/lib/tableSchema.d.ts.map +1 -1
  156. package/lib/tableSchema.js +73 -23
  157. package/lib/tableSchema.js.map +1 -1
  158. package/lib/tsdoc-metadata.json +1 -1
  159. package/package.json +25 -25
  160. package/src/feature-libraries/flex-tree/context.ts +18 -20
  161. package/src/feature-libraries/flex-tree/index.ts +0 -1
  162. package/src/feature-libraries/flex-tree/lazyField.ts +2 -14
  163. package/src/feature-libraries/flex-tree/utilities.ts +8 -8
  164. package/src/feature-libraries/index.ts +0 -1
  165. package/src/packageVersion.ts +1 -1
  166. package/src/shared-tree/checkoutFlexTreeView.ts +10 -6
  167. package/src/shared-tree/schematizingTreeView.ts +11 -12
  168. package/src/shared-tree/treeAlpha.ts +21 -5
  169. package/src/simple-tree/api/create.ts +15 -15
  170. package/src/simple-tree/api/index.ts +6 -2
  171. package/src/simple-tree/api/storedSchema.ts +2 -19
  172. package/src/simple-tree/arrayNode.ts +9 -20
  173. package/src/simple-tree/core/unhydratedFlexTree.ts +4 -4
  174. package/src/simple-tree/index.ts +6 -5
  175. package/src/simple-tree/mapNode.ts +8 -12
  176. package/src/simple-tree/objectNode.ts +3 -12
  177. package/src/simple-tree/prepareForInsertion.ts +236 -0
  178. package/src/simple-tree/proxies.ts +2 -147
  179. package/src/simple-tree/toMapTree.ts +1 -1
  180. package/src/tableSchema.ts +243 -77
@@ -79,7 +79,6 @@ export {
79
79
  extractPersistedSchema,
80
80
  comparePersistedSchema,
81
81
  type ConciseTree,
82
- comparePersistedSchemaInternal,
83
82
  SchemaCompatibilityTester,
84
83
  type Unenforced,
85
84
  type System_Unsafe,
@@ -123,6 +122,7 @@ export {
123
122
  type FixRecursiveRecursionLimit,
124
123
  schemaStatics,
125
124
  type TreeChangeEvents,
125
+ createFromMapTree,
126
126
  } from "./api/index.js";
127
127
  export type {
128
128
  SimpleTreeSchema,
@@ -184,10 +184,7 @@ export {
184
184
  type NodeSchemaMetadata,
185
185
  evaluateLazySchema,
186
186
  } from "./schemaTypes.js";
187
- export {
188
- getTreeNodeForField,
189
- prepareContentForHydration,
190
- } from "./proxies.js";
187
+ export { getTreeNodeForField } from "./proxies.js";
191
188
  export {
192
189
  TreeArrayNode,
193
190
  IterableTreeArrayContent,
@@ -220,6 +217,10 @@ export {
220
217
  type FactoryContent,
221
218
  type FactoryContentObject,
222
219
  } from "./toMapTree.js";
220
+ export {
221
+ prepareForInsertion,
222
+ prepareForInsertionContextless,
223
+ } from "./prepareForInsertion.js";
223
224
  export { toStoredSchema, getStoredSchema } from "./toStoredSchema.js";
224
225
  export {
225
226
  numberSchema,
@@ -4,13 +4,12 @@
4
4
  */
5
5
 
6
6
  import { Lazy } from "@fluidframework/core-utils/internal";
7
- import {
8
- type FlexTreeNode,
9
- type FlexTreeOptionalField,
10
- type OptionalFieldEditBuilder,
11
- getSchemaAndPolicy,
7
+ import type {
8
+ FlexTreeNode,
9
+ FlexTreeOptionalField,
10
+ OptionalFieldEditBuilder,
12
11
  } from "../feature-libraries/index.js";
13
- import { getTreeNodeForField, prepareContentForHydration } from "./proxies.js";
12
+ import { getTreeNodeForField } from "./proxies.js";
14
13
  import {
15
14
  createFieldSchema,
16
15
  FieldKind,
@@ -42,6 +41,7 @@ import {
42
41
  type FactoryContent,
43
42
  type InsertableContent,
44
43
  } from "./toMapTree.js";
44
+ import { prepareForInsertion } from "./prepareForInsertion.js";
45
45
  import { brand, count, type RestrictiveStringRecord } from "../util/index.js";
46
46
  import { TreeNodeValid, type MostDerivedData } from "./treeNodeValid.js";
47
47
  import type { ExclusiveMapTree } from "../core/index.js";
@@ -191,17 +191,13 @@ abstract class CustomMapNodeBase<const T extends ImplicitAllowedTypes> extends T
191
191
  public set(key: string, value: InsertableTreeNodeFromImplicitAllowedTypes<T>): this {
192
192
  const kernel = getKernel(this);
193
193
  const node = this.innerNode;
194
- const mapTree = mapTreeFromNodeData(
194
+ const mapTree = prepareForInsertion(
195
195
  value as InsertableContent | undefined,
196
196
  createFieldSchema(FieldKind.Optional, kernel.schema.info as ImplicitAllowedTypes),
197
- node.context.isHydrated() ? node.context.nodeKeyManager : undefined,
198
- getSchemaAndPolicy(node),
197
+ node.context,
199
198
  );
200
199
 
201
200
  const field = node.getBoxed(brand(key));
202
- if (node.context.isHydrated()) {
203
- prepareContentForHydration(mapTree, node.context.checkout.forest);
204
- }
205
201
 
206
202
  this.editor(key).set(mapTree, field.length === 0);
207
203
  return this;
@@ -13,9 +13,8 @@ import {
13
13
  type FlexTreeNode,
14
14
  type FlexTreeOptionalField,
15
15
  type FlexTreeRequiredField,
16
- getSchemaAndPolicy,
17
16
  } from "../feature-libraries/index.js";
18
- import { getTreeNodeForField, prepareContentForHydration } from "./proxies.js";
17
+ import { getTreeNodeForField } from "./proxies.js";
19
18
  import {
20
19
  type ImplicitFieldSchema,
21
20
  getStoredKey,
@@ -47,6 +46,7 @@ import {
47
46
  getOrCreateInnerNode,
48
47
  } from "./core/index.js";
49
48
  import { mapTreeFromNodeData, type InsertableContent } from "./toMapTree.js";
49
+ import { prepareForInsertion } from "./prepareForInsertion.js";
50
50
  import type { RestrictiveStringRecord, FlattenKeys } from "../util/index.js";
51
51
  import {
52
52
  isObjectNodeSchema,
@@ -328,16 +328,7 @@ export function setField(
328
328
  simpleFieldSchema: FieldSchema,
329
329
  value: InsertableContent | undefined,
330
330
  ): void {
331
- const mapTree = mapTreeFromNodeData(
332
- value,
333
- simpleFieldSchema,
334
- field.context.isHydrated() ? field.context.nodeKeyManager : undefined,
335
- getSchemaAndPolicy(field),
336
- );
337
-
338
- if (field.context.isHydrated()) {
339
- prepareContentForHydration(mapTree, field.context.checkout.forest);
340
- }
331
+ const mapTree = prepareForInsertion(value, simpleFieldSchema, field.context);
341
332
 
342
333
  switch (field.schema) {
343
334
  case FieldKinds.required.identifier: {
@@ -0,0 +1,236 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import type {
7
+ ExclusiveMapTree,
8
+ SchemaAndPolicy,
9
+ IForestSubscription,
10
+ MapTree,
11
+ UpPath,
12
+ NodeIndex,
13
+ FieldKey,
14
+ DetachedField,
15
+ } from "../core/index.js";
16
+ import {
17
+ type FlexTreeContext,
18
+ getSchemaAndPolicy,
19
+ type FlexTreeHydratedContext,
20
+ } from "../feature-libraries/index.js";
21
+ import type { ImplicitAllowedTypes, ImplicitFieldSchema } from "./schemaTypes.js";
22
+ import { type InsertableContent, mapTreeFromNodeData } from "./toMapTree.js";
23
+ import { UsageError } from "@fluidframework/telemetry-utils/internal";
24
+ import { brand } from "../util/index.js";
25
+ import {
26
+ getKernel,
27
+ type TreeNode,
28
+ tryUnhydratedFlexTreeNode,
29
+ unhydratedFlexTreeNodeToTreeNode,
30
+ } from "./core/index.js";
31
+ import { debugAssert } from "@fluidframework/core-utils/internal";
32
+
33
+ /**
34
+ * Prepare content from a user for insertion into a tree.
35
+ * @remarks
36
+ * This validates and converts the input, and if necessary invokes {@link prepareContentForHydration}.
37
+ */
38
+ export function prepareForInsertion<TIn extends InsertableContent | undefined>(
39
+ data: TIn,
40
+ schema: ImplicitFieldSchema,
41
+ destinationContext: FlexTreeContext,
42
+ ): TIn extends undefined ? undefined : ExclusiveMapTree {
43
+ return prepareForInsertionContextless(
44
+ data,
45
+ schema,
46
+ getSchemaAndPolicy(destinationContext),
47
+ destinationContext.isHydrated() ? destinationContext : undefined,
48
+ );
49
+ }
50
+
51
+ /**
52
+ * {@link prepareForInsertion} but batched for array content.
53
+ * @privateRemarks
54
+ * TODO:
55
+ * Experimentally it was determined that making separate calls to prepareContentForHydration for each array item did not work.
56
+ * This should be understood and fixed or have the factors that cause it clearly documented.
57
+ * If fixed, this function should be removed, and arrays can just map over prepareForInsertion.
58
+ */
59
+ export function prepareArrayForInsertion(
60
+ data: readonly InsertableContent[],
61
+ schema: ImplicitAllowedTypes,
62
+ destinationContext: FlexTreeContext,
63
+ ): ExclusiveMapTree[] {
64
+ const mapTrees: ExclusiveMapTree[] = data.map((item) =>
65
+ mapTreeFromNodeData(
66
+ item,
67
+ schema,
68
+ destinationContext.isHydrated() ? destinationContext.nodeKeyManager : undefined,
69
+ getSchemaAndPolicy(destinationContext),
70
+ ),
71
+ );
72
+
73
+ if (destinationContext.isHydrated()) {
74
+ prepareContentForHydration(mapTrees, destinationContext.checkout.forest);
75
+ }
76
+
77
+ return mapTrees;
78
+ }
79
+
80
+ /**
81
+ * Split out from {@link prepareForInsertion} as to allow use without a context.
82
+ * @remarks
83
+ * Adding this entry point is a workaround for initialize not currently having a context.
84
+ */
85
+ export function prepareForInsertionContextless<TIn extends InsertableContent | undefined>(
86
+ data: TIn,
87
+ schema: ImplicitFieldSchema,
88
+ schemaAndPolicy: SchemaAndPolicy,
89
+ hydratedData: Pick<FlexTreeHydratedContext, "checkout" | "nodeKeyManager"> | undefined,
90
+ ): TIn extends undefined ? undefined : ExclusiveMapTree {
91
+ const mapTree = mapTreeFromNodeData(
92
+ data,
93
+ schema,
94
+ hydratedData?.nodeKeyManager,
95
+ schemaAndPolicy,
96
+ );
97
+
98
+ if (mapTree !== undefined && hydratedData !== undefined) {
99
+ prepareContentForHydration([mapTree], hydratedData.checkout.forest);
100
+ }
101
+
102
+ return mapTree as TIn extends undefined ? undefined : ExclusiveMapTree;
103
+ }
104
+
105
+ /**
106
+ * An {@link UpPath} that is just index zero in a {@link DetachedField} which can be modified at a later time.
107
+ */
108
+ interface Root extends UpPath {
109
+ readonly parent: undefined;
110
+ parentField: DetachedField & FieldKey;
111
+ readonly parentIndex: NodeIndex & 0;
112
+ }
113
+
114
+ /**
115
+ * The path from the included node to the root of the content tree it was inserted as part of.
116
+ */
117
+ interface RelativeNodePath {
118
+ readonly path: UpPath;
119
+ readonly node: TreeNode;
120
+ }
121
+
122
+ /**
123
+ * {@link RelativeNodePath}s for every {@link TreeNode} in the content tree inserted as an atomic operation.
124
+ */
125
+ interface LocatedNodesBatch {
126
+ /**
127
+ * UpPath shared by all {@link RelativeNodePath}s in this batch corresponding to the root of the inserted content.
128
+ */
129
+ readonly rootPath: Root;
130
+ readonly paths: RelativeNodePath[];
131
+ }
132
+
133
+ /**
134
+ * A dummy key value used in {@link LocatedNodesBatch.rootPath} which will be replaced with the actual detached field once it is known.
135
+ */
136
+ const placeholderKey: DetachedField & FieldKey = brand("placeholder" as const);
137
+
138
+ /**
139
+ * Records any proxies in the given content tree and does the necessary bookkeeping to ensure they are synchronized with subsequent reads of the tree.
140
+ * @remarks If the content tree contains any proxies, this function must be called just prior to inserting the content into the tree.
141
+ * Specifically, no other content may be inserted into the tree between the invocation of this function and the insertion of `content`.
142
+ * The insertion of `content` must occur or else this function will cause memory leaks.
143
+ * @param content - the content subsequence to be inserted, of which might deeply contain {@link TreeNode}s which need to be hydrated.
144
+ * @param forest - the forest the content is being inserted into.
145
+ * See {@link extractFactoryContent} for more details.
146
+ */
147
+ function prepareContentForHydration(
148
+ content: readonly MapTree[],
149
+ forest: IForestSubscription,
150
+ ): void {
151
+ const batches: LocatedNodesBatch[] = [];
152
+ for (const item of content) {
153
+ const batch: LocatedNodesBatch = {
154
+ rootPath: {
155
+ parent: undefined,
156
+ parentField: placeholderKey,
157
+ parentIndex: 0,
158
+ },
159
+ paths: [],
160
+ };
161
+ batches.push(batch);
162
+ walkMapTree(item, batch.rootPath, (p, node) => {
163
+ batch.paths.push({ path: p, node });
164
+ });
165
+ }
166
+
167
+ bindTreeNodes(batches, forest);
168
+ }
169
+
170
+ function walkMapTree(
171
+ mapTree: MapTree,
172
+ path: UpPath,
173
+ onVisitTreeNode: (path: UpPath, treeNode: TreeNode) => void,
174
+ ): void {
175
+ if (tryUnhydratedFlexTreeNode(mapTree)?.parentField.parent.parent !== undefined) {
176
+ throw new UsageError(
177
+ "Attempted to insert a node which is already under a parent. If this is desired, remove the node from its parent before inserting it elsewhere.",
178
+ );
179
+ }
180
+
181
+ type Next = [path: UpPath, tree: MapTree];
182
+ const nexts: Next[] = [];
183
+ for (let next: Next | undefined = [path, mapTree]; next !== undefined; next = nexts.pop()) {
184
+ const [p, m] = next;
185
+ const mapTreeNode = tryUnhydratedFlexTreeNode(m);
186
+ if (mapTreeNode !== undefined) {
187
+ const treeNode = unhydratedFlexTreeNodeToTreeNode.get(mapTreeNode);
188
+ if (treeNode !== undefined) {
189
+ onVisitTreeNode(p, treeNode);
190
+ }
191
+ }
192
+
193
+ for (const [key, field] of m.fields) {
194
+ for (const [i, child] of field.entries()) {
195
+ nexts.push([
196
+ {
197
+ parent: p,
198
+ parentField: key,
199
+ parentIndex: i,
200
+ },
201
+ child,
202
+ ]);
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Register a collection of nodes with the forest so that they can be hydrated.
210
+ * @param locatedNodes - the nodes to register with the forest.
211
+ * Each index in this array expects its content to be added and produce its own `afterRootFieldCreated` event.
212
+ * If array subsequence insertion is optimized to produce a single event, this will not work correctly as is, and will need to be modified to take in a single {@link LocatedNodesBatch}.
213
+ */
214
+ function bindTreeNodes(
215
+ locatedNodes: readonly LocatedNodesBatch[],
216
+ forest: IForestSubscription,
217
+ ): void {
218
+ // Only subscribe to the event if there is at least one TreeNode tree to hydrate - this is not the case when inserting an empty array [].
219
+ if (locatedNodes.length > 0) {
220
+ // Creating a new array emits one event per element in the array, so listen to the event once for each element
221
+ let i = 0;
222
+ const off = forest.events.on("afterRootFieldCreated", (fieldKey) => {
223
+ // Non null asserting here because of the length check above
224
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
225
+ const batch = locatedNodes[i]!;
226
+ debugAssert(() => batch.rootPath.parentField === placeholderKey);
227
+ batch.rootPath.parentField = brand(fieldKey);
228
+ for (const { path, node } of batch.paths) {
229
+ getKernel(node).anchorProxy(forest.anchors, path);
230
+ }
231
+ if (++i === locatedNodes.length) {
232
+ off();
233
+ }
234
+ });
235
+ }
236
+ }
@@ -3,16 +3,8 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { UsageError } from "@fluidframework/telemetry-utils/internal";
7
6
  import { fail } from "@fluidframework/core-utils/internal";
8
- import {
9
- EmptyKey,
10
- type IForestSubscription,
11
- type MapTree,
12
- type TreeValue,
13
- type UpPath,
14
- } from "../core/index.js";
15
-
7
+ import type { TreeValue } from "../core/index.js";
16
8
  import {
17
9
  FieldKinds,
18
10
  type FlexTreeField,
@@ -20,14 +12,7 @@ import {
20
12
  type FlexTreeRequiredField,
21
13
  type FlexTreeOptionalField,
22
14
  } from "../feature-libraries/index.js";
23
- import { type Mutable, isReadonlyArray } from "../util/index.js";
24
- import {
25
- getKernel,
26
- type TreeNode,
27
- getOrCreateNodeFromInnerNode,
28
- tryUnhydratedFlexTreeNode,
29
- unhydratedFlexTreeNodeToTreeNode,
30
- } from "./core/index.js";
15
+ import { type TreeNode, getOrCreateNodeFromInnerNode } from "./core/index.js";
31
16
 
32
17
  /**
33
18
  * Retrieve the associated {@link TreeNode} for the given field's content.
@@ -59,133 +44,3 @@ export function getTreeNodeForField(field: FlexTreeField): TreeNode | TreeValue
59
44
  fail(0xadf /* invalid field kind */);
60
45
  }
61
46
  }
62
-
63
- // #region Content insertion and proxy binding
64
-
65
- /** The path of a proxy, relative to the root of the content tree that the proxy belongs to */
66
- interface RelativeProxyPath {
67
- readonly path: UpPath;
68
- readonly proxy: TreeNode;
69
- }
70
-
71
- /** All {@link RelativeProxyPath}s that are under the given root path */
72
- interface RootedProxyPaths {
73
- readonly rootPath: UpPath;
74
- readonly proxyPaths: RelativeProxyPath[];
75
- }
76
-
77
- /**
78
- * Records any proxies in the given content tree and does the necessary bookkeeping to ensure they are synchronized with subsequent reads of the tree.
79
- * @remarks If the content tree contains any proxies, this function must be called just prior to inserting the content into the tree.
80
- * Specifically, no other content may be inserted into the tree between the invocation of this function and the insertion of `content`.
81
- * The insertion of `content` must occur or else this function will cause memory leaks.
82
- * @param content - the tree of content to be inserted, of which any of its object/map/array nodes might be a proxy
83
- * @param anchors - the {@link AnchorSet} for the tree
84
- * @returns The content after having all proxies replaced inline with plain javascript objects.
85
- * See {@link extractFactoryContent} for more details.
86
- */
87
- export function prepareContentForHydration(
88
- content: MapTree | readonly MapTree[] | undefined,
89
- forest: IForestSubscription,
90
- ): void {
91
- if (isReadonlyArray(content)) {
92
- return prepareArrayContentForHydration(content, forest);
93
- }
94
-
95
- if (content !== undefined) {
96
- const proxies: RootedProxyPaths = {
97
- rootPath: { parent: undefined, parentField: EmptyKey, parentIndex: 0 },
98
- proxyPaths: [],
99
- };
100
-
101
- walkMapTree(content, proxies.rootPath, (p, proxy) => {
102
- proxies.proxyPaths.push({ path: p, proxy });
103
- });
104
-
105
- bindProxies([proxies], forest);
106
- }
107
- }
108
-
109
- function prepareArrayContentForHydration(
110
- content: readonly MapTree[],
111
- forest: IForestSubscription,
112
- ): void {
113
- const proxyPaths: RootedProxyPaths[] = [];
114
- for (const item of content) {
115
- const proxyPath: RootedProxyPaths = {
116
- rootPath: {
117
- parent: undefined,
118
- parentField: EmptyKey,
119
- parentIndex: 0,
120
- },
121
- proxyPaths: [],
122
- };
123
- proxyPaths.push(proxyPath);
124
- walkMapTree(item, proxyPath.rootPath, (p, proxy) => {
125
- proxyPath.proxyPaths.push({ path: p, proxy });
126
- });
127
- }
128
-
129
- bindProxies(proxyPaths, forest);
130
- }
131
-
132
- function walkMapTree(
133
- mapTree: MapTree,
134
- path: UpPath,
135
- onVisitTreeNode: (path: UpPath, treeNode: TreeNode) => void,
136
- ): void {
137
- if (tryUnhydratedFlexTreeNode(mapTree)?.parentField.parent.parent !== undefined) {
138
- throw new UsageError(
139
- "Attempted to insert a node which is already under a parent. If this is desired, remove the node from its parent before inserting it elsewhere.",
140
- );
141
- }
142
-
143
- type Next = [path: UpPath, tree: MapTree];
144
- const nexts: Next[] = [];
145
- for (let next: Next | undefined = [path, mapTree]; next !== undefined; next = nexts.pop()) {
146
- const [p, m] = next;
147
- const mapTreeNode = tryUnhydratedFlexTreeNode(m);
148
- if (mapTreeNode !== undefined) {
149
- const treeNode = unhydratedFlexTreeNodeToTreeNode.get(mapTreeNode);
150
- if (treeNode !== undefined) {
151
- onVisitTreeNode(p, treeNode);
152
- }
153
- }
154
-
155
- for (const [key, field] of m.fields) {
156
- for (const [i, child] of field.entries()) {
157
- nexts.push([
158
- {
159
- parent: p,
160
- parentField: key,
161
- parentIndex: i,
162
- },
163
- child,
164
- ]);
165
- }
166
- }
167
- }
168
- }
169
-
170
- function bindProxies(proxies: RootedProxyPaths[], forest: IForestSubscription): void {
171
- // Only subscribe to the event if there is at least one proxy tree to hydrate - this is not the case when inserting an empty array [].
172
- if (proxies.length > 0) {
173
- // Creating a new array emits one event per element in the array, so listen to the event once for each element
174
- let i = 0;
175
- const off = forest.events.on("afterRootFieldCreated", (fieldKey) => {
176
- // Non null asserting here because of the length check above
177
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
178
- (proxies[i]!.rootPath as Mutable<UpPath>).parentField = fieldKey;
179
- // Non null asserting here because of the length check above
180
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
181
- for (const { path, proxy } of proxies[i]!.proxyPaths) {
182
- getKernel(proxy).anchorProxy(forest.anchors, path);
183
- }
184
- if (++i === proxies.length) {
185
- off();
186
- }
187
- });
188
- }
189
- }
190
-
191
- // #endregion Content insertion and proxy binding
@@ -482,7 +482,7 @@ For class-based schema, this can be done by replacing an expression like "{foo:
482
482
  }
483
483
 
484
484
  /**
485
- * @returns all types for which the data is schema-compatible.
485
+ * Returns all types for which the data is schema-compatible.
486
486
  */
487
487
  export function getPossibleTypes(
488
488
  allowedTypes: ReadonlySet<TreeNodeSchema>,