@fluidframework/tree 2.2.0 → 2.3.0-288113

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 (144) hide show
  1. package/api-report/tree.alpha.api.md +39 -3
  2. package/api-report/tree.beta.api.md +8 -3
  3. package/api-report/tree.public.api.md +8 -3
  4. package/dist/beta.d.ts +1 -0
  5. package/dist/core/tree/anchorSet.d.ts +4 -6
  6. package/dist/core/tree/anchorSet.d.ts.map +1 -1
  7. package/dist/core/tree/anchorSet.js +11 -1
  8. package/dist/core/tree/anchorSet.js.map +1 -1
  9. package/dist/events/events.d.ts +7 -1
  10. package/dist/events/events.d.ts.map +1 -1
  11. package/dist/events/events.js +5 -2
  12. package/dist/events/events.js.map +1 -1
  13. package/dist/feature-libraries/flex-map-tree/mapTreeNode.d.ts +0 -2
  14. package/dist/feature-libraries/flex-map-tree/mapTreeNode.d.ts.map +1 -1
  15. package/dist/feature-libraries/flex-map-tree/mapTreeNode.js +0 -12
  16. package/dist/feature-libraries/flex-map-tree/mapTreeNode.js.map +1 -1
  17. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +4 -95
  18. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  19. package/dist/feature-libraries/flex-tree/flexTreeTypes.js +1 -30
  20. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  21. package/dist/feature-libraries/flex-tree/index.d.ts +2 -2
  22. package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
  23. package/dist/feature-libraries/flex-tree/index.js +1 -3
  24. package/dist/feature-libraries/flex-tree/index.js.map +1 -1
  25. package/dist/feature-libraries/flex-tree/lazyField.d.ts +0 -1
  26. package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  27. package/dist/feature-libraries/flex-tree/lazyField.js +0 -3
  28. package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
  29. package/dist/feature-libraries/flex-tree/lazyNode.d.ts +3 -10
  30. package/dist/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  31. package/dist/feature-libraries/flex-tree/lazyNode.js +2 -87
  32. package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  33. package/dist/feature-libraries/index.d.ts +1 -1
  34. package/dist/feature-libraries/index.d.ts.map +1 -1
  35. package/dist/feature-libraries/index.js +2 -4
  36. package/dist/feature-libraries/index.js.map +1 -1
  37. package/dist/index.d.ts +2 -2
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +36 -31
  40. package/dist/index.js.map +1 -1
  41. package/dist/packageVersion.d.ts +1 -1
  42. package/dist/packageVersion.d.ts.map +1 -1
  43. package/dist/packageVersion.js +1 -1
  44. package/dist/packageVersion.js.map +1 -1
  45. package/dist/public.d.ts +1 -0
  46. package/dist/simple-tree/api/treeNodeApi.d.ts +1 -1
  47. package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  48. package/dist/simple-tree/api/treeNodeApi.js +30 -2
  49. package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
  50. package/dist/simple-tree/arrayNode.d.ts.map +1 -1
  51. package/dist/simple-tree/arrayNode.js +5 -19
  52. package/dist/simple-tree/arrayNode.js.map +1 -1
  53. package/dist/simple-tree/core/index.d.ts +1 -1
  54. package/dist/simple-tree/core/index.d.ts.map +1 -1
  55. package/dist/simple-tree/core/index.js.map +1 -1
  56. package/dist/simple-tree/core/treeNodeKernel.d.ts +18 -5
  57. package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  58. package/dist/simple-tree/core/treeNodeKernel.js +57 -21
  59. package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
  60. package/dist/simple-tree/core/types.d.ts +28 -10
  61. package/dist/simple-tree/core/types.d.ts.map +1 -1
  62. package/dist/simple-tree/core/types.js.map +1 -1
  63. package/dist/simple-tree/index.d.ts +1 -1
  64. package/dist/simple-tree/index.d.ts.map +1 -1
  65. package/dist/simple-tree/index.js.map +1 -1
  66. package/lib/beta.d.ts +1 -0
  67. package/lib/core/tree/anchorSet.d.ts +4 -6
  68. package/lib/core/tree/anchorSet.d.ts.map +1 -1
  69. package/lib/core/tree/anchorSet.js +11 -1
  70. package/lib/core/tree/anchorSet.js.map +1 -1
  71. package/lib/events/events.d.ts +7 -1
  72. package/lib/events/events.d.ts.map +1 -1
  73. package/lib/events/events.js +5 -2
  74. package/lib/events/events.js.map +1 -1
  75. package/lib/feature-libraries/flex-map-tree/mapTreeNode.d.ts +0 -2
  76. package/lib/feature-libraries/flex-map-tree/mapTreeNode.d.ts.map +1 -1
  77. package/lib/feature-libraries/flex-map-tree/mapTreeNode.js +0 -12
  78. package/lib/feature-libraries/flex-map-tree/mapTreeNode.js.map +1 -1
  79. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +4 -95
  80. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  81. package/lib/feature-libraries/flex-tree/flexTreeTypes.js +0 -29
  82. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  83. package/lib/feature-libraries/flex-tree/index.d.ts +2 -2
  84. package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
  85. package/lib/feature-libraries/flex-tree/index.js +1 -1
  86. package/lib/feature-libraries/flex-tree/index.js.map +1 -1
  87. package/lib/feature-libraries/flex-tree/lazyField.d.ts +0 -1
  88. package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
  89. package/lib/feature-libraries/flex-tree/lazyField.js +0 -3
  90. package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
  91. package/lib/feature-libraries/flex-tree/lazyNode.d.ts +3 -10
  92. package/lib/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
  93. package/lib/feature-libraries/flex-tree/lazyNode.js +3 -86
  94. package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
  95. package/lib/feature-libraries/index.d.ts +1 -1
  96. package/lib/feature-libraries/index.d.ts.map +1 -1
  97. package/lib/feature-libraries/index.js +1 -1
  98. package/lib/feature-libraries/index.js.map +1 -1
  99. package/lib/index.d.ts +2 -2
  100. package/lib/index.d.ts.map +1 -1
  101. package/lib/index.js +4 -0
  102. package/lib/index.js.map +1 -1
  103. package/lib/packageVersion.d.ts +1 -1
  104. package/lib/packageVersion.d.ts.map +1 -1
  105. package/lib/packageVersion.js +1 -1
  106. package/lib/packageVersion.js.map +1 -1
  107. package/lib/public.d.ts +1 -0
  108. package/lib/simple-tree/api/treeNodeApi.d.ts +1 -1
  109. package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
  110. package/lib/simple-tree/api/treeNodeApi.js +30 -2
  111. package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
  112. package/lib/simple-tree/arrayNode.d.ts.map +1 -1
  113. package/lib/simple-tree/arrayNode.js +5 -19
  114. package/lib/simple-tree/arrayNode.js.map +1 -1
  115. package/lib/simple-tree/core/index.d.ts +1 -1
  116. package/lib/simple-tree/core/index.d.ts.map +1 -1
  117. package/lib/simple-tree/core/index.js.map +1 -1
  118. package/lib/simple-tree/core/treeNodeKernel.d.ts +18 -5
  119. package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  120. package/lib/simple-tree/core/treeNodeKernel.js +58 -22
  121. package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
  122. package/lib/simple-tree/core/types.d.ts +28 -10
  123. package/lib/simple-tree/core/types.d.ts.map +1 -1
  124. package/lib/simple-tree/core/types.js.map +1 -1
  125. package/lib/simple-tree/index.d.ts +1 -1
  126. package/lib/simple-tree/index.d.ts.map +1 -1
  127. package/lib/simple-tree/index.js.map +1 -1
  128. package/package.json +22 -32
  129. package/src/core/tree/anchorSet.ts +20 -9
  130. package/src/events/events.ts +10 -2
  131. package/src/feature-libraries/flex-map-tree/mapTreeNode.ts +0 -21
  132. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +3 -170
  133. package/src/feature-libraries/flex-tree/index.ts +1 -17
  134. package/src/feature-libraries/flex-tree/lazyField.ts +0 -6
  135. package/src/feature-libraries/flex-tree/lazyNode.ts +3 -154
  136. package/src/feature-libraries/index.ts +0 -14
  137. package/src/index.ts +8 -0
  138. package/src/packageVersion.ts +1 -1
  139. package/src/simple-tree/api/treeNodeApi.ts +37 -5
  140. package/src/simple-tree/arrayNode.ts +3 -12
  141. package/src/simple-tree/core/index.ts +1 -0
  142. package/src/simple-tree/core/treeNodeKernel.ts +88 -29
  143. package/src/simple-tree/core/types.ts +35 -9
  144. package/src/simple-tree/index.ts +1 -0
