@fluidframework/tree 2.61.0 → 2.62.0
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/CHANGELOG.md +162 -0
- package/api-report/tree.alpha.api.md +26 -21
- package/api-report/tree.beta.api.md +15 -0
- package/api-report/tree.legacy.beta.api.md +18 -0
- package/dist/alpha.d.ts +8 -8
- package/dist/api.d.ts +17 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +24 -0
- package/dist/api.js.map +1 -0
- package/dist/beta.d.ts +5 -0
- package/dist/codec/codec.d.ts +3 -5
- package/dist/codec/codec.d.ts.map +1 -1
- package/dist/codec/codec.js +9 -2
- package/dist/codec/codec.js.map +1 -1
- package/dist/codec/index.d.ts +0 -1
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/codec/index.js +1 -3
- package/dist/codec/index.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/rebase/index.d.ts +1 -1
- package/dist/core/rebase/index.d.ts.map +1 -1
- package/dist/core/rebase/index.js +2 -1
- package/dist/core/rebase/index.js.map +1 -1
- package/dist/core/rebase/utils.d.ts +10 -0
- package/dist/core/rebase/utils.d.ts.map +1 -1
- package/dist/core/rebase/utils.js +20 -1
- package/dist/core/rebase/utils.js.map +1 -1
- package/dist/core/tree/detachedFieldIndex.js +1 -1
- package/dist/core/tree/detachedFieldIndex.js.map +1 -1
- package/dist/external-utilities/index.d.ts +1 -1
- package/dist/external-utilities/index.d.ts.map +1 -1
- package/dist/external-utilities/index.js +1 -2
- package/dist/external-utilities/index.js.map +1 -1
- package/dist/external-utilities/typeboxValidator.d.ts +0 -13
- package/dist/external-utilities/typeboxValidator.d.ts.map +1 -1
- package/dist/external-utilities/typeboxValidator.js +3 -5
- package/dist/external-utilities/typeboxValidator.js.map +1 -1
- 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/index.d.ts +1 -0
- package/dist/feature-libraries/flex-tree/index.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/index.js +4 -1
- 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 +15 -8
- package/dist/feature-libraries/flex-tree/lazyNode.js.map +1 -1
- package/dist/feature-libraries/flex-tree/observer.d.ts +32 -0
- package/dist/feature-libraries/flex-tree/observer.d.ts.map +1 -0
- package/dist/feature-libraries/flex-tree/observer.js +33 -0
- package/dist/feature-libraries/flex-tree/observer.js.map +1 -0
- 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 +3 -1
- package/dist/feature-libraries/index.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +7 -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/index.d.ts +2 -2
- package/dist/shared-tree/index.d.ts.map +1 -1
- package/dist/shared-tree/index.js.map +1 -1
- package/dist/shared-tree/schematizingTreeView.js +2 -2
- package/dist/shared-tree/schematizingTreeView.js.map +1 -1
- package/dist/shared-tree/sharedTree.d.ts +21 -6
- package/dist/shared-tree/sharedTree.d.ts.map +1 -1
- package/dist/shared-tree/sharedTree.js +76 -37
- package/dist/shared-tree/sharedTree.js.map +1 -1
- package/dist/shared-tree/treeAlpha.d.ts +114 -1
- package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
- package/dist/shared-tree/treeAlpha.js +140 -1
- package/dist/shared-tree/treeAlpha.js.map +1 -1
- package/dist/shared-tree/treeCheckout.d.ts +13 -7
- package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
- package/dist/shared-tree/treeCheckout.js +115 -85
- package/dist/shared-tree/treeCheckout.js.map +1 -1
- package/dist/shared-tree-core/branch.d.ts +3 -0
- package/dist/shared-tree-core/branch.d.ts.map +1 -1
- package/dist/shared-tree-core/branch.js.map +1 -1
- package/dist/shared-tree-core/branchIdCodec.d.ts +11 -0
- package/dist/shared-tree-core/branchIdCodec.d.ts.map +1 -0
- package/dist/shared-tree-core/branchIdCodec.js +18 -0
- package/dist/shared-tree-core/branchIdCodec.js.map +1 -0
- package/dist/shared-tree-core/editManager.d.ts +39 -64
- package/dist/shared-tree-core/editManager.d.ts.map +1 -1
- package/dist/shared-tree-core/editManager.js +455 -295
- package/dist/shared-tree-core/editManager.js.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.d.ts +1 -1
- package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.js +7 -96
- package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/dist/shared-tree-core/editManagerCodecsCommons.d.ts +17 -0
- package/dist/shared-tree-core/editManagerCodecsCommons.d.ts.map +1 -0
- package/dist/shared-tree-core/editManagerCodecsCommons.js +139 -0
- package/dist/shared-tree-core/editManagerCodecsCommons.js.map +1 -0
- package/dist/shared-tree-core/editManagerCodecsV1toV4.d.ts +16 -0
- package/dist/shared-tree-core/editManagerCodecsV1toV4.d.ts.map +1 -0
- package/dist/shared-tree-core/editManagerCodecsV1toV4.js +39 -0
- package/dist/shared-tree-core/editManagerCodecsV1toV4.js.map +1 -0
- package/dist/shared-tree-core/editManagerCodecsV5.d.ts +16 -0
- package/dist/shared-tree-core/editManagerCodecsV5.d.ts.map +1 -0
- package/dist/shared-tree-core/editManagerCodecsV5.js +58 -0
- package/dist/shared-tree-core/editManagerCodecsV5.js.map +1 -0
- package/dist/shared-tree-core/{editManagerFormat.d.ts → editManagerFormatCommons.d.ts} +31 -7
- package/dist/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -0
- package/dist/shared-tree-core/{editManagerFormat.js → editManagerFormatCommons.js} +13 -12
- package/dist/shared-tree-core/editManagerFormatCommons.js.map +1 -0
- package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts +31 -0
- package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -0
- package/dist/shared-tree-core/editManagerFormatV1toV4.js +24 -0
- package/dist/shared-tree-core/editManagerFormatV1toV4.js.map +1 -0
- package/dist/shared-tree-core/editManagerFormatV5.d.ts +62 -0
- package/dist/shared-tree-core/editManagerFormatV5.d.ts.map +1 -0
- package/dist/shared-tree-core/editManagerFormatV5.js +20 -0
- package/dist/shared-tree-core/editManagerFormatV5.js.map +1 -0
- package/dist/shared-tree-core/index.d.ts +3 -3
- package/dist/shared-tree-core/index.d.ts.map +1 -1
- package/dist/shared-tree-core/index.js.map +1 -1
- package/dist/shared-tree-core/messageCodecV1ToV4.d.ts +11 -0
- package/dist/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -0
- package/dist/shared-tree-core/messageCodecV1ToV4.js +59 -0
- package/dist/shared-tree-core/messageCodecV1ToV4.js.map +1 -0
- package/dist/shared-tree-core/messageCodecV5.d.ts +11 -0
- package/dist/shared-tree-core/messageCodecV5.d.ts.map +1 -0
- package/dist/shared-tree-core/messageCodecV5.js +78 -0
- package/dist/shared-tree-core/messageCodecV5.js.map +1 -0
- package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/messageCodecs.js +16 -47
- package/dist/shared-tree-core/messageCodecs.js.map +1 -1
- package/dist/shared-tree-core/{messageFormat.d.ts → messageFormatV1ToV4.d.ts} +1 -1
- package/dist/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -0
- package/dist/shared-tree-core/{messageFormat.js → messageFormatV1ToV4.js} +1 -1
- package/dist/shared-tree-core/messageFormatV1ToV4.js.map +1 -0
- package/dist/shared-tree-core/messageFormatV5.d.ts +42 -0
- package/dist/shared-tree-core/messageFormatV5.d.ts.map +1 -0
- package/dist/shared-tree-core/messageFormatV5.js +20 -0
- package/dist/shared-tree-core/messageFormatV5.js.map +1 -0
- package/dist/shared-tree-core/messageTypes.d.ts +12 -2
- package/dist/shared-tree-core/messageTypes.d.ts.map +1 -1
- package/dist/shared-tree-core/messageTypes.js.map +1 -1
- package/dist/shared-tree-core/sequenceIdUtils.d.ts +1 -1
- package/dist/shared-tree-core/sequenceIdUtils.d.ts.map +1 -1
- package/dist/shared-tree-core/sequenceIdUtils.js.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.d.ts +19 -5
- package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.js +182 -58
- package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/dist/simple-tree/api/tree.d.ts +17 -0
- package/dist/simple-tree/api/tree.d.ts.map +1 -1
- package/dist/simple-tree/api/tree.js +2 -0
- 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 +7 -1
- package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/dist/treeFactory.d.ts +38 -9
- package/dist/treeFactory.d.ts.map +1 -1
- package/dist/treeFactory.js +44 -9
- package/dist/treeFactory.js.map +1 -1
- package/lib/alpha.d.ts +8 -8
- package/lib/api.d.ts +17 -0
- package/lib/api.d.ts.map +1 -0
- package/lib/api.js +22 -0
- package/lib/api.js.map +1 -0
- package/lib/beta.d.ts +5 -0
- package/lib/codec/codec.d.ts +3 -5
- package/lib/codec/codec.d.ts.map +1 -1
- package/lib/codec/codec.js +8 -1
- package/lib/codec/codec.js.map +1 -1
- package/lib/codec/index.d.ts +0 -1
- package/lib/codec/index.d.ts.map +1 -1
- package/lib/codec/index.js +0 -1
- package/lib/codec/index.js.map +1 -1
- package/lib/core/index.d.ts +1 -1
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +1 -1
- package/lib/core/index.js.map +1 -1
- package/lib/core/rebase/index.d.ts +1 -1
- package/lib/core/rebase/index.d.ts.map +1 -1
- package/lib/core/rebase/index.js +1 -1
- package/lib/core/rebase/index.js.map +1 -1
- package/lib/core/rebase/utils.d.ts +10 -0
- package/lib/core/rebase/utils.d.ts.map +1 -1
- package/lib/core/rebase/utils.js +18 -0
- package/lib/core/rebase/utils.js.map +1 -1
- package/lib/core/tree/detachedFieldIndex.js +2 -2
- package/lib/core/tree/detachedFieldIndex.js.map +1 -1
- package/lib/external-utilities/index.d.ts +1 -1
- package/lib/external-utilities/index.d.ts.map +1 -1
- package/lib/external-utilities/index.js +1 -1
- package/lib/external-utilities/index.js.map +1 -1
- package/lib/external-utilities/typeboxValidator.d.ts +0 -13
- package/lib/external-utilities/typeboxValidator.d.ts.map +1 -1
- package/lib/external-utilities/typeboxValidator.js +1 -3
- package/lib/external-utilities/typeboxValidator.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/index.d.ts +1 -0
- package/lib/feature-libraries/flex-tree/index.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/index.js +1 -0
- 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 +15 -8
- package/lib/feature-libraries/flex-tree/lazyNode.js.map +1 -1
- package/lib/feature-libraries/flex-tree/observer.d.ts +32 -0
- package/lib/feature-libraries/flex-tree/observer.d.ts.map +1 -0
- package/lib/feature-libraries/flex-tree/observer.js +40 -0
- package/lib/feature-libraries/flex-tree/observer.js.map +1 -0
- 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 +5 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -3
- package/lib/index.js.map +1 -1
- package/lib/legacy.d.ts +7 -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/index.d.ts +2 -2
- package/lib/shared-tree/index.d.ts.map +1 -1
- package/lib/shared-tree/index.js.map +1 -1
- package/lib/shared-tree/schematizingTreeView.js +2 -2
- package/lib/shared-tree/schematizingTreeView.js.map +1 -1
- package/lib/shared-tree/sharedTree.d.ts +21 -6
- package/lib/shared-tree/sharedTree.d.ts.map +1 -1
- package/lib/shared-tree/sharedTree.js +78 -39
- package/lib/shared-tree/sharedTree.js.map +1 -1
- package/lib/shared-tree/treeAlpha.d.ts +114 -1
- package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
- package/lib/shared-tree/treeAlpha.js +143 -4
- package/lib/shared-tree/treeAlpha.js.map +1 -1
- package/lib/shared-tree/treeCheckout.d.ts +13 -7
- package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
- package/lib/shared-tree/treeCheckout.js +117 -87
- package/lib/shared-tree/treeCheckout.js.map +1 -1
- package/lib/shared-tree-core/branch.d.ts +3 -0
- package/lib/shared-tree-core/branch.d.ts.map +1 -1
- package/lib/shared-tree-core/branch.js.map +1 -1
- package/lib/shared-tree-core/branchIdCodec.d.ts +11 -0
- package/lib/shared-tree-core/branchIdCodec.d.ts.map +1 -0
- package/lib/shared-tree-core/branchIdCodec.js +13 -0
- package/lib/shared-tree-core/branchIdCodec.js.map +1 -0
- package/lib/shared-tree-core/editManager.d.ts +39 -64
- package/lib/shared-tree-core/editManager.d.ts.map +1 -1
- package/lib/shared-tree-core/editManager.js +455 -295
- package/lib/shared-tree-core/editManager.js.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.d.ts +1 -1
- package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.js +4 -93
- package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/lib/shared-tree-core/editManagerCodecsCommons.d.ts +17 -0
- package/lib/shared-tree-core/editManagerCodecsCommons.d.ts.map +1 -0
- package/lib/shared-tree-core/editManagerCodecsCommons.js +134 -0
- package/lib/shared-tree-core/editManagerCodecsCommons.js.map +1 -0
- package/lib/shared-tree-core/editManagerCodecsV1toV4.d.ts +16 -0
- package/lib/shared-tree-core/editManagerCodecsV1toV4.d.ts.map +1 -0
- package/lib/shared-tree-core/editManagerCodecsV1toV4.js +35 -0
- package/lib/shared-tree-core/editManagerCodecsV1toV4.js.map +1 -0
- package/lib/shared-tree-core/editManagerCodecsV5.d.ts +16 -0
- package/lib/shared-tree-core/editManagerCodecsV5.d.ts.map +1 -0
- package/lib/shared-tree-core/editManagerCodecsV5.js +54 -0
- package/lib/shared-tree-core/editManagerCodecsV5.js.map +1 -0
- package/lib/shared-tree-core/{editManagerFormat.d.ts → editManagerFormatCommons.d.ts} +31 -7
- package/lib/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -0
- package/lib/shared-tree-core/{editManagerFormat.js → editManagerFormatCommons.js} +10 -11
- package/lib/shared-tree-core/editManagerFormatCommons.js.map +1 -0
- package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts +31 -0
- package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -0
- package/lib/shared-tree-core/editManagerFormatV1toV4.js +20 -0
- package/lib/shared-tree-core/editManagerFormatV1toV4.js.map +1 -0
- package/lib/shared-tree-core/editManagerFormatV5.d.ts +62 -0
- package/lib/shared-tree-core/editManagerFormatV5.d.ts.map +1 -0
- package/lib/shared-tree-core/editManagerFormatV5.js +16 -0
- package/lib/shared-tree-core/editManagerFormatV5.js.map +1 -0
- package/lib/shared-tree-core/index.d.ts +3 -3
- package/lib/shared-tree-core/index.d.ts.map +1 -1
- package/lib/shared-tree-core/index.js.map +1 -1
- package/lib/shared-tree-core/messageCodecV1ToV4.d.ts +11 -0
- package/lib/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -0
- package/lib/shared-tree-core/messageCodecV1ToV4.js +55 -0
- package/lib/shared-tree-core/messageCodecV1ToV4.js.map +1 -0
- package/lib/shared-tree-core/messageCodecV5.d.ts +11 -0
- package/lib/shared-tree-core/messageCodecV5.d.ts.map +1 -0
- package/lib/shared-tree-core/messageCodecV5.js +74 -0
- package/lib/shared-tree-core/messageCodecV5.js.map +1 -0
- package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/messageCodecs.js +17 -48
- package/lib/shared-tree-core/messageCodecs.js.map +1 -1
- package/lib/shared-tree-core/{messageFormat.d.ts → messageFormatV1ToV4.d.ts} +1 -1
- package/lib/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -0
- package/lib/shared-tree-core/{messageFormat.js → messageFormatV1ToV4.js} +1 -1
- package/lib/shared-tree-core/messageFormatV1ToV4.js.map +1 -0
- package/lib/shared-tree-core/messageFormatV5.d.ts +42 -0
- package/lib/shared-tree-core/messageFormatV5.d.ts.map +1 -0
- package/lib/shared-tree-core/messageFormatV5.js +16 -0
- package/lib/shared-tree-core/messageFormatV5.js.map +1 -0
- package/lib/shared-tree-core/messageTypes.d.ts +12 -2
- package/lib/shared-tree-core/messageTypes.d.ts.map +1 -1
- package/lib/shared-tree-core/messageTypes.js.map +1 -1
- package/lib/shared-tree-core/sequenceIdUtils.d.ts +1 -1
- package/lib/shared-tree-core/sequenceIdUtils.d.ts.map +1 -1
- package/lib/shared-tree-core/sequenceIdUtils.js.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.d.ts +19 -5
- package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.js +183 -59
- package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/lib/simple-tree/api/tree.d.ts +17 -0
- package/lib/simple-tree/api/tree.d.ts.map +1 -1
- package/lib/simple-tree/api/tree.js +2 -0
- 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 +8 -2
- package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/lib/treeFactory.d.ts +38 -9
- package/lib/treeFactory.d.ts.map +1 -1
- package/lib/treeFactory.js +41 -8
- package/lib/treeFactory.js.map +1 -1
- package/package.json +25 -25
- package/src/api.ts +30 -0
- package/src/codec/codec.ts +12 -6
- package/src/codec/index.ts +0 -1
- package/src/core/index.ts +1 -0
- package/src/core/rebase/index.ts +1 -0
- package/src/core/rebase/utils.ts +27 -0
- package/src/core/tree/detachedFieldIndex.ts +2 -2
- package/src/external-utilities/index.ts +1 -1
- package/src/external-utilities/typeboxValidator.ts +1 -3
- package/src/feature-libraries/flex-tree/flexTreeTypes.ts +2 -0
- package/src/feature-libraries/flex-tree/index.ts +2 -0
- package/src/feature-libraries/flex-tree/lazyNode.ts +13 -3
- package/src/feature-libraries/flex-tree/observer.ts +64 -0
- package/src/feature-libraries/index.ts +3 -0
- package/src/index.ts +6 -4
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/index.ts +2 -0
- package/src/shared-tree/schematizingTreeView.ts +2 -2
- package/src/shared-tree/sharedTree.ts +116 -52
- package/src/shared-tree/treeAlpha.ts +309 -4
- package/src/shared-tree/treeCheckout.ts +152 -100
- package/src/shared-tree-core/branch.ts +7 -0
- package/src/shared-tree-core/branchIdCodec.ts +28 -0
- package/src/shared-tree-core/editManager.ts +729 -430
- package/src/shared-tree-core/editManagerCodecs.ts +4 -164
- package/src/shared-tree-core/editManagerCodecsCommons.ts +245 -0
- package/src/shared-tree-core/editManagerCodecsV1toV4.ts +108 -0
- package/src/shared-tree-core/editManagerCodecsV5.ts +156 -0
- package/src/shared-tree-core/{editManagerFormat.ts → editManagerFormatCommons.ts} +17 -13
- package/src/shared-tree-core/editManagerFormatV1toV4.ts +42 -0
- package/src/shared-tree-core/editManagerFormatV5.ts +35 -0
- package/src/shared-tree-core/index.ts +3 -1
- package/src/shared-tree-core/messageCodecV1ToV4.ts +104 -0
- package/src/shared-tree-core/messageCodecV5.ts +131 -0
- package/src/shared-tree-core/messageCodecs.ts +16 -85
- package/src/shared-tree-core/messageFormatV5.ts +50 -0
- package/src/shared-tree-core/messageTypes.ts +15 -2
- package/src/shared-tree-core/sequenceIdUtils.ts +1 -1
- package/src/shared-tree-core/sharedTreeCore.ts +281 -85
- package/src/simple-tree/api/tree.ts +23 -0
- package/src/simple-tree/core/unhydratedFlexTree.ts +11 -2
- package/src/treeFactory.ts +48 -8
- package/dist/codec/noopValidator.d.ts +0 -13
- package/dist/codec/noopValidator.d.ts.map +0 -1
- package/dist/codec/noopValidator.js +0 -17
- package/dist/codec/noopValidator.js.map +0 -1
- package/dist/shared-tree-core/editManagerFormat.d.ts.map +0 -1
- package/dist/shared-tree-core/editManagerFormat.js.map +0 -1
- package/dist/shared-tree-core/messageFormat.d.ts.map +0 -1
- package/dist/shared-tree-core/messageFormat.js.map +0 -1
- package/docs/user-facing/schema-evolution.md +0 -309
- package/lib/codec/noopValidator.d.ts +0 -13
- package/lib/codec/noopValidator.d.ts.map +0 -1
- package/lib/codec/noopValidator.js +0 -14
- package/lib/codec/noopValidator.js.map +0 -1
- package/lib/shared-tree-core/editManagerFormat.d.ts.map +0 -1
- package/lib/shared-tree-core/editManagerFormat.js.map +0 -1
- package/lib/shared-tree-core/messageFormat.d.ts.map +0 -1
- package/lib/shared-tree-core/messageFormat.js.map +0 -1
- package/src/codec/noopValidator.ts +0 -18
- /package/src/shared-tree-core/{messageFormat.ts → messageFormatV1ToV4.ts} +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { ErasedType, IFluidLoadable } from "@fluidframework/core-interfaces/internal";
|
|
7
7
|
import { assert, fail } from "@fluidframework/core-utils/internal";
|
|
8
8
|
import type { IChannelStorageService } from "@fluidframework/datastore-definitions/internal";
|
|
9
|
-
import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
9
|
+
import type { IIdCompressor, StableId } from "@fluidframework/id-compressor";
|
|
10
10
|
import type {
|
|
11
11
|
IChannelView,
|
|
12
12
|
IFluidSerializer,
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
import {
|
|
21
21
|
type CodecWriteOptions,
|
|
22
22
|
FluidClientVersion,
|
|
23
|
+
FormatValidatorNoOp,
|
|
23
24
|
type ICodecOptions,
|
|
24
|
-
noopValidator,
|
|
25
25
|
} from "../codec/index.js";
|
|
26
26
|
import {
|
|
27
27
|
type FieldKey,
|
|
@@ -33,7 +33,6 @@ import {
|
|
|
33
33
|
ObjectNodeStoredSchema,
|
|
34
34
|
RevisionTagCodec,
|
|
35
35
|
SchemaVersion,
|
|
36
|
-
type TaggedChange,
|
|
37
36
|
type TreeFieldStoredSchema,
|
|
38
37
|
type TreeNodeSchemaIdentifier,
|
|
39
38
|
type TreeNodeStoredSchema,
|
|
@@ -62,8 +61,8 @@ import {
|
|
|
62
61
|
// eslint-disable-next-line import/no-internal-modules
|
|
63
62
|
import type { FormatV1 } from "../feature-libraries/schema-index/index.js";
|
|
64
63
|
import {
|
|
64
|
+
type BranchId,
|
|
65
65
|
type ClonableSchemaAndPolicy,
|
|
66
|
-
DefaultResubmitMachine,
|
|
67
66
|
type ExplicitCoreCodecVersions,
|
|
68
67
|
SharedTreeCore,
|
|
69
68
|
} from "../shared-tree-core/index.js";
|
|
@@ -189,6 +188,10 @@ const formatVersionToTopLevelCodecVersions = new Map<number, ExplicitCodecVersio
|
|
|
189
188
|
5,
|
|
190
189
|
{ forest: 1, schema: 2, detachedFieldIndex: 1, editManager: 4, message: 4, fieldBatch: 1 },
|
|
191
190
|
],
|
|
191
|
+
[
|
|
192
|
+
100, // SharedTreeFormatVersion.vSharedBranches
|
|
193
|
+
{ forest: 1, schema: 2, detachedFieldIndex: 1, editManager: 5, message: 5, fieldBatch: 1 },
|
|
194
|
+
],
|
|
192
195
|
]);
|
|
193
196
|
|
|
194
197
|
function getCodecVersions(formatVersion: number): ExplicitCodecVersions {
|
|
@@ -217,6 +220,8 @@ export class SharedTreeKernel
|
|
|
217
220
|
return this.checkout.storedSchema;
|
|
218
221
|
}
|
|
219
222
|
|
|
223
|
+
private readonly checkouts: Map<BranchId, TreeCheckout> = new Map();
|
|
224
|
+
|
|
220
225
|
/**
|
|
221
226
|
* The app-facing API for SharedTree implemented by this Kernel.
|
|
222
227
|
* @remarks
|
|
@@ -232,7 +237,7 @@ export class SharedTreeKernel
|
|
|
232
237
|
serializer: IFluidSerializer,
|
|
233
238
|
submitLocalMessage: (content: unknown, localOpMetadata?: unknown) => void,
|
|
234
239
|
lastSequenceNumber: () => number | undefined,
|
|
235
|
-
logger: ITelemetryLoggerExt | undefined,
|
|
240
|
+
private readonly logger: ITelemetryLoggerExt | undefined,
|
|
236
241
|
idCompressor: IIdCompressor,
|
|
237
242
|
optionsParam: SharedTreeOptionsInternal,
|
|
238
243
|
) {
|
|
@@ -319,16 +324,12 @@ export class SharedTreeKernel
|
|
|
319
324
|
idCompressor,
|
|
320
325
|
schema,
|
|
321
326
|
defaultSchemaPolicy,
|
|
322
|
-
|
|
323
|
-
(change: TaggedChange<SharedTreeChange>) =>
|
|
324
|
-
changeFamily.rebaser.invert(change, true, this.mintRevisionTag()),
|
|
325
|
-
changeEnricher,
|
|
326
|
-
),
|
|
327
|
+
undefined,
|
|
327
328
|
changeEnricher,
|
|
328
329
|
);
|
|
329
|
-
|
|
330
|
+
|
|
330
331
|
this.checkout = createTreeCheckout(idCompressor, this.mintRevisionTag, revisionTagCodec, {
|
|
331
|
-
branch:
|
|
332
|
+
branch: this.getLocalBranch(),
|
|
332
333
|
changeFamily,
|
|
333
334
|
schema,
|
|
334
335
|
forest,
|
|
@@ -340,39 +341,49 @@ export class SharedTreeKernel
|
|
|
340
341
|
disposeForksAfterTransaction: options.disposeForksAfterTransaction,
|
|
341
342
|
});
|
|
342
343
|
|
|
343
|
-
this.
|
|
344
|
-
|
|
344
|
+
this.registerCheckout("main", this.checkout);
|
|
345
|
+
|
|
346
|
+
this.view = {
|
|
347
|
+
contentSnapshot: () => this.contentSnapshot(),
|
|
348
|
+
exportSimpleSchema: () => this.exportSimpleSchema(),
|
|
349
|
+
exportVerbose: () => this.exportVerbose(),
|
|
350
|
+
viewWith: this.viewWith.bind(this),
|
|
351
|
+
viewSharedBranchWith: this.viewBranchWith.bind(this),
|
|
352
|
+
createSharedBranch: this.createSharedBranch.bind(this),
|
|
353
|
+
getSharedBranchIds: this.getSharedBranchIds.bind(this),
|
|
354
|
+
kernel: this,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private registerCheckout(branchId: BranchId, checkout: TreeCheckout): void {
|
|
359
|
+
this.checkouts.set(branchId, checkout);
|
|
360
|
+
const enricher = this.getCommitEnricher(branchId);
|
|
361
|
+
checkout.transaction.events.on("started", () => {
|
|
362
|
+
if (this.sharedObject.isAttached()) {
|
|
345
363
|
// It is currently forbidden to attach during a transaction, so transaction state changes can be ignored until after attaching.
|
|
346
|
-
|
|
364
|
+
enricher.startTransaction();
|
|
347
365
|
}
|
|
348
366
|
});
|
|
349
|
-
|
|
350
|
-
|
|
367
|
+
|
|
368
|
+
checkout.transaction.events.on("aborting", () => {
|
|
369
|
+
if (this.sharedObject.isAttached()) {
|
|
351
370
|
// It is currently forbidden to attach during a transaction, so transaction state changes can be ignored until after attaching.
|
|
352
|
-
|
|
371
|
+
enricher.abortTransaction();
|
|
353
372
|
}
|
|
354
373
|
});
|
|
355
|
-
|
|
356
|
-
if (sharedObject.isAttached()) {
|
|
374
|
+
checkout.transaction.events.on("committing", () => {
|
|
375
|
+
if (this.sharedObject.isAttached()) {
|
|
357
376
|
// It is currently forbidden to attach during a transaction, so transaction state changes can be ignored until after attaching.
|
|
358
|
-
|
|
377
|
+
enricher.commitTransaction();
|
|
359
378
|
}
|
|
360
379
|
});
|
|
361
|
-
|
|
362
|
-
if (event.type === "append" && sharedObject.isAttached()) {
|
|
363
|
-
if (
|
|
364
|
-
|
|
380
|
+
checkout.events.on("beforeBatch", (event) => {
|
|
381
|
+
if (event.type === "append" && this.sharedObject.isAttached()) {
|
|
382
|
+
if (checkout.transaction.isInProgress()) {
|
|
383
|
+
enricher.addTransactionCommits(event.newCommits);
|
|
365
384
|
}
|
|
366
385
|
}
|
|
367
386
|
});
|
|
368
|
-
|
|
369
|
-
this.view = {
|
|
370
|
-
contentSnapshot: () => this.contentSnapshot(),
|
|
371
|
-
exportSimpleSchema: () => this.exportSimpleSchema(),
|
|
372
|
-
exportVerbose: () => this.exportVerbose(),
|
|
373
|
-
viewWith: this.viewWith.bind(this),
|
|
374
|
-
kernel: this,
|
|
375
|
-
};
|
|
376
387
|
}
|
|
377
388
|
|
|
378
389
|
public exportVerbose(): VerboseTree | undefined {
|
|
@@ -415,18 +426,56 @@ export class SharedTreeKernel
|
|
|
415
426
|
TreeView<ReadSchema<TRoot>>;
|
|
416
427
|
}
|
|
417
428
|
|
|
429
|
+
public viewBranchWith<TRoot extends ImplicitFieldSchema>(
|
|
430
|
+
branchId: string,
|
|
431
|
+
config: TreeViewConfiguration<TRoot>,
|
|
432
|
+
): TreeView<TRoot>;
|
|
433
|
+
|
|
434
|
+
public viewBranchWith<TRoot extends ImplicitFieldSchema | UnsafeUnknownSchema>(
|
|
435
|
+
branchId: string,
|
|
436
|
+
config: TreeViewConfiguration<ReadSchema<TRoot>>,
|
|
437
|
+
): SchematizingSimpleTreeView<TRoot> & TreeView<ReadSchema<TRoot>> {
|
|
438
|
+
const compressedId = this.idCompressor.tryRecompress(branchId as StableId);
|
|
439
|
+
if (compressedId === undefined) {
|
|
440
|
+
throw new UsageError(`No branch found with id: ${branchId}`);
|
|
441
|
+
}
|
|
442
|
+
return this.getCheckout(compressedId).viewWith(
|
|
443
|
+
config,
|
|
444
|
+
) as SchematizingSimpleTreeView<TRoot> & TreeView<ReadSchema<TRoot>>;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
private getCheckout(branchId: BranchId): TreeCheckout {
|
|
448
|
+
return this.checkouts.get(branchId) ?? this.checkoutBranch(branchId);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
private checkoutBranch(branchId: BranchId): TreeCheckout {
|
|
452
|
+
const checkout = this.checkout.branch();
|
|
453
|
+
checkout.switchBranch(this.getSharedBranch(branchId));
|
|
454
|
+
const enricher = new SharedTreeReadonlyChangeEnricher(
|
|
455
|
+
checkout.forest,
|
|
456
|
+
checkout.storedSchema,
|
|
457
|
+
checkout.removedRoots,
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
this.registerSharedBranchForEditing(branchId, enricher);
|
|
461
|
+
this.registerCheckout(branchId, checkout);
|
|
462
|
+
return checkout;
|
|
463
|
+
}
|
|
464
|
+
|
|
418
465
|
public override async loadCore(services: IChannelStorageService): Promise<void> {
|
|
419
466
|
await super.loadCore(services);
|
|
420
467
|
this.checkout.load();
|
|
421
468
|
}
|
|
422
469
|
|
|
423
470
|
public override didAttach(): void {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
471
|
+
for (const checkout of this.checkouts.values()) {
|
|
472
|
+
if (checkout.transaction.isInProgress()) {
|
|
473
|
+
// Attaching during a transaction is not currently supported.
|
|
474
|
+
// At least part of of the system is known to not handle this case correctly - commit enrichment - and there may be others.
|
|
475
|
+
throw new UsageError(
|
|
476
|
+
"Cannot attach while a transaction is in progress. Commit or abort the transaction before attaching.",
|
|
477
|
+
);
|
|
478
|
+
}
|
|
430
479
|
}
|
|
431
480
|
super.didAttach();
|
|
432
481
|
}
|
|
@@ -436,31 +485,35 @@ export class SharedTreeKernel
|
|
|
436
485
|
SharedTreeCore<SharedTreeEditBuilder, SharedTreeChange>["applyStashedOp"]
|
|
437
486
|
>
|
|
438
487
|
): void {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
488
|
+
for (const checkout of this.checkouts.values()) {
|
|
489
|
+
assert(
|
|
490
|
+
!checkout.transaction.isInProgress(),
|
|
491
|
+
0x674 /* Unexpected transaction is open while applying stashed ops */,
|
|
492
|
+
);
|
|
493
|
+
}
|
|
443
494
|
super.applyStashedOp(...args);
|
|
444
495
|
}
|
|
445
496
|
|
|
446
497
|
protected override submitCommit(
|
|
498
|
+
branchId: BranchId,
|
|
447
499
|
commit: GraphCommit<SharedTreeChange>,
|
|
448
500
|
schemaAndPolicy: ClonableSchemaAndPolicy,
|
|
449
501
|
isResubmit: boolean,
|
|
450
502
|
): void {
|
|
503
|
+
const checkout = this.getCheckout(branchId);
|
|
451
504
|
assert(
|
|
452
|
-
!
|
|
505
|
+
!checkout.transaction.isInProgress(),
|
|
453
506
|
0xaa6 /* Cannot submit a commit while a transaction is in progress */,
|
|
454
507
|
);
|
|
455
508
|
if (isResubmit) {
|
|
456
|
-
return super.submitCommit(commit, schemaAndPolicy, isResubmit);
|
|
509
|
+
return super.submitCommit(branchId, commit, schemaAndPolicy, isResubmit);
|
|
457
510
|
}
|
|
458
511
|
|
|
459
512
|
// Refrain from submitting new commits until they are validated by the checkout.
|
|
460
513
|
// This is not a strict requirement for correctness in our system, but in the event that there is a bug when applying commits to the checkout
|
|
461
514
|
// that causes a crash (e.g. in the forest), this will at least prevent this client from sending the problematic commit to any other clients.
|
|
462
|
-
|
|
463
|
-
super.submitCommit(commit, schemaAndPolicy, isResubmit),
|
|
515
|
+
checkout.onCommitValid(commit, () =>
|
|
516
|
+
super.submitCommit(branchId, commit, schemaAndPolicy, isResubmit),
|
|
464
517
|
);
|
|
465
518
|
}
|
|
466
519
|
|
|
@@ -561,6 +614,11 @@ export const SharedTreeFormatVersion = {
|
|
|
561
614
|
* Requires \@fluidframework/tree \>= 2.0.0.
|
|
562
615
|
*/
|
|
563
616
|
v5: 5,
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* For testing purposes only.
|
|
620
|
+
*/
|
|
621
|
+
vSharedBranches: 100,
|
|
564
622
|
} as const;
|
|
565
623
|
|
|
566
624
|
/**
|
|
@@ -577,13 +635,19 @@ export const SharedTreeFormatVersion = {
|
|
|
577
635
|
*/
|
|
578
636
|
export type SharedTreeFormatVersion = typeof SharedTreeFormatVersion;
|
|
579
637
|
|
|
638
|
+
/**
|
|
639
|
+
* Configuration options for SharedTree.
|
|
640
|
+
* @beta @input
|
|
641
|
+
*/
|
|
642
|
+
export type SharedTreeOptionsBeta = ForestOptions;
|
|
643
|
+
|
|
580
644
|
/**
|
|
581
645
|
* Configuration options for SharedTree.
|
|
582
646
|
* @alpha @input
|
|
583
647
|
*/
|
|
584
648
|
export type SharedTreeOptions = Partial<CodecWriteOptions> &
|
|
585
649
|
Partial<SharedTreeFormatOptions> &
|
|
586
|
-
|
|
650
|
+
SharedTreeOptionsBeta;
|
|
587
651
|
|
|
588
652
|
export interface SharedTreeOptionsInternal
|
|
589
653
|
extends Omit<SharedTreeOptions, "treeEncodeType">,
|
|
@@ -661,7 +725,7 @@ export interface ForestType extends ErasedType<"ForestType"> {}
|
|
|
661
725
|
* A simple implementation with minimal complexity and moderate debuggability, validation and performance.
|
|
662
726
|
* @privateRemarks
|
|
663
727
|
* The "ObjectForest" forest type.
|
|
664
|
-
* @
|
|
728
|
+
* @beta
|
|
665
729
|
*/
|
|
666
730
|
export const ForestTypeReference = toForestType(
|
|
667
731
|
(breaker: Breakable, schema: TreeStoredSchemaSubscription, idCompressor: IIdCompressor) =>
|
|
@@ -675,7 +739,7 @@ export const ForestTypeReference = toForestType(
|
|
|
675
739
|
* Uses an internal representation optimized for size designed to scale to larger datasets with reduced overhead.
|
|
676
740
|
* @privateRemarks
|
|
677
741
|
* The "ChunkedForest" forest type.
|
|
678
|
-
* @
|
|
742
|
+
* @beta
|
|
679
743
|
*/
|
|
680
744
|
export const ForestTypeOptimized = toForestType(
|
|
681
745
|
(breaker: Breakable, schema: TreeStoredSchemaSubscription, idCompressor: IIdCompressor) =>
|
|
@@ -689,7 +753,7 @@ export const ForestTypeOptimized = toForestType(
|
|
|
689
753
|
* May be asymptotically slower than {@link ForestTypeReference}, and may perform very badly with larger data sizes.
|
|
690
754
|
* @privateRemarks
|
|
691
755
|
* The "ObjectForest" forest type with expensive asserts for debugging.
|
|
692
|
-
* @
|
|
756
|
+
* @beta
|
|
693
757
|
*/
|
|
694
758
|
export const ForestTypeExpensiveDebug = toForestType(
|
|
695
759
|
(breaker: Breakable, schema: TreeStoredSchemaSubscription) =>
|
|
@@ -719,7 +783,7 @@ export function buildConfiguredForest(
|
|
|
719
783
|
}
|
|
720
784
|
|
|
721
785
|
export const defaultSharedTreeOptions: Required<SharedTreeOptionsInternal> = {
|
|
722
|
-
jsonValidator:
|
|
786
|
+
jsonValidator: FormatValidatorNoOp,
|
|
723
787
|
oldestCompatibleClient: FluidClientVersion.v2_0,
|
|
724
788
|
forest: ForestTypeReference,
|
|
725
789
|
treeEncodeType: TreeCompressionStrategy.Compressed,
|
|
@@ -17,7 +17,7 @@ import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
|
17
17
|
import {
|
|
18
18
|
asIndex,
|
|
19
19
|
getKernel,
|
|
20
|
-
|
|
20
|
+
TreeNode,
|
|
21
21
|
type Unhydrated,
|
|
22
22
|
TreeBeta,
|
|
23
23
|
tryGetSchema,
|
|
@@ -55,15 +55,16 @@ 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 {
|
|
61
62
|
FluidClientVersion,
|
|
62
|
-
noopValidator,
|
|
63
63
|
type ICodecOptions,
|
|
64
64
|
type CodecWriteOptions,
|
|
65
|
+
FormatValidatorNoOp,
|
|
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,
|
|
@@ -76,6 +77,9 @@ import {
|
|
|
76
77
|
fluidVersionToFieldBatchCodecWriteVersion,
|
|
77
78
|
type LocalNodeIdentifier,
|
|
78
79
|
type FlexTreeSequenceField,
|
|
80
|
+
type FlexTreeNode,
|
|
81
|
+
type Observer,
|
|
82
|
+
withObservation,
|
|
79
83
|
} from "../feature-libraries/index.js";
|
|
80
84
|
import { independentInitializedView, type ViewContent } from "./independentView.js";
|
|
81
85
|
import { SchematizingSimpleTreeView, ViewSlot } from "./schematizingTreeView.js";
|
|
@@ -419,6 +423,283 @@ export interface TreeAlpha {
|
|
|
419
423
|
children(
|
|
420
424
|
node: TreeNode,
|
|
421
425
|
): 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
|
+
* These subscriptions remain active until `unsubscribe` is called: `onInvalidation` may be called multiple times.
|
|
439
|
+
* See {@link (TreeAlpha:interface).trackObservationsOnce} for a version which automatically unsubscribes on the first invalidation.
|
|
440
|
+
* @privateRemarks
|
|
441
|
+
* This version, while more general than {@link (TreeAlpha:interface).trackObservationsOnce}, might be unnecessary.
|
|
442
|
+
* Maybe this should be removed and only `trackObservationsOnce` kept.
|
|
443
|
+
* Reevaluate this before stabilizing.
|
|
444
|
+
*/
|
|
445
|
+
trackObservations<TResult>(
|
|
446
|
+
onInvalidation: () => void,
|
|
447
|
+
trackDuring: () => TResult,
|
|
448
|
+
): ObservationResults<TResult>;
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* {@link (TreeAlpha:interface).trackObservations} except automatically unsubscribes when the first invalidation occurs.
|
|
452
|
+
* @remarks
|
|
453
|
+
* This also supports tracking parentage, unlike {@link (TreeAlpha:interface).trackObservations}, as long as the parent is not undefined.
|
|
454
|
+
*
|
|
455
|
+
* @example Simple cached value invalidation
|
|
456
|
+
* ```typescript
|
|
457
|
+
* // Compute and cache this "foo" value, and clear the cache when the fields read in the callback to compute it change.
|
|
458
|
+
* cachedFoo ??= TreeAlpha.trackObservationsOnce(
|
|
459
|
+
* () => {
|
|
460
|
+
* cachedFoo = undefined;
|
|
461
|
+
* },
|
|
462
|
+
* () => nodeA.someChild.bar + nodeB.someChild.baz,
|
|
463
|
+
* ).result;
|
|
464
|
+
* ```
|
|
465
|
+
*
|
|
466
|
+
* That is equivalent to doing the following:
|
|
467
|
+
* ```typescript
|
|
468
|
+
* if (cachedFoo === undefined) {
|
|
469
|
+
* cachedFoo = nodeA.someChild.bar + nodeB.someChild.baz;
|
|
470
|
+
* const invalidate = (): void => {
|
|
471
|
+
* cachedFoo = undefined;
|
|
472
|
+
* for (const u of unsubscribe) {
|
|
473
|
+
* u();
|
|
474
|
+
* }
|
|
475
|
+
* };
|
|
476
|
+
* const unsubscribe: (() => void)[] = [
|
|
477
|
+
* TreeBeta.on(nodeA, "nodeChanged", (data) => {
|
|
478
|
+
* if (data.changedProperties.has("someChild")) {
|
|
479
|
+
* invalidate();
|
|
480
|
+
* }
|
|
481
|
+
* }),
|
|
482
|
+
* TreeBeta.on(nodeB, "nodeChanged", (data) => {
|
|
483
|
+
* if (data.changedProperties.has("someChild")) {
|
|
484
|
+
* invalidate();
|
|
485
|
+
* }
|
|
486
|
+
* }),
|
|
487
|
+
* TreeBeta.on(nodeA.someChild, "nodeChanged", (data) => {
|
|
488
|
+
* if (data.changedProperties.has("bar")) {
|
|
489
|
+
* invalidate();
|
|
490
|
+
* }
|
|
491
|
+
* }),
|
|
492
|
+
* TreeBeta.on(nodeB.someChild, "nodeChanged", (data) => {
|
|
493
|
+
* if (data.changedProperties.has("baz")) {
|
|
494
|
+
* invalidate();
|
|
495
|
+
* }
|
|
496
|
+
* }),
|
|
497
|
+
* ];
|
|
498
|
+
* }
|
|
499
|
+
* ```
|
|
500
|
+
* @example Cached derived schema property
|
|
501
|
+
* ```typescript
|
|
502
|
+
* const factory = new SchemaFactory("com.example");
|
|
503
|
+
* class Vector extends factory.object("Vector", {
|
|
504
|
+
* x: SchemaFactory.number,
|
|
505
|
+
* y: SchemaFactory.number,
|
|
506
|
+
* }) {
|
|
507
|
+
* #length: number | undefined = undefined;
|
|
508
|
+
* public length(): number {
|
|
509
|
+
* if (this.#length === undefined) {
|
|
510
|
+
* const result = TreeAlpha.trackObservationsOnce(
|
|
511
|
+
* () => {
|
|
512
|
+
* this.#length = undefined;
|
|
513
|
+
* },
|
|
514
|
+
* () => Math.hypot(this.x, this.y),
|
|
515
|
+
* );
|
|
516
|
+
* this.#length = result.result;
|
|
517
|
+
* }
|
|
518
|
+
* return this.#length;
|
|
519
|
+
* }
|
|
520
|
+
* }
|
|
521
|
+
* const vec = new Vector({ x: 3, y: 4 });
|
|
522
|
+
* assert.equal(vec.length(), 5);
|
|
523
|
+
* vec.x = 0;
|
|
524
|
+
* assert.equal(vec.length(), 4);
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
trackObservationsOnce<TResult>(
|
|
528
|
+
onInvalidation: () => void,
|
|
529
|
+
trackDuring: () => TResult,
|
|
530
|
+
): ObservationResults<TResult>;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Results from an operation with tracked observations.
|
|
535
|
+
* @remarks
|
|
536
|
+
* Results from {@link (TreeAlpha:interface).trackObservations} or {@link (TreeAlpha:interface).trackObservationsOnce}.
|
|
537
|
+
* @sealed @alpha
|
|
538
|
+
*/
|
|
539
|
+
export interface ObservationResults<TResult> {
|
|
540
|
+
/**
|
|
541
|
+
* The result of the operation which had its observations tracked.
|
|
542
|
+
*/
|
|
543
|
+
readonly result: TResult;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Call to unsubscribe from further invalidations.
|
|
547
|
+
*/
|
|
548
|
+
readonly unsubscribe: () => void;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Subscription to changes on a single node.
|
|
553
|
+
* @remarks
|
|
554
|
+
* Either tracks some set of fields, or all fields and can be updated to track more fields.
|
|
555
|
+
*/
|
|
556
|
+
class NodeSubscription {
|
|
557
|
+
/**
|
|
558
|
+
* If undefined, subscribes to all keys.
|
|
559
|
+
* Otherwise only subscribes to the keys in the set.
|
|
560
|
+
*/
|
|
561
|
+
private keys: Set<FieldKey> | undefined;
|
|
562
|
+
private readonly unsubscribe: () => void;
|
|
563
|
+
private constructor(
|
|
564
|
+
private readonly onInvalidation: () => void,
|
|
565
|
+
flexNode: FlexTreeNode,
|
|
566
|
+
) {
|
|
567
|
+
// TODO:Performance: It is possible to optimize this to not use the public TreeNode API.
|
|
568
|
+
const node = getOrCreateNodeFromInnerNode(flexNode);
|
|
569
|
+
assert(node instanceof TreeNode, 0xc54 /* Unexpected leaf value */);
|
|
570
|
+
|
|
571
|
+
const handler = (data: NodeChangedData): void => {
|
|
572
|
+
if (this.keys === undefined || data.changedProperties === undefined) {
|
|
573
|
+
this.onInvalidation();
|
|
574
|
+
} else {
|
|
575
|
+
let keyMap: ReadonlyMap<FieldKey, string> | undefined;
|
|
576
|
+
const schema = treeNodeApi.schema(node);
|
|
577
|
+
if (isObjectNodeSchema(schema)) {
|
|
578
|
+
keyMap = schema.storedKeyToPropertyKey;
|
|
579
|
+
}
|
|
580
|
+
// TODO:Performance: Ideally this would use Set.prototype.isDisjointFrom when available.
|
|
581
|
+
for (const flexKey of this.keys) {
|
|
582
|
+
// TODO:Performance: doing everything at the flex tree layer could avoid this translation
|
|
583
|
+
const key = keyMap?.get(flexKey) ?? flexKey;
|
|
584
|
+
|
|
585
|
+
if (data.changedProperties.has(key)) {
|
|
586
|
+
this.onInvalidation();
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
this.unsubscribe = TreeBeta.on(node, "nodeChanged", handler);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Create an {@link Observer} which subscribes to what was observed in {@link NodeSubscription}s.
|
|
597
|
+
*/
|
|
598
|
+
public static createObserver(
|
|
599
|
+
invalidate: () => void,
|
|
600
|
+
onlyOnce = false,
|
|
601
|
+
): { observer: Observer; unsubscribe: () => void } {
|
|
602
|
+
const subscriptions = new Map<FlexTreeNode, NodeSubscription>();
|
|
603
|
+
const observer: Observer = {
|
|
604
|
+
observeNodeFields(flexNode: FlexTreeNode): void {
|
|
605
|
+
if (flexNode.value !== undefined) {
|
|
606
|
+
// Leaf value, nothing to observe.
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
const subscription = subscriptions.get(flexNode);
|
|
610
|
+
if (subscription !== undefined) {
|
|
611
|
+
// Already subscribed to this node.
|
|
612
|
+
subscription.keys = undefined; // Now subscribed to all keys.
|
|
613
|
+
} else {
|
|
614
|
+
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
615
|
+
subscriptions.set(flexNode, newSubscription);
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
observeNodeField(flexNode: FlexTreeNode, key: FieldKey): void {
|
|
619
|
+
if (flexNode.value !== undefined) {
|
|
620
|
+
// Leaf value, nothing to observe.
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const subscription = subscriptions.get(flexNode);
|
|
624
|
+
if (subscription !== undefined) {
|
|
625
|
+
// Already subscribed to this node: if not subscribed to all keys, subscribe to this one.
|
|
626
|
+
// TODO:Performance: due to how JavaScript set ordering works,
|
|
627
|
+
// it might be faster to check `has` and only add if not present in case the same field is viewed many times.
|
|
628
|
+
subscription.keys?.add(key);
|
|
629
|
+
} else {
|
|
630
|
+
const newSubscription = new NodeSubscription(invalidate, flexNode);
|
|
631
|
+
newSubscription.keys = new Set([key]);
|
|
632
|
+
subscriptions.set(flexNode, newSubscription);
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
observeParentOf(node: FlexTreeNode): void {
|
|
636
|
+
// Supporting parent tracking is more difficult that it might seem at first.
|
|
637
|
+
// There are two main complicating factors:
|
|
638
|
+
// 1. The parent may be undefined (the node is a root).
|
|
639
|
+
// 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.
|
|
640
|
+
//
|
|
641
|
+
// If not supporting the first case (undefined parents), the second case gets problematic: edits which un-parent a node could error due to being unable to update the event subscription.
|
|
642
|
+
// For now this is mitigated by only supporting one of tracking (non-undefined) parents or maintaining event subscriptions across edits.
|
|
643
|
+
|
|
644
|
+
if (!onlyOnce) {
|
|
645
|
+
// TODO: better APIS should be provided which make handling this case practical.
|
|
646
|
+
throw new UsageError("Observation tracking for parents is currently not supported.");
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const parent = withObservation(undefined, () => node.parentField.parent);
|
|
650
|
+
|
|
651
|
+
if (parent.parent === undefined) {
|
|
652
|
+
// TODO: better APIS should be provided which make handling this case practical.
|
|
653
|
+
throw new UsageError(
|
|
654
|
+
"Observation tracking for parents is currently not supported when parent is undefined.",
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
observer.observeNodeField(parent.parent, parent.key);
|
|
658
|
+
},
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
let subscribed = true;
|
|
662
|
+
|
|
663
|
+
return {
|
|
664
|
+
observer,
|
|
665
|
+
unsubscribe: () => {
|
|
666
|
+
if (!subscribed) {
|
|
667
|
+
throw new UsageError("Already unsubscribed");
|
|
668
|
+
}
|
|
669
|
+
subscribed = false;
|
|
670
|
+
for (const subscription of subscriptions.values()) {
|
|
671
|
+
subscription.unsubscribe();
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Handles both {@link (TreeAlpha:interface).trackObservations} and {@link (TreeAlpha:interface).trackObservationsOnce}.
|
|
680
|
+
*/
|
|
681
|
+
function trackObservations<TResult>(
|
|
682
|
+
onInvalidation: () => void,
|
|
683
|
+
trackDuring: () => TResult,
|
|
684
|
+
onlyOnce = false,
|
|
685
|
+
): ObservationResults<TResult> {
|
|
686
|
+
let observing = true;
|
|
687
|
+
|
|
688
|
+
const invalidate = (): void => {
|
|
689
|
+
if (observing) {
|
|
690
|
+
throw new UsageError("Cannot invalidate while tracking observations");
|
|
691
|
+
}
|
|
692
|
+
onInvalidation();
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
const { observer, unsubscribe } = NodeSubscription.createObserver(invalidate, onlyOnce);
|
|
696
|
+
const result = withObservation(observer, trackDuring);
|
|
697
|
+
observing = false;
|
|
698
|
+
|
|
699
|
+
return {
|
|
700
|
+
result,
|
|
701
|
+
unsubscribe,
|
|
702
|
+
};
|
|
422
703
|
}
|
|
423
704
|
|
|
424
705
|
/**
|
|
@@ -427,6 +708,30 @@ export interface TreeAlpha {
|
|
|
427
708
|
* @alpha
|
|
428
709
|
*/
|
|
429
710
|
export const TreeAlpha: TreeAlpha = {
|
|
711
|
+
trackObservations<TResult>(
|
|
712
|
+
onInvalidation: () => void,
|
|
713
|
+
trackDuring: () => TResult,
|
|
714
|
+
): ObservationResults<TResult> {
|
|
715
|
+
return trackObservations(onInvalidation, trackDuring);
|
|
716
|
+
},
|
|
717
|
+
|
|
718
|
+
trackObservationsOnce<TResult>(
|
|
719
|
+
onInvalidation: () => void,
|
|
720
|
+
trackDuring: () => TResult,
|
|
721
|
+
): ObservationResults<TResult> {
|
|
722
|
+
const result = trackObservations(
|
|
723
|
+
() => {
|
|
724
|
+
// trackObservations ensures no invalidation occurs while its running,
|
|
725
|
+
// so this callback can only run after trackObservations has returns and thus result is defined.
|
|
726
|
+
result.unsubscribe();
|
|
727
|
+
onInvalidation();
|
|
728
|
+
},
|
|
729
|
+
trackDuring,
|
|
730
|
+
true,
|
|
731
|
+
);
|
|
732
|
+
return result;
|
|
733
|
+
},
|
|
734
|
+
|
|
430
735
|
branch(node: TreeNode): TreeBranch | undefined {
|
|
431
736
|
const kernel = getKernel(node);
|
|
432
737
|
if (!kernel.isHydrated()) {
|
|
@@ -523,7 +828,7 @@ export const TreeAlpha: TreeAlpha = {
|
|
|
523
828
|
): JsonCompatible<IFluidHandle> {
|
|
524
829
|
const schema = tryGetSchema(node) ?? fail(0xacf /* invalid input */);
|
|
525
830
|
const format = fluidVersionToFieldBatchCodecWriteVersion(options.oldestCompatibleClient);
|
|
526
|
-
const codec = makeFieldBatchCodec({ jsonValidator:
|
|
831
|
+
const codec = makeFieldBatchCodec({ jsonValidator: FormatValidatorNoOp }, format);
|
|
527
832
|
const cursor = borrowFieldCursorFromTreeNodeOrValue(node);
|
|
528
833
|
const batch: FieldBatch = [cursor];
|
|
529
834
|
// If none provided, create a compressor which will not compress anything.
|