import { DetachedSequenceId , NodeId } from '../Identifiers' ; import { Snapshot , SnapshotPlace , SnapshotRange } from '../Snapshot' ; import { assert , assertNotUndefined , fail } from '../Common' ; import { EditValidationResult } from '../Checkout' ; import { BuildNode , TraitLocation , TreeNodeSequence } from '../generic' ; import { Change , StablePlace , StableRange } from './PersistedTypes' ; /**
 * Functions for constructing edits.
 */ public export function setTrait ( trait , nodes ) { const id = 0 as DetachedSequenceId ; const traitContents = StableRange . all ( trait ) ; return [ Change . detach ( traitContents ) , Change . build ( nodes , id ) , Change . insert ( id , traitContents . start ) ] ; } param snapshot param place export function validateStablePlace ( snapshot , place ) { const { referenceSibling , referenceTrait } = place ; if ( ( referenceSibling === undefined && referenceTrait === undefined ) || ( referenceSibling !== undefined && referenceTrait !== undefined ) ) { return EditValidationResult . Malformed ; } if ( referenceSibling !== undefined ) { if ( ! snapshot . hasNode ( referenceSibling ) ) { return EditValidationResult . Invalid ; } if ( snapshot . getTraitLabel ( referenceSibling ) === undefined ) { return EditValidationResult . Invalid ; } return EditValidationResult . Valid ; } if ( ! snapshot . hasNode ( assertNotUndefined ( referenceTrait ) . parent ) ) { return EditValidationResult . Invalid ; } return EditValidationResult . Valid ; } param snapshot param range export function validateStableRange ( snapshot , range ) { const { start , end } = range ; const startValidationResult = validateStablePlace ( snapshot , start ) ; if ( startValidationResult !== EditValidationResult . Valid ) { return startValidationResult ; } const endValidationResult = validateStablePlace ( snapshot , end ) ; if ( endValidationResult !== EditValidationResult . Valid ) { return endValidationResult ; } const startTraitLocation = start . referenceTrait || snapshot . getTraitLocation ( assertNotUndefined ( start . referenceSibling ) ) ; const endTraitLocation = end . referenceTrait || snapshot . getTraitLocation ( assertNotUndefined ( end . referenceSibling ) ) ; if ( ! compareTraits ( startTraitLocation , endTraitLocation ) ) { return EditValidationResult . Invalid ; } const { start : startPlace , end : endPlace } = rangeFromStableRange ( snapshot , range ) ; const startIndex = snapshot . findIndexWithinTrait ( startPlace ) ; const endIndex = snapshot . findIndexWithinTrait ( endPlace ) ; if ( startIndex > endIndex ) { return EditValidationResult . Invalid ; } return EditValidationResult . Valid ; } param snapshot param range function getTraitLocationOfRange ( snapshot , range ) { const referenceTrait = range . start . referenceTrait ?? range . end . referenceTrait ; if ( referenceTrait ) { return referenceTrait ; } const sibling = range . start . referenceSibling ?? range . end . referenceSibling ?? fail ( 'malformed range does not indicate trait' ) ; return snapshot . getTraitLocation ( sibling ) ; } /**
 * Describes the side of a range.
 */ enum SideOfRange { /**
     * The start of the range
     */ Start = 0 , /**
     * The end of the range
     */ End = 1 } function sideOfRange ( range , sideOfRange , trait ) { const siblingRelative = sideOfRange === SideOfRange . Start ? range . start : range . end ; return { trait , side : siblingRelative . side , sibling : siblingRelative . referenceSibling } ; } /**
 * Express the given `StableRange` as a `Range`
 */ export function rangeFromStableRange ( snapshot , range ) { const location = getTraitLocationOfRange ( snapshot , range ) ; return { start : sideOfRange ( range , SideOfRange . Start , location ) , end : sideOfRange ( range , SideOfRange . End , location ) } ; } /**
 * Express the given `StablePlace` as a `Place`
 */ export function placeFromStablePlace ( snapshot , stablePlace ) { const { side } = stablePlace ; if ( stablePlace . referenceSibling === undefined ) { assert ( stablePlace . referenceTrait !== undefined ) ; return { trait : stablePlace . referenceTrait , side } ; } return { trait : snapshot . getTraitLocation ( stablePlace . referenceSibling ) , side : stablePlace . side , sibling : stablePlace . referenceSibling } ; } /**
 * Check if two TraitLocations are equal.
 */ function compareTraits ( traitA , traitB ) { if ( traitA . label !== traitB . label || traitA . parent !== traitB . parent ) { return false ; } return true ; } param nodesToInsert param placeToInsert export function insertIntoTrait ( snapshot , nodesToInsert , placeToInsert ) { return snapshot . attachRange ( nodesToInsert , placeFromStablePlace ( snapshot , placeToInsert ) ) ; } param rangeToDetach export function detachRange ( snapshot , rangeToDetach ) { return snapshot . detachRange ( rangeFromStableRange ( snapshot , rangeToDetach ) ) ; } internal export function isDetachedSequenceId ( node ) { return typeof node !== 'object' ; }