@fluidframework/tree 2.74.0 → 2.81.0-374083
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 +18 -0
- package/api-report/tree.alpha.api.md +63 -9
- package/dist/alpha.d.ts +9 -0
- package/dist/codec/codec.d.ts +31 -3
- package/dist/codec/codec.d.ts.map +1 -1
- package/dist/codec/codec.js +10 -0
- package/dist/codec/codec.js.map +1 -1
- package/dist/codec/index.d.ts +2 -2
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/codec/index.js +2 -2
- package/dist/codec/index.js.map +1 -1
- package/dist/codec/versioned/codec.d.ts +80 -22
- package/dist/codec/versioned/codec.d.ts.map +1 -1
- package/dist/codec/versioned/codec.js +137 -15
- package/dist/codec/versioned/codec.js.map +1 -1
- package/dist/codec/versioned/index.d.ts +1 -1
- package/dist/codec/versioned/index.d.ts.map +1 -1
- package/dist/codec/versioned/index.js +2 -2
- package/dist/codec/versioned/index.js.map +1 -1
- package/dist/core/change-family/changeFamily.d.ts +4 -1
- package/dist/core/change-family/changeFamily.d.ts.map +1 -1
- package/dist/core/change-family/changeFamily.js.map +1 -1
- package/dist/core/change-family/index.d.ts +1 -1
- package/dist/core/change-family/index.d.ts.map +1 -1
- package/dist/core/change-family/index.js.map +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -6
- package/dist/core/index.js.map +1 -1
- package/dist/core/rebase/changeRebaser.d.ts +42 -3
- package/dist/core/rebase/changeRebaser.d.ts.map +1 -1
- package/dist/core/rebase/changeRebaser.js.map +1 -1
- package/dist/core/rebase/index.d.ts +2 -2
- package/dist/core/rebase/index.d.ts.map +1 -1
- package/dist/core/rebase/index.js +2 -2
- package/dist/core/rebase/index.js.map +1 -1
- package/dist/core/rebase/types.d.ts +52 -10
- package/dist/core/rebase/types.d.ts.map +1 -1
- package/dist/core/rebase/types.js +5 -12
- package/dist/core/rebase/types.js.map +1 -1
- package/dist/core/rebase/utils.d.ts.map +1 -1
- package/dist/core/rebase/utils.js +33 -11
- package/dist/core/rebase/utils.js.map +1 -1
- package/dist/core/schema-stored/schema.js +3 -3
- package/dist/core/schema-stored/schema.js.map +1 -1
- package/dist/core/tree/anchorSet.d.ts.map +1 -1
- package/dist/core/tree/anchorSet.js +4 -4
- package/dist/core/tree/anchorSet.js.map +1 -1
- package/dist/core/tree/detachedFieldIndex.d.ts +7 -2
- package/dist/core/tree/detachedFieldIndex.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndex.js +21 -56
- package/dist/core/tree/detachedFieldIndex.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecCommon.d.ts +18 -10
- package/dist/core/tree/detachedFieldIndexCodecCommon.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecCommon.js +6 -6
- package/dist/core/tree/detachedFieldIndexCodecCommon.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV1.d.ts +2 -3
- package/dist/core/tree/detachedFieldIndexCodecV1.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV1.js +4 -5
- package/dist/core/tree/detachedFieldIndexCodecV1.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV2.d.ts +2 -3
- package/dist/core/tree/detachedFieldIndexCodecV2.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV2.js +4 -6
- package/dist/core/tree/detachedFieldIndexCodecV2.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecs.d.ts +5 -6
- package/dist/core/tree/detachedFieldIndexCodecs.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecs.js +11 -41
- package/dist/core/tree/detachedFieldIndexCodecs.js.map +1 -1
- package/dist/core/tree/index.d.ts +2 -2
- package/dist/core/tree/index.d.ts.map +1 -1
- package/dist/core/tree/index.js +5 -4
- package/dist/core/tree/index.js.map +1 -1
- package/dist/core/tree/mapTree.js +1 -1
- package/dist/core/tree/mapTree.js.map +1 -1
- package/dist/core/tree/pathTree.d.ts +11 -3
- package/dist/core/tree/pathTree.d.ts.map +1 -1
- package/dist/core/tree/pathTree.js +14 -2
- package/dist/core/tree/pathTree.js.map +1 -1
- package/dist/core/tree/sparseTree.d.ts.map +1 -1
- package/dist/core/tree/sparseTree.js +1 -0
- package/dist/core/tree/sparseTree.js.map +1 -1
- package/dist/core/tree/treeTextFormat.d.ts.map +1 -1
- package/dist/core/tree/treeTextFormat.js +5 -9
- package/dist/core/tree/treeTextFormat.js.map +1 -1
- package/dist/core/tree/visitDelta.d.ts.map +1 -1
- package/dist/core/tree/visitDelta.js +3 -2
- package/dist/core/tree/visitDelta.js.map +1 -1
- package/dist/core/tree/visitorUtils.d.ts.map +1 -1
- package/dist/core/tree/visitorUtils.js +58 -18
- package/dist/core/tree/visitorUtils.js.map +1 -1
- package/dist/feature-libraries/changeAtomIdBTree.d.ts +16 -0
- package/dist/feature-libraries/changeAtomIdBTree.d.ts.map +1 -0
- package/dist/feature-libraries/changeAtomIdBTree.js +30 -0
- package/dist/feature-libraries/changeAtomIdBTree.js.map +1 -0
- package/dist/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/basicChunk.js +8 -1
- package/dist/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.js +4 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.js +9 -7
- package/dist/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.js +7 -4
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/codecs.js +19 -11
- package/dist/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/compressedEncode.js +4 -3
- package/dist/feature-libraries/chunked-forest/codec/compressedEncode.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/schemaBasedEncode.js +9 -5
- package/dist/feature-libraries/chunked-forest/codec/schemaBasedEncode.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/uniformChunk.js +1 -1
- package/dist/feature-libraries/chunked-forest/uniformChunk.js.map +1 -1
- package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts +103 -44
- package/dist/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
- package/dist/feature-libraries/default-schema/defaultEditBuilder.js +251 -77
- package/dist/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
- package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts +1 -1
- package/dist/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
- package/dist/feature-libraries/default-schema/defaultFieldKinds.js +22 -3
- package/dist/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
- package/dist/feature-libraries/default-schema/index.d.ts +2 -1
- package/dist/feature-libraries/default-schema/index.d.ts.map +1 -1
- package/dist/feature-libraries/default-schema/index.js +5 -2
- package/dist/feature-libraries/default-schema/index.js.map +1 -1
- package/dist/feature-libraries/default-schema/locationBasedEditBuilder.d.ts +38 -0
- package/dist/feature-libraries/default-schema/locationBasedEditBuilder.d.ts.map +1 -0
- package/dist/feature-libraries/default-schema/locationBasedEditBuilder.js +132 -0
- package/dist/feature-libraries/default-schema/locationBasedEditBuilder.js.map +1 -0
- package/dist/feature-libraries/default-schema/mappedEditBuilder.d.ts +9 -6
- package/dist/feature-libraries/default-schema/mappedEditBuilder.d.ts.map +1 -1
- package/dist/feature-libraries/default-schema/mappedEditBuilder.js +21 -0
- package/dist/feature-libraries/default-schema/mappedEditBuilder.js.map +1 -1
- package/dist/feature-libraries/deltaUtils.d.ts +1 -0
- package/dist/feature-libraries/deltaUtils.d.ts.map +1 -1
- package/dist/feature-libraries/deltaUtils.js +6 -1
- package/dist/feature-libraries/deltaUtils.js.map +1 -1
- package/dist/feature-libraries/flex-tree/context.d.ts +9 -0
- package/dist/feature-libraries/flex-tree/context.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/context.js +6 -0
- package/dist/feature-libraries/flex-tree/context.js.map +1 -1
- package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +6 -6
- 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/lazyField.d.ts +8 -7
- package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/lazyField.js +44 -15
- package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
- package/dist/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
- package/dist/feature-libraries/forest-summary/forestSummarizer.js +3 -1
- package/dist/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
- package/dist/feature-libraries/index.d.ts +5 -4
- package/dist/feature-libraries/index.d.ts.map +1 -1
- package/dist/feature-libraries/index.js +15 -8
- package/dist/feature-libraries/index.js.map +1 -1
- package/dist/feature-libraries/indexing/anchorTreeIndex.js +6 -6
- package/dist/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
- package/dist/feature-libraries/mapTreeCursor.d.ts.map +1 -1
- package/dist/feature-libraries/mapTreeCursor.js +1 -0
- package/dist/feature-libraries/mapTreeCursor.js.map +1 -1
- package/dist/feature-libraries/mitigatedChangeFamily.d.ts.map +1 -1
- package/dist/feature-libraries/mitigatedChangeFamily.js +12 -3
- package/dist/feature-libraries/mitigatedChangeFamily.js.map +1 -1
- package/dist/feature-libraries/modular-schema/comparison.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/comparison.js +12 -9
- package/dist/feature-libraries/modular-schema/comparison.js.map +1 -1
- package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts +97 -21
- package/dist/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/crossFieldQueries.js +4 -7
- package/dist/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
- package/dist/feature-libraries/modular-schema/defaultRevisionReplacer.d.ts +25 -0
- package/dist/feature-libraries/modular-schema/defaultRevisionReplacer.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/defaultRevisionReplacer.js +59 -0
- package/dist/feature-libraries/modular-schema/defaultRevisionReplacer.js.map +1 -0
- package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts +22 -53
- package/dist/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
- package/dist/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/genericFieldKind.js +7 -13
- package/dist/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
- package/dist/feature-libraries/modular-schema/genericFieldKindCodecs.js +2 -2
- package/dist/feature-libraries/modular-schema/genericFieldKindCodecs.js.map +1 -1
- package/dist/feature-libraries/modular-schema/index.d.ts +7 -5
- package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/index.js +12 -8
- package/dist/feature-libraries/modular-schema/index.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeCodecV1.d.ts +32 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV1.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV1.js +409 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV1.js.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV2.d.ts +15 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV2.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV2.js +31 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV2.js.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV3.d.ts +15 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV3.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV3.js +393 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecV3.js.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts +2 -2
- package/dist/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +32 -288
- package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts +60 -26
- package/dist/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeFamily.js +1519 -615
- package/dist/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
- package/{lib/feature-libraries/modular-schema/modularChangeFormat.d.ts → dist/feature-libraries/modular-schema/modularChangeFormatV1.d.ts} +5 -6
- package/dist/feature-libraries/modular-schema/modularChangeFormatV1.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/{modularChangeFormat.js → modularChangeFormatV1.js} +7 -7
- package/dist/feature-libraries/modular-schema/modularChangeFormatV1.js.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV2.d.ts +112 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV2.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV2.js +21 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV2.js.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV3.d.ts +146 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV3.d.ts.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV3.js +32 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormatV3.js.map +1 -0
- package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +59 -13
- package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeTypes.js +3 -3
- package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
- package/dist/feature-libraries/node-identifier/mockNodeIdentifierManager.js +1 -1
- package/dist/feature-libraries/node-identifier/mockNodeIdentifierManager.js.map +1 -1
- package/dist/feature-libraries/object-forest/objectForest.d.ts.map +1 -1
- package/dist/feature-libraries/object-forest/objectForest.js +7 -5
- package/dist/feature-libraries/object-forest/objectForest.js.map +1 -1
- package/dist/feature-libraries/optional-field/index.d.ts +2 -2
- package/dist/feature-libraries/optional-field/index.d.ts.map +1 -1
- package/dist/feature-libraries/optional-field/index.js +1 -2
- package/dist/feature-libraries/optional-field/index.js.map +1 -1
- package/dist/feature-libraries/optional-field/optionalField.d.ts +5 -26
- package/dist/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
- package/dist/feature-libraries/optional-field/optionalField.js +223 -450
- package/dist/feature-libraries/optional-field/optionalField.js.map +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts +23 -0
- package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts.map +1 -0
- package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.js +31 -0
- package/dist/feature-libraries/optional-field/optionalFieldChangeFormatV3.js.map +1 -0
- package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts +24 -33
- package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts.map +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldChangeTypes.js.map +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldCodecV2.d.ts +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldCodecV2.d.ts.map +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldCodecV2.js +57 -28
- package/dist/feature-libraries/optional-field/optionalFieldCodecV2.js.map +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldCodecV3.d.ts +12 -0
- package/dist/feature-libraries/optional-field/optionalFieldCodecV3.d.ts.map +1 -0
- package/dist/feature-libraries/optional-field/optionalFieldCodecV3.js +57 -0
- package/dist/feature-libraries/optional-field/optionalFieldCodecV3.js.map +1 -0
- package/dist/feature-libraries/optional-field/optionalFieldCodecs.d.ts.map +1 -1
- package/dist/feature-libraries/optional-field/optionalFieldCodecs.js +5 -1
- package/dist/feature-libraries/optional-field/optionalFieldCodecs.js.map +1 -1
- package/dist/feature-libraries/schema-edits/schemaChangeCodecs.d.ts.map +1 -1
- package/dist/feature-libraries/schema-edits/schemaChangeCodecs.js +14 -2
- package/dist/feature-libraries/schema-edits/schemaChangeCodecs.js.map +1 -1
- package/dist/feature-libraries/schema-index/codec.d.ts +7 -21
- package/dist/feature-libraries/schema-index/codec.d.ts.map +1 -1
- package/dist/feature-libraries/schema-index/codec.js +28 -70
- package/dist/feature-libraries/schema-index/codec.js.map +1 -1
- package/dist/feature-libraries/schema-index/index.d.ts +2 -2
- package/dist/feature-libraries/schema-index/index.d.ts.map +1 -1
- package/dist/feature-libraries/schema-index/index.js +2 -5
- package/dist/feature-libraries/schema-index/index.js.map +1 -1
- package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts +1 -9
- package/dist/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
- package/dist/feature-libraries/schema-index/schemaSummarizer.js +1 -12
- package/dist/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
- package/dist/feature-libraries/schemaChecker.d.ts.map +1 -1
- package/dist/feature-libraries/schemaChecker.js +11 -6
- package/dist/feature-libraries/schemaChecker.js.map +1 -1
- package/dist/feature-libraries/sequence-field/compose.d.ts +6 -7
- package/dist/feature-libraries/sequence-field/compose.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/compose.js +91 -263
- package/dist/feature-libraries/sequence-field/compose.js.map +1 -1
- package/dist/feature-libraries/sequence-field/helperTypes.d.ts +14 -10
- package/dist/feature-libraries/sequence-field/helperTypes.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/helperTypes.js.map +1 -1
- package/dist/feature-libraries/sequence-field/index.d.ts +2 -3
- package/dist/feature-libraries/sequence-field/index.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/index.js +1 -3
- package/dist/feature-libraries/sequence-field/index.js.map +1 -1
- package/dist/feature-libraries/sequence-field/invert.d.ts +3 -3
- package/dist/feature-libraries/sequence-field/invert.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/invert.js +67 -168
- package/dist/feature-libraries/sequence-field/invert.js.map +1 -1
- package/dist/feature-libraries/sequence-field/markQueue.d.ts +2 -2
- package/dist/feature-libraries/sequence-field/markQueue.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/markQueue.js.map +1 -1
- package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts +4 -56
- package/dist/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/moveEffectTable.js +10 -87
- package/dist/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
- package/dist/feature-libraries/sequence-field/rebase.d.ts +3 -3
- package/dist/feature-libraries/sequence-field/rebase.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/rebase.js +120 -119
- package/dist/feature-libraries/sequence-field/rebase.js.map +1 -1
- package/dist/feature-libraries/sequence-field/replaceRevisions.d.ts +2 -2
- package/dist/feature-libraries/sequence-field/replaceRevisions.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/replaceRevisions.js +35 -43
- package/dist/feature-libraries/sequence-field/replaceRevisions.js.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +0 -2
- package/dist/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +22 -4
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js +365 -179
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js +20 -60
- package/dist/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldEditor.d.ts +2 -2
- package/dist/feature-libraries/sequence-field/sequenceFieldEditor.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldEditor.js +10 -10
- package/dist/feature-libraries/sequence-field/sequenceFieldEditor.js.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +3 -2
- package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js +20 -112
- package/dist/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
- package/dist/feature-libraries/sequence-field/types.d.ts +30 -59
- package/dist/feature-libraries/sequence-field/types.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/types.js.map +1 -1
- package/dist/feature-libraries/sequence-field/utils.d.ts +15 -24
- package/dist/feature-libraries/sequence-field/utils.d.ts.map +1 -1
- package/dist/feature-libraries/sequence-field/utils.js +148 -318
- package/dist/feature-libraries/sequence-field/utils.js.map +1 -1
- package/dist/feature-libraries/treeCursorUtils.js +7 -7
- package/dist/feature-libraries/treeCursorUtils.js.map +1 -1
- package/dist/feature-libraries/treeTextCursor.js +2 -2
- package/dist/feature-libraries/treeTextCursor.js.map +1 -1
- package/dist/feature-libraries/valueUtilities.d.ts.map +1 -1
- package/dist/feature-libraries/valueUtilities.js +16 -8
- package/dist/feature-libraries/valueUtilities.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/shared-tree/index.d.ts +1 -1
- package/dist/shared-tree/index.d.ts.map +1 -1
- package/dist/shared-tree/index.js.map +1 -1
- package/dist/shared-tree/schematizeTree.d.ts +4 -4
- package/dist/shared-tree/schematizeTree.d.ts.map +1 -1
- package/dist/shared-tree/schematizeTree.js +2 -1
- package/dist/shared-tree/schematizeTree.js.map +1 -1
- package/dist/shared-tree/schematizingTreeView.d.ts +3 -8
- package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
- package/dist/shared-tree/schematizingTreeView.js +58 -44
- package/dist/shared-tree/schematizingTreeView.js.map +1 -1
- package/dist/shared-tree/sharedTree.d.ts +9 -3
- package/dist/shared-tree/sharedTree.d.ts.map +1 -1
- package/dist/shared-tree/sharedTree.js +72 -44
- package/dist/shared-tree/sharedTree.js.map +1 -1
- package/dist/shared-tree/sharedTreeChangeCodecs.d.ts +1 -1
- package/dist/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
- package/dist/shared-tree/sharedTreeChangeCodecs.js +10 -8
- package/dist/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
- package/dist/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
- package/dist/shared-tree/sharedTreeChangeEnricher.js +5 -3
- package/dist/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
- package/dist/shared-tree/sharedTreeChangeFamily.d.ts +7 -6
- package/dist/shared-tree/sharedTreeChangeFamily.d.ts.map +1 -1
- package/dist/shared-tree/sharedTreeChangeFamily.js +29 -18
- package/dist/shared-tree/sharedTreeChangeFamily.js.map +1 -1
- package/dist/shared-tree/sharedTreeEditBuilder.d.ts +16 -6
- package/dist/shared-tree/sharedTreeEditBuilder.d.ts.map +1 -1
- package/dist/shared-tree/sharedTreeEditBuilder.js +14 -7
- package/dist/shared-tree/sharedTreeEditBuilder.js.map +1 -1
- package/dist/shared-tree/treeAlpha.d.ts +35 -29
- package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
- package/dist/shared-tree/treeAlpha.js +21 -23
- package/dist/shared-tree/treeAlpha.js.map +1 -1
- package/dist/shared-tree/treeCheckout.d.ts +11 -10
- package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
- package/dist/shared-tree/treeCheckout.js +93 -25
- package/dist/shared-tree/treeCheckout.js.map +1 -1
- package/dist/shared-tree-core/branch.d.ts +6 -3
- package/dist/shared-tree-core/branch.d.ts.map +1 -1
- package/dist/shared-tree-core/branch.js +13 -6
- package/dist/shared-tree-core/branch.js.map +1 -1
- package/dist/shared-tree-core/branchCommitEnricher.d.ts.map +1 -1
- package/dist/shared-tree-core/branchCommitEnricher.js +1 -1
- package/dist/shared-tree-core/branchCommitEnricher.js.map +1 -1
- package/dist/shared-tree-core/editManager.d.ts +2 -2
- package/dist/shared-tree-core/editManager.d.ts.map +1 -1
- package/dist/shared-tree-core/editManager.js +21 -15
- package/dist/shared-tree-core/editManager.js.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.d.ts +4 -0
- package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.js +18 -5
- package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/dist/shared-tree-core/editManagerFormatCommons.d.ts +2 -0
- package/dist/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerFormatCommons.js +12 -0
- package/dist/shared-tree-core/editManagerFormatCommons.js.map +1 -1
- package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts +2 -2
- package/dist/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerFormatV1toV4.js +2 -0
- package/dist/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
- package/dist/shared-tree-core/editManagerSummarizer.js +3 -3
- package/dist/shared-tree-core/editManagerSummarizer.js.map +1 -1
- package/dist/shared-tree-core/index.d.ts +2 -2
- package/dist/shared-tree-core/index.d.ts.map +1 -1
- package/dist/shared-tree-core/index.js +3 -1
- package/dist/shared-tree-core/index.js.map +1 -1
- package/dist/shared-tree-core/messageCodecV1ToV4.d.ts +1 -1
- package/dist/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
- package/dist/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
- package/dist/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -1
- package/dist/shared-tree-core/messageCodecVSharedBranches.js +2 -1
- package/dist/shared-tree-core/messageCodecVSharedBranches.js.map +1 -1
- package/dist/shared-tree-core/messageCodecs.d.ts +4 -0
- package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/messageCodecs.js +17 -5
- package/dist/shared-tree-core/messageCodecs.js.map +1 -1
- package/dist/shared-tree-core/messageFormat.d.ts +2 -0
- package/dist/shared-tree-core/messageFormat.d.ts.map +1 -1
- package/dist/shared-tree-core/messageFormat.js +12 -0
- package/dist/shared-tree-core/messageFormat.js.map +1 -1
- package/dist/shared-tree-core/messageFormatV1ToV4.d.ts +3 -2
- package/dist/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
- package/dist/shared-tree-core/messageFormatV1ToV4.js +9 -1
- package/dist/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
- package/dist/shared-tree-core/sequenceIdUtils.d.ts.map +1 -1
- package/dist/shared-tree-core/sequenceIdUtils.js +4 -4
- package/dist/shared-tree-core/sequenceIdUtils.js.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.d.ts +1 -0
- package/dist/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.js +13 -9
- package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/dist/shared-tree-core/transaction.d.ts +25 -8
- package/dist/shared-tree-core/transaction.d.ts.map +1 -1
- package/dist/shared-tree-core/transaction.js +65 -30
- package/dist/shared-tree-core/transaction.js.map +1 -1
- package/dist/shared-tree-core/transactionEnricher.d.ts +2 -2
- package/dist/shared-tree-core/transactionEnricher.d.ts.map +1 -1
- package/dist/shared-tree-core/transactionEnricher.js +3 -3
- package/dist/shared-tree-core/transactionEnricher.js.map +1 -1
- package/dist/simple-tree/api/configuration.js +1 -1
- package/dist/simple-tree/api/configuration.js.map +1 -1
- package/dist/simple-tree/api/customTree.d.ts.map +1 -1
- package/dist/simple-tree/api/customTree.js +13 -9
- package/dist/simple-tree/api/customTree.js.map +1 -1
- package/dist/simple-tree/api/discrepancies.d.ts.map +1 -1
- package/dist/simple-tree/api/discrepancies.js +21 -17
- package/dist/simple-tree/api/discrepancies.js.map +1 -1
- package/dist/simple-tree/api/index.d.ts +2 -2
- package/dist/simple-tree/api/index.d.ts.map +1 -1
- package/dist/simple-tree/api/index.js +2 -1
- package/dist/simple-tree/api/index.js.map +1 -1
- package/dist/simple-tree/api/schemaFactory.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaFactory.js +12 -8
- package/dist/simple-tree/api/schemaFactory.js.map +1 -1
- package/dist/simple-tree/api/schemaFactoryAlpha.js +1 -1
- package/dist/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
- package/dist/simple-tree/api/schemaFactoryBeta.js +1 -1
- package/dist/simple-tree/api/schemaFactoryBeta.js.map +1 -1
- package/dist/simple-tree/api/schemaFromSimple.js +18 -9
- package/dist/simple-tree/api/schemaFromSimple.js.map +1 -1
- package/dist/simple-tree/api/simpleSchemaCodec.js +10 -5
- package/dist/simple-tree/api/simpleSchemaCodec.js.map +1 -1
- package/dist/simple-tree/api/simpleSchemaToJsonSchema.d.ts.map +1 -1
- package/dist/simple-tree/api/simpleSchemaToJsonSchema.js +19 -15
- package/dist/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
- package/dist/simple-tree/api/simpleTreeIndex.js +10 -10
- package/dist/simple-tree/api/simpleTreeIndex.js.map +1 -1
- package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts +244 -0
- package/dist/simple-tree/api/snapshotCompatibilityChecker.d.ts.map +1 -1
- package/dist/simple-tree/api/snapshotCompatibilityChecker.js +297 -1
- package/dist/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
- package/dist/simple-tree/api/storedSchema.d.ts.map +1 -1
- package/dist/simple-tree/api/storedSchema.js +2 -3
- package/dist/simple-tree/api/storedSchema.js.map +1 -1
- package/dist/simple-tree/api/transactionTypes.d.ts +17 -4
- package/dist/simple-tree/api/transactionTypes.d.ts.map +1 -1
- package/dist/simple-tree/api/transactionTypes.js.map +1 -1
- package/dist/simple-tree/api/tree.d.ts +3 -1
- package/dist/simple-tree/api/tree.d.ts.map +1 -1
- package/dist/simple-tree/api/tree.js.map +1 -1
- package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
- package/dist/simple-tree/api/treeNodeApi.js +21 -13
- package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
- package/dist/simple-tree/api/verboseTree.d.ts.map +1 -1
- package/dist/simple-tree/api/verboseTree.js +14 -9
- package/dist/simple-tree/api/verboseTree.js.map +1 -1
- package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
- package/dist/simple-tree/core/treeNodeKernel.js +12 -5
- package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.d.ts +15 -15
- package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.js +79 -23
- package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/dist/simple-tree/fieldSchema.d.ts +4 -4
- package/dist/simple-tree/fieldSchema.d.ts.map +1 -1
- package/dist/simple-tree/fieldSchema.js.map +1 -1
- package/dist/simple-tree/getTreeNodeForField.d.ts.map +1 -1
- package/dist/simple-tree/getTreeNodeForField.js +2 -1
- package/dist/simple-tree/getTreeNodeForField.js.map +1 -1
- package/dist/simple-tree/index.d.ts +3 -3
- package/dist/simple-tree/index.d.ts.map +1 -1
- package/dist/simple-tree/index.js +4 -3
- package/dist/simple-tree/index.js.map +1 -1
- package/dist/simple-tree/leafNodeSchema.js +9 -6
- package/dist/simple-tree/leafNodeSchema.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 +22 -20
- package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/common.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/common.js +1 -1
- package/dist/simple-tree/node-kinds/common.js.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.js +2 -2
- package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/object/objectNode.js +21 -22
- package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/record/recordNode.js +6 -5
- package/dist/simple-tree/node-kinds/record/recordNode.js.map +1 -1
- package/dist/simple-tree/prepareForInsertion.d.ts +54 -47
- package/dist/simple-tree/prepareForInsertion.d.ts.map +1 -1
- package/dist/simple-tree/prepareForInsertion.js +184 -126
- package/dist/simple-tree/prepareForInsertion.js.map +1 -1
- package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
- package/dist/simple-tree/toStoredSchema.js +9 -5
- package/dist/simple-tree/toStoredSchema.js.map +1 -1
- package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts +13 -4
- package/dist/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -1
- package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js +31 -13
- package/dist/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -1
- package/dist/text/index.d.ts +6 -0
- package/dist/text/index.d.ts.map +1 -0
- package/dist/text/index.js +10 -0
- package/dist/text/index.js.map +1 -0
- package/dist/text/textDomain.d.ts +138 -0
- package/dist/text/textDomain.d.ts.map +1 -0
- package/dist/text/textDomain.js +121 -0
- package/dist/text/textDomain.js.map +1 -0
- package/dist/treeFactory.d.ts.map +1 -1
- package/dist/treeFactory.js +17 -3
- package/dist/treeFactory.js.map +1 -1
- package/dist/util/bTreeUtils.d.ts +12 -4
- package/dist/util/bTreeUtils.d.ts.map +1 -1
- package/dist/util/bTreeUtils.js +15 -19
- package/dist/util/bTreeUtils.js.map +1 -1
- package/dist/util/breakable.js +7 -9
- package/dist/util/breakable.js.map +1 -1
- package/dist/util/idAllocator.d.ts.map +1 -1
- package/dist/util/idAllocator.js +1 -2
- package/dist/util/idAllocator.js.map +1 -1
- package/dist/util/index.d.ts +1 -1
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +2 -1
- package/dist/util/index.js.map +1 -1
- package/dist/util/nestedMap.d.ts.map +1 -1
- package/dist/util/nestedMap.js +13 -13
- package/dist/util/nestedMap.js.map +1 -1
- package/dist/util/rangeMap.d.ts +24 -12
- package/dist/util/rangeMap.d.ts.map +1 -1
- package/dist/util/rangeMap.js +46 -6
- package/dist/util/rangeMap.js.map +1 -1
- package/dist/util/utils.d.ts.map +1 -1
- package/dist/util/utils.js +16 -15
- package/dist/util/utils.js.map +1 -1
- package/docs/user-facing/merge-semantics.md +3 -2
- package/eslint.config.mts +5 -48
- package/lib/alpha.d.ts +9 -0
- package/lib/codec/codec.d.ts +31 -3
- package/lib/codec/codec.d.ts.map +1 -1
- package/lib/codec/codec.js +10 -0
- package/lib/codec/codec.js.map +1 -1
- package/lib/codec/index.d.ts +2 -2
- package/lib/codec/index.d.ts.map +1 -1
- package/lib/codec/index.js +1 -1
- package/lib/codec/index.js.map +1 -1
- package/lib/codec/versioned/codec.d.ts +80 -22
- package/lib/codec/versioned/codec.d.ts.map +1 -1
- package/lib/codec/versioned/codec.js +138 -15
- package/lib/codec/versioned/codec.js.map +1 -1
- package/lib/codec/versioned/index.d.ts +1 -1
- package/lib/codec/versioned/index.d.ts.map +1 -1
- package/lib/codec/versioned/index.js +1 -1
- package/lib/codec/versioned/index.js.map +1 -1
- package/lib/core/change-family/changeFamily.d.ts +4 -1
- package/lib/core/change-family/changeFamily.d.ts.map +1 -1
- package/lib/core/change-family/changeFamily.js.map +1 -1
- package/lib/core/change-family/index.d.ts +1 -1
- package/lib/core/change-family/index.d.ts.map +1 -1
- package/lib/core/change-family/index.js.map +1 -1
- package/lib/core/index.d.ts +3 -3
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +2 -2
- package/lib/core/index.js.map +1 -1
- package/lib/core/rebase/changeRebaser.d.ts +42 -3
- package/lib/core/rebase/changeRebaser.d.ts.map +1 -1
- package/lib/core/rebase/changeRebaser.js.map +1 -1
- package/lib/core/rebase/index.d.ts +2 -2
- 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/types.d.ts +52 -10
- package/lib/core/rebase/types.d.ts.map +1 -1
- package/lib/core/rebase/types.js +3 -10
- package/lib/core/rebase/types.js.map +1 -1
- package/lib/core/rebase/utils.d.ts.map +1 -1
- package/lib/core/rebase/utils.js +33 -11
- package/lib/core/rebase/utils.js.map +1 -1
- package/lib/core/schema-stored/schema.js +3 -3
- package/lib/core/schema-stored/schema.js.map +1 -1
- package/lib/core/tree/anchorSet.d.ts.map +1 -1
- package/lib/core/tree/anchorSet.js +4 -4
- package/lib/core/tree/anchorSet.js.map +1 -1
- package/lib/core/tree/detachedFieldIndex.d.ts +7 -2
- package/lib/core/tree/detachedFieldIndex.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndex.js +23 -58
- package/lib/core/tree/detachedFieldIndex.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecCommon.d.ts +18 -10
- package/lib/core/tree/detachedFieldIndexCodecCommon.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecCommon.js +4 -4
- package/lib/core/tree/detachedFieldIndexCodecCommon.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV1.d.ts +2 -3
- package/lib/core/tree/detachedFieldIndexCodecV1.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV1.js +4 -5
- package/lib/core/tree/detachedFieldIndexCodecV1.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV2.d.ts +2 -3
- package/lib/core/tree/detachedFieldIndexCodecV2.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV2.js +4 -6
- package/lib/core/tree/detachedFieldIndexCodecV2.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecs.d.ts +5 -6
- package/lib/core/tree/detachedFieldIndexCodecs.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecs.js +12 -39
- package/lib/core/tree/detachedFieldIndexCodecs.js.map +1 -1
- package/lib/core/tree/index.d.ts +2 -2
- package/lib/core/tree/index.d.ts.map +1 -1
- package/lib/core/tree/index.js +2 -2
- package/lib/core/tree/index.js.map +1 -1
- package/lib/core/tree/mapTree.js +1 -1
- package/lib/core/tree/mapTree.js.map +1 -1
- package/lib/core/tree/pathTree.d.ts +11 -3
- package/lib/core/tree/pathTree.d.ts.map +1 -1
- package/lib/core/tree/pathTree.js +12 -1
- package/lib/core/tree/pathTree.js.map +1 -1
- package/lib/core/tree/sparseTree.d.ts.map +1 -1
- package/lib/core/tree/sparseTree.js +1 -0
- package/lib/core/tree/sparseTree.js.map +1 -1
- package/lib/core/tree/treeTextFormat.d.ts.map +1 -1
- package/lib/core/tree/treeTextFormat.js +5 -9
- package/lib/core/tree/treeTextFormat.js.map +1 -1
- package/lib/core/tree/visitDelta.d.ts.map +1 -1
- package/lib/core/tree/visitDelta.js +3 -2
- package/lib/core/tree/visitDelta.js.map +1 -1
- package/lib/core/tree/visitorUtils.d.ts.map +1 -1
- package/lib/core/tree/visitorUtils.js +58 -18
- package/lib/core/tree/visitorUtils.js.map +1 -1
- package/lib/feature-libraries/changeAtomIdBTree.d.ts +16 -0
- package/lib/feature-libraries/changeAtomIdBTree.d.ts.map +1 -0
- package/lib/feature-libraries/changeAtomIdBTree.js +24 -0
- package/lib/feature-libraries/changeAtomIdBTree.js.map +1 -0
- package/lib/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/basicChunk.js +9 -2
- package/lib/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.js +4 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.js +9 -7
- package/lib/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.js +7 -4
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/codecs.js +19 -11
- package/lib/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/compressedEncode.js +4 -3
- package/lib/feature-libraries/chunked-forest/codec/compressedEncode.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/schemaBasedEncode.js +9 -5
- package/lib/feature-libraries/chunked-forest/codec/schemaBasedEncode.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/uniformChunk.js +1 -1
- package/lib/feature-libraries/chunked-forest/uniformChunk.js.map +1 -1
- package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts +103 -44
- package/lib/feature-libraries/default-schema/defaultEditBuilder.d.ts.map +1 -1
- package/lib/feature-libraries/default-schema/defaultEditBuilder.js +249 -78
- package/lib/feature-libraries/default-schema/defaultEditBuilder.js.map +1 -1
- package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts +1 -1
- package/lib/feature-libraries/default-schema/defaultFieldKinds.d.ts.map +1 -1
- package/lib/feature-libraries/default-schema/defaultFieldKinds.js +22 -3
- package/lib/feature-libraries/default-schema/defaultFieldKinds.js.map +1 -1
- package/lib/feature-libraries/default-schema/index.d.ts +2 -1
- package/lib/feature-libraries/default-schema/index.d.ts.map +1 -1
- package/lib/feature-libraries/default-schema/index.js +2 -1
- package/lib/feature-libraries/default-schema/index.js.map +1 -1
- package/lib/feature-libraries/default-schema/locationBasedEditBuilder.d.ts +38 -0
- package/lib/feature-libraries/default-schema/locationBasedEditBuilder.d.ts.map +1 -0
- package/lib/feature-libraries/default-schema/locationBasedEditBuilder.js +128 -0
- package/lib/feature-libraries/default-schema/locationBasedEditBuilder.js.map +1 -0
- package/lib/feature-libraries/default-schema/mappedEditBuilder.d.ts +9 -6
- package/lib/feature-libraries/default-schema/mappedEditBuilder.d.ts.map +1 -1
- package/lib/feature-libraries/default-schema/mappedEditBuilder.js +21 -0
- package/lib/feature-libraries/default-schema/mappedEditBuilder.js.map +1 -1
- package/lib/feature-libraries/deltaUtils.d.ts +1 -0
- package/lib/feature-libraries/deltaUtils.d.ts.map +1 -1
- package/lib/feature-libraries/deltaUtils.js +5 -1
- package/lib/feature-libraries/deltaUtils.js.map +1 -1
- package/lib/feature-libraries/flex-tree/context.d.ts +9 -0
- package/lib/feature-libraries/flex-tree/context.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/context.js +6 -0
- package/lib/feature-libraries/flex-tree/context.js.map +1 -1
- package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +6 -6
- 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/lazyField.d.ts +8 -7
- package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyField.js +45 -16
- package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
- package/lib/feature-libraries/forest-summary/forestSummarizer.d.ts.map +1 -1
- package/lib/feature-libraries/forest-summary/forestSummarizer.js +3 -1
- package/lib/feature-libraries/forest-summary/forestSummarizer.js.map +1 -1
- package/lib/feature-libraries/index.d.ts +5 -4
- package/lib/feature-libraries/index.d.ts.map +1 -1
- package/lib/feature-libraries/index.js +5 -4
- package/lib/feature-libraries/index.js.map +1 -1
- package/lib/feature-libraries/indexing/anchorTreeIndex.js +6 -6
- package/lib/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
- package/lib/feature-libraries/mapTreeCursor.d.ts.map +1 -1
- package/lib/feature-libraries/mapTreeCursor.js +2 -1
- package/lib/feature-libraries/mapTreeCursor.js.map +1 -1
- package/lib/feature-libraries/mitigatedChangeFamily.d.ts.map +1 -1
- package/lib/feature-libraries/mitigatedChangeFamily.js +12 -3
- package/lib/feature-libraries/mitigatedChangeFamily.js.map +1 -1
- package/lib/feature-libraries/modular-schema/comparison.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/comparison.js +12 -9
- package/lib/feature-libraries/modular-schema/comparison.js.map +1 -1
- package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts +97 -21
- package/lib/feature-libraries/modular-schema/crossFieldQueries.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/crossFieldQueries.js +3 -5
- package/lib/feature-libraries/modular-schema/crossFieldQueries.js.map +1 -1
- package/lib/feature-libraries/modular-schema/defaultRevisionReplacer.d.ts +25 -0
- package/lib/feature-libraries/modular-schema/defaultRevisionReplacer.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/defaultRevisionReplacer.js +55 -0
- package/lib/feature-libraries/modular-schema/defaultRevisionReplacer.js.map +1 -0
- package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts +22 -53
- package/lib/feature-libraries/modular-schema/fieldChangeHandler.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/fieldChangeHandler.js.map +1 -1
- package/lib/feature-libraries/modular-schema/genericFieldKind.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/genericFieldKind.js +8 -14
- package/lib/feature-libraries/modular-schema/genericFieldKind.js.map +1 -1
- package/lib/feature-libraries/modular-schema/genericFieldKindCodecs.js +1 -1
- package/lib/feature-libraries/modular-schema/genericFieldKindCodecs.js.map +1 -1
- package/lib/feature-libraries/modular-schema/index.d.ts +7 -5
- package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/index.js +5 -3
- package/lib/feature-libraries/modular-schema/index.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeCodecV1.d.ts +32 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV1.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV1.js +402 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV1.js.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV2.d.ts +15 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV2.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV2.js +27 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV2.js.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV3.d.ts +15 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV3.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV3.js +389 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecV3.js.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts +2 -2
- package/lib/feature-libraries/modular-schema/modularChangeCodecs.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +34 -290
- package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts +60 -26
- package/lib/feature-libraries/modular-schema/modularChangeFamily.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeFamily.js +1441 -546
- package/lib/feature-libraries/modular-schema/modularChangeFamily.js.map +1 -1
- package/{dist/feature-libraries/modular-schema/modularChangeFormat.d.ts → lib/feature-libraries/modular-schema/modularChangeFormatV1.d.ts} +5 -6
- package/lib/feature-libraries/modular-schema/modularChangeFormatV1.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/{modularChangeFormat.js → modularChangeFormatV1.js} +4 -4
- package/lib/feature-libraries/modular-schema/modularChangeFormatV1.js.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV2.d.ts +112 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV2.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV2.js +18 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV2.js.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV3.d.ts +146 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV3.d.ts.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV3.js +29 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormatV3.js.map +1 -0
- package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +59 -13
- package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeTypes.js +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
- package/lib/feature-libraries/node-identifier/mockNodeIdentifierManager.js +1 -1
- package/lib/feature-libraries/node-identifier/mockNodeIdentifierManager.js.map +1 -1
- package/lib/feature-libraries/object-forest/objectForest.d.ts.map +1 -1
- package/lib/feature-libraries/object-forest/objectForest.js +7 -5
- package/lib/feature-libraries/object-forest/objectForest.js.map +1 -1
- package/lib/feature-libraries/optional-field/index.d.ts +2 -2
- package/lib/feature-libraries/optional-field/index.d.ts.map +1 -1
- package/lib/feature-libraries/optional-field/index.js +1 -1
- package/lib/feature-libraries/optional-field/index.js.map +1 -1
- package/lib/feature-libraries/optional-field/optionalField.d.ts +5 -26
- package/lib/feature-libraries/optional-field/optionalField.d.ts.map +1 -1
- package/lib/feature-libraries/optional-field/optionalField.js +223 -448
- package/lib/feature-libraries/optional-field/optionalField.js.map +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts +23 -0
- package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.d.ts.map +1 -0
- package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.js +27 -0
- package/lib/feature-libraries/optional-field/optionalFieldChangeFormatV3.js.map +1 -0
- package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts +24 -33
- package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.d.ts.map +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldChangeTypes.js.map +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldCodecV2.d.ts +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldCodecV2.d.ts.map +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldCodecV2.js +55 -26
- package/lib/feature-libraries/optional-field/optionalFieldCodecV2.js.map +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldCodecV3.d.ts +12 -0
- package/lib/feature-libraries/optional-field/optionalFieldCodecV3.d.ts.map +1 -0
- package/lib/feature-libraries/optional-field/optionalFieldCodecV3.js +53 -0
- package/lib/feature-libraries/optional-field/optionalFieldCodecV3.js.map +1 -0
- package/lib/feature-libraries/optional-field/optionalFieldCodecs.d.ts.map +1 -1
- package/lib/feature-libraries/optional-field/optionalFieldCodecs.js +5 -1
- package/lib/feature-libraries/optional-field/optionalFieldCodecs.js.map +1 -1
- package/lib/feature-libraries/schema-edits/schemaChangeCodecs.d.ts.map +1 -1
- package/lib/feature-libraries/schema-edits/schemaChangeCodecs.js +15 -3
- package/lib/feature-libraries/schema-edits/schemaChangeCodecs.js.map +1 -1
- package/lib/feature-libraries/schema-index/codec.d.ts +7 -21
- package/lib/feature-libraries/schema-index/codec.d.ts.map +1 -1
- package/lib/feature-libraries/schema-index/codec.js +30 -68
- package/lib/feature-libraries/schema-index/codec.js.map +1 -1
- package/lib/feature-libraries/schema-index/index.d.ts +2 -2
- package/lib/feature-libraries/schema-index/index.d.ts.map +1 -1
- package/lib/feature-libraries/schema-index/index.js +2 -2
- package/lib/feature-libraries/schema-index/index.js.map +1 -1
- package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts +1 -9
- package/lib/feature-libraries/schema-index/schemaSummarizer.d.ts.map +1 -1
- package/lib/feature-libraries/schema-index/schemaSummarizer.js +0 -10
- package/lib/feature-libraries/schema-index/schemaSummarizer.js.map +1 -1
- package/lib/feature-libraries/schemaChecker.d.ts.map +1 -1
- package/lib/feature-libraries/schemaChecker.js +11 -6
- package/lib/feature-libraries/schemaChecker.js.map +1 -1
- package/lib/feature-libraries/sequence-field/compose.d.ts +6 -7
- package/lib/feature-libraries/sequence-field/compose.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/compose.js +93 -265
- package/lib/feature-libraries/sequence-field/compose.js.map +1 -1
- package/lib/feature-libraries/sequence-field/helperTypes.d.ts +14 -10
- package/lib/feature-libraries/sequence-field/helperTypes.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/helperTypes.js.map +1 -1
- package/lib/feature-libraries/sequence-field/index.d.ts +2 -3
- package/lib/feature-libraries/sequence-field/index.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/index.js +0 -1
- package/lib/feature-libraries/sequence-field/index.js.map +1 -1
- package/lib/feature-libraries/sequence-field/invert.d.ts +3 -3
- package/lib/feature-libraries/sequence-field/invert.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/invert.js +69 -170
- package/lib/feature-libraries/sequence-field/invert.js.map +1 -1
- package/lib/feature-libraries/sequence-field/markQueue.d.ts +2 -2
- package/lib/feature-libraries/sequence-field/markQueue.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/markQueue.js.map +1 -1
- package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts +4 -56
- package/lib/feature-libraries/sequence-field/moveEffectTable.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/moveEffectTable.js +9 -81
- package/lib/feature-libraries/sequence-field/moveEffectTable.js.map +1 -1
- package/lib/feature-libraries/sequence-field/rebase.d.ts +3 -3
- package/lib/feature-libraries/sequence-field/rebase.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/rebase.js +122 -121
- package/lib/feature-libraries/sequence-field/rebase.js.map +1 -1
- package/lib/feature-libraries/sequence-field/replaceRevisions.d.ts +2 -2
- package/lib/feature-libraries/sequence-field/replaceRevisions.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/replaceRevisions.js +36 -44
- package/lib/feature-libraries/sequence-field/replaceRevisions.js.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js +0 -2
- package/lib/feature-libraries/sequence-field/sequenceFieldChangeHandler.js.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts +22 -4
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js +356 -174
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV2.js.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js +21 -61
- package/lib/feature-libraries/sequence-field/sequenceFieldCodecV3.js.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldEditor.d.ts +2 -2
- package/lib/feature-libraries/sequence-field/sequenceFieldEditor.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldEditor.js +10 -10
- package/lib/feature-libraries/sequence-field/sequenceFieldEditor.js.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts +3 -2
- package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js +20 -112
- package/lib/feature-libraries/sequence-field/sequenceFieldToDelta.js.map +1 -1
- package/lib/feature-libraries/sequence-field/types.d.ts +30 -59
- package/lib/feature-libraries/sequence-field/types.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/types.js.map +1 -1
- package/lib/feature-libraries/sequence-field/utils.d.ts +15 -24
- package/lib/feature-libraries/sequence-field/utils.d.ts.map +1 -1
- package/lib/feature-libraries/sequence-field/utils.js +144 -311
- package/lib/feature-libraries/sequence-field/utils.js.map +1 -1
- package/lib/feature-libraries/treeCursorUtils.js +7 -7
- package/lib/feature-libraries/treeCursorUtils.js.map +1 -1
- package/lib/feature-libraries/treeTextCursor.js +2 -2
- package/lib/feature-libraries/treeTextCursor.js.map +1 -1
- package/lib/feature-libraries/valueUtilities.d.ts.map +1 -1
- package/lib/feature-libraries/valueUtilities.js +16 -8
- package/lib/feature-libraries/valueUtilities.js.map +1 -1
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/shared-tree/index.d.ts +1 -1
- package/lib/shared-tree/index.d.ts.map +1 -1
- package/lib/shared-tree/index.js.map +1 -1
- package/lib/shared-tree/schematizeTree.d.ts +4 -4
- package/lib/shared-tree/schematizeTree.d.ts.map +1 -1
- package/lib/shared-tree/schematizeTree.js +3 -2
- package/lib/shared-tree/schematizeTree.js.map +1 -1
- package/lib/shared-tree/schematizingTreeView.d.ts +3 -8
- package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
- package/lib/shared-tree/schematizingTreeView.js +61 -47
- package/lib/shared-tree/schematizingTreeView.js.map +1 -1
- package/lib/shared-tree/sharedTree.d.ts +9 -3
- package/lib/shared-tree/sharedTree.d.ts.map +1 -1
- package/lib/shared-tree/sharedTree.js +41 -13
- package/lib/shared-tree/sharedTree.js.map +1 -1
- package/lib/shared-tree/sharedTreeChangeCodecs.d.ts +1 -1
- package/lib/shared-tree/sharedTreeChangeCodecs.d.ts.map +1 -1
- package/lib/shared-tree/sharedTreeChangeCodecs.js +10 -8
- package/lib/shared-tree/sharedTreeChangeCodecs.js.map +1 -1
- package/lib/shared-tree/sharedTreeChangeEnricher.d.ts.map +1 -1
- package/lib/shared-tree/sharedTreeChangeEnricher.js +6 -4
- package/lib/shared-tree/sharedTreeChangeEnricher.js.map +1 -1
- package/lib/shared-tree/sharedTreeChangeFamily.d.ts +7 -6
- package/lib/shared-tree/sharedTreeChangeFamily.d.ts.map +1 -1
- package/lib/shared-tree/sharedTreeChangeFamily.js +30 -19
- package/lib/shared-tree/sharedTreeChangeFamily.js.map +1 -1
- package/lib/shared-tree/sharedTreeEditBuilder.d.ts +16 -6
- package/lib/shared-tree/sharedTreeEditBuilder.d.ts.map +1 -1
- package/lib/shared-tree/sharedTreeEditBuilder.js +12 -6
- package/lib/shared-tree/sharedTreeEditBuilder.js.map +1 -1
- package/lib/shared-tree/treeAlpha.d.ts +35 -29
- package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
- package/lib/shared-tree/treeAlpha.js +21 -23
- package/lib/shared-tree/treeAlpha.js.map +1 -1
- package/lib/shared-tree/treeCheckout.d.ts +11 -10
- package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
- package/lib/shared-tree/treeCheckout.js +97 -29
- package/lib/shared-tree/treeCheckout.js.map +1 -1
- package/lib/shared-tree-core/branch.d.ts +6 -3
- package/lib/shared-tree-core/branch.d.ts.map +1 -1
- package/lib/shared-tree-core/branch.js +13 -6
- package/lib/shared-tree-core/branch.js.map +1 -1
- package/lib/shared-tree-core/branchCommitEnricher.d.ts.map +1 -1
- package/lib/shared-tree-core/branchCommitEnricher.js +2 -2
- package/lib/shared-tree-core/branchCommitEnricher.js.map +1 -1
- package/lib/shared-tree-core/editManager.d.ts +2 -2
- package/lib/shared-tree-core/editManager.d.ts.map +1 -1
- package/lib/shared-tree-core/editManager.js +21 -15
- package/lib/shared-tree-core/editManager.js.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.d.ts +4 -0
- package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.js +16 -4
- package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/lib/shared-tree-core/editManagerFormatCommons.d.ts +2 -0
- package/lib/shared-tree-core/editManagerFormatCommons.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerFormatCommons.js +12 -0
- package/lib/shared-tree-core/editManagerFormatCommons.js.map +1 -1
- package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts +2 -2
- package/lib/shared-tree-core/editManagerFormatV1toV4.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerFormatV1toV4.js +2 -0
- package/lib/shared-tree-core/editManagerFormatV1toV4.js.map +1 -1
- package/lib/shared-tree-core/editManagerSummarizer.js +3 -3
- package/lib/shared-tree-core/editManagerSummarizer.js.map +1 -1
- package/lib/shared-tree-core/index.d.ts +2 -2
- package/lib/shared-tree-core/index.d.ts.map +1 -1
- package/lib/shared-tree-core/index.js +2 -2
- package/lib/shared-tree-core/index.js.map +1 -1
- package/lib/shared-tree-core/messageCodecV1ToV4.d.ts +1 -1
- package/lib/shared-tree-core/messageCodecV1ToV4.d.ts.map +1 -1
- package/lib/shared-tree-core/messageCodecV1ToV4.js.map +1 -1
- package/lib/shared-tree-core/messageCodecVSharedBranches.d.ts.map +1 -1
- package/lib/shared-tree-core/messageCodecVSharedBranches.js +2 -1
- package/lib/shared-tree-core/messageCodecVSharedBranches.js.map +1 -1
- package/lib/shared-tree-core/messageCodecs.d.ts +4 -0
- package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/messageCodecs.js +15 -4
- package/lib/shared-tree-core/messageCodecs.js.map +1 -1
- package/lib/shared-tree-core/messageFormat.d.ts +2 -0
- package/lib/shared-tree-core/messageFormat.d.ts.map +1 -1
- package/lib/shared-tree-core/messageFormat.js +12 -0
- package/lib/shared-tree-core/messageFormat.js.map +1 -1
- package/lib/shared-tree-core/messageFormatV1ToV4.d.ts +3 -2
- package/lib/shared-tree-core/messageFormatV1ToV4.d.ts.map +1 -1
- package/lib/shared-tree-core/messageFormatV1ToV4.js +9 -1
- package/lib/shared-tree-core/messageFormatV1ToV4.js.map +1 -1
- package/lib/shared-tree-core/sequenceIdUtils.d.ts.map +1 -1
- package/lib/shared-tree-core/sequenceIdUtils.js +4 -4
- package/lib/shared-tree-core/sequenceIdUtils.js.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.d.ts +1 -0
- package/lib/shared-tree-core/sharedTreeCore.d.ts.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.js +13 -9
- package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/lib/shared-tree-core/transaction.d.ts +25 -8
- package/lib/shared-tree-core/transaction.d.ts.map +1 -1
- package/lib/shared-tree-core/transaction.js +67 -32
- package/lib/shared-tree-core/transaction.js.map +1 -1
- package/lib/shared-tree-core/transactionEnricher.d.ts +2 -2
- package/lib/shared-tree-core/transactionEnricher.d.ts.map +1 -1
- package/lib/shared-tree-core/transactionEnricher.js +3 -3
- package/lib/shared-tree-core/transactionEnricher.js.map +1 -1
- package/lib/simple-tree/api/configuration.js +1 -1
- package/lib/simple-tree/api/configuration.js.map +1 -1
- package/lib/simple-tree/api/customTree.d.ts.map +1 -1
- package/lib/simple-tree/api/customTree.js +13 -9
- package/lib/simple-tree/api/customTree.js.map +1 -1
- package/lib/simple-tree/api/discrepancies.d.ts.map +1 -1
- package/lib/simple-tree/api/discrepancies.js +21 -17
- package/lib/simple-tree/api/discrepancies.js.map +1 -1
- package/lib/simple-tree/api/index.d.ts +2 -2
- package/lib/simple-tree/api/index.d.ts.map +1 -1
- package/lib/simple-tree/api/index.js +1 -1
- package/lib/simple-tree/api/index.js.map +1 -1
- package/lib/simple-tree/api/schemaFactory.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaFactory.js +12 -8
- package/lib/simple-tree/api/schemaFactory.js.map +1 -1
- package/lib/simple-tree/api/schemaFactoryAlpha.js +1 -1
- package/lib/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
- package/lib/simple-tree/api/schemaFactoryBeta.js +1 -1
- package/lib/simple-tree/api/schemaFactoryBeta.js.map +1 -1
- package/lib/simple-tree/api/schemaFromSimple.js +18 -9
- package/lib/simple-tree/api/schemaFromSimple.js.map +1 -1
- package/lib/simple-tree/api/simpleSchemaCodec.js +10 -5
- package/lib/simple-tree/api/simpleSchemaCodec.js.map +1 -1
- package/lib/simple-tree/api/simpleSchemaToJsonSchema.d.ts.map +1 -1
- package/lib/simple-tree/api/simpleSchemaToJsonSchema.js +19 -15
- package/lib/simple-tree/api/simpleSchemaToJsonSchema.js.map +1 -1
- package/lib/simple-tree/api/simpleTreeIndex.js +10 -10
- package/lib/simple-tree/api/simpleTreeIndex.js.map +1 -1
- package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts +244 -0
- package/lib/simple-tree/api/snapshotCompatibilityChecker.d.ts.map +1 -1
- package/lib/simple-tree/api/snapshotCompatibilityChecker.js +270 -0
- package/lib/simple-tree/api/snapshotCompatibilityChecker.js.map +1 -1
- package/lib/simple-tree/api/storedSchema.d.ts.map +1 -1
- package/lib/simple-tree/api/storedSchema.js +4 -7
- package/lib/simple-tree/api/storedSchema.js.map +1 -1
- package/lib/simple-tree/api/transactionTypes.d.ts +17 -4
- package/lib/simple-tree/api/transactionTypes.d.ts.map +1 -1
- package/lib/simple-tree/api/transactionTypes.js.map +1 -1
- package/lib/simple-tree/api/tree.d.ts +3 -1
- package/lib/simple-tree/api/tree.d.ts.map +1 -1
- package/lib/simple-tree/api/tree.js.map +1 -1
- package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
- package/lib/simple-tree/api/treeNodeApi.js +21 -13
- package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
- package/lib/simple-tree/api/verboseTree.d.ts.map +1 -1
- package/lib/simple-tree/api/verboseTree.js +14 -9
- package/lib/simple-tree/api/verboseTree.js.map +1 -1
- package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
- package/lib/simple-tree/core/treeNodeKernel.js +12 -5
- package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.d.ts +15 -15
- package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.js +78 -23
- package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/lib/simple-tree/fieldSchema.d.ts +4 -4
- package/lib/simple-tree/fieldSchema.d.ts.map +1 -1
- package/lib/simple-tree/fieldSchema.js.map +1 -1
- package/lib/simple-tree/getTreeNodeForField.d.ts.map +1 -1
- package/lib/simple-tree/getTreeNodeForField.js +2 -1
- package/lib/simple-tree/getTreeNodeForField.js.map +1 -1
- package/lib/simple-tree/index.d.ts +3 -3
- package/lib/simple-tree/index.d.ts.map +1 -1
- package/lib/simple-tree/index.js +2 -2
- package/lib/simple-tree/index.js.map +1 -1
- package/lib/simple-tree/leafNodeSchema.js +9 -6
- package/lib/simple-tree/leafNodeSchema.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 +23 -21
- package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/common.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/common.js +2 -2
- package/lib/simple-tree/node-kinds/common.js.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.js +2 -2
- package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/object/objectNode.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/object/objectNode.js +22 -23
- package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/record/recordNode.js +6 -5
- package/lib/simple-tree/node-kinds/record/recordNode.js.map +1 -1
- package/lib/simple-tree/prepareForInsertion.d.ts +54 -47
- package/lib/simple-tree/prepareForInsertion.d.ts.map +1 -1
- package/lib/simple-tree/prepareForInsertion.js +184 -125
- package/lib/simple-tree/prepareForInsertion.js.map +1 -1
- package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
- package/lib/simple-tree/toStoredSchema.js +9 -5
- package/lib/simple-tree/toStoredSchema.js.map +1 -1
- package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts +13 -4
- package/lib/simple-tree/unhydratedFlexTreeFromInsertable.d.ts.map +1 -1
- package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js +28 -11
- package/lib/simple-tree/unhydratedFlexTreeFromInsertable.js.map +1 -1
- package/lib/text/index.d.ts +6 -0
- package/lib/text/index.d.ts.map +1 -0
- package/lib/text/index.js +6 -0
- package/lib/text/index.js.map +1 -0
- package/lib/text/textDomain.d.ts +138 -0
- package/lib/text/textDomain.d.ts.map +1 -0
- package/lib/text/textDomain.js +118 -0
- package/lib/text/textDomain.js.map +1 -0
- package/lib/treeFactory.d.ts.map +1 -1
- package/lib/treeFactory.js +18 -4
- package/lib/treeFactory.js.map +1 -1
- package/lib/util/bTreeUtils.d.ts +12 -4
- package/lib/util/bTreeUtils.d.ts.map +1 -1
- package/lib/util/bTreeUtils.js +16 -20
- package/lib/util/bTreeUtils.js.map +1 -1
- package/lib/util/breakable.js +7 -9
- package/lib/util/breakable.js.map +1 -1
- package/lib/util/idAllocator.d.ts.map +1 -1
- package/lib/util/idAllocator.js +1 -2
- package/lib/util/idAllocator.js.map +1 -1
- package/lib/util/index.d.ts +1 -1
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -1
- package/lib/util/index.js.map +1 -1
- package/lib/util/nestedMap.d.ts.map +1 -1
- package/lib/util/nestedMap.js +13 -13
- package/lib/util/nestedMap.js.map +1 -1
- package/lib/util/rangeMap.d.ts +24 -12
- package/lib/util/rangeMap.d.ts.map +1 -1
- package/lib/util/rangeMap.js +44 -5
- package/lib/util/rangeMap.js.map +1 -1
- package/lib/util/utils.d.ts.map +1 -1
- package/lib/util/utils.js +16 -15
- package/lib/util/utils.js.map +1 -1
- package/package.json +33 -33
- package/src/codec/codec.ts +48 -8
- package/src/codec/index.ts +4 -1
- package/src/codec/versioned/codec.ts +340 -22
- package/src/codec/versioned/index.ts +3 -1
- package/src/core/change-family/changeFamily.ts +5 -0
- package/src/core/change-family/index.ts +1 -0
- package/src/core/index.ts +8 -3
- package/src/core/rebase/changeRebaser.ts +46 -7
- package/src/core/rebase/index.ts +4 -1
- package/src/core/rebase/types.ts +71 -39
- package/src/core/rebase/utils.ts +42 -14
- package/src/core/schema-stored/schema.ts +3 -3
- package/src/core/tree/anchorSet.ts +4 -4
- package/src/core/tree/detachedFieldIndex.ts +29 -74
- package/src/core/tree/detachedFieldIndexCodecCommon.ts +4 -8
- package/src/core/tree/detachedFieldIndexCodecV1.ts +3 -7
- package/src/core/tree/detachedFieldIndexCodecV2.ts +5 -9
- package/src/core/tree/detachedFieldIndexCodecs.ts +21 -64
- package/src/core/tree/index.ts +3 -2
- package/src/core/tree/mapTree.ts +1 -1
- package/src/core/tree/pathTree.ts +16 -4
- package/src/core/tree/sparseTree.ts +1 -0
- package/src/core/tree/treeTextFormat.ts +5 -9
- package/src/core/tree/visitDelta.ts +6 -2
- package/src/core/tree/visitorUtils.ts +55 -19
- package/src/feature-libraries/changeAtomIdBTree.ts +56 -0
- package/src/feature-libraries/chunked-forest/basicChunk.ts +8 -2
- package/src/feature-libraries/chunked-forest/chunkTree.ts +6 -1
- package/src/feature-libraries/chunked-forest/chunkedForest.ts +8 -6
- package/src/feature-libraries/chunked-forest/codec/chunkDecoding.ts +7 -4
- package/src/feature-libraries/chunked-forest/codec/codecs.ts +19 -11
- package/src/feature-libraries/chunked-forest/codec/compressedEncode.ts +4 -3
- package/src/feature-libraries/chunked-forest/codec/schemaBasedEncode.ts +9 -5
- package/src/feature-libraries/chunked-forest/uniformChunk.ts +1 -1
- package/src/feature-libraries/default-schema/defaultEditBuilder.ts +442 -139
- package/src/feature-libraries/default-schema/defaultFieldKinds.ts +24 -6
- package/src/feature-libraries/default-schema/index.ts +17 -5
- package/src/feature-libraries/default-schema/locationBasedEditBuilder.ts +188 -0
- package/src/feature-libraries/default-schema/mappedEditBuilder.ts +41 -9
- package/src/feature-libraries/deltaUtils.ts +6 -1
- package/src/feature-libraries/flex-tree/context.ts +17 -0
- package/src/feature-libraries/flex-tree/flexTreeTypes.ts +7 -8
- package/src/feature-libraries/flex-tree/lazyField.ts +72 -30
- package/src/feature-libraries/forest-summary/forestSummarizer.ts +3 -1
- package/src/feature-libraries/index.ts +32 -13
- package/src/feature-libraries/indexing/anchorTreeIndex.ts +5 -5
- package/src/feature-libraries/mapTreeCursor.ts +2 -1
- package/src/feature-libraries/mitigatedChangeFamily.ts +14 -7
- package/src/feature-libraries/modular-schema/comparison.ts +12 -9
- package/src/feature-libraries/modular-schema/crossFieldQueries.ts +142 -44
- package/src/feature-libraries/modular-schema/defaultRevisionReplacer.ts +70 -0
- package/src/feature-libraries/modular-schema/fieldChangeHandler.ts +35 -64
- package/src/feature-libraries/modular-schema/genericFieldKind.ts +11 -25
- package/src/feature-libraries/modular-schema/genericFieldKindCodecs.ts +1 -1
- package/src/feature-libraries/modular-schema/index.ts +20 -16
- package/src/feature-libraries/modular-schema/modularChangeCodecV1.ts +912 -0
- package/src/feature-libraries/modular-schema/modularChangeCodecV2.ts +89 -0
- package/src/feature-libraries/modular-schema/modularChangeCodecV3.ts +760 -0
- package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +52 -523
- package/src/feature-libraries/modular-schema/modularChangeFamily.ts +2756 -884
- package/src/feature-libraries/modular-schema/{modularChangeFormat.ts → modularChangeFormatV1.ts} +5 -4
- package/src/feature-libraries/modular-schema/modularChangeFormatV2.ts +34 -0
- package/src/feature-libraries/modular-schema/modularChangeFormatV3.ts +62 -0
- package/src/feature-libraries/modular-schema/modularChangeTypes.ts +70 -14
- package/src/feature-libraries/node-identifier/mockNodeIdentifierManager.ts +1 -1
- package/src/feature-libraries/object-forest/objectForest.ts +7 -5
- package/src/feature-libraries/optional-field/index.ts +1 -3
- package/src/feature-libraries/optional-field/optionalField.ts +320 -576
- package/src/feature-libraries/optional-field/optionalFieldChangeFormatV3.ts +45 -0
- package/src/feature-libraries/optional-field/optionalFieldChangeTypes.ts +24 -38
- package/src/feature-libraries/optional-field/optionalFieldCodecV2.ts +89 -35
- package/src/feature-libraries/optional-field/optionalFieldCodecV3.ts +94 -0
- package/src/feature-libraries/optional-field/optionalFieldCodecs.ts +5 -1
- package/src/feature-libraries/schema-edits/schemaChangeCodecs.ts +18 -3
- package/src/feature-libraries/schema-index/codec.ts +30 -90
- package/src/feature-libraries/schema-index/index.ts +2 -4
- package/src/feature-libraries/schema-index/schemaSummarizer.ts +0 -17
- package/src/feature-libraries/schemaChecker.ts +11 -6
- package/src/feature-libraries/sequence-field/compose.ts +147 -526
- package/src/feature-libraries/sequence-field/helperTypes.ts +34 -19
- package/src/feature-libraries/sequence-field/index.ts +0 -9
- package/src/feature-libraries/sequence-field/invert.ts +103 -227
- package/src/feature-libraries/sequence-field/markQueue.ts +2 -2
- package/src/feature-libraries/sequence-field/moveEffectTable.ts +11 -192
- package/src/feature-libraries/sequence-field/rebase.ts +182 -210
- package/src/feature-libraries/sequence-field/replaceRevisions.ts +54 -80
- package/src/feature-libraries/sequence-field/sequenceFieldChangeHandler.ts +0 -2
- package/src/feature-libraries/sequence-field/sequenceFieldCodecV2.ts +648 -220
- package/src/feature-libraries/sequence-field/sequenceFieldCodecV3.ts +56 -68
- package/src/feature-libraries/sequence-field/sequenceFieldEditor.ts +25 -27
- package/src/feature-libraries/sequence-field/sequenceFieldToDelta.ts +25 -132
- package/src/feature-libraries/sequence-field/types.ts +34 -64
- package/src/feature-libraries/sequence-field/utils.ts +171 -366
- package/src/feature-libraries/treeCursorUtils.ts +7 -7
- package/src/feature-libraries/treeTextCursor.ts +2 -2
- package/src/feature-libraries/valueUtilities.ts +16 -8
- package/src/index.ts +11 -0
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/index.ts +3 -2
- package/src/shared-tree/schematizeTree.ts +21 -8
- package/src/shared-tree/schematizingTreeView.ts +79 -83
- package/src/shared-tree/sharedTree.ts +50 -17
- package/src/shared-tree/sharedTreeChangeCodecs.ts +14 -9
- package/src/shared-tree/sharedTreeChangeEnricher.ts +6 -2
- package/src/shared-tree/sharedTreeChangeFamily.ts +44 -24
- package/src/shared-tree/sharedTreeEditBuilder.ts +48 -13
- package/src/shared-tree/treeAlpha.ts +60 -51
- package/src/shared-tree/treeCheckout.ts +160 -73
- package/src/shared-tree-core/branch.ts +21 -6
- package/src/shared-tree-core/branchCommitEnricher.ts +3 -8
- package/src/shared-tree-core/editManager.ts +43 -29
- package/src/shared-tree-core/editManagerCodecs.ts +19 -4
- package/src/shared-tree-core/editManagerFormatCommons.ts +12 -0
- package/src/shared-tree-core/editManagerFormatV1toV4.ts +5 -1
- package/src/shared-tree-core/editManagerSummarizer.ts +3 -3
- package/src/shared-tree-core/index.ts +2 -0
- package/src/shared-tree-core/messageCodecV1ToV4.ts +3 -1
- package/src/shared-tree-core/messageCodecVSharedBranches.ts +2 -1
- package/src/shared-tree-core/messageCodecs.ts +18 -4
- package/src/shared-tree-core/messageFormat.ts +12 -1
- package/src/shared-tree-core/messageFormatV1ToV4.ts +18 -2
- package/src/shared-tree-core/sequenceIdUtils.ts +4 -4
- package/src/shared-tree-core/sharedTreeCore.ts +15 -8
- package/src/shared-tree-core/transaction.ts +115 -56
- package/src/shared-tree-core/transactionEnricher.ts +5 -6
- package/src/simple-tree/api/configuration.ts +1 -1
- package/src/simple-tree/api/customTree.ts +14 -10
- package/src/simple-tree/api/discrepancies.ts +23 -17
- package/src/simple-tree/api/index.ts +5 -0
- package/src/simple-tree/api/schemaFactory.ts +11 -7
- package/src/simple-tree/api/schemaFactoryAlpha.ts +1 -1
- package/src/simple-tree/api/schemaFactoryBeta.ts +1 -1
- package/src/simple-tree/api/schemaFromSimple.ts +18 -9
- package/src/simple-tree/api/simpleSchemaCodec.ts +10 -5
- package/src/simple-tree/api/simpleSchemaToJsonSchema.ts +21 -17
- package/src/simple-tree/api/simpleTreeIndex.ts +8 -8
- package/src/simple-tree/api/snapshotCompatibilityChecker.ts +501 -0
- package/src/simple-tree/api/storedSchema.ts +10 -7
- package/src/simple-tree/api/transactionTypes.ts +19 -4
- package/src/simple-tree/api/tree.ts +3 -1
- package/src/simple-tree/api/treeNodeApi.ts +21 -13
- package/src/simple-tree/api/verboseTree.ts +14 -9
- package/src/simple-tree/core/treeNodeKernel.ts +12 -5
- package/src/simple-tree/core/unhydratedFlexTree.ts +109 -53
- package/src/simple-tree/fieldSchema.ts +6 -4
- package/src/simple-tree/getTreeNodeForField.ts +2 -1
- package/src/simple-tree/index.ts +7 -1
- package/src/simple-tree/leafNodeSchema.ts +8 -5
- package/src/simple-tree/node-kinds/array/arrayNode.ts +32 -30
- package/src/simple-tree/node-kinds/common.ts +2 -5
- package/src/simple-tree/node-kinds/map/mapNode.ts +4 -4
- package/src/simple-tree/node-kinds/object/objectNode.ts +29 -30
- package/src/simple-tree/node-kinds/record/recordNode.ts +12 -12
- package/src/simple-tree/prepareForInsertion.ts +343 -201
- package/src/simple-tree/toStoredSchema.ts +9 -5
- package/src/simple-tree/unhydratedFlexTreeFromInsertable.ts +43 -15
- package/src/text/README.md +8 -0
- package/src/text/index.ts +6 -0
- package/src/text/textDomain.ts +199 -0
- package/src/treeFactory.ts +20 -5
- package/src/util/bTreeUtils.ts +34 -23
- package/src/util/breakable.ts +9 -9
- package/src/util/idAllocator.ts +1 -2
- package/src/util/index.ts +3 -0
- package/src/util/nestedMap.ts +13 -15
- package/src/util/rangeMap.ts +72 -18
- package/src/util/utils.ts +14 -13
- package/.eslintrc.cjs +0 -140
- package/assertTagging.config.mjs +0 -14
- package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +0 -1
- package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +0 -1
- package/dist/feature-libraries/sequence-field/relevantRemovedRoots.d.ts +0 -9
- package/dist/feature-libraries/sequence-field/relevantRemovedRoots.d.ts.map +0 -1
- package/dist/feature-libraries/sequence-field/relevantRemovedRoots.js +0 -50
- package/dist/feature-libraries/sequence-field/relevantRemovedRoots.js.map +0 -1
- package/docs/main/sequence-field/move-composition.md +0 -46
- package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +0 -1
- package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +0 -1
- package/lib/feature-libraries/sequence-field/relevantRemovedRoots.d.ts +0 -9
- package/lib/feature-libraries/sequence-field/relevantRemovedRoots.d.ts.map +0 -1
- package/lib/feature-libraries/sequence-field/relevantRemovedRoots.js +0 -46
- package/lib/feature-libraries/sequence-field/relevantRemovedRoots.js.map +0 -1
- package/src/feature-libraries/sequence-field/relevantRemovedRoots.ts +0 -57
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
import { assert, fail } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import { BTree } from "@tylerbu/sorted-btree-es6";
|
|
8
|
+
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
8
9
|
|
|
9
|
-
import
|
|
10
|
+
import {
|
|
11
|
+
FluidClientVersion,
|
|
12
|
+
type CodecWriteOptions,
|
|
13
|
+
type ICodecFamily,
|
|
14
|
+
} from "../../codec/index.js";
|
|
10
15
|
import {
|
|
11
16
|
type ChangeEncodingContext,
|
|
12
17
|
type ChangeFamily,
|
|
@@ -22,24 +27,30 @@ import {
|
|
|
22
27
|
EditBuilder,
|
|
23
28
|
type FieldKey,
|
|
24
29
|
type FieldKindIdentifier,
|
|
25
|
-
type FieldUpPath,
|
|
26
30
|
type RevisionInfo,
|
|
27
31
|
type RevisionMetadataSource,
|
|
28
32
|
type RevisionTag,
|
|
29
33
|
type TaggedChange,
|
|
30
|
-
type UpPath,
|
|
31
34
|
makeDetachedNodeId,
|
|
32
|
-
replaceAtomRevisions,
|
|
33
35
|
revisionMetadataSourceFromInfo,
|
|
34
36
|
areEqualChangeAtomIds,
|
|
35
37
|
type ChangeAtomId,
|
|
36
38
|
areEqualChangeAtomIdOpts,
|
|
37
39
|
tagChange,
|
|
38
40
|
makeAnonChange,
|
|
39
|
-
newChangeAtomIdRangeMap,
|
|
40
41
|
type DeltaDetachedNodeChanges,
|
|
41
42
|
type DeltaDetachedNodeRename,
|
|
42
43
|
mapTaggedChange,
|
|
44
|
+
newChangeAtomIdRangeMap,
|
|
45
|
+
newChangeAtomIdTransform,
|
|
46
|
+
type ChangeAtomIdRangeMap,
|
|
47
|
+
offsetChangeAtomId,
|
|
48
|
+
type NormalizedUpPath,
|
|
49
|
+
type NormalizedFieldUpPath,
|
|
50
|
+
isDetachedUpPathRoot,
|
|
51
|
+
subtractChangeAtomIds,
|
|
52
|
+
makeChangeAtomId,
|
|
53
|
+
type RevisionReplacer,
|
|
43
54
|
} from "../../core/index.js";
|
|
44
55
|
import {
|
|
45
56
|
type IdAllocationState,
|
|
@@ -55,14 +66,19 @@ import {
|
|
|
55
66
|
type TupleBTree,
|
|
56
67
|
RangeMap,
|
|
57
68
|
balancedReduce,
|
|
69
|
+
type RangeQueryEntry,
|
|
70
|
+
type RangeQueryResultFragment,
|
|
58
71
|
} from "../../util/index.js";
|
|
59
72
|
import type { TreeChunk } from "../chunked-forest/index.js";
|
|
60
73
|
|
|
61
74
|
import {
|
|
62
|
-
type
|
|
75
|
+
type ComposeNodeManager,
|
|
63
76
|
type CrossFieldMap,
|
|
64
77
|
CrossFieldTarget,
|
|
65
|
-
|
|
78
|
+
type DetachedNodeEntry,
|
|
79
|
+
type InvertNodeManager,
|
|
80
|
+
type RebaseDetachedNodeEntry,
|
|
81
|
+
type RebaseNodeManager,
|
|
66
82
|
setInCrossFieldMap,
|
|
67
83
|
} from "./crossFieldQueries.js";
|
|
68
84
|
import {
|
|
@@ -73,20 +89,31 @@ import {
|
|
|
73
89
|
import { convertGenericChange, genericFieldKind } from "./genericFieldKind.js";
|
|
74
90
|
import type { GenericChangeset } from "./genericFieldKindTypes.js";
|
|
75
91
|
import {
|
|
76
|
-
type ChangeAtomIdBTree,
|
|
77
92
|
type CrossFieldKey,
|
|
78
93
|
type CrossFieldKeyRange,
|
|
79
94
|
type CrossFieldKeyTable,
|
|
95
|
+
type CrossFieldRangeTable,
|
|
80
96
|
type FieldChange,
|
|
81
97
|
type FieldChangeMap,
|
|
82
98
|
type FieldChangeset,
|
|
83
99
|
type FieldId,
|
|
84
100
|
type ModularChangeset,
|
|
85
|
-
|
|
101
|
+
newCrossFieldRangeTable,
|
|
102
|
+
type NoChangeConstraint,
|
|
86
103
|
type NodeChangeset,
|
|
87
104
|
type NodeId,
|
|
105
|
+
type NodeLocation,
|
|
106
|
+
type RebaseVersion,
|
|
107
|
+
type RootNodeTable,
|
|
88
108
|
} from "./modularChangeTypes.js";
|
|
89
109
|
import type { FlexFieldKind } from "./fieldKind.js";
|
|
110
|
+
import { lt } from "semver-ts";
|
|
111
|
+
import {
|
|
112
|
+
getFromChangeAtomIdMap,
|
|
113
|
+
rangeQueryChangeAtomIdMap,
|
|
114
|
+
setInChangeAtomIdMap,
|
|
115
|
+
type ChangeAtomIdBTree,
|
|
116
|
+
} from "../changeAtomIdBTree.js";
|
|
90
117
|
|
|
91
118
|
/**
|
|
92
119
|
* Implementation of ChangeFamily which delegates work in a given field to the appropriate FieldKind
|
|
@@ -104,6 +131,7 @@ export class ModularChangeFamily
|
|
|
104
131
|
public constructor(
|
|
105
132
|
fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
106
133
|
public readonly codecs: ICodecFamily<ModularChangeset, ChangeEncodingContext>,
|
|
134
|
+
public readonly codecOptions: CodecWriteOptions,
|
|
107
135
|
) {
|
|
108
136
|
this.fieldKinds = fieldKinds;
|
|
109
137
|
}
|
|
@@ -130,9 +158,9 @@ export class ModularChangeFamily
|
|
|
130
158
|
} {
|
|
131
159
|
// TODO: Handle the case where changes have conflicting field kinds
|
|
132
160
|
const kind =
|
|
133
|
-
change1.fieldKind
|
|
134
|
-
?
|
|
135
|
-
:
|
|
161
|
+
change1.fieldKind === genericFieldKind.identifier
|
|
162
|
+
? change2.fieldKind
|
|
163
|
+
: change1.fieldKind;
|
|
136
164
|
|
|
137
165
|
if (kind === genericFieldKind.identifier) {
|
|
138
166
|
// Both changes are generic
|
|
@@ -171,14 +199,14 @@ export class ModularChangeFamily
|
|
|
171
199
|
}
|
|
172
200
|
|
|
173
201
|
public compose(changes: TaggedChange<ModularChangeset>[]): ModularChangeset {
|
|
174
|
-
const {
|
|
202
|
+
const { maxId } = getRevInfoFromTaggedChanges(changes);
|
|
175
203
|
const idState: IdAllocationState = { maxId };
|
|
176
204
|
|
|
177
205
|
const pairwiseDelegate = (
|
|
178
206
|
left: ModularChangeset,
|
|
179
207
|
right: ModularChangeset,
|
|
180
208
|
): ModularChangeset => {
|
|
181
|
-
return this.composePair(left, right,
|
|
209
|
+
return this.composePair(left, right, idState);
|
|
182
210
|
};
|
|
183
211
|
|
|
184
212
|
const innerChanges = changes.map((change) => change.change);
|
|
@@ -188,10 +216,11 @@ export class ModularChangeFamily
|
|
|
188
216
|
private composePair(
|
|
189
217
|
change1: ModularChangeset,
|
|
190
218
|
change2: ModularChangeset,
|
|
191
|
-
revInfos: RevisionInfo[],
|
|
192
219
|
idState: IdAllocationState,
|
|
193
220
|
): ModularChangeset {
|
|
194
|
-
const
|
|
221
|
+
const revInfos = composeRevInfos(change1.revisions, change2.revisions);
|
|
222
|
+
|
|
223
|
+
const { fieldChanges, nodeChanges, nodeToParent, nodeAliases, crossFieldKeys, rootNodes } =
|
|
195
224
|
this.composeAllFields(change1, change2, revInfos, idState);
|
|
196
225
|
|
|
197
226
|
const { allBuilds, allDestroys, allRefreshers } = composeBuildsDestroysAndRefreshers(
|
|
@@ -199,7 +228,12 @@ export class ModularChangeFamily
|
|
|
199
228
|
change2,
|
|
200
229
|
);
|
|
201
230
|
|
|
202
|
-
|
|
231
|
+
// The composed changeset has a "no change" constraint if either change has one
|
|
232
|
+
const noChangeConstraint = change1.noChangeConstraint ?? change2.noChangeConstraint;
|
|
233
|
+
const noChangeConstraintOnRevert =
|
|
234
|
+
change1.noChangeConstraintOnRevert ?? change2.noChangeConstraintOnRevert;
|
|
235
|
+
|
|
236
|
+
const composed = makeModularChangeset({
|
|
203
237
|
fieldChanges,
|
|
204
238
|
nodeChanges,
|
|
205
239
|
nodeToParent,
|
|
@@ -207,16 +241,23 @@ export class ModularChangeFamily
|
|
|
207
241
|
crossFieldKeys,
|
|
208
242
|
maxId: idState.maxId,
|
|
209
243
|
revisions: revInfos,
|
|
244
|
+
rootNodes,
|
|
210
245
|
builds: allBuilds,
|
|
211
246
|
destroys: allDestroys,
|
|
212
247
|
refreshers: allRefreshers,
|
|
248
|
+
noChangeConstraint,
|
|
249
|
+
noChangeConstraintOnRevert,
|
|
213
250
|
});
|
|
251
|
+
|
|
252
|
+
// XXX: This is an expensive assert which should be disabled before merging.
|
|
253
|
+
validateChangeset(composed, this.fieldKinds);
|
|
254
|
+
return composed;
|
|
214
255
|
}
|
|
215
256
|
|
|
216
257
|
private composeAllFields(
|
|
217
258
|
potentiallyConflictedChange1: ModularChangeset,
|
|
218
259
|
potentiallyConflictedChange2: ModularChangeset,
|
|
219
|
-
revInfos: RevisionInfo[],
|
|
260
|
+
revInfos: readonly RevisionInfo[],
|
|
220
261
|
idState: IdAllocationState,
|
|
221
262
|
): ModularChangesetContent {
|
|
222
263
|
// Our current cell ordering scheme in sequences depends on being able to rebase over a change with conflicts.
|
|
@@ -240,14 +281,38 @@ export class ModularChangeFamily
|
|
|
240
281
|
mergeTupleBTrees(change1.nodeChanges, change2.nodeChanges),
|
|
241
282
|
);
|
|
242
283
|
|
|
243
|
-
const composedNodeToParent: ChangeAtomIdBTree<
|
|
284
|
+
const composedNodeToParent: ChangeAtomIdBTree<NodeLocation> = brand(
|
|
244
285
|
mergeTupleBTrees(change1.nodeToParent, change2.nodeToParent),
|
|
245
286
|
);
|
|
246
287
|
const composedNodeAliases: ChangeAtomIdBTree<NodeId> = brand(
|
|
247
288
|
mergeTupleBTrees(change1.nodeAliases, change2.nodeAliases),
|
|
248
289
|
);
|
|
249
290
|
|
|
250
|
-
const
|
|
291
|
+
const pendingCompositions: PendingCompositions = {
|
|
292
|
+
nodeIdsToCompose: [],
|
|
293
|
+
affectedBaseFields: newTupleBTree(),
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const movedCrossFieldKeys: CrossFieldKeyTable = newCrossFieldRangeTable();
|
|
297
|
+
const removedCrossFieldKeys: CrossFieldRangeTable<boolean> = newCrossFieldRangeTable();
|
|
298
|
+
|
|
299
|
+
const composedRoots = composeRootTables(
|
|
300
|
+
change1,
|
|
301
|
+
change2,
|
|
302
|
+
composedNodeToParent,
|
|
303
|
+
movedCrossFieldKeys,
|
|
304
|
+
removedCrossFieldKeys,
|
|
305
|
+
pendingCompositions,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
const crossFieldTable = newComposeTable(
|
|
309
|
+
change1,
|
|
310
|
+
change2,
|
|
311
|
+
composedRoots,
|
|
312
|
+
movedCrossFieldKeys,
|
|
313
|
+
removedCrossFieldKeys,
|
|
314
|
+
pendingCompositions,
|
|
315
|
+
);
|
|
251
316
|
|
|
252
317
|
const composedFields = this.composeFieldMaps(
|
|
253
318
|
change1.fieldChanges,
|
|
@@ -268,17 +333,32 @@ export class ModularChangeFamily
|
|
|
268
333
|
revisionMetadata,
|
|
269
334
|
);
|
|
270
335
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
)
|
|
336
|
+
for (const entry of crossFieldTable.renamesToDelete.entries()) {
|
|
337
|
+
deleteNodeRenameFrom(crossFieldTable.composedRootNodes, entry.start, entry.length);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
for (const [nodeId, location] of crossFieldTable.movedNodeToParent.entries()) {
|
|
341
|
+
// Moved nodes are from change2.
|
|
342
|
+
// If there is a corresponding node in change1, then composedNodeToParent will already have the correct entry,
|
|
343
|
+
// because the location of the node is the same in change1 and the composed change
|
|
344
|
+
// (since they have the same input context).
|
|
345
|
+
if (crossFieldTable.newToBaseNodeId.get(nodeId) === undefined) {
|
|
346
|
+
composedNodeToParent.set(nodeId, location);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
276
350
|
return {
|
|
277
351
|
fieldChanges: composedFields,
|
|
278
352
|
nodeChanges: composedNodeChanges,
|
|
279
353
|
nodeToParent: composedNodeToParent,
|
|
280
354
|
nodeAliases: composedNodeAliases,
|
|
281
|
-
crossFieldKeys:
|
|
355
|
+
crossFieldKeys: composeCrossFieldKeyTables(
|
|
356
|
+
change1.crossFieldKeys,
|
|
357
|
+
change2.crossFieldKeys,
|
|
358
|
+
crossFieldTable.movedCrossFieldKeys,
|
|
359
|
+
crossFieldTable.removedCrossFieldKeys,
|
|
360
|
+
),
|
|
361
|
+
rootNodes: composedRoots,
|
|
282
362
|
};
|
|
283
363
|
}
|
|
284
364
|
|
|
@@ -290,17 +370,16 @@ export class ModularChangeFamily
|
|
|
290
370
|
): void {
|
|
291
371
|
const context = crossFieldTable.fieldToContext.get(fieldChange);
|
|
292
372
|
assert(context !== undefined, 0x8cc /* Should have context for every invalidated field */);
|
|
293
|
-
const {
|
|
373
|
+
const { change1: fieldChange1, change2: fieldChange2, composedChange } = context;
|
|
374
|
+
|
|
375
|
+
crossFieldTable.pendingCompositions.affectedBaseFields.delete(
|
|
376
|
+
fieldIdKeyFromFieldId(context.fieldId),
|
|
377
|
+
);
|
|
294
378
|
|
|
295
379
|
const rebaser = getChangeHandler(this.fieldKinds, composedChange.fieldKind).rebaser;
|
|
296
380
|
const composeNodes = (child1: NodeId | undefined, child2: NodeId | undefined): NodeId => {
|
|
297
|
-
if (
|
|
298
|
-
child1
|
|
299
|
-
child2 !== undefined &&
|
|
300
|
-
getFromChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2) === undefined
|
|
301
|
-
) {
|
|
302
|
-
setInChangeAtomIdMap(crossFieldTable.newToBaseNodeId, child2, child1);
|
|
303
|
-
crossFieldTable.pendingCompositions.nodeIdsToCompose.push([child1, child2]);
|
|
381
|
+
if (child1 !== undefined && child2 !== undefined) {
|
|
382
|
+
addNodesToCompose(crossFieldTable, child1, child2);
|
|
304
383
|
}
|
|
305
384
|
|
|
306
385
|
return child1 ?? child2 ?? fail(0xb22 /* Should not compose two undefined nodes */);
|
|
@@ -311,7 +390,7 @@ export class ModularChangeFamily
|
|
|
311
390
|
fieldChange2,
|
|
312
391
|
composeNodes,
|
|
313
392
|
genId,
|
|
314
|
-
new
|
|
393
|
+
new ComposeNodeManagerI(crossFieldTable, context.fieldId, false),
|
|
315
394
|
revisionMetadata,
|
|
316
395
|
);
|
|
317
396
|
composedChange.change = brand(amendedChange);
|
|
@@ -323,7 +402,7 @@ export class ModularChangeFamily
|
|
|
323
402
|
* - discovering that two node changesets refer to the same node (`nodeIdsToCompose`)
|
|
324
403
|
* - a previously composed field being invalidated by a cross field effect (`invalidatedFields`)
|
|
325
404
|
* - a field which was copied directly from an input changeset being invalidated by a cross field effect
|
|
326
|
-
* (`affectedBaseFields`
|
|
405
|
+
* (`affectedBaseFields`)
|
|
327
406
|
*
|
|
328
407
|
* Updating an element may invalidate further elements. This function runs until there is no more invalidation.
|
|
329
408
|
*/
|
|
@@ -331,72 +410,59 @@ export class ModularChangeFamily
|
|
|
331
410
|
table: ComposeTable,
|
|
332
411
|
composedFields: FieldChangeMap,
|
|
333
412
|
composedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
334
|
-
composedNodeToParent: ChangeAtomIdBTree<
|
|
413
|
+
composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
335
414
|
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
336
415
|
genId: IdAllocator,
|
|
337
416
|
metadata: RevisionMetadataSource,
|
|
338
417
|
): void {
|
|
339
418
|
const pending = table.pendingCompositions;
|
|
340
|
-
while (
|
|
341
|
-
|
|
342
|
-
pending.nodeIdsToCompose.length > 0 ||
|
|
343
|
-
pending.affectedBaseFields.length > 0 ||
|
|
344
|
-
pending.affectedNewFields.length > 0
|
|
345
|
-
) {
|
|
346
|
-
// Note that the call to `composeNodesById` can add entries to `crossFieldTable.nodeIdPairs`.
|
|
347
|
-
for (const [id1, id2] of pending.nodeIdsToCompose) {
|
|
348
|
-
this.composeNodesById(
|
|
349
|
-
table.baseChange.nodeChanges,
|
|
350
|
-
table.newChange.nodeChanges,
|
|
351
|
-
composedNodes,
|
|
352
|
-
composedNodeToParent,
|
|
353
|
-
nodeAliases,
|
|
354
|
-
id1,
|
|
355
|
-
id2,
|
|
356
|
-
genId,
|
|
357
|
-
table,
|
|
358
|
-
metadata,
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
pending.nodeIdsToCompose.length = 0;
|
|
363
|
-
|
|
364
|
-
this.composeAffectedFields(
|
|
419
|
+
while (pending.nodeIdsToCompose.length > 0 || pending.affectedBaseFields.length > 0) {
|
|
420
|
+
this.processPendingNodeCompositions(
|
|
365
421
|
table,
|
|
366
|
-
table.baseChange,
|
|
367
|
-
true,
|
|
368
|
-
pending.affectedBaseFields,
|
|
369
|
-
composedFields,
|
|
370
422
|
composedNodes,
|
|
423
|
+
composedNodeToParent,
|
|
424
|
+
nodeAliases,
|
|
371
425
|
genId,
|
|
372
426
|
metadata,
|
|
373
427
|
);
|
|
374
428
|
|
|
375
429
|
this.composeAffectedFields(
|
|
376
430
|
table,
|
|
377
|
-
table.
|
|
378
|
-
|
|
379
|
-
pending.affectedNewFields,
|
|
431
|
+
table.baseChange,
|
|
432
|
+
pending.affectedBaseFields,
|
|
380
433
|
composedFields,
|
|
381
434
|
composedNodes,
|
|
382
435
|
genId,
|
|
383
436
|
metadata,
|
|
384
437
|
);
|
|
385
|
-
|
|
386
|
-
this.processInvalidatedCompositions(table, genId, metadata);
|
|
387
438
|
}
|
|
388
439
|
}
|
|
389
440
|
|
|
390
|
-
private
|
|
441
|
+
private processPendingNodeCompositions(
|
|
391
442
|
table: ComposeTable,
|
|
443
|
+
composedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
444
|
+
composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
445
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
392
446
|
genId: IdAllocator,
|
|
393
447
|
metadata: RevisionMetadataSource,
|
|
394
448
|
): void {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
449
|
+
// Note that the call to `composeNodesById` can add entries to `crossFieldTable.nodeIdPairs`.
|
|
450
|
+
for (const [id1, id2] of table.pendingCompositions.nodeIdsToCompose) {
|
|
451
|
+
this.composeNodesById(
|
|
452
|
+
table.baseChange,
|
|
453
|
+
table.newChange,
|
|
454
|
+
composedNodes,
|
|
455
|
+
composedNodeToParent,
|
|
456
|
+
nodeAliases,
|
|
457
|
+
id1,
|
|
458
|
+
id2,
|
|
459
|
+
genId,
|
|
460
|
+
table,
|
|
461
|
+
metadata,
|
|
462
|
+
);
|
|
399
463
|
}
|
|
464
|
+
|
|
465
|
+
table.pendingCompositions.nodeIdsToCompose.length = 0;
|
|
400
466
|
}
|
|
401
467
|
|
|
402
468
|
/**
|
|
@@ -413,63 +479,79 @@ export class ModularChangeFamily
|
|
|
413
479
|
private composeAffectedFields(
|
|
414
480
|
table: ComposeTable,
|
|
415
481
|
change: ModularChangeset,
|
|
416
|
-
areBaseFields: boolean,
|
|
417
482
|
affectedFields: BTree<FieldIdKey, true>,
|
|
418
483
|
composedFields: FieldChangeMap,
|
|
419
484
|
composedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
420
485
|
genId: IdAllocator,
|
|
421
486
|
metadata: RevisionMetadataSource,
|
|
422
487
|
): void {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
488
|
+
const fieldsToProcess = affectedFields.clone();
|
|
489
|
+
affectedFields.clear();
|
|
490
|
+
|
|
491
|
+
for (const fieldIdKey of fieldsToProcess.keys()) {
|
|
492
|
+
const fieldId = fieldIdFromFieldIdKey(fieldIdKey);
|
|
493
|
+
const fieldChange = fieldChangeFromId(change, fieldId);
|
|
426
494
|
|
|
427
495
|
if (
|
|
428
496
|
table.fieldToContext.has(fieldChange) ||
|
|
429
497
|
table.newFieldToBaseField.has(fieldChange)
|
|
430
498
|
) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
499
|
+
this.composeInvalidatedField(fieldChange, table, genId, metadata);
|
|
500
|
+
} else {
|
|
501
|
+
this.composeFieldWithNoNewChange(
|
|
502
|
+
table,
|
|
503
|
+
fieldChange,
|
|
504
|
+
fieldId,
|
|
505
|
+
composedFields,
|
|
506
|
+
composedNodes,
|
|
507
|
+
genId,
|
|
508
|
+
metadata,
|
|
509
|
+
);
|
|
435
510
|
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
436
513
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
table,
|
|
448
|
-
metadata,
|
|
449
|
-
);
|
|
514
|
+
private composeFieldWithNoNewChange(
|
|
515
|
+
table: ComposeTable,
|
|
516
|
+
baseFieldChange: FieldChange,
|
|
517
|
+
fieldId: FieldId,
|
|
518
|
+
composedFields: FieldChangeMap,
|
|
519
|
+
composedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
520
|
+
genId: IdAllocator,
|
|
521
|
+
metadata: RevisionMetadataSource,
|
|
522
|
+
): void {
|
|
523
|
+
const emptyChange = this.createEmptyFieldChange(baseFieldChange.fieldKind);
|
|
450
524
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
525
|
+
const composedField = this.composeFieldChanges(
|
|
526
|
+
fieldId,
|
|
527
|
+
baseFieldChange,
|
|
528
|
+
emptyChange,
|
|
529
|
+
genId,
|
|
530
|
+
table,
|
|
531
|
+
metadata,
|
|
532
|
+
);
|
|
455
533
|
|
|
456
|
-
|
|
457
|
-
|
|
534
|
+
if (fieldId.nodeId === undefined) {
|
|
535
|
+
composedFields.set(fieldId.field, composedField);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
458
538
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
539
|
+
const nodeId = normalizeNodeId(
|
|
540
|
+
getFromChangeAtomIdMap(table.newToBaseNodeId, fieldId.nodeId) ?? fieldId.nodeId,
|
|
541
|
+
table.baseChange.nodeAliases,
|
|
542
|
+
);
|
|
464
543
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
544
|
+
// We clone the node changeset before mutating it, as it may be from one of the input changesets.
|
|
545
|
+
const nodeChangeset: Mutable<NodeChangeset> = cloneNodeChangeset(
|
|
546
|
+
nodeChangeFromId(composedNodes, table.baseChange.nodeAliases, nodeId),
|
|
547
|
+
);
|
|
548
|
+
setInChangeAtomIdMap(composedNodes, nodeId, nodeChangeset);
|
|
468
549
|
|
|
469
|
-
|
|
550
|
+
if (nodeChangeset.fieldChanges === undefined) {
|
|
551
|
+
nodeChangeset.fieldChanges = new Map();
|
|
470
552
|
}
|
|
471
553
|
|
|
472
|
-
|
|
554
|
+
nodeChangeset.fieldChanges.set(fieldId.field, composedField);
|
|
473
555
|
}
|
|
474
556
|
|
|
475
557
|
private composeFieldMaps(
|
|
@@ -488,17 +570,29 @@ export class ModularChangeFamily
|
|
|
488
570
|
for (const [field, fieldChange1] of change1) {
|
|
489
571
|
const fieldId: FieldId = { nodeId: parentId, field };
|
|
490
572
|
const fieldChange2 = change2.get(field);
|
|
573
|
+
|
|
574
|
+
const cachedComposedFieldChange =
|
|
575
|
+
crossFieldTable.fieldToContext.get(fieldChange1)?.composedChange;
|
|
576
|
+
|
|
577
|
+
if (fieldChange2 === undefined && cachedComposedFieldChange !== undefined) {
|
|
578
|
+
// This can happen if the field was previous processed in `composeFieldWithNoNewChange`.
|
|
579
|
+
// If `change2` does not have a change for this field, then without this check we would
|
|
580
|
+
// lose the composed field change and instead simply have `change1`'s change.
|
|
581
|
+
composedFields.set(field, cachedComposedFieldChange);
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
|
|
491
585
|
const composedField =
|
|
492
|
-
fieldChange2
|
|
493
|
-
?
|
|
586
|
+
fieldChange2 === undefined
|
|
587
|
+
? fieldChange1
|
|
588
|
+
: this.composeFieldChanges(
|
|
494
589
|
fieldId,
|
|
495
590
|
fieldChange1,
|
|
496
591
|
fieldChange2,
|
|
497
592
|
genId,
|
|
498
593
|
crossFieldTable,
|
|
499
594
|
revisionMetadata,
|
|
500
|
-
)
|
|
501
|
-
: fieldChange1;
|
|
595
|
+
);
|
|
502
596
|
|
|
503
597
|
composedFields.set(field, composedField);
|
|
504
598
|
}
|
|
@@ -519,7 +613,7 @@ export class ModularChangeFamily
|
|
|
519
613
|
* will be added to `crossFieldTable.pendingCompositions.nodeIdsToCompose`.
|
|
520
614
|
*
|
|
521
615
|
* Any fields which had cross-field information sent to them as part of this field composition
|
|
522
|
-
* will be added to
|
|
616
|
+
* will be added to `affectedBaseFields` in `crossFieldTable.pendingCompositions`.
|
|
523
617
|
*
|
|
524
618
|
* Any composed `FieldChange` which is invalidated by new cross-field information will be added to `crossFieldTable.invalidatedFields`.
|
|
525
619
|
*/
|
|
@@ -538,15 +632,14 @@ export class ModularChangeFamily
|
|
|
538
632
|
change2: change2Normalized,
|
|
539
633
|
} = this.normalizeFieldChanges(change1, change2);
|
|
540
634
|
|
|
541
|
-
const manager = new
|
|
635
|
+
const manager = new ComposeNodeManagerI(crossFieldTable, fieldId);
|
|
542
636
|
|
|
543
637
|
const composedChange = changeHandler.rebaser.compose(
|
|
544
638
|
change1Normalized,
|
|
545
639
|
change2Normalized,
|
|
546
640
|
(child1, child2) => {
|
|
547
641
|
if (child1 !== undefined && child2 !== undefined) {
|
|
548
|
-
|
|
549
|
-
crossFieldTable.pendingCompositions.nodeIdsToCompose.push([child1, child2]);
|
|
642
|
+
addNodesToCompose(crossFieldTable, child1, child2);
|
|
550
643
|
}
|
|
551
644
|
return child1 ?? child2 ?? fail(0xb23 /* Should not compose two undefined nodes */);
|
|
552
645
|
},
|
|
@@ -572,19 +665,19 @@ export class ModularChangeFamily
|
|
|
572
665
|
}
|
|
573
666
|
|
|
574
667
|
private composeNodesById(
|
|
575
|
-
|
|
576
|
-
|
|
668
|
+
change1: ModularChangeset,
|
|
669
|
+
change2: ModularChangeset,
|
|
577
670
|
composedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
578
|
-
composedNodeToParent: ChangeAtomIdBTree<
|
|
579
|
-
|
|
671
|
+
composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
672
|
+
composedAliases: ChangeAtomIdBTree<NodeId>,
|
|
580
673
|
id1: NodeId,
|
|
581
674
|
id2: NodeId,
|
|
582
675
|
idAllocator: IdAllocator,
|
|
583
676
|
crossFieldTable: ComposeTable,
|
|
584
677
|
revisionMetadata: RevisionMetadataSource,
|
|
585
678
|
): void {
|
|
586
|
-
const nodeChangeset1 = nodeChangeFromId(
|
|
587
|
-
const nodeChangeset2 = nodeChangeFromId(
|
|
679
|
+
const nodeChangeset1 = nodeChangeFromId(change1.nodeChanges, change1.nodeAliases, id1);
|
|
680
|
+
const nodeChangeset2 = nodeChangeFromId(change2.nodeChanges, change2.nodeAliases, id2);
|
|
588
681
|
const composedNodeChangeset = this.composeNodeChanges(
|
|
589
682
|
id1,
|
|
590
683
|
nodeChangeset1,
|
|
@@ -599,13 +692,11 @@ export class ModularChangeFamily
|
|
|
599
692
|
if (!areEqualChangeAtomIds(id1, id2)) {
|
|
600
693
|
composedNodes.delete([id2.revision, id2.localId]);
|
|
601
694
|
composedNodeToParent.delete([id2.revision, id2.localId]);
|
|
602
|
-
setInChangeAtomIdMap(
|
|
695
|
+
setInChangeAtomIdMap(composedAliases, id2, id1);
|
|
603
696
|
|
|
604
697
|
// We need to delete id1 to avoid forming a cycle in case id1 already had an alias.
|
|
605
|
-
|
|
698
|
+
composedAliases.delete([id1.revision, id1.localId]);
|
|
606
699
|
}
|
|
607
|
-
|
|
608
|
-
crossFieldTable.composedNodes.add(composedNodeChangeset);
|
|
609
700
|
}
|
|
610
701
|
|
|
611
702
|
private composeNodeChanges(
|
|
@@ -640,7 +731,7 @@ export class ModularChangeFamily
|
|
|
640
731
|
revisionMetadata,
|
|
641
732
|
);
|
|
642
733
|
|
|
643
|
-
const composedNodeChange: NodeChangeset = {};
|
|
734
|
+
const composedNodeChange: Mutable<NodeChangeset> = {};
|
|
644
735
|
|
|
645
736
|
if (composedFieldChanges.size > 0) {
|
|
646
737
|
composedNodeChange.fieldChanges = composedFieldChanges;
|
|
@@ -660,8 +751,8 @@ export class ModularChangeFamily
|
|
|
660
751
|
/**
|
|
661
752
|
* @param change - The change to invert.
|
|
662
753
|
* @param isRollback - Whether the inverted change is meant to rollback a change on a branch as is the case when
|
|
663
|
-
* @param revisionForInvert - The revision for the invert changeset.
|
|
664
754
|
* performing a sandwich rebase.
|
|
755
|
+
* @param revisionForInvert - The revision for the invert changeset.
|
|
665
756
|
*/
|
|
666
757
|
public invert(
|
|
667
758
|
change: TaggedChange<ModularChangeset>,
|
|
@@ -681,6 +772,9 @@ export class ModularChangeFamily
|
|
|
681
772
|
? [{ revision: revisionForInvert, rollbackOf: change.revision }]
|
|
682
773
|
: [{ revision: revisionForInvert }];
|
|
683
774
|
|
|
775
|
+
const noChangeConstraint = change.change.noChangeConstraintOnRevert;
|
|
776
|
+
const noChangeConstraintOnRevert = change.change.noChangeConstraint;
|
|
777
|
+
|
|
684
778
|
if (hasConflicts(change.change)) {
|
|
685
779
|
return makeModularChangeset({
|
|
686
780
|
maxId: change.change.maxId as number,
|
|
@@ -692,9 +786,14 @@ export class ModularChangeFamily
|
|
|
692
786
|
const genId: IdAllocator = idAllocatorFromMaxId(change.change.maxId ?? -1);
|
|
693
787
|
|
|
694
788
|
const crossFieldTable: InvertTable = {
|
|
695
|
-
|
|
789
|
+
change: change.change,
|
|
790
|
+
entries: newChangeAtomIdRangeMap(),
|
|
696
791
|
originalFieldToContext: new Map(),
|
|
792
|
+
invertRevision: revisionForInvert,
|
|
697
793
|
invertedNodeToParent: brand(change.change.nodeToParent.clone()),
|
|
794
|
+
invalidatedFields: new Set(),
|
|
795
|
+
invertedRoots: invertRootTable(change.change, isRollback),
|
|
796
|
+
attachToDetachId: newChangeAtomIdTransform(),
|
|
698
797
|
};
|
|
699
798
|
const { revInfos: oldRevInfos } = getRevInfoFromTaggedChanges([change]);
|
|
700
799
|
const revisionMetadata = revisionMetadataSourceFromInfo(oldRevInfos);
|
|
@@ -735,7 +834,7 @@ export class ModularChangeFamily
|
|
|
735
834
|
context !== undefined,
|
|
736
835
|
0x851 /* Should have context for every invalidated field */,
|
|
737
836
|
);
|
|
738
|
-
const { invertedField
|
|
837
|
+
const { invertedField } = context;
|
|
739
838
|
|
|
740
839
|
const amendedChange = getChangeHandler(
|
|
741
840
|
this.fieldKinds,
|
|
@@ -745,7 +844,7 @@ export class ModularChangeFamily
|
|
|
745
844
|
isRollback,
|
|
746
845
|
genId,
|
|
747
846
|
revisionForInvert,
|
|
748
|
-
new
|
|
847
|
+
new InvertNodeManagerI(crossFieldTable, context.fieldId),
|
|
749
848
|
revisionMetadata,
|
|
750
849
|
);
|
|
751
850
|
invertedField.change = brand(amendedChange);
|
|
@@ -754,16 +853,21 @@ export class ModularChangeFamily
|
|
|
754
853
|
|
|
755
854
|
const crossFieldKeys = this.makeCrossFieldKeyTable(invertedFields, invertedNodes);
|
|
756
855
|
|
|
856
|
+
this.processInvertRenames(crossFieldTable);
|
|
857
|
+
|
|
757
858
|
return makeModularChangeset({
|
|
758
859
|
fieldChanges: invertedFields,
|
|
759
860
|
nodeChanges: invertedNodes,
|
|
760
861
|
nodeToParent: crossFieldTable.invertedNodeToParent,
|
|
862
|
+
rootNodes: crossFieldTable.invertedRoots,
|
|
761
863
|
nodeAliases: change.change.nodeAliases,
|
|
762
864
|
crossFieldKeys,
|
|
763
865
|
maxId: genId.getMaxId(),
|
|
764
866
|
revisions: revInfos,
|
|
765
867
|
constraintViolationCount: change.change.constraintViolationCountOnRevert,
|
|
766
868
|
constraintViolationCountOnRevert: change.change.constraintViolationCount,
|
|
869
|
+
noChangeConstraint,
|
|
870
|
+
noChangeConstraintOnRevert,
|
|
767
871
|
destroys,
|
|
768
872
|
});
|
|
769
873
|
}
|
|
@@ -781,7 +885,7 @@ export class ModularChangeFamily
|
|
|
781
885
|
|
|
782
886
|
for (const [field, fieldChange] of changes) {
|
|
783
887
|
const fieldId = { nodeId: parentId, field };
|
|
784
|
-
const manager = new
|
|
888
|
+
const manager = new InvertNodeManagerI(crossFieldTable, fieldId);
|
|
785
889
|
const invertedChange = getChangeHandler(
|
|
786
890
|
this.fieldKinds,
|
|
787
891
|
fieldChange.fieldKind,
|
|
@@ -818,7 +922,7 @@ export class ModularChangeFamily
|
|
|
818
922
|
revisionMetadata: RevisionMetadataSource,
|
|
819
923
|
revisionForInvert: RevisionTag,
|
|
820
924
|
): NodeChangeset {
|
|
821
|
-
const inverse: NodeChangeset = {};
|
|
925
|
+
const inverse: Mutable<NodeChangeset> = {};
|
|
822
926
|
|
|
823
927
|
// If the node has a constraint, it should be inverted to a node-exist-on-revert constraint. This ensure that if
|
|
824
928
|
// the inverse is inverted again, the original input constraint will be restored.
|
|
@@ -848,6 +952,17 @@ export class ModularChangeFamily
|
|
|
848
952
|
return inverse;
|
|
849
953
|
}
|
|
850
954
|
|
|
955
|
+
private processInvertRenames(table: InvertTable): void {
|
|
956
|
+
for (const {
|
|
957
|
+
start: newAttachId,
|
|
958
|
+
value: originalDetachId,
|
|
959
|
+
length,
|
|
960
|
+
} of table.attachToDetachId.entries()) {
|
|
961
|
+
// Note that the detach location is already set in `invertDetach`.
|
|
962
|
+
addNodeRename(table.invertedRoots, originalDetachId, newAttachId, length, undefined);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
851
966
|
public rebase(
|
|
852
967
|
taggedChange: TaggedChange<ModularChangeset>,
|
|
853
968
|
potentiallyConflictedOver: TaggedChange<ModularChangeset>,
|
|
@@ -867,17 +982,41 @@ export class ModularChangeFamily
|
|
|
867
982
|
const idState: IdAllocationState = { maxId };
|
|
868
983
|
const genId: IdAllocator = idAllocatorFromState(idState);
|
|
869
984
|
|
|
985
|
+
const affectedBaseFields: TupleBTree<FieldIdKey, boolean> = newTupleBTree();
|
|
986
|
+
const nodesToRebase: [newChangeset: NodeId, baseChangeset: NodeId][] = [];
|
|
987
|
+
|
|
988
|
+
const rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation> = brand(
|
|
989
|
+
change.nodeToParent.clone(),
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
const rebaseVersion = Math.max(
|
|
993
|
+
change.rebaseVersion,
|
|
994
|
+
over.change.rebaseVersion,
|
|
995
|
+
) as RebaseVersion;
|
|
996
|
+
|
|
997
|
+
const rebasedRootNodes = rebaseRoots(
|
|
998
|
+
change,
|
|
999
|
+
over.change,
|
|
1000
|
+
affectedBaseFields,
|
|
1001
|
+
nodesToRebase,
|
|
1002
|
+
rebasedNodeToParent,
|
|
1003
|
+
rebaseVersion,
|
|
1004
|
+
);
|
|
870
1005
|
const crossFieldTable: RebaseTable = {
|
|
871
|
-
|
|
1006
|
+
rebaseVersion,
|
|
1007
|
+
entries: newDetachedEntryMap(),
|
|
872
1008
|
newChange: change,
|
|
873
1009
|
baseChange: over.change,
|
|
874
1010
|
baseFieldToContext: new Map(),
|
|
1011
|
+
baseRoots: over.change.rootNodes,
|
|
1012
|
+
rebasedRootNodes,
|
|
875
1013
|
baseToRebasedNodeId: newTupleBTree(),
|
|
876
1014
|
rebasedFields: new Set(),
|
|
877
|
-
rebasedNodeToParent
|
|
878
|
-
|
|
1015
|
+
rebasedNodeToParent,
|
|
1016
|
+
rebasedDetachLocations: newChangeAtomIdRangeMap(),
|
|
1017
|
+
movedDetaches: newChangeAtomIdRangeMap(),
|
|
879
1018
|
nodeIdPairs: [],
|
|
880
|
-
affectedBaseFields
|
|
1019
|
+
affectedBaseFields,
|
|
881
1020
|
fieldsWithUnattachedChild: new Set(),
|
|
882
1021
|
};
|
|
883
1022
|
|
|
@@ -893,13 +1032,14 @@ export class ModularChangeFamily
|
|
|
893
1032
|
const rebasedNodes: ChangeAtomIdBTree<NodeChangeset> = brand(change.nodeChanges.clone());
|
|
894
1033
|
|
|
895
1034
|
const rebasedFields = this.rebaseIntersectingFields(
|
|
1035
|
+
nodesToRebase,
|
|
896
1036
|
crossFieldTable,
|
|
897
1037
|
rebasedNodes,
|
|
898
1038
|
genId,
|
|
899
1039
|
rebaseMetadata,
|
|
900
1040
|
);
|
|
901
1041
|
|
|
902
|
-
this.
|
|
1042
|
+
this.rebaseInvalidatedFields(
|
|
903
1043
|
rebasedFields,
|
|
904
1044
|
rebasedNodes,
|
|
905
1045
|
crossFieldTable,
|
|
@@ -907,40 +1047,86 @@ export class ModularChangeFamily
|
|
|
907
1047
|
genId,
|
|
908
1048
|
);
|
|
909
1049
|
|
|
1050
|
+
fixupRebasedDetachLocations(crossFieldTable);
|
|
1051
|
+
|
|
910
1052
|
const constraintState = newConstraintState(change.constraintViolationCount ?? 0);
|
|
911
1053
|
const revertConstraintState = newConstraintState(
|
|
912
1054
|
change.constraintViolationCountOnRevert ?? 0,
|
|
913
1055
|
);
|
|
914
|
-
|
|
1056
|
+
|
|
1057
|
+
let noChangeConstraint = change.noChangeConstraint;
|
|
1058
|
+
if (noChangeConstraint !== undefined && !noChangeConstraint.violated) {
|
|
1059
|
+
noChangeConstraint = { violated: true };
|
|
1060
|
+
constraintState.violationCount += 1;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
this.updateConstraints(
|
|
915
1064
|
rebasedFields,
|
|
916
|
-
|
|
917
|
-
|
|
1065
|
+
rebasedNodes,
|
|
1066
|
+
rebasedRootNodes,
|
|
918
1067
|
constraintState,
|
|
919
1068
|
revertConstraintState,
|
|
920
|
-
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
const fieldsWithRootMoves = getFieldsWithRootMoves(
|
|
1072
|
+
crossFieldTable.rebasedRootNodes,
|
|
1073
|
+
change.nodeAliases,
|
|
1074
|
+
);
|
|
1075
|
+
|
|
1076
|
+
const fieldToRootChanges = getFieldToRootChanges(
|
|
1077
|
+
crossFieldTable.rebasedRootNodes,
|
|
1078
|
+
change.nodeAliases,
|
|
921
1079
|
);
|
|
922
1080
|
|
|
923
1081
|
const rebased = makeModularChangeset({
|
|
924
|
-
fieldChanges: this.pruneFieldMap(
|
|
1082
|
+
fieldChanges: this.pruneFieldMap(
|
|
1083
|
+
rebasedFields,
|
|
1084
|
+
undefined,
|
|
1085
|
+
rebasedNodes,
|
|
1086
|
+
crossFieldTable.rebasedNodeToParent,
|
|
1087
|
+
change.nodeAliases,
|
|
1088
|
+
crossFieldTable.rebasedRootNodes,
|
|
1089
|
+
fieldsWithRootMoves,
|
|
1090
|
+
fieldToRootChanges,
|
|
1091
|
+
),
|
|
925
1092
|
nodeChanges: rebasedNodes,
|
|
926
1093
|
nodeToParent: crossFieldTable.rebasedNodeToParent,
|
|
1094
|
+
rootNodes: this.pruneRoots(
|
|
1095
|
+
crossFieldTable.rebasedRootNodes,
|
|
1096
|
+
rebasedNodes,
|
|
1097
|
+
crossFieldTable.rebasedNodeToParent,
|
|
1098
|
+
change.nodeAliases,
|
|
1099
|
+
fieldsWithRootMoves,
|
|
1100
|
+
fieldToRootChanges,
|
|
1101
|
+
),
|
|
1102
|
+
// TODO: Do we need to include aliases for node changesets added during rebasing?
|
|
927
1103
|
nodeAliases: change.nodeAliases,
|
|
928
|
-
crossFieldKeys:
|
|
1104
|
+
crossFieldKeys: rebaseCrossFieldKeys(
|
|
1105
|
+
change.crossFieldKeys,
|
|
1106
|
+
crossFieldTable.movedDetaches,
|
|
1107
|
+
crossFieldTable.rebasedDetachLocations,
|
|
1108
|
+
),
|
|
929
1109
|
maxId: idState.maxId,
|
|
930
1110
|
revisions: change.revisions,
|
|
931
1111
|
constraintViolationCount: constraintState.violationCount,
|
|
932
1112
|
constraintViolationCountOnRevert: revertConstraintState.violationCount,
|
|
1113
|
+
noChangeConstraint,
|
|
1114
|
+
noChangeConstraintOnRevert: change.noChangeConstraintOnRevert,
|
|
933
1115
|
builds: change.builds,
|
|
934
1116
|
destroys: change.destroys,
|
|
935
1117
|
refreshers: change.refreshers,
|
|
1118
|
+
rebaseVersion,
|
|
936
1119
|
});
|
|
937
1120
|
|
|
1121
|
+
// XXX: This is an expensive assert which should be disabled before merging.
|
|
1122
|
+
validateChangeset(rebased, this.fieldKinds);
|
|
938
1123
|
return rebased;
|
|
939
1124
|
}
|
|
940
1125
|
|
|
941
1126
|
// This performs a first pass on all fields which have both new and base changes.
|
|
942
1127
|
// TODO: Can we also handle additional passes in this method?
|
|
943
1128
|
private rebaseIntersectingFields(
|
|
1129
|
+
rootChanges: [newChangeset: NodeId, baseChangeset: NodeId][],
|
|
944
1130
|
crossFieldTable: RebaseTable,
|
|
945
1131
|
rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
946
1132
|
genId: IdAllocator,
|
|
@@ -957,6 +1143,18 @@ export class ModularChangeFamily
|
|
|
957
1143
|
metadata,
|
|
958
1144
|
);
|
|
959
1145
|
|
|
1146
|
+
for (const [newChildChange, baseChildChange] of rootChanges) {
|
|
1147
|
+
const rebasedNode = this.rebaseNodeChange(
|
|
1148
|
+
newChildChange,
|
|
1149
|
+
baseChildChange,
|
|
1150
|
+
genId,
|
|
1151
|
+
crossFieldTable,
|
|
1152
|
+
metadata,
|
|
1153
|
+
);
|
|
1154
|
+
|
|
1155
|
+
setInChangeAtomIdMap(rebasedNodes, newChildChange, rebasedNode);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
960
1158
|
// This loop processes all fields which have both base and new changes.
|
|
961
1159
|
// Note that the call to `rebaseNodeChange` can add entries to `crossFieldTable.nodeIdPairs`.
|
|
962
1160
|
for (const [newId, baseId, _attachState] of crossFieldTable.nodeIdPairs) {
|
|
@@ -974,146 +1172,150 @@ export class ModularChangeFamily
|
|
|
974
1172
|
return rebasedFields;
|
|
975
1173
|
}
|
|
976
1174
|
|
|
977
|
-
|
|
978
|
-
|
|
1175
|
+
private rebaseFieldWithoutNewChanges(
|
|
1176
|
+
baseFieldChange: FieldChange,
|
|
1177
|
+
baseFieldId: FieldId,
|
|
1178
|
+
crossFieldTable: RebaseTable,
|
|
979
1179
|
rebasedFields: FieldChangeMap,
|
|
980
1180
|
rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
981
|
-
crossFieldTable: RebaseTable,
|
|
982
1181
|
genId: IdAllocator,
|
|
983
1182
|
metadata: RebaseRevisionMetadata,
|
|
984
|
-
): void {
|
|
985
|
-
const baseChange = crossFieldTable.baseChange;
|
|
986
|
-
for (const [revision, localId, fieldKey] of crossFieldTable.affectedBaseFields.keys()) {
|
|
987
|
-
const baseNodeId =
|
|
988
|
-
localId !== undefined
|
|
989
|
-
? normalizeNodeId({ revision, localId }, baseChange.nodeAliases)
|
|
990
|
-
: undefined;
|
|
991
|
-
|
|
992
|
-
const baseFieldChange = fieldMapFromNodeId(
|
|
993
|
-
baseChange.fieldChanges,
|
|
994
|
-
baseChange.nodeChanges,
|
|
995
|
-
baseNodeId,
|
|
996
|
-
).get(fieldKey);
|
|
997
1183
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1184
|
+
/**
|
|
1185
|
+
* The ID of a node in `baseFieldChange` which should be included in the rebased field change.
|
|
1186
|
+
*/
|
|
1187
|
+
baseNodeId?: NodeId,
|
|
1188
|
+
): void {
|
|
1189
|
+
// This field has no changes in the new changeset, otherwise it would have been added to
|
|
1190
|
+
// `crossFieldTable.baseFieldToContext` when processing fields with both base and new changes.
|
|
1191
|
+
const rebaseChild = (
|
|
1192
|
+
child: NodeId | undefined,
|
|
1193
|
+
baseChild: NodeId | undefined,
|
|
1194
|
+
stateChange: NodeAttachState | undefined,
|
|
1195
|
+
): NodeId | undefined => {
|
|
1196
|
+
assert(child === undefined, 0x9c3 /* There should be no new changes in this field */);
|
|
1197
|
+
if (baseChild === undefined || baseNodeId === undefined) {
|
|
1198
|
+
return undefined;
|
|
1005
1199
|
}
|
|
1006
1200
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
assert(child === undefined, 0x9c3 /* There should be no new changes in this field */);
|
|
1015
|
-
return undefined;
|
|
1016
|
-
};
|
|
1201
|
+
return areEqualChangeAtomIds(
|
|
1202
|
+
normalizeNodeId(baseChild, crossFieldTable.baseChange.nodeAliases),
|
|
1203
|
+
baseNodeId,
|
|
1204
|
+
)
|
|
1205
|
+
? baseNodeId
|
|
1206
|
+
: undefined;
|
|
1207
|
+
};
|
|
1017
1208
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1209
|
+
const handler = getChangeHandler(this.fieldKinds, baseFieldChange.fieldKind);
|
|
1210
|
+
const fieldChange: FieldChange = {
|
|
1211
|
+
...baseFieldChange,
|
|
1212
|
+
change: brand(handler.createEmpty()),
|
|
1213
|
+
};
|
|
1023
1214
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1215
|
+
const rebasedNodeId =
|
|
1216
|
+
baseFieldId.nodeId === undefined
|
|
1217
|
+
? undefined
|
|
1218
|
+
: rebasedNodeIdFromBaseNodeId(crossFieldTable, baseFieldId.nodeId);
|
|
1028
1219
|
|
|
1029
|
-
|
|
1030
|
-
const rebasedField: unknown = handler.rebaser.rebase(
|
|
1031
|
-
fieldChange.change,
|
|
1032
|
-
baseFieldChange.change,
|
|
1033
|
-
rebaseChild,
|
|
1034
|
-
genId,
|
|
1035
|
-
new RebaseManager(crossFieldTable, baseFieldChange, fieldId),
|
|
1036
|
-
metadata,
|
|
1037
|
-
);
|
|
1220
|
+
const fieldId: FieldId = { nodeId: rebasedNodeId, field: baseFieldId.field };
|
|
1038
1221
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1222
|
+
const rebasedField: unknown = handler.rebaser.rebase(
|
|
1223
|
+
fieldChange.change,
|
|
1224
|
+
baseFieldChange.change,
|
|
1225
|
+
rebaseChild,
|
|
1226
|
+
genId,
|
|
1227
|
+
new RebaseNodeManagerI(crossFieldTable, fieldId),
|
|
1228
|
+
metadata,
|
|
1229
|
+
crossFieldTable.rebaseVersion,
|
|
1230
|
+
);
|
|
1043
1231
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
rebasedChange: rebasedFieldChange,
|
|
1049
|
-
fieldId,
|
|
1050
|
-
baseNodeIds: [],
|
|
1051
|
-
});
|
|
1052
|
-
crossFieldTable.rebasedFields.add(rebasedFieldChange);
|
|
1232
|
+
const rebasedFieldChange: FieldChange = {
|
|
1233
|
+
...baseFieldChange,
|
|
1234
|
+
change: brand(rebasedField),
|
|
1235
|
+
};
|
|
1053
1236
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1237
|
+
const context: RebaseFieldContext = {
|
|
1238
|
+
newChange: fieldChange,
|
|
1239
|
+
baseChange: baseFieldChange,
|
|
1240
|
+
rebasedChange: rebasedFieldChange,
|
|
1241
|
+
fieldId,
|
|
1242
|
+
baseNodeIds: newTupleBTree(),
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
if (baseNodeId !== undefined) {
|
|
1246
|
+
setInChangeAtomIdMap(context.baseNodeIds, baseNodeId, true);
|
|
1063
1247
|
}
|
|
1064
|
-
}
|
|
1065
1248
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
idAllocator: IdAllocator,
|
|
1072
|
-
): void {
|
|
1073
|
-
this.rebaseFieldsWithoutNewChanges(
|
|
1249
|
+
crossFieldTable.baseFieldToContext.set(baseFieldChange, context);
|
|
1250
|
+
|
|
1251
|
+
crossFieldTable.rebasedFields.add(rebasedFieldChange);
|
|
1252
|
+
|
|
1253
|
+
this.attachRebasedField(
|
|
1074
1254
|
rebasedFields,
|
|
1075
1255
|
rebasedNodes,
|
|
1076
|
-
|
|
1077
|
-
|
|
1256
|
+
crossFieldTable,
|
|
1257
|
+
rebasedFieldChange,
|
|
1258
|
+
fieldId,
|
|
1259
|
+
genId,
|
|
1078
1260
|
metadata,
|
|
1079
1261
|
);
|
|
1080
|
-
|
|
1081
|
-
this.rebaseFieldsWithUnattachedChild(table, metadata, idAllocator);
|
|
1082
|
-
this.rebaseInvalidatedFields(table, metadata, idAllocator);
|
|
1083
1262
|
}
|
|
1084
1263
|
|
|
1085
1264
|
private rebaseInvalidatedFields(
|
|
1265
|
+
rebasedFields: FieldChangeMap,
|
|
1266
|
+
rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
1086
1267
|
crossFieldTable: RebaseTable,
|
|
1087
1268
|
rebaseMetadata: RebaseRevisionMetadata,
|
|
1088
1269
|
genId: IdAllocator,
|
|
1089
1270
|
): void {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1271
|
+
while (crossFieldTable.affectedBaseFields.size > 0) {
|
|
1272
|
+
const baseFields = crossFieldTable.affectedBaseFields.clone();
|
|
1273
|
+
crossFieldTable.affectedBaseFields.clear();
|
|
1274
|
+
|
|
1275
|
+
for (const baseFieldIdKey of baseFields.keys()) {
|
|
1276
|
+
const baseFieldId = normalizeFieldId(
|
|
1277
|
+
fieldIdFromFieldIdKey(baseFieldIdKey),
|
|
1278
|
+
crossFieldTable.baseChange.nodeAliases,
|
|
1279
|
+
);
|
|
1096
1280
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1281
|
+
const baseField = fieldChangeFromId(crossFieldTable.baseChange, baseFieldId);
|
|
1282
|
+
|
|
1283
|
+
assert(
|
|
1284
|
+
baseField !== undefined,
|
|
1285
|
+
0x9c2 /* Cross field key registered for empty field */,
|
|
1286
|
+
);
|
|
1287
|
+
|
|
1288
|
+
const context = crossFieldTable.baseFieldToContext.get(baseField);
|
|
1289
|
+
if (context === undefined) {
|
|
1290
|
+
this.rebaseFieldWithoutNewChanges(
|
|
1291
|
+
baseField,
|
|
1292
|
+
baseFieldId,
|
|
1293
|
+
crossFieldTable,
|
|
1294
|
+
rebasedFields,
|
|
1295
|
+
rebasedNodes,
|
|
1296
|
+
genId,
|
|
1297
|
+
rebaseMetadata,
|
|
1298
|
+
);
|
|
1299
|
+
} else {
|
|
1300
|
+
this.rebaseInvalidatedField(
|
|
1301
|
+
baseField,
|
|
1302
|
+
crossFieldTable,
|
|
1303
|
+
context,
|
|
1304
|
+
rebaseMetadata,
|
|
1305
|
+
genId,
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1105
1309
|
}
|
|
1106
1310
|
}
|
|
1107
1311
|
|
|
1108
1312
|
private rebaseInvalidatedField(
|
|
1109
1313
|
baseField: FieldChange,
|
|
1110
1314
|
crossFieldTable: RebaseTable,
|
|
1315
|
+
context: RebaseFieldContext,
|
|
1111
1316
|
rebaseMetadata: RebaseRevisionMetadata,
|
|
1112
1317
|
genId: IdAllocator,
|
|
1113
|
-
allowInval = false,
|
|
1114
1318
|
): void {
|
|
1115
|
-
const context = crossFieldTable.baseFieldToContext.get(baseField);
|
|
1116
|
-
assert(context !== undefined, 0x852 /* Every field should have a context */);
|
|
1117
1319
|
const {
|
|
1118
1320
|
changeHandler,
|
|
1119
1321
|
change1: fieldChangeset,
|
|
@@ -1128,25 +1330,28 @@ export class ModularChangeFamily
|
|
|
1128
1330
|
return curr;
|
|
1129
1331
|
}
|
|
1130
1332
|
|
|
1131
|
-
if (base !== undefined) {
|
|
1132
|
-
|
|
1133
|
-
if (areEqualChangeAtomIds(base, id)) {
|
|
1134
|
-
return base;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1333
|
+
if (base !== undefined && getFromChangeAtomIdMap(context.baseNodeIds, base) === true) {
|
|
1334
|
+
return base;
|
|
1137
1335
|
}
|
|
1138
1336
|
|
|
1139
1337
|
return undefined;
|
|
1140
1338
|
};
|
|
1141
1339
|
|
|
1340
|
+
let allowInval = false;
|
|
1341
|
+
if (crossFieldTable.fieldsWithUnattachedChild.has(baseField)) {
|
|
1342
|
+
crossFieldTable.fieldsWithUnattachedChild.delete(baseField);
|
|
1343
|
+
allowInval = true;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1142
1346
|
context.rebasedChange.change = brand(
|
|
1143
1347
|
changeHandler.rebaser.rebase(
|
|
1144
1348
|
fieldChangeset,
|
|
1145
1349
|
baseChangeset,
|
|
1146
1350
|
rebaseChild,
|
|
1147
1351
|
genId,
|
|
1148
|
-
new
|
|
1352
|
+
new RebaseNodeManagerI(crossFieldTable, context.fieldId, allowInval),
|
|
1149
1353
|
rebaseMetadata,
|
|
1354
|
+
crossFieldTable.rebaseVersion,
|
|
1150
1355
|
),
|
|
1151
1356
|
);
|
|
1152
1357
|
}
|
|
@@ -1166,14 +1371,20 @@ export class ModularChangeFamily
|
|
|
1166
1371
|
}
|
|
1167
1372
|
const rebasedNode = getFromChangeAtomIdMap(rebasedNodes, nodeId);
|
|
1168
1373
|
if (rebasedNode !== undefined) {
|
|
1169
|
-
|
|
1170
|
-
|
|
1374
|
+
const updatedRebasedNode: Mutable<NodeChangeset> = cloneNodeChangeset(rebasedNode);
|
|
1375
|
+
setInChangeAtomIdMap(rebasedNodes, nodeId, updatedRebasedNode);
|
|
1376
|
+
|
|
1377
|
+
if (updatedRebasedNode.fieldChanges === undefined) {
|
|
1378
|
+
updatedRebasedNode.fieldChanges = new Map([[fieldKey, rebasedField]]);
|
|
1171
1379
|
return;
|
|
1172
1380
|
}
|
|
1173
1381
|
|
|
1174
|
-
assert(
|
|
1175
|
-
|
|
1176
|
-
|
|
1382
|
+
assert(
|
|
1383
|
+
!updatedRebasedNode.fieldChanges.has(fieldKey),
|
|
1384
|
+
0x9c4 /* Expected an empty field */,
|
|
1385
|
+
);
|
|
1386
|
+
updatedRebasedNode.fieldChanges.set(fieldKey, rebasedField);
|
|
1387
|
+
return;
|
|
1177
1388
|
}
|
|
1178
1389
|
|
|
1179
1390
|
const newNode: NodeChangeset = {
|
|
@@ -1183,14 +1394,14 @@ export class ModularChangeFamily
|
|
|
1183
1394
|
setInChangeAtomIdMap(rebasedNodes, nodeId, newNode);
|
|
1184
1395
|
setInChangeAtomIdMap(table.baseToRebasedNodeId, nodeId, nodeId);
|
|
1185
1396
|
|
|
1186
|
-
const
|
|
1397
|
+
const parentBase = getNodeParent(table.baseChange, nodeId);
|
|
1187
1398
|
|
|
1188
1399
|
this.attachRebasedNode(
|
|
1189
1400
|
rebasedFields,
|
|
1190
1401
|
rebasedNodes,
|
|
1191
1402
|
table,
|
|
1192
1403
|
nodeId,
|
|
1193
|
-
|
|
1404
|
+
parentBase,
|
|
1194
1405
|
idAllocator,
|
|
1195
1406
|
metadata,
|
|
1196
1407
|
);
|
|
@@ -1201,65 +1412,100 @@ export class ModularChangeFamily
|
|
|
1201
1412
|
rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
1202
1413
|
table: RebaseTable,
|
|
1203
1414
|
baseNodeId: NodeId,
|
|
1204
|
-
|
|
1415
|
+
parentBase: NodeLocation,
|
|
1205
1416
|
idAllocator: IdAllocator,
|
|
1206
1417
|
metadata: RebaseRevisionMetadata,
|
|
1207
1418
|
): void {
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1419
|
+
if (parentBase.root !== undefined) {
|
|
1420
|
+
const renamedRoot = firstAttachIdFromDetachId(
|
|
1421
|
+
table.baseChange.rootNodes,
|
|
1422
|
+
parentBase.root,
|
|
1423
|
+
1,
|
|
1424
|
+
).value;
|
|
1425
|
+
|
|
1426
|
+
const attachField = table.baseChange.crossFieldKeys.getFirst(
|
|
1427
|
+
{ ...renamedRoot, target: CrossFieldTarget.Destination },
|
|
1428
|
+
1,
|
|
1429
|
+
).value;
|
|
1430
|
+
|
|
1431
|
+
if (attachField === undefined) {
|
|
1432
|
+
const baseDetachLocation = table.baseChange.rootNodes.detachLocations.getFirst(
|
|
1433
|
+
parentBase.root,
|
|
1434
|
+
1,
|
|
1435
|
+
).value;
|
|
1436
|
+
|
|
1437
|
+
assignRootChange(
|
|
1438
|
+
table.rebasedRootNodes,
|
|
1439
|
+
table.rebasedNodeToParent,
|
|
1440
|
+
renamedRoot,
|
|
1441
|
+
baseNodeId,
|
|
1442
|
+
baseDetachLocation,
|
|
1443
|
+
table.rebaseVersion,
|
|
1444
|
+
);
|
|
1445
|
+
|
|
1446
|
+
// We need to make sure the rebased changeset includes the detach location,
|
|
1447
|
+
// so we add that field to `affectedBaseFields` unless it's already been processed.
|
|
1448
|
+
if (
|
|
1449
|
+
baseDetachLocation !== undefined &&
|
|
1450
|
+
!table.baseFieldToContext.has(
|
|
1451
|
+
fieldChangeFromId(table.baseChange, baseDetachLocation),
|
|
1452
|
+
)
|
|
1453
|
+
) {
|
|
1454
|
+
table.affectedBaseFields.set(fieldIdKeyFromFieldId(baseDetachLocation), true);
|
|
1455
|
+
}
|
|
1456
|
+
} else {
|
|
1457
|
+
// The base change inserts this node into `attachField`, so the rebased change should represent this node there.
|
|
1458
|
+
const normalizedAttachField = normalizeFieldId(
|
|
1459
|
+
attachField,
|
|
1460
|
+
table.baseChange.nodeAliases,
|
|
1461
|
+
);
|
|
1462
|
+
|
|
1463
|
+
const entry: DetachedNodeEntry = table.entries.getFirst(renamedRoot, 1).value ?? {};
|
|
1464
|
+
table.entries.set(renamedRoot, 1, { ...entry, nodeChange: baseNodeId });
|
|
1465
|
+
table.affectedBaseFields.set(fieldIdKeyFromFieldId(normalizedAttachField), true);
|
|
1466
|
+
this.attachRebasedNode(
|
|
1467
|
+
rebasedFields,
|
|
1468
|
+
rebasedNodes,
|
|
1469
|
+
table,
|
|
1470
|
+
baseNodeId,
|
|
1471
|
+
{ field: normalizedAttachField },
|
|
1472
|
+
idAllocator,
|
|
1473
|
+
metadata,
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
const parentFieldIdBase = parentBase.field;
|
|
1481
|
+
const baseFieldChange = fieldChangeFromId(table.baseChange, parentFieldIdBase);
|
|
1213
1482
|
|
|
1214
1483
|
const rebasedFieldId = rebasedFieldIdFromBaseId(table, parentFieldIdBase);
|
|
1215
|
-
setInChangeAtomIdMap(table.rebasedNodeToParent, baseNodeId, rebasedFieldId);
|
|
1484
|
+
setInChangeAtomIdMap(table.rebasedNodeToParent, baseNodeId, { field: rebasedFieldId });
|
|
1216
1485
|
|
|
1217
1486
|
const context = table.baseFieldToContext.get(baseFieldChange);
|
|
1218
1487
|
if (context !== undefined) {
|
|
1219
1488
|
// We've already processed this field.
|
|
1220
|
-
// The new child node will be attached in
|
|
1221
|
-
|
|
1222
|
-
|
|
1489
|
+
// The new child node will be attached in the next pass.
|
|
1490
|
+
// Note that adding to `fieldsWithUnattachedChild` allows that field to generate new invalidations,
|
|
1491
|
+
// so to avoid invalidation cycles we make sure we only add to it once per new unattached child.
|
|
1492
|
+
// This is done by checking whether `context.baseNodeIds` already contained `baseNodeId`.
|
|
1493
|
+
if (setInChangeAtomIdMap(context.baseNodeIds, baseNodeId, true)) {
|
|
1494
|
+
table.fieldsWithUnattachedChild.add(baseFieldChange);
|
|
1495
|
+
table.affectedBaseFields.set(fieldIdKeyFromFieldId(parentFieldIdBase), true);
|
|
1496
|
+
}
|
|
1223
1497
|
return;
|
|
1224
1498
|
}
|
|
1225
1499
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
change: brand(handler.createEmpty()),
|
|
1231
|
-
};
|
|
1232
|
-
|
|
1233
|
-
const rebasedChangeset = handler.rebaser.rebase(
|
|
1234
|
-
handler.createEmpty(),
|
|
1235
|
-
baseFieldChange.change,
|
|
1236
|
-
(_idNew, idBase) =>
|
|
1237
|
-
idBase !== undefined && areEqualChangeAtomIds(idBase, baseNodeId)
|
|
1238
|
-
? baseNodeId
|
|
1239
|
-
: undefined,
|
|
1240
|
-
idAllocator,
|
|
1241
|
-
new RebaseManager(table, baseFieldChange, rebasedFieldId),
|
|
1242
|
-
metadata,
|
|
1243
|
-
);
|
|
1244
|
-
|
|
1245
|
-
const rebasedField: FieldChange = { ...baseFieldChange, change: brand(rebasedChangeset) };
|
|
1246
|
-
table.rebasedFields.add(rebasedField);
|
|
1247
|
-
table.baseFieldToContext.set(baseFieldChange, {
|
|
1248
|
-
newChange: fieldChange,
|
|
1249
|
-
baseChange: baseFieldChange,
|
|
1250
|
-
rebasedChange: rebasedField,
|
|
1251
|
-
fieldId: rebasedFieldId,
|
|
1252
|
-
baseNodeIds: [],
|
|
1253
|
-
});
|
|
1254
|
-
|
|
1255
|
-
this.attachRebasedField(
|
|
1500
|
+
this.rebaseFieldWithoutNewChanges(
|
|
1501
|
+
baseFieldChange,
|
|
1502
|
+
parentFieldIdBase,
|
|
1503
|
+
table,
|
|
1256
1504
|
rebasedFields,
|
|
1257
1505
|
rebasedNodes,
|
|
1258
|
-
table,
|
|
1259
|
-
rebasedField,
|
|
1260
|
-
rebasedFieldId,
|
|
1261
1506
|
idAllocator,
|
|
1262
1507
|
metadata,
|
|
1508
|
+
baseNodeId,
|
|
1263
1509
|
);
|
|
1264
1510
|
}
|
|
1265
1511
|
|
|
@@ -1298,7 +1544,7 @@ export class ModularChangeFamily
|
|
|
1298
1544
|
change2: baseChangeset,
|
|
1299
1545
|
} = this.normalizeFieldChanges(fieldChange, baseChange);
|
|
1300
1546
|
|
|
1301
|
-
const manager = new
|
|
1547
|
+
const manager = new RebaseNodeManagerI(crossFieldTable, fieldId);
|
|
1302
1548
|
|
|
1303
1549
|
const rebasedField = changeHandler.rebaser.rebase(
|
|
1304
1550
|
fieldChangeset,
|
|
@@ -1307,6 +1553,7 @@ export class ModularChangeFamily
|
|
|
1307
1553
|
genId,
|
|
1308
1554
|
manager,
|
|
1309
1555
|
revisionMetadata,
|
|
1556
|
+
crossFieldTable.rebaseVersion,
|
|
1310
1557
|
);
|
|
1311
1558
|
|
|
1312
1559
|
const rebasedFieldChange: FieldChange = {
|
|
@@ -1321,7 +1568,7 @@ export class ModularChangeFamily
|
|
|
1321
1568
|
newChange: fieldChange,
|
|
1322
1569
|
rebasedChange: rebasedFieldChange,
|
|
1323
1570
|
fieldId,
|
|
1324
|
-
baseNodeIds:
|
|
1571
|
+
baseNodeIds: newTupleBTree(),
|
|
1325
1572
|
});
|
|
1326
1573
|
|
|
1327
1574
|
crossFieldTable.rebasedFields.add(rebasedFieldChange);
|
|
@@ -1337,8 +1584,16 @@ export class ModularChangeFamily
|
|
|
1337
1584
|
crossFieldTable: RebaseTable,
|
|
1338
1585
|
revisionMetadata: RebaseRevisionMetadata,
|
|
1339
1586
|
): NodeChangeset {
|
|
1340
|
-
const change = nodeChangeFromId(
|
|
1341
|
-
|
|
1587
|
+
const change = nodeChangeFromId(
|
|
1588
|
+
crossFieldTable.newChange.nodeChanges,
|
|
1589
|
+
crossFieldTable.newChange.nodeAliases,
|
|
1590
|
+
newId,
|
|
1591
|
+
);
|
|
1592
|
+
const over = nodeChangeFromId(
|
|
1593
|
+
crossFieldTable.baseChange.nodeChanges,
|
|
1594
|
+
crossFieldTable.baseChange.nodeAliases,
|
|
1595
|
+
baseId,
|
|
1596
|
+
);
|
|
1342
1597
|
|
|
1343
1598
|
const baseMap: FieldChangeMap = over?.fieldChanges ?? new Map();
|
|
1344
1599
|
|
|
@@ -1354,7 +1609,7 @@ export class ModularChangeFamily
|
|
|
1354
1609
|
)
|
|
1355
1610
|
: change.fieldChanges;
|
|
1356
1611
|
|
|
1357
|
-
const rebasedChange: NodeChangeset = {};
|
|
1612
|
+
const rebasedChange: Mutable<NodeChangeset> = {};
|
|
1358
1613
|
|
|
1359
1614
|
if (fieldChanges !== undefined && fieldChanges.size > 0) {
|
|
1360
1615
|
rebasedChange.fieldChanges = fieldChanges;
|
|
@@ -1372,6 +1627,37 @@ export class ModularChangeFamily
|
|
|
1372
1627
|
return rebasedChange;
|
|
1373
1628
|
}
|
|
1374
1629
|
|
|
1630
|
+
private updateConstraints(
|
|
1631
|
+
rebasedFields: FieldChangeMap,
|
|
1632
|
+
rebasedNodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
1633
|
+
rebasedRoots: RootNodeTable,
|
|
1634
|
+
constraintState: ConstraintState,
|
|
1635
|
+
revertConstraintState: ConstraintState,
|
|
1636
|
+
): void {
|
|
1637
|
+
this.updateConstraintsForFields(
|
|
1638
|
+
rebasedFields,
|
|
1639
|
+
NodeAttachState.Attached,
|
|
1640
|
+
NodeAttachState.Attached,
|
|
1641
|
+
constraintState,
|
|
1642
|
+
revertConstraintState,
|
|
1643
|
+
rebasedNodes,
|
|
1644
|
+
);
|
|
1645
|
+
|
|
1646
|
+
for (const [_detachId, nodeId] of rebasedRoots.nodeChanges.entries()) {
|
|
1647
|
+
// XXX: This is incorrect if the rebased changeset attaches the node.
|
|
1648
|
+
// Efficiently computing whether the changeset attaches the node would require maintaining a mapping from node ID to attach ID.
|
|
1649
|
+
const detachedInOutput = true;
|
|
1650
|
+
this.updateConstraintsForNode(
|
|
1651
|
+
nodeId,
|
|
1652
|
+
NodeAttachState.Detached,
|
|
1653
|
+
detachedInOutput ? NodeAttachState.Detached : NodeAttachState.Attached,
|
|
1654
|
+
rebasedNodes,
|
|
1655
|
+
constraintState,
|
|
1656
|
+
revertConstraintState,
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1375
1661
|
private updateConstraintsForFields(
|
|
1376
1662
|
fields: FieldChangeMap,
|
|
1377
1663
|
parentInputAttachState: NodeAttachState,
|
|
@@ -1382,20 +1668,18 @@ export class ModularChangeFamily
|
|
|
1382
1668
|
): void {
|
|
1383
1669
|
for (const field of fields.values()) {
|
|
1384
1670
|
const handler = getChangeHandler(this.fieldKinds, field.fieldKind);
|
|
1385
|
-
for (const [nodeId
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
? NodeAttachState.Detached
|
|
1390
|
-
: NodeAttachState.Attached;
|
|
1391
|
-
const isOutputDetached = outputIndex === undefined;
|
|
1671
|
+
for (const [nodeId] of handler.getNestedChanges(field.change)) {
|
|
1672
|
+
// XXX: This is incorrect if the rebased changeset detaches this node.
|
|
1673
|
+
// Efficiently computing whether the changeset detaches the node would require maintaining a mapping from node ID to detach ID.
|
|
1674
|
+
const isOutputDetached = false;
|
|
1392
1675
|
const outputAttachState =
|
|
1393
1676
|
parentOutputAttachState === NodeAttachState.Detached || isOutputDetached
|
|
1394
1677
|
? NodeAttachState.Detached
|
|
1395
1678
|
: NodeAttachState.Attached;
|
|
1679
|
+
|
|
1396
1680
|
this.updateConstraintsForNode(
|
|
1397
1681
|
nodeId,
|
|
1398
|
-
|
|
1682
|
+
parentInputAttachState,
|
|
1399
1683
|
outputAttachState,
|
|
1400
1684
|
nodes,
|
|
1401
1685
|
constraintState,
|
|
@@ -1413,12 +1697,15 @@ export class ModularChangeFamily
|
|
|
1413
1697
|
constraintState: ConstraintState,
|
|
1414
1698
|
revertConstraintState: ConstraintState,
|
|
1415
1699
|
): void {
|
|
1416
|
-
const node =
|
|
1417
|
-
|
|
1700
|
+
const node = getFromChangeAtomIdMap(nodes, nodeId) ?? fail(0xb24 /* Unknown node ID */);
|
|
1701
|
+
|
|
1702
|
+
const updatedNode: Mutable<NodeChangeset> = { ...node };
|
|
1703
|
+
setInChangeAtomIdMap(nodes, nodeId, updatedNode);
|
|
1704
|
+
|
|
1418
1705
|
if (node.nodeExistsConstraint !== undefined) {
|
|
1419
1706
|
const isNowViolated = inputAttachState === NodeAttachState.Detached;
|
|
1420
1707
|
if (node.nodeExistsConstraint.violated !== isNowViolated) {
|
|
1421
|
-
|
|
1708
|
+
updatedNode.nodeExistsConstraint = {
|
|
1422
1709
|
...node.nodeExistsConstraint,
|
|
1423
1710
|
violated: isNowViolated,
|
|
1424
1711
|
};
|
|
@@ -1428,7 +1715,7 @@ export class ModularChangeFamily
|
|
|
1428
1715
|
if (node.nodeExistsConstraintOnRevert !== undefined) {
|
|
1429
1716
|
const isNowViolated = outputAttachState === NodeAttachState.Detached;
|
|
1430
1717
|
if (node.nodeExistsConstraintOnRevert.violated !== isNowViolated) {
|
|
1431
|
-
|
|
1718
|
+
updatedNode.nodeExistsConstraintOnRevert = {
|
|
1432
1719
|
...node.nodeExistsConstraintOnRevert,
|
|
1433
1720
|
violated: isNowViolated,
|
|
1434
1721
|
};
|
|
@@ -1450,7 +1737,13 @@ export class ModularChangeFamily
|
|
|
1450
1737
|
|
|
1451
1738
|
private pruneFieldMap(
|
|
1452
1739
|
changeset: FieldChangeMap | undefined,
|
|
1740
|
+
parentId: NodeId | undefined,
|
|
1453
1741
|
nodeMap: ChangeAtomIdBTree<NodeChangeset>,
|
|
1742
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
1743
|
+
aliases: ChangeAtomIdBTree<NodeId>,
|
|
1744
|
+
roots: RootNodeTable,
|
|
1745
|
+
fieldsWithRootMoves: TupleBTree<FieldIdKey, boolean>,
|
|
1746
|
+
fieldsToRootChanges: TupleBTree<FieldIdKey, ChangeAtomId[]>,
|
|
1454
1747
|
): FieldChangeMap | undefined {
|
|
1455
1748
|
if (changeset === undefined) {
|
|
1456
1749
|
return undefined;
|
|
@@ -1461,10 +1754,48 @@ export class ModularChangeFamily
|
|
|
1461
1754
|
const handler = getChangeHandler(this.fieldKinds, fieldChange.fieldKind);
|
|
1462
1755
|
|
|
1463
1756
|
const prunedFieldChangeset = handler.rebaser.prune(fieldChange.change, (nodeId) =>
|
|
1464
|
-
this.pruneNodeChange(
|
|
1757
|
+
this.pruneNodeChange(
|
|
1758
|
+
nodeId,
|
|
1759
|
+
nodeMap,
|
|
1760
|
+
nodeToParent,
|
|
1761
|
+
aliases,
|
|
1762
|
+
roots,
|
|
1763
|
+
fieldsWithRootMoves,
|
|
1764
|
+
fieldsToRootChanges,
|
|
1765
|
+
),
|
|
1465
1766
|
);
|
|
1466
1767
|
|
|
1467
|
-
|
|
1768
|
+
const fieldId: FieldId = { nodeId: parentId, field };
|
|
1769
|
+
const fieldIdKey = fieldIdKeyFromFieldId(fieldId);
|
|
1770
|
+
const rootsWithChanges = fieldsToRootChanges.get(fieldIdKey) ?? [];
|
|
1771
|
+
let hasRootWithNodeChange = false;
|
|
1772
|
+
for (const rootId of rootsWithChanges) {
|
|
1773
|
+
const nodeId =
|
|
1774
|
+
getFromChangeAtomIdMap(roots.nodeChanges, rootId) ?? fail("No root change found");
|
|
1775
|
+
|
|
1776
|
+
const isRootChangeEmpty =
|
|
1777
|
+
this.pruneNodeChange(
|
|
1778
|
+
nodeId,
|
|
1779
|
+
nodeMap,
|
|
1780
|
+
nodeToParent,
|
|
1781
|
+
aliases,
|
|
1782
|
+
roots,
|
|
1783
|
+
fieldsWithRootMoves,
|
|
1784
|
+
fieldsToRootChanges,
|
|
1785
|
+
) === undefined;
|
|
1786
|
+
|
|
1787
|
+
if (isRootChangeEmpty) {
|
|
1788
|
+
roots.nodeChanges.delete([rootId.revision, rootId.localId]);
|
|
1789
|
+
tryRemoveDetachLocation(roots, rootId, 1);
|
|
1790
|
+
} else {
|
|
1791
|
+
hasRootWithNodeChange = true;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
const hasRootChanges =
|
|
1796
|
+
hasRootWithNodeChange || fieldsWithRootMoves.get(fieldIdKey) === true;
|
|
1797
|
+
|
|
1798
|
+
if (!handler.isEmpty(prunedFieldChangeset) || hasRootChanges) {
|
|
1468
1799
|
prunedChangeset.set(field, { ...fieldChange, change: brand(prunedFieldChangeset) });
|
|
1469
1800
|
}
|
|
1470
1801
|
}
|
|
@@ -1472,15 +1803,65 @@ export class ModularChangeFamily
|
|
|
1472
1803
|
return prunedChangeset.size > 0 ? prunedChangeset : undefined;
|
|
1473
1804
|
}
|
|
1474
1805
|
|
|
1806
|
+
private pruneRoots(
|
|
1807
|
+
roots: RootNodeTable,
|
|
1808
|
+
nodeMap: ChangeAtomIdBTree<NodeChangeset>,
|
|
1809
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
1810
|
+
aliases: ChangeAtomIdBTree<NodeId>,
|
|
1811
|
+
fieldsWithRootMoves: TupleBTree<FieldIdKey, boolean>,
|
|
1812
|
+
fieldsToRootChanges: TupleBTree<FieldIdKey, ChangeAtomId[]>,
|
|
1813
|
+
): RootNodeTable {
|
|
1814
|
+
const pruned: RootNodeTable = { ...roots, nodeChanges: newTupleBTree() };
|
|
1815
|
+
for (const [rootIdKey, nodeId] of roots.nodeChanges.entries()) {
|
|
1816
|
+
const rootId: ChangeAtomId = { revision: rootIdKey[0], localId: rootIdKey[1] };
|
|
1817
|
+
const hasDetachLocation = roots.detachLocations.getFirst(rootId, 1).value !== undefined;
|
|
1818
|
+
|
|
1819
|
+
// If the root has a detach location it should be pruned by recursion when pruning the field it was detached from.
|
|
1820
|
+
const prunedId = hasDetachLocation
|
|
1821
|
+
? nodeId
|
|
1822
|
+
: this.pruneNodeChange(
|
|
1823
|
+
nodeId,
|
|
1824
|
+
nodeMap,
|
|
1825
|
+
nodeToParent,
|
|
1826
|
+
aliases,
|
|
1827
|
+
roots,
|
|
1828
|
+
fieldsWithRootMoves,
|
|
1829
|
+
fieldsToRootChanges,
|
|
1830
|
+
);
|
|
1831
|
+
|
|
1832
|
+
if (prunedId !== undefined) {
|
|
1833
|
+
pruned.nodeChanges.set(rootIdKey, prunedId);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
tryRemoveDetachLocation(pruned, rootId, 1);
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
return pruned;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1475
1842
|
private pruneNodeChange(
|
|
1476
1843
|
nodeId: NodeId,
|
|
1477
|
-
|
|
1844
|
+
nodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
1845
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
1846
|
+
aliases: ChangeAtomIdBTree<NodeId>,
|
|
1847
|
+
roots: RootNodeTable,
|
|
1848
|
+
fieldsWithRootMoves: TupleBTree<FieldIdKey, boolean>,
|
|
1849
|
+
fieldsToRootChanges: TupleBTree<FieldIdKey, ChangeAtomId[]>,
|
|
1478
1850
|
): NodeId | undefined {
|
|
1479
|
-
const changeset = nodeChangeFromId(
|
|
1851
|
+
const changeset = nodeChangeFromId(nodes, aliases, nodeId);
|
|
1480
1852
|
const prunedFields =
|
|
1481
|
-
changeset.fieldChanges
|
|
1482
|
-
?
|
|
1483
|
-
:
|
|
1853
|
+
changeset.fieldChanges === undefined
|
|
1854
|
+
? undefined
|
|
1855
|
+
: this.pruneFieldMap(
|
|
1856
|
+
changeset.fieldChanges,
|
|
1857
|
+
nodeId,
|
|
1858
|
+
nodes,
|
|
1859
|
+
nodeToParent,
|
|
1860
|
+
aliases,
|
|
1861
|
+
roots,
|
|
1862
|
+
fieldsWithRootMoves,
|
|
1863
|
+
fieldsToRootChanges,
|
|
1864
|
+
);
|
|
1484
1865
|
|
|
1485
1866
|
const prunedChange = { ...changeset, fieldChanges: prunedFields };
|
|
1486
1867
|
if (prunedChange.fieldChanges === undefined) {
|
|
@@ -1488,103 +1869,92 @@ export class ModularChangeFamily
|
|
|
1488
1869
|
}
|
|
1489
1870
|
|
|
1490
1871
|
if (isEmptyNodeChangeset(prunedChange)) {
|
|
1491
|
-
|
|
1872
|
+
const nodeIdKey: [RevisionTag | undefined, ChangesetLocalId] = [
|
|
1873
|
+
nodeId.revision,
|
|
1874
|
+
nodeId.localId,
|
|
1875
|
+
];
|
|
1876
|
+
|
|
1877
|
+
// TODO: Shouldn't we also delete all aliases associated with this node?
|
|
1878
|
+
nodes.delete(nodeIdKey);
|
|
1879
|
+
nodeToParent.delete(nodeIdKey);
|
|
1492
1880
|
return undefined;
|
|
1493
1881
|
} else {
|
|
1494
|
-
setInChangeAtomIdMap(
|
|
1882
|
+
setInChangeAtomIdMap(nodes, nodeId, prunedChange);
|
|
1495
1883
|
return nodeId;
|
|
1496
1884
|
}
|
|
1497
1885
|
}
|
|
1498
1886
|
|
|
1887
|
+
public getRevisions(change: ModularChangeset): Set<RevisionTag | undefined> {
|
|
1888
|
+
if (change.revisions === undefined || change.revisions.length === 0) {
|
|
1889
|
+
return new Set([undefined]);
|
|
1890
|
+
}
|
|
1891
|
+
const aggregated: Set<RevisionTag | undefined> = new Set();
|
|
1892
|
+
for (const revInfo of change.revisions) {
|
|
1893
|
+
aggregated.add(revInfo.revision);
|
|
1894
|
+
}
|
|
1895
|
+
return aggregated;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1499
1898
|
public changeRevision(
|
|
1500
1899
|
change: ModularChangeset,
|
|
1501
|
-
|
|
1502
|
-
rollbackOf?: RevisionTag,
|
|
1900
|
+
replacer: RevisionReplacer,
|
|
1503
1901
|
): ModularChangeset {
|
|
1504
|
-
const
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
: change.revisions.map((revInfo) => revInfo.revision),
|
|
1508
|
-
);
|
|
1509
|
-
const updatedFields = this.replaceFieldMapRevisions(
|
|
1510
|
-
change.fieldChanges,
|
|
1511
|
-
oldRevisions,
|
|
1512
|
-
newRevision,
|
|
1902
|
+
const updatedFields = this.replaceFieldMapRevisions(change.fieldChanges, replacer);
|
|
1903
|
+
const updatedNodes = replaceIdMapRevisions(change.nodeChanges, replacer, (nodeChangeset) =>
|
|
1904
|
+
this.replaceNodeChangesetRevisions(nodeChangeset, replacer),
|
|
1513
1905
|
);
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
const updatedNodeToParent: ChangeAtomIdBTree<FieldId> = newTupleBTree();
|
|
1524
|
-
for (const [[revision, id], fieldId] of change.nodeToParent.entries()) {
|
|
1525
|
-
updatedNodeToParent.set(
|
|
1526
|
-
[replaceRevision(revision, oldRevisions, newRevision), id],
|
|
1527
|
-
replaceFieldIdRevision(
|
|
1528
|
-
normalizeFieldId(fieldId, change.nodeAliases),
|
|
1529
|
-
oldRevisions,
|
|
1530
|
-
newRevision,
|
|
1906
|
+
const updatedNodeToParent = replaceIdMapRevisions(
|
|
1907
|
+
change.nodeToParent,
|
|
1908
|
+
replacer,
|
|
1909
|
+
(location) =>
|
|
1910
|
+
replaceNodeLocationRevision(
|
|
1911
|
+
normalizeNodeLocation(location, change.nodeAliases),
|
|
1912
|
+
replacer,
|
|
1531
1913
|
),
|
|
1532
|
-
|
|
1533
|
-
}
|
|
1914
|
+
);
|
|
1534
1915
|
|
|
1535
1916
|
const updated: Mutable<ModularChangeset> = {
|
|
1536
1917
|
...change,
|
|
1537
1918
|
fieldChanges: updatedFields,
|
|
1538
1919
|
nodeChanges: updatedNodes,
|
|
1539
1920
|
nodeToParent: updatedNodeToParent,
|
|
1921
|
+
rootNodes: replaceRootTableRevision(change.rootNodes, replacer, change.nodeAliases),
|
|
1540
1922
|
|
|
1541
1923
|
// We've updated all references to old node IDs, so we no longer need an alias table.
|
|
1542
1924
|
nodeAliases: newTupleBTree(),
|
|
1543
1925
|
crossFieldKeys: replaceCrossFieldKeyTableRevisions(
|
|
1544
1926
|
change.crossFieldKeys,
|
|
1545
|
-
|
|
1546
|
-
newRevision,
|
|
1927
|
+
replacer,
|
|
1547
1928
|
change.nodeAliases,
|
|
1548
1929
|
),
|
|
1549
1930
|
};
|
|
1550
1931
|
|
|
1551
1932
|
if (change.builds !== undefined) {
|
|
1552
|
-
updated.builds = replaceIdMapRevisions(change.builds,
|
|
1933
|
+
updated.builds = replaceIdMapRevisions(change.builds, replacer);
|
|
1553
1934
|
}
|
|
1554
1935
|
|
|
1555
1936
|
if (change.destroys !== undefined) {
|
|
1556
|
-
updated.destroys = replaceIdMapRevisions(change.destroys,
|
|
1937
|
+
updated.destroys = replaceIdMapRevisions(change.destroys, replacer);
|
|
1557
1938
|
}
|
|
1558
1939
|
|
|
1559
1940
|
if (change.refreshers !== undefined) {
|
|
1560
|
-
updated.refreshers = replaceIdMapRevisions(change.refreshers,
|
|
1941
|
+
updated.refreshers = replaceIdMapRevisions(change.refreshers, replacer);
|
|
1561
1942
|
}
|
|
1562
1943
|
|
|
1563
|
-
|
|
1564
|
-
const revInfo: Mutable<RevisionInfo> = { revision: newRevision };
|
|
1565
|
-
if (rollbackOf !== undefined) {
|
|
1566
|
-
revInfo.rollbackOf = rollbackOf;
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
updated.revisions = [revInfo];
|
|
1570
|
-
} else {
|
|
1571
|
-
delete updated.revisions;
|
|
1572
|
-
}
|
|
1944
|
+
updated.revisions = [{ revision: replacer.updatedRevision }];
|
|
1573
1945
|
|
|
1574
1946
|
return updated;
|
|
1575
1947
|
}
|
|
1576
1948
|
|
|
1577
1949
|
private replaceNodeChangesetRevisions(
|
|
1578
1950
|
nodeChangeset: NodeChangeset,
|
|
1579
|
-
|
|
1580
|
-
newRevision: RevisionTag | undefined,
|
|
1951
|
+
replacer: RevisionReplacer,
|
|
1581
1952
|
): NodeChangeset {
|
|
1582
1953
|
const updated = { ...nodeChangeset };
|
|
1583
1954
|
if (nodeChangeset.fieldChanges !== undefined) {
|
|
1584
1955
|
updated.fieldChanges = this.replaceFieldMapRevisions(
|
|
1585
1956
|
nodeChangeset.fieldChanges,
|
|
1586
|
-
|
|
1587
|
-
newRevision,
|
|
1957
|
+
replacer,
|
|
1588
1958
|
);
|
|
1589
1959
|
}
|
|
1590
1960
|
|
|
@@ -1593,15 +1963,14 @@ export class ModularChangeFamily
|
|
|
1593
1963
|
|
|
1594
1964
|
private replaceFieldMapRevisions(
|
|
1595
1965
|
fields: FieldChangeMap,
|
|
1596
|
-
|
|
1597
|
-
newRevision: RevisionTag | undefined,
|
|
1966
|
+
replacer: RevisionReplacer,
|
|
1598
1967
|
): FieldChangeMap {
|
|
1599
1968
|
const updatedFields: FieldChangeMap = new Map();
|
|
1600
1969
|
for (const [field, fieldChange] of fields) {
|
|
1601
1970
|
const updatedFieldChange = getChangeHandler(
|
|
1602
1971
|
this.fieldKinds,
|
|
1603
1972
|
fieldChange.fieldKind,
|
|
1604
|
-
).rebaser.replaceRevisions(fieldChange.change,
|
|
1973
|
+
).rebaser.replaceRevisions(fieldChange.change, replacer);
|
|
1605
1974
|
|
|
1606
1975
|
updatedFields.set(field, { ...fieldChange, change: brand(updatedFieldChange) });
|
|
1607
1976
|
}
|
|
@@ -1613,7 +1982,7 @@ export class ModularChangeFamily
|
|
|
1613
1982
|
fields: FieldChangeMap,
|
|
1614
1983
|
nodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
1615
1984
|
): CrossFieldKeyTable {
|
|
1616
|
-
const keys: CrossFieldKeyTable =
|
|
1985
|
+
const keys: CrossFieldKeyTable = newCrossFieldRangeTable();
|
|
1617
1986
|
this.populateCrossFieldKeyTableForFieldMap(keys, fields, undefined);
|
|
1618
1987
|
nodes.forEachPair(([revision, localId], node) => {
|
|
1619
1988
|
if (node.fieldChanges !== undefined) {
|
|
@@ -1643,9 +2012,10 @@ export class ModularChangeFamily
|
|
|
1643
2012
|
}
|
|
1644
2013
|
|
|
1645
2014
|
public buildEditor(
|
|
2015
|
+
mintRevisionTag: () => RevisionTag,
|
|
1646
2016
|
changeReceiver: (change: TaggedChange<ModularChangeset>) => void,
|
|
1647
2017
|
): ModularEditBuilder {
|
|
1648
|
-
return new ModularEditBuilder(this, this.fieldKinds, changeReceiver);
|
|
2018
|
+
return new ModularEditBuilder(this, this.fieldKinds, changeReceiver, this.codecOptions);
|
|
1649
2019
|
}
|
|
1650
2020
|
|
|
1651
2021
|
private createEmptyFieldChange(fieldKind: FieldKindIdentifier): FieldChange {
|
|
@@ -1653,63 +2023,6 @@ export class ModularChangeFamily
|
|
|
1653
2023
|
return { fieldKind, change: brand(emptyChange) };
|
|
1654
2024
|
}
|
|
1655
2025
|
|
|
1656
|
-
public validateChangeset(change: ModularChangeset): void {
|
|
1657
|
-
let numNodes = this.validateFieldChanges(change, change.fieldChanges, undefined);
|
|
1658
|
-
|
|
1659
|
-
for (const [[revision, localId], node] of change.nodeChanges.entries()) {
|
|
1660
|
-
if (node.fieldChanges === undefined) {
|
|
1661
|
-
continue;
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
const nodeId: NodeId = { revision, localId };
|
|
1665
|
-
const numChildren = this.validateFieldChanges(change, node.fieldChanges, nodeId);
|
|
1666
|
-
|
|
1667
|
-
numNodes += numChildren;
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
assert(
|
|
1671
|
-
numNodes === change.nodeChanges.size,
|
|
1672
|
-
0xa4d /* Node table contains unparented nodes */,
|
|
1673
|
-
);
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
/**
|
|
1677
|
-
* Asserts that each child and cross field key in each field has a correct entry in
|
|
1678
|
-
* `nodeToParent` or `crossFieldKeyTable`.
|
|
1679
|
-
* @returns the number of children found.
|
|
1680
|
-
*/
|
|
1681
|
-
private validateFieldChanges(
|
|
1682
|
-
change: ModularChangeset,
|
|
1683
|
-
fieldChanges: FieldChangeMap,
|
|
1684
|
-
nodeParent: NodeId | undefined,
|
|
1685
|
-
): number {
|
|
1686
|
-
let numChildren = 0;
|
|
1687
|
-
for (const [field, fieldChange] of fieldChanges.entries()) {
|
|
1688
|
-
const fieldId = { nodeId: nodeParent, field };
|
|
1689
|
-
const handler = getChangeHandler(this.fieldKinds, fieldChange.fieldKind);
|
|
1690
|
-
for (const [child, _index] of handler.getNestedChanges(fieldChange.change)) {
|
|
1691
|
-
const parentFieldId = getParentFieldId(change, child);
|
|
1692
|
-
assert(
|
|
1693
|
-
areEqualFieldIds(parentFieldId, fieldId),
|
|
1694
|
-
0xa4e /* Inconsistent node parentage */,
|
|
1695
|
-
);
|
|
1696
|
-
numChildren += 1;
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
for (const keyRange of handler.getCrossFieldKeys(fieldChange.change)) {
|
|
1700
|
-
const fields = getFieldsForCrossFieldKey(change, keyRange.key, keyRange.count);
|
|
1701
|
-
assert(
|
|
1702
|
-
fields.length === 1 &&
|
|
1703
|
-
fields[0] !== undefined &&
|
|
1704
|
-
areEqualFieldIds(fields[0], fieldId),
|
|
1705
|
-
0xa4f /* Inconsistent cross field keys */,
|
|
1706
|
-
);
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
return numChildren;
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
2026
|
private getEffectiveChange(change: ModularChangeset): ModularChangeset {
|
|
1714
2027
|
if (hasConflicts(change)) {
|
|
1715
2028
|
return this.muteChange(change);
|
|
@@ -1723,7 +2036,8 @@ export class ModularChangeFamily
|
|
|
1723
2036
|
private muteChange(change: ModularChangeset): ModularChangeset {
|
|
1724
2037
|
const muted: Mutable<ModularChangeset> = {
|
|
1725
2038
|
...change,
|
|
1726
|
-
|
|
2039
|
+
rootNodes: muteRootChanges(change.rootNodes),
|
|
2040
|
+
crossFieldKeys: newCrossFieldRangeTable(),
|
|
1727
2041
|
fieldChanges: this.muteFieldChanges(change.fieldChanges),
|
|
1728
2042
|
nodeChanges: brand(change.nodeChanges.mapValues((v) => this.muteNodeChange(v))),
|
|
1729
2043
|
};
|
|
@@ -1757,25 +2071,20 @@ export class ModularChangeFamily
|
|
|
1757
2071
|
|
|
1758
2072
|
function replaceCrossFieldKeyTableRevisions(
|
|
1759
2073
|
table: CrossFieldKeyTable,
|
|
1760
|
-
|
|
1761
|
-
newRevision: RevisionTag | undefined,
|
|
2074
|
+
replacer: RevisionReplacer,
|
|
1762
2075
|
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
1763
2076
|
): CrossFieldKeyTable {
|
|
1764
|
-
const updated: CrossFieldKeyTable =
|
|
2077
|
+
const updated: CrossFieldKeyTable = newCrossFieldRangeTable();
|
|
1765
2078
|
for (const entry of table.entries()) {
|
|
1766
2079
|
const key = entry.start;
|
|
1767
|
-
const updatedKey: CrossFieldKey =
|
|
1768
|
-
target: key.target,
|
|
1769
|
-
revision: replaceRevision(key.revision, oldRevisions, newRevision),
|
|
1770
|
-
localId: key.localId,
|
|
1771
|
-
};
|
|
2080
|
+
const updatedKey: CrossFieldKey = replacer.getUpdatedAtomId(key);
|
|
1772
2081
|
|
|
1773
2082
|
const field = entry.value;
|
|
1774
2083
|
const normalizedFieldId = normalizeFieldId(field, nodeAliases);
|
|
1775
2084
|
const updatedNodeId =
|
|
1776
|
-
normalizedFieldId.nodeId
|
|
1777
|
-
?
|
|
1778
|
-
:
|
|
2085
|
+
normalizedFieldId.nodeId === undefined
|
|
2086
|
+
? undefined
|
|
2087
|
+
: replacer.getUpdatedAtomId(normalizedFieldId.nodeId);
|
|
1779
2088
|
|
|
1780
2089
|
const updatedValue: FieldId = {
|
|
1781
2090
|
...normalizedFieldId,
|
|
@@ -1788,22 +2097,15 @@ function replaceCrossFieldKeyTableRevisions(
|
|
|
1788
2097
|
return updated;
|
|
1789
2098
|
}
|
|
1790
2099
|
|
|
1791
|
-
function replaceRevision(
|
|
1792
|
-
revision: RevisionTag | undefined,
|
|
1793
|
-
oldRevisions: Set<RevisionTag | undefined>,
|
|
1794
|
-
newRevision: RevisionTag | undefined,
|
|
1795
|
-
): RevisionTag | undefined {
|
|
1796
|
-
return oldRevisions.has(revision) ? newRevision : revision;
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
2100
|
function replaceIdMapRevisions<T>(
|
|
1800
2101
|
map: ChangeAtomIdBTree<T>,
|
|
1801
|
-
|
|
1802
|
-
|
|
2102
|
+
replacer: RevisionReplacer,
|
|
2103
|
+
valueMapper: (value: T) => T = (value) => value,
|
|
1803
2104
|
): ChangeAtomIdBTree<T> {
|
|
1804
2105
|
const updated: ChangeAtomIdBTree<T> = newTupleBTree();
|
|
1805
|
-
for (const [[revision,
|
|
1806
|
-
|
|
2106
|
+
for (const [[revision, localId], value] of map.entries()) {
|
|
2107
|
+
const newAtom = replacer.getUpdatedAtomId({ revision, localId });
|
|
2108
|
+
updated.set([newAtom.revision, newAtom.localId], valueMapper(value));
|
|
1807
2109
|
}
|
|
1808
2110
|
|
|
1809
2111
|
return updated;
|
|
@@ -1879,6 +2181,20 @@ function composeBuildsDestroysAndRefreshers(
|
|
|
1879
2181
|
}
|
|
1880
2182
|
}
|
|
1881
2183
|
|
|
2184
|
+
// It's possible to have a build and a refresher for the same root because an attach operation need not be performed in the same changeset as the corresponding build.
|
|
2185
|
+
if (change1.builds !== undefined && change2.refreshers !== undefined) {
|
|
2186
|
+
for (const [key, chunk] of change2.refreshers.entries()) {
|
|
2187
|
+
assert(chunk.topLevelLength === 1, "Expected refresher chunk to have length 1");
|
|
2188
|
+
const match = change1.builds.getPairOrNextLower(key);
|
|
2189
|
+
if (match !== undefined) {
|
|
2190
|
+
const [buildKey, buildChunk] = match;
|
|
2191
|
+
if (buildKey[0] === key[0] && buildKey[1] + buildChunk.topLevelLength > key[1]) {
|
|
2192
|
+
allRefreshers.delete(key);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
|
|
1882
2198
|
return { allBuilds, allDestroys, allRefreshers };
|
|
1883
2199
|
}
|
|
1884
2200
|
|
|
@@ -1910,27 +2226,77 @@ export function* relevantRemovedRoots(
|
|
|
1910
2226
|
change: ModularChangeset,
|
|
1911
2227
|
fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
1912
2228
|
): Iterable<DeltaDetachedNodeId> {
|
|
1913
|
-
|
|
2229
|
+
const rootIds: ChangeAtomIdRangeMap<boolean> = newChangeAtomIdRangeMap();
|
|
2230
|
+
addAttachesToSet(change, rootIds);
|
|
2231
|
+
addRenamesToSet(change, rootIds);
|
|
2232
|
+
|
|
2233
|
+
for (const [[revision, localId]] of change.rootNodes.nodeChanges.entries()) {
|
|
2234
|
+
rootIds.set({ revision, localId }, 1, true);
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
for (const entry of rootIds.entries()) {
|
|
2238
|
+
for (let offset = 0; offset < entry.length; offset++) {
|
|
2239
|
+
const detachId = offsetChangeAtomId(entry.start, offset);
|
|
2240
|
+
yield makeDetachedNodeId(detachId.revision, detachId.localId);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
1914
2243
|
}
|
|
1915
2244
|
|
|
1916
|
-
function*
|
|
1917
|
-
change
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
2245
|
+
export function* getBuildIds(change: ModularChangeset): Iterable<DeltaDetachedNodeId> {
|
|
2246
|
+
if (change.builds !== undefined) {
|
|
2247
|
+
for (const [[revision, localId]] of change.builds.entries()) {
|
|
2248
|
+
yield makeDetachedNodeId(revision, localId);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
function addAttachesToSet(
|
|
2254
|
+
change: ModularChangeset,
|
|
2255
|
+
rootIds: ChangeAtomIdRangeMap<boolean>,
|
|
2256
|
+
): void {
|
|
2257
|
+
// This includes each attach which does not have a corresponding detach.
|
|
2258
|
+
for (const entry of change.crossFieldKeys.entries()) {
|
|
2259
|
+
if (entry.start.target !== CrossFieldTarget.Destination) {
|
|
2260
|
+
continue;
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
for (const detachIdEntry of change.rootNodes.newToOldId.getAll2(
|
|
2264
|
+
entry.start,
|
|
2265
|
+
entry.length,
|
|
2266
|
+
)) {
|
|
2267
|
+
const detachId =
|
|
2268
|
+
detachIdEntry.value ?? offsetChangeAtomId(entry.start, detachIdEntry.offset);
|
|
2269
|
+
for (const detachEntry of change.crossFieldKeys.getAll2(
|
|
2270
|
+
{ ...detachId, target: CrossFieldTarget.Source },
|
|
2271
|
+
detachIdEntry.length,
|
|
2272
|
+
)) {
|
|
2273
|
+
if (detachEntry.value === undefined) {
|
|
2274
|
+
rootIds.set(
|
|
2275
|
+
offsetChangeAtomId(detachId, detachEntry.offset),
|
|
2276
|
+
detachEntry.length,
|
|
2277
|
+
true,
|
|
2278
|
+
);
|
|
2279
|
+
}
|
|
1931
2280
|
}
|
|
1932
|
-
}
|
|
1933
|
-
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
function addRenamesToSet(
|
|
2286
|
+
change: ModularChangeset,
|
|
2287
|
+
rootIds: ChangeAtomIdRangeMap<boolean>,
|
|
2288
|
+
): void {
|
|
2289
|
+
for (const renameEntry of change.rootNodes.oldToNewId.entries()) {
|
|
2290
|
+
for (const detachEntry of change.crossFieldKeys.getAll2(
|
|
2291
|
+
{ ...renameEntry.start, target: CrossFieldTarget.Source },
|
|
2292
|
+
renameEntry.length,
|
|
2293
|
+
)) {
|
|
2294
|
+
// We only want to include renames of nodes which are detached in the input context of the changeset.
|
|
2295
|
+
// So if there is a detach for the node, the rename is not relevant.
|
|
2296
|
+
if (detachEntry.value === undefined) {
|
|
2297
|
+
rootIds.set(renameEntry.start, renameEntry.length, true);
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
1934
2300
|
}
|
|
1935
2301
|
}
|
|
1936
2302
|
|
|
@@ -1990,20 +2356,25 @@ export function updateRefreshers(
|
|
|
1990
2356
|
const {
|
|
1991
2357
|
fieldChanges,
|
|
1992
2358
|
nodeChanges,
|
|
2359
|
+
nodeToParent,
|
|
2360
|
+
nodeAliases,
|
|
2361
|
+
crossFieldKeys,
|
|
1993
2362
|
maxId,
|
|
1994
2363
|
revisions,
|
|
1995
2364
|
constraintViolationCount,
|
|
1996
2365
|
constraintViolationCountOnRevert,
|
|
1997
2366
|
builds,
|
|
1998
2367
|
destroys,
|
|
2368
|
+
rootNodes,
|
|
1999
2369
|
} = change;
|
|
2000
2370
|
|
|
2001
2371
|
return makeModularChangeset({
|
|
2002
2372
|
fieldChanges,
|
|
2003
2373
|
nodeChanges,
|
|
2004
|
-
nodeToParent
|
|
2005
|
-
nodeAliases
|
|
2006
|
-
crossFieldKeys
|
|
2374
|
+
nodeToParent,
|
|
2375
|
+
nodeAliases,
|
|
2376
|
+
crossFieldKeys,
|
|
2377
|
+
rootNodes,
|
|
2007
2378
|
maxId: maxId as number,
|
|
2008
2379
|
revisions,
|
|
2009
2380
|
constraintViolationCount,
|
|
@@ -2026,18 +2397,42 @@ export function intoDelta(
|
|
|
2026
2397
|
): DeltaRoot {
|
|
2027
2398
|
const change = taggedChange.change;
|
|
2028
2399
|
const rootDelta: Mutable<DeltaRoot> = {};
|
|
2029
|
-
const global: DeltaDetachedNodeChanges[] = [];
|
|
2030
|
-
const rename: DeltaDetachedNodeRename[] = [];
|
|
2031
2400
|
|
|
2032
2401
|
if (!hasConflicts(change)) {
|
|
2033
2402
|
// If there are no constraint violations, then tree changes apply.
|
|
2034
2403
|
const fieldDeltas = intoDeltaImpl(
|
|
2035
2404
|
change.fieldChanges,
|
|
2036
2405
|
change.nodeChanges,
|
|
2406
|
+
change.nodeAliases,
|
|
2037
2407
|
fieldKinds,
|
|
2038
|
-
global,
|
|
2039
|
-
rename,
|
|
2040
2408
|
);
|
|
2409
|
+
|
|
2410
|
+
const global: DeltaDetachedNodeChanges[] = [];
|
|
2411
|
+
for (const [[major, minor], nodeId] of change.rootNodes.nodeChanges.entries()) {
|
|
2412
|
+
global.push({
|
|
2413
|
+
id: { major, minor },
|
|
2414
|
+
fields: deltaFromNodeChange(
|
|
2415
|
+
nodeChangeFromId(change.nodeChanges, change.nodeAliases, nodeId),
|
|
2416
|
+
change.nodeChanges,
|
|
2417
|
+
change.nodeAliases,
|
|
2418
|
+
fieldKinds,
|
|
2419
|
+
),
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
const rename: DeltaDetachedNodeRename[] = [];
|
|
2424
|
+
for (const {
|
|
2425
|
+
start: oldId,
|
|
2426
|
+
value: newId,
|
|
2427
|
+
length,
|
|
2428
|
+
} of change.rootNodes.oldToNewId.entries()) {
|
|
2429
|
+
rename.push({
|
|
2430
|
+
count: length,
|
|
2431
|
+
oldId: makeDetachedNodeId(oldId.revision, oldId.localId),
|
|
2432
|
+
newId: makeDetachedNodeId(newId.revision, newId.localId),
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2041
2436
|
if (fieldDeltas.size > 0) {
|
|
2042
2437
|
rootDelta.fields = fieldDeltas;
|
|
2043
2438
|
}
|
|
@@ -2066,6 +2461,7 @@ export function intoDelta(
|
|
|
2066
2461
|
if (change.refreshers && change.refreshers.size > 0) {
|
|
2067
2462
|
rootDelta.refreshers = copyDetachedNodes(change.refreshers);
|
|
2068
2463
|
}
|
|
2464
|
+
|
|
2069
2465
|
return rootDelta;
|
|
2070
2466
|
}
|
|
2071
2467
|
|
|
@@ -2091,29 +2487,22 @@ function copyDetachedNodes(
|
|
|
2091
2487
|
function intoDeltaImpl(
|
|
2092
2488
|
change: FieldChangeMap,
|
|
2093
2489
|
nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
|
|
2490
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
2094
2491
|
fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
2095
|
-
global: DeltaDetachedNodeChanges[],
|
|
2096
|
-
rename: DeltaDetachedNodeRename[],
|
|
2097
2492
|
): Map<FieldKey, DeltaFieldChanges> {
|
|
2098
2493
|
const delta: Map<FieldKey, DeltaFieldChanges> = new Map();
|
|
2099
2494
|
|
|
2100
2495
|
for (const [field, fieldChange] of change) {
|
|
2101
|
-
const
|
|
2102
|
-
local: fieldChanges,
|
|
2103
|
-
global: fieldGlobal,
|
|
2104
|
-
rename: fieldRename,
|
|
2105
|
-
} = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
|
|
2496
|
+
const fieldDelta = getChangeHandler(fieldKinds, fieldChange.fieldKind).intoDelta(
|
|
2106
2497
|
fieldChange.change,
|
|
2107
2498
|
(childChange): DeltaFieldMap => {
|
|
2108
|
-
const nodeChange = nodeChangeFromId(nodeChanges, childChange);
|
|
2109
|
-
return deltaFromNodeChange(nodeChange, nodeChanges,
|
|
2499
|
+
const nodeChange = nodeChangeFromId(nodeChanges, nodeAliases, childChange);
|
|
2500
|
+
return deltaFromNodeChange(nodeChange, nodeChanges, nodeAliases, fieldKinds);
|
|
2110
2501
|
},
|
|
2111
2502
|
);
|
|
2112
|
-
if (
|
|
2113
|
-
delta.set(field,
|
|
2503
|
+
if (fieldDelta !== undefined && fieldDelta.length > 0) {
|
|
2504
|
+
delta.set(field, fieldDelta);
|
|
2114
2505
|
}
|
|
2115
|
-
fieldGlobal?.forEach((c) => global.push(c));
|
|
2116
|
-
fieldRename?.forEach((r) => rename.push(r));
|
|
2117
2506
|
}
|
|
2118
2507
|
return delta;
|
|
2119
2508
|
}
|
|
@@ -2121,12 +2510,11 @@ function intoDeltaImpl(
|
|
|
2121
2510
|
function deltaFromNodeChange(
|
|
2122
2511
|
change: NodeChangeset,
|
|
2123
2512
|
nodeChanges: ChangeAtomIdBTree<NodeChangeset>,
|
|
2513
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
2124
2514
|
fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
2125
|
-
global: DeltaDetachedNodeChanges[],
|
|
2126
|
-
rename: DeltaDetachedNodeRename[],
|
|
2127
2515
|
): DeltaFieldMap {
|
|
2128
2516
|
if (change.fieldChanges !== undefined) {
|
|
2129
|
-
return intoDeltaImpl(change.fieldChanges, nodeChanges,
|
|
2517
|
+
return intoDeltaImpl(change.fieldChanges, nodeChanges, nodeAliases, fieldKinds);
|
|
2130
2518
|
}
|
|
2131
2519
|
// TODO: update the API to allow undefined to be returned here
|
|
2132
2520
|
return new Map();
|
|
@@ -2191,19 +2579,21 @@ export function getChangeHandler(
|
|
|
2191
2579
|
return getFieldKind(fieldKinds, kind).changeHandler;
|
|
2192
2580
|
}
|
|
2193
2581
|
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
interface CrossFieldTable<TFieldData> {
|
|
2197
|
-
srcTable: CrossFieldMap<unknown>;
|
|
2198
|
-
dstTable: CrossFieldMap<unknown>;
|
|
2199
|
-
srcDependents: CrossFieldMap<TFieldData>;
|
|
2200
|
-
dstDependents: CrossFieldMap<TFieldData>;
|
|
2201
|
-
invalidatedFields: Set<TFieldData>;
|
|
2202
|
-
}
|
|
2582
|
+
interface InvertTable {
|
|
2583
|
+
change: ModularChangeset;
|
|
2203
2584
|
|
|
2204
|
-
|
|
2585
|
+
// Entries are keyed on attach ID
|
|
2586
|
+
entries: CrossFieldMap<NodeId>;
|
|
2205
2587
|
originalFieldToContext: Map<FieldChange, InvertContext>;
|
|
2206
|
-
invertedNodeToParent: ChangeAtomIdBTree<
|
|
2588
|
+
invertedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
|
|
2589
|
+
invertRevision: RevisionTag;
|
|
2590
|
+
invalidatedFields: Set<FieldChange>;
|
|
2591
|
+
invertedRoots: RootNodeTable;
|
|
2592
|
+
|
|
2593
|
+
/**
|
|
2594
|
+
* Maps from attach ID in the inverted changeset to the corresponding detach ID in the base changeset.
|
|
2595
|
+
*/
|
|
2596
|
+
attachToDetachId: ChangeAtomIdRangeMap<ChangeAtomId>;
|
|
2207
2597
|
}
|
|
2208
2598
|
|
|
2209
2599
|
interface InvertContext {
|
|
@@ -2211,7 +2601,11 @@ interface InvertContext {
|
|
|
2211
2601
|
invertedField: FieldChange;
|
|
2212
2602
|
}
|
|
2213
2603
|
|
|
2214
|
-
interface RebaseTable
|
|
2604
|
+
interface RebaseTable {
|
|
2605
|
+
readonly rebaseVersion: RebaseVersion;
|
|
2606
|
+
|
|
2607
|
+
// Entries are keyed on attach ID
|
|
2608
|
+
readonly entries: CrossFieldMap<RebaseDetachedNodeEntry>;
|
|
2215
2609
|
readonly baseChange: ModularChangeset;
|
|
2216
2610
|
readonly newChange: ModularChangeset;
|
|
2217
2611
|
|
|
@@ -2220,10 +2614,13 @@ interface RebaseTable extends CrossFieldTable<FieldChange> {
|
|
|
2220
2614
|
* to the context for the field.
|
|
2221
2615
|
*/
|
|
2222
2616
|
readonly baseFieldToContext: Map<FieldChange, RebaseFieldContext>;
|
|
2617
|
+
readonly baseRoots: RootNodeTable;
|
|
2223
2618
|
readonly baseToRebasedNodeId: ChangeAtomIdBTree<NodeId>;
|
|
2224
2619
|
readonly rebasedFields: Set<FieldChange>;
|
|
2225
|
-
readonly rebasedNodeToParent: ChangeAtomIdBTree<
|
|
2226
|
-
readonly
|
|
2620
|
+
readonly rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
|
|
2621
|
+
readonly rebasedDetachLocations: ChangeAtomIdRangeMap<FieldId>;
|
|
2622
|
+
readonly movedDetaches: ChangeAtomIdRangeMap<boolean>;
|
|
2623
|
+
readonly rebasedRootNodes: RootNodeTable;
|
|
2227
2624
|
|
|
2228
2625
|
/**
|
|
2229
2626
|
* List of unprocessed (newId, baseId) pairs encountered so far.
|
|
@@ -2237,7 +2634,7 @@ interface RebaseTable extends CrossFieldTable<FieldChange> {
|
|
|
2237
2634
|
readonly fieldsWithUnattachedChild: Set<FieldChange>;
|
|
2238
2635
|
}
|
|
2239
2636
|
|
|
2240
|
-
type FieldIdKey = [RevisionTag | undefined, ChangesetLocalId | undefined, FieldKey];
|
|
2637
|
+
export type FieldIdKey = [RevisionTag | undefined, ChangesetLocalId | undefined, FieldKey];
|
|
2241
2638
|
|
|
2242
2639
|
interface RebaseFieldContext {
|
|
2243
2640
|
baseChange: FieldChange;
|
|
@@ -2249,32 +2646,43 @@ interface RebaseFieldContext {
|
|
|
2249
2646
|
* The set of node IDs in the base changeset which should be included in the rebased field,
|
|
2250
2647
|
* even if there is no corresponding node changeset in the new change.
|
|
2251
2648
|
*/
|
|
2252
|
-
baseNodeIds:
|
|
2649
|
+
baseNodeIds: ChangeAtomIdBTree<boolean>;
|
|
2253
2650
|
}
|
|
2254
2651
|
|
|
2255
2652
|
function newComposeTable(
|
|
2256
2653
|
baseChange: ModularChangeset,
|
|
2257
2654
|
newChange: ModularChangeset,
|
|
2258
|
-
|
|
2655
|
+
composedRootNodes: RootNodeTable,
|
|
2656
|
+
movedCrossFieldKeys: CrossFieldKeyTable,
|
|
2657
|
+
removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
|
|
2658
|
+
pendingCompositions: PendingCompositions,
|
|
2259
2659
|
): ComposeTable {
|
|
2260
2660
|
return {
|
|
2261
|
-
|
|
2661
|
+
rebaseVersion: Math.max(
|
|
2662
|
+
baseChange.rebaseVersion,
|
|
2663
|
+
newChange.rebaseVersion,
|
|
2664
|
+
) as RebaseVersion,
|
|
2665
|
+
entries: newDetachedEntryMap(),
|
|
2262
2666
|
baseChange,
|
|
2263
2667
|
newChange,
|
|
2264
2668
|
fieldToContext: new Map(),
|
|
2265
2669
|
newFieldToBaseField: new Map(),
|
|
2266
2670
|
newToBaseNodeId: newTupleBTree(),
|
|
2267
2671
|
composedNodes: new Set(),
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2672
|
+
movedNodeToParent: newTupleBTree(),
|
|
2673
|
+
composedRootNodes,
|
|
2674
|
+
movedCrossFieldKeys,
|
|
2675
|
+
removedCrossFieldKeys,
|
|
2676
|
+
renamesToDelete: newChangeAtomIdRangeMap(),
|
|
2677
|
+
pendingCompositions,
|
|
2274
2678
|
};
|
|
2275
2679
|
}
|
|
2276
2680
|
|
|
2277
|
-
interface ComposeTable
|
|
2681
|
+
interface ComposeTable {
|
|
2682
|
+
readonly rebaseVersion: RebaseVersion;
|
|
2683
|
+
|
|
2684
|
+
// Entries are keyed on detach ID
|
|
2685
|
+
readonly entries: ChangeAtomIdRangeMap<DetachedNodeEntry>;
|
|
2278
2686
|
readonly baseChange: ModularChangeset;
|
|
2279
2687
|
readonly newChange: ModularChangeset;
|
|
2280
2688
|
|
|
@@ -2285,7 +2693,11 @@ interface ComposeTable extends CrossFieldTable<FieldChange> {
|
|
|
2285
2693
|
readonly newFieldToBaseField: Map<FieldChange, FieldChange>;
|
|
2286
2694
|
readonly newToBaseNodeId: ChangeAtomIdBTree<NodeId>;
|
|
2287
2695
|
readonly composedNodes: Set<NodeChangeset>;
|
|
2288
|
-
readonly
|
|
2696
|
+
readonly movedNodeToParent: ChangeAtomIdBTree<NodeLocation>;
|
|
2697
|
+
readonly composedRootNodes: RootNodeTable;
|
|
2698
|
+
readonly movedCrossFieldKeys: CrossFieldKeyTable;
|
|
2699
|
+
readonly removedCrossFieldKeys: CrossFieldRangeTable<boolean>;
|
|
2700
|
+
readonly renamesToDelete: ChangeAtomIdRangeMap<boolean>;
|
|
2289
2701
|
readonly pendingCompositions: PendingCompositions;
|
|
2290
2702
|
}
|
|
2291
2703
|
|
|
@@ -2300,11 +2712,6 @@ interface PendingCompositions {
|
|
|
2300
2712
|
* The set of fields in the base changeset which have been affected by a cross field effect.
|
|
2301
2713
|
*/
|
|
2302
2714
|
readonly affectedBaseFields: BTree<FieldIdKey, true>;
|
|
2303
|
-
|
|
2304
|
-
/**
|
|
2305
|
-
* The set of fields in the new changeset which have been affected by a cross field effect.
|
|
2306
|
-
*/
|
|
2307
|
-
readonly affectedNewFields: BTree<FieldIdKey, true>;
|
|
2308
2715
|
}
|
|
2309
2716
|
|
|
2310
2717
|
interface ComposeFieldContext {
|
|
@@ -2317,16 +2724,6 @@ interface ComposeFieldContext {
|
|
|
2317
2724
|
composedChange: FieldChange;
|
|
2318
2725
|
}
|
|
2319
2726
|
|
|
2320
|
-
function newCrossFieldTable<T>(): CrossFieldTable<T> {
|
|
2321
|
-
return {
|
|
2322
|
-
srcTable: newChangeAtomIdRangeMap(),
|
|
2323
|
-
dstTable: newChangeAtomIdRangeMap(),
|
|
2324
|
-
srcDependents: newChangeAtomIdRangeMap(),
|
|
2325
|
-
dstDependents: newChangeAtomIdRangeMap(),
|
|
2326
|
-
invalidatedFields: new Set(),
|
|
2327
|
-
};
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
2727
|
interface ConstraintState {
|
|
2331
2728
|
violationCount: number;
|
|
2332
2729
|
}
|
|
@@ -2337,342 +2734,771 @@ function newConstraintState(violationCount: number): ConstraintState {
|
|
|
2337
2734
|
};
|
|
2338
2735
|
}
|
|
2339
2736
|
|
|
2340
|
-
|
|
2737
|
+
class InvertNodeManagerI implements InvertNodeManager {
|
|
2341
2738
|
public constructor(
|
|
2342
|
-
|
|
2343
|
-
private readonly
|
|
2344
|
-
protected readonly allowInval = true,
|
|
2739
|
+
private readonly table: InvertTable,
|
|
2740
|
+
private readonly fieldId: FieldId,
|
|
2345
2741
|
) {}
|
|
2346
2742
|
|
|
2347
|
-
public
|
|
2348
|
-
|
|
2349
|
-
revision: RevisionTag | undefined,
|
|
2350
|
-
id: ChangesetLocalId,
|
|
2743
|
+
public invertDetach(
|
|
2744
|
+
detachId: ChangeAtomId,
|
|
2351
2745
|
count: number,
|
|
2352
|
-
|
|
2353
|
-
|
|
2746
|
+
nodeChange: NodeId | undefined,
|
|
2747
|
+
newAttachId: ChangeAtomId,
|
|
2354
2748
|
): void {
|
|
2355
|
-
if (
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2749
|
+
if (nodeChange !== undefined) {
|
|
2750
|
+
assert(count === 1, "A node change should only affect one node");
|
|
2751
|
+
|
|
2752
|
+
const attachEntry = firstAttachIdFromDetachId(
|
|
2753
|
+
this.table.change.rootNodes,
|
|
2754
|
+
detachId,
|
|
2755
|
+
count,
|
|
2756
|
+
);
|
|
2757
|
+
|
|
2758
|
+
const attachFieldEntry = this.table.change.crossFieldKeys.getFirst(
|
|
2759
|
+
{ target: CrossFieldTarget.Destination, ...attachEntry.value },
|
|
2760
|
+
count,
|
|
2761
|
+
);
|
|
2368
2762
|
|
|
2369
|
-
|
|
2763
|
+
if (attachFieldEntry.value === undefined) {
|
|
2764
|
+
assignRootChange(
|
|
2765
|
+
this.table.invertedRoots,
|
|
2766
|
+
this.table.invertedNodeToParent,
|
|
2767
|
+
attachEntry.value,
|
|
2768
|
+
nodeChange,
|
|
2769
|
+
this.fieldId,
|
|
2770
|
+
this.table.change.rebaseVersion,
|
|
2771
|
+
);
|
|
2772
|
+
} else {
|
|
2773
|
+
setInCrossFieldMap(this.table.entries, attachEntry.value, count, nodeChange);
|
|
2774
|
+
this.table.invalidatedFields.add(
|
|
2775
|
+
fieldChangeFromId(this.table.change, attachFieldEntry.value),
|
|
2776
|
+
);
|
|
2370
2777
|
}
|
|
2371
2778
|
}
|
|
2372
|
-
setInCrossFieldMap(this.getMap(target), revision, id, count, newValue);
|
|
2373
|
-
}
|
|
2374
2779
|
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
count: number,
|
|
2380
|
-
addDependency: boolean,
|
|
2381
|
-
): RangeQueryResult<ChangeAtomId, unknown> {
|
|
2382
|
-
if (addDependency) {
|
|
2383
|
-
// We assume that if there is already an entry for this ID it is because
|
|
2384
|
-
// a field handler has called compose on the same node multiple times.
|
|
2385
|
-
// In this case we only want to update the latest version, so we overwrite the dependency.
|
|
2386
|
-
setInCrossFieldMap(
|
|
2387
|
-
this.getDependents(target),
|
|
2388
|
-
revision,
|
|
2389
|
-
id,
|
|
2780
|
+
if (!areEqualChangeAtomIds(detachId, newAttachId)) {
|
|
2781
|
+
for (const entry of doesChangeAttachNodes(
|
|
2782
|
+
this.table.change.crossFieldKeys,
|
|
2783
|
+
detachId,
|
|
2390
2784
|
count,
|
|
2391
|
-
|
|
2392
|
-
|
|
2785
|
+
)) {
|
|
2786
|
+
if (!entry.value) {
|
|
2787
|
+
this.table.attachToDetachId.set(newAttachId, count, detachId);
|
|
2788
|
+
this.table.invertedRoots.detachLocations.set(detachId, count, this.fieldId);
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2393
2791
|
}
|
|
2394
|
-
return getFirstFromCrossFieldMap(this.getMap(target), revision, id, count);
|
|
2395
2792
|
}
|
|
2396
2793
|
|
|
2397
|
-
public
|
|
2398
|
-
|
|
2399
|
-
public abstract moveKey(
|
|
2400
|
-
target: CrossFieldTarget,
|
|
2401
|
-
revision: RevisionTag | undefined,
|
|
2402
|
-
id: ChangesetLocalId,
|
|
2794
|
+
public invertAttach(
|
|
2795
|
+
attachId: ChangeAtomId,
|
|
2403
2796
|
count: number,
|
|
2404
|
-
):
|
|
2405
|
-
|
|
2406
|
-
private getMap(target: CrossFieldTarget): CrossFieldMap<unknown> {
|
|
2407
|
-
return target === CrossFieldTarget.Source
|
|
2408
|
-
? this.crossFieldTable.srcTable
|
|
2409
|
-
: this.crossFieldTable.dstTable;
|
|
2410
|
-
}
|
|
2797
|
+
): RangeQueryResult<DetachedNodeEntry> {
|
|
2798
|
+
let countToProcess = count;
|
|
2411
2799
|
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
}
|
|
2800
|
+
const detachIdEntry = firstDetachIdFromAttachId(
|
|
2801
|
+
this.table.change.rootNodes,
|
|
2802
|
+
attachId,
|
|
2803
|
+
countToProcess,
|
|
2804
|
+
);
|
|
2418
2805
|
|
|
2419
|
-
|
|
2420
|
-
public constructor(
|
|
2421
|
-
table: InvertTable,
|
|
2422
|
-
field: FieldChange,
|
|
2423
|
-
private readonly fieldId: FieldId,
|
|
2424
|
-
allowInval = true,
|
|
2425
|
-
) {
|
|
2426
|
-
super(table, field, allowInval);
|
|
2427
|
-
}
|
|
2806
|
+
countToProcess = detachIdEntry.length;
|
|
2428
2807
|
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2808
|
+
const detachEntry = getFirstFieldForCrossFieldKey(
|
|
2809
|
+
this.table.change,
|
|
2810
|
+
{ target: CrossFieldTarget.Source, ...detachIdEntry.value },
|
|
2811
|
+
countToProcess,
|
|
2812
|
+
);
|
|
2813
|
+
countToProcess = detachEntry.length;
|
|
2814
|
+
|
|
2815
|
+
let result: RangeQueryResult<DetachedNodeEntry>;
|
|
2816
|
+
if (detachEntry.value === undefined) {
|
|
2817
|
+
// This node is detached in the input context of the original change.
|
|
2818
|
+
const nodeIdEntry = rangeQueryChangeAtomIdMap(
|
|
2819
|
+
this.table.change.rootNodes.nodeChanges,
|
|
2820
|
+
detachIdEntry.value,
|
|
2821
|
+
countToProcess,
|
|
2822
|
+
);
|
|
2432
2823
|
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2824
|
+
countToProcess = nodeIdEntry.length;
|
|
2825
|
+
result = {
|
|
2826
|
+
value: { nodeChange: nodeIdEntry.value, detachId: detachIdEntry.value },
|
|
2827
|
+
length: countToProcess,
|
|
2828
|
+
};
|
|
2829
|
+
} else {
|
|
2830
|
+
const moveEntry = this.table.entries.getFirst(attachId, countToProcess);
|
|
2831
|
+
result = { ...moveEntry, value: { nodeChange: moveEntry.value } };
|
|
2832
|
+
}
|
|
2441
2833
|
|
|
2442
|
-
|
|
2443
|
-
|
|
2834
|
+
if (result.value?.nodeChange !== undefined) {
|
|
2835
|
+
setInChangeAtomIdMap(this.table.invertedNodeToParent, result.value.nodeChange, {
|
|
2836
|
+
field: this.fieldId,
|
|
2837
|
+
});
|
|
2838
|
+
}
|
|
2839
|
+
return result;
|
|
2444
2840
|
}
|
|
2445
2841
|
}
|
|
2446
2842
|
|
|
2447
|
-
class
|
|
2843
|
+
class RebaseNodeManagerI implements RebaseNodeManager {
|
|
2448
2844
|
public constructor(
|
|
2449
|
-
table: RebaseTable,
|
|
2450
|
-
currentField: FieldChange,
|
|
2845
|
+
private readonly table: RebaseTable,
|
|
2451
2846
|
private readonly fieldId: FieldId,
|
|
2452
|
-
allowInval = true,
|
|
2453
|
-
) {
|
|
2454
|
-
super(table, currentField, allowInval);
|
|
2455
|
-
}
|
|
2847
|
+
private readonly allowInval: boolean = true,
|
|
2848
|
+
) {}
|
|
2456
2849
|
|
|
2457
|
-
public
|
|
2458
|
-
|
|
2459
|
-
revision: RevisionTag | undefined,
|
|
2460
|
-
id: ChangesetLocalId,
|
|
2850
|
+
public getNewChangesForBaseAttach(
|
|
2851
|
+
baseAttachId: ChangeAtomId,
|
|
2461
2852
|
count: number,
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
): void {
|
|
2465
|
-
if (invalidateDependents && this.allowInval) {
|
|
2466
|
-
const newFieldIds = getFieldsForCrossFieldKey(
|
|
2467
|
-
this.table.newChange,
|
|
2468
|
-
{
|
|
2469
|
-
target,
|
|
2470
|
-
revision,
|
|
2471
|
-
localId: id,
|
|
2472
|
-
},
|
|
2473
|
-
count,
|
|
2474
|
-
);
|
|
2853
|
+
): RangeQueryResult<RebaseDetachedNodeEntry | undefined> {
|
|
2854
|
+
let countToProcess = count;
|
|
2475
2855
|
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2856
|
+
const detachEntry = firstDetachIdFromAttachId(
|
|
2857
|
+
this.table.baseChange.rootNodes,
|
|
2858
|
+
baseAttachId,
|
|
2859
|
+
countToProcess,
|
|
2860
|
+
);
|
|
2480
2861
|
|
|
2481
|
-
|
|
2482
|
-
this.table.baseChange,
|
|
2483
|
-
{
|
|
2484
|
-
target,
|
|
2485
|
-
revision,
|
|
2486
|
-
localId: id,
|
|
2487
|
-
},
|
|
2488
|
-
count,
|
|
2489
|
-
);
|
|
2862
|
+
countToProcess = detachEntry.length;
|
|
2490
2863
|
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2864
|
+
const nodeEntry = rangeQueryChangeAtomIdMap(
|
|
2865
|
+
this.table.newChange.rootNodes.nodeChanges,
|
|
2866
|
+
detachEntry.value,
|
|
2867
|
+
countToProcess,
|
|
2868
|
+
);
|
|
2869
|
+
|
|
2870
|
+
countToProcess = nodeEntry.length;
|
|
2871
|
+
const newNodeId = nodeEntry.value;
|
|
2872
|
+
|
|
2873
|
+
const newRenameEntry = this.table.newChange.rootNodes.oldToNewId.getFirst(
|
|
2874
|
+
detachEntry.value,
|
|
2875
|
+
countToProcess,
|
|
2876
|
+
);
|
|
2877
|
+
|
|
2878
|
+
countToProcess = newRenameEntry.length;
|
|
2879
|
+
|
|
2880
|
+
let result: RangeQueryResult<DetachedNodeEntry | undefined>;
|
|
2881
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
|
2882
|
+
if (newNodeId !== undefined || newRenameEntry.value !== undefined) {
|
|
2883
|
+
result = {
|
|
2884
|
+
...newRenameEntry,
|
|
2885
|
+
value: { detachId: newRenameEntry.value, nodeChange: newNodeId },
|
|
2886
|
+
};
|
|
2887
|
+
} else {
|
|
2888
|
+
// This handles the case where the base changeset has moved these nodes,
|
|
2889
|
+
// meaning they were attached in the input context of the base changeset.
|
|
2890
|
+
result = this.table.entries.getFirst(baseAttachId, countToProcess);
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
// TODO: Consider moving these two checks into a separate method so that this function has no side effects.
|
|
2894
|
+
if (result.value?.detachId !== undefined) {
|
|
2895
|
+
this.table.rebasedDetachLocations.set(
|
|
2896
|
+
result.value.detachId,
|
|
2897
|
+
result.length,
|
|
2898
|
+
this.fieldId,
|
|
2494
2899
|
);
|
|
2900
|
+
}
|
|
2495
2901
|
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2902
|
+
if (result.value?.nodeChange !== undefined) {
|
|
2903
|
+
setInChangeAtomIdMap(this.table.rebasedNodeToParent, result.value.nodeChange, {
|
|
2904
|
+
field: this.fieldId,
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
return result;
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
public rebaseOverDetach(
|
|
2912
|
+
baseDetachId: ChangeAtomId,
|
|
2913
|
+
count: number,
|
|
2914
|
+
newDetachId: ChangeAtomId | undefined,
|
|
2915
|
+
nodeChange: NodeId | undefined,
|
|
2916
|
+
cellRename?: ChangeAtomId,
|
|
2917
|
+
): void {
|
|
2918
|
+
let countToProcess = count;
|
|
2919
|
+
const attachIdEntry = firstAttachIdFromDetachId(
|
|
2920
|
+
this.table.baseRoots,
|
|
2921
|
+
baseDetachId,
|
|
2922
|
+
countToProcess,
|
|
2923
|
+
);
|
|
2924
|
+
const baseAttachId = attachIdEntry.value;
|
|
2925
|
+
countToProcess = attachIdEntry.length;
|
|
2926
|
+
|
|
2927
|
+
const attachFieldEntry = getFirstFieldForCrossFieldKey(
|
|
2928
|
+
this.table.baseChange,
|
|
2929
|
+
{ ...baseAttachId, target: CrossFieldTarget.Destination },
|
|
2930
|
+
countToProcess,
|
|
2931
|
+
);
|
|
2932
|
+
countToProcess = attachFieldEntry.length;
|
|
2933
|
+
|
|
2934
|
+
const detachedMoveEntry = this.table.baseChange.rootNodes.outputDetachLocations.getFirst(
|
|
2935
|
+
baseDetachId,
|
|
2936
|
+
countToProcess,
|
|
2937
|
+
);
|
|
2938
|
+
countToProcess = detachedMoveEntry.length;
|
|
2939
|
+
|
|
2940
|
+
const destinationField = attachFieldEntry.value ?? detachedMoveEntry.value;
|
|
2941
|
+
if (destinationField !== undefined) {
|
|
2942
|
+
// The base detach is part of a move (or move of detach location) in the base changeset.
|
|
2943
|
+
setInCrossFieldMap(this.table.entries, baseAttachId, countToProcess, {
|
|
2944
|
+
nodeChange,
|
|
2945
|
+
detachId: newDetachId,
|
|
2946
|
+
cellRename,
|
|
2947
|
+
});
|
|
2948
|
+
|
|
2949
|
+
if (nodeChange !== undefined || newDetachId !== undefined) {
|
|
2950
|
+
this.invalidateBaseFields([destinationField]);
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
if (attachFieldEntry.value === undefined) {
|
|
2955
|
+
// These nodes are detached in the output context of the base changeset.
|
|
2956
|
+
if (nodeChange !== undefined) {
|
|
2957
|
+
assignRootChange(
|
|
2958
|
+
this.table.rebasedRootNodes,
|
|
2959
|
+
this.table.rebasedNodeToParent,
|
|
2960
|
+
baseAttachId,
|
|
2961
|
+
nodeChange,
|
|
2962
|
+
this.fieldId,
|
|
2963
|
+
this.table.rebaseVersion,
|
|
2500
2964
|
);
|
|
2501
2965
|
}
|
|
2966
|
+
|
|
2967
|
+
if (newDetachId !== undefined) {
|
|
2968
|
+
addNodeRename(
|
|
2969
|
+
this.table.rebasedRootNodes,
|
|
2970
|
+
baseAttachId,
|
|
2971
|
+
newDetachId,
|
|
2972
|
+
countToProcess,
|
|
2973
|
+
this.fieldId,
|
|
2974
|
+
);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
if (newDetachId !== undefined) {
|
|
2979
|
+
this.table.movedDetaches.set(newDetachId, countToProcess, true);
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
if (countToProcess < count) {
|
|
2983
|
+
const remainingCount = count - countToProcess;
|
|
2984
|
+
|
|
2985
|
+
const nextDetachId =
|
|
2986
|
+
newDetachId === undefined
|
|
2987
|
+
? undefined
|
|
2988
|
+
: offsetChangeAtomId(newDetachId, countToProcess);
|
|
2989
|
+
|
|
2990
|
+
this.rebaseOverDetach(
|
|
2991
|
+
offsetChangeAtomId(baseDetachId, countToProcess),
|
|
2992
|
+
remainingCount,
|
|
2993
|
+
nextDetachId,
|
|
2994
|
+
nodeChange,
|
|
2995
|
+
);
|
|
2502
2996
|
}
|
|
2997
|
+
}
|
|
2503
2998
|
|
|
2504
|
-
|
|
2999
|
+
public addDetach(id: ChangeAtomId, count: number): void {
|
|
3000
|
+
this.table.rebasedDetachLocations.set(id, count, this.fieldId);
|
|
2505
3001
|
}
|
|
2506
3002
|
|
|
2507
|
-
public
|
|
2508
|
-
|
|
3003
|
+
public removeDetach(id: ChangeAtomId, count: number): void {
|
|
3004
|
+
this.table.movedDetaches.set(id, count, true);
|
|
2509
3005
|
}
|
|
2510
3006
|
|
|
2511
|
-
public
|
|
2512
|
-
|
|
2513
|
-
revision: RevisionTag | undefined,
|
|
2514
|
-
id: ChangesetLocalId,
|
|
3007
|
+
public doesBaseAttachNodes(
|
|
3008
|
+
id: ChangeAtomId,
|
|
2515
3009
|
count: number,
|
|
2516
|
-
):
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
3010
|
+
): RangeQueryEntry<ChangeAtomId, boolean> {
|
|
3011
|
+
let countToProcess = count;
|
|
3012
|
+
const attachEntry = getFirstAttachField(
|
|
3013
|
+
this.table.baseChange.crossFieldKeys,
|
|
3014
|
+
id,
|
|
3015
|
+
countToProcess,
|
|
3016
|
+
);
|
|
3017
|
+
|
|
3018
|
+
countToProcess = attachEntry.length;
|
|
3019
|
+
return { start: id, value: attachEntry.value !== undefined, length: countToProcess };
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
public getBaseRename(
|
|
3023
|
+
id: ChangeAtomId,
|
|
3024
|
+
count: number,
|
|
3025
|
+
): RangeQueryResult<ChangeAtomId | undefined> {
|
|
3026
|
+
return this.table.baseChange.rootNodes.oldToNewId.getFirst(id, count);
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
public getNewRenameForBaseRename(
|
|
3030
|
+
baseRenameTo: ChangeAtomId,
|
|
3031
|
+
count: number,
|
|
3032
|
+
): RangeQueryResult<ChangeAtomId | undefined> {
|
|
3033
|
+
let countToProcess = count;
|
|
3034
|
+
const inputEntry = firstDetachIdFromAttachId(
|
|
3035
|
+
this.table.baseChange.rootNodes,
|
|
3036
|
+
baseRenameTo,
|
|
3037
|
+
countToProcess,
|
|
3038
|
+
);
|
|
3039
|
+
|
|
3040
|
+
const attachEntry = getFirstAttachField(
|
|
3041
|
+
this.table.baseChange.crossFieldKeys,
|
|
3042
|
+
baseRenameTo,
|
|
3043
|
+
countToProcess,
|
|
2521
3044
|
);
|
|
3045
|
+
|
|
3046
|
+
countToProcess = attachEntry.length;
|
|
3047
|
+
if (attachEntry.value !== undefined) {
|
|
3048
|
+
// These nodes are attached in the output context of the base changeset.
|
|
3049
|
+
return { value: undefined, length: countToProcess };
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
countToProcess = inputEntry.length;
|
|
3053
|
+
const inputId = inputEntry.value;
|
|
3054
|
+
|
|
3055
|
+
const moveEntry = this.table.entries.getFirst(inputId, countToProcess);
|
|
3056
|
+
|
|
3057
|
+
countToProcess = moveEntry.length;
|
|
3058
|
+
if (moveEntry.value !== undefined) {
|
|
3059
|
+
return { ...moveEntry, value: moveEntry.value.cellRename ?? moveEntry.value.detachId };
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
return this.table.newChange.rootNodes.oldToNewId.getFirst(inputId, countToProcess);
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
private invalidateBaseFields(fields: FieldId[]): void {
|
|
3066
|
+
if (this.allowInval) {
|
|
3067
|
+
for (const fieldId of fields) {
|
|
3068
|
+
this.table.affectedBaseFields.set(fieldIdKeyFromFieldId(fieldId), true);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
2522
3071
|
}
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
function assignRootChange(
|
|
3075
|
+
table: RootNodeTable,
|
|
3076
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation> | undefined,
|
|
3077
|
+
detachId: ChangeAtomId,
|
|
3078
|
+
nodeId: NodeId,
|
|
3079
|
+
detachLocation: FieldId | undefined,
|
|
3080
|
+
rebaseVersion: RebaseVersion,
|
|
3081
|
+
): void {
|
|
3082
|
+
assert(
|
|
3083
|
+
rebaseVersion >= 2 || detachLocation !== undefined,
|
|
3084
|
+
"All root changes need a detach location to support compatibility with older client versions",
|
|
3085
|
+
);
|
|
3086
|
+
|
|
3087
|
+
setInChangeAtomIdMap(table.nodeChanges, detachId, nodeId);
|
|
2523
3088
|
|
|
2524
|
-
|
|
2525
|
-
|
|
3089
|
+
if (nodeToParent !== undefined) {
|
|
3090
|
+
setInChangeAtomIdMap(nodeToParent, nodeId, { root: detachId });
|
|
2526
3091
|
}
|
|
3092
|
+
|
|
3093
|
+
table.detachLocations.set(detachId, 1, detachLocation);
|
|
2527
3094
|
}
|
|
2528
3095
|
|
|
2529
|
-
|
|
2530
|
-
class ComposeManager extends CrossFieldManagerI<FieldChange> {
|
|
3096
|
+
class ComposeNodeManagerI implements ComposeNodeManager {
|
|
2531
3097
|
public constructor(
|
|
2532
|
-
table: ComposeTable,
|
|
2533
|
-
currentField: FieldChange,
|
|
3098
|
+
private readonly table: ComposeTable,
|
|
2534
3099
|
private readonly fieldId: FieldId,
|
|
2535
|
-
allowInval = true,
|
|
2536
|
-
) {
|
|
2537
|
-
|
|
3100
|
+
private readonly allowInval: boolean = true,
|
|
3101
|
+
) {}
|
|
3102
|
+
|
|
3103
|
+
public getNewChangesForBaseDetach(
|
|
3104
|
+
baseDetachId: ChangeAtomId,
|
|
3105
|
+
count: number,
|
|
3106
|
+
): RangeQueryResult<DetachedNodeEntry | undefined> {
|
|
3107
|
+
let countToProcess = count;
|
|
3108
|
+
|
|
3109
|
+
const baseAttachEntry = getFirstFieldForCrossFieldKey(
|
|
3110
|
+
this.table.baseChange,
|
|
3111
|
+
{ target: CrossFieldTarget.Destination, ...baseDetachId },
|
|
3112
|
+
countToProcess,
|
|
3113
|
+
);
|
|
3114
|
+
|
|
3115
|
+
countToProcess = baseAttachEntry.length;
|
|
3116
|
+
|
|
3117
|
+
let result: RangeQueryResult<DetachedNodeEntry | undefined>;
|
|
3118
|
+
if (baseAttachEntry.value === undefined) {
|
|
3119
|
+
// The detached nodes are still detached in the new change's input context.
|
|
3120
|
+
const rootEntry = rangeQueryChangeAtomIdMap(
|
|
3121
|
+
this.table.newChange.rootNodes.nodeChanges,
|
|
3122
|
+
baseDetachId,
|
|
3123
|
+
countToProcess,
|
|
3124
|
+
);
|
|
3125
|
+
|
|
3126
|
+
countToProcess = rootEntry.length;
|
|
3127
|
+
|
|
3128
|
+
const newRenameEntry = this.table.newChange.rootNodes.oldToNewId.getFirst(
|
|
3129
|
+
baseDetachId,
|
|
3130
|
+
countToProcess,
|
|
3131
|
+
);
|
|
3132
|
+
|
|
3133
|
+
countToProcess = newRenameEntry.length;
|
|
3134
|
+
|
|
3135
|
+
result = {
|
|
3136
|
+
value: { nodeChange: rootEntry.value, detachId: newRenameEntry.value },
|
|
3137
|
+
length: countToProcess,
|
|
3138
|
+
};
|
|
3139
|
+
} else {
|
|
3140
|
+
// The base detach was part of a move.
|
|
3141
|
+
// We check if we've previously seen a node change at the move destination.
|
|
3142
|
+
const entry = this.table.entries.getFirst(baseDetachId, countToProcess);
|
|
3143
|
+
result = { value: entry.value, length: entry.length };
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
// TODO: Consider moving this to a separate method so that this method can be side-effect free.
|
|
3147
|
+
if (result.value?.nodeChange !== undefined) {
|
|
3148
|
+
setInChangeAtomIdMap(this.table.movedNodeToParent, result.value.nodeChange, {
|
|
3149
|
+
field: this.fieldId,
|
|
3150
|
+
});
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
return result;
|
|
2538
3154
|
}
|
|
2539
3155
|
|
|
2540
|
-
public
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
id: ChangesetLocalId,
|
|
3156
|
+
public composeAttachDetach(
|
|
3157
|
+
baseAttachId: ChangeAtomId,
|
|
3158
|
+
newDetachId: ChangeAtomId,
|
|
2544
3159
|
count: number,
|
|
2545
|
-
newValue: unknown,
|
|
2546
|
-
invalidateDependents: boolean,
|
|
2547
3160
|
): void {
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
3161
|
+
let countToProcess = count;
|
|
3162
|
+
|
|
3163
|
+
const newAttachEntry = getFirstAttachField(
|
|
3164
|
+
this.table.newChange.crossFieldKeys,
|
|
3165
|
+
newDetachId,
|
|
3166
|
+
countToProcess,
|
|
3167
|
+
);
|
|
3168
|
+
|
|
3169
|
+
countToProcess = newAttachEntry.length;
|
|
3170
|
+
|
|
3171
|
+
// Both changes can have the same ID if they came from inverse changesets.
|
|
3172
|
+
// If the new detach is part of a move,
|
|
3173
|
+
// then both input changesets contain the attach cross-field key for this ID.
|
|
3174
|
+
// The new attach may still exist in the composed changeset so we do not remove it here.
|
|
3175
|
+
// The new attach will typically cancel with a base detach,
|
|
3176
|
+
// in which case the cross-field key will be removed in `composeDetachAttach`.
|
|
3177
|
+
const hasNewAttachWithBaseAttachId =
|
|
3178
|
+
areEqualChangeAtomIds(baseAttachId, newDetachId) && newAttachEntry.value !== undefined;
|
|
3179
|
+
|
|
3180
|
+
if (!hasNewAttachWithBaseAttachId) {
|
|
3181
|
+
this.table.removedCrossFieldKeys.set(
|
|
3182
|
+
{ ...baseAttachId, target: CrossFieldTarget.Destination },
|
|
3183
|
+
countToProcess,
|
|
3184
|
+
true,
|
|
2557
3185
|
);
|
|
3186
|
+
}
|
|
2558
3187
|
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
3188
|
+
const baseDetachEntry = getFirstDetachField(
|
|
3189
|
+
this.table.baseChange.crossFieldKeys,
|
|
3190
|
+
baseAttachId,
|
|
3191
|
+
countToProcess,
|
|
3192
|
+
);
|
|
3193
|
+
|
|
3194
|
+
countToProcess = baseDetachEntry.length;
|
|
3195
|
+
|
|
3196
|
+
const baseRootIdEntry = firstDetachIdFromAttachId(
|
|
3197
|
+
this.table.baseChange.rootNodes,
|
|
3198
|
+
baseAttachId,
|
|
3199
|
+
countToProcess,
|
|
3200
|
+
);
|
|
3201
|
+
countToProcess = baseRootIdEntry.length;
|
|
3202
|
+
|
|
3203
|
+
const baseDetachId = baseRootIdEntry.value;
|
|
3204
|
+
|
|
3205
|
+
if (baseDetachEntry.value === undefined) {
|
|
3206
|
+
const baseDetachLocationEntry = this.table.baseChange.rootNodes.detachLocations.getFirst(
|
|
3207
|
+
baseDetachId,
|
|
3208
|
+
countToProcess,
|
|
3209
|
+
);
|
|
3210
|
+
countToProcess = baseDetachLocationEntry.length;
|
|
3211
|
+
|
|
3212
|
+
// These nodes were detached in the base change's input context,
|
|
3213
|
+
// so the net effect of the two changes is a rename.
|
|
3214
|
+
appendNodeRename(
|
|
3215
|
+
this.table.composedRootNodes,
|
|
3216
|
+
baseAttachId,
|
|
3217
|
+
newDetachId,
|
|
3218
|
+
baseDetachEntry.length,
|
|
3219
|
+
this.table.baseChange.rootNodes,
|
|
3220
|
+
baseDetachLocationEntry.value ?? this.fieldId,
|
|
3221
|
+
);
|
|
3222
|
+
|
|
3223
|
+
this.table.removedCrossFieldKeys.set(
|
|
3224
|
+
{ ...newDetachId, target: CrossFieldTarget.Source },
|
|
3225
|
+
countToProcess,
|
|
3226
|
+
true,
|
|
3227
|
+
);
|
|
3228
|
+
} else {
|
|
3229
|
+
// The base change moves these nodes.
|
|
3230
|
+
const prevEntry =
|
|
3231
|
+
this.table.entries.getFirst(baseAttachId, baseDetachEntry.length).value ?? {};
|
|
3232
|
+
|
|
3233
|
+
this.table.entries.set(baseAttachId, baseDetachEntry.length, {
|
|
3234
|
+
...prevEntry,
|
|
3235
|
+
detachId: newDetachId,
|
|
3236
|
+
});
|
|
3237
|
+
|
|
3238
|
+
// The new detach will replace the base detach, so we remove the key for the base detach, unless they have the same ID.
|
|
3239
|
+
if (!areEqualChangeAtomIds(baseAttachId, newDetachId)) {
|
|
3240
|
+
this.table.removedCrossFieldKeys.set(
|
|
3241
|
+
{ ...baseAttachId, target: CrossFieldTarget.Source },
|
|
3242
|
+
countToProcess,
|
|
3243
|
+
true,
|
|
2575
3244
|
);
|
|
3245
|
+
}
|
|
2576
3246
|
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
3247
|
+
this.table.movedCrossFieldKeys.set(
|
|
3248
|
+
{ ...newDetachId, target: CrossFieldTarget.Source },
|
|
3249
|
+
countToProcess,
|
|
3250
|
+
baseDetachEntry.value,
|
|
3251
|
+
);
|
|
3252
|
+
|
|
3253
|
+
this.invalidateBaseFields([baseDetachEntry.value]);
|
|
3254
|
+
}
|
|
3255
|
+
|
|
3256
|
+
if (newAttachEntry.value === undefined) {
|
|
3257
|
+
const newOutputDetachLocationEntry =
|
|
3258
|
+
this.table.newChange.rootNodes.outputDetachLocations.getFirst(
|
|
3259
|
+
newDetachId,
|
|
3260
|
+
countToProcess,
|
|
2580
3261
|
);
|
|
2581
3262
|
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
3263
|
+
countToProcess = newOutputDetachLocationEntry.length;
|
|
3264
|
+
|
|
3265
|
+
this.table.composedRootNodes.outputDetachLocations.set(
|
|
3266
|
+
newDetachId,
|
|
3267
|
+
countToProcess,
|
|
3268
|
+
newOutputDetachLocationEntry.value ?? this.fieldId,
|
|
3269
|
+
);
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
if (countToProcess < count) {
|
|
3273
|
+
const remainingCount = count - countToProcess;
|
|
3274
|
+
this.composeAttachDetach(
|
|
3275
|
+
offsetChangeAtomId(baseAttachId, countToProcess),
|
|
3276
|
+
offsetChangeAtomId(newDetachId, countToProcess),
|
|
3277
|
+
remainingCount,
|
|
3278
|
+
);
|
|
2589
3279
|
}
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
public sendNewChangesToBaseSourceLocation(
|
|
3283
|
+
baseAttachId: ChangeAtomId,
|
|
3284
|
+
newChanges: NodeId,
|
|
3285
|
+
): void {
|
|
3286
|
+
const { value: baseDetachId } = firstDetachIdFromAttachId(
|
|
3287
|
+
this.table.baseChange.rootNodes,
|
|
3288
|
+
baseAttachId,
|
|
3289
|
+
1,
|
|
3290
|
+
);
|
|
3291
|
+
|
|
3292
|
+
const detachFields = getFieldsForCrossFieldKey(
|
|
3293
|
+
this.table.baseChange,
|
|
3294
|
+
{
|
|
3295
|
+
...baseDetachId,
|
|
3296
|
+
target: CrossFieldTarget.Source,
|
|
3297
|
+
},
|
|
3298
|
+
1,
|
|
3299
|
+
);
|
|
3300
|
+
|
|
3301
|
+
if (detachFields.length > 0) {
|
|
3302
|
+
// The base attach is part of a move in the base changeset.
|
|
3303
|
+
const prevEntry = this.table.entries.getFirst(baseDetachId, 1).value ?? {};
|
|
3304
|
+
this.table.entries.set(baseDetachId, 1, { ...prevEntry, nodeChange: newChanges });
|
|
2590
3305
|
|
|
2591
|
-
|
|
3306
|
+
if (newChanges !== undefined) {
|
|
3307
|
+
this.invalidateBaseFields(detachFields);
|
|
3308
|
+
}
|
|
3309
|
+
} else {
|
|
3310
|
+
const baseNodeId = getFromChangeAtomIdMap(
|
|
3311
|
+
this.table.baseChange.rootNodes.nodeChanges,
|
|
3312
|
+
baseDetachId,
|
|
3313
|
+
);
|
|
3314
|
+
|
|
3315
|
+
if (baseNodeId === undefined) {
|
|
3316
|
+
assignRootChange(
|
|
3317
|
+
this.table.composedRootNodes,
|
|
3318
|
+
this.table.movedNodeToParent,
|
|
3319
|
+
baseDetachId,
|
|
3320
|
+
newChanges,
|
|
3321
|
+
this.fieldId,
|
|
3322
|
+
this.table.rebaseVersion,
|
|
3323
|
+
);
|
|
3324
|
+
} else {
|
|
3325
|
+
addNodesToCompose(this.table, baseNodeId, newChanges);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
2592
3328
|
}
|
|
2593
3329
|
|
|
2594
|
-
|
|
2595
|
-
|
|
3330
|
+
private areSameNodes(
|
|
3331
|
+
baseDetachId: ChangeAtomId,
|
|
3332
|
+
newAttachId: ChangeAtomId,
|
|
3333
|
+
count: number,
|
|
3334
|
+
): RangeQueryResult<boolean> {
|
|
3335
|
+
const renamedDetachEntry = firstAttachIdFromDetachId(
|
|
3336
|
+
this.table.composedRootNodes,
|
|
3337
|
+
baseDetachId,
|
|
3338
|
+
count,
|
|
3339
|
+
);
|
|
3340
|
+
|
|
3341
|
+
const isReattachOfSameNodes = areEqualChangeAtomIds(renamedDetachEntry.value, newAttachId);
|
|
3342
|
+
return { ...renamedDetachEntry, value: isReattachOfSameNodes };
|
|
2596
3343
|
}
|
|
2597
3344
|
|
|
2598
|
-
public
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
id: ChangesetLocalId,
|
|
3345
|
+
public composeDetachAttach(
|
|
3346
|
+
baseDetachId: ChangeAtomId,
|
|
3347
|
+
newAttachId: ChangeAtomId,
|
|
2602
3348
|
count: number,
|
|
3349
|
+
composeToPin: boolean,
|
|
2603
3350
|
): void {
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
3351
|
+
const areSameEntry = this.areSameNodes(baseDetachId, newAttachId, count);
|
|
3352
|
+
|
|
3353
|
+
const countToProcess = areSameEntry.length;
|
|
3354
|
+
if (areSameEntry.value) {
|
|
3355
|
+
// These nodes have been moved back to their original location, so the composed changeset should not have any renames for them.
|
|
3356
|
+
// Note that deleting the rename from `this.table.composedRootNodes` would change the result of this method
|
|
3357
|
+
// if it were rerun due to the field being invalidated, so we instead record that the rename should be deleted later.
|
|
3358
|
+
this.table.renamesToDelete.set(baseDetachId, countToProcess, true);
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
if (composeToPin) {
|
|
3362
|
+
this.table.movedCrossFieldKeys.set(
|
|
3363
|
+
{ target: CrossFieldTarget.Source, ...newAttachId },
|
|
3364
|
+
countToProcess,
|
|
3365
|
+
this.fieldId,
|
|
3366
|
+
);
|
|
3367
|
+
|
|
3368
|
+
if (!areEqualChangeAtomIds(baseDetachId, newAttachId)) {
|
|
3369
|
+
// The pin will have `newAttachId` as both its detach and attach ID.
|
|
3370
|
+
// So we remove `baseDetachId` unless that is equal to the pin's detach ID.
|
|
3371
|
+
this.table.removedCrossFieldKeys.set(
|
|
3372
|
+
{ target: CrossFieldTarget.Source, ...baseDetachId },
|
|
3373
|
+
countToProcess,
|
|
3374
|
+
true,
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
// Note that while change2 should already have this key, change1 may have a rollback for the same ID in a different location.
|
|
3379
|
+
// In that case, change1's attach should be canceled out by a detach from change2.
|
|
3380
|
+
// Here we make sure that the composed change has the correct location (this field) for the attach ID.
|
|
3381
|
+
this.table.movedCrossFieldKeys.set(
|
|
3382
|
+
{ target: CrossFieldTarget.Destination, ...newAttachId },
|
|
3383
|
+
countToProcess,
|
|
3384
|
+
this.fieldId,
|
|
3385
|
+
);
|
|
3386
|
+
} else {
|
|
3387
|
+
this.table.removedCrossFieldKeys.set(
|
|
3388
|
+
{ target: CrossFieldTarget.Source, ...baseDetachId },
|
|
3389
|
+
countToProcess,
|
|
3390
|
+
true,
|
|
3391
|
+
);
|
|
3392
|
+
|
|
3393
|
+
this.table.removedCrossFieldKeys.set(
|
|
3394
|
+
{ target: CrossFieldTarget.Destination, ...newAttachId },
|
|
3395
|
+
countToProcess,
|
|
3396
|
+
true,
|
|
3397
|
+
);
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
if (countToProcess < count) {
|
|
3401
|
+
this.composeAttachDetach(
|
|
3402
|
+
offsetChangeAtomId(baseDetachId, countToProcess),
|
|
3403
|
+
offsetChangeAtomId(newAttachId, countToProcess),
|
|
3404
|
+
count - countToProcess,
|
|
3405
|
+
);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
private invalidateBaseFields(fields: FieldId[]): void {
|
|
3410
|
+
if (this.allowInval) {
|
|
3411
|
+
for (const fieldId of fields) {
|
|
3412
|
+
this.table.pendingCompositions.affectedBaseFields.set(
|
|
3413
|
+
fieldIdKeyFromFieldId(fieldId),
|
|
3414
|
+
true,
|
|
3415
|
+
);
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
function makeModularChangeset(props?: {
|
|
3422
|
+
rebaseVersion?: RebaseVersion;
|
|
3423
|
+
fieldChanges?: FieldChangeMap;
|
|
3424
|
+
nodeChanges?: ChangeAtomIdBTree<NodeChangeset>;
|
|
3425
|
+
rootNodes?: RootNodeTable;
|
|
3426
|
+
nodeToParent?: ChangeAtomIdBTree<NodeLocation>;
|
|
3427
|
+
nodeAliases?: ChangeAtomIdBTree<NodeId>;
|
|
3428
|
+
crossFieldKeys?: CrossFieldKeyTable;
|
|
3429
|
+
maxId: number;
|
|
3430
|
+
revisions?: readonly RevisionInfo[];
|
|
3431
|
+
constraintViolationCount?: number;
|
|
3432
|
+
constraintViolationCountOnRevert?: number;
|
|
3433
|
+
noChangeConstraint?: NoChangeConstraint;
|
|
3434
|
+
noChangeConstraintOnRevert?: NoChangeConstraint;
|
|
3435
|
+
builds?: ChangeAtomIdBTree<TreeChunk>;
|
|
3436
|
+
destroys?: ChangeAtomIdBTree<number>;
|
|
3437
|
+
refreshers?: ChangeAtomIdBTree<TreeChunk>;
|
|
3438
|
+
}): ModularChangeset {
|
|
3439
|
+
const p = props ?? { maxId: -1 };
|
|
2630
3440
|
const changeset: Mutable<ModularChangeset> = {
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3441
|
+
rebaseVersion: p.rebaseVersion ?? 1,
|
|
3442
|
+
fieldChanges: p.fieldChanges ?? new Map(),
|
|
3443
|
+
nodeChanges: p.nodeChanges ?? newTupleBTree(),
|
|
3444
|
+
rootNodes: p.rootNodes ?? newRootTable(),
|
|
3445
|
+
nodeToParent: p.nodeToParent ?? newTupleBTree(),
|
|
3446
|
+
nodeAliases: p.nodeAliases ?? newTupleBTree(),
|
|
3447
|
+
crossFieldKeys: p.crossFieldKeys ?? newCrossFieldRangeTable(),
|
|
2636
3448
|
};
|
|
2637
3449
|
|
|
2638
|
-
if (
|
|
2639
|
-
changeset.revisions =
|
|
3450
|
+
if (p.revisions !== undefined && p.revisions.length > 0) {
|
|
3451
|
+
changeset.revisions = p.revisions;
|
|
2640
3452
|
}
|
|
2641
|
-
if (
|
|
2642
|
-
changeset.maxId = brand(
|
|
3453
|
+
if (p.maxId >= 0) {
|
|
3454
|
+
changeset.maxId = brand(p.maxId);
|
|
2643
3455
|
}
|
|
2644
|
-
if (
|
|
2645
|
-
changeset.constraintViolationCount =
|
|
3456
|
+
if (p.constraintViolationCount !== undefined && p.constraintViolationCount > 0) {
|
|
3457
|
+
changeset.constraintViolationCount = p.constraintViolationCount;
|
|
2646
3458
|
}
|
|
2647
3459
|
if (
|
|
2648
|
-
|
|
2649
|
-
|
|
3460
|
+
p.constraintViolationCountOnRevert !== undefined &&
|
|
3461
|
+
p.constraintViolationCountOnRevert > 0
|
|
2650
3462
|
) {
|
|
2651
|
-
changeset.constraintViolationCountOnRevert =
|
|
3463
|
+
changeset.constraintViolationCountOnRevert = p.constraintViolationCountOnRevert;
|
|
3464
|
+
}
|
|
3465
|
+
if (p.noChangeConstraint !== undefined) {
|
|
3466
|
+
changeset.noChangeConstraint = p.noChangeConstraint;
|
|
2652
3467
|
}
|
|
2653
|
-
if (
|
|
2654
|
-
changeset.
|
|
3468
|
+
if (p.noChangeConstraintOnRevert !== undefined) {
|
|
3469
|
+
changeset.noChangeConstraintOnRevert = p.noChangeConstraintOnRevert;
|
|
2655
3470
|
}
|
|
2656
|
-
if (
|
|
2657
|
-
changeset.
|
|
3471
|
+
if (p.builds !== undefined && p.builds.size > 0) {
|
|
3472
|
+
changeset.builds = p.builds;
|
|
2658
3473
|
}
|
|
2659
|
-
if (
|
|
2660
|
-
changeset.
|
|
3474
|
+
if (p.destroys !== undefined && p.destroys.size > 0) {
|
|
3475
|
+
changeset.destroys = p.destroys;
|
|
2661
3476
|
}
|
|
3477
|
+
if (p.refreshers !== undefined && p.refreshers.size > 0) {
|
|
3478
|
+
changeset.refreshers = p.refreshers;
|
|
3479
|
+
}
|
|
3480
|
+
|
|
2662
3481
|
return changeset;
|
|
2663
3482
|
}
|
|
2664
3483
|
|
|
2665
3484
|
export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
2666
3485
|
private transactionDepth: number = 0;
|
|
2667
3486
|
private idAllocator: IdAllocator;
|
|
3487
|
+
private readonly codecOptions: CodecWriteOptions;
|
|
2668
3488
|
|
|
2669
3489
|
public constructor(
|
|
2670
3490
|
family: ChangeFamily<ChangeFamilyEditor, ModularChangeset>,
|
|
2671
3491
|
private readonly fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
2672
3492
|
changeReceiver: (change: TaggedChange<ModularChangeset>) => void,
|
|
3493
|
+
codecOptions: CodecWriteOptions,
|
|
2673
3494
|
) {
|
|
2674
3495
|
super(family, changeReceiver);
|
|
2675
3496
|
this.idAllocator = idAllocatorFromMaxId();
|
|
3497
|
+
this.codecOptions = codecOptions;
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
public isInTransaction(): boolean {
|
|
3501
|
+
return this.transactionDepth > 0;
|
|
2676
3502
|
}
|
|
2677
3503
|
|
|
2678
3504
|
public override enterTransaction(): void {
|
|
@@ -2729,7 +3555,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2729
3555
|
* @param revision - the revision of the change
|
|
2730
3556
|
*/
|
|
2731
3557
|
public submitChange(
|
|
2732
|
-
field:
|
|
3558
|
+
field: NormalizedFieldUpPath,
|
|
2733
3559
|
fieldKind: FieldKindIdentifier,
|
|
2734
3560
|
change: FieldChangeset,
|
|
2735
3561
|
revision: RevisionTag,
|
|
@@ -2743,7 +3569,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2743
3569
|
fieldChange: { fieldKind, change },
|
|
2744
3570
|
nodeChanges: newTupleBTree(),
|
|
2745
3571
|
nodeToParent: newTupleBTree(),
|
|
2746
|
-
crossFieldKeys:
|
|
3572
|
+
crossFieldKeys: newCrossFieldRangeTable(),
|
|
3573
|
+
rootNodes: newRootTable(),
|
|
2747
3574
|
idAllocator: this.idAllocator,
|
|
2748
3575
|
localCrossFieldKeys,
|
|
2749
3576
|
revision,
|
|
@@ -2765,6 +3592,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2765
3592
|
? makeModularChangeset({
|
|
2766
3593
|
maxId: this.idAllocator.getMaxId(),
|
|
2767
3594
|
builds: change.builds,
|
|
3595
|
+
rootNodes: renameTableFromRenameDescriptions(change.renames ?? []),
|
|
2768
3596
|
revisions: [{ revision: change.revision }],
|
|
2769
3597
|
})
|
|
2770
3598
|
: buildModularChangesetFromField({
|
|
@@ -2775,7 +3603,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2775
3603
|
},
|
|
2776
3604
|
nodeChanges: newTupleBTree(),
|
|
2777
3605
|
nodeToParent: newTupleBTree(),
|
|
2778
|
-
crossFieldKeys:
|
|
3606
|
+
crossFieldKeys: newCrossFieldRangeTable(),
|
|
3607
|
+
rootNodes: newRootTable(),
|
|
2779
3608
|
idAllocator: this.idAllocator,
|
|
2780
3609
|
localCrossFieldKeys: getChangeHandler(
|
|
2781
3610
|
this.fieldKinds,
|
|
@@ -2785,7 +3614,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2785
3614
|
}),
|
|
2786
3615
|
);
|
|
2787
3616
|
});
|
|
2788
|
-
const revInfo =
|
|
3617
|
+
const revInfo = [...revisions].map((revision) => ({ revision }));
|
|
2789
3618
|
const composedChange: Mutable<ModularChangeset> = {
|
|
2790
3619
|
...this.changeFamily.rebaser.compose(changeMaps),
|
|
2791
3620
|
revisions: revInfo,
|
|
@@ -2802,7 +3631,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2802
3631
|
return brand(this.idAllocator.allocate(count));
|
|
2803
3632
|
}
|
|
2804
3633
|
|
|
2805
|
-
public addNodeExistsConstraint(path:
|
|
3634
|
+
public addNodeExistsConstraint(path: NormalizedUpPath, revision: RevisionTag): void {
|
|
2806
3635
|
const nodeChange: NodeChangeset = {
|
|
2807
3636
|
nodeExistsConstraint: { violated: false },
|
|
2808
3637
|
};
|
|
@@ -2814,7 +3643,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2814
3643
|
nodeChange,
|
|
2815
3644
|
nodeChanges: newTupleBTree(),
|
|
2816
3645
|
nodeToParent: newTupleBTree(),
|
|
2817
|
-
crossFieldKeys:
|
|
3646
|
+
crossFieldKeys: newCrossFieldRangeTable(),
|
|
3647
|
+
rootNodes: newRootTable(),
|
|
2818
3648
|
idAllocator: this.idAllocator,
|
|
2819
3649
|
revision,
|
|
2820
3650
|
}),
|
|
@@ -2823,7 +3653,7 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2823
3653
|
);
|
|
2824
3654
|
}
|
|
2825
3655
|
|
|
2826
|
-
public addNodeExistsConstraintOnRevert(path:
|
|
3656
|
+
public addNodeExistsConstraintOnRevert(path: NormalizedUpPath, revision: RevisionTag): void {
|
|
2827
3657
|
const nodeChange: NodeChangeset = {
|
|
2828
3658
|
nodeExistsConstraintOnRevert: { violated: false },
|
|
2829
3659
|
};
|
|
@@ -2835,7 +3665,8 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2835
3665
|
nodeChange,
|
|
2836
3666
|
nodeChanges: newTupleBTree(),
|
|
2837
3667
|
nodeToParent: newTupleBTree(),
|
|
2838
|
-
crossFieldKeys:
|
|
3668
|
+
crossFieldKeys: newCrossFieldRangeTable(),
|
|
3669
|
+
rootNodes: newRootTable(),
|
|
2839
3670
|
idAllocator: this.idAllocator,
|
|
2840
3671
|
revision,
|
|
2841
3672
|
}),
|
|
@@ -2843,14 +3674,45 @@ export class ModularEditBuilder extends EditBuilder<ModularChangeset> {
|
|
|
2843
3674
|
),
|
|
2844
3675
|
);
|
|
2845
3676
|
}
|
|
3677
|
+
|
|
3678
|
+
public addNoChangeConstraint(revision: RevisionTag): void {
|
|
3679
|
+
if (lt(this.codecOptions.minVersionForCollab, FluidClientVersion.v2_80)) {
|
|
3680
|
+
throw new UsageError(
|
|
3681
|
+
`No change constraints require min client version of at least ${FluidClientVersion.v2_80}`,
|
|
3682
|
+
);
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
const changeset = makeModularChangeset({
|
|
3686
|
+
maxId: -1,
|
|
3687
|
+
noChangeConstraint: { violated: false },
|
|
3688
|
+
});
|
|
3689
|
+
|
|
3690
|
+
this.applyChange(tagChange(changeset, revision));
|
|
3691
|
+
}
|
|
3692
|
+
|
|
3693
|
+
public addNoChangeConstraintOnRevert(revision: RevisionTag): void {
|
|
3694
|
+
if (lt(this.codecOptions.minVersionForCollab, FluidClientVersion.v2_80)) {
|
|
3695
|
+
throw new UsageError(
|
|
3696
|
+
`No change constraints require min client version of at least ${FluidClientVersion.v2_80}`,
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3700
|
+
const changeset = makeModularChangeset({
|
|
3701
|
+
maxId: -1,
|
|
3702
|
+
noChangeConstraintOnRevert: { violated: false },
|
|
3703
|
+
});
|
|
3704
|
+
|
|
3705
|
+
this.applyChange(tagChange(changeset, revision));
|
|
3706
|
+
}
|
|
2846
3707
|
}
|
|
2847
3708
|
|
|
2848
|
-
function buildModularChangesetFromField(props: {
|
|
2849
|
-
path:
|
|
3709
|
+
export function buildModularChangesetFromField(props: {
|
|
3710
|
+
path: NormalizedFieldUpPath;
|
|
2850
3711
|
fieldChange: FieldChange;
|
|
2851
3712
|
nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
|
|
2852
|
-
nodeToParent: ChangeAtomIdBTree<
|
|
3713
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation>;
|
|
2853
3714
|
crossFieldKeys: CrossFieldKeyTable;
|
|
3715
|
+
rootNodes: RootNodeTable;
|
|
2854
3716
|
localCrossFieldKeys?: CrossFieldKeyRange[];
|
|
2855
3717
|
revision: RevisionTag;
|
|
2856
3718
|
idAllocator?: IdAllocator;
|
|
@@ -2862,6 +3724,7 @@ function buildModularChangesetFromField(props: {
|
|
|
2862
3724
|
nodeChanges,
|
|
2863
3725
|
nodeToParent,
|
|
2864
3726
|
crossFieldKeys,
|
|
3727
|
+
rootNodes,
|
|
2865
3728
|
idAllocator = idAllocatorFromMaxId(),
|
|
2866
3729
|
localCrossFieldKeys = [],
|
|
2867
3730
|
childId,
|
|
@@ -2870,14 +3733,17 @@ function buildModularChangesetFromField(props: {
|
|
|
2870
3733
|
const fieldChanges: FieldChangeMap = new Map([[path.field, fieldChange]]);
|
|
2871
3734
|
|
|
2872
3735
|
if (path.parent === undefined) {
|
|
3736
|
+
const field = { nodeId: undefined, field: path.field };
|
|
2873
3737
|
for (const { key, count } of localCrossFieldKeys) {
|
|
2874
|
-
crossFieldKeys.set(key, count,
|
|
3738
|
+
crossFieldKeys.set(key, count, field);
|
|
2875
3739
|
}
|
|
2876
3740
|
|
|
2877
3741
|
if (childId !== undefined) {
|
|
2878
3742
|
setInChangeAtomIdMap(nodeToParent, childId, {
|
|
2879
|
-
|
|
2880
|
-
|
|
3743
|
+
field: {
|
|
3744
|
+
nodeId: undefined,
|
|
3745
|
+
field: path.field,
|
|
3746
|
+
},
|
|
2881
3747
|
});
|
|
2882
3748
|
}
|
|
2883
3749
|
|
|
@@ -2886,6 +3752,7 @@ function buildModularChangesetFromField(props: {
|
|
|
2886
3752
|
nodeChanges,
|
|
2887
3753
|
nodeToParent,
|
|
2888
3754
|
crossFieldKeys,
|
|
3755
|
+
rootNodes,
|
|
2889
3756
|
maxId: idAllocator.getMaxId(),
|
|
2890
3757
|
revisions: [{ revision }],
|
|
2891
3758
|
});
|
|
@@ -2896,6 +3763,7 @@ function buildModularChangesetFromField(props: {
|
|
|
2896
3763
|
};
|
|
2897
3764
|
|
|
2898
3765
|
const parentId: NodeId = { localId: brand(idAllocator.allocate()), revision };
|
|
3766
|
+
const fieldId = { nodeId: parentId, field: path.field };
|
|
2899
3767
|
|
|
2900
3768
|
for (const { key, count } of localCrossFieldKeys) {
|
|
2901
3769
|
crossFieldKeys.set(key, count, { nodeId: parentId, field: path.field });
|
|
@@ -2903,8 +3771,7 @@ function buildModularChangesetFromField(props: {
|
|
|
2903
3771
|
|
|
2904
3772
|
if (childId !== undefined) {
|
|
2905
3773
|
setInChangeAtomIdMap(nodeToParent, childId, {
|
|
2906
|
-
|
|
2907
|
-
field: path.field,
|
|
3774
|
+
field: fieldId,
|
|
2908
3775
|
});
|
|
2909
3776
|
}
|
|
2910
3777
|
|
|
@@ -2914,6 +3781,7 @@ function buildModularChangesetFromField(props: {
|
|
|
2914
3781
|
nodeChanges,
|
|
2915
3782
|
nodeToParent,
|
|
2916
3783
|
crossFieldKeys,
|
|
3784
|
+
rootNodes,
|
|
2917
3785
|
idAllocator,
|
|
2918
3786
|
revision,
|
|
2919
3787
|
nodeId: parentId,
|
|
@@ -2921,41 +3789,62 @@ function buildModularChangesetFromField(props: {
|
|
|
2921
3789
|
}
|
|
2922
3790
|
|
|
2923
3791
|
function buildModularChangesetFromNode(props: {
|
|
2924
|
-
path:
|
|
3792
|
+
path: NormalizedUpPath;
|
|
2925
3793
|
nodeChange: NodeChangeset;
|
|
2926
3794
|
nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
|
|
2927
|
-
nodeToParent: ChangeAtomIdBTree<
|
|
3795
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation>;
|
|
2928
3796
|
crossFieldKeys: CrossFieldKeyTable;
|
|
3797
|
+
rootNodes: RootNodeTable;
|
|
2929
3798
|
idAllocator: IdAllocator;
|
|
2930
3799
|
revision: RevisionTag;
|
|
2931
3800
|
nodeId?: NodeId;
|
|
2932
3801
|
}): ModularChangeset {
|
|
2933
3802
|
const {
|
|
2934
3803
|
path,
|
|
2935
|
-
|
|
3804
|
+
idAllocator,
|
|
3805
|
+
revision,
|
|
3806
|
+
nodeChanges,
|
|
3807
|
+
nodeChange,
|
|
3808
|
+
nodeId = { localId: brand(idAllocator.allocate()), revision },
|
|
2936
3809
|
} = props;
|
|
2937
|
-
setInChangeAtomIdMap(
|
|
2938
|
-
const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChanges([
|
|
2939
|
-
[path.parentIndex, nodeId],
|
|
2940
|
-
]);
|
|
2941
|
-
|
|
2942
|
-
const fieldChange: FieldChange = {
|
|
2943
|
-
fieldKind: genericFieldKind.identifier,
|
|
2944
|
-
change: fieldChangeset,
|
|
2945
|
-
};
|
|
3810
|
+
setInChangeAtomIdMap(nodeChanges, nodeId, nodeChange);
|
|
2946
3811
|
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
3812
|
+
if (isDetachedUpPathRoot(path)) {
|
|
3813
|
+
props.rootNodes.nodeChanges.set(
|
|
3814
|
+
[path.detachedNodeId.major, brand(path.detachedNodeId.minor)],
|
|
3815
|
+
nodeId,
|
|
3816
|
+
);
|
|
3817
|
+
return makeModularChangeset({
|
|
3818
|
+
rootNodes: props.rootNodes,
|
|
3819
|
+
nodeChanges: props.nodeChanges,
|
|
3820
|
+
nodeToParent: props.nodeToParent,
|
|
3821
|
+
crossFieldKeys: props.crossFieldKeys,
|
|
3822
|
+
maxId: props.idAllocator.getMaxId(),
|
|
3823
|
+
revisions: [{ revision: props.revision }],
|
|
3824
|
+
});
|
|
3825
|
+
} else {
|
|
3826
|
+
const fieldChangeset = genericFieldKind.changeHandler.editor.buildChildChanges([
|
|
3827
|
+
[path.parentIndex, nodeId],
|
|
3828
|
+
]);
|
|
3829
|
+
|
|
3830
|
+
const fieldChange: FieldChange = {
|
|
3831
|
+
fieldKind: genericFieldKind.identifier,
|
|
3832
|
+
change: fieldChangeset,
|
|
3833
|
+
};
|
|
3834
|
+
|
|
3835
|
+
return buildModularChangesetFromField({
|
|
3836
|
+
...props,
|
|
3837
|
+
path: { parent: path.parent, field: path.parentField },
|
|
3838
|
+
fieldChange,
|
|
3839
|
+
localCrossFieldKeys: [],
|
|
3840
|
+
childId: nodeId,
|
|
3841
|
+
});
|
|
3842
|
+
}
|
|
2954
3843
|
}
|
|
2955
3844
|
|
|
2956
3845
|
export interface FieldEditDescription {
|
|
2957
3846
|
type: "field";
|
|
2958
|
-
field:
|
|
3847
|
+
field: NormalizedFieldUpPath;
|
|
2959
3848
|
fieldKind: FieldKindIdentifier;
|
|
2960
3849
|
change: FieldChangeset;
|
|
2961
3850
|
revision: RevisionTag;
|
|
@@ -2965,6 +3854,23 @@ export interface GlobalEditDescription {
|
|
|
2965
3854
|
type: "global";
|
|
2966
3855
|
revision: RevisionTag;
|
|
2967
3856
|
builds?: ChangeAtomIdBTree<TreeChunk>;
|
|
3857
|
+
renames?: RenameDescription[];
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3860
|
+
export interface RenameDescription {
|
|
3861
|
+
count: number;
|
|
3862
|
+
oldId: ChangeAtomId;
|
|
3863
|
+
newId: ChangeAtomId;
|
|
3864
|
+
detachLocation: FieldId | undefined;
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
function renameTableFromRenameDescriptions(renames: RenameDescription[]): RootNodeTable {
|
|
3868
|
+
const table = newRootTable();
|
|
3869
|
+
for (const rename of renames) {
|
|
3870
|
+
addNodeRename(table, rename.oldId, rename.newId, rename.count, rename.detachLocation);
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3873
|
+
return table;
|
|
2968
3874
|
}
|
|
2969
3875
|
|
|
2970
3876
|
export type EditDescription = FieldEditDescription | GlobalEditDescription;
|
|
@@ -2975,25 +3881,16 @@ function getRevInfoFromTaggedChanges(changes: TaggedChange<ModularChangeset>[]):
|
|
|
2975
3881
|
} {
|
|
2976
3882
|
let maxId = -1;
|
|
2977
3883
|
const revInfos: RevisionInfo[] = [];
|
|
3884
|
+
const revisions = new Set<RevisionTag>();
|
|
2978
3885
|
for (const taggedChange of changes) {
|
|
2979
3886
|
const change = taggedChange.change;
|
|
2980
3887
|
maxId = Math.max(change.maxId ?? -1, maxId);
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
revisions.add(info.revision);
|
|
2988
|
-
if (info.rollbackOf !== undefined) {
|
|
2989
|
-
rolledBackRevisions.push(info.rollbackOf);
|
|
2990
|
-
}
|
|
2991
|
-
}
|
|
2992
|
-
|
|
2993
|
-
rolledBackRevisions.reverse();
|
|
2994
|
-
for (const revision of rolledBackRevisions) {
|
|
2995
|
-
if (!revisions.has(revision)) {
|
|
2996
|
-
revInfos.push({ revision });
|
|
3888
|
+
const infosToAdd = revisionInfoFromTaggedChange(taggedChange);
|
|
3889
|
+
for (const info of infosToAdd) {
|
|
3890
|
+
if (!revisions.has(info.revision)) {
|
|
3891
|
+
revisions.add(info.revision);
|
|
3892
|
+
revInfos.push(info);
|
|
3893
|
+
}
|
|
2997
3894
|
}
|
|
2998
3895
|
}
|
|
2999
3896
|
|
|
@@ -3016,25 +3913,28 @@ function revisionInfoFromTaggedChange(
|
|
|
3016
3913
|
return revInfos;
|
|
3017
3914
|
}
|
|
3018
3915
|
|
|
3019
|
-
function fieldChangeFromId(
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3916
|
+
function fieldChangeFromId(change: ModularChangeset, id: FieldId): FieldChange {
|
|
3917
|
+
const fieldId = normalizeFieldId(id, change.nodeAliases);
|
|
3918
|
+
const fieldMap = fieldMapFromNodeId(
|
|
3919
|
+
change.fieldChanges,
|
|
3920
|
+
change.nodeChanges,
|
|
3921
|
+
change.nodeAliases,
|
|
3922
|
+
fieldId.nodeId,
|
|
3923
|
+
);
|
|
3025
3924
|
return fieldMap.get(id.field) ?? fail(0xb25 /* No field exists for the given ID */);
|
|
3026
3925
|
}
|
|
3027
3926
|
|
|
3028
3927
|
function fieldMapFromNodeId(
|
|
3029
3928
|
rootFieldMap: FieldChangeMap,
|
|
3030
3929
|
nodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
3930
|
+
aliases: ChangeAtomIdBTree<NodeId>,
|
|
3031
3931
|
nodeId: NodeId | undefined,
|
|
3032
3932
|
): FieldChangeMap {
|
|
3033
3933
|
if (nodeId === undefined) {
|
|
3034
3934
|
return rootFieldMap;
|
|
3035
3935
|
}
|
|
3036
3936
|
|
|
3037
|
-
const node = nodeChangeFromId(nodes, nodeId);
|
|
3937
|
+
const node = nodeChangeFromId(nodes, aliases, nodeId);
|
|
3038
3938
|
assert(node.fieldChanges !== undefined, 0x9c9 /* Expected node to have field changes */);
|
|
3039
3939
|
return node.fieldChanges;
|
|
3040
3940
|
}
|
|
@@ -3051,17 +3951,26 @@ function rebasedNodeIdFromBaseNodeId(table: RebaseTable, baseId: NodeId): NodeId
|
|
|
3051
3951
|
return getFromChangeAtomIdMap(table.baseToRebasedNodeId, baseId) ?? baseId;
|
|
3052
3952
|
}
|
|
3053
3953
|
|
|
3054
|
-
function nodeChangeFromId(
|
|
3055
|
-
|
|
3954
|
+
function nodeChangeFromId(
|
|
3955
|
+
nodes: ChangeAtomIdBTree<NodeChangeset>,
|
|
3956
|
+
aliases: ChangeAtomIdBTree<NodeId>,
|
|
3957
|
+
id: NodeId,
|
|
3958
|
+
): NodeChangeset {
|
|
3959
|
+
const normalizedId = normalizeNodeId(id, aliases);
|
|
3960
|
+
const node = getFromChangeAtomIdMap(nodes, normalizedId);
|
|
3056
3961
|
assert(node !== undefined, 0x9ca /* Unknown node ID */);
|
|
3057
3962
|
return node;
|
|
3058
3963
|
}
|
|
3059
3964
|
|
|
3060
3965
|
function fieldIdFromFieldIdKey([revision, localId, field]: FieldIdKey): FieldId {
|
|
3061
|
-
const nodeId = localId
|
|
3966
|
+
const nodeId = localId === undefined ? undefined : { revision, localId };
|
|
3062
3967
|
return { nodeId, field };
|
|
3063
3968
|
}
|
|
3064
3969
|
|
|
3970
|
+
function fieldIdKeyFromFieldId(fieldId: FieldId): FieldIdKey {
|
|
3971
|
+
return [fieldId.nodeId?.revision, fieldId.nodeId?.localId, fieldId.field];
|
|
3972
|
+
}
|
|
3973
|
+
|
|
3065
3974
|
function cloneNodeChangeset(nodeChangeset: NodeChangeset): NodeChangeset {
|
|
3066
3975
|
if (nodeChangeset.fieldChanges !== undefined) {
|
|
3067
3976
|
return { ...nodeChangeset, fieldChanges: new Map(nodeChangeset.fieldChanges) };
|
|
@@ -3070,28 +3979,39 @@ function cloneNodeChangeset(nodeChangeset: NodeChangeset): NodeChangeset {
|
|
|
3070
3979
|
return { ...nodeChangeset };
|
|
3071
3980
|
}
|
|
3072
3981
|
|
|
3073
|
-
function
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3982
|
+
function replaceNodeLocationRevision(
|
|
3983
|
+
location: NodeLocation,
|
|
3984
|
+
replacer: RevisionReplacer,
|
|
3985
|
+
): NodeLocation {
|
|
3986
|
+
return location.field === undefined
|
|
3987
|
+
? { root: replacer.getUpdatedAtomId(location.root) }
|
|
3988
|
+
: { field: replaceFieldIdRevision(location.field, replacer) };
|
|
3989
|
+
}
|
|
3990
|
+
|
|
3991
|
+
function replaceFieldIdRevision(fieldId: FieldId, replacer: RevisionReplacer): FieldId {
|
|
3078
3992
|
if (fieldId.nodeId === undefined) {
|
|
3079
3993
|
return fieldId;
|
|
3080
3994
|
}
|
|
3081
3995
|
|
|
3082
3996
|
return {
|
|
3083
3997
|
...fieldId,
|
|
3084
|
-
nodeId:
|
|
3998
|
+
nodeId: replacer.getUpdatedAtomId(fieldId.nodeId),
|
|
3085
3999
|
};
|
|
3086
4000
|
}
|
|
3087
4001
|
|
|
3088
|
-
export function
|
|
3089
|
-
const
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
}
|
|
4002
|
+
export function getNodeParent(changeset: ModularChangeset, nodeId: NodeId): NodeLocation {
|
|
4003
|
+
const normalizedNodeId = normalizeNodeId(nodeId, changeset.nodeAliases);
|
|
4004
|
+
const location = getFromChangeAtomIdMap(changeset.nodeToParent, normalizedNodeId);
|
|
4005
|
+
assert(location !== undefined, 0x9cb /* Parent field should be defined */);
|
|
3093
4006
|
|
|
3094
|
-
|
|
4007
|
+
if (location.field !== undefined) {
|
|
4008
|
+
return { field: normalizeFieldId(location.field, changeset.nodeAliases) };
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
return location;
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
function getFieldsForCrossFieldKey(
|
|
3095
4015
|
changeset: ModularChangeset,
|
|
3096
4016
|
key: CrossFieldKey,
|
|
3097
4017
|
count: number,
|
|
@@ -3101,21 +4021,49 @@ function getFieldsForCrossFieldKey(
|
|
|
3101
4021
|
.map(({ value: fieldId }) => normalizeFieldId(fieldId, changeset.nodeAliases));
|
|
3102
4022
|
}
|
|
3103
4023
|
|
|
4024
|
+
function getFirstFieldForCrossFieldKey(
|
|
4025
|
+
changeset: ModularChangeset,
|
|
4026
|
+
key: CrossFieldKey,
|
|
4027
|
+
count: number,
|
|
4028
|
+
): RangeQueryResult<FieldId | undefined> {
|
|
4029
|
+
const result = changeset.crossFieldKeys.getFirst(key, count);
|
|
4030
|
+
if (result.value === undefined) {
|
|
4031
|
+
return result;
|
|
4032
|
+
}
|
|
4033
|
+
|
|
4034
|
+
return { ...result, value: normalizeFieldId(result.value, changeset.nodeAliases) };
|
|
4035
|
+
}
|
|
4036
|
+
|
|
4037
|
+
function normalizeNodeLocation(
|
|
4038
|
+
location: NodeLocation,
|
|
4039
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
4040
|
+
): NodeLocation {
|
|
4041
|
+
if (location.field !== undefined) {
|
|
4042
|
+
return { field: normalizeFieldId(location.field, nodeAliases) };
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
return location;
|
|
4046
|
+
}
|
|
4047
|
+
|
|
3104
4048
|
// This is only exported for use in test utilities.
|
|
3105
4049
|
export function normalizeFieldId(
|
|
3106
4050
|
fieldId: FieldId,
|
|
3107
4051
|
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
3108
4052
|
): FieldId {
|
|
3109
|
-
return fieldId.nodeId
|
|
3110
|
-
?
|
|
3111
|
-
: fieldId;
|
|
4053
|
+
return fieldId.nodeId === undefined
|
|
4054
|
+
? fieldId
|
|
4055
|
+
: { ...fieldId, nodeId: normalizeNodeId(fieldId.nodeId, nodeAliases) };
|
|
3112
4056
|
}
|
|
3113
4057
|
|
|
3114
4058
|
/**
|
|
3115
4059
|
* @returns The canonical form of nodeId, according to nodeAliases
|
|
3116
4060
|
*/
|
|
3117
|
-
function normalizeNodeId(
|
|
4061
|
+
export function normalizeNodeId(
|
|
4062
|
+
nodeId: NodeId,
|
|
4063
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
4064
|
+
): NodeId {
|
|
3118
4065
|
let currentId = nodeId;
|
|
4066
|
+
let cycleProbeId: NodeId | undefined = nodeId;
|
|
3119
4067
|
|
|
3120
4068
|
// eslint-disable-next-line no-constant-condition
|
|
3121
4069
|
while (true) {
|
|
@@ -3125,6 +4073,16 @@ function normalizeNodeId(nodeId: NodeId, nodeAliases: ChangeAtomIdBTree<NodeId>)
|
|
|
3125
4073
|
}
|
|
3126
4074
|
|
|
3127
4075
|
currentId = dealiased;
|
|
4076
|
+
|
|
4077
|
+
if (cycleProbeId !== undefined) {
|
|
4078
|
+
cycleProbeId = getFromChangeAtomIdMap(nodeAliases, cycleProbeId);
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
if (cycleProbeId !== undefined) {
|
|
4082
|
+
cycleProbeId = getFromChangeAtomIdMap(nodeAliases, cycleProbeId);
|
|
4083
|
+
}
|
|
4084
|
+
|
|
4085
|
+
assert(!areEqualChangeAtomIdOpts(cycleProbeId, currentId), "Alias cycle detected");
|
|
3128
4086
|
}
|
|
3129
4087
|
}
|
|
3130
4088
|
|
|
@@ -3135,22 +4093,936 @@ function hasConflicts(change: ModularChangeset): boolean {
|
|
|
3135
4093
|
interface ModularChangesetContent {
|
|
3136
4094
|
fieldChanges: FieldChangeMap;
|
|
3137
4095
|
nodeChanges: ChangeAtomIdBTree<NodeChangeset>;
|
|
3138
|
-
nodeToParent: ChangeAtomIdBTree<
|
|
4096
|
+
nodeToParent: ChangeAtomIdBTree<NodeLocation>;
|
|
4097
|
+
rootNodes: RootNodeTable;
|
|
3139
4098
|
nodeAliases: ChangeAtomIdBTree<NodeId>;
|
|
3140
4099
|
crossFieldKeys: CrossFieldKeyTable;
|
|
3141
4100
|
}
|
|
3142
4101
|
|
|
3143
|
-
function
|
|
3144
|
-
|
|
4102
|
+
function areEqualFieldIds(a: FieldId, b: FieldId): boolean {
|
|
4103
|
+
return areEqualChangeAtomIdOpts(a.nodeId, b.nodeId) && a.field === b.field;
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
function firstAttachIdFromDetachId(
|
|
4107
|
+
roots: RootNodeTable,
|
|
4108
|
+
detachId: ChangeAtomId,
|
|
4109
|
+
count: number,
|
|
4110
|
+
): RangeQueryResult<ChangeAtomId> {
|
|
4111
|
+
const result = roots.oldToNewId.getFirst(detachId, count);
|
|
4112
|
+
return { ...result, value: result.value ?? detachId };
|
|
4113
|
+
}
|
|
4114
|
+
|
|
4115
|
+
function firstDetachIdFromAttachId(
|
|
4116
|
+
roots: RootNodeTable,
|
|
4117
|
+
attachId: ChangeAtomId,
|
|
4118
|
+
count: number,
|
|
4119
|
+
): RangeQueryEntry<ChangeAtomId, ChangeAtomId> {
|
|
4120
|
+
const result = roots.newToOldId.getFirst(attachId, count);
|
|
4121
|
+
return { ...result, start: attachId, value: result.value ?? attachId };
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
function rebaseCrossFieldKeys(
|
|
4125
|
+
sourceTable: CrossFieldKeyTable,
|
|
4126
|
+
movedDetaches: ChangeAtomIdRangeMap<boolean>,
|
|
4127
|
+
newDetachLocations: ChangeAtomIdRangeMap<FieldId>,
|
|
4128
|
+
): CrossFieldKeyTable {
|
|
4129
|
+
const rebasedTable = sourceTable.clone();
|
|
4130
|
+
for (const entry of movedDetaches.entries()) {
|
|
4131
|
+
rebasedTable.delete({ ...entry.start, target: CrossFieldTarget.Source }, entry.length);
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4134
|
+
for (const entry of newDetachLocations.entries()) {
|
|
4135
|
+
rebasedTable.set(
|
|
4136
|
+
{ ...entry.start, target: CrossFieldTarget.Source },
|
|
4137
|
+
entry.length,
|
|
4138
|
+
entry.value,
|
|
4139
|
+
);
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
return rebasedTable;
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
export function newRootTable(): RootNodeTable {
|
|
4146
|
+
return {
|
|
4147
|
+
newToOldId: newChangeAtomIdTransform(),
|
|
4148
|
+
oldToNewId: newChangeAtomIdTransform(),
|
|
4149
|
+
nodeChanges: newTupleBTree(),
|
|
4150
|
+
detachLocations: newChangeAtomIdRangeMap(),
|
|
4151
|
+
outputDetachLocations: newChangeAtomIdRangeMap(),
|
|
4152
|
+
};
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4155
|
+
function rebaseRoots(
|
|
4156
|
+
change: ModularChangeset,
|
|
4157
|
+
base: ModularChangeset,
|
|
4158
|
+
affectedBaseFields: TupleBTree<FieldIdKey, boolean>,
|
|
4159
|
+
nodesToRebase: [newChangeset: NodeId, baseChangeset: NodeId][],
|
|
4160
|
+
rebasedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
4161
|
+
rebaseVersion: RebaseVersion,
|
|
4162
|
+
): RootNodeTable {
|
|
4163
|
+
const rebasedRoots = newRootTable();
|
|
4164
|
+
for (const renameEntry of change.rootNodes.oldToNewId.entries()) {
|
|
4165
|
+
rebaseRename(change.rootNodes, rebasedRoots, renameEntry, base, affectedBaseFields);
|
|
4166
|
+
}
|
|
4167
|
+
|
|
4168
|
+
for (const [detachIdKey, nodeId] of change.rootNodes.nodeChanges.entries()) {
|
|
4169
|
+
const changes = base.rootNodes.nodeChanges.get(detachIdKey);
|
|
4170
|
+
if (changes !== undefined) {
|
|
4171
|
+
nodesToRebase.push([nodeId, changes]);
|
|
4172
|
+
}
|
|
4173
|
+
|
|
4174
|
+
const detachId = makeChangeAtomId(detachIdKey[1], detachIdKey[0]);
|
|
4175
|
+
const attachId = firstAttachIdFromDetachId(base.rootNodes, detachId, 1).value;
|
|
4176
|
+
const baseAttachEntry = base.crossFieldKeys.getFirst(
|
|
4177
|
+
{ target: CrossFieldTarget.Destination, ...attachId },
|
|
4178
|
+
1,
|
|
4179
|
+
);
|
|
4180
|
+
if (baseAttachEntry.value === undefined) {
|
|
4181
|
+
const renamedDetachId = firstAttachIdFromDetachId(base.rootNodes, detachId, 1).value;
|
|
4182
|
+
const baseOutputDetachLocation = base.rootNodes.outputDetachLocations.getFirst(
|
|
4183
|
+
renamedDetachId,
|
|
4184
|
+
1,
|
|
4185
|
+
).value;
|
|
4186
|
+
|
|
4187
|
+
if (baseOutputDetachLocation !== undefined) {
|
|
4188
|
+
affectedBaseFields.set(fieldIdKeyFromFieldId(baseOutputDetachLocation), true);
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
const detachLocation =
|
|
4192
|
+
baseOutputDetachLocation ??
|
|
4193
|
+
change.rootNodes.detachLocations.getFirst(detachId, 1).value;
|
|
4194
|
+
|
|
4195
|
+
// Note that `baseOutputDetachLocation` may contain a node ID from the base changeset.
|
|
4196
|
+
// We will replace the detach location entry with the node ID from the rebased changeset in `fixupRebasedDetachLocations`
|
|
4197
|
+
assignRootChange(
|
|
4198
|
+
rebasedRoots,
|
|
4199
|
+
rebasedNodeToParent,
|
|
4200
|
+
renamedDetachId,
|
|
4201
|
+
nodeId,
|
|
4202
|
+
detachLocation,
|
|
4203
|
+
rebaseVersion,
|
|
4204
|
+
);
|
|
4205
|
+
} else {
|
|
4206
|
+
affectedBaseFields.set(fieldIdKeyFromFieldId(baseAttachEntry.value), true);
|
|
4207
|
+
rebasedNodeToParent.delete(detachIdKey);
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
for (const entry of change.rootNodes.outputDetachLocations.entries()) {
|
|
4212
|
+
rebasedRoots.outputDetachLocations.set(entry.start, entry.length, entry.value);
|
|
4213
|
+
}
|
|
4214
|
+
|
|
4215
|
+
return rebasedRoots;
|
|
4216
|
+
}
|
|
4217
|
+
|
|
4218
|
+
function rebaseRename(
|
|
4219
|
+
newRoots: RootNodeTable,
|
|
4220
|
+
rebasedRoots: RootNodeTable,
|
|
4221
|
+
renameEntry: RangeQueryEntry<ChangeAtomId, ChangeAtomId>,
|
|
4222
|
+
base: ModularChangeset,
|
|
4223
|
+
affectedBaseFields: TupleBTree<FieldIdKey, boolean>,
|
|
4224
|
+
): void {
|
|
4225
|
+
let count = renameEntry.length;
|
|
4226
|
+
const baseRenameEntry = firstAttachIdFromDetachId(base.rootNodes, renameEntry.start, count);
|
|
4227
|
+
count = baseRenameEntry.length;
|
|
4228
|
+
|
|
4229
|
+
const baseAttachEntry = base.crossFieldKeys.getFirst(
|
|
4230
|
+
{
|
|
4231
|
+
...baseRenameEntry.value,
|
|
4232
|
+
target: CrossFieldTarget.Destination,
|
|
4233
|
+
},
|
|
4234
|
+
count,
|
|
4235
|
+
);
|
|
4236
|
+
|
|
4237
|
+
count = baseAttachEntry.length;
|
|
4238
|
+
|
|
4239
|
+
if (baseAttachEntry.value === undefined) {
|
|
4240
|
+
const baseOutputDetachLocation = base.rootNodes.outputDetachLocations.getFirst(
|
|
4241
|
+
baseRenameEntry.value,
|
|
4242
|
+
1,
|
|
4243
|
+
).value;
|
|
4244
|
+
|
|
4245
|
+
if (baseOutputDetachLocation !== undefined) {
|
|
4246
|
+
affectedBaseFields.set(fieldIdKeyFromFieldId(baseOutputDetachLocation), true);
|
|
4247
|
+
}
|
|
4248
|
+
|
|
4249
|
+
const detachEntry = newRoots.detachLocations.getFirst(renameEntry.start, count);
|
|
4250
|
+
count = detachEntry.length;
|
|
4251
|
+
|
|
4252
|
+
const detachLocation = baseOutputDetachLocation ?? detachEntry.value;
|
|
4253
|
+
|
|
4254
|
+
// Note that `baseOutputDetachLocation` may contain a node ID from the base changeset.
|
|
4255
|
+
// We will replace the detach location entry with the node ID from the rebased changeset in `fixupRebasedDetachLocations`
|
|
4256
|
+
addNodeRename(
|
|
4257
|
+
rebasedRoots,
|
|
4258
|
+
baseRenameEntry.value,
|
|
4259
|
+
renameEntry.value,
|
|
4260
|
+
count,
|
|
4261
|
+
detachLocation,
|
|
4262
|
+
);
|
|
4263
|
+
} else {
|
|
4264
|
+
// This rename represents an intention to detach these nodes.
|
|
4265
|
+
// The rebased change should have a detach in the field where the base change attaches the nodes,
|
|
4266
|
+
// so we need to ensure that field is processed.
|
|
4267
|
+
affectedBaseFields.set(
|
|
4268
|
+
fieldIdKeyFromFieldId(normalizeFieldId(baseAttachEntry.value, base.nodeAliases)),
|
|
4269
|
+
true,
|
|
4270
|
+
);
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
const countRemaining = renameEntry.length - count;
|
|
4274
|
+
if (countRemaining > 0) {
|
|
4275
|
+
rebaseRename(
|
|
4276
|
+
newRoots,
|
|
4277
|
+
rebasedRoots,
|
|
4278
|
+
{
|
|
4279
|
+
start: offsetChangeAtomId(renameEntry.start, count),
|
|
4280
|
+
value: offsetChangeAtomId(renameEntry.value, count),
|
|
4281
|
+
length: countRemaining,
|
|
4282
|
+
},
|
|
4283
|
+
base,
|
|
4284
|
+
affectedBaseFields,
|
|
4285
|
+
);
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
|
|
4289
|
+
/**
|
|
4290
|
+
* For each root detach location, replaces any node ID from the base changeset
|
|
4291
|
+
* with the corresponding ID in the new changeset.
|
|
4292
|
+
*/
|
|
4293
|
+
function fixupRebasedDetachLocations(table: RebaseTable): void {
|
|
4294
|
+
for (const {
|
|
4295
|
+
start,
|
|
4296
|
+
length,
|
|
4297
|
+
value: detachLocation,
|
|
4298
|
+
} of table.rebasedRootNodes.detachLocations.entries()) {
|
|
4299
|
+
const normalizedDetachLocation = normalizeFieldId(
|
|
4300
|
+
detachLocation,
|
|
4301
|
+
table.baseChange.nodeAliases,
|
|
4302
|
+
);
|
|
4303
|
+
|
|
4304
|
+
if (normalizedDetachLocation.nodeId !== undefined) {
|
|
4305
|
+
const rebasedNodeId = getFromChangeAtomIdMap(
|
|
4306
|
+
table.baseToRebasedNodeId,
|
|
4307
|
+
normalizedDetachLocation.nodeId,
|
|
4308
|
+
);
|
|
4309
|
+
|
|
4310
|
+
if (rebasedNodeId !== undefined) {
|
|
4311
|
+
table.rebasedRootNodes.detachLocations.set(start, length, {
|
|
4312
|
+
...normalizedDetachLocation,
|
|
4313
|
+
nodeId: rebasedNodeId,
|
|
4314
|
+
});
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
function addNodesToCompose(table: ComposeTable, id1: NodeId, id2: NodeId): void {
|
|
4321
|
+
const normalizedId1 = normalizeNodeId(id1, table.baseChange.nodeAliases);
|
|
4322
|
+
const normalizedId2 = normalizeNodeId(id2, table.newChange.nodeAliases);
|
|
4323
|
+
if (getFromChangeAtomIdMap(table.newToBaseNodeId, normalizedId2) === undefined) {
|
|
4324
|
+
setInChangeAtomIdMap(table.newToBaseNodeId, normalizedId2, normalizedId1);
|
|
4325
|
+
table.pendingCompositions.nodeIdsToCompose.push([normalizedId1, normalizedId2]);
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
function composeRevInfos(
|
|
4330
|
+
revisions1: readonly RevisionInfo[] | undefined,
|
|
4331
|
+
revisions2: readonly RevisionInfo[] | undefined,
|
|
4332
|
+
): readonly RevisionInfo[] {
|
|
4333
|
+
if (
|
|
4334
|
+
revisions1?.length === 1 &&
|
|
4335
|
+
revisions2?.length === 1 &&
|
|
4336
|
+
revisions1[0]?.revision === revisions2[0]?.revision
|
|
4337
|
+
) {
|
|
4338
|
+
// This is a special case where we are composing two changesets from the same transaction.
|
|
4339
|
+
// We return one of the input arrays to avoid duplicating revision entries.
|
|
4340
|
+
return revisions1;
|
|
4341
|
+
}
|
|
4342
|
+
const result: RevisionInfo[] = [...(revisions1 ?? []), ...(revisions2 ?? [])];
|
|
4343
|
+
return result;
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
function composeCrossFieldKeyTables(
|
|
4347
|
+
table1: CrossFieldKeyTable,
|
|
4348
|
+
table2: CrossFieldKeyTable,
|
|
4349
|
+
movedCrossFieldKeys: CrossFieldKeyTable,
|
|
4350
|
+
removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
|
|
4351
|
+
): CrossFieldKeyTable {
|
|
4352
|
+
const composedTable = RangeMap.union(table1, table2);
|
|
4353
|
+
for (const entry of movedCrossFieldKeys.entries()) {
|
|
4354
|
+
composedTable.set(entry.start, entry.length, entry.value);
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
for (const entry of removedCrossFieldKeys.entries()) {
|
|
4358
|
+
composedTable.delete(entry.start, entry.length);
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
return composedTable;
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
function composeRootTables(
|
|
4365
|
+
change1: ModularChangeset,
|
|
4366
|
+
change2: ModularChangeset,
|
|
4367
|
+
composedNodeToParent: ChangeAtomIdBTree<NodeLocation>,
|
|
4368
|
+
movedCrossFieldKeys: CrossFieldKeyTable,
|
|
4369
|
+
removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
|
|
4370
|
+
pendingCompositions: PendingCompositions,
|
|
4371
|
+
): RootNodeTable {
|
|
4372
|
+
const composedTable = cloneRootTable(change1.rootNodes);
|
|
4373
|
+
|
|
4374
|
+
for (const renameEntry of change2.rootNodes.oldToNewId.entries()) {
|
|
4375
|
+
composeRename(
|
|
4376
|
+
change1,
|
|
4377
|
+
change2,
|
|
4378
|
+
composedTable,
|
|
4379
|
+
renameEntry.start,
|
|
4380
|
+
renameEntry.value,
|
|
4381
|
+
renameEntry.length,
|
|
4382
|
+
movedCrossFieldKeys,
|
|
4383
|
+
removedCrossFieldKeys,
|
|
4384
|
+
pendingCompositions,
|
|
4385
|
+
);
|
|
4386
|
+
}
|
|
4387
|
+
|
|
4388
|
+
for (const [[revision2, id2], nodeId2] of change2.rootNodes.nodeChanges.entries()) {
|
|
4389
|
+
const detachId2 = { revision: revision2, localId: id2 };
|
|
4390
|
+
const detachId1 = firstDetachIdFromAttachId(change1.rootNodes, detachId2, 1).value;
|
|
4391
|
+
const nodeId1 = getFromChangeAtomIdMap(change1.rootNodes.nodeChanges, detachId1);
|
|
4392
|
+
|
|
4393
|
+
if (nodeId1 === undefined) {
|
|
4394
|
+
const fieldId = getFieldsForCrossFieldKey(
|
|
4395
|
+
change1,
|
|
4396
|
+
{ ...detachId1, target: CrossFieldTarget.Source },
|
|
4397
|
+
1,
|
|
4398
|
+
)[0];
|
|
4399
|
+
|
|
4400
|
+
if (fieldId === undefined) {
|
|
4401
|
+
assignRootChange(
|
|
4402
|
+
composedTable,
|
|
4403
|
+
composedNodeToParent,
|
|
4404
|
+
detachId1,
|
|
4405
|
+
nodeId2,
|
|
4406
|
+
change1.rootNodes.detachLocations.getFirst(detachId1, 1).value ??
|
|
4407
|
+
change2.rootNodes.detachLocations.getFirst(detachId2, 1).value,
|
|
4408
|
+
Math.max(change1.rebaseVersion, change2.rebaseVersion) as RebaseVersion,
|
|
4409
|
+
);
|
|
4410
|
+
} else {
|
|
4411
|
+
// In this case, this node is attached in the input context of change1,
|
|
4412
|
+
// and is represented in detachFieldId.
|
|
4413
|
+
pendingCompositions.affectedBaseFields.set(
|
|
4414
|
+
[fieldId.nodeId?.revision, fieldId.nodeId?.localId, fieldId.field],
|
|
4415
|
+
true,
|
|
4416
|
+
);
|
|
4417
|
+
}
|
|
4418
|
+
} else {
|
|
4419
|
+
pendingCompositions.nodeIdsToCompose.push([nodeId1, nodeId2]);
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
for (const outputDetachEntry of change1.rootNodes.outputDetachLocations.entries()) {
|
|
4424
|
+
composeOutputDetachLocation(
|
|
4425
|
+
outputDetachEntry.start,
|
|
4426
|
+
outputDetachEntry.length,
|
|
4427
|
+
outputDetachEntry.value,
|
|
4428
|
+
change2,
|
|
4429
|
+
composedTable,
|
|
4430
|
+
);
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
for (const entry of change2.rootNodes.outputDetachLocations.entries()) {
|
|
4434
|
+
composedTable.outputDetachLocations.set(entry.start, entry.length, entry.value);
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
return composedTable;
|
|
4438
|
+
}
|
|
4439
|
+
|
|
4440
|
+
function composeOutputDetachLocation(
|
|
4441
|
+
outputDetachId1: ChangeAtomId,
|
|
4442
|
+
count: number,
|
|
4443
|
+
detachLocation: FieldId,
|
|
4444
|
+
change2: ModularChangeset,
|
|
4445
|
+
composedTable: RootNodeTable,
|
|
4446
|
+
): void {
|
|
4447
|
+
let countToProcess = count;
|
|
4448
|
+
const renameEntry = firstAttachIdFromDetachId(
|
|
4449
|
+
change2.rootNodes,
|
|
4450
|
+
outputDetachId1,
|
|
4451
|
+
countToProcess,
|
|
4452
|
+
);
|
|
4453
|
+
countToProcess = renameEntry.length;
|
|
4454
|
+
|
|
4455
|
+
const attachEntry = getFirstAttachField(
|
|
4456
|
+
change2.crossFieldKeys,
|
|
4457
|
+
renameEntry.value,
|
|
4458
|
+
countToProcess,
|
|
4459
|
+
);
|
|
4460
|
+
countToProcess = attachEntry.length;
|
|
4461
|
+
|
|
4462
|
+
composedTable.outputDetachLocations.delete(outputDetachId1, countToProcess);
|
|
4463
|
+
|
|
4464
|
+
if (attachEntry.value === undefined) {
|
|
4465
|
+
// We update the key for the detach location to the renamed ID of the root in the composed output context.
|
|
4466
|
+
composedTable.outputDetachLocations.set(renameEntry.value, countToProcess, detachLocation);
|
|
4467
|
+
} else {
|
|
4468
|
+
// These nodes are attached by `change2` and thus attached in the composed output context,
|
|
4469
|
+
// so there should be no output detach location.
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
const countRemaining = count - countToProcess;
|
|
4473
|
+
if (countRemaining > 0) {
|
|
4474
|
+
composeOutputDetachLocation(
|
|
4475
|
+
offsetChangeAtomId(outputDetachId1, countToProcess),
|
|
4476
|
+
countRemaining,
|
|
4477
|
+
detachLocation,
|
|
4478
|
+
change2,
|
|
4479
|
+
composedTable,
|
|
4480
|
+
);
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
function composeRename(
|
|
4485
|
+
change1: ModularChangeset,
|
|
4486
|
+
change2: ModularChangeset,
|
|
4487
|
+
mergedTable: RootNodeTable,
|
|
4488
|
+
oldId: ChangeAtomId,
|
|
4489
|
+
newId: ChangeAtomId,
|
|
4490
|
+
count: number,
|
|
4491
|
+
movedCrossFieldKeys: CrossFieldKeyTable,
|
|
4492
|
+
removedCrossFieldKeys: CrossFieldRangeTable<boolean>,
|
|
4493
|
+
pendingCompositions: PendingCompositions,
|
|
4494
|
+
): void {
|
|
4495
|
+
let countToProcess = count;
|
|
4496
|
+
const detachEntry = getFirstDetachField(change1.crossFieldKeys, oldId, countToProcess);
|
|
4497
|
+
countToProcess = detachEntry.length;
|
|
4498
|
+
|
|
4499
|
+
if (detachEntry.value === undefined) {
|
|
4500
|
+
// `change1` may also have a rename to `renameEntry.value`, in which case it must refer to a different node.
|
|
4501
|
+
// That node must have been attached by `change1` and detached by `change2`.
|
|
4502
|
+
// The final rename for that node will be created in `composeAttachDetach`.
|
|
4503
|
+
// We delete any such rename for now to avoid colliding with the rename currently being processed.
|
|
4504
|
+
deleteNodeRenameTo(mergedTable, newId, countToProcess);
|
|
4505
|
+
|
|
4506
|
+
// The nodes were detached before `change`, so we append this rename.
|
|
4507
|
+
appendNodeRename(
|
|
4508
|
+
mergedTable,
|
|
4509
|
+
oldId,
|
|
4510
|
+
newId,
|
|
4511
|
+
countToProcess,
|
|
4512
|
+
change1.rootNodes,
|
|
4513
|
+
change2.rootNodes.detachLocations.getFirst(oldId, countToProcess).value,
|
|
4514
|
+
);
|
|
4515
|
+
} else {
|
|
4516
|
+
// `change1` detached these nodes,
|
|
4517
|
+
// so we invalidate the detach location so that the detach's ID can be replaced with the new ID.
|
|
4518
|
+
pendingCompositions.affectedBaseFields.set(fieldIdKeyFromFieldId(detachEntry.value), true);
|
|
4519
|
+
|
|
4520
|
+
if (!areEqualChangeAtomIds(oldId, newId)) {
|
|
4521
|
+
// `change1`'s detach will be replaced by `change2`'s detach, so we update the cross-field keys.
|
|
4522
|
+
removedCrossFieldKeys.set(
|
|
4523
|
+
{ ...oldId, target: CrossFieldTarget.Source },
|
|
4524
|
+
countToProcess,
|
|
4525
|
+
true,
|
|
4526
|
+
);
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
movedCrossFieldKeys.set(
|
|
4530
|
+
{ ...newId, target: CrossFieldTarget.Source },
|
|
4531
|
+
countToProcess,
|
|
4532
|
+
detachEntry.value,
|
|
4533
|
+
);
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4536
|
+
if (countToProcess < count) {
|
|
4537
|
+
composeRename(
|
|
4538
|
+
change1,
|
|
4539
|
+
change2,
|
|
4540
|
+
mergedTable,
|
|
4541
|
+
offsetChangeAtomId(oldId, countToProcess),
|
|
4542
|
+
offsetChangeAtomId(newId, countToProcess),
|
|
4543
|
+
count - countToProcess,
|
|
4544
|
+
movedCrossFieldKeys,
|
|
4545
|
+
removedCrossFieldKeys,
|
|
4546
|
+
pendingCompositions,
|
|
4547
|
+
);
|
|
4548
|
+
}
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4551
|
+
export function cloneRootTable(table: RootNodeTable): RootNodeTable {
|
|
4552
|
+
return {
|
|
4553
|
+
oldToNewId: table.oldToNewId.clone(),
|
|
4554
|
+
newToOldId: table.newToOldId.clone(),
|
|
4555
|
+
nodeChanges: brand(table.nodeChanges.clone()),
|
|
4556
|
+
detachLocations: table.detachLocations.clone(),
|
|
4557
|
+
outputDetachLocations: table.outputDetachLocations.clone(),
|
|
4558
|
+
};
|
|
4559
|
+
}
|
|
4560
|
+
|
|
4561
|
+
function invertRootTable(change: ModularChangeset, isRollback: boolean): RootNodeTable {
|
|
4562
|
+
const invertedRoots: RootNodeTable = newRootTable();
|
|
4563
|
+
for (const [[revision, localId], nodeId] of change.rootNodes.nodeChanges.entries()) {
|
|
4564
|
+
const detachId: ChangeAtomId = { revision, localId };
|
|
4565
|
+
const renamedId = firstAttachIdFromDetachId(change.rootNodes, detachId, 1).value;
|
|
4566
|
+
|
|
4567
|
+
// This checks whether `change` attaches this node.
|
|
4568
|
+
// If it does, the node is not detached in the input context of the inverse, and so should not be included in the root table.
|
|
4569
|
+
if (
|
|
4570
|
+
change.crossFieldKeys.getFirst({ ...renamedId, target: CrossFieldTarget.Destination }, 1)
|
|
4571
|
+
.value === undefined
|
|
4572
|
+
) {
|
|
4573
|
+
assignRootChange(
|
|
4574
|
+
invertedRoots,
|
|
4575
|
+
undefined,
|
|
4576
|
+
renamedId,
|
|
4577
|
+
nodeId,
|
|
4578
|
+
change.rootNodes.detachLocations.getFirst(detachId, 1).value,
|
|
4579
|
+
change.rebaseVersion,
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
if (isRollback) {
|
|
4585
|
+
// We only invert renames of nodes which are not attached or detached by this changeset.
|
|
4586
|
+
// When we invert an attach we will create a detach which incorporates the rename.
|
|
4587
|
+
for (const {
|
|
4588
|
+
start: oldId,
|
|
4589
|
+
value: newId,
|
|
4590
|
+
length,
|
|
4591
|
+
} of change.rootNodes.oldToNewId.entries()) {
|
|
4592
|
+
invertRename(change, invertedRoots, oldId, newId, length);
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
|
|
4596
|
+
return invertedRoots;
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
function invertRename(
|
|
4600
|
+
change: ModularChangeset,
|
|
4601
|
+
invertedRoots: RootNodeTable,
|
|
4602
|
+
oldId: ChangeAtomId,
|
|
4603
|
+
newId: ChangeAtomId,
|
|
4604
|
+
length: number,
|
|
4605
|
+
): void {
|
|
4606
|
+
for (const detachEntry of doesChangeDetachNodes(change.crossFieldKeys, newId, length)) {
|
|
4607
|
+
assert(
|
|
4608
|
+
!detachEntry.value,
|
|
4609
|
+
"A changeset should not have a rename and detach for the same node.",
|
|
4610
|
+
);
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
let countProcessed = length;
|
|
4614
|
+
const attachEntry = getFirstAttachField(change.crossFieldKeys, newId, countProcessed);
|
|
4615
|
+
countProcessed = attachEntry.length;
|
|
4616
|
+
if (attachEntry.value === undefined) {
|
|
4617
|
+
const outputDetachEntry = change.rootNodes.outputDetachLocations.getFirst(
|
|
4618
|
+
newId,
|
|
4619
|
+
countProcessed,
|
|
4620
|
+
);
|
|
4621
|
+
countProcessed = outputDetachEntry.length;
|
|
4622
|
+
|
|
4623
|
+
const inputDetachEntry = change.rootNodes.detachLocations.getFirst(oldId, countProcessed);
|
|
4624
|
+
countProcessed = inputDetachEntry.length;
|
|
4625
|
+
|
|
4626
|
+
addNodeRename(
|
|
4627
|
+
invertedRoots,
|
|
4628
|
+
newId,
|
|
4629
|
+
oldId,
|
|
4630
|
+
countProcessed,
|
|
4631
|
+
outputDetachEntry.value ?? inputDetachEntry.value,
|
|
4632
|
+
);
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4635
|
+
if (countProcessed < length) {
|
|
4636
|
+
invertRename(
|
|
4637
|
+
change,
|
|
4638
|
+
invertedRoots,
|
|
4639
|
+
offsetChangeAtomId(oldId, countProcessed),
|
|
4640
|
+
offsetChangeAtomId(newId, countProcessed),
|
|
4641
|
+
length - countProcessed,
|
|
4642
|
+
);
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4646
|
+
function doesChangeAttachNodes(
|
|
4647
|
+
table: CrossFieldKeyTable,
|
|
3145
4648
|
id: ChangeAtomId,
|
|
3146
|
-
|
|
3147
|
-
|
|
4649
|
+
count: number,
|
|
4650
|
+
): RangeQueryResultFragment<boolean>[] {
|
|
4651
|
+
return table
|
|
4652
|
+
.getAll2({ ...id, target: CrossFieldTarget.Destination }, count)
|
|
4653
|
+
.map((entry) => ({ ...entry, value: entry.value !== undefined }));
|
|
3148
4654
|
}
|
|
3149
4655
|
|
|
3150
|
-
function
|
|
3151
|
-
|
|
4656
|
+
function doesChangeDetachNodes(
|
|
4657
|
+
table: CrossFieldKeyTable,
|
|
4658
|
+
id: ChangeAtomId,
|
|
4659
|
+
count: number,
|
|
4660
|
+
): RangeQueryResultFragment<boolean>[] {
|
|
4661
|
+
return table
|
|
4662
|
+
.getAll2({ ...id, target: CrossFieldTarget.Source }, count)
|
|
4663
|
+
.map((entry) => ({ ...entry, value: entry.value !== undefined }));
|
|
3152
4664
|
}
|
|
3153
4665
|
|
|
3154
|
-
function
|
|
3155
|
-
|
|
4666
|
+
export function getFirstDetachField(
|
|
4667
|
+
table: CrossFieldKeyTable,
|
|
4668
|
+
id: ChangeAtomId,
|
|
4669
|
+
count: number,
|
|
4670
|
+
): RangeQueryResult<FieldId | undefined> {
|
|
4671
|
+
return table.getFirst({ target: CrossFieldTarget.Source, ...id }, count);
|
|
4672
|
+
}
|
|
4673
|
+
|
|
4674
|
+
export function getFirstAttachField(
|
|
4675
|
+
table: CrossFieldKeyTable,
|
|
4676
|
+
id: ChangeAtomId,
|
|
4677
|
+
count: number,
|
|
4678
|
+
): RangeQueryResult<FieldId | undefined> {
|
|
4679
|
+
return table.getFirst({ target: CrossFieldTarget.Destination, ...id }, count);
|
|
4680
|
+
}
|
|
4681
|
+
|
|
4682
|
+
export function addNodeRename(
|
|
4683
|
+
table: RootNodeTable,
|
|
4684
|
+
oldId: ChangeAtomId,
|
|
4685
|
+
newId: ChangeAtomId,
|
|
4686
|
+
count: number,
|
|
4687
|
+
detachLocation: FieldId | undefined,
|
|
4688
|
+
): void {
|
|
4689
|
+
if (areEqualChangeAtomIds(oldId, newId)) {
|
|
4690
|
+
return;
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
for (const entry of table.oldToNewId.getAll2(oldId, count)) {
|
|
4694
|
+
assert(
|
|
4695
|
+
entry.value === undefined ||
|
|
4696
|
+
areEqualChangeAtomIds(entry.value, offsetChangeAtomId(newId, entry.offset)),
|
|
4697
|
+
"Rename collision detected",
|
|
4698
|
+
);
|
|
4699
|
+
}
|
|
4700
|
+
|
|
4701
|
+
for (const entry of table.newToOldId.getAll2(newId, count)) {
|
|
4702
|
+
assert(
|
|
4703
|
+
entry.value === undefined ||
|
|
4704
|
+
areEqualChangeAtomIds(entry.value, offsetChangeAtomId(oldId, entry.offset)),
|
|
4705
|
+
"Rename collision detected",
|
|
4706
|
+
);
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
table.oldToNewId.set(oldId, count, newId);
|
|
4710
|
+
table.newToOldId.set(newId, count, oldId);
|
|
4711
|
+
|
|
4712
|
+
if (detachLocation !== undefined) {
|
|
4713
|
+
table.detachLocations.set(oldId, count, detachLocation);
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
|
|
4717
|
+
/**
|
|
4718
|
+
* Deletes any renames from `id`.
|
|
4719
|
+
*/
|
|
4720
|
+
function deleteNodeRenameFrom(roots: RootNodeTable, id: ChangeAtomId, count: number): void {
|
|
4721
|
+
for (const entry of roots.oldToNewId.getAll(id, count)) {
|
|
4722
|
+
deleteNodeRenameEntry(roots, entry.start, entry.value, entry.length);
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
|
|
4726
|
+
/**
|
|
4727
|
+
* Deletes any renames to `id`.
|
|
4728
|
+
*/
|
|
4729
|
+
function deleteNodeRenameTo(roots: RootNodeTable, id: ChangeAtomId, count: number): void {
|
|
4730
|
+
for (const entry of roots.newToOldId.getAll(id, count)) {
|
|
4731
|
+
deleteNodeRenameEntry(roots, entry.value, entry.start, entry.length);
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
function appendNodeRename(
|
|
4736
|
+
composedTable: RootNodeTable,
|
|
4737
|
+
oldId: ChangeAtomId,
|
|
4738
|
+
newId: ChangeAtomId,
|
|
4739
|
+
count: number,
|
|
4740
|
+
change1Table: RootNodeTable,
|
|
4741
|
+
detachLocation: FieldId | undefined,
|
|
4742
|
+
): void {
|
|
4743
|
+
let countToProcess = count;
|
|
4744
|
+
const rename1Entry = change1Table.newToOldId.getFirst(oldId, countToProcess);
|
|
4745
|
+
countToProcess = rename1Entry.length;
|
|
4746
|
+
|
|
4747
|
+
if (rename1Entry.value !== undefined) {
|
|
4748
|
+
deleteNodeRenameFrom(composedTable, rename1Entry.value, countToProcess);
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4751
|
+
addNodeRename(
|
|
4752
|
+
composedTable,
|
|
4753
|
+
rename1Entry.value ?? oldId,
|
|
4754
|
+
newId,
|
|
4755
|
+
countToProcess,
|
|
4756
|
+
detachLocation,
|
|
4757
|
+
);
|
|
4758
|
+
|
|
4759
|
+
tryRemoveDetachLocation(composedTable, newId, countToProcess);
|
|
4760
|
+
|
|
4761
|
+
if (countToProcess < count) {
|
|
4762
|
+
const countRemaining = count - countToProcess;
|
|
4763
|
+
appendNodeRename(
|
|
4764
|
+
composedTable,
|
|
4765
|
+
offsetChangeAtomId(oldId, countToProcess),
|
|
4766
|
+
offsetChangeAtomId(newId, countToProcess),
|
|
4767
|
+
countRemaining,
|
|
4768
|
+
change1Table,
|
|
4769
|
+
detachLocation,
|
|
4770
|
+
);
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4774
|
+
function tryRemoveDetachLocation(
|
|
4775
|
+
roots: RootNodeTable,
|
|
4776
|
+
rootId: ChangeAtomId,
|
|
4777
|
+
count: number,
|
|
4778
|
+
): void {
|
|
4779
|
+
let countProcessed = count;
|
|
4780
|
+
const renameEntry = roots.oldToNewId.getFirst(rootId, countProcessed);
|
|
4781
|
+
countProcessed = renameEntry.length;
|
|
4782
|
+
|
|
4783
|
+
const outputDetachEntry = roots.outputDetachLocations.getFirst(rootId, countProcessed);
|
|
4784
|
+
countProcessed = outputDetachEntry.length;
|
|
4785
|
+
|
|
4786
|
+
const nodeChangeEntry = rangeQueryChangeAtomIdMap(roots.nodeChanges, rootId, countProcessed);
|
|
4787
|
+
countProcessed = nodeChangeEntry.length;
|
|
4788
|
+
|
|
4789
|
+
if (
|
|
4790
|
+
nodeChangeEntry.value === undefined &&
|
|
4791
|
+
renameEntry.value === undefined &&
|
|
4792
|
+
outputDetachEntry.value === undefined
|
|
4793
|
+
) {
|
|
4794
|
+
roots.detachLocations.delete(rootId, countProcessed);
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
const countRemaining = count - countProcessed;
|
|
4798
|
+
if (countRemaining > 0) {
|
|
4799
|
+
tryRemoveDetachLocation(roots, offsetChangeAtomId(rootId, countProcessed), countRemaining);
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4803
|
+
/**
|
|
4804
|
+
* Deletes the entry renaming the ID range of length `count` from `oldId` to `newId`.
|
|
4805
|
+
* This function assumes that such an entry exists.
|
|
4806
|
+
*/
|
|
4807
|
+
function deleteNodeRenameEntry(
|
|
4808
|
+
roots: RootNodeTable,
|
|
4809
|
+
oldId: ChangeAtomId,
|
|
4810
|
+
newId: ChangeAtomId,
|
|
4811
|
+
count: number,
|
|
4812
|
+
): void {
|
|
4813
|
+
roots.oldToNewId.delete(oldId, count);
|
|
4814
|
+
roots.newToOldId.delete(newId, count);
|
|
4815
|
+
}
|
|
4816
|
+
|
|
4817
|
+
function replaceRootTableRevision(
|
|
4818
|
+
table: RootNodeTable,
|
|
4819
|
+
replacer: RevisionReplacer,
|
|
4820
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
4821
|
+
): RootNodeTable {
|
|
4822
|
+
const oldToNewId = table.oldToNewId.mapEntries(
|
|
4823
|
+
(id) => replacer.getUpdatedAtomId(id),
|
|
4824
|
+
(id) => replacer.getUpdatedAtomId(id),
|
|
4825
|
+
);
|
|
4826
|
+
|
|
4827
|
+
const newToOldId = table.newToOldId.mapEntries(
|
|
4828
|
+
(id) => replacer.getUpdatedAtomId(id),
|
|
4829
|
+
(id) => replacer.getUpdatedAtomId(id),
|
|
4830
|
+
);
|
|
4831
|
+
|
|
4832
|
+
const nodeChanges: ChangeAtomIdBTree<NodeId> = replaceIdMapRevisions(
|
|
4833
|
+
table.nodeChanges,
|
|
4834
|
+
replacer,
|
|
4835
|
+
(nodeId) => replacer.getUpdatedAtomId(normalizeNodeId(nodeId, nodeAliases)),
|
|
4836
|
+
);
|
|
4837
|
+
|
|
4838
|
+
const detachLocations = table.detachLocations.mapEntries(
|
|
4839
|
+
(id) => replacer.getUpdatedAtomId(id),
|
|
4840
|
+
(fieldId) => replaceFieldIdRevision(normalizeFieldId(fieldId, nodeAliases), replacer),
|
|
4841
|
+
);
|
|
4842
|
+
|
|
4843
|
+
const outputDetachLocations = table.outputDetachLocations.mapEntries(
|
|
4844
|
+
(id) => replacer.getUpdatedAtomId(id),
|
|
4845
|
+
(fieldId) => replaceFieldIdRevision(normalizeFieldId(fieldId, nodeAliases), replacer),
|
|
4846
|
+
);
|
|
4847
|
+
|
|
4848
|
+
return { oldToNewId, newToOldId, nodeChanges, detachLocations, outputDetachLocations };
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4851
|
+
function newDetachedEntryMap(): ChangeAtomIdRangeMap<DetachedNodeEntry> {
|
|
4852
|
+
return new RangeMap(offsetChangeAtomId, subtractChangeAtomIds, offsetDetachedNodeEntry);
|
|
4853
|
+
}
|
|
4854
|
+
|
|
4855
|
+
function offsetDetachedNodeEntry(entry: DetachedNodeEntry, count: number): DetachedNodeEntry {
|
|
4856
|
+
assert(
|
|
4857
|
+
count <= 1 || entry.nodeChange === undefined,
|
|
4858
|
+
"Cannot split an entry with a node change",
|
|
4859
|
+
);
|
|
4860
|
+
|
|
4861
|
+
return entry.detachId === undefined
|
|
4862
|
+
? entry
|
|
4863
|
+
: { ...entry, detachId: offsetChangeAtomId(entry.detachId, count) };
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4866
|
+
function getFieldsWithRootMoves(
|
|
4867
|
+
roots: RootNodeTable,
|
|
4868
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
4869
|
+
): TupleBTree<FieldIdKey, boolean> {
|
|
4870
|
+
const fields: TupleBTree<FieldIdKey, boolean> = newTupleBTree();
|
|
4871
|
+
for (const { start: rootId, value: fieldId, length } of roots.detachLocations.entries()) {
|
|
4872
|
+
let isRootMoved = false;
|
|
4873
|
+
for (const renameEntry of roots.oldToNewId.getAll2(rootId, length)) {
|
|
4874
|
+
if (renameEntry.value !== undefined) {
|
|
4875
|
+
isRootMoved = true;
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4878
|
+
|
|
4879
|
+
for (const outputDetachEntry of roots.outputDetachLocations.getAll2(rootId, length)) {
|
|
4880
|
+
if (outputDetachEntry.value !== undefined) {
|
|
4881
|
+
isRootMoved = true;
|
|
4882
|
+
}
|
|
4883
|
+
}
|
|
4884
|
+
|
|
4885
|
+
if (isRootMoved) {
|
|
4886
|
+
fields.set(fieldIdKeyFromFieldId(normalizeFieldId(fieldId, nodeAliases)), true);
|
|
4887
|
+
}
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
return fields;
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4893
|
+
function getFieldToRootChanges(
|
|
4894
|
+
roots: RootNodeTable,
|
|
4895
|
+
nodeAliases: ChangeAtomIdBTree<NodeId>,
|
|
4896
|
+
): TupleBTree<FieldIdKey, ChangeAtomId[]> {
|
|
4897
|
+
const fields: TupleBTree<FieldIdKey, ChangeAtomId[]> = newTupleBTree();
|
|
4898
|
+
for (const rootIdKey of roots.nodeChanges.keys()) {
|
|
4899
|
+
const rootId: ChangeAtomId = { revision: rootIdKey[0], localId: rootIdKey[1] };
|
|
4900
|
+
const detachLocation = roots.detachLocations.getFirst(rootId, 1).value;
|
|
4901
|
+
if (detachLocation !== undefined) {
|
|
4902
|
+
const fieldIdKey = fieldIdKeyFromFieldId(normalizeFieldId(detachLocation, nodeAliases));
|
|
4903
|
+
let rootsInField = fields.get(fieldIdKey);
|
|
4904
|
+
if (rootsInField === undefined) {
|
|
4905
|
+
rootsInField = [];
|
|
4906
|
+
fields.set(fieldIdKey, rootsInField);
|
|
4907
|
+
}
|
|
4908
|
+
|
|
4909
|
+
rootsInField.push(rootId);
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
|
|
4913
|
+
return fields;
|
|
4914
|
+
}
|
|
4915
|
+
|
|
4916
|
+
function muteRootChanges(roots: RootNodeTable): RootNodeTable {
|
|
4917
|
+
return {
|
|
4918
|
+
oldToNewId: newChangeAtomIdTransform(),
|
|
4919
|
+
newToOldId: newChangeAtomIdTransform(),
|
|
4920
|
+
nodeChanges: brand(roots.nodeChanges.clone()),
|
|
4921
|
+
detachLocations: roots.detachLocations.clone(),
|
|
4922
|
+
outputDetachLocations: newChangeAtomIdRangeMap(),
|
|
4923
|
+
};
|
|
4924
|
+
}
|
|
4925
|
+
|
|
4926
|
+
export function validateChangeset(
|
|
4927
|
+
change: ModularChangeset,
|
|
4928
|
+
fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
4929
|
+
): void {
|
|
4930
|
+
const unreachableNodes: ChangeAtomIdBTree<NodeLocation> = brand(change.nodeToParent.clone());
|
|
4931
|
+
|
|
4932
|
+
const unreachableCFKs = change.crossFieldKeys.clone();
|
|
4933
|
+
|
|
4934
|
+
validateFieldChanges(
|
|
4935
|
+
fieldKinds,
|
|
4936
|
+
change,
|
|
4937
|
+
change.fieldChanges,
|
|
4938
|
+
undefined,
|
|
4939
|
+
unreachableNodes,
|
|
4940
|
+
unreachableCFKs,
|
|
4941
|
+
);
|
|
4942
|
+
|
|
4943
|
+
for (const [[revision, localId], node] of change.nodeChanges.entries()) {
|
|
4944
|
+
if (node.fieldChanges === undefined) {
|
|
4945
|
+
continue;
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4948
|
+
const nodeId = normalizeNodeId({ revision, localId }, change.nodeAliases);
|
|
4949
|
+
validateFieldChanges(
|
|
4950
|
+
fieldKinds,
|
|
4951
|
+
change,
|
|
4952
|
+
node.fieldChanges,
|
|
4953
|
+
nodeId,
|
|
4954
|
+
unreachableNodes,
|
|
4955
|
+
unreachableCFKs,
|
|
4956
|
+
);
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4959
|
+
for (const [detachIdKey, nodeId] of change.rootNodes.nodeChanges.entries()) {
|
|
4960
|
+
const detachId: ChangeAtomId = { revision: detachIdKey[0], localId: detachIdKey[1] };
|
|
4961
|
+
const location = getNodeParent(change, nodeId);
|
|
4962
|
+
assert(areEqualChangeAtomIdOpts(location.root, detachId), "Inconsistent node location");
|
|
4963
|
+
|
|
4964
|
+
const normalizedNodeId = normalizeNodeId(nodeId, change.nodeAliases);
|
|
4965
|
+
unreachableNodes.delete([normalizedNodeId.revision, normalizedNodeId.localId]);
|
|
4966
|
+
|
|
4967
|
+
const fieldChanges = nodeChangeFromId(
|
|
4968
|
+
change.nodeChanges,
|
|
4969
|
+
change.nodeAliases,
|
|
4970
|
+
nodeId,
|
|
4971
|
+
).fieldChanges;
|
|
4972
|
+
|
|
4973
|
+
if (fieldChanges !== undefined) {
|
|
4974
|
+
validateFieldChanges(
|
|
4975
|
+
fieldKinds,
|
|
4976
|
+
change,
|
|
4977
|
+
fieldChanges,
|
|
4978
|
+
normalizedNodeId,
|
|
4979
|
+
unreachableNodes,
|
|
4980
|
+
unreachableCFKs,
|
|
4981
|
+
);
|
|
4982
|
+
}
|
|
4983
|
+
}
|
|
4984
|
+
|
|
4985
|
+
assert(unreachableNodes.size === 0, "Unreachable nodes found");
|
|
4986
|
+
assert(unreachableCFKs.entries().length === 0, "Unreachable cross-field keys found");
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4989
|
+
/**
|
|
4990
|
+
* Asserts that each node has a correct entry in `change.nodeToParent`,
|
|
4991
|
+
* and each cross field key has a correct entry in `change.crossFieldKeys`.
|
|
4992
|
+
* @returns the number of children found.
|
|
4993
|
+
*/
|
|
4994
|
+
function validateFieldChanges(
|
|
4995
|
+
fieldKinds: ReadonlyMap<FieldKindIdentifier, FlexFieldKind>,
|
|
4996
|
+
change: ModularChangeset,
|
|
4997
|
+
fieldChanges: FieldChangeMap,
|
|
4998
|
+
nodeParent: NodeId | undefined,
|
|
4999
|
+
unreachableNodes: ChangeAtomIdBTree<NodeLocation>,
|
|
5000
|
+
unreachableCFKs: CrossFieldRangeTable<FieldId>,
|
|
5001
|
+
): void {
|
|
5002
|
+
for (const [field, fieldChange] of fieldChanges.entries()) {
|
|
5003
|
+
const fieldId = { nodeId: nodeParent, field };
|
|
5004
|
+
const handler = getChangeHandler(fieldKinds, fieldChange.fieldKind);
|
|
5005
|
+
for (const [child, _index] of handler.getNestedChanges(fieldChange.change)) {
|
|
5006
|
+
const parentFieldId = getNodeParent(change, child);
|
|
5007
|
+
assert(
|
|
5008
|
+
parentFieldId.field !== undefined && areEqualFieldIds(parentFieldId.field, fieldId),
|
|
5009
|
+
0xa4e /* Inconsistent node parentage */,
|
|
5010
|
+
);
|
|
5011
|
+
|
|
5012
|
+
unreachableNodes.delete([child.revision, child.localId]);
|
|
5013
|
+
}
|
|
5014
|
+
|
|
5015
|
+
for (const keyRange of handler.getCrossFieldKeys(fieldChange.change)) {
|
|
5016
|
+
const fields = getFieldsForCrossFieldKey(change, keyRange.key, keyRange.count);
|
|
5017
|
+
assert(fields.length > 0, "Unregistered cross-field key");
|
|
5018
|
+
for (const fieldFromLookup of fields) {
|
|
5019
|
+
assert(
|
|
5020
|
+
areEqualFieldIds(fieldFromLookup, fieldId),
|
|
5021
|
+
0xa4f /* Inconsistent cross field keys */,
|
|
5022
|
+
);
|
|
5023
|
+
}
|
|
5024
|
+
|
|
5025
|
+
unreachableCFKs.delete(keyRange.key, keyRange.count);
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
3156
5028
|
}
|