@@ -11,7 +11,7 @@ import {
11
11
  type TreeValue,
12
12
  anchorSlot,
13
13
  } from "../../core/index.js";
14
- import type { Assume, FlattenKeys } from "../../util/index.js";
14
+ import type { Assume } from "../../util/index.js";
15
15
  import type {
16
16
  FieldKinds,
17
17
  SequenceFieldEditBuilder,
@@ -26,7 +26,6 @@ import type {
26
26
  FlexList,
27
27
  FlexListToUnion,
28
28
  FlexMapNodeSchema,
29
- FlexObjectNodeFields,
30
29
  FlexObjectNodeSchema,
31
30
  FlexTreeNodeSchema,
32
31
  LazyItem,
@@ -309,33 +308,6 @@ export interface FlexTreeMapNode<in out TSchema extends FlexMapNodeSchema>
309
308
  */
310
309
  entries(): IterableIterator<[FieldKey, FlexTreeUnboxField<TSchema["info"], "notEmpty">]>;
311
310
 
312
- /**
313
- * Executes a provided function once per each key/value pair in the map.
314
- * @param callbackFn - The function to run for each map entry
315
- * @param thisArg - If present, `callbackFn` will be bound to `thisArg`
316
- *
317
- * @privateRemarks
318
- * TODO: This should run over fields in insertion order if we want to match the javascript foreach spec.
319
- */
320
- forEach(
321
- callbackFn: (
322
- value: FlexTreeUnboxField<TSchema["info"], "notEmpty">,
323
- key: FieldKey,
324
- map: FlexTreeMapNode<TSchema>,
325
- ) => void,
326
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
327
- thisArg?: any,
328
- ): void;
329
-
330
- /**
331
- * Iterate through all fields in the map.
332
- *
333
- * @remarks
334
- * No mutations to the current view of the shared tree are permitted during iteration.
335
- * To iterate over the unboxed values of the map, use `Symbol.Iterator()`.
336
- */
337
- boxedIterator(): IterableIterator<FlexTreeTypedField<TSchema["info"]>>;
338
-
339
311
  [Symbol.iterator](): IterableIterator<
340
312
  [FieldKey, FlexTreeUnboxField<TSchema["info"], "notEmpty">]
341
313
  >;
@@ -348,7 +320,6 @@ export interface FlexTreeMapNode<in out TSchema extends FlexMapNodeSchema>
348
320
  *
349
321
  * @remarks
350
322
  * ObjectNodes require complex typing, and have been split into two parts for implementation purposes.
351
- * See {@link FlexTreeObjectNodeTyped} for the schema aware extensions to this that provide access to the fields.
352
323
  *
353
324
  * These "Objects" resemble "Structs" from a wide variety of programming languages
354
325
  * (Including Algol 68, C, Go, Rust, C# etc.).
@@ -380,138 +351,6 @@ export interface FlexTreeLeafNode<in out TSchema extends LeafNodeSchema> extends
380
351
  readonly value: TreeValue<TSchema["info"]>;
381
352
  }
382
353
 
383
- /**
384
- * An {@link FlexTreeObjectNode} with schema aware accessors for its fields.
385
- *
386
- * @privateRemarks
387
- *
388
- * The corresponding implementation logic for this lives in `LazyTree.ts` under `buildStructClass`.
389
- * If you change the signature here, you will need to update that logic to match.
390
- */
391
- export type FlexTreeObjectNodeTyped<TSchema extends FlexObjectNodeSchema> =
392
- FlexObjectNodeSchema extends TSchema
393
- ? FlexTreeObjectNode
394
- : FlexTreeObjectNode & FlexTreeObjectNodeFields<TSchema["info"]>;
395
-
396
- /**
397
- * Properties to access an object node's fields. See {@link FlexTreeObjectNodeTyped}.
398
- *
399
- * @privateRemarks
400
- * TODO: Support custom field keys.
401
- */
402
- export type FlexTreeObjectNodeFields<TFields extends FlexObjectNodeFields> =
403
- FlexTreeObjectNodeFieldsInner<
404
- FlattenKeys<
405
- {
406
- // When the key does not need to be escaped, map it from the input TFields in a way that doesn't break navigate to declaration
407
- [key in keyof TFields as key extends PropertyNameFromFieldKey<key & string>
408
- ? key
409
- : never]: TFields[key];
410
- } & {
411
- [key in keyof TFields as key extends PropertyNameFromFieldKey<key & string>
412
- ? never
413
- : PropertyNameFromFieldKey<key & string>]: TFields[key];
414
- }
415
- >
416
- >;
417
-
418
- /**
419
- * Properties to access an object node's fields. See {@link FlexTreeObjectNodeTyped}.
420
- *
421
- * @privateRemarks
422
- * TODO: Do we keep assignment operator + "setFoo" methods, or just use methods?
423
- * Inconsistency in the API experience could confusing for consumers.
424
- */
425
- export type FlexTreeObjectNodeFieldsInner<TFields extends FlexObjectNodeFields> = FlattenKeys<
426
- {
427
- // boxed fields (TODO: maybe remove these when same as non-boxed version?)
428
- readonly [key in keyof TFields as `boxed${Capitalize<key & string>}`]: FlexTreeTypedField<
429
- TFields[key]
430
- >;
431
- } & {
432
- // Add getter only (make property readonly) when the field is **not** of a kind that has a logical set operation.
433
- // If we could map to getters and setters separately, we would preferably do that, but we can't.
434
- // See https://github.com/microsoft/TypeScript/issues/43826 for more details on this limitation.
435
- readonly [key in keyof TFields as TFields[key]["kind"] extends AssignableFieldKinds
436
- ? never
437
- : key]: FlexTreeUnboxField<TFields[key]>;
438
- } & {
439
- // Add setter (make property writable) when the field is of a kind that has a logical set operation.
440
- // If we could map to getters and setters separately, we would preferably do that, but we can't.
441
- // See https://github.com/microsoft/TypeScript/issues/43826 for more details on this limitation.
442
- -readonly [key in keyof TFields as TFields[key]["kind"] extends AssignableFieldKinds
443
- ? key
444
- : never]: FlexTreeUnboxField<TFields[key]>;
445
- } & {
446
- // Setter method (when the field is of a kind that has a logical set operation).
447
- readonly [key in keyof TFields as TFields[key]["kind"] extends AssignableFieldKinds
448
- ? `set${Capitalize<key & string>}`
449
- : never]: (content: FlexibleNodeContent) => void;
450
- }
451
- >;
452
-
453
- /**
454
- * Reserved object node field property names to avoid collisions with the rest of the object node API.
455
- */
456
- export const reservedObjectNodeFieldPropertyNames = [
457
- "anchorNode",
458
- "constructor",
459
- "context",
460
- "is",
461
- "parentField",
462
- "schema",
463
- "tryGetField",
464
- "type",
465
- "value",
466
- "boxedIterator",
467
- "iterator",
468
- "getBoxed",
469
- ] as const;
470
-
471
- /**
472
- * Reserved object node field property names prefixes.
473
- * These are reserved to avoid collisions with properties derived from field other field names.
474
- *
475
- * Field names starting with these must be followed by a lowercase letter, or be escaped.
476
- */
477
- export const reservedObjectNodeFieldPropertyNamePrefixes = [
478
- "set",
479
- "boxed",
480
- "field",
481
- "Field",
482
- ] as const;
483
-
484
- /**
485
- * {@link reservedObjectNodeFieldPropertyNamePrefixes} as a type union.
486
- */
487
- export type ReservedObjectNodeFieldPropertyNames =
488
- (typeof reservedObjectNodeFieldPropertyNames)[number];
489
-
490
- /**
491
- * {@link reservedObjectNodeFieldPropertyNamePrefixes} as a type union.
492
- */
493
- export type ReservedObjectNodeFieldPropertyNamePrefixes =
494
- (typeof reservedObjectNodeFieldPropertyNamePrefixes)[number];
495
-
496
- /**
497
- * Convert an object node's field key into an escaped string usable as a property name.
498
- *
499
- * @privateRemarks
500
- * TODO:
501
- * Collisions are still possible.
502
- * For example fields named "foo" and "Foo" would both produce a setter "setFoo".
503
- * Consider naming schemes to avoid this, ensure that there is a good workaround for these cases.
504
- * Another approach would be to support custom field names (separate from keys),
505
- * and do the escaping (if needed) when creating the flex tree schema (both when manually creating them and when doing so automatically):
506
- * this would enable better intellisense for escaped fields, as well as allow the feature of custom field property names.
507
- */
508
- export type PropertyNameFromFieldKey<T extends string> =
509
- T extends ReservedObjectNodeFieldPropertyNames
510
- ? `field${Capitalize<T>}`
511
- : T extends `${ReservedObjectNodeFieldPropertyNamePrefixes}${Capitalize<string>}`
512
- ? `field${Capitalize<T>}`
513
- : T;
514
-
515
354
  /**
516
355
  * Field kinds that allow value assignment.
517
356
  */
@@ -588,12 +427,6 @@ export interface FlexTreeSequenceField<in out TTypes extends FlexAllowedTypes>
588
427
  */
589
428
  map<U>(callbackfn: (value: FlexTreeUnboxNodeUnion<TTypes>, index: number) => U): U[];
590
429
 
591
- /**
592
- * Calls the provided callback function on each child of this sequence, and returns an array that contains the results.
593
- * @param callbackfn - A function that accepts the child and its index.
594
- */
595
- mapBoxed<U>(callbackfn: (value: FlexTreeTypedNodeUnion<TTypes>, index: number) => U): U[];
596
-
597
430
  readonly length: number;
598
431
 
599
432
  /**
@@ -687,7 +520,7 @@ export type FlexTreeTypedNode<TSchema extends FlexTreeNodeSchema> =
687
520
  : TSchema extends FlexMapNodeSchema
688
521
  ? FlexTreeMapNode<TSchema>
689
522
  : TSchema extends FlexObjectNodeSchema
690
- ? FlexTreeObjectNodeTyped<TSchema>
523
+ ? FlexTreeObjectNode
691
524
  : FlexTreeNode;
692
525
 
693
526
  // #endregion
@@ -764,7 +597,7 @@ export type FlexTreeUnboxNode<TSchema extends FlexTreeNodeSchema> =
764
597
  : TSchema extends FlexMapNodeSchema
765
598
  ? FlexTreeMapNode<TSchema>
766
599
  : TSchema extends FlexObjectNodeSchema
767
- ? FlexTreeObjectNodeTyped<TSchema>
600
+ ? FlexTreeObjectNode
768
601
  : FlexTreeUnknownUnboxed;
769
602
 
770
603
  /**
@@ -16,7 +16,6 @@ export {
16
16
  type FlexTreeRequiredField,
17
17
  type FlexTreeSequenceField,
18
18
  type FlexTreeObjectNode,
19
- type FlexTreeObjectNodeTyped,
20
19
  type AssignableFieldKinds,
21
20
  type FlexTreeTypedNode,
22
21
  type FlexTreeTypedNodeUnion,
@@ -27,12 +26,6 @@ export {
27
26
  flexTreeMarker,
28
27
  FlexTreeEntityKind,
29
28
  isFlexTreeNode,
30
- type PropertyNameFromFieldKey,
31
- type ReservedObjectNodeFieldPropertyNames,
32
- type ReservedObjectNodeFieldPropertyNamePrefixes,
33
- reservedObjectNodeFieldPropertyNames,
34
- reservedObjectNodeFieldPropertyNamePrefixes,
35
- type FlexTreeObjectNodeFieldsInner,
36
29
  flexTreeSlot,
37
30
  } from "./flexTreeTypes.js";
38
31
 
@@ -48,16 +41,7 @@ export { getTreeContext, type FlexTreeContext, Context, ContextSlot } from "./co
48
41
 
49
42
  export { type FlexTreeNodeEvents } from "./treeEvents.js";
50
43
 
51
- // Below here are things that are used by the above, but not part of the desired API surface.
52
- export type {
53
- FlexTreeTypedFieldInner,
54
- FlexTreeUnboxFieldInner,
55
- FlexTreeObjectNodeFields,
56
- FlexTreeUnboxNode,
57
- FlexTreeUnboxNodeUnion,
58
- IsArrayOfOne,
59
- FlexibleNodeSubSequence,
60
- } from "./flexTreeTypes.js";
44
+ export type { FlexTreeUnboxNodeUnion } from "./flexTreeTypes.js";
61
45
 
62
46
  export {
63
47
  assertFlexTreeEntityNotFreed,
@@ -225,12 +225,6 @@ export abstract class LazyField<
225
225
  return Array.from(this, callbackfn);
226
226
  }
227
227
 
228
- public mapBoxed<U>(
229
- callbackfn: (value: FlexTreeTypedNodeUnion<TTypes>, index: number) => U,
230
- ): U[] {
231
- return Array.from(this.boxedIterator(), callbackfn);
232
- }
233
-
234
228
  public boxedIterator(): IterableIterator<FlexTreeTypedNodeUnion<TTypes>> {
235
229
  return iterateCursorField(
236
230
  this[cursorSymbol],
@@ -19,14 +19,12 @@ import {
19
19
  mapCursorFields,
20
20
  rootFieldKey,
21
21
  } from "../../core/index.js";
22
- import { brand, capitalize, disposeSymbol, fail, getOrCreate } from "../../util/index.js";
22
+ import { brand, disposeSymbol, fail } from "../../util/index.js";
23
23
  import { FieldKinds } from "../default-schema/index.js";
24
24
  import {
25
25
  Any,
26
- type FlexAllowedTypes,
27
26
  FlexFieldSchema,
28
27
  type FlexMapNodeSchema,
29
- type FlexObjectNodeSchema,
30
28
  type FlexTreeNodeSchema,
31
29
  type LeafNodeSchema,
32
30
  schemaIsLeaf,
@@ -41,18 +39,11 @@ import {
41
39
  type FlexTreeLeafNode,
42
40
  type FlexTreeMapNode,
43
41
  type FlexTreeNode,
44
- type FlexTreeObjectNodeTyped,
45
- type FlexTreeOptionalField,
46
- type FlexTreeRequiredField,
47
42
  type FlexTreeTypedField,
48
43
  type FlexTreeTypedNode,
49
44
  type FlexTreeUnboxField,
50
- type FlexibleNodeContent,
51
- type PropertyNameFromFieldKey,
52
45
  flexTreeMarker,
53
46
  flexTreeSlot,
54
- reservedObjectNodeFieldPropertyNamePrefixes,
55
- reservedObjectNodeFieldPropertyNames,
56
47
  } from "./flexTreeTypes.js";
57
48
  import {
58
49
  LazyEntity,
@@ -103,7 +94,7 @@ function buildSubclass(
103
94
  return new LazyLeaf(context, schema, cursor, anchorNode, anchor);
104
95
  }
105
96
  if (schemaIsObjectNode(schema)) {
106
- return buildLazyObjectNode(context, schema, cursor, anchorNode, anchor);
97
+ return new LazyTreeNode(context, schema, cursor, anchorNode, anchor);
107
98
  }
108
99
  // TODO: there should be a common fallback that works for cases without a specialized implementation.
109
100
  fail("unrecognized node kind");
@@ -112,7 +103,7 @@ function buildSubclass(
112
103
  /**
113
104
  * Lazy implementation of {@link FlexTreeNode}.
114
105
  */
115
- export abstract class LazyTreeNode<TSchema extends FlexTreeNodeSchema = FlexTreeNodeSchema>
106
+ export class LazyTreeNode<TSchema extends FlexTreeNodeSchema = FlexTreeNodeSchema>
116
107
  extends LazyEntity<TSchema, Anchor>
117
108
  implements FlexTreeNode
118
109
  {
@@ -307,10 +298,6 @@ export class LazyMap<TSchema extends FlexMapNodeSchema>
307
298
  return super.getBoxed(brand(key)) as FlexTreeTypedField<TSchema["info"]>;
308
299
  }
309
300
 
310
- public override boxedIterator(): IterableIterator<FlexTreeTypedField<TSchema["info"]>> {
311
- return super.boxedIterator() as IterableIterator<FlexTreeTypedField<TSchema["info"]>>;
312
- }
313
-
314
301
  public [Symbol.iterator](): IterableIterator<
315
302
  [FieldKey, FlexTreeUnboxField<TSchema["info"], "notEmpty">]
316
303
  > {
@@ -337,54 +324,6 @@ export class LazyLeaf<TSchema extends LeafNodeSchema>
337
324
  }
338
325
  }
339
326
 
340
- /**
341
- * {@link reservedObjectNodeFieldPropertyNames} but as a set.
342
- */
343
- export const reservedObjectNodeFieldPropertyNameSet: ReadonlySet<string> = new Set(
344
- reservedObjectNodeFieldPropertyNames,
345
- );
346
-
347
- export function propertyNameFromFieldKey<T extends string>(
348
- key: T,
349
- ): PropertyNameFromFieldKey<T> {
350
- if (reservedObjectNodeFieldPropertyNameSet.has(key)) {
351
- return `field${capitalize(key)}` as PropertyNameFromFieldKey<T>;
352
- }
353
- for (const prefix of reservedObjectNodeFieldPropertyNamePrefixes) {
354
- if (key.startsWith(prefix)) {
355
- const afterPrefix = key.slice(prefix.length);
356
- if (afterPrefix === capitalize(afterPrefix)) {
357
- return `field${capitalize(key)}` as PropertyNameFromFieldKey<T>;
358
- }
359
- }
360
- }
361
- return key as PropertyNameFromFieldKey<T>;
362
- }
363
-
364
- export function buildLazyObjectNode<TSchema extends FlexObjectNodeSchema>(
365
- context: Context,
366
- schema: TSchema,
367
- cursor: ITreeSubscriptionCursor,
368
- anchorNode: AnchorNode,
369
- anchor: Anchor,
370
- ): LazyTreeNode<TSchema> & FlexTreeObjectNodeTyped<TSchema> {
371
- const objectNodeClass = getOrCreate(cachedStructClasses, schema, () =>
372
- buildStructClass(schema),
373
- );
374
- return new objectNodeClass(context, cursor, anchorNode, anchor) as LazyTreeNode<TSchema> &
375
- FlexTreeObjectNodeTyped<TSchema>;
376
- }
377
-
378
- const cachedStructClasses = new WeakMap<
379
- FlexObjectNodeSchema,
380
- new (
381
- context: Context,
382
- cursor: ITreeSubscriptionCursor,
383
- anchorNode: AnchorNode,
384
- anchor: Anchor,
385
- ) => LazyTreeNode<FlexObjectNodeSchema>
386
- >();
387
-
388
327
  function getBoxedField(
389
328
  objectNode: LazyTreeNode,
390
329
  key: FieldKey,
@@ -394,93 +333,3 @@ function getBoxedField(
394
333
  return makeField(objectNode.context, fieldSchema, cursor);
395
334
  });
396
335
  }
397
-
398
- function buildStructClass<TSchema extends FlexObjectNodeSchema>(
399
- schema: TSchema,
400
- ): new (
401
- context: Context,
402
- cursor: ITreeSubscriptionCursor,
403
- anchorNode: AnchorNode,
404
- anchor: Anchor,
405
- ) => LazyTreeNode<TSchema> {
406
- const propertyDescriptorMap: PropertyDescriptorMap = {};
407
-
408
- for (const [key, fieldSchema] of schema.objectNodeFields) {
409
- const escapedKey = propertyNameFromFieldKey(key);
410
- let setter: ((newContent: FlexibleNodeContent) => void) | undefined;
411
- switch (fieldSchema.kind) {
412
- case FieldKinds.optional: {
413
- setter = function (
414
- this: CustomStruct,
415
- newContent: FlexibleNodeContent | undefined,
416
- ): void {
417
- const field = getBoxedField(
418
- this,
419
- key,
420
- fieldSchema,
421
- ) as FlexTreeOptionalField<FlexAllowedTypes>;
422
- field.editor.set(newContent, field.length === 0);
423
- };
424
- break;
425
- }
426
- case FieldKinds.required: {
427
- setter = function (this: CustomStruct, newContent: FlexibleNodeContent): void {
428
- const field = getBoxedField(
429
- this,
430
- key,
431
- fieldSchema,
432
- ) as FlexTreeRequiredField<FlexAllowedTypes>;
433
- field.editor.set(newContent);
434
- };
435
- break;
436
- }
437
- default:
438
- setter = undefined;
439
- break;
440
- }
441
-
442
- // Create getter and setter (when appropriate) for property
443
- propertyDescriptorMap[escapedKey] = {
444
- enumerable: true,
445
- get(this: CustomStruct): unknown {
446
- return inCursorField(this[cursorSymbol], key, (cursor) =>
447
- unboxedField(this.context, fieldSchema, cursor),
448
- );
449
- },
450
- set: setter,
451
- };
452
-
453
- // Create set method for property (when appropriate)
454
- if (setter !== undefined) {
455
- propertyDescriptorMap[`set${capitalize(escapedKey)}`] = {
456
- enumerable: false,
457
- get(this: CustomStruct) {
458
- return setter;
459
- },
460
- };
461
- }
462
-
463
- propertyDescriptorMap[`boxed${capitalize(escapedKey)}`] = {
464
- enumerable: false,
465
- get(this: CustomStruct) {
466
- return getBoxedField(this, key, fieldSchema);
467
- },
468
- };
469
- }
470
-
471
- // This must implement `StructTyped<TSchema>`, but TypeScript can't constrain it to do so.
472
- class CustomStruct extends LazyTreeNode<TSchema> {
473
- public constructor(
474
- context: Context,
475
- cursor: ITreeSubscriptionCursor,
476
- anchorNode: AnchorNode,
477
- anchor: Anchor,
478
- ) {
479
- super(context, schema, cursor, anchorNode, anchor);
480
- }
481
- }
482
-
483
- Object.defineProperties(CustomStruct.prototype, propertyDescriptorMap);
484
-
485
- return CustomStruct;
486
- }
@@ -224,7 +224,6 @@ export {
224
224
  type FlexTreeSequenceField,
225
225
  Skip,
226
226
  type FlexTreeObjectNode,
227
- type FlexTreeObjectNodeTyped,
228
227
  type FlexTreeContext,
229
228
  type FlexTreeTypedField,
230
229
  type FlexTreeTypedNode,
@@ -241,22 +240,9 @@ export {
241
240
  isFlexTreeNode,
242
241
  ContextSlot,
243
242
  // Internal
244
- type FlexTreeTypedFieldInner,
245
- type FlexTreeUnboxFieldInner,
246
- type FlexTreeObjectNodeFields,
247
243
  type FlexTreeUnboxField,
248
- type FlexTreeUnboxNode,
249
- type FlexTreeUnboxNodeUnion,
250
- type IsArrayOfOne,
251
- type FlexibleNodeSubSequence,
252
244
  flexTreeMarker,
253
245
  FlexTreeEntityKind,
254
- type PropertyNameFromFieldKey,
255
- type ReservedObjectNodeFieldPropertyNames,
256
- type ReservedObjectNodeFieldPropertyNamePrefixes,
257
- reservedObjectNodeFieldPropertyNames,
258
- reservedObjectNodeFieldPropertyNamePrefixes,
259
- type FlexTreeObjectNodeFieldsInner,
260
246
  assertFlexTreeEntityNotFreed,
261
247
  flexTreeSlot,
262
248
  getSchemaAndPolicy,
package/src/index.ts CHANGED
@@ -36,6 +36,13 @@ export {
36
36
  type IsListener,
37
37
  type Listenable,
38
38
  type Off,
39
+ // Alpha APIs for using event library to implement events externally.
40
+ // If stabilizing these APIs, they should probably move out of the tree package first.
41
+ createEmitter,
42
+ EventEmitter,
43
+ type IEmitter,
44
+ type HasListeners,
45
+ type NoListenersCallback,
39
46
  } from "./events/index.js";
40
47
 
41
48
  export {
@@ -93,6 +100,7 @@ export {
93
100
  type FieldProps,
94
101
  type InternalTreeNode,
95
102
  type WithType,
103
+ type NodeChangedData,
96
104
  // Types not really intended for public use, but used in links.
97
105
  // Can not be moved to internalTypes since doing so causes app code to throw errors like:
98
106
  // Error: src/simple-tree/objectNode.ts:72:1 - (ae-unresolved-link) The @link reference could not be resolved: The package "@fluidframework/tree" does not have an export "TreeNodeApi"
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tree";
9
- export const pkgVersion = "2.2.0";
9
+ export const pkgVersion = "2.3.0-288113";
@@ -44,6 +44,7 @@ import {
44
44
  type TreeChangeEvents,
45
45
  tryGetTreeNodeSchema,
46
46
  } from "../core/index.js";
47
+ import { isObjectNodeSchema } from "../objectNodeTypes.js";
47
48
 
48
49
  /**
49
50
  * Provides various functions for analyzing {@link TreeNode}s.
@@ -98,10 +99,10 @@ export interface TreeNodeApi {
98
99
  * @returns A callback function which will deregister the event.
99
100
  * This callback should be called only once.
100
101
  */
101
- on<K extends keyof TreeChangeEvents>(
102
- node: TreeNode,
102
+ on<K extends keyof TreeChangeEvents<TNode>, TNode extends TreeNode>(
103
+ node: TNode,
103
104
  eventName: K,
104
- listener: TreeChangeEvents[K],
105
+ listener: TreeChangeEvents<TNode>[K],
105
106
  ): () => void;
106
107
 
107
108
  /**
@@ -167,7 +168,38 @@ export const treeNodeApi: TreeNodeApi = {
167
168
  eventName: K,
168
169
  listener: TreeChangeEvents[K],
169
170
  ): Off {
170
- return getKernel(node).on(eventName, listener);
171
+ const kernel = getKernel(node);
172
+ switch (eventName) {
173
+ case "nodeChanged": {
174
+ const nodeSchema = kernel.schema;
175
+ if (isObjectNodeSchema(nodeSchema)) {
176
+ return kernel.on("childrenChangedAfterBatch", ({ changedFields }) => {
177
+ const changedProperties = new Set(
178
+ Array.from(
179
+ changedFields,
180
+ (field) =>
181
+ nodeSchema.storedKeyToPropertyKey.get(field) ??
182
+ fail(`Could not find stored key '${field}' in schema.`),
183
+ ),
184
+ );
185
+ listener({ changedProperties });
186
+ });
187
+ } else if (nodeSchema.kind === NodeKind.Array) {
188
+ return kernel.on("childrenChangedAfterBatch", () => {
189
+ listener({ changedProperties: undefined });
190
+ });
191
+ } else {
192
+ return kernel.on("childrenChangedAfterBatch", ({ changedFields }) => {
193
+ listener({ changedProperties: changedFields });
194
+ });
195
+ }
196
+ }
197
+ case "treeChanged": {
198
+ return kernel.on("subtreeChangedAfterBatch", () => listener({}));
199
+ }
200
+ default:
201
+ throw new UsageError(`No event named ${JSON.stringify(eventName)}.`);
202
+ }
171
203
  },
172
204
  status(node: TreeNode): TreeStatus {
173
205
  return getKernel(node).getStatus();
@@ -245,7 +277,7 @@ export function tryGetSchema(value: unknown): undefined | TreeNodeSchema {
245
277
  return booleanSchema;
246
278
  case "object": {
247
279
  if (isTreeNode(value)) {
248
- // This case could be optimized, for example by placing the simple schema in a symbol on tree nodes.
280
+ // TODO: This case could be optimized, for example by placing the simple schema in a symbol on tree nodes.
249
281
  return tryGetTreeNodeSchema(value);
250
282
  }
251
283
  if (value === null) {
@@ -670,19 +670,10 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
670
670
 
671
671
  protected abstract get simpleSchema(): T;
672
672
 
673
- /**
674
- * Generation number which is incremented any time we have an edit on the node.
675
- * Used during iteration to make sure there has been no edits that were concurrently made.
676
- */
677
- #generationNumber: number = 0;
678
-
679
673
  public constructor(
680
674
  input: Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>> | InternalTreeNode,
681
675
  ) {
682
676
  super(input);
683
- getKernel(this).on("nodeChanged", () => {
684
- this.#generationNumber += 1;
685
- });
686
677
  }
687
678
 
688
679
  #mapTreesFromFieldData(value: Insertable<T>): ExclusiveMapTree[] {
@@ -884,17 +875,17 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
884
875
  }
885
876
 
886
877
  public values(): IterableIterator<TreeNodeFromImplicitAllowedTypes<T>> {
887
- return this.generateValues(this.#generationNumber);
878
+ return this.generateValues(getKernel(this).generationNumber);
888
879
  }
889
880
  private *generateValues(
890
881
  initialLastUpdatedStamp: number,
891
882
  ): Generator<TreeNodeFromImplicitAllowedTypes<T>> {
892
- if (initialLastUpdatedStamp !== this.#generationNumber) {
883
+ if (initialLastUpdatedStamp !== getKernel(this).generationNumber) {
893
884
  throw new UsageError(`Concurrent editing and iteration is not allowed.`);
894
885
  }
895
886
  for (let i = 0; i < this.length; i++) {
896
887
  yield this.at(i) ?? fail("Index is out of bounds");
897
- if (initialLastUpdatedStamp !== this.#generationNumber) {
888
+ if (initialLastUpdatedStamp !== getKernel(this).generationNumber) {
898
889
  throw new UsageError(`Concurrent editing and iteration is not allowed.`);
899
890
  }
900
891
  }
@@ -17,6 +17,7 @@ export {
17
17
  inPrototypeChain,
18
18
  type InternalTreeNode,
19
19
  privateToken,
20
+ type NodeChangedData,
20
21
  } from "./types.js";
21
22
  export {
22
23
  type TreeNodeSchema,