@fluidframework/tree 2.0.2 → 2.1.0-276326

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 (157) hide show
  1. package/.vscode/settings.json +16 -0
  2. package/README.md +6 -9
  3. package/api-report/tree.alpha.api.md +0 -15
  4. package/api-report/tree.beta.api.md +0 -12
  5. package/api-report/tree.public.api.md +0 -12
  6. package/dist/core/tree/anchorSet.js +2 -2
  7. package/dist/core/tree/anchorSet.js.map +1 -1
  8. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -1
  9. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  10. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  11. package/dist/feature-libraries/flex-tree/lazyField.d.ts +1 -1
  12. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  13. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  14. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +4 -0
  15. package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  16. package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts +4 -0
  17. package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
  18. package/dist/feature-libraries/modular-schema/modularChangeFormat.js +4 -0
  19. package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/packageVersion.d.ts +1 -1
  24. package/dist/packageVersion.d.ts.map +1 -1
  25. package/dist/packageVersion.js +1 -1
  26. package/dist/packageVersion.js.map +1 -1
  27. package/dist/shared-tree/index.d.ts +1 -1
  28. package/dist/shared-tree/index.d.ts.map +1 -1
  29. package/dist/shared-tree/index.js.map +1 -1
  30. package/dist/shared-tree/schematizingTreeView.d.ts +4 -6
  31. package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
  32. package/dist/shared-tree/schematizingTreeView.js +16 -12
  33. package/dist/shared-tree/schematizingTreeView.js.map +1 -1
  34. package/dist/shared-tree/sharedTree.d.ts +1 -2
  35. package/dist/shared-tree/sharedTree.d.ts.map +1 -1
  36. package/dist/shared-tree/sharedTree.js +0 -10
  37. package/dist/shared-tree/sharedTree.js.map +1 -1
  38. package/dist/shared-tree/treeApi.js.map +1 -1
  39. package/dist/shared-tree/treeView.d.ts +13 -6
  40. package/dist/shared-tree/treeView.d.ts.map +1 -1
  41. package/dist/shared-tree/treeView.js +0 -2
  42. package/dist/shared-tree/treeView.js.map +1 -1
  43. package/dist/simple-tree/index.d.ts +4 -3
  44. package/dist/simple-tree/index.d.ts.map +1 -1
  45. package/dist/simple-tree/index.js +5 -3
  46. package/dist/simple-tree/index.js.map +1 -1
  47. package/dist/simple-tree/objectNode.d.ts.map +1 -1
  48. package/dist/simple-tree/objectNode.js +4 -0
  49. package/dist/simple-tree/objectNode.js.map +1 -1
  50. package/dist/simple-tree/proxies.d.ts.map +1 -1
  51. package/dist/simple-tree/proxies.js +13 -16
  52. package/dist/simple-tree/proxies.js.map +1 -1
  53. package/dist/simple-tree/schemaFactory.d.ts.map +1 -1
  54. package/dist/simple-tree/schemaFactory.js +2 -24
  55. package/dist/simple-tree/schemaFactory.js.map +1 -1
  56. package/dist/simple-tree/toFlexSchema.d.ts +0 -15
  57. package/dist/simple-tree/toFlexSchema.d.ts.map +1 -1
  58. package/dist/simple-tree/toFlexSchema.js +1 -35
  59. package/dist/simple-tree/toFlexSchema.js.map +1 -1
  60. package/dist/simple-tree/tree.d.ts +0 -29
  61. package/dist/simple-tree/tree.d.ts.map +1 -1
  62. package/dist/simple-tree/tree.js +1 -24
  63. package/dist/simple-tree/tree.js.map +1 -1
  64. package/dist/treeFactory.d.ts +1 -1
  65. package/dist/treeFactory.js +1 -1
  66. package/dist/treeFactory.js.map +1 -1
  67. package/dist/util/brandedMap.d.ts +9 -2
  68. package/dist/util/brandedMap.d.ts.map +1 -1
  69. package/dist/util/brandedMap.js +3 -4
  70. package/dist/util/brandedMap.js.map +1 -1
  71. package/lib/core/tree/anchorSet.js +2 -2
  72. package/lib/core/tree/anchorSet.js.map +1 -1
  73. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -1
  74. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  75. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  76. package/lib/feature-libraries/flex-tree/lazyField.d.ts +1 -1
  77. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  78. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  79. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +4 -0
  80. package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
  81. package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts +4 -0
  82. package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
  83. package/lib/feature-libraries/modular-schema/modularChangeFormat.js +4 -0
  84. package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
  85. package/lib/index.d.ts +1 -1
  86. package/lib/index.d.ts.map +1 -1
  87. package/lib/index.js.map +1 -1
  88. package/lib/packageVersion.d.ts +1 -1
  89. package/lib/packageVersion.d.ts.map +1 -1
  90. package/lib/packageVersion.js +1 -1
  91. package/lib/packageVersion.js.map +1 -1
  92. package/lib/shared-tree/index.d.ts +1 -1
  93. package/lib/shared-tree/index.d.ts.map +1 -1
  94. package/lib/shared-tree/index.js +1 -1
  95. package/lib/shared-tree/index.js.map +1 -1
  96. package/lib/shared-tree/schematizingTreeView.d.ts +4 -6
  97. package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
  98. package/lib/shared-tree/schematizingTreeView.js +19 -15
  99. package/lib/shared-tree/schematizingTreeView.js.map +1 -1
  100. package/lib/shared-tree/sharedTree.d.ts +1 -2
  101. package/lib/shared-tree/sharedTree.d.ts.map +1 -1
  102. package/lib/shared-tree/sharedTree.js +0 -10
  103. package/lib/shared-tree/sharedTree.js.map +1 -1
  104. package/lib/shared-tree/treeApi.js.map +1 -1
  105. package/lib/shared-tree/treeView.d.ts +13 -6
  106. package/lib/shared-tree/treeView.d.ts.map +1 -1
  107. package/lib/shared-tree/treeView.js +0 -2
  108. package/lib/shared-tree/treeView.js.map +1 -1
  109. package/lib/simple-tree/index.d.ts +4 -3
  110. package/lib/simple-tree/index.d.ts.map +1 -1
  111. package/lib/simple-tree/index.js +4 -3
  112. package/lib/simple-tree/index.js.map +1 -1
  113. package/lib/simple-tree/objectNode.d.ts.map +1 -1
  114. package/lib/simple-tree/objectNode.js +4 -0
  115. package/lib/simple-tree/objectNode.js.map +1 -1
  116. package/lib/simple-tree/proxies.d.ts.map +1 -1
  117. package/lib/simple-tree/proxies.js +14 -17
  118. package/lib/simple-tree/proxies.js.map +1 -1
  119. package/lib/simple-tree/schemaFactory.d.ts.map +1 -1
  120. package/lib/simple-tree/schemaFactory.js +3 -25
  121. package/lib/simple-tree/schemaFactory.js.map +1 -1
  122. package/lib/simple-tree/toFlexSchema.d.ts +0 -15
  123. package/lib/simple-tree/toFlexSchema.d.ts.map +1 -1
  124. package/lib/simple-tree/toFlexSchema.js +0 -33
  125. package/lib/simple-tree/toFlexSchema.js.map +1 -1
  126. package/lib/simple-tree/tree.d.ts +0 -29
  127. package/lib/simple-tree/tree.d.ts.map +1 -1
  128. package/lib/simple-tree/tree.js +0 -22
  129. package/lib/simple-tree/tree.js.map +1 -1
  130. package/lib/treeFactory.d.ts +1 -1
  131. package/lib/treeFactory.js +1 -1
  132. package/lib/treeFactory.js.map +1 -1
  133. package/lib/util/brandedMap.d.ts +9 -2
  134. package/lib/util/brandedMap.d.ts.map +1 -1
  135. package/lib/util/brandedMap.js +3 -4
  136. package/lib/util/brandedMap.js.map +1 -1
  137. package/package.json +23 -23
  138. package/src/core/tree/anchorSet.ts +3 -3
  139. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +5 -1
  140. package/src/feature-libraries/flex-tree/lazyField.ts +8 -5
  141. package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +5 -0
  142. package/src/feature-libraries/modular-schema/modularChangeFormat.ts +4 -0
  143. package/src/index.ts +1 -0
  144. package/src/packageVersion.ts +1 -1
  145. package/src/shared-tree/index.ts +6 -1
  146. package/src/shared-tree/schematizingTreeView.ts +32 -26
  147. package/src/shared-tree/sharedTree.ts +0 -18
  148. package/src/shared-tree/treeApi.ts +2 -2
  149. package/src/shared-tree/treeView.ts +14 -8
  150. package/src/simple-tree/index.ts +7 -3
  151. package/src/simple-tree/objectNode.ts +6 -0
  152. package/src/simple-tree/proxies.ts +22 -20
  153. package/src/simple-tree/schemaFactory.ts +5 -41
  154. package/src/simple-tree/toFlexSchema.ts +0 -47
  155. package/src/simple-tree/tree.ts +0 -37
  156. package/src/treeFactory.ts +1 -1
  157. package/src/util/brandedMap.ts +18 -11
