import { cloneDeep } from 'lodash' ; import { Capabilities , CapabilitiesSwitcher } from './types' ; import { OpenSearchDashboardsRequest } from '../http' ; export type CapabilitiesResolver = ( request : OpenSearchDashboardsRequest , applications : string [ ] ) => Promise < Capabilities > ; export const getCapabilitiesResolver = ( capabilities , switchers ) : CapabilitiesResolver => async ( request , applications ) : Promise < Capabilities > => { return resolveCapabilities ( capabilities ( ) , switchers ( ) , request , applications ) ; } ; export const resolveCapabilities = async ( capabilities , switchers , request , applications ) : Promise < Capabilities > => { const mergedCaps = cloneDeep ( { ... capabilities , navLinks : applications . reduce ( ( acc , app ) => ( { ... acc , [ app ] : true , } ) , capabilities . navLinks ) , } ) ; return switchers . reduce ( async ( caps , switcher ) => { const resolvedCaps = await caps ; const changes = await switcher ( request , resolvedCaps ) ; return recursiveApplyChanges ( resolvedCaps , changes ) ; } , Promise . resolve ( mergedCaps ) ) ; } ; function recursiveApplyChanges < TDestination extends Record < string , any > , TSource extends Record < string , any > > ( destination , source ) { return Object . keys ( destination ) . map ( ( key ) => { const orig = destination [ key ] ; const changed = source [ key ] ; if ( changed == null ) { return [ key , orig ] ; } if ( typeof orig === 'object' && typeof changed === 'object' ) { return [ key , recursiveApplyChanges ( orig , changed ) ] ; } return [ key , typeof orig === typeof changed ? changed : orig ] ; } ) . reduce ( ( acc , [ key , value ] ) => ( { ... acc , [ key ] : value , } ) , { } as TDestination ) ; }