import { loadCannedMetricsFile , MetricTemplate } from './canned-metrics/canned-metrics-schema' ; export type NonEmptyArray < T > = [ T , ... T [ ] ] ; /**
 * A single canned service metric
 *
 * These are kindly provided to us by the good people of CloudWatch Explorer.
 */ export interface CannedMetric { /**
     * Metric namespace
     */ readonly namespace : string ; /**
     * Metric name
     */ readonly metricName : string ; /**
     * List of all possible dimension permutations for this metric
     *
     * Most metrics will have a single list of strings as their one set of
     * allowed dimensions, but some metrics are emitted under multiple
     * combinations of dimensions.
     */ readonly dimensions : NonEmptyArray < string [ ] > ; /**
     * Suggested default aggregration statistic
     *
     * Not always the most appropriate one to use! These defaults have
     * been classified by people and they generally just pick "Average"
     * as the default, even if it doesn't make sense.
     *
     * For example: for event-based metrics that only ever emit `1`
     * (and never `0`) the better statistic would be `Sum`.
     *
     * Use your judgement based on the type of metric this is.
     */ readonly defaultStat : string ; } /**
 * Return the list of canned metrics for the given service
 */ export function cannedMetricsForService ( cloudFormationNamespace ) { const metricTemplates = cannedMetricsIndex ( ) [ cloudFormationNamespace ] ?? [ ] ; const metricsWithDuplicates = flatMap ( metricTemplates , metricSet => { const dimensions = metricSet . dimensions . map ( d => d . dimensionName ) ; return metricSet . metrics . map ( metric => ( { namespace : metricSet . namespace , dimensions , metricName : metric . name , defaultStat : metric . defaultStat , } ) ) ; } ) ; return groupBy ( metricsWithDuplicates , m => `${ m . namespace }/${ m . metricName }` ) . map ( metrics => ( { namespace : metrics [ 0 ] . namespace , metricName : metrics [ 0 ] . metricName , defaultStat : metrics [ 0 ] . defaultStat , dimensions : Array . from ( dedupeStringLists ( metrics . map ( m => m . dimensions ) ) ) as any , } ) ) ; } type CannedMetricsIndex = Record < string , MetricTemplate [ ] > ; let cannedMetricsCache ; /**
 * Load the canned metrics file and process it into an index, grouped by service namespace
 */ function cannedMetricsIndex ( ) { if ( cannedMetricsCache === undefined ) { cannedMetricsCache = { } ; for ( const group of loadCannedMetricsFile ( ) ) { for ( const metricTemplate of group . metricTemplates ) { const [ aws , service ] = metricTemplate . resourceType . split ( '::' ) ; const serviceKey = [ aws , service ] . join ( '::' ) ; ( cannedMetricsCache [ serviceKey ] ?? ( cannedMetricsCache [ serviceKey ] = [ ] ) ) . push ( metricTemplate ) ; } } } return cannedMetricsCache ; } function flatMap < A , B > ( xs , fn ) { return Array . prototype . concat . apply ( [ ] , xs . map ( fn ) ) ; } function groupBy < A > ( xs , keyFn ) { const obj = { } ; for ( const x of xs ) { const key = keyFn ( x ) ; if ( key in obj ) { obj [ key ] . push ( x ) ; } else { obj [ key ] = [ x ] ; } } return Object . values ( obj ) ; } function * dedupeStringLists ( xs ) { const seen = new Set < string > ( ) ; for ( const x of xs ) { x . sort ( ) ; const key = `${ x . join ( ',' ) }` ; if ( ! seen . has ( key ) ) { yield x ; } seen . add ( key ) ; } }