import { DetachedSequenceId , NodeId , TraitLabel , UuidString } from '../Identifiers' ; import { Side } from '../Snapshot' ; import { EditBase , BuildNode , NodeData , Payload , TraitLocation , TreeNodeSequence } from '../generic' ; import { Build , Change , ConstraintEffect , Detach , Insert , Move , SetValue , StablePlace , StableRange , Constraint , getNodeId , } from '../default-edits' ; /**
 * Types for Edits in Fluid Ops and Fluid summaries.
 *
 * Types describing locations in the tree are stable in the presence of other concurrent edits.
 *
 * All types are compatible with Fluid Serializable.
 *
 * These types can only be modified in ways that are both backwards and forwards compatible since they
 * are used in edits, and thus are persisted (using Fluid serialization).
 *
 * This means these types cannot be changed in any way that impacts their Fluid serialization
 * except through a very careful process:
 *
 * 1. The planned change must support all old data, and maintain the exact semantics of it.
 * This means that the change is pretty much limited to adding optional fields,
 * or making required fields optional.
 * 2. Support for the new format must be deployed to all users (This means all applications using SharedTree must do this),
 * and this deployment must be confirmed to be stable and will not be rolled back.
 * 3. Usage of the new format may start.
 *
 * Support for the old format can NEVER be removed: it must be maintained indefinably or old documents will break.
 * Because this process puts requirements on applications using shared tree,
 * step 3 should only ever be done in a Major version update,
 * and must be explicitly called out in the release notes
 * stating which versions of SharedTree are supported for documents modified by the new version.
 */ public export type AnchoredEditBase = EditBase < AnchoredChange > ; example public export type AnchoredChange = AnchoredInsert | AnchoredDetach | Build | AnchoredSetValue | AnchoredConstraint ; public export interface AnchoredInsert extends Insert { readonly destination : PlaceAnchor ; } public export interface AnchoredDetach extends Detach { readonly source : RangeAnchor ; } public export interface AnchoredSetValue extends SetValue { readonly nodeToModify : NodeAnchor ; } public export interface AnchoredConstraint extends Constraint { /**
     * Selects a sequence of nodes which will be checked against the constraints specified by the optional fields.
     * If `toConstrain` is invalid, it will be treated like a constraint being unmet.
     * Depending on `effect` this may or may not make the Edit invalid.
     *
     * When a constraint is not met, the effects is specified by `effect`.
     */ readonly toConstrain : RangeAnchor ; } public export const AnchoredChange = { build : Change . build , insert : Change . insert as ( source : DetachedSequenceId , destination : PlaceAnchor ) => AnchoredInsert , detach : Change . detach as ( source : RangeAnchor , destination ? : DetachedSequenceId ) => AnchoredDetach , setPayload : Change . setPayload as ( nodeToModify : NodeAnchor , payload : Payload ) => AnchoredSetValue , clearPayload : Change . clearPayload as ( nodeToModify : NodeAnchor ) => AnchoredSetValue , constraint : Change . constraint as ( toConstrain : RangeAnchor , effect : ConstraintEffect , identityHash ? : UuidString , length ? : number , contentHash ? : UuidString , parentNode ? : NodeId , label ? : TraitLabel ) => AnchoredConstraint } ; public export const AnchoredDelete = { returns create : ( rangeAnchor ) : AnchoredChange => AnchoredChange . detach ( rangeAnchor ) } ; public export const AnchoredInsert = { returns create : Insert . create as ( nodes : TreeNodeSequence < BuildNode > , destination : PlaceAnchor ) => AnchoredChange [ ] } ; public export const AnchoredMove = { returns create : Move . create as ( source : RangeAnchor , destination : PlaceAnchor ) => AnchoredChange [ ] } ; /**
 * Indicates one of the predefined alternatives for the semantics of a place in a tree.
 */ export enum PlaceAnchorSemanticsChoice { /**
     * The resulting `PlaceAnchor` is valid iff the referenced sibling or parent node with the given ID exists in the snapshot on which the
     * change is applied.
     */ BoundToNode = 0 , /**
     * The resulting `PlaceAnchor` is interpreted as relative to the siblings in the trait (or the parent in the case of start and end).
     * If the sibling referenced in the `PlaceAnchor` is moved, the anchor moves with it.
     * If the sibling referenced in the `PlaceAnchor` is deleted, the anchor is interpreted as relative to the next remaining sibling.
     * If no siblings remain on the side of interest (before the referenced sibling for "After" places and after the referenced sibling
     *   for "Before" places) then the anchor is interpreted relative to the containing parent/trait (the start of the trait for "After"
     *   places and the end of the trait for "Before" places).
     * If no siblings and no parent remains, the anchor is invalid.
     */ RelativeToNode = 1 } example public export interface PlaceAnchor extends StablePlace { /**
     * The choice of semantics for the place.
     * No value is equivalent to PlaceAnchorSemanticsChoice.BoundToNode.
     */ readonly semantics ? : PlaceAnchorSemanticsChoice ; } export type RelativePlaceAnchor = PlaceAnchor & { semantic : PlaceAnchorSemanticsChoice . RelativeToNode ; } ; example public export interface RangeAnchor extends StableRange { readonly start : PlaceAnchor ; readonly end : PlaceAnchor ; } export type NodeAnchor = NodeId ; /**
 * The remainder of this file consists of ergonomic factory methods for persisted types, or common combinations thereof (e.g. "Move" as a
 * combination of a "Detach" change and an "Insert" change).
 *
 * None of these helpers are persisted in documents, and therefore changes to their semantics need only follow standard semantic versioning
 * practices.
 */ public export const PlaceAnchor = { returns before : ( node , semantics = PlaceAnchorSemanticsChoice . RelativeToNode ) : PlaceAnchor => ( { side : Side . Before , referenceSibling : getNodeId ( node ) , semantics } ) , returns after : ( node , semantics = PlaceAnchorSemanticsChoice . RelativeToNode ) : PlaceAnchor => ( { side : Side . After , referenceSibling : getNodeId ( node ) , semantics } ) , returns atStartOf : ( trait , semantics = PlaceAnchorSemanticsChoice . RelativeToNode ) : PlaceAnchor => ( { side : Side . After , referenceTrait : trait , semantics } ) , returns atEndOf : ( trait , semantics = PlaceAnchorSemanticsChoice . RelativeToNode ) : PlaceAnchor => ( { side : Side . Before , referenceTrait : trait , semantics } ) } ; public export const RangeAnchor = { example from : StableRange . from as ( start : PlaceAnchor ) => { to : ( end : PlaceAnchor ) => RangeAnchor ; } , returns only : ( node , semantics = PlaceAnchorSemanticsChoice . RelativeToNode ) : RangeAnchor => ( { start : PlaceAnchor . before ( node , semantics ) , end : PlaceAnchor . after ( node , semantics ) } ) , returns all : StableRange . all as ( trait : TraitLocation ) => RangeAnchor } ;