@fluidframework/tree 2.61.0-356132 → 2.61.0-356312
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/api-report/tree.alpha.api.md +14 -8
- package/dist/alpha.d.ts +3 -0
- package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +0 -2
- 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/index.d.ts +0 -1
- package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/index.js +1 -4
- package/dist/feature-libraries/flex-tree/index.js.map +1 -1
- package/dist/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/lazyNode.js +8 -15
- package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
- package/dist/feature-libraries/index.d.ts +1 -1
- package/dist/feature-libraries/index.d.ts.map +1 -1
- package/dist/feature-libraries/index.js +1 -3
- package/dist/feature-libraries/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.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 -28
- package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
- package/dist/shared-tree/treeAlpha.js +0 -139
- package/dist/shared-tree/treeAlpha.js.map +1 -1
- package/dist/simple-tree/api/dirtyIndex.d.ts +43 -0
- package/dist/simple-tree/api/dirtyIndex.d.ts.map +1 -0
- package/dist/simple-tree/api/dirtyIndex.js +122 -0
- package/dist/simple-tree/api/dirtyIndex.js.map +1 -0
- package/dist/simple-tree/api/index.d.ts +1 -0
- package/dist/simple-tree/api/index.d.ts.map +1 -1
- package/dist/simple-tree/api/index.js +3 -1
- package/dist/simple-tree/api/index.js.map +1 -1
- package/dist/simple-tree/api/tree.d.ts +4 -3
- package/dist/simple-tree/api/tree.d.ts.map +1 -1
- package/dist/simple-tree/api/tree.js.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.js +1 -7
- package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/dist/simple-tree/index.d.ts +1 -1
- package/dist/simple-tree/index.d.ts.map +1 -1
- package/dist/simple-tree/index.js +3 -2
- package/dist/simple-tree/index.js.map +1 -1
- package/lib/alpha.d.ts +3 -0
- package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +0 -2
- 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/index.d.ts +0 -1
- package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/index.js +0 -1
- package/lib/feature-libraries/flex-tree/index.js.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyNode.js +8 -15
- package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
- package/lib/feature-libraries/index.d.ts +1 -1
- package/lib/feature-libraries/index.d.ts.map +1 -1
- package/lib/feature-libraries/index.js +1 -1
- package/lib/feature-libraries/index.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.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 -28
- package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
- package/lib/shared-tree/treeAlpha.js +2 -141
- package/lib/shared-tree/treeAlpha.js.map +1 -1
- package/lib/simple-tree/api/dirtyIndex.d.ts +43 -0
- package/lib/simple-tree/api/dirtyIndex.d.ts.map +1 -0
- package/lib/simple-tree/api/dirtyIndex.js +118 -0
- package/lib/simple-tree/api/dirtyIndex.js.map +1 -0
- package/lib/simple-tree/api/index.d.ts +1 -0
- package/lib/simple-tree/api/index.d.ts.map +1 -1
- package/lib/simple-tree/api/index.js +1 -0
- package/lib/simple-tree/api/index.js.map +1 -1
- package/lib/simple-tree/api/tree.d.ts +4 -3
- package/lib/simple-tree/api/tree.d.ts.map +1 -1
- package/lib/simple-tree/api/tree.js.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.js +2 -8
- package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/lib/simple-tree/index.d.ts +1 -1
- package/lib/simple-tree/index.d.ts.map +1 -1
- package/lib/simple-tree/index.js +1 -1
- package/lib/simple-tree/index.js.map +1 -1
- package/package.json +20 -20
- package/src/feature-libraries/flex-tree/flexTreeTypes.ts +0 -2
- package/src/feature-libraries/flex-tree/index.ts +0 -2
- package/src/feature-libraries/flex-tree/lazyNode.ts +3 -13
- package/src/feature-libraries/index.ts +0 -3
- package/src/index.ts +3 -0
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/treeAlpha.ts +2 -213
- package/src/simple-tree/api/dirtyIndex.ts +155 -0
- package/src/simple-tree/api/index.ts +5 -0
- package/src/simple-tree/api/tree.ts +4 -3
- package/src/simple-tree/core/unhydratedFlexTree.ts +2 -11
- package/src/simple-tree/index.ts +3 -0
- package/dist/feature-libraries/flex-tree/observer.d.ts +0 -27
- package/dist/feature-libraries/flex-tree/observer.d.ts.map +0 -1
- package/dist/feature-libraries/flex-tree/observer.js +0 -33
- package/dist/feature-libraries/flex-tree/observer.js.map +0 -1
- package/lib/feature-libraries/flex-tree/observer.d.ts +0 -27
- package/lib/feature-libraries/flex-tree/observer.d.ts.map +0 -1
- package/lib/feature-libraries/flex-tree/observer.js +0 -35
- package/lib/feature-libraries/flex-tree/observer.js.map +0 -1
- package/src/feature-libraries/flex-tree/observer.ts +0 -58
package/src/index.ts
CHANGED
package/src/packageVersion.ts
CHANGED
|
@@ -17,7 +17,7 @@ import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
|
17
17
|
import {
|
|
18
18
|
asIndex,
|
|
19
19
|
getKernel,
|
|
20
|
-
TreeNode,
|
|
20
|
+
type TreeNode,
|
|
21
21
|
type Unhydrated,
|
|
22
22
|
TreeBeta,
|
|
23
23
|
tryGetSchema,
|
|
@@ -55,7 +55,6 @@ import {
|
|
|
55
55
|
convertField,
|
|
56
56
|
toUnhydratedSchema,
|
|
57
57
|
type TreeParsingOptions,
|
|
58
|
-
type NodeChangedData,
|
|
59
58
|
} from "../simple-tree/index.js";
|
|
60
59
|
import { brand, extractFromOpaque, type JsonCompatible } from "../util/index.js";
|
|
61
60
|
import {
|
|
@@ -64,7 +63,7 @@ import {
|
|
|
64
63
|
type ICodecOptions,
|
|
65
64
|
type CodecWriteOptions,
|
|
66
65
|
} from "../codec/index.js";
|
|
67
|
-
import { EmptyKey, type
|
|
66
|
+
import { EmptyKey, type ITreeCursorSynchronous } from "../core/index.js";
|
|
68
67
|
import {
|
|
69
68
|
cursorForMapTreeField,
|
|
70
69
|
defaultSchemaPolicy,
|
|
@@ -77,9 +76,6 @@ import {
|
|
|
77
76
|
fluidVersionToFieldBatchCodecWriteVersion,
|
|
78
77
|
type LocalNodeIdentifier,
|
|
79
78
|
type FlexTreeSequenceField,
|
|
80
|
-
type FlexTreeNode,
|
|
81
|
-
type Observer,
|
|
82
|
-
withObservation,
|
|
83
79
|
} from "../feature-libraries/index.js";
|
|
84
80
|
import { independentInitializedView, type ViewContent } from "./independentView.js";
|
|
85
81
|
import { SchematizingSimpleTreeView, ViewSlot } from "./schematizingTreeView.js";
|
|
@@ -423,189 +419,6 @@ export interface TreeAlpha {
|
|
|
423
419
|
children(
|
|
424
420
|
node: TreeNode,
|
|
425
421
|
): Iterable<[propertyKey: string | number, child: TreeNode | TreeLeafValue]>;
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Track observations of any TreeNode content.
|
|
429
|
-
* @remarks
|
|
430
|
-
* This subscribes to changes to any nodes content observed during `trackDuring`.
|
|
431
|
-
*
|
|
432
|
-
* Currently this does not support tracking parentage (see {@link (TreeAlpha:interface).trackObservationsOnce} for a version which does):
|
|
433
|
-
* if accessing parentage during `trackDuring`, this will throw a usage error.
|
|
434
|
-
*
|
|
435
|
-
* This also does not track node status changes (e.g. whether a node is attached to a view or not).
|
|
436
|
-
* The current behavior of checking status is unspecified: future versions may track it, error, or ignore it.
|
|
437
|
-
*
|
|
438
|
-
* Even after onInvalidation is called, these subscriptions remain active until `unsubscribe` is called.
|
|
439
|
-
* See {@link (TreeAlpha:interface).trackObservationsOnce} for a version which automatically unsubscribes on the first invalidation.
|
|
440
|
-
*/
|
|
441
|
-
trackObservations<TResult>(
|
|
442
|
-
onInvalidation: () => void,
|
|
443
|
-
trackDuring: () => TResult,
|
|
444
|
-
): { result: TResult; unsubscribe: () => void };
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* {@link (TreeAlpha:interface).trackObservations} except automatically unsubscribes when the first invalidation occurs.
|
|
448
|
-
* @remarks
|
|
449
|
-
* This also supports tracking parentage, unlike {@link (TreeAlpha:interface).trackObservations}, as long as the parent is not undefined.
|
|
450
|
-
*/
|
|
451
|
-
trackObservationsOnce<TResult>(
|
|
452
|
-
onInvalidation: () => void,
|
|
453
|
-
trackDuring: () => TResult,
|
|
454
|
-
): { result: TResult; unsubscribe: () => void };
|
|
455
|
-
}
|
|
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
|
-
*/
|
|
462
|
-
class NodeSubscription {
|
|
463
|
-
/**
|
|
464
|
-
* If undefined, subscribes to all keys.
|
|
465
|
-
* Otherwise only subscribes to the keys in the set.
|
|
466
|
-
*/
|
|
467
|
-
private keys: Set<FieldKey> | undefined;
|
|
468
|
-
private readonly unsubscribe: () => void;
|
|
469
|
-
private constructor(
|
|
470
|
-
private readonly onInvalidation: () => void,
|
|
471
|
-
flexNode: FlexTreeNode,
|
|
472
|
-
) {
|
|
473
|
-
// TODO:Performance: It is possible to optimize this to not use the public TreeNode API.
|
|
474
|
-
const node = getOrCreateNodeFromInnerNode(flexNode);
|
|
475
|
-
assert(node instanceof TreeNode, "Unexpected leaf value");
|
|
476
|
-
|
|
477
|
-
const handler = (data: NodeChangedData): void => {
|
|
478
|
-
if (this.keys === undefined || data.changedProperties === undefined) {
|
|
479
|
-
this.onInvalidation();
|
|
480
|
-
} else {
|
|
481
|
-
let keyMap: ReadonlyMap<FieldKey, string> | undefined;
|
|
482
|
-
const schema = treeNodeApi.schema(node);
|
|
483
|
-
if (isObjectNodeSchema(schema)) {
|
|
484
|
-
keyMap = schema.storedKeyToPropertyKey;
|
|
485
|
-
}
|
|
486
|
-
// TODO:Performance: Ideally this would use Set.prototype.isDisjointFrom when available.
|
|
487
|
-
for (const flexKey of this.keys) {
|
|
488
|
-
// TODO:Performance: doing everything at the flex tree layer could avoid this translation
|
|
489
|
-
const key = keyMap?.get(flexKey) ?? flexKey;
|
|
490
|
-
|
|
491
|
-
if (data.changedProperties.has(key)) {
|
|
492
|
-
this.onInvalidation();
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
this.unsubscribe = TreeBeta.on(node, "nodeChanged", handler);
|
|
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
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Handles both {@link (TreeAlpha:interface).trackObservations} and {@link (TreeAlpha:interface).trackObservationsOnce}.
|
|
586
|
-
*/
|
|
587
|
-
function trackObservations<TResult>(
|
|
588
|
-
onInvalidation: () => void,
|
|
589
|
-
trackDuring: () => TResult,
|
|
590
|
-
onlyOnce = false,
|
|
591
|
-
): { result: TResult; unsubscribe: () => void } {
|
|
592
|
-
let observing = true;
|
|
593
|
-
|
|
594
|
-
const invalidate = (): void => {
|
|
595
|
-
if (observing) {
|
|
596
|
-
throw new UsageError("Cannot invalidate while tracking observations");
|
|
597
|
-
}
|
|
598
|
-
onInvalidation();
|
|
599
|
-
};
|
|
600
|
-
|
|
601
|
-
const { observer, unsubscribe } = NodeSubscription.createObserver(invalidate, onlyOnce);
|
|
602
|
-
const result = withObservation(observer, trackDuring);
|
|
603
|
-
observing = false;
|
|
604
|
-
|
|
605
|
-
return {
|
|
606
|
-
result,
|
|
607
|
-
unsubscribe,
|
|
608
|
-
};
|
|
609
422
|
}
|
|
610
423
|
|
|
611
424
|
/**
|
|
@@ -614,30 +427,6 @@ function trackObservations<TResult>(
|
|
|
614
427
|
* @alpha
|
|
615
428
|
*/
|
|
616
429
|
export const TreeAlpha: TreeAlpha = {
|
|
617
|
-
trackObservations<TResult>(
|
|
618
|
-
onInvalidation: () => void,
|
|
619
|
-
trackDuring: () => TResult,
|
|
620
|
-
): { result: TResult; unsubscribe: () => void } {
|
|
621
|
-
return trackObservations(onInvalidation, trackDuring);
|
|
622
|
-
},
|
|
623
|
-
|
|
624
|
-
trackObservationsOnce<TResult>(
|
|
625
|
-
onInvalidation: () => void,
|
|
626
|
-
trackDuring: () => TResult,
|
|
627
|
-
): { result: TResult; unsubscribe: () => void } {
|
|
628
|
-
const result = trackObservations(
|
|
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.
|
|
632
|
-
result.unsubscribe();
|
|
633
|
-
onInvalidation();
|
|
634
|
-
},
|
|
635
|
-
trackDuring,
|
|
636
|
-
true,
|
|
637
|
-
);
|
|
638
|
-
return result;
|
|
639
|
-
},
|
|
640
|
-
|
|
641
430
|
branch(node: TreeNode): TreeBranch | undefined {
|
|
642
431
|
const kernel = getKernel(node);
|
|
643
432
|
if (!kernel.isHydrated()) {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { assert } from "@fluidframework/core-utils/internal";
|
|
7
|
+
import {
|
|
8
|
+
createAnnouncedVisitor,
|
|
9
|
+
CursorLocationType,
|
|
10
|
+
type AnnouncedVisitor,
|
|
11
|
+
type FieldKey,
|
|
12
|
+
type IEditableForest,
|
|
13
|
+
type UpPath,
|
|
14
|
+
} from "../../core/index.js";
|
|
15
|
+
import { TreeNode, treeNodeFromAnchor } from "../core/index.js";
|
|
16
|
+
import type { TreeViewAlpha } from "./tree.js";
|
|
17
|
+
import type { SchematizingSimpleTreeView } from "../../shared-tree/index.js";
|
|
18
|
+
import type { ImplicitFieldSchema } from "../fieldSchema.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The status of a node in a that has been {@link trackDirtyNodes | tracked for changes}.
|
|
22
|
+
* @remarks Nodes can be marked "new", "changed", or "moved", with "new" taking precedence over "changed" and "changed" taking precedence over "moved".
|
|
23
|
+
* * "new": The node was added.
|
|
24
|
+
* * "changed": A direct child was updated, added, removed, or moved (and the node is not "new").
|
|
25
|
+
* * "moved": The node was moved between/within arrays (and the node is not "new" or "changed").
|
|
26
|
+
* @alpha
|
|
27
|
+
*/
|
|
28
|
+
export type DirtyTreeStatus = "new" | "changed" | "moved";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A map-like interface for tracking the {@link DirtyTreeStatus | status} of nodes that have been {@link trackDirtyNodes | tracked for changes}.
|
|
32
|
+
* @privateRemarks TODO: Replace this with `MapGetSet` from `@fluidframework/core-interfaces`.
|
|
33
|
+
* @alpha
|
|
34
|
+
*/
|
|
35
|
+
export interface DirtyTreeMap {
|
|
36
|
+
get(node: TreeNode): DirtyTreeStatus | undefined;
|
|
37
|
+
set(node: TreeNode, status: DirtyTreeStatus): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Registers a visitor on the view's forest that tracks which nodes are dirty.
|
|
42
|
+
* @param view - The view to track dirty nodes on
|
|
43
|
+
* @param dirty - A {@link DirtyTreeMap | map} that will be updated over time to reflect the {@link DirtyTreeStatus | status} of nodes as they change.
|
|
44
|
+
* Nodes that have not changed will not be inserted/updated in the map.
|
|
45
|
+
* @returns a cleanup function that should be called when the tracking is no longer needed.
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const dirty = new Map<TreeNode, DirtyTreeStatus>();
|
|
49
|
+
* const stopTracking = trackDirtyNodes(view, dirty);
|
|
50
|
+
* // ... make changes to the view ...
|
|
51
|
+
* console.log(`The root of the tree is ${dirty.get(view.root) ?? "unchanged"}`);
|
|
52
|
+
* stopTracking();
|
|
53
|
+
* ```
|
|
54
|
+
* @alpha
|
|
55
|
+
*/
|
|
56
|
+
export function trackDirtyNodes(
|
|
57
|
+
view: TreeViewAlpha<ImplicitFieldSchema>,
|
|
58
|
+
dirty: DirtyTreeMap,
|
|
59
|
+
): () => void {
|
|
60
|
+
const forest = (view as SchematizingSimpleTreeView<ImplicitFieldSchema>).checkout.forest;
|
|
61
|
+
const announcedVisitor = (): AnnouncedVisitor => createDirtyVisitor(forest, dirty);
|
|
62
|
+
forest.registerAnnouncedVisitor(announcedVisitor);
|
|
63
|
+
return () => {
|
|
64
|
+
forest.deregisterAnnouncedVisitor(announcedVisitor);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function createDirtyVisitor(forest: IEditableForest, dirty: DirtyTreeMap): AnnouncedVisitor {
|
|
69
|
+
// When cursor is in Fields mode, `parentField` is the field and `parent` is the parent node above that field (if any).
|
|
70
|
+
// When cursor is in Nodes mode, `parent` is the current node and `parentField` is undefined.
|
|
71
|
+
let parentField: FieldKey | undefined;
|
|
72
|
+
let parent: UpPath | undefined;
|
|
73
|
+
|
|
74
|
+
return createAnnouncedVisitor({
|
|
75
|
+
beforeDetach: (src) => {
|
|
76
|
+
assert(parent !== undefined, "Expected node");
|
|
77
|
+
assert(parentField !== undefined, "Expected field");
|
|
78
|
+
for (let parentIndex = src.start; parentIndex < src.end; parentIndex++) {
|
|
79
|
+
const path: UpPath = {
|
|
80
|
+
parent,
|
|
81
|
+
parentField,
|
|
82
|
+
parentIndex,
|
|
83
|
+
};
|
|
84
|
+
// The only way a detached node can be re-attached (and become visible/usable again) is via a move, so mark it as moved ahead of time.
|
|
85
|
+
const node = getNodeAtPath(forest, path);
|
|
86
|
+
if (node !== undefined && dirty.get(node) === undefined) {
|
|
87
|
+
// Only mark the node as moved if it is not already marked as something else.
|
|
88
|
+
dirty.set(node, "moved");
|
|
89
|
+
}
|
|
90
|
+
// Mark the parent as changed unless it is already marked as new.
|
|
91
|
+
const parentNode = getNodeAtPath(forest, parent);
|
|
92
|
+
if (parentNode !== undefined && dirty.get(parentNode) !== "new") {
|
|
93
|
+
dirty.set(parentNode, "changed");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
afterAttach: (_, dst) => {
|
|
98
|
+
assert(parent !== undefined, "Expected node");
|
|
99
|
+
assert(parentField !== undefined, "Expected field");
|
|
100
|
+
for (let parentIndex = dst.start; parentIndex < dst.end; parentIndex++) {
|
|
101
|
+
const path: UpPath = {
|
|
102
|
+
parent,
|
|
103
|
+
parentField,
|
|
104
|
+
parentIndex,
|
|
105
|
+
};
|
|
106
|
+
const node = getNodeAtPath(forest, path);
|
|
107
|
+
if (node !== undefined && dirty.get(node) === undefined) {
|
|
108
|
+
// Only mark the node as new if it is not already marked as something else - this ensures that a moved node is not marked as new (since nodes are marked move when detached).
|
|
109
|
+
dirty.set(node, "new");
|
|
110
|
+
}
|
|
111
|
+
// Mark the parent as changed unless it is already marked as new.
|
|
112
|
+
const parentNode = getNodeAtPath(forest, parent);
|
|
113
|
+
if (parentNode !== undefined && dirty.get(parentNode) !== "new") {
|
|
114
|
+
dirty.set(parentNode, "changed");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
enterNode(index: number): void {
|
|
119
|
+
assert(parentField !== undefined, "Expected field");
|
|
120
|
+
parent = {
|
|
121
|
+
parent,
|
|
122
|
+
parentField,
|
|
123
|
+
parentIndex: index,
|
|
124
|
+
};
|
|
125
|
+
parentField = undefined;
|
|
126
|
+
},
|
|
127
|
+
exitNode(): void {
|
|
128
|
+
assert(parent !== undefined, "Expected node");
|
|
129
|
+
parentField = parent.parentField;
|
|
130
|
+
parent = parent.parent;
|
|
131
|
+
},
|
|
132
|
+
enterField: (key: FieldKey) => {
|
|
133
|
+
parentField = key;
|
|
134
|
+
},
|
|
135
|
+
exitField(): void {
|
|
136
|
+
parentField = undefined;
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getNodeAtPath(forest: IEditableForest, path: UpPath): TreeNode | undefined {
|
|
142
|
+
const cursor = forest.allocateCursor();
|
|
143
|
+
forest.moveCursorToPath(path, cursor);
|
|
144
|
+
assert(cursor.mode === CursorLocationType.Nodes, 0xa9c /* attach should happen in a node */);
|
|
145
|
+
const anchor = cursor.buildAnchor();
|
|
146
|
+
const anchorNode = forest.anchors.locate(anchor);
|
|
147
|
+
cursor.free();
|
|
148
|
+
if (anchorNode !== undefined) {
|
|
149
|
+
const node = treeNodeFromAnchor(anchorNode);
|
|
150
|
+
if (node instanceof TreeNode) {
|
|
151
|
+
return node;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
@@ -56,6 +56,11 @@ export {
|
|
|
56
56
|
tryGetSchema,
|
|
57
57
|
} from "./treeNodeApi.js";
|
|
58
58
|
export { createFromCursor } from "./create.js";
|
|
59
|
+
export {
|
|
60
|
+
type DirtyTreeStatus,
|
|
61
|
+
trackDirtyNodes,
|
|
62
|
+
type DirtyTreeMap,
|
|
63
|
+
} from "./dirtyIndex.js";
|
|
59
64
|
export {
|
|
60
65
|
type JsonSchemaId,
|
|
61
66
|
type JsonSchemaType,
|
|
@@ -257,11 +257,12 @@ export interface TreeBranch extends IDisposable {
|
|
|
257
257
|
/**
|
|
258
258
|
* An editable view of a (version control style) branch of a shared tree based on some schema.
|
|
259
259
|
*
|
|
260
|
-
*
|
|
260
|
+
* @remarks
|
|
261
|
+
* This schema (known as the view schema) may or may not align with the stored schema of the document.
|
|
261
262
|
* Information about discrepancies between the two schemas is available via {@link TreeView.compatibility | compatibility}.
|
|
262
263
|
*
|
|
263
|
-
* Application authors are encouraged to read
|
|
264
|
-
* choose a schema compatibility policy that aligns with their application's needs.
|
|
264
|
+
* Application authors are encouraged to read {@link https://github.com/microsoft/FluidFramework/blob/main/packages/dds/tree/docs/user-facing/schema-evolution.md | schema-evolution.md}
|
|
265
|
+
* and choose a schema compatibility policy that aligns with their application's needs.
|
|
265
266
|
*
|
|
266
267
|
* @privateRemarks
|
|
267
268
|
* From an API design perspective, `upgradeSchema` could be merged into `viewWith` and/or `viewWith` could return errors explicitly on incompatible documents.
|
|
@@ -50,7 +50,6 @@ import {
|
|
|
50
50
|
type HydratedFlexTreeNode,
|
|
51
51
|
cursorForMapTreeField,
|
|
52
52
|
type MinimalFieldMap,
|
|
53
|
-
currentObserver,
|
|
54
53
|
} from "../../feature-libraries/index.js";
|
|
55
54
|
import { brand, filterIterable, getOrCreate, mapIterable } from "../../util/index.js";
|
|
56
55
|
|
|
@@ -145,10 +144,8 @@ export class UnhydratedFlexTreeNode
|
|
|
145
144
|
*/
|
|
146
145
|
public readonly fields: MinimalFieldMap<UnhydratedFlexTreeField> = {
|
|
147
146
|
get: (key: FieldKey): UnhydratedFlexTreeField | undefined => this.tryGetField(key),
|
|
148
|
-
[Symbol.iterator]: (): IterableIterator<[FieldKey, UnhydratedFlexTreeField]> =>
|
|
149
|
-
|
|
150
|
-
return filterIterable(this.fieldsAll, ([, field]) => field.length > 0);
|
|
151
|
-
},
|
|
147
|
+
[Symbol.iterator]: (): IterableIterator<[FieldKey, UnhydratedFlexTreeField]> =>
|
|
148
|
+
filterIterable(this.fieldsAll, ([, field]) => field.length > 0),
|
|
152
149
|
};
|
|
153
150
|
|
|
154
151
|
public [Symbol.iterator](): IterableIterator<UnhydratedFlexTreeField> {
|
|
@@ -221,7 +218,6 @@ export class UnhydratedFlexTreeNode
|
|
|
221
218
|
* @remarks If this node is unparented, this method will return the special {@link unparentedLocation} as the parent.
|
|
222
219
|
*/
|
|
223
220
|
public get parentField(): LocationInField {
|
|
224
|
-
currentObserver?.observeParentOf(this);
|
|
225
221
|
return this.location;
|
|
226
222
|
}
|
|
227
223
|
|
|
@@ -230,8 +226,6 @@ export class UnhydratedFlexTreeNode
|
|
|
230
226
|
}
|
|
231
227
|
|
|
232
228
|
public tryGetField(key: FieldKey): UnhydratedFlexTreeField | undefined {
|
|
233
|
-
currentObserver?.observeNodeField(this, key);
|
|
234
|
-
|
|
235
229
|
const field = this.fieldsAll.get(key);
|
|
236
230
|
// Only return the field if it is not empty, in order to fulfill the contract of `tryGetField`.
|
|
237
231
|
if (field !== undefined && field.length > 0) {
|
|
@@ -241,9 +235,6 @@ export class UnhydratedFlexTreeNode
|
|
|
241
235
|
|
|
242
236
|
public getBoxed(key: string): UnhydratedFlexTreeField {
|
|
243
237
|
const fieldKey: FieldKey = brand(key);
|
|
244
|
-
|
|
245
|
-
currentObserver?.observeNodeField(this, fieldKey);
|
|
246
|
-
|
|
247
238
|
return this.getOrCreateField(fieldKey);
|
|
248
239
|
}
|
|
249
240
|
|
package/src/simple-tree/index.ts
CHANGED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import type { FlexTreeNode } from "./flexTreeTypes.js";
|
|
6
|
-
import type { FieldKey } from "../../core/index.js";
|
|
7
|
-
/**
|
|
8
|
-
* An object informed about observation made to trees.
|
|
9
|
-
* @remarks
|
|
10
|
-
* See {@link withObservation} and {@link currentObserver}.
|
|
11
|
-
*/
|
|
12
|
-
export interface Observer {
|
|
13
|
-
observeNodeFields(node: FlexTreeNode): void;
|
|
14
|
-
observeNodeField(node: FlexTreeNode, key: FieldKey): void;
|
|
15
|
-
observeParentOf(node: FlexTreeNode): void;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* The current observer, if any.
|
|
19
|
-
* @remarks
|
|
20
|
-
* Set via {@link setObserver} as used by {@link withObservation}.
|
|
21
|
-
*/
|
|
22
|
-
export declare let currentObserver: Observer | undefined;
|
|
23
|
-
/**
|
|
24
|
-
* For the duration of `f`, pushes `newObserver` onto the observer stack, making it the {@link currentObserver}.
|
|
25
|
-
*/
|
|
26
|
-
export declare function withObservation<T>(newObserver: Observer | undefined, f: () => T): T;
|
|
27
|
-
//# sourceMappingURL=observer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../../../src/feature-libraries/flex-tree/observer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AASpD;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACxB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5C,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1D,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CAC1C;AACD;;;;GAIG;AACH,eAAO,IAAI,eAAe,EAAE,QAAQ,GAAG,SAAS,CAAC;AAgBjD;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAOnF"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*!
|
|
3
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
-
* Licensed under the MIT License.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.withObservation = exports.currentObserver = void 0;
|
|
8
|
-
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
9
|
-
const observerStack = [];
|
|
10
|
-
function setObserver(newObserver) {
|
|
11
|
-
observerStack.push(newObserver);
|
|
12
|
-
exports.currentObserver = newObserver;
|
|
13
|
-
}
|
|
14
|
-
function clearObserver() {
|
|
15
|
-
(0, internal_1.debugAssert)(() => observerStack.length > 0 || "Empty Observer stack on clear");
|
|
16
|
-
const popped = observerStack.pop();
|
|
17
|
-
(0, internal_1.debugAssert)(() => popped === exports.currentObserver || "Mismatched observer stack");
|
|
18
|
-
exports.currentObserver = observerStack[observerStack.length - 1];
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* For the duration of `f`, pushes `newObserver` onto the observer stack, making it the {@link currentObserver}.
|
|
22
|
-
*/
|
|
23
|
-
function withObservation(newObserver, f) {
|
|
24
|
-
setObserver(newObserver);
|
|
25
|
-
try {
|
|
26
|
-
return f();
|
|
27
|
-
}
|
|
28
|
-
finally {
|
|
29
|
-
clearObserver();
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
exports.withObservation = withObservation;
|
|
33
|
-
//# sourceMappingURL=observer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/feature-libraries/flex-tree/observer.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,kEAAkE;AA4BlE,MAAM,aAAa,GAA6B,EAAE,CAAC;AAEnD,SAAS,WAAW,CAAC,WAAiC;IACrD,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAChC,uBAAe,GAAG,WAAW,CAAC;AAC/B,CAAC;AAED,SAAS,aAAa;IACrB,IAAA,sBAAW,EAAC,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,+BAA+B,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC;IACnC,IAAA,sBAAW,EAAC,GAAG,EAAE,CAAC,MAAM,KAAK,uBAAe,IAAI,2BAA2B,CAAC,CAAC;IAC7E,uBAAe,GAAG,aAAa,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe,CAAI,WAAiC,EAAE,CAAU;IAC/E,WAAW,CAAC,WAAW,CAAC,CAAC;IACzB,IAAI,CAAC;QACJ,OAAO,CAAC,EAAE,CAAC;IACZ,CAAC;YAAS,CAAC;QACV,aAAa,EAAE,CAAC;IACjB,CAAC;AACF,CAAC;AAPD,0CAOC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { debugAssert } from \"@fluidframework/core-utils/internal\";\nimport type { FlexTreeNode } from \"./flexTreeTypes.js\";\nimport type { FieldKey } from \"../../core/index.js\";\n\n/*\n * This file sets up a static observation tracking system.\n *\n * This library used to contain a more general variant of this which was deleted in https://github.com/microsoft/FluidFramework/pull/18659.\n * This pattern somewhat resembles the approach in https://github.com/tc39/proposal-signals.\n */\n\n/**\n * An object informed about observation made to trees.\n * @remarks\n * See {@link withObservation} and {@link currentObserver}.\n */\nexport interface Observer {\n\tobserveNodeFields(node: FlexTreeNode): void;\n\tobserveNodeField(node: FlexTreeNode, key: FieldKey): void;\n\tobserveParentOf(node: FlexTreeNode): void;\n}\n/**\n * The current observer, if any.\n * @remarks\n * Set via {@link setObserver} as used by {@link withObservation}.\n */\nexport let currentObserver: Observer | undefined;\n\nconst observerStack: (Observer | undefined)[] = [];\n\nfunction setObserver(newObserver: Observer | undefined): void {\n\tobserverStack.push(newObserver);\n\tcurrentObserver = newObserver;\n}\n\nfunction clearObserver(): void {\n\tdebugAssert(() => observerStack.length > 0 || \"Empty Observer stack on clear\");\n\tconst popped = observerStack.pop();\n\tdebugAssert(() => popped === currentObserver || \"Mismatched observer stack\");\n\tcurrentObserver = observerStack[observerStack.length - 1];\n}\n\n/**\n * For the duration of `f`, pushes `newObserver` onto the observer stack, making it the {@link currentObserver}.\n */\nexport function withObservation<T>(newObserver: Observer | undefined, f: () => T): T {\n\tsetObserver(newObserver);\n\ttry {\n\t\treturn f();\n\t} finally {\n\t\tclearObserver();\n\t}\n}\n"]}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import type { FlexTreeNode } from "./flexTreeTypes.js";
|
|
6
|
-
import type { FieldKey } from "../../core/index.js";
|
|
7
|
-
/**
|
|
8
|
-
* An object informed about observation made to trees.
|
|
9
|
-
* @remarks
|
|
10
|
-
* See {@link withObservation} and {@link currentObserver}.
|
|
11
|
-
*/
|
|
12
|
-
export interface Observer {
|
|
13
|
-
observeNodeFields(node: FlexTreeNode): void;
|
|
14
|
-
observeNodeField(node: FlexTreeNode, key: FieldKey): void;
|
|
15
|
-
observeParentOf(node: FlexTreeNode): void;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* The current observer, if any.
|
|
19
|
-
* @remarks
|
|
20
|
-
* Set via {@link setObserver} as used by {@link withObservation}.
|
|
21
|
-
*/
|
|
22
|
-
export declare let currentObserver: Observer | undefined;
|
|
23
|
-
/**
|
|
24
|
-
* For the duration of `f`, pushes `newObserver` onto the observer stack, making it the {@link currentObserver}.
|
|
25
|
-
*/
|
|
26
|
-
export declare function withObservation<T>(newObserver: Observer | undefined, f: () => T): T;
|
|
27
|
-
//# sourceMappingURL=observer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observer.d.ts","sourceRoot":"","sources":["../../../src/feature-libraries/flex-tree/observer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AASpD;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACxB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5C,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1D,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CAC1C;AACD;;;;GAIG;AACH,eAAO,IAAI,eAAe,EAAE,QAAQ,GAAG,SAAS,CAAC;AAgBjD;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAOnF"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import { debugAssert } from "@fluidframework/core-utils/internal";
|
|
6
|
-
/**
|
|
7
|
-
* The current observer, if any.
|
|
8
|
-
* @remarks
|
|
9
|
-
* Set via {@link setObserver} as used by {@link withObservation}.
|
|
10
|
-
*/
|
|
11
|
-
export let currentObserver;
|
|
12
|
-
const observerStack = [];
|
|
13
|
-
function setObserver(newObserver) {
|
|
14
|
-
observerStack.push(newObserver);
|
|
15
|
-
currentObserver = newObserver;
|
|
16
|
-
}
|
|
17
|
-
function clearObserver() {
|
|
18
|
-
debugAssert(() => observerStack.length > 0 || "Empty Observer stack on clear");
|
|
19
|
-
const popped = observerStack.pop();
|
|
20
|
-
debugAssert(() => popped === currentObserver || "Mismatched observer stack");
|
|
21
|
-
currentObserver = observerStack[observerStack.length - 1];
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* For the duration of `f`, pushes `newObserver` onto the observer stack, making it the {@link currentObserver}.
|
|
25
|
-
*/
|
|
26
|
-
export function withObservation(newObserver, f) {
|
|
27
|
-
setObserver(newObserver);
|
|
28
|
-
try {
|
|
29
|
-
return f();
|
|
30
|
-
}
|
|
31
|
-
finally {
|
|
32
|
-
clearObserver();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=observer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/feature-libraries/flex-tree/observer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAqBlE;;;;GAIG;AACH,MAAM,CAAC,IAAI,eAAqC,CAAC;AAEjD,MAAM,aAAa,GAA6B,EAAE,CAAC;AAEnD,SAAS,WAAW,CAAC,WAAiC;IACrD,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAChC,eAAe,GAAG,WAAW,CAAC;AAC/B,CAAC;AAED,SAAS,aAAa;IACrB,WAAW,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,+BAA+B,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC;IACnC,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,KAAK,eAAe,IAAI,2BAA2B,CAAC,CAAC;IAC7E,eAAe,GAAG,aAAa,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAI,WAAiC,EAAE,CAAU;IAC/E,WAAW,CAAC,WAAW,CAAC,CAAC;IACzB,IAAI,CAAC;QACJ,OAAO,CAAC,EAAE,CAAC;IACZ,CAAC;YAAS,CAAC;QACV,aAAa,EAAE,CAAC;IACjB,CAAC;AACF,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { debugAssert } from \"@fluidframework/core-utils/internal\";\nimport type { FlexTreeNode } from \"./flexTreeTypes.js\";\nimport type { FieldKey } from \"../../core/index.js\";\n\n/*\n * This file sets up a static observation tracking system.\n *\n * This library used to contain a more general variant of this which was deleted in https://github.com/microsoft/FluidFramework/pull/18659.\n * This pattern somewhat resembles the approach in https://github.com/tc39/proposal-signals.\n */\n\n/**\n * An object informed about observation made to trees.\n * @remarks\n * See {@link withObservation} and {@link currentObserver}.\n */\nexport interface Observer {\n\tobserveNodeFields(node: FlexTreeNode): void;\n\tobserveNodeField(node: FlexTreeNode, key: FieldKey): void;\n\tobserveParentOf(node: FlexTreeNode): void;\n}\n/**\n * The current observer, if any.\n * @remarks\n * Set via {@link setObserver} as used by {@link withObservation}.\n */\nexport let currentObserver: Observer | undefined;\n\nconst observerStack: (Observer | undefined)[] = [];\n\nfunction setObserver(newObserver: Observer | undefined): void {\n\tobserverStack.push(newObserver);\n\tcurrentObserver = newObserver;\n}\n\nfunction clearObserver(): void {\n\tdebugAssert(() => observerStack.length > 0 || \"Empty Observer stack on clear\");\n\tconst popped = observerStack.pop();\n\tdebugAssert(() => popped === currentObserver || \"Mismatched observer stack\");\n\tcurrentObserver = observerStack[observerStack.length - 1];\n}\n\n/**\n * For the duration of `f`, pushes `newObserver` onto the observer stack, making it the {@link currentObserver}.\n */\nexport function withObservation<T>(newObserver: Observer | undefined, f: () => T): T {\n\tsetObserver(newObserver);\n\ttry {\n\t\treturn f();\n\t} finally {\n\t\tclearObserver();\n\t}\n}\n"]}
|