export function trimEndSlash ( str ) { if ( str . endsWith ( '/' ) || str . endsWith ( '\\' ) ) return str . slice ( 0 , - 1 ) ; return str ; } export function trimStartDot ( str ) { if ( str . startsWith ( './' ) ) return str . slice ( 2 ) ; return str ; } export function dirname ( str ) { const parts = str . split ( /[\/\\]/g ) ; return parts [ parts . length - 2 ] ; } export function join ( ... parts ) { return parts . map ( trimEndSlash ) . map ( trimStartDot ) . join ( '/' ) ; } export function groupBy < TElement , TKey > ( elements , keyGetter ) { const map = new Map < TKey , TElement [ ] > ( ) ; for ( const element of elements ) { const key = keyGetter ( element ) ; if ( map . has ( key ) ) { const group = map . get ( key ) ; group . push ( element ) ; } else { map . set ( key , [ element ] ) ; } } return map ; }