'use strict' ; function replaceAll ( s , substr , newSubstr ) { while ( s . indexOf ( substr ) !== - 1 ) { s = s . replace ( substr , newSubstr ) ; } return s ; } function * reversed < T > ( a ) { for ( let i = a . length - 1 ; i >= 0 ; i -- ) { yield a [ i ] ; } } export class Expander { private definitions = new Map < string , string > ( ) ; private topologicalOrder : string [ ] = [ ] ; constructor ( M ) { for ( let [ k , v ] of M ) { this . definitions . set ( `\${${ k }}` , v ) ; } const visiting = new Set < string > ( ) ; const visited = new Set < string > ( ) ; const visit = ( s ) => { if ( visiting . has ( s ) ) { throw Error ( "cyclic variable definition" ) ; } if ( visited . has ( s ) ) { return ; } visiting . add ( s ) ; visited . add ( s ) ; const val = this . definitions . get ( s ) ; if ( val !== null ) { for ( let k of this . definitions . keys ( ) ) { if ( val . indexOf ( k ) !== - 1 ) { visit ( k ) ; } } } visiting . delete ( s ) ; this . topologicalOrder . push ( s ) ; } ; for ( let k of this . definitions . keys ( ) ) { visit ( k ) ; } } private expandString ( s ) { for ( let v of reversed ( this . topologicalOrder ) ) { s = replaceAll ( s , v , this . definitions . get ( v ) ) ; } return s ; } private expandArray ( a ) { return a . map ( s => this . expandString ( s ) ) ; } private expandMap ( a ) { let M = new Map < string , string > ( ) ; for ( let [ v , val ] of a ) { M . set ( v , this . expandString ( val ) ) ; } return M ; } public expand ( s ) ; public expand ( a ) ; public expand ( n ) ; public expand ( u ) ; public expand ( x ) ; public expand ( x ) { if ( x === null ) { return null ; } else if ( x === undefined ) { return undefined ; } else if ( typeof x === 'string' ) { return this . expandString ( x ) ; } else if ( x instanceof Array ) { return this . expandArray ( x ) ; } else { return this . expandMap ( x ) ; } } }