package/src/index.ts CHANGED
@@ -248,6 +248,7 @@ export {
248
248
  ForestType,
249
249
  type SharedTreeContentSnapshot,
250
250
  type FlexTreeView,
251
+ type FlexTreeViewGeneric,
251
252
  type ITreeViewFork,
252
253
  buildTreeConfiguration,
253
254
  type ISharedTreeEditor,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tree";
9
- export const pkgVersion = "2.0.2";
9
+ export const pkgVersion = "2.1.0-276326";
@@ -33,7 +33,12 @@ export {
33
33
  buildTreeConfiguration,
34
34
  } from "./schematizeTree.js";
35
35
 
36
- export { type FlexTreeView, CheckoutFlexTreeView, type ITreeViewFork } from "./treeView.js";
36
+ export {
37
+ type FlexTreeView,
38
+ CheckoutFlexTreeView,
39
+ type ITreeViewFork,
40
+ type FlexTreeViewGeneric,
41
+ } from "./treeView.js";
37
42
 
38
43
  export type { ISharedTreeEditor, ISchemaEditor } from "./sharedTreeEditBuilder.js";
39
44
 
@@ -19,33 +19,29 @@ import {
19
19
  ViewSchema,
20
20
  defaultSchemaPolicy,
21
21
  ContextSlot,
22
+ cursorForMapTreeNode,
23
+ type FlexTreeSchema,
22
24
  } from "../feature-libraries/index.js";
23
25
  import {
24
26
  type FieldSchema,
25
27
  type ImplicitFieldSchema,
26
28
  type SchemaCompatibilityStatus,
27
29
  type InsertableTreeFieldFromImplicitField,
28
- // eslint-disable-next-line import/no-deprecated
29
- type TreeConfiguration,
30
30
  type TreeFieldFromImplicitField,
31
31
  type TreeView,
32
32
  type TreeViewEvents,
33
33
  getProxyForField,
34
- toFlexConfig,
34
+ toFlexSchema,
35
35
  setField,
36
36
  normalizeFieldSchema,
37
37
  type InsertableContent,
38
- cursorFromUnhydratedRoot,
39
38
  type TreeViewConfiguration,
39
+ mapTreeFromNodeData,
40
+ prepareContentForHydration,
40
41
  } from "../simple-tree/index.js";
41
42
  import { disposeSymbol } from "../util/index.js";
42
43
 
43
- import {
44
- type TreeContent,
45
- canInitialize,
46
- ensureSchema,
47
- initialize,
48
- } from "./schematizeTree.js";
44
+ import { canInitialize, ensureSchema, initialize } from "./schematizeTree.js";
49
45
  import type { TreeCheckout } from "./treeCheckout.js";
50
46
  import { CheckoutFlexTreeView } from "./treeView.js";
51
47
 
@@ -66,7 +62,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
66
62
  * Undefined iff uninitialized or disposed.
67
63
  */
68
64
  private currentCompatibility: SchemaCompatibilityStatus | undefined;
69
- private readonly flexConfig: TreeContent;
65
+ private readonly flexSchema: FlexTreeSchema;
70
66
  public readonly events: Listenable<TreeViewEvents> &
71
67
  IEmitter<TreeViewEvents> &
72
68
  HasListeners<TreeViewEvents> = createEmitter();
@@ -88,8 +84,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
88
84
 
89
85
  public constructor(
90
86
  public readonly checkout: TreeCheckout,
91
- public readonly config: // eslint-disable-next-line import/no-deprecated
92
- TreeConfiguration<TRootSchema> | TreeViewConfiguration<TRootSchema>,
87
+ public readonly config: TreeViewConfiguration<TRootSchema>,
93
88
  public readonly nodeKeyManager: NodeKeyManager,
94
89
  ) {
95
90
  const policy = {
@@ -97,11 +92,9 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
97
92
  validateSchema: config.enableSchemaValidation,
98
93
  };
99
94
  this.rootFieldSchema = normalizeFieldSchema(config.schema);
100
- this.flexConfig = toFlexConfig(config, nodeKeyManager, {
101
- schema: checkout.storedSchema,
102
- policy,
103
- });
104
- this.viewSchema = new ViewSchema(policy, {}, this.flexConfig.schema);
95
+ this.flexSchema = toFlexSchema(config.schema);
96
+
97
+ this.viewSchema = new ViewSchema(policy, {}, this.flexSchema);
105
98
  // This must be initialized before `update` can be called.
106
99
  this.currentCompatibility = {
107
100
  canView: false,
@@ -127,12 +120,23 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
127
120
  }
128
121
 
129
122
  this.runSchemaEdit(() => {
123
+ const mapTree = mapTreeFromNodeData(
124
+ content as InsertableContent,
125
+ this.rootFieldSchema.allowedTypes,
126
+ this.nodeKeyManager,
127
+ {
128
+ schema: this.checkout.storedSchema,
129
+ policy: {
130
+ ...defaultSchemaPolicy,
131
+ validateSchema: this.config.enableSchemaValidation,
132
+ },
133
+ },
134
+ );
135
+
136
+ prepareContentForHydration(mapTree, this.checkout.forest);
130
137
  initialize(this.checkout, {
131
- schema: this.flexConfig.schema,
132
- initialTree:
133
- content === undefined
134
- ? undefined
135
- : cursorFromUnhydratedRoot(this.config.schema, content, this.nodeKeyManager),
138
+ schema: this.flexSchema,
139
+ initialTree: mapTree === undefined ? undefined : cursorForMapTreeNode(mapTree),
136
140
  });
137
141
  });
138
142
  }
@@ -155,10 +159,12 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
155
159
  this.runSchemaEdit(() => {
156
160
  const result = ensureSchema(
157
161
  this.viewSchema,
158
- // eslint-disable-next-line no-bitwise
159
- AllowedUpdateType.SchemaCompatible | AllowedUpdateType.Initialize,
162
+ AllowedUpdateType.SchemaCompatible,
160
163
  this.checkout,
161
- this.flexConfig,
164
+ {
165
+ schema: this.flexSchema,
166
+ initialTree: undefined,
167
+ },
162
168
  );
163
169
  assert(result, 0x8bf /* Schema upgrade should always work if canUpgrade is set. */);
164
170
  });
@@ -53,8 +53,6 @@ import {
53
53
  import type {
54
54
  ITree,
55
55
  ImplicitFieldSchema,
56
- // eslint-disable-next-line import/no-deprecated
57
- TreeConfiguration,
58
56
  TreeView,
59
57
  TreeViewConfiguration,
60
58
  } from "../simple-tree/index.js";
@@ -322,22 +320,6 @@ export class SharedTree
322
320
  );
323
321
  }
