import { MetaID , VersionID , assert , FieldID } from "./exports" ; /**
 * ID of an item. Immutable and interned, so can use ===
 * Arrays use plain JS numbers, either ordinals or serial numbers.
 * Strings are used as a convenience in APIs but not used as Item id
 */ export type RealID = FieldID | number ; export type ID = RealID | string ; /** Path down into the Space. A sequence of IDs starting with a VersionID.
 * Immutable after construction */ export class Path { readonly ids : ReadonlyArray < ID > ; get length ( ) { return this . ids . length ; } constructor ( ids ) { assert ( ! ids . length || ids [ 0 ] instanceof VersionID ) ; this . ids = ids ; } static readonly empty = new Path ( [ ] ) ; /** extend path downward */ down ( id ) { return new Path ( [ ... this . ids , id ] ) ; } /** lift path upwards */ up ( n ) { if ( n === 0 ) return this ; return new Path ( this . ids . slice ( 0 , - n ) ) ; } /** path equality */ equals ( other ) { return ( this . ids . length === other . ids . length && this . ids . every ( ( id , i ) => id === other . ids [ i ] ) ) ; } /** whether other path equals or extends this path. Considers metadata to
     * extend the base data */ extendedBy ( other ) { return ( this . length <= other . length && this . ids . every ( ( id , i ) => id === other . ids [ i ] ) ) ; } /** Whether other path is within but not equal to this path */ contains ( other ) { return ( other . length > this . length && ! ( other . ids [ this . length ] instanceof MetaID ) && this . ids . every ( ( id , i ) => id === other . ids [ i ] ) ) ; } containsOrEquals ( other ) { return this . equals ( other ) || this . contains ( other ) ; } /** Whether other path is in our metadata */ metadataContains ( other ) { return ( other . length > this . length && other . ids [ this . length ] instanceof MetaID && this . ids . every ( ( id , i ) => id === other . ids [ i ] ) ) ; } /** returns least upper bound with another path, which is their shared prefix
     * */ lub ( other ) { let end = this . ids . findIndex ( ( id , i ) => i >= other . ids . length || id !== other . ids [ i ] ) ; if ( end < 0 ) { return this ; } else { return new Path ( other . ids . slice ( 0 , end ) ) ; } } /**
    * Path translation. Paths within a deep copy get translated, so that any path
    * contained in the source of the copy gets translated into a path contained in
    * the destination. Relative paths are not translated.
    */ translate ( src , dst ) { if ( src . contains ( this ) ) { return new Path ( [ ... dst . ids , ... this . ids . slice ( src . length ) ] ) ; } assert ( ! dst . contains ( this ) ) ; return this ; } toString ( ) { return this . dump ( ) ; } ; dump ( ) { return this . ids . join ( '.' ) ; } dumpInVersion ( ) { return this . ids . slice ( 1 ) . join ( '.' ) ; } }