export function arrayJoin < T1 , T2 > ( arr , joiner ) { const newArr = [ ] ; for ( let i = 0 ; i < arr . length ; i ++ ) { newArr . push ( arr [ i ] ) ; const last = i === arr . length - 1 ; if ( ! last ) { newArr . push ( joiner ) ; } } return newArr ; } export function flatten < T > ( arr ) { return [ ] . concat . apply ( [ ] , arr ) ; } export function times < T > ( n , cb ) { return new Array ( n ) . fill ( null ) . map ( ( _ , i ) => cb ( i ) ) ; } export function repeat ( n , char ) { return new Array ( n ) . fill ( char ) . join ( "" ) ; } export class ScopedIdMap { _map : Map < string , number > ; constructor ( ) { this . _map = new Map ( ) ; } get ( namespace , key ) { const jointKey = namespace == null ? key : `${ namespace }::${ key }` ; if ( ! this . _map . has ( jointKey ) ) { this . _map . set ( jointKey , this . _map . size ) ; } return this . _map . get ( jointKey ) ; } size ( ) { return this . _map . size ; } } export function formatList ( list ) { if ( list . length === 0 ) { throw new Error ( "Cannot format an empty list" ) ; } if ( list . length === 1 ) { return list [ 0 ] ; } const quoted = list . map ( name => `"${ name }"` ) ; const last = quoted . pop ( ) ; return quoted . join ( ", " ) + ` and ${ last }` ; }