324
322
 
325
- public schematize<TRoot extends ImplicitFieldSchema>(
326
- // eslint-disable-next-line import/no-deprecated
327
- config: TreeConfiguration<TRoot>,
328
- ): TreeView<TRoot> {
329
- const view = new SchematizingSimpleTreeView(
330
- this.checkout,
331
- config,
332
- createNodeKeyManager(this.runtime.idCompressor),
333
- );
334
- // As a subjective API design choice, we initialize the tree here if it is not already initialized.
335
- if (view.compatibility.canInitialize === true) {
336
- view.initialize(config.initialTree());
337
- }
338
- return view;
339
- }
340
-
341
323
  public viewWith<TRoot extends ImplicitFieldSchema>(
342
324
  config: TreeViewConfiguration<TRoot>,
343
325
  ): TreeView<TRoot> {
@@ -17,7 +17,7 @@ import {
17
17
  import { fail } from "../util/index.js";
18
18
 
19
19
  import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
20
- import type { TreeCheckout } from "./treeCheckout.js";
20
+ import type { ITreeCheckout } from "./treeCheckout.js";
21
21
  import { contextToTreeView } from "./treeView.js";
22
22
 
23
23
  /**
@@ -445,7 +445,7 @@ export function runTransaction<
445
445
  }
446
446
 
447
447
  function runTransactionInCheckout<TResult>(
448
- checkout: TreeCheckout,
448
+ checkout: ITreeCheckout,
449
449
  transaction: () => TResult | typeof rollback,
450
450
  preconditions: readonly TransactionConstraint[],
451
451
  ): TResult | typeof rollback {
@@ -17,14 +17,12 @@ import { type IDisposable, disposeSymbol } from "../util/index.js";
17
17
  import type { ITreeCheckout, ITreeCheckoutFork, TreeCheckout } from "./treeCheckout.js";
18
18
 
19
19
  /**
20
- * An editable view of a (version control style) branch of a shared tree.
20
+ * The portion of {@link FlexTreeView} that does not depend on the schema's type.
21
21
  * @privateRemarks
22
- * TODO:
23
- * 1. Once ISharedTreeView is renamed this can become ISharedTreeView.
24
- * 2. This object should be combined with or accessible from the TreeContext to allow easy access to thinks like branching.
22
+ * Since {@link FlexTreeView}'s schema is invariant, `FlexTreeView<FlexFieldSchema>` does not cover this use case.
25
23
  * @internal
26
24
  */
27
- export interface FlexTreeView<in out TRoot extends FlexFieldSchema> extends IDisposable {
25
+ export interface FlexTreeViewGeneric extends IDisposable {
28
26
  /**
29
27
  * Context for controlling the FlexTree nodes produced from {@link FlexTreeView.flexTree}.
30
28
  *
@@ -40,7 +38,17 @@ export interface FlexTreeView<in out TRoot extends FlexFieldSchema> extends IDis
40
38
  * This is a non-owning reference: disposing of this view does not impact the branch.
41
39
  */
42
40
  readonly checkout: ITreeCheckout;
41
+ }
43
42
 
43
+ /**
44
+ * An editable view of a (version control style) branch of a shared tree.
45
+ * @privateRemarks
46
+ * TODO:
47
+ * If schema aware APIs are removed from flex tree, this can be combined with {@link FlexTreeViewGeneric}.
48
+ * @internal
49
+ */
50
+ export interface FlexTreeView<in out TRoot extends FlexFieldSchema>
51
+ extends FlexTreeViewGeneric {
44
52
  /**
45
53
  * Get a typed view of the tree content using the flex-tree API.
46
54
  */
@@ -100,6 +108,4 @@ export class CheckoutFlexTreeView<
100
108
  * Maps the context of every {@link CheckoutFlexTreeView} to the view.
101
109
  * In practice, this allows the view or checkout to be obtained from a flex node by first getting the context from the flex node and then using this map.
102
110
  */
103
- // TODO: use something other than `any`
104
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
- export const contextToTreeView = new WeakMap<Context, CheckoutFlexTreeView<any>>();
111
+ export const contextToTreeView = new WeakMap<Context, FlexTreeViewGeneric>();
@@ -7,7 +7,6 @@ export {
7
7
  type ITree,
8
8
  type TreeView,
9
9
  type TreeViewEvents,
10
- TreeConfiguration,
11
10
  TreeViewConfiguration,
12
11
  type ITreeViewConfiguration,
13
12
  type SchemaCompatibilityStatus,
@@ -42,7 +41,7 @@ export {
42
41
  export { SchemaFactory, type ScopedSchemaName } from "./schemaFactory.js";
43
42
  export { getFlexNode } from "./proxyBinding.js";
44
43
  export { treeNodeApi, type TreeNodeApi, type TreeChangeEvents } from "./treeNodeApi.js";
45
- export { toFlexConfig, cursorFromUnhydratedRoot } from "./toFlexSchema.js";
44
+ export { toFlexSchema, cursorFromUnhydratedRoot } from "./toFlexSchema.js";
46
45
  export type {
47
46
  FieldHasDefaultUnsafe,
48
47
  ObjectFromSchemaRecordUnsafe,
@@ -60,7 +59,11 @@ export type {
60
59
  NodeFromSchemaUnsafe,
61
60
  } from "./typesUnsafe.js";
62
61
  export type { ValidateRecursiveSchema } from "./schemaFactoryRecursive.js";
63
- export { getProxyForField, type InsertableContent } from "./proxies.js";
62
+ export {
63
+ getProxyForField,
64
+ type InsertableContent,
65
+ prepareContentForHydration,
66
+ } from "./proxies.js";
64
67
 
65
68
  export {
66
69
  adaptEnum,
@@ -93,3 +96,4 @@ export {
93
96
  setField,
94
97
  } from "./objectNode.js";
95
98
  export type { TreeMapNode } from "./mapNode.js";
99
+ export { mapTreeFromNodeData } from "./toMapTree.js";
@@ -200,6 +200,12 @@ function createProxyHandler(
200
200
  setField(flexNode.getBoxed(fieldInfo.storedKey), fieldInfo.schema, value);
201
201
  return true;
202
202
  },
203
+ deleteProperty(target, viewKey): boolean {
204
+ // TODO: supporting delete when it makes sense (custom local fields, and optional field) could be added as a feature in the future.
205
+ throw new UsageError(
206
+ `Object nodes do not support the delete operator. Optional fields can be assigned to undefined instead.`,
207
+ );
208
+ },
203
209
  has: (target, viewKey) => {
204
210
  return (
205
211
  flexKeyMap.has(viewKey) ||
@@ -25,6 +25,7 @@ import {
25
25
  type MapTreeNode,
26
26
  tryGetMapTreeNode,
27
27
  typeNameSymbol,
28
+ isFlexTreeNode,
28
29
  } from "../feature-libraries/index.js";
29
30
  import { type Mutable, fail, isReadonlyArray } from "../util/index.js";
30
31
 
@@ -55,27 +56,28 @@ export function isTreeNode(candidate: unknown): candidate is TreeNode | Unhydrat
55
56
  * Retrieve the associated proxy for the given field.
56
57
  * */
57
58
  export function getProxyForField(field: FlexTreeField): TreeNode | TreeValue | undefined {
59
+ function tryToUnboxLeaves(
60
+ flexField: FlexTreeTypedField<
61
+ FlexFieldSchema<typeof FieldKinds.required | typeof FieldKinds.optional>
62
+ >,
63
+ ): TreeNode | TreeValue | undefined {
64
+ const maybeUnboxedContent = flexField.content;
65
+ return isFlexTreeNode(maybeUnboxedContent)
66
+ ? getOrCreateNodeProxy(maybeUnboxedContent)
67
+ : maybeUnboxedContent;
68
+ }
58
69
  switch (field.schema.kind) {
59
70
  case FieldKinds.required: {
60
- const asValue = field as FlexTreeTypedField<FlexFieldSchema<typeof FieldKinds.required>>;
61
-
62
- // TODO: Ideally, we would return leaves without first boxing them. However, this is not
63
- // as simple as calling '.content' since this skips the node and returns the FieldNode's
64
- // inner field.
65
- return getOrCreateNodeProxy(asValue.boxedContent);
71
+ const typedField = field as FlexTreeTypedField<
72
+ FlexFieldSchema<typeof FieldKinds.required>
73
+ >;
74
+ return tryToUnboxLeaves(typedField);
66
75
  }
67
76
  case FieldKinds.optional: {
68
- const asValue = field as FlexTreeTypedField<FlexFieldSchema<typeof FieldKinds.optional>>;
69
-
70
- // TODO: Ideally, we would return leaves without first boxing them. However, this is not
71
- // as simple as calling '.content' since this skips the node and returns the FieldNode's
72
- // inner field.
73
-
74
- const maybeContent = asValue.boxedContent;
75
-
76
- // Normally, empty fields are unreachable due to the behavior of 'tryGetField'. However, the
77
- // root field is a special case where the field is always present (even if empty).
78
- return maybeContent === undefined ? undefined : getOrCreateNodeProxy(maybeContent);
77
+ const typedField = field as FlexTreeTypedField<
78
+ FlexFieldSchema<typeof FieldKinds.optional>
79
+ >;
80
+ return tryToUnboxLeaves(typedField);
79
81
  }
80
82
  // TODO: Remove if/when 'FieldNode' is removed.
81
83
  case FieldKinds.sequence: {
@@ -84,9 +86,9 @@ export function getProxyForField(field: FlexTreeField): TreeNode | TreeValue | u
84
86
  fail("'sequence' field is unexpected.");
85
87
  }
86
88
  case FieldKinds.identifier: {
87
- const identifier = field.boxedAt(0);
88
- assert(identifier !== undefined, 0x91a /* identifier must exist */);
89
- return getOrCreateNodeProxy(identifier);
89
+ // Identifier fields are just value fields that hold strings
90
+ return (field as FlexTreeTypedField<FlexFieldSchema<typeof FieldKinds.required>>)
91
+ .content as string;
90
92
  }
91
93
 
92
94
  default:
@@ -10,13 +10,7 @@ import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
10
10
  import type { IFluidHandle as _dummyImport } from "@fluidframework/core-interfaces";
11
11
 
12
12
  import type { TreeValue } from "../core/index.js";
13
- import {
14
- type FlexTreeNode,
15
- type NodeKeyManager,
16
- type Unenforced,
17
- isFlexTreeNode,
18
- isLazy,
19
- } from "../feature-libraries/index.js";
13
+ import { type NodeKeyManager, type Unenforced, isLazy } from "../feature-libraries/index.js";
20
14
  import {
21
15
  type RestrictiveReadonlyRecord,
22
16
  getOrCreate,
@@ -641,26 +635,12 @@ export class SchemaFactory<
641
635
  const Name extends TName,
642
636
  const T extends Unenforced<ImplicitAllowedTypes>,
643
637
  >(name: Name, allowedTypes: T) {
644
- class RecursiveArray extends this.namedArray(
638
+ const RecursiveArray = this.namedArray(
645
639
  name,
646
640
  allowedTypes as T & ImplicitAllowedTypes,
647
641
  true,
648
642
  false,
649
- ) {
650
- public constructor(
651
- data:
652
- | Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T & ImplicitAllowedTypes>>
653
- | FlexTreeNode,
654
- ) {
655
- if (isFlexTreeNode(data)) {
656
- // TODO: use something other than `any`
657
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
658
- super(data as any);
659
- } else {
660
- super(data);
661
- }
662
- }
663
- }
643
+ );
664
644
 
665
645
  return RecursiveArray as TreeNodeSchemaClass<
666
646
  ScopedSchemaName<TScope, Name>,
@@ -697,28 +677,12 @@ export class SchemaFactory<
697
677
  name: Name,
698
678
  allowedTypes: T,
699
679
  ) {
700
- class MapSchema extends this.namedMap(
680
+ const MapSchema = this.namedMap(
701
681
  name,
702
682
  allowedTypes as T & ImplicitAllowedTypes,
703
683
  true,
704
684
  false,
705
- ) {
706
- public constructor(
707
- data:
708
- | Iterable<
709
- [string, InsertableTreeNodeFromImplicitAllowedTypes<T & ImplicitAllowedTypes>]
710
- >
711
- | FlexTreeNode,
712
- ) {
713
- if (isFlexTreeNode(data)) {
714
- // TODO: use something other than `any`
715
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
716
- super(data as any);
717
- } else {
718
- super(new Map(data));
719
- }
720
- }
721
- }
685
+ );
722
686
 
723
687
  return MapSchema as TreeNodeSchemaClass<
724
688
  ScopedSchemaName<TScope, Name>,
@@ -27,7 +27,6 @@ import {
27
27
  schemaIsLeaf,
28
28
  } from "../feature-libraries/index.js";
29
29
  import { normalizeFlexListEager } from "../feature-libraries/typed-schema/flexList.js";
30
- import type { TreeContent } from "../shared-tree/index.js";
31
30
  import { brand, fail, isReadonlyArray, mapIterable } from "../util/index.js";
32
31
 
33
32
  import type { InsertableContent } from "./proxies.js";
@@ -48,8 +47,6 @@ import {
48
47
  getStoredKey,
49
48
  } from "./schemaTypes.js";
50
49
  import { cursorFromNodeData } from "./toMapTree.js";
51
- // eslint-disable-next-line import/no-deprecated
52
- import { TreeConfiguration, type TreeViewConfiguration } from "./tree.js";
53
50
 
54
51
  /**
55
52
  * Returns a cursor (in nodes mode) for the root node.
@@ -77,50 +74,6 @@ export function cursorFromUnhydratedRoot(
77
74
  );
78
75
  }
79
76
 
80
- /* eslint-disable import/no-deprecated */
81
- function isTreeConfiguration(
82
- config: TreeViewConfiguration | TreeConfiguration,
83
- ): config is TreeConfiguration {
84
- return config instanceof TreeConfiguration;
85
- }
86
- /* eslint-enable import/no-deprecated */
87
-
88
- /**
89
- * Generates a configuration object (schema + initial tree) for a FlexTree.
90
- * @param config - Configuration for how to {@link ITree.schematize|schematize} a tree.
91
- * @param nodeKeyManager - See {@link NodeKeyManager}.
92
- * @param schemaValidationPolicy - Stored schema and policy for the tree. If the policy specifies
93
- * `{@link SchemaPolicy.validateSchema} === true`, new content inserted into the tree will be validated using this
94
- * object.
95
- * @returns A configuration object for a FlexTree.
96
- *
97
- * @privateremarks
98
- * I wrote these docs without a ton of context, they can probably be improved.
99
- */
100
- export function toFlexConfig(
101
- // eslint-disable-next-line import/no-deprecated
102
- config: TreeViewConfiguration | TreeConfiguration,
103
- nodeKeyManager: NodeKeyManager,
104
- schemaValidationPolicy: SchemaAndPolicy | undefined = undefined,
105
- ): TreeContent {
106
- const unhydrated = isTreeConfiguration(config) ? config.initialTree() : undefined;
107
- const initialTree =
108
- unhydrated === undefined
109
- ? undefined
110
- : [
111
- cursorFromUnhydratedRoot(
112
- config.schema,
113
- unhydrated,
114
- nodeKeyManager,
115
- schemaValidationPolicy,
116
- ),
117
- ];
118
- return {
119
- schema: toFlexSchema(config.schema),
120
- initialTree,
121
- };
122
- }
123
-
124
77
  interface SchemaInfo {
125
78
  toFlex: () => FlexTreeNodeSchema;
126
79
  original: TreeNodeSchema;
@@ -133,43 +133,6 @@ export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = Implici
133
133
  }
134
134
  }
135
135
 
136
- /**
137
- * Configuration for how to {@link ITree.schematize | schematize} a tree.
138
- * @sealed @public
139
- * @deprecated Please migrate to use {@link TreeViewConfiguration} with {@link ITree.viewWith} instead.
140
- */
141
- export class TreeConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> {
142
- /**
143
- * If `true`, the tree will validate new content against its stored schema at insertion time
144
- * and throw an error if the new content doesn't match the expected schema.
145
- *
146
- * @defaultValue `false`.
147
- *
148
- * @remarks Enabling schema validation has a performance penalty when inserting new content into the tree because
149
- * additional checks are done. Enable this option only in scenarios where you are ok with that operation being a
150
- * bit slower.
151
- */
152
- public readonly enableSchemaValidation: boolean;
153
-
154
- /**
155
- * @param schema - The schema which the application wants to view the tree with.
156
- * @param initialTree - A function that returns the default tree content to initialize the tree with iff the tree is uninitialized
157
- * (meaning it does not even have any schema set at all).
158
- * If `initialTree` returns any actual node instances, they should be recreated each time `initialTree` runs.
159
- * This is because if the config is used a second time any nodes that were not recreated could error since nodes cannot be inserted into the tree multiple times.
160
- * @param options - Additional options that can be specified when {@link ITree.schematize | schematizing } a tree.
161
- */
162
- public constructor(
163
- public readonly schema: TSchema,
164
- public readonly initialTree: () => InsertableTreeFieldFromImplicitField<TSchema>,
165
- options?: ITreeConfigurationOptions,
166
- ) {
167
- this.enableSchemaValidation =
168
- options?.enableSchemaValidation ??
169
- defaultTreeConfigurationOptions.enableSchemaValidation;
170
- }
171
- }
172
-
173
136
  /**
174
137
  * An editable view of a (version control style) branch of a shared tree based on some schema.
175
138
  *
@@ -56,7 +56,7 @@ export class TreeFactory implements IChannelFactory<ITree> {
56
56
  /**
57
57
  * SharedTree is a hierarchical data structure for collaboratively editing strongly typed JSON-like trees
58
58
  * of objects, arrays, and other data types.
59
- * @alpha
59
+ * @internal
60
60
  */
61
61
  export const SharedTree = configuredSharedTree({});
62
62
 
@@ -3,11 +3,16 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
+ import type { Brand } from "./brand.js";
7
+ import type { Opaque } from "./opaque.js";
6
8
  import type { Invariant } from "./typeCheck.js";
7
9
  import { getOrCreate } from "./utils.js";
8
10
 
9
11
  /**
10
12
  * Key in a {@link BrandedMapSubset}.
13
+ * @remarks
14
+ * Due to the `TContent` type parameter being invariant (which it has to be since keys are used to both read and write data),
15
+ * generic collections end up needing to constrain their key's `TContent` to `any`.
11
16
  * @internal
12
17
  */
13
18
  export type BrandedKey<TKey, TContent> = TKey & Invariant<TContent>;
@@ -49,16 +54,15 @@ export interface BrandedMapSubset<K extends BrandedKey<unknown, any>> {
49
54
 
50
55
  /**
51
56
  * Version of {@link getOrCreate} with better typing for {@link BrandedMapSubset}.
57
+ * @privateRemarks
58
+ * Only infers type from key to avoid inferring `any` from map's key.
52
59
  */
53
- export function getOrCreateSlotContent<
54
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
- M extends BrandedMapSubset<BrandedKey<unknown, any>>,
56
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
- K extends BrandedKey<unknown, any>,
58
- >(map: M, key: K, defaultValue: (key: K) => BrandedKeyContent<K>): BrandedKeyContent<K> {
59
- const result: BrandedKeyContent<K> = getOrCreate(map, key, defaultValue);
60
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
61
- return result;
60
+ export function getOrCreateSlotContent<K, V>(
61
+ map: NoInfer<BrandedMapSubset<BrandedKey<K, V>>>,
62
+ key: BrandedKey<K, V>,
63
+ defaultValue: NoInfer<(key: BrandedKey<K, V>) => V>,
64
+ ): V {
65
+ return getOrCreate<BrandedKey<K, V>, V>(map, key, defaultValue);
62
66
  }
63
67
 
64
68
  /**
@@ -72,7 +76,10 @@ let slotCounter = 0;
72
76
  * Define a strongly typed slot in which data can be stored in a {@link BrandedMapSubset}.
73
77
  * @internal
74
78
  */
75
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
- export function brandedSlot<TSlot extends BrandedKey<any, any>>(): TSlot {
79
+ export function brandedSlot<
80
+ // See note on BrandedKey.
81
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
+ TSlot extends BrandedKey<number | Opaque<Brand<number, string>>, any>,
83
+ >(): TSlot {
77
84
  return slotCounter++ as TSlot;
78
85
  }