@fluidframework/tree 2.115.0 → 2.116.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 +84 -0
- package/README.md +5 -3
- package/api-report/tree.alpha.api.md +4 -2
- package/api-report/tree.beta.api.md +1 -1
- package/api-report/tree.legacy.beta.api.md +1 -1
- package/dist/codec/codec.d.ts +6 -6
- package/dist/codec/codec.d.ts.map +1 -1
- package/dist/codec/codec.js +3 -3
- package/dist/codec/codec.js.map +1 -1
- package/dist/codec/versioned/codec.d.ts +3 -3
- package/dist/codec/versioned/codec.d.ts.map +1 -1
- package/dist/codec/versioned/codec.js.map +1 -1
- package/dist/core/forest/editableForest.d.ts +2 -0
- package/dist/core/forest/editableForest.d.ts.map +1 -1
- package/dist/core/forest/editableForest.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 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/tree/index.d.ts +1 -1
- package/dist/core/tree/index.d.ts.map +1 -1
- package/dist/core/tree/index.js +2 -2
- package/dist/core/tree/index.js.map +1 -1
- package/dist/core/tree/visitorUtils.d.ts +24 -3
- package/dist/core/tree/visitorUtils.d.ts.map +1 -1
- package/dist/core/tree/visitorUtils.js +24 -6
- package/dist/core/tree/visitorUtils.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.d.ts +30 -6
- package/dist/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.js +146 -54
- package/dist/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/dist/feature-libraries/comparison-forest/comparisonForest.d.ts +2 -1
- package/dist/feature-libraries/comparison-forest/comparisonForest.d.ts.map +1 -1
- package/dist/feature-libraries/comparison-forest/comparisonForest.js +87 -70
- package/dist/feature-libraries/comparison-forest/comparisonForest.js.map +1 -1
- package/dist/feature-libraries/detachedFieldIndexSummarizer.js.map +1 -1
- package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts +5 -0
- package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
- package/dist/feature-libraries/forest-summary/forestSummarizer.js +127 -107
- package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
- package/dist/feature-libraries/forest-summary/summaryTypes.d.ts +2 -2
- package/dist/feature-libraries/forest-summary/summaryTypes.d.ts.map +1 -1
- package/dist/feature-libraries/forest-summary/summaryTypes.js.map +1 -1
- package/dist/feature-libraries/indexing/anchorTreeIndex.js +1 -1
- package/dist/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
- package/dist/feature-libraries/modular-schema/invert.js +1 -1
- package/dist/feature-libraries/modular-schema/invert.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeFamily.js +2 -11
- package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeUtils.d.ts +11 -16
- package/dist/feature-libraries/modular-schema/modularChangeUtils.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeUtils.js +10 -3
- package/dist/feature-libraries/modular-schema/modularChangeUtils.js.map +1 -1
- package/dist/feature-libraries/object-forest/objectForest.d.ts.map +1 -1
- package/dist/feature-libraries/object-forest/objectForest.js +34 -13
- package/dist/feature-libraries/object-forest/objectForest.js.map +1 -1
- package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts +2 -2
- package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
- package/dist/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
- package/dist/feature-libraries/sequence-field/rebase.js +1 -1
- package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
- package/dist/feature-libraries/sequence-field/utils.js +1 -1
- package/dist/feature-libraries/sequence-field/utils.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/independentView.d.ts.map +1 -1
- package/dist/shared-tree/independentView.js +2 -4
- package/dist/shared-tree/independentView.js.map +1 -1
- package/dist/shared-tree/sharedTree.d.ts +30 -5
- package/dist/shared-tree/sharedTree.d.ts.map +1 -1
- package/dist/shared-tree/sharedTree.js +8 -8
- package/dist/shared-tree/sharedTree.js.map +1 -1
- package/dist/shared-tree/sharedTreeChangeCodecs.d.ts +2 -2
- package/dist/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
- package/dist/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
- package/dist/shared-tree/sharedTreeChangeEnricher.d.ts +25 -1
- package/dist/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
- package/dist/shared-tree/sharedTreeChangeEnricher.js +24 -0
- package/dist/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
- package/dist/shared-tree/treeCheckout.d.ts +21 -10
- package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
- package/dist/shared-tree/treeCheckout.js +48 -16
- package/dist/shared-tree/treeCheckout.js.map +1 -1
- package/dist/shared-tree-core/branchCommitEnricher.d.ts +2 -1
- package/dist/shared-tree-core/branchCommitEnricher.d.ts.map +1 -1
- package/dist/shared-tree-core/branchCommitEnricher.js +3 -2
- package/dist/shared-tree-core/branchCommitEnricher.js.map +1 -1
- package/dist/shared-tree-core/changeEnricher.d.ts +3 -2
- package/dist/shared-tree-core/changeEnricher.d.ts.map +1 -1
- package/dist/shared-tree-core/changeEnricher.js.map +1 -1
- package/dist/shared-tree-core/defaultResubmitMachine.d.ts +9 -1
- package/dist/shared-tree-core/defaultResubmitMachine.d.ts.map +1 -1
- package/dist/shared-tree-core/defaultResubmitMachine.js +7 -2
- package/dist/shared-tree-core/defaultResubmitMachine.js.map +1 -1
- package/dist/shared-tree-core/editManager.d.ts.map +1 -1
- package/dist/shared-tree-core/editManager.js +2 -2
- package/dist/shared-tree-core/editManager.js.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.d.ts +2 -2
- package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/dist/shared-tree-core/editManagerSummarizer.d.ts +2 -2
- package/dist/shared-tree-core/editManagerSummarizer.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerSummarizer.js.map +1 -1
- package/dist/shared-tree-core/messageCodecs.d.ts +2 -2
- package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/messageCodecs.js.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.d.ts +11 -2
- package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.js +11 -8
- package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/dist/shared-tree-core/summaryTypes.d.ts +2 -2
- package/dist/shared-tree-core/summaryTypes.d.ts.map +1 -1
- package/dist/shared-tree-core/summaryTypes.js.map +1 -1
- package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts +1 -1
- package/dist/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
- package/dist/simple-tree/api/storedSchema.d.ts +2 -2
- package/dist/simple-tree/api/storedSchema.d.ts.map +1 -1
- package/dist/simple-tree/api/storedSchema.js.map +1 -1
- package/dist/simple-tree/api/treeChangeEvents.d.ts +5 -1
- package/dist/simple-tree/api/treeChangeEvents.d.ts.map +1 -1
- package/dist/simple-tree/api/treeChangeEvents.js.map +1 -1
- package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/array/arrayNode.js +10 -0
- package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.js +19 -2
- package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/dist/tableSchema.d.ts +1 -1
- package/dist/tableSchema.js +1 -1
- package/dist/tableSchema.js.map +1 -1
- package/dist/treeFactory.d.ts.map +1 -1
- package/dist/treeFactory.js +1 -1
- package/dist/treeFactory.js.map +1 -1
- package/dist/util/breakable.d.ts +14 -2
- package/dist/util/breakable.d.ts.map +1 -1
- package/dist/util/breakable.js +9 -1
- package/dist/util/breakable.js.map +1 -1
- package/dist/util/compressedIds.d.ts +2 -2
- package/dist/util/compressedIds.d.ts.map +1 -1
- package/dist/util/compressedIds.js +1 -6
- package/dist/util/compressedIds.js.map +1 -1
- package/lib/codec/codec.d.ts +6 -6
- package/lib/codec/codec.d.ts.map +1 -1
- package/lib/codec/codec.js +3 -3
- package/lib/codec/codec.js.map +1 -1
- package/lib/codec/versioned/codec.d.ts +3 -3
- package/lib/codec/versioned/codec.d.ts.map +1 -1
- package/lib/codec/versioned/codec.js.map +1 -1
- package/lib/core/forest/editableForest.d.ts +2 -0
- package/lib/core/forest/editableForest.d.ts.map +1 -1
- package/lib/core/forest/editableForest.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/tree/index.d.ts +1 -1
- package/lib/core/tree/index.d.ts.map +1 -1
- package/lib/core/tree/index.js +1 -1
- package/lib/core/tree/index.js.map +1 -1
- package/lib/core/tree/visitorUtils.d.ts +24 -3
- package/lib/core/tree/visitorUtils.d.ts.map +1 -1
- package/lib/core/tree/visitorUtils.js +22 -4
- package/lib/core/tree/visitorUtils.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.d.ts +30 -6
- package/lib/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.js +146 -56
- package/lib/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/lib/feature-libraries/comparison-forest/comparisonForest.d.ts +2 -1
- package/lib/feature-libraries/comparison-forest/comparisonForest.d.ts.map +1 -1
- package/lib/feature-libraries/comparison-forest/comparisonForest.js +88 -70
- package/lib/feature-libraries/comparison-forest/comparisonForest.js.map +1 -1
- package/lib/feature-libraries/detachedFieldIndexSummarizer.js.map +1 -1
- package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts +5 -0
- package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
- package/lib/feature-libraries/forest-summary/forestSummarizer.js +129 -108
- package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
- package/lib/feature-libraries/forest-summary/summaryTypes.d.ts +2 -2
- package/lib/feature-libraries/forest-summary/summaryTypes.d.ts.map +1 -1
- package/lib/feature-libraries/forest-summary/summaryTypes.js.map +1 -1
- package/lib/feature-libraries/indexing/anchorTreeIndex.js +1 -1
- package/lib/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
- package/lib/feature-libraries/modular-schema/invert.js +2 -2
- package/lib/feature-libraries/modular-schema/invert.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeFamily.js +2 -11
- package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeUtils.d.ts +11 -16
- package/lib/feature-libraries/modular-schema/modularChangeUtils.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeUtils.js +10 -3
- package/lib/feature-libraries/modular-schema/modularChangeUtils.js.map +1 -1
- package/lib/feature-libraries/object-forest/objectForest.d.ts.map +1 -1
- package/lib/feature-libraries/object-forest/objectForest.js +35 -14
- package/lib/feature-libraries/object-forest/objectForest.js.map +1 -1
- package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts +2 -2
- package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
- package/lib/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
- package/lib/feature-libraries/sequence-field/rebase.js +2 -2
- package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
- package/lib/feature-libraries/sequence-field/utils.js +1 -1
- package/lib/feature-libraries/sequence-field/utils.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/independentView.d.ts.map +1 -1
- package/lib/shared-tree/independentView.js +3 -5
- package/lib/shared-tree/independentView.js.map +1 -1
- package/lib/shared-tree/sharedTree.d.ts +30 -5
- package/lib/shared-tree/sharedTree.d.ts.map +1 -1
- package/lib/shared-tree/sharedTree.js +8 -8
- package/lib/shared-tree/sharedTree.js.map +1 -1
- package/lib/shared-tree/sharedTreeChangeCodecs.d.ts +2 -2
- package/lib/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
- package/lib/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
- package/lib/shared-tree/sharedTreeChangeEnricher.d.ts +25 -1
- package/lib/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
- package/lib/shared-tree/sharedTreeChangeEnricher.js +24 -0
- package/lib/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
- package/lib/shared-tree/treeCheckout.d.ts +21 -10
- package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
- package/lib/shared-tree/treeCheckout.js +48 -16
- package/lib/shared-tree/treeCheckout.js.map +1 -1
- package/lib/shared-tree-core/branchCommitEnricher.d.ts +2 -1
- package/lib/shared-tree-core/branchCommitEnricher.d.ts.map +1 -1
- package/lib/shared-tree-core/branchCommitEnricher.js +3 -2
- package/lib/shared-tree-core/branchCommitEnricher.js.map +1 -1
- package/lib/shared-tree-core/changeEnricher.d.ts +3 -2
- package/lib/shared-tree-core/changeEnricher.d.ts.map +1 -1
- package/lib/shared-tree-core/changeEnricher.js.map +1 -1
- package/lib/shared-tree-core/defaultResubmitMachine.d.ts +9 -1
- package/lib/shared-tree-core/defaultResubmitMachine.d.ts.map +1 -1
- package/lib/shared-tree-core/defaultResubmitMachine.js +7 -2
- package/lib/shared-tree-core/defaultResubmitMachine.js.map +1 -1
- package/lib/shared-tree-core/editManager.d.ts.map +1 -1
- package/lib/shared-tree-core/editManager.js +2 -2
- package/lib/shared-tree-core/editManager.js.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.d.ts +2 -2
- package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/lib/shared-tree-core/editManagerSummarizer.d.ts +2 -2
- package/lib/shared-tree-core/editManagerSummarizer.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerSummarizer.js.map +1 -1
- package/lib/shared-tree-core/messageCodecs.d.ts +2 -2
- package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/messageCodecs.js.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.d.ts +11 -2
- package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.js +11 -8
- package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/lib/shared-tree-core/summaryTypes.d.ts +2 -2
- package/lib/shared-tree-core/summaryTypes.d.ts.map +1 -1
- package/lib/shared-tree-core/summaryTypes.js.map +1 -1
- package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts +1 -1
- package/lib/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
- package/lib/simple-tree/api/storedSchema.d.ts +2 -2
- package/lib/simple-tree/api/storedSchema.d.ts.map +1 -1
- package/lib/simple-tree/api/storedSchema.js.map +1 -1
- package/lib/simple-tree/api/treeChangeEvents.d.ts +5 -1
- package/lib/simple-tree/api/treeChangeEvents.d.ts.map +1 -1
- package/lib/simple-tree/api/treeChangeEvents.js.map +1 -1
- package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/array/arrayNode.js +10 -0
- package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.js +19 -2
- package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/lib/tableSchema.d.ts +1 -1
- package/lib/tableSchema.js +1 -1
- package/lib/tableSchema.js.map +1 -1
- package/lib/treeFactory.d.ts.map +1 -1
- package/lib/treeFactory.js +1 -1
- package/lib/treeFactory.js.map +1 -1
- package/lib/util/breakable.d.ts +14 -2
- package/lib/util/breakable.d.ts.map +1 -1
- package/lib/util/breakable.js +9 -1
- package/lib/util/breakable.js.map +1 -1
- package/lib/util/compressedIds.d.ts +2 -2
- package/lib/util/compressedIds.d.ts.map +1 -1
- package/lib/util/compressedIds.js +1 -6
- package/lib/util/compressedIds.js.map +1 -1
- package/package.json +27 -27
- package/src/codec/codec.ts +7 -7
- package/src/codec/versioned/codec.ts +5 -5
- package/src/core/forest/editableForest.ts +2 -0
- package/src/core/index.ts +1 -1
- package/src/core/tree/index.ts +1 -1
- package/src/core/tree/visitorUtils.ts +37 -12
- package/src/feature-libraries/chunked-forest/chunkedForest.ts +214 -59
- package/src/feature-libraries/comparison-forest/comparisonForest.ts +6 -1
- package/src/feature-libraries/detachedFieldIndexSummarizer.ts +2 -2
- package/src/feature-libraries/forest-summary/forestSummarizer.ts +10 -0
- package/src/feature-libraries/forest-summary/summaryTypes.ts +2 -2
- package/src/feature-libraries/indexing/anchorTreeIndex.ts +1 -1
- package/src/feature-libraries/modular-schema/invert.ts +2 -2
- package/src/feature-libraries/modular-schema/modularChangeFamily.ts +2 -23
- package/src/feature-libraries/modular-schema/modularChangeUtils.ts +12 -21
- package/src/feature-libraries/object-forest/objectForest.ts +48 -14
- package/src/feature-libraries/schema-index/schemaSummarizer.ts +3 -3
- package/src/feature-libraries/sequence-field/rebase.ts +2 -2
- package/src/feature-libraries/sequence-field/utils.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/independentView.ts +5 -12
- package/src/shared-tree/sharedTree.ts +41 -10
- package/src/shared-tree/sharedTreeChangeCodecs.ts +2 -2
- package/src/shared-tree/sharedTreeChangeEnricher.ts +25 -1
- package/src/shared-tree/treeCheckout.ts +45 -16
- package/src/shared-tree-core/branchCommitEnricher.ts +6 -2
- package/src/shared-tree-core/changeEnricher.ts +7 -2
- package/src/shared-tree-core/defaultResubmitMachine.ts +5 -0
- package/src/shared-tree-core/editManager.ts +2 -4
- package/src/shared-tree-core/editManagerCodecs.ts +2 -2
- package/src/shared-tree-core/editManagerSummarizer.ts +3 -3
- package/src/shared-tree-core/messageCodecs.ts +2 -2
- package/src/shared-tree-core/sharedTreeCore.ts +29 -11
- package/src/shared-tree-core/summaryTypes.ts +2 -2
- package/src/simple-tree/api/snapshotCompatibilityChecker.ts +1 -1
- package/src/simple-tree/api/storedSchema.ts +2 -2
- package/src/simple-tree/api/treeChangeEvents.ts +5 -1
- package/src/simple-tree/node-kinds/array/arrayNode.ts +15 -0
- package/src/simple-tree/node-kinds/map/mapNode.ts +23 -2
- package/src/tableSchema.ts +1 -1
- package/src/treeFactory.ts +0 -1
- package/src/util/breakable.ts +9 -1
- package/src/util/compressedIds.ts +7 -13
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { type IdAllocator, idAllocatorFromMaxId } from "../../util/index.js";
|
|
6
|
+
import { type Breakable, type IdAllocator, idAllocatorFromMaxId } from "../../util/index.js";
|
|
7
7
|
import type { RevisionTag } from "../rebase/index.js";
|
|
8
8
|
import type { FieldKey } from "../schema-stored/index.js";
|
|
9
9
|
|
|
@@ -29,28 +29,53 @@ export function applyDelta(
|
|
|
29
29
|
visitor.free();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function announceDelta(
|
|
33
|
-
delta: Root,
|
|
34
|
-
latestRevision: RevisionTag | undefined,
|
|
35
|
-
deltaProcessor: { acquireVisitor: () => DeltaVisitor & AnnouncedVisitor },
|
|
36
|
-
detachedFieldIndex: DetachedFieldIndex,
|
|
37
|
-
): void {
|
|
38
|
-
const visitor = deltaProcessor.acquireVisitor();
|
|
39
|
-
visitDelta(delta, combineVisitors([visitor]), detachedFieldIndex, latestRevision);
|
|
40
|
-
visitor.free();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
32
|
export interface CombinedVisitor extends DeltaVisitor {
|
|
44
33
|
readonly type: "Combined";
|
|
45
34
|
|
|
46
35
|
readonly visitors: readonly CombinableVisitor[];
|
|
47
36
|
}
|
|
48
37
|
|
|
38
|
+
/**
|
|
39
|
+
* A visitor accepted by {@link combineVisitors}.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* Plain {@link DeltaVisitor}s are intersected with `{ readonly type?: never }` so this forms a
|
|
43
|
+
* discriminated union with {@link AnnouncedVisitor} and {@link CombinedVisitor}. The optional
|
|
44
|
+
* `never` property permits visitors without a `type`, while preventing a visitor with an unknown
|
|
45
|
+
* or widened `type` from being treated as plain and losing its specialized composition behavior.
|
|
46
|
+
*/
|
|
49
47
|
export type CombinableVisitor =
|
|
50
48
|
| (DeltaVisitor & { type?: never })
|
|
51
49
|
| AnnouncedVisitor
|
|
52
50
|
| CombinedVisitor;
|
|
53
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Wraps a visitor so any error breaks the supplied scope and all subsequent calls fail.
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* The `{ readonly type?: never }` intersection restricts this helper to plain visitors. Wrapping
|
|
57
|
+
* an {@link AnnouncedVisitor} or {@link CombinedVisitor} as a plain visitor would hide its `type`
|
|
58
|
+
* discriminator and prevent {@link combineVisitors} from preserving announced-event ordering or
|
|
59
|
+
* flattening nested combined visitors.
|
|
60
|
+
*/
|
|
61
|
+
export function makeBreakingVisitor(
|
|
62
|
+
visitor: DeltaVisitor & { readonly type?: never },
|
|
63
|
+
breaker: Breakable,
|
|
64
|
+
): DeltaVisitor & { readonly type?: never } {
|
|
65
|
+
return {
|
|
66
|
+
free: () => breaker.run(() => visitor.free()),
|
|
67
|
+
create: (...args) => breaker.run(() => visitor.create(...args)),
|
|
68
|
+
destroy: (...args) => breaker.run(() => visitor.destroy(...args)),
|
|
69
|
+
attach: (...args) => breaker.run(() => visitor.attach(...args)),
|
|
70
|
+
detach: (...args) => breaker.run(() => visitor.detach(...args)),
|
|
71
|
+
enterNode: (...args) => breaker.run(() => visitor.enterNode(...args)),
|
|
72
|
+
exitNode: (...args) => breaker.run(() => visitor.exitNode(...args)),
|
|
73
|
+
enterField: (...args) => breaker.run(() => visitor.enterField(...args)),
|
|
74
|
+
exitField: (...args) => breaker.run(() => visitor.exitField(...args)),
|
|
75
|
+
fieldMarks: (...args) => breaker.run(() => visitor.fieldMarks?.(...args)),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
54
79
|
/**
|
|
55
80
|
* Combines multiple visitors into a single visitor.
|
|
56
81
|
* @param visitors - The returned visitor invokes the corresponding events for all these visitors, in order.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { createEmitter } from "@fluid-internal/client-utils";
|
|
7
7
|
import type { Listenable } from "@fluidframework/core-interfaces";
|
|
8
|
-
import { assert, oob, fail } from "@fluidframework/core-utils/internal";
|
|
8
|
+
import { assert, oob, fail, debugAssert } from "@fluidframework/core-utils/internal";
|
|
9
9
|
import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
10
10
|
|
|
11
11
|
import {
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
aboveRootPlaceholder,
|
|
30
30
|
combineVisitors,
|
|
31
31
|
detachedFieldAsKey,
|
|
32
|
+
makeBreakingVisitor,
|
|
32
33
|
mapCursorField,
|
|
33
34
|
rootFieldKey,
|
|
34
35
|
type ChunkedCursor,
|
|
@@ -36,11 +37,13 @@ import {
|
|
|
36
37
|
type DeltaDetachedNodeId,
|
|
37
38
|
} from "../../core/index.js";
|
|
38
39
|
import {
|
|
40
|
+
assertNonNegativeSafeInteger,
|
|
39
41
|
brand,
|
|
40
42
|
getLast,
|
|
41
43
|
getOrAddEmptyToMap,
|
|
42
44
|
hasSome,
|
|
43
|
-
|
|
45
|
+
Breakable,
|
|
46
|
+
type WithBreakable,
|
|
44
47
|
} from "../../util/index.js";
|
|
45
48
|
|
|
46
49
|
import { BasicChunk, BasicChunkCursor, type SiblingsOrKey } from "./basicChunk.js";
|
|
@@ -57,8 +60,112 @@ function makeRoot(): BasicChunk {
|
|
|
57
60
|
return new BasicChunk(aboveRootPlaceholder, new Map());
|
|
58
61
|
}
|
|
59
62
|
|
|
63
|
+
/** Returns the number of top-level nodes represented by a field's chunks. */
|
|
64
|
+
function getFieldLength(field: readonly TreeChunk[]): number {
|
|
65
|
+
return field.reduce((length, chunk) => length + chunk.topLevelLength, 0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Locates a top-level node within a field's chunk representation.
|
|
70
|
+
* @param chunks - The chunks representing the field.
|
|
71
|
+
* @param index - The node index within the field.
|
|
72
|
+
* @returns The containing chunk, its array index, and the node's offset within it.
|
|
73
|
+
*/
|
|
74
|
+
export function locateNodeInChunks(
|
|
75
|
+
chunks: readonly TreeChunk[],
|
|
76
|
+
index: number,
|
|
77
|
+
): { chunk: TreeChunk; indexOfChunk: number; indexWithinChunk: number } {
|
|
78
|
+
assertNonNegativeSafeInteger(index);
|
|
79
|
+
// Remaining node offset while scanning chunks; afterward, the offset within the matched chunk.
|
|
80
|
+
let indexWithinChunk = index;
|
|
81
|
+
// Array index of the chunk currently being examined.
|
|
82
|
+
let indexOfChunk = 0;
|
|
83
|
+
while (true) {
|
|
84
|
+
const chunk = chunks[indexOfChunk] ?? oob();
|
|
85
|
+
if (indexWithinChunk < chunk.topLevelLength) {
|
|
86
|
+
return { chunk, indexOfChunk, indexWithinChunk };
|
|
87
|
+
}
|
|
88
|
+
indexWithinChunk -= chunk.topLevelLength;
|
|
89
|
+
indexOfChunk++;
|
|
90
|
+
if (indexOfChunk === chunks.length) {
|
|
91
|
+
fail(0xaf7 /* missing edited node */);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Ensures the node at index `index` within the field represented by `chunks` is contained in a non-shared {@link BasicChunk}.
|
|
98
|
+
*
|
|
99
|
+
* @param chunks - The chunks representing the field which will be modified to ensure the node at
|
|
100
|
+
* `index` is in a non-shared {@link BasicChunk}.
|
|
101
|
+
* @param index - The node index within the field.
|
|
102
|
+
* @returns The exclusively owned {@link BasicChunk} containing the node at `index`. This chunk is part of and owned by `chunks`.
|
|
103
|
+
* @remarks
|
|
104
|
+
* This function may modify the `chunks` array to ensure the node at `index` is in a non-shared {@link BasicChunk}.
|
|
105
|
+
* This can include splitting chunks, and cloning.
|
|
106
|
+
*/
|
|
107
|
+
export function ensureExclusiveBasicChunk(
|
|
108
|
+
chunks: TreeChunk[],
|
|
109
|
+
index: number,
|
|
110
|
+
compressor: ChunkCompressor,
|
|
111
|
+
): BasicChunk {
|
|
112
|
+
const { chunk, indexOfChunk, indexWithinChunk } = locateNodeInChunks(chunks, index);
|
|
113
|
+
|
|
114
|
+
// Normalize to a BasicChunk, splitting the chunk if needed.
|
|
115
|
+
let finalIndexOfChunk: number;
|
|
116
|
+
let basicChunk: BasicChunk;
|
|
117
|
+
if (chunk instanceof BasicChunk) {
|
|
118
|
+
basicChunk = chunk;
|
|
119
|
+
finalIndexOfChunk = indexOfChunk;
|
|
120
|
+
} else {
|
|
121
|
+
// TODO:Perf: support in place editing of other chunk formats when possible:
|
|
122
|
+
// 1. Support updating values in uniform chunks.
|
|
123
|
+
// 2. Support traversing sequence chunks.
|
|
124
|
+
//
|
|
125
|
+
// Maybe build path when visitor navigates then lazily sync to chunk tree when editing?
|
|
126
|
+
const newChunks = mapCursorField(chunk.cursor(), (cursor) =>
|
|
127
|
+
basicChunkTree(cursor, compressor),
|
|
128
|
+
);
|
|
129
|
+
// TODO: this could fail for really long chunks being split (due to argument count limits).
|
|
130
|
+
// Current implementations of chunks shouldn't ever be that long, but it could be an issue if they get bigger.
|
|
131
|
+
chunks.splice(indexOfChunk, 1, ...newChunks);
|
|
132
|
+
// We just overwrote the reference to the old chunk in the array, so drop the ref count for it.
|
|
133
|
+
chunk.referenceRemoved();
|
|
134
|
+
|
|
135
|
+
// Sanity check that the chunk indexing is as expected before updating it.
|
|
136
|
+
debugAssert(
|
|
137
|
+
() =>
|
|
138
|
+
newChunks[indexWithinChunk] === chunks[indexOfChunk + indexWithinChunk] ||
|
|
139
|
+
"bad chunk indexing",
|
|
140
|
+
);
|
|
141
|
+
basicChunk = newChunks[indexWithinChunk] ?? oob();
|
|
142
|
+
finalIndexOfChunk = indexOfChunk + indexWithinChunk;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
debugAssert(() => chunks[finalIndexOfChunk] === basicChunk || "bad child index");
|
|
146
|
+
|
|
147
|
+
// Ensure the BasicChunk we have is exclusively owned, so we can edit it in place.
|
|
148
|
+
let exclusiveChunk: BasicChunk;
|
|
149
|
+
if (basicChunk.isShared()) {
|
|
150
|
+
exclusiveChunk = chunks[finalIndexOfChunk] = basicChunk.clone();
|
|
151
|
+
basicChunk.referenceRemoved();
|
|
152
|
+
} else {
|
|
153
|
+
exclusiveChunk = basicChunk;
|
|
154
|
+
}
|
|
155
|
+
return exclusiveChunk;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Layer in the stack of basic chunks from traversing down the tree.
|
|
160
|
+
*/
|
|
60
161
|
interface StackNode {
|
|
162
|
+
/**
|
|
163
|
+
* The parent node.
|
|
164
|
+
*/
|
|
61
165
|
mutableChunk: BasicChunk;
|
|
166
|
+
/**
|
|
167
|
+
* A key under {@link mutableChunk} into which this stack traverses.
|
|
168
|
+
*/
|
|
62
169
|
key: FieldKey;
|
|
63
170
|
}
|
|
64
171
|
|
|
@@ -67,7 +174,7 @@ interface StackNode {
|
|
|
67
174
|
*
|
|
68
175
|
* This implementation focuses on performance.
|
|
69
176
|
*/
|
|
70
|
-
export class ChunkedForest implements IEditableForest {
|
|
177
|
+
export class ChunkedForest implements IEditableForest, WithBreakable {
|
|
71
178
|
private activeVisitor?: DeltaVisitor;
|
|
72
179
|
|
|
73
180
|
private readonly deltaVisitors: Set<() => AnnouncedVisitor> = new Set();
|
|
@@ -86,18 +193,29 @@ export class ChunkedForest implements IEditableForest {
|
|
|
86
193
|
public readonly chunker: IChunker,
|
|
87
194
|
public readonly anchors: AnchorSet = new AnchorSet(),
|
|
88
195
|
public readonly idCompressor?: IIdCompressor,
|
|
196
|
+
public readonly breaker: Breakable = new Breakable("ChunkedForest"),
|
|
89
197
|
) {}
|
|
90
198
|
|
|
91
199
|
public get isEmpty(): boolean {
|
|
200
|
+
this.breaker.use();
|
|
92
201
|
return this.roots.fields.size === 0;
|
|
93
202
|
}
|
|
94
203
|
|
|
95
|
-
public clone(schema: TreeStoredSchemaSubscription,
|
|
204
|
+
public clone(schema: TreeStoredSchemaSubscription, breaker?: Breakable): ChunkedForest {
|
|
205
|
+
this.breaker.use();
|
|
96
206
|
this.roots.referenceAdded();
|
|
97
|
-
return new ChunkedForest(
|
|
207
|
+
return new ChunkedForest(
|
|
208
|
+
this.roots,
|
|
209
|
+
schema,
|
|
210
|
+
this.chunker.clone(schema),
|
|
211
|
+
undefined,
|
|
212
|
+
this.idCompressor,
|
|
213
|
+
breaker ?? this.breaker,
|
|
214
|
+
);
|
|
98
215
|
}
|
|
99
216
|
|
|
100
217
|
public chunkField(cursor: ITreeCursorSynchronous): TreeChunk[] {
|
|
218
|
+
this.breaker.use();
|
|
101
219
|
return chunkField(cursor, { idCompressor: this.idCompressor, policy: this.chunker });
|
|
102
220
|
}
|
|
103
221
|
|
|
@@ -114,6 +232,7 @@ export class ChunkedForest implements IEditableForest {
|
|
|
114
232
|
}
|
|
115
233
|
|
|
116
234
|
public acquireVisitor(): DeltaVisitor {
|
|
235
|
+
this.breaker.use();
|
|
117
236
|
assert(
|
|
118
237
|
this.activeVisitor === undefined,
|
|
119
238
|
0x76a /* Must release existing visitor before acquiring another */,
|
|
@@ -123,11 +242,24 @@ export class ChunkedForest implements IEditableForest {
|
|
|
123
242
|
this.roots = this.roots.clone();
|
|
124
243
|
}
|
|
125
244
|
|
|
245
|
+
// The `CombinableVisitor` which can apply deltas to this forest.
|
|
246
|
+
// Annoyingly declaring the type here or in a satisfies clause causes this code not to build,
|
|
247
|
+
// so the type is inferred.
|
|
248
|
+
//
|
|
249
|
+
// This visitor works by shallow copying (where needed) the forest as it's walked down
|
|
250
|
+
// to ensure the location being traversed (and thus possibly edited) is an exclusively owned BasicChunk.
|
|
251
|
+
// Future optimizations may improve this, but currently that is a requirement for the editing code to work.
|
|
126
252
|
const forestVisitor = {
|
|
127
253
|
forest: this,
|
|
128
|
-
|
|
129
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Current location in the tree, as a non-shared BasicChunk (TODO: support in-place modification of other chunk formats when possible).
|
|
256
|
+
* Starts above root detached sequences.
|
|
257
|
+
*/
|
|
130
258
|
mutableChunkStack: [] as StackNode[],
|
|
259
|
+
/**
|
|
260
|
+
* When at a node level, this is set to the basic chunk for the current node.
|
|
261
|
+
* When at a field level, undefined, see mutableChunkStack for the field.
|
|
262
|
+
*/
|
|
131
263
|
mutableChunk: this.roots as BasicChunk | undefined,
|
|
132
264
|
getParent(): StackNode {
|
|
133
265
|
assert(hasSome(this.mutableChunkStack), 0x532 /* invalid access to root's parent */);
|
|
@@ -144,10 +276,23 @@ export class ChunkedForest implements IEditableForest {
|
|
|
144
276
|
},
|
|
145
277
|
destroy(detachedField: FieldKey, count: number): void {
|
|
146
278
|
this.forest.#events.emit("beforeChange");
|
|
279
|
+
const field = this.forest.roots.fields.get(detachedField);
|
|
280
|
+
assert(field !== undefined, 0xd1d /* Destroyed field must exist */);
|
|
281
|
+
assert(
|
|
282
|
+
getFieldLength(field) === count,
|
|
283
|
+
0xd1e /* Destroy count must match field length */,
|
|
284
|
+
);
|
|
147
285
|
this.forest.roots.fields.delete(detachedField);
|
|
286
|
+
for (const chunk of field) {
|
|
287
|
+
chunk.referenceRemoved();
|
|
288
|
+
}
|
|
148
289
|
},
|
|
149
290
|
create(content: readonly ITreeCursorSynchronous[], destination: FieldKey): void {
|
|
150
291
|
this.forest.#events.emit("beforeChange");
|
|
292
|
+
assert(
|
|
293
|
+
!this.forest.roots.fields.has(destination),
|
|
294
|
+
0xd1f /* Create destination must be a new empty field */,
|
|
295
|
+
);
|
|
151
296
|
const chunks: TreeChunk[] = content.map((c) =>
|
|
152
297
|
chunkTree(c, {
|
|
153
298
|
policy: this.forest.chunker,
|
|
@@ -171,18 +316,27 @@ export class ChunkedForest implements IEditableForest {
|
|
|
171
316
|
*/
|
|
172
317
|
attachEdit(source: FieldKey, count: number, destination: PlaceIndex): void {
|
|
173
318
|
this.forest.#events.emit("beforeChange");
|
|
174
|
-
const sourceField = this.forest.roots.fields.get(source) ?? [];
|
|
175
|
-
this.forest.roots.fields.delete(source);
|
|
176
|
-
if (sourceField.length === 0) {
|
|
177
|
-
return; // Prevent creating 0 sized fields when inserting empty into empty.
|
|
178
|
-
}
|
|
179
|
-
|
|
180
319
|
const parent = this.getParent();
|
|
320
|
+
assert(
|
|
321
|
+
parent.mutableChunk !== this.forest.roots || parent.key !== source,
|
|
322
|
+
0xd20 /* Attach source field must be different from current field */,
|
|
323
|
+
);
|
|
324
|
+
const sourceField = this.forest.roots.fields.get(source);
|
|
325
|
+
assert(sourceField !== undefined, 0xd21 /* Attach source field must exist */);
|
|
326
|
+
assert(
|
|
327
|
+
getFieldLength(sourceField) === count,
|
|
328
|
+
0xd22 /* Attach must consume all nodes in source field */,
|
|
329
|
+
);
|
|
181
330
|
const destinationField = getOrAddEmptyToMap(parent.mutableChunk.fields, parent.key);
|
|
331
|
+
assert(
|
|
332
|
+
destination <= getFieldLength(destinationField),
|
|
333
|
+
0xd23 /* Attach destination must not exceed field length */,
|
|
334
|
+
);
|
|
182
335
|
const destinationChunkIndex = splitFieldAtIndex(destinationField, destination, {
|
|
183
336
|
policy: this.forest.chunker,
|
|
184
337
|
idCompressor: this.forest.idCompressor,
|
|
185
338
|
});
|
|
339
|
+
this.forest.roots.fields.delete(source);
|
|
186
340
|
// TODO: this will fail for very large moves due to argument limits.
|
|
187
341
|
destinationField.splice(destinationChunkIndex, 0, ...sourceField);
|
|
188
342
|
},
|
|
@@ -203,7 +357,21 @@ export class ChunkedForest implements IEditableForest {
|
|
|
203
357
|
this.forest.#events.emit("beforeChange");
|
|
204
358
|
const parent = this.getParent();
|
|
205
359
|
const sourceField = parent.mutableChunk.fields.get(parent.key) ?? [];
|
|
206
|
-
assert(source.start <= source.end,
|
|
360
|
+
assert(source.start <= source.end, 0xd24 /* Detach range start must not exceed end */);
|
|
361
|
+
assert(
|
|
362
|
+
source.end <= getFieldLength(sourceField),
|
|
363
|
+
0xd25 /* Detach range must not exceed field length */,
|
|
364
|
+
);
|
|
365
|
+
if (destination !== undefined) {
|
|
366
|
+
assert(
|
|
367
|
+
parent.mutableChunk !== this.forest.roots || parent.key !== destination,
|
|
368
|
+
0xd26 /* Detach destination field must be different from current field */,
|
|
369
|
+
);
|
|
370
|
+
assert(
|
|
371
|
+
!this.forest.roots.fields.has(destination),
|
|
372
|
+
0xd27 /* Detach destination must be a new empty field */,
|
|
373
|
+
);
|
|
374
|
+
}
|
|
207
375
|
|
|
208
376
|
const policy: ChunkCompressor = {
|
|
209
377
|
policy: this.forest.chunker,
|
|
@@ -222,10 +390,6 @@ export class ChunkedForest implements IEditableForest {
|
|
|
222
390
|
child.referenceRemoved();
|
|
223
391
|
}
|
|
224
392
|
} else {
|
|
225
|
-
assert(
|
|
226
|
-
!this.forest.roots.fields.has(destination),
|
|
227
|
-
0x7af /* Destination must be a new empty detached field */,
|
|
228
|
-
);
|
|
229
393
|
if (newField.length > 0) {
|
|
230
394
|
this.forest.roots.fields.set(destination, newField);
|
|
231
395
|
}
|
|
@@ -236,49 +400,24 @@ export class ChunkedForest implements IEditableForest {
|
|
|
236
400
|
parent.mutableChunk.fields.delete(parent.key);
|
|
237
401
|
}
|
|
238
402
|
},
|
|
403
|
+
/**
|
|
404
|
+
* Ensure the selected node (by `index`) is an exclusively owned basic node,
|
|
405
|
+
* and store it under `this.mutableChunk`.
|
|
406
|
+
*/
|
|
239
407
|
enterNode(index: number): void {
|
|
240
408
|
assert(this.mutableChunk === undefined, 0x535 /* should be in field */);
|
|
409
|
+
|
|
410
|
+
// Get the mutable parent, which we might have to modify to ensure the desired child is an exclusively owned (and thus mutable) BasicChunk.
|
|
241
411
|
const parent = this.getParent();
|
|
412
|
+
|
|
413
|
+
// Lookup the current location of the node to be entered
|
|
242
414
|
const chunks =
|
|
243
415
|
parent.mutableChunk.fields.get(parent.key) ?? fail(0xaf6 /* missing edited field */);
|
|
244
|
-
let indexWithinChunk = index;
|
|
245
|
-
let indexOfChunk = 0;
|
|
246
|
-
let chunk = chunks[indexOfChunk] ?? oob();
|
|
247
|
-
while (indexWithinChunk >= chunk.topLevelLength) {
|
|
248
|
-
indexWithinChunk -= chunk.topLevelLength;
|
|
249
|
-
indexOfChunk++;
|
|
250
|
-
if (indexOfChunk === chunks.length) {
|
|
251
|
-
fail(0xaf7 /* missing edited node */);
|
|
252
|
-
}
|
|
253
|
-
chunk = chunks[indexOfChunk] ?? oob();
|
|
254
|
-
}
|
|
255
|
-
let found = chunks[indexOfChunk] ?? oob();
|
|
256
|
-
if (!(found instanceof BasicChunk)) {
|
|
257
|
-
// TODO:Perf: support in place editing of other chunk formats when possible:
|
|
258
|
-
// 1. Support updating values in uniform chunks.
|
|
259
|
-
// 2. Support traversing sequence chunks.
|
|
260
|
-
//
|
|
261
|
-
// Maybe build path when visitor navigates then lazily sync to chunk tree when editing?
|
|
262
|
-
const newChunks = mapCursorField(found.cursor(), (cursor) =>
|
|
263
|
-
basicChunkTree(cursor, {
|
|
264
|
-
policy: this.forest.chunker,
|
|
265
|
-
idCompressor: this.forest.idCompressor,
|
|
266
|
-
}),
|
|
267
|
-
);
|
|
268
|
-
// TODO: this could fail for really long chunks being split (due to argument count limits).
|
|
269
|
-
// Current implementations of chunks shouldn't ever be that long, but it could be an issue if they get bigger.
|
|
270
|
-
chunks.splice(indexOfChunk, 1, ...newChunks);
|
|
271
|
-
found.referenceRemoved();
|
|
272
416
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
this.mutableChunk = chunks[indexOfChunk] = found.clone();
|
|
278
|
-
found.referenceRemoved();
|
|
279
|
-
} else {
|
|
280
|
-
this.mutableChunk = found;
|
|
281
|
-
}
|
|
417
|
+
this.mutableChunk = ensureExclusiveBasicChunk(chunks, index, {
|
|
418
|
+
policy: this.forest.chunker,
|
|
419
|
+
idCompressor: this.forest.idCompressor,
|
|
420
|
+
});
|
|
282
421
|
},
|
|
283
422
|
exitNode(index: number): void {
|
|
284
423
|
assert(this.mutableChunk !== undefined, 0x537 /* should be in node */);
|
|
@@ -300,9 +439,12 @@ export class ChunkedForest implements IEditableForest {
|
|
|
300
439
|
for (const getVisitor of this.deltaVisitors) {
|
|
301
440
|
announcedVisitors.push(getVisitor());
|
|
302
441
|
}
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
442
|
+
const visitor = combineVisitors([
|
|
443
|
+
makeBreakingVisitor(forestVisitor, this.breaker),
|
|
444
|
+
...announcedVisitors,
|
|
445
|
+
]);
|
|
446
|
+
this.activeVisitor = visitor;
|
|
447
|
+
return visitor;
|
|
306
448
|
}
|
|
307
449
|
|
|
308
450
|
private nextDetachedFieldIdentifier = 0;
|
|
@@ -317,6 +459,7 @@ export class ChunkedForest implements IEditableForest {
|
|
|
317
459
|
}
|
|
318
460
|
|
|
319
461
|
public allocateCursor(): Cursor {
|
|
462
|
+
this.breaker.use();
|
|
320
463
|
return new Cursor(
|
|
321
464
|
this,
|
|
322
465
|
ITreeSubscriptionCursorState.Cleared,
|
|
@@ -337,6 +480,7 @@ export class ChunkedForest implements IEditableForest {
|
|
|
337
480
|
destination: Anchor,
|
|
338
481
|
cursorToMove: ITreeSubscriptionCursor,
|
|
339
482
|
): TreeNavigationResult {
|
|
483
|
+
this.breaker.use();
|
|
340
484
|
const path = this.anchors.locate(destination);
|
|
341
485
|
if (path === undefined) {
|
|
342
486
|
return TreeNavigationResult.NotFound;
|
|
@@ -349,6 +493,7 @@ export class ChunkedForest implements IEditableForest {
|
|
|
349
493
|
destination: FieldAnchor,
|
|
350
494
|
cursorToMove: ITreeSubscriptionCursor,
|
|
351
495
|
): TreeNavigationResult {
|
|
496
|
+
this.breaker.use();
|
|
352
497
|
assert(
|
|
353
498
|
cursorToMove instanceof Cursor,
|
|
354
499
|
0x53b /* ChunkedForest must only be given its own Cursor type */,
|
|
@@ -367,6 +512,7 @@ export class ChunkedForest implements IEditableForest {
|
|
|
367
512
|
}
|
|
368
513
|
|
|
369
514
|
public moveCursorToPath(destination: UpPath, cursorToMove: ITreeSubscriptionCursor): void {
|
|
515
|
+
this.breaker.use();
|
|
370
516
|
assert(
|
|
371
517
|
cursorToMove instanceof Cursor,
|
|
372
518
|
0x53c /* ChunkedForest must only be given its own Cursor type */,
|
|
@@ -402,6 +548,7 @@ export class ChunkedForest implements IEditableForest {
|
|
|
402
548
|
}
|
|
403
549
|
|
|
404
550
|
public getCursorAboveDetachedFields(): ITreeCursorSynchronous {
|
|
551
|
+
this.breaker.use();
|
|
405
552
|
const rootCursor = this.roots.cursor();
|
|
406
553
|
rootCursor.enterNode(0);
|
|
407
554
|
return rootCursor;
|
|
@@ -497,6 +644,14 @@ export function buildChunkedForest(
|
|
|
497
644
|
chunker: IChunker,
|
|
498
645
|
anchors?: AnchorSet,
|
|
499
646
|
idCompressor?: IIdCompressor,
|
|
647
|
+
breaker?: Breakable,
|
|
500
648
|
): ChunkedForest {
|
|
501
|
-
return new ChunkedForest(
|
|
649
|
+
return new ChunkedForest(
|
|
650
|
+
makeRoot(),
|
|
651
|
+
chunker.schema,
|
|
652
|
+
chunker,
|
|
653
|
+
anchors,
|
|
654
|
+
idCompressor,
|
|
655
|
+
breaker,
|
|
656
|
+
);
|
|
502
657
|
}
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
combineVisitors,
|
|
23
23
|
createAnnouncedVisitor,
|
|
24
24
|
} from "../../core/index.js";
|
|
25
|
-
import type
|
|
25
|
+
import { breakingMethod, type Breakable } from "../../util/index.js";
|
|
26
26
|
|
|
27
27
|
import { assertForestsEqual } from "../treeTextCursor.js";
|
|
28
28
|
|
|
@@ -57,6 +57,7 @@ export class ComparisonForest implements IEditableForest {
|
|
|
57
57
|
this.assertValid();
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
@breakingMethod
|
|
60
61
|
private assertValid(): void {
|
|
61
62
|
assertForestsEqual(this.main, this.reference);
|
|
62
63
|
}
|
|
@@ -73,6 +74,10 @@ export class ComparisonForest implements IEditableForest {
|
|
|
73
74
|
return this.main.isEmpty;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
public get breaker(): Breakable {
|
|
78
|
+
return this.main.breaker;
|
|
79
|
+
}
|
|
80
|
+
|
|
76
81
|
public clone(schema: TreeStoredSchemaSubscription, breaker?: Breakable): ComparisonForest {
|
|
77
82
|
this.assertValid();
|
|
78
83
|
return new ComparisonForest(
|
|
@@ -9,7 +9,7 @@ import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
|
9
9
|
import type {
|
|
10
10
|
IExperimentalIncrementalSummaryContext,
|
|
11
11
|
ITelemetryContext,
|
|
12
|
-
|
|
12
|
+
OldestSupportedClientVersion,
|
|
13
13
|
} from "@fluidframework/runtime-definitions/internal";
|
|
14
14
|
import type { SummaryTreeBuilder } from "@fluidframework/runtime-utils/internal";
|
|
15
15
|
|
|
@@ -65,7 +65,7 @@ const supportedVersions = new Set<DetachedFieldIndexSummaryFormatVersion>([
|
|
|
65
65
|
* Returns the summary version to use as per the given minimum version for collab.
|
|
66
66
|
*/
|
|
67
67
|
function minVersionToDetachedFieldIndexSummaryFormatVersion(
|
|
68
|
-
version:
|
|
68
|
+
version: OldestSupportedClientVersion,
|
|
69
69
|
): DetachedFieldIndexSummaryFormatVersion {
|
|
70
70
|
// Currently, version 2 is written which adds metadata blob to the summary.
|
|
71
71
|
return DetachedFieldIndexSummaryFormatVersion.v2;
|
|
@@ -32,8 +32,10 @@ import {
|
|
|
32
32
|
type SummaryElementStringifier,
|
|
33
33
|
} from "../../shared-tree-core/index.js";
|
|
34
34
|
import {
|
|
35
|
+
breakingMethod,
|
|
35
36
|
idAllocatorFromMaxId,
|
|
36
37
|
readAndParseSnapshotBlob,
|
|
38
|
+
type Breakable,
|
|
37
39
|
type JsonCompatibleReadOnly,
|
|
38
40
|
} from "../../util/index.js";
|
|
39
41
|
// eslint-disable-next-line import-x/no-internal-modules
|
|
@@ -70,6 +72,13 @@ export class ForestSummarizer
|
|
|
70
72
|
{
|
|
71
73
|
private readonly codec: ForestCodec;
|
|
72
74
|
|
|
75
|
+
/**
|
|
76
|
+
* This object is broken if and only if the forest it owns is broken.
|
|
77
|
+
*/
|
|
78
|
+
public get breaker(): Breakable {
|
|
79
|
+
return this.forest.breaker;
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
private readonly incrementalSummaryBuilder: ForestIncrementalSummaryBuilder;
|
|
74
83
|
private readonly forestRootSummaryContentKey: string;
|
|
75
84
|
|
|
@@ -178,6 +187,7 @@ export class ForestSummarizer
|
|
|
178
187
|
});
|
|
179
188
|
}
|
|
180
189
|
|
|
190
|
+
@breakingMethod
|
|
181
191
|
protected async loadInternal(
|
|
182
192
|
services: IChannelStorageService,
|
|
183
193
|
parse: SummaryElementParser,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type { OldestSupportedClientVersion } from "@fluidframework/runtime-definitions/internal";
|
|
7
7
|
import {
|
|
8
8
|
getConfigForMinVersionForCollab,
|
|
9
9
|
lowestMinVersionForCollab,
|
|
@@ -19,7 +19,7 @@ import { summaryContentBlobKey as summaryContentBlobKeyV3 } from "./summaryForma
|
|
|
19
19
|
* Returns the summary format version to use as per the given minimum version for collab.
|
|
20
20
|
*/
|
|
21
21
|
export function minVersionToForestSummaryFormatVersion(
|
|
22
|
-
version:
|
|
22
|
+
version: OldestSupportedClientVersion,
|
|
23
23
|
): ForestSummaryFormatVersion {
|
|
24
24
|
return getConfigForMinVersionForCollab(version, {
|
|
25
25
|
[lowestMinVersionForCollab]: ForestSummaryFormatVersion.v2,
|
|
@@ -329,7 +329,7 @@ export class AnchorTreeIndex<TKey, TValue> implements TreeIndex<TKey, TValue> {
|
|
|
329
329
|
if (errorMessage !== undefined) {
|
|
330
330
|
throw new Error(errorMessage);
|
|
331
331
|
}
|
|
332
|
-
|
|
332
|
+
fail(0xa8f /* invalid operation on a disposed index */);
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
335
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { assert } from "@fluidframework/core-utils/internal";
|
|
6
|
+
import { assert, fail } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import {
|
|
8
8
|
revisionMetadataSourceFromInfo,
|
|
9
9
|
type ChangeAtomId,
|
|
@@ -289,7 +289,7 @@ class InvertManager extends CrossFieldManagerI<FieldChange> {
|
|
|
289
289
|
id: ChangesetLocalId,
|
|
290
290
|
count: number,
|
|
291
291
|
): void {
|
|
292
|
-
|
|
292
|
+
fail(0x9c5 /* Keys should not be moved manually during invert */);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
private get table(): InvertTable {
|
|
@@ -1673,30 +1673,9 @@ export function updateRefreshers(
|
|
|
1673
1673
|
}
|
|
1674
1674
|
}
|
|
1675
1675
|
|
|
1676
|
-
const {
|
|
1677
|
-
fieldChanges,
|
|
1678
|
-
nodeChanges,
|
|
1679
|
-
nodeToParent,
|
|
1680
|
-
nodeAliases,
|
|
1681
|
-
crossFieldKeys,
|
|
1682
|
-
maxId,
|
|
1683
|
-
revisions,
|
|
1684
|
-
constraintViolationCount,
|
|
1685
|
-
builds,
|
|
1686
|
-
destroys,
|
|
1687
|
-
} = change;
|
|
1688
|
-
|
|
1689
1676
|
return makeModularChangeset({
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
nodeToParent,
|
|
1693
|
-
nodeAliases,
|
|
1694
|
-
crossFieldKeys,
|
|
1695
|
-
maxId: maxId as number,
|
|
1696
|
-
revisions,
|
|
1697
|
-
constraintViolationCount,
|
|
1698
|
-
builds,
|
|
1699
|
-
destroys,
|
|
1677
|
+
...change,
|
|
1678
|
+
maxId: change.maxId,
|
|
1700
1679
|
refreshers,
|
|
1701
1680
|
});
|
|
1702
1681
|
}
|