/**
 * A metric name with the ability to include semantic tags.
 *
 * This replaces the previous style where metric names where strictly
 * dot-separated strings.
 *
 */ import { MetricLevel } from './MetricLevel' ; const SEPARATOR = '.' ; export class MetricName { key : string ; tags : Object ; level : MetricLevel ; static EMPTY = new MetricName ( ) ; static EMPTY_TAGS = { } ; static TAGS_SPLIT = '^&*' ; static NAME_JOIN = '@%^' ; static TAGS_JOIN = '!*&' ; static TAGS_CONCAT = '%^&' ; constructor ( key = '' , tags = { } , level = MetricLevel . NORMAL ) { this . key = key ; this . tags = tags ; this . level = level ; } getKey ( ) { return this . key ; } getTags ( ) { return this . tags ; } return getMetricLevel ( ) { return this . level ; } param level setLevel ( level ) { this . level = level ; return this ; } param parts return static build ( ... parts ) { if ( parts === null || parts . length === 0 ) { return MetricName . EMPTY ; } if ( parts . length === 1 ) { return new MetricName ( parts [ 0 ] ) ; } return new MetricName ( MetricName . buildName ( parts ) ) ; } param parts return static join ( ... parts ) { let nameBuilder = [ ] ; let tags = { } ; let first = true ; let firstName = null ; for ( let part of parts ) { let name = part . getKey ( ) ; if ( name ) { if ( first ) { first = false ; firstName = part ; } else { nameBuilder . push ( SEPARATOR ) ; } nameBuilder . push ( name ) ; } if ( Object . keys ( part . getTags ( ) ) . length ) { Object . assign ( tags , part . getTags ( ) ) ; } } let level = firstName === null ? null : firstName . getMetricLevel ( ) ; return new MetricName ( nameBuilder . join ( '' ) , tags , MetricLevel [ level ] ) ; } private static buildName ( names ) { return names . join ( SEPARATOR ) ; } param p param inheritTags return resolve ( p , inheritTags = true ) { let next ; if ( p ) { if ( this . key ) { next = this . key + SEPARATOR + p ; } else { next = p ; } } else { next = this . key ; } return inheritTags ? new MetricName ( next , this . tags , this . level ) : new MetricName ( next , null , this . level ) ; } /**
     * Same as  {@link #tagged(Map)} , but takes a variadic list
     * of arguments.
     *
     *  see param pairs return tagged ( ... pairs ) { if ( ! pairs ) { return this ; } if ( pairs . length === 1 && typeof pairs [ 0 ] === 'object' ) { let tags = pairs [ 0 ] ; Object . assign ( tags , this . tags ) ; return new MetricName ( this . key , tags , this . level ) ; } if ( pairs . length % 2 !== 0 ) { throw new Error ( 'Argument count must be even' ) ; } let add = { } ; for ( let i = 0 ; i < pairs . length ; i += 2 ) { add [ pairs [ i ] ] = pairs [ i + 1 ] ; } return this . tagged ( add ) ; } getNameKey ( ) { let tagsArr = [ ] ; for ( let key in this . tags ) { if ( this . tags . hasOwnProperty ( key ) ) { tagsArr . push ( key + MetricName . TAGS_CONCAT + this . tags [ key ] ) ; } } tagsArr . sort ( ) ; return [ this . key , tagsArr . join ( MetricName . TAGS_JOIN ) , this . level ] . join ( MetricName . NAME_JOIN ) ; } toString ( ) { return this . getNameKey ( ) ; } param key static parseKey ( key ) { let arrs = key . split ( MetricName . NAME_JOIN ) ; if ( arrs . length === 3 ) { let key = arrs [ 0 ] ; let tagArr = arrs [ 1 ] . split ( MetricName . TAGS_JOIN ) ; let tags = { } ; for ( let tagStr of tagArr ) { if ( tagStr ) { let tagO = tagStr . split ( MetricName . TAGS_CONCAT ) ; tags [ tagO [ 0 ] ] = tagO [ 1 ] ; } } let level = MetricLevel [ arrs [ 2 ] ] ; return new MetricName ( key , tags , level ) ; } else if ( arrs . length === 1 ) { let key = arrs [ 0 ] ; return new MetricName ( key ) ; } else if ( arrs . length === 2 ) { let key = arrs [ 0 ] ; let tagArr = arrs [ 1 ] . split ( MetricName . TAGS_JOIN ) ; let tags = { } ; for ( let tagStr of tagArr ) { let tagO = tagStr . split ( MetricName . TAGS_CONCAT ) ; tags [ tagO [ 0 ] ] = tagO [ 1 ] ; } return new MetricName ( key , tags ) ; } return MetricName . EMPTY ; } }