@fluidframework/tree 2.61.0-355990 → 2.61.0-356132
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.
- package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +2 -0
- package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
- package/dist/feature-libraries/flex-tree/observer.d.ts +8 -0
- package/dist/feature-libraries/flex-tree/observer.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/observer.js +3 -0
- package/dist/feature-libraries/flex-tree/observer.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/shared-tree/treeAlpha.d.ts +1 -1
- package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
- package/dist/shared-tree/treeAlpha.js +85 -65
- package/dist/shared-tree/treeAlpha.js.map +1 -1
- package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +2 -0
- package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
- package/lib/feature-libraries/flex-tree/observer.d.ts +8 -0
- package/lib/feature-libraries/flex-tree/observer.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/observer.js +3 -0
- package/lib/feature-libraries/flex-tree/observer.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/shared-tree/treeAlpha.d.ts +1 -1
- package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
- package/lib/shared-tree/treeAlpha.js +86 -66
- package/lib/shared-tree/treeAlpha.js.map +1 -1
- package/package.json +23 -23
- package/src/feature-libraries/flex-tree/flexTreeTypes.ts +2 -0
- package/src/feature-libraries/flex-tree/observer.ts +18 -1
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/treeAlpha.ts +99 -74
|
@@ -17,13 +17,13 @@ import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
|
17
17
|
import {
|
|
18
18
|
asIndex,
|
|
19
19
|
getKernel,
|
|
20
|
+
TreeNode,
|
|
20
21
|
type Unhydrated,
|
|
21
22
|
TreeBeta,
|
|
22
23
|
tryGetSchema,
|
|
23
24
|
createFromCursor,
|
|
24
25
|
FieldKind,
|
|
25
26
|
normalizeFieldSchema,
|
|
26
|
-
TreeNode,
|
|
27
27
|
type ImplicitFieldSchema,
|
|
28
28
|
type InsertableField,
|
|
29
29
|
type TreeFieldFromImplicitField,
|
|
@@ -454,15 +454,20 @@ export interface TreeAlpha {
|
|
|
454
454
|
): { result: TResult; unsubscribe: () => void };
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Subscription to changes on a single node.
|
|
459
|
+
* @remarks
|
|
460
|
+
* Either tracks some set of fields, or all fields and can be updated to track more fields.
|
|
461
|
+
*/
|
|
457
462
|
class NodeSubscription {
|
|
458
463
|
/**
|
|
459
464
|
* If undefined, subscribes to all keys.
|
|
460
465
|
* Otherwise only subscribes to the keys in the set.
|
|
461
466
|
*/
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
467
|
+
private keys: Set<FieldKey> | undefined;
|
|
468
|
+
private readonly unsubscribe: () => void;
|
|
469
|
+
private constructor(
|
|
470
|
+
private readonly onInvalidation: () => void,
|
|
466
471
|
flexNode: FlexTreeNode,
|
|
467
472
|
) {
|
|
468
473
|
// TODO:Performance: It is possible to optimize this to not use the public TreeNode API.
|
|
@@ -492,8 +497,93 @@ class NodeSubscription {
|
|
|
492
497
|
};
|
|
493
498
|
this.unsubscribe = TreeBeta.on(node, "nodeChanged", handler);
|
|
494
499
|
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Create an {@link Observer} which subscribes to what was observed in {@link NodeSubscription}s.
|
|
503
|
+
*/
|
|
504
|
+
public static createObserver(
|
|
505
|
+
invalidate: () => void,
|
|
506
|
+
onlyOnce = false,
|
|
507
|
+
): { observer: Observer; unsubscribe: () => void } {
|
|
508
|
+
const subscriptions = new Map<FlexTreeNode, NodeSubscription>();
|
|
509
|
+
const observer: Observer = {
|
|
510
|
+
observeNodeFields(flexNode: FlexTreeNode): void {
|
|
511
|
+
if (flexNode.value !== undefined) {
|
|
512
|
+
// Leaf value, nothing to observe.
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
const subscription = subscriptions.get(flexNode);
|
|
516
|
+
if (subscription !== undefined) {
|
|
517
|
+
// Already subscribed to this node.
|
|
518
|
+
subscription.keys = undefined; // Now subscribed to all keys.
|
|
519
|
+
} else {
|
|
520
|
+
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
521
|
+
subscriptions.set(flexNode, newSubscription);
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
observeNodeField(flexNode: FlexTreeNode, key: FieldKey): void {
|
|
525
|
+
if (flexNode.value !== undefined) {
|
|
526
|
+
// Leaf value, nothing to observe.
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
const subscription = subscriptions.get(flexNode);
|
|
530
|
+
if (subscription !== undefined) {
|
|
531
|
+
// Already subscribed to this node: if not subscribed to all keys, subscribe to this one.
|
|
532
|
+
// TODO:Performance: due to how JavaScript set ordering works,
|
|
533
|
+
// it might be faster to check `has` and only add if not present in case the same field is viewed many times.
|
|
534
|
+
subscription.keys?.add(key);
|
|
535
|
+
} else {
|
|
536
|
+
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
537
|
+
newSubscription.keys = new Set([key]);
|
|
538
|
+
subscriptions.set(flexNode, newSubscription);
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
observeParentOf(node: FlexTreeNode): void {
|
|
542
|
+
// Supporting parent tracking is more difficult that it might seem at first.
|
|
543
|
+
// There are two main complicating factors:
|
|
544
|
+
// 1. The parent may be undefined (the node is a root).
|
|
545
|
+
// 2. If tracking this by subscribing to the parent's changes, then which events are subscribed to needs to be updated after the parent changes.
|
|
546
|
+
//
|
|
547
|
+
// If not supporting the first case (undefined parents), the second case gets problematic since it would result in edits which take a node who's parent was observed,
|
|
548
|
+
// and un-parent it, could then throw a usage error.
|
|
549
|
+
|
|
550
|
+
if (!onlyOnce) {
|
|
551
|
+
// TODO: better APIS should be provided which make handling this case practical.
|
|
552
|
+
throw new UsageError("Observation tracking for parents is currently not supported.");
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const parent = withObservation(undefined, () => node.parentField.parent);
|
|
556
|
+
|
|
557
|
+
if (parent.parent === undefined) {
|
|
558
|
+
// TODO: better APIS should be provided which make handling this case practical.
|
|
559
|
+
throw new UsageError(
|
|
560
|
+
"Observation tracking for parents is currently not supported when parent is undefined.",
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
observer.observeNodeField(parent.parent, parent.key);
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
let subscribed = true;
|
|
568
|
+
|
|
569
|
+
return {
|
|
570
|
+
observer,
|
|
571
|
+
unsubscribe: () => {
|
|
572
|
+
if (!subscribed) {
|
|
573
|
+
throw new UsageError("Already unsubscribed");
|
|
574
|
+
}
|
|
575
|
+
subscribed = false;
|
|
576
|
+
for (const subscription of subscriptions.values()) {
|
|
577
|
+
subscription.unsubscribe();
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
};
|
|
581
|
+
}
|
|
495
582
|
}
|
|
496
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Handles both {@link (TreeAlpha:interface).trackObservations} and {@link (TreeAlpha:interface).trackObservationsOnce}.
|
|
586
|
+
*/
|
|
497
587
|
function trackObservations<TResult>(
|
|
498
588
|
onInvalidation: () => void,
|
|
499
589
|
trackDuring: () => TResult,
|
|
@@ -508,80 +598,13 @@ function trackObservations<TResult>(
|
|
|
508
598
|
onInvalidation();
|
|
509
599
|
};
|
|
510
600
|
|
|
511
|
-
const
|
|
512
|
-
const observer: Observer = {
|
|
513
|
-
observeNodeFields(flexNode: FlexTreeNode): void {
|
|
514
|
-
if (flexNode.value !== undefined) {
|
|
515
|
-
// Leaf value, nothing to observe.
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
const subscription = subscriptions.get(flexNode);
|
|
519
|
-
if (subscription !== undefined) {
|
|
520
|
-
// Already subscribed to this node.
|
|
521
|
-
subscription.keys = undefined; // Now subscribed to all keys.
|
|
522
|
-
} else {
|
|
523
|
-
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
524
|
-
subscriptions.set(flexNode, newSubscription);
|
|
525
|
-
}
|
|
526
|
-
},
|
|
527
|
-
observeNodeField(flexNode: FlexTreeNode, key: FieldKey): void {
|
|
528
|
-
if (flexNode.value !== undefined) {
|
|
529
|
-
// Leaf value, nothing to observe.
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
const subscription = subscriptions.get(flexNode);
|
|
533
|
-
if (subscription !== undefined) {
|
|
534
|
-
// Already subscribed to this node: if not subscribed to all keys, subscribe to this one.
|
|
535
|
-
// TODO:Performance: due to how JavaScript set ordering works,
|
|
536
|
-
// it might be faster to check `has` and only add if not present in case the same field is viewed many times.
|
|
537
|
-
subscription.keys?.add(key);
|
|
538
|
-
} else {
|
|
539
|
-
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
540
|
-
newSubscription.keys = new Set([key]);
|
|
541
|
-
subscriptions.set(flexNode, newSubscription);
|
|
542
|
-
}
|
|
543
|
-
},
|
|
544
|
-
observeParentOf(node: FlexTreeNode): void {
|
|
545
|
-
// Supporting parent tracking is more difficult that it might seem at first.
|
|
546
|
-
// There are two main complicating factors:
|
|
547
|
-
// 1. The parent may be undefined (the node is a root).
|
|
548
|
-
// 2. If tracking this by subscribing to the parent's changes, then which events are subscribed to needs to be updated after the parent changes.
|
|
549
|
-
//
|
|
550
|
-
// If not supporting the first case (undefined parents), the second case gets problematic since it would result in edits which take a node who's parent was observed,
|
|
551
|
-
// and un-parent it, could then throw a usage error.
|
|
552
|
-
|
|
553
|
-
if (!onlyOnce) {
|
|
554
|
-
// TODO: better APIS should be provided which make handling this case practical.
|
|
555
|
-
throw new UsageError("Observation tracking for parents is currently not supported.");
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const parent = withObservation(undefined, () => node.parentField.parent);
|
|
559
|
-
|
|
560
|
-
if (parent.parent === undefined) {
|
|
561
|
-
// TODO: better APIS should be provided which make handling this case practical.
|
|
562
|
-
throw new UsageError(
|
|
563
|
-
"Observation tracking for parents is currently not supported when parent is undefined.",
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
observer.observeNodeField(parent.parent, parent.key);
|
|
567
|
-
},
|
|
568
|
-
};
|
|
601
|
+
const { observer, unsubscribe } = NodeSubscription.createObserver(invalidate, onlyOnce);
|
|
569
602
|
const result = withObservation(observer, trackDuring);
|
|
570
603
|
observing = false;
|
|
571
604
|
|
|
572
|
-
let subscribed = true;
|
|
573
|
-
|
|
574
605
|
return {
|
|
575
606
|
result,
|
|
576
|
-
unsubscribe
|
|
577
|
-
if (!subscribed) {
|
|
578
|
-
throw new UsageError("Already unsubscribed");
|
|
579
|
-
}
|
|
580
|
-
subscribed = false;
|
|
581
|
-
for (const subscription of subscriptions.values()) {
|
|
582
|
-
subscription.unsubscribe();
|
|
583
|
-
}
|
|
584
|
-
},
|
|
607
|
+
unsubscribe,
|
|
585
608
|
};
|
|
586
609
|
}
|
|
587
610
|
|
|
@@ -604,6 +627,8 @@ export const TreeAlpha: TreeAlpha = {
|
|
|
604
627
|
): { result: TResult; unsubscribe: () => void } {
|
|
605
628
|
const result = trackObservations(
|
|
606
629
|
() => {
|
|
630
|
+
// trackObservations ensures no invalidation occurs while its running,
|
|
631
|
+
// so this callback can only run after trackObservations has returns and thus result is defined.
|
|
607
632
|
result.unsubscribe();
|
|
608
633
|
onInvalidation();
|
|
609
634
|
},
|