@fluidframework/tree 2.61.0-355651 → 2.61.0-355781
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/lazyNode.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/lazyNode.js +4 -3
- package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
- package/dist/feature-libraries/flex-tree/observer.d.ts +3 -1
- package/dist/feature-libraries/flex-tree/observer.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/shared-tree/treeAlpha.js +67 -10
- package/dist/shared-tree/treeAlpha.js.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.js +3 -3
- package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyNode.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyNode.js +4 -3
- package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
- package/lib/feature-libraries/flex-tree/observer.d.ts +3 -1
- package/lib/feature-libraries/flex-tree/observer.d.ts.map +1 -1
- 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.map +1 -1
- package/lib/shared-tree/treeAlpha.js +67 -10
- package/lib/shared-tree/treeAlpha.js.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.js +3 -3
- package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/package.json +20 -20
- package/src/feature-libraries/flex-tree/lazyNode.ts +5 -3
- package/src/feature-libraries/flex-tree/observer.ts +3 -1
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/treeAlpha.ts +80 -12
- package/src/simple-tree/core/unhydratedFlexTree.ts +5 -4
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
convertField,
|
|
56
56
|
toUnhydratedSchema,
|
|
57
57
|
type TreeParsingOptions,
|
|
58
|
+
type NodeChangedData,
|
|
58
59
|
} from "../simple-tree/index.js";
|
|
59
60
|
import { brand, extractFromOpaque, type JsonCompatible } from "../util/index.js";
|
|
60
61
|
import {
|
|
@@ -63,7 +64,7 @@ import {
|
|
|
63
64
|
type ICodecOptions,
|
|
64
65
|
type CodecWriteOptions,
|
|
65
66
|
} from "../codec/index.js";
|
|
66
|
-
import { EmptyKey, type ITreeCursorSynchronous } from "../core/index.js";
|
|
67
|
+
import { EmptyKey, type FieldKey, type ITreeCursorSynchronous } from "../core/index.js";
|
|
67
68
|
import {
|
|
68
69
|
cursorForMapTreeField,
|
|
69
70
|
defaultSchemaPolicy,
|
|
@@ -432,6 +433,46 @@ export interface TreeAlpha {
|
|
|
432
433
|
): { result: TResult; unsubscribe: () => void };
|
|
433
434
|
}
|
|
434
435
|
|
|
436
|
+
class NodeSubscription {
|
|
437
|
+
/**
|
|
438
|
+
* If undefined, subscribes to all keys.
|
|
439
|
+
* Otherwise only subscribes to the keys in the set.
|
|
440
|
+
*/
|
|
441
|
+
public keys: Set<FieldKey> | undefined;
|
|
442
|
+
public readonly unsubscribe: () => void;
|
|
443
|
+
public constructor(
|
|
444
|
+
public readonly onInvalidation: () => void,
|
|
445
|
+
flexNode: FlexTreeNode,
|
|
446
|
+
) {
|
|
447
|
+
// TODO:Performance: It is possible to optimize this to not use the public TreeNode API.
|
|
448
|
+
const node = getOrCreateNodeFromInnerNode(flexNode);
|
|
449
|
+
assert(node instanceof TreeNode, "Unexpected leaf value");
|
|
450
|
+
|
|
451
|
+
const handler = (data: NodeChangedData): void => {
|
|
452
|
+
if (this.keys === undefined || data.changedProperties === undefined) {
|
|
453
|
+
this.onInvalidation();
|
|
454
|
+
} else {
|
|
455
|
+
let keyMap: ReadonlyMap<FieldKey, string> | undefined;
|
|
456
|
+
const schema = treeNodeApi.schema(node);
|
|
457
|
+
if (isObjectNodeSchema(schema)) {
|
|
458
|
+
keyMap = schema.storedKeyToPropertyKey;
|
|
459
|
+
}
|
|
460
|
+
// TODO:Performance: Ideally this would use Set.prototype.isDisjointFrom when available.
|
|
461
|
+
for (const flexKey of this.keys) {
|
|
462
|
+
// TODO:Performance: doing everything at the flex tree layer could avoid this translation
|
|
463
|
+
const key = keyMap?.get(flexKey) ?? flexKey;
|
|
464
|
+
|
|
465
|
+
if (data.changedProperties.has(key)) {
|
|
466
|
+
this.onInvalidation();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
this.unsubscribe = TreeBeta.on(node, "nodeChanged", handler);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
435
476
|
/**
|
|
436
477
|
* Extensions to {@link (Tree:variable)} and {@link (TreeBeta:variable)} which are not yet stable.
|
|
437
478
|
* @see {@link (TreeAlpha:interface)}.
|
|
@@ -442,20 +483,46 @@ export const TreeAlpha: TreeAlpha = {
|
|
|
442
483
|
onInvalidation: () => void,
|
|
443
484
|
trackDuring: () => TResult,
|
|
444
485
|
): { result: TResult; unsubscribe: () => void } {
|
|
445
|
-
|
|
486
|
+
let observing = true;
|
|
487
|
+
|
|
488
|
+
const invalidate = (): void => {
|
|
489
|
+
if (observing) {
|
|
490
|
+
throw new UsageError("Cannot invalidate while tracking observations");
|
|
491
|
+
}
|
|
492
|
+
onInvalidation();
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
const subscriptions = new Map<FlexTreeNode, NodeSubscription>();
|
|
446
496
|
const observer: Observer = {
|
|
447
|
-
|
|
497
|
+
observeNodeFields(flexNode: FlexTreeNode): void {
|
|
498
|
+
if (flexNode.value !== undefined) {
|
|
499
|
+
// Leaf value, nothing to observe.
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const subscription = subscriptions.get(flexNode);
|
|
503
|
+
if (subscription !== undefined) {
|
|
504
|
+
// Already subscribed to this node.
|
|
505
|
+
subscription.keys = undefined; // Now subscribed to all keys.
|
|
506
|
+
} else {
|
|
507
|
+
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
508
|
+
subscriptions.set(flexNode, newSubscription);
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
observeNodeField(flexNode: FlexTreeNode, key: FieldKey): void {
|
|
448
512
|
if (flexNode.value !== undefined) {
|
|
449
513
|
// Leaf value, nothing to observe.
|
|
450
514
|
return;
|
|
451
515
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
516
|
+
const subscription = subscriptions.get(flexNode);
|
|
517
|
+
if (subscription !== undefined) {
|
|
518
|
+
// Already subscribed to this node: if not subscribed to all keys, subscribe to this one.
|
|
519
|
+
// TODO:Performance: due to how JavaScript set ordering works,
|
|
520
|
+
// it might be faster to check `has` and only add if not present in case the same field is viewed many times.
|
|
521
|
+
subscription.keys?.add(key);
|
|
522
|
+
} else {
|
|
523
|
+
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
524
|
+
newSubscription.keys = new Set([key]);
|
|
525
|
+
subscriptions.set(flexNode, newSubscription);
|
|
459
526
|
}
|
|
460
527
|
},
|
|
461
528
|
observeParentOf(node: FlexTreeNode): void {
|
|
@@ -465,6 +532,7 @@ export const TreeAlpha: TreeAlpha = {
|
|
|
465
532
|
},
|
|
466
533
|
};
|
|
467
534
|
const result = withObservation(observer, trackDuring);
|
|
535
|
+
observing = false;
|
|
468
536
|
|
|
469
537
|
let subscribed = true;
|
|
470
538
|
|
|
@@ -475,8 +543,8 @@ export const TreeAlpha: TreeAlpha = {
|
|
|
475
543
|
throw new UsageError("Already unsubscribed");
|
|
476
544
|
}
|
|
477
545
|
subscribed = false;
|
|
478
|
-
for (const
|
|
479
|
-
unsubscribe();
|
|
546
|
+
for (const subscription of subscriptions.values()) {
|
|
547
|
+
subscription.unsubscribe();
|
|
480
548
|
}
|
|
481
549
|
},
|
|
482
550
|
};
|
|
@@ -146,7 +146,7 @@ export class UnhydratedFlexTreeNode
|
|
|
146
146
|
public readonly fields: MinimalFieldMap<UnhydratedFlexTreeField> = {
|
|
147
147
|
get: (key: FieldKey): UnhydratedFlexTreeField | undefined => this.tryGetField(key),
|
|
148
148
|
[Symbol.iterator]: (): IterableIterator<[FieldKey, UnhydratedFlexTreeField]> => {
|
|
149
|
-
currentObserver?.
|
|
149
|
+
currentObserver?.observeNodeFields(this);
|
|
150
150
|
return filterIterable(this.fieldsAll, ([, field]) => field.length > 0);
|
|
151
151
|
},
|
|
152
152
|
};
|
|
@@ -230,7 +230,7 @@ export class UnhydratedFlexTreeNode
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
public tryGetField(key: FieldKey): UnhydratedFlexTreeField | undefined {
|
|
233
|
-
currentObserver?.
|
|
233
|
+
currentObserver?.observeNodeField(this, key);
|
|
234
234
|
|
|
235
235
|
const field = this.fieldsAll.get(key);
|
|
236
236
|
// Only return the field if it is not empty, in order to fulfill the contract of `tryGetField`.
|
|
@@ -240,9 +240,10 @@ export class UnhydratedFlexTreeNode
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
public getBoxed(key: string): UnhydratedFlexTreeField {
|
|
243
|
-
currentObserver?.observeNodeContent(this);
|
|
244
|
-
|
|
245
243
|
const fieldKey: FieldKey = brand(key);
|
|
244
|
+
|
|
245
|
+
currentObserver?.observeNodeField(this, fieldKey);
|
|
246
|
+
|
|
246
247
|
return this.getOrCreateField(fieldKey);
|
|
247
248
|
}
|
|
248
249
|
|