import { ArrayExt , StringExt } from '@lumino/algorithm' ; import { ReadonlyJSONValue } from '@lumino/coreutils' ; import { Field } from './field' ; import { createDuplexId } from './utilities' ; /**
 * A field which represents a collaborative key:value map.
 */ export class MapField < T extends ReadonlyJSONValue > extends Field < MapField . Value < T > , MapField . Update < T > , MapField . Metadata < T > , MapField . Change < T > , MapField . Patch < T > > { param options constructor ( options = { } ) { super ( options ) ; } /**
     * The discriminated type of the field.
     */ get type ( ) : 'map' { return 'map' ; } returns createValue ( ) { return { } ; } returns createMetadata ( ) { return { ids : { } , values : { } } ; } param args returns applyUpdate ( args ) { let { previous , update , metadata , version , storeId } = args ; let id = createDuplexId ( version , storeId ) ; let clone = { ... previous } ; let prev = { } ; let curr = { } ; for ( let key in update ) { let value = Private . insertIntoMetadata ( metadata , key , id , update [ key ] ) ; if ( value === null ) { delete clone [ key ] ; } else { clone [ key ] = value ; } prev [ key ] = key in previous ? previous [ key ] : null ; curr [ key ] = value ; } let change = { previous : prev , current : curr } ; let patch = { id , values : update } ; return { value : clone , change , patch } ; } param args returns applyPatch ( args ) { let { previous , patch , metadata } = args ; let { id , values } = patch ; let clone = { ... previous } ; let prev = { } ; let curr = { } ; for ( let key in values ) { let value = Private . insertIntoMetadata ( metadata , key , id , values [ key ] ) ; if ( value === null ) { delete clone [ key ] ; } else { clone [ key ] = value ; } prev [ key ] = key in previous ? previous [ key ] : null ; curr [ key ] = value ; } let change = { previous : prev , current : curr } ; return { value : clone , change } ; } param args returns unapplyPatch ( args ) { let { previous , patch , metadata } = args ; let { id , values } = patch ; let clone = { ... previous } ; let prev = { } ; let curr = { } ; for ( let key in values ) { let value = Private . removeFromMetadata ( metadata , key , id ) ; if ( value === null ) { delete clone [ key ] ; } else { clone [ key ] = value ; } prev [ key ] = key in previous ? previous [ key ] : null ; curr [ key ] = value ; } let change = { previous : prev , current : curr } ; return { value : clone , change } ; } param first param second returns mergeChange ( first , second ) { let previous = { ... second . previous , ... first . previous } ; let current = { ... first . current , ... second . current } ; return { previous , current } ; } param first param second returns mergePatch ( first , second ) { return { id : second . id , values : { ... first . values , ... second . values } } ; } } /**
 * The namespace for the `MapField` class statics.
 */ export namespace MapField { /**
     * An options object for initializing a map field.
     */ export interface IOptions < T extends ReadonlyJSONValue > extends Field . IOptions { } /**
     * A type alias for the map field value type.
     */ export type Value < T extends ReadonlyJSONValue > = { readonly [ key ] : T ; } ; /**
     * A type alias for the map field update type.
     */ export type Update < T extends ReadonlyJSONValue > = { readonly [ key ] : T | null ; } ; /**
     * A type alias for the map field metadata type.
     */ export type Metadata < T extends ReadonlyJSONValue > = { /**
         * A mapping of key:id-history.
         */ readonly ids : { [ key ] : Array < string > ; } ; /**
         * A mapping of key:value-history.
         */ readonly values : { [ key ] : Array < T | null > ; } ; } ; /**
     * A type alias for the map field change type.
     */ export type Change < T extends ReadonlyJSONValue > = { /**
         * The previous values of the changed items.
         */ readonly previous : { readonly [ key ] : T | null ; } ; /**
         * The current values of the changed items.
         */ readonly current : { readonly [ key ] : T | null ; } ; } ; /**
     * A type alias for the map field patch type.
     */ export type Patch < T extends ReadonlyJSONValue > = { /**
         * The unique id associated with the values.
         */ readonly id : string ; /**
         * The current values of the changed items.
         */ readonly values : { readonly [ key ] : T | null ; } ; } ; } /**
 * The namespace for the module implementation details.
 */ namespace Private { param metadata param key param id param value returns export function insertIntoMetadata < T extends ReadonlyJSONValue > ( metadata , key , id , value ) { let ids = metadata . ids [ key ] || ( metadata . ids [ key ] = [ ] ) ; let values = metadata . values [ key ] || ( metadata . values [ key ] = [ ] ) ; let i = ArrayExt . lowerBound ( ids , id , StringExt . cmp ) ; if ( i < ids . length && ids [ i ] === id ) { values [ i ] = value ; } else { ArrayExt . insert ( ids , i , id ) ; ArrayExt . insert ( values , i , value ) ; } return values [ values . length - 1 ] ; } param metadata param key param id returns export function removeFromMetadata < T extends ReadonlyJSONValue > ( metadata , key , id ) { let ids = metadata . ids [ key ] || ( metadata . ids [ key ] = [ ] ) ; let values = metadata . values [ key ] || ( metadata . values [ key ] = [ ] ) ; let i = ArrayExt . lowerBound ( ids , id , StringExt . cmp ) ; if ( ids [ i ] === id ) { ArrayExt . removeAt ( ids , i ) ; ArrayExt . removeAt ( values , i ) ; } return values . length ? values [ values . length - 1 ] : null ; } }