import { consumeEntryFacade , createEntryFacade } from "./entry" ; import { idSignifiesNew } from "./tools" ; import { FACADE_VERSION } from "./symbols" ; import Entry from "../core/Entry" ; import Group from "../core/Group" ; import Vault from "../core/Vault" ; import { EntryFacade , GroupFacade , GroupID , VaultFacade } from "../types" ; import { generateUUID } from "../tools/uuid" ; export interface ConsumeVaultFacadeOptions { mergeMode ? : boolean ; } export interface CreateVaultFacadeOptions { includeTrash ? : boolean ; } export interface GetGroupEntriesFacadesOptions { includeTrash ? : boolean ; } export interface GetGroupsFacadesOptions { includeTrash ? : boolean ; } const { FacadeType } = Entry . Attributes ; param group param facade memberof export function consumeGroupFacade ( group , facade ) { const { id , title , type , attributes } = facade ; const existingAttributes = group . getAttribute ( ) ; if ( type !== "group" ) { throw new Error ( `Failed consuming group facade: Invalid facade type: ${ type }` ) ; } if ( id !== group . id ) { throw new Error ( `Failed consuming group facade: Provided facade ID (${ id }) does not match target group's ID: ${ group . id }` ) ; } if ( ! title || title . trim ( ) . length <= 0 ) { throw new Error ( "Failed consuming group facade: Title must not be empty" ) ; } if ( group . getTitle ( ) !== title ) { group . setTitle ( title ) ; } Object . keys ( existingAttributes ) . filter ( attr => ! attributes . hasOwnProperty ( attr ) ) . forEach ( attr => { group . deleteAttribute ( attr ) ; } ) ; Object . keys ( attributes ) . forEach ( attr => { if ( ! existingAttributes [ attr ] || existingAttributes [ attr ] !== attributes [ attr ] ) { group . setAttribute ( attr , attributes [ attr ] ) ; } } ) ; } param vault param facade param options memberof export function consumeVaultFacade ( vault , facade , options = { } ) { if ( facade . _ver !== FACADE_VERSION ) { throw new Error ( "Invalid vault facade version" ) ; } if ( ! facade || ( facade && facade . type !== "vault" ) ) { throw new Error ( `Failed consuming vault facade: Second parameter expected to be a vault facade, got: ${ facade . type }` ) ; } const { mergeMode = false } = options ; const { id , type , attributes , groups , entries } = facade ; if ( type !== "vault" ) { throw new Error ( `Failed consuming vault facade: Invalid facade type: ${ type }` ) ; } if ( ! mergeMode && id !== vault . id ) { throw new Error ( `Failed consuming vault facade: Provided facade ID (${ id }) does not match target vault ID: ${ vault . id }` ) ; } const newIDLookup = { } ; let { groups : currentGroups , entries : currentEntries , attributes : currentAttributes } = createVaultFacade ( vault ) ; if ( ! mergeMode ) { currentGroups . forEach ( currentGroupFacade => { const existing = groups . find ( group => group . id === currentGroupFacade . id ) ; if ( ! existing ) { const targetItem = vault . findGroupByID ( currentGroupFacade . id ) ; if ( targetItem ) { targetItem . delete ( ) ; } } } ) ; } currentGroups = getGroupsFacades ( vault ) ; let groupsLeft = [ ... groups ] ; while ( groupsLeft . length > 0 ) { let originalLength = groupsLeft . length ; groupsLeft = groupsLeft . filter ( groupRaw => { const groupFacade = Object . assign ( { } , groupRaw ) ; const groupIDTargetedNew = idSignifiesNew ( groupFacade . id , mergeMode ) ; if ( ! groupFacade . id || groupIDTargetedNew ) { let targetParentID = groupFacade . parentID ; if ( idSignifiesNew ( targetParentID , mergeMode ) ) { if ( newIDLookup [ targetParentID ] ) { targetParentID = newIDLookup [ targetParentID ] ; } else { return true ; } } const targetParent = targetParentID === "0" ? vault : vault . findGroupByID ( targetParentID ) ; const newGroupInst = targetParent . createGroup ( groupFacade . title ) ; if ( groupIDTargetedNew ) { newIDLookup [ `${ groupFacade . id }` ] = newGroupInst . id ; } groupFacade . id = newGroupInst . id ; } else { if ( ! currentGroups . find ( group => group . id === groupFacade . id ) ) { return ; } const { id : groupID , parentID : groupParentID } = groupFacade ; const ref = vault . findGroupByID ( groupID ) ; const refGroup = ref . getParentGroup ( ) ; if ( ( refGroup === null && groupParentID !== "0" ) || ( refGroup !== null && refGroup . id !== groupParentID ) ) { ref . moveTo ( groupParentID === "0" ? vault : vault . findGroupByID ( groupParentID ) ) ; } } consumeGroupFacade ( vault . findGroupByID ( groupFacade . id ) , groupFacade ) ; return false ; } ) ; if ( originalLength === groupsLeft . length ) { const ids = groupsLeft . map ( group => group . id ) ; throw new Error ( `Processing facade stalled: groups not resolveable: ${ ids . join ( ", " ) }` ) ; } } if ( ! mergeMode ) { currentEntries . forEach ( currentEntryFacade => { const existing = entries . find ( entry => entry . id === currentEntryFacade . id ) ; if ( ! existing ) { const entry = vault . findEntryByID ( currentEntryFacade . id ) ; if ( entry ) { entry . delete ( ) ; } } } ) ; } currentEntries = getEntriesFacades ( vault ) ; let entriesLeft = [ ... entries ] ; entriesLeft = entriesLeft . filter ( entryRaw => { const entryFacade = Object . assign ( { } , entryRaw ) ; const entryIDTargetedNew = idSignifiesNew ( entryFacade . id , mergeMode ) ; if ( ! entryFacade . id || entryIDTargetedNew ) { let targetGroupID = entryFacade . parentID ; if ( idSignifiesNew ( targetGroupID , mergeMode ) ) { if ( newIDLookup [ targetGroupID ] ) { targetGroupID = newIDLookup [ targetGroupID ] ; } else { return true ; } } const targetGroup = vault . findGroupByID ( targetGroupID ) ; const newEntry = targetGroup . createEntry ( ) ; if ( entryIDTargetedNew ) { newIDLookup [ `${ entryFacade . id }` ] = newEntry . id ; } entryFacade . id = newEntry . id ; if ( entryFacade . type ) { newEntry . setAttribute ( FacadeType , entryFacade . type ) ; } } else { if ( ! currentEntries . find ( entry => entry . id === entryRaw . id ) ) { return ; } const ref = vault . findEntryByID ( entryFacade . id ) ; const refGroup = ref . getGroup ( ) ; if ( refGroup . id !== entryFacade . parentID ) { ref . moveToGroup ( vault . findGroupByID ( entryFacade . parentID ) ) ; } } const entryToUpdate = vault . findEntryByID ( entryFacade . id ) ; consumeEntryFacade ( entryToUpdate , entryFacade ) ; return false ; } ) ; Object . keys ( currentAttributes ) . filter ( attr => ! attributes . hasOwnProperty ( attr ) ) . forEach ( attr => { vault . deleteAttribute ( attr ) ; } ) ; Object . keys ( attributes ) . forEach ( attr => { if ( attr === Vault . Attribute . AttachmentsKey && mergeMode ) return ; if ( ! currentAttributes [ attr ] || currentAttributes [ attr ] !== attributes [ attr ] ) { vault . setAttribute ( attr , attributes [ attr ] ) ; } } ) ; } param vault returns memberof export function createVaultFacade ( vault , options = { } ) { const { includeTrash = true } = options ; return { _tag : generateUUID ( ) , _ver : FACADE_VERSION , type : "vault" , id : vault . id , attributes : vault . getAttribute ( ) as { [ key ] : string ; } , groups : getGroupsFacades ( vault , { includeTrash } ) , entries : getEntriesFacades ( vault , { includeTrash } ) } ; } param group param parentID memberof export function createGroupFacade ( group , parentID = "0" ) { return { type : "group" , id : group ? group . id : null , title : group ? group . getTitle ( ) : "" , attributes : group ? ( group . getAttribute ( ) as { [ key ] : string ; } ) : { } , parentID } ; } param vault param options returns function getEntriesFacades ( vault , options = { } ) { return vault . getGroups ( ) . reduce ( ( output , group ) => [ ... output , ... getGroupEntriesFacades ( group , options ) ] , [ ] ) ; } param entryCollection param options returns function getGroupEntriesFacades ( entryCollection , options = { } ) { const { includeTrash = true } = options ; const facades = entryCollection . getEntries ( ) . reduce ( ( facades , entry ) => { if ( includeTrash === false && entry . isInTrash ( ) ) { return facades ; } return [ ... facades , Object . assign ( { } , createEntryFacade ( entry ) ) ] ; } , [ ] ) ; entryCollection . getGroups ( ) . forEach ( group => { facades . push ( ... getGroupEntriesFacades ( group , options ) ) ; } ) ; return facades ; } param vault param options returns function getGroupsFacades ( vault , options = { } ) { const { includeTrash = true } = options ; return vault . _groups . reduce ( ( output , group ) => { if ( includeTrash === false && ( group . isTrash ( ) || group . isInTrash ( ) ) ) { return output ; } return [ ... output , createGroupFacade ( group , group . vault . format . getItemParentID ( group . _source ) ) ] ; } , [ ] ) ; }