'use strict' ; function _encode ( ch ) { return '%' + ch . charCodeAt ( 0 ) . toString ( 16 ) . toUpperCase ( ) ; } function encodeURIComponent2 ( str ) { return encodeURIComponent ( str ) . replace ( /[!'()*]/g , _encode ) ; } function encodeNoop ( str ) { return str ; } /**
 * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
 * This class is a simple parser which creates the basic component paths
 * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation
 * and encoding.
 *
 *       foo://example.com:8042/over/there?name=ferret#nose
 *       \_/   \______________/\_________/ \_________/ \__/
 *        |           |            |            |        |
 *     scheme     authority       path        query   fragment
 *        |   _____________________|__
 *       / \ /                        \
 *       urn:example:animal:ferret:nose
 *
 *
 */ export default class URI { private static _empty = '' ; private static _slash = '/' ; private static _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/ ; private static _driveLetterPath = /^\/[a-zA-z]:/ ; private static _upperCaseDrive = /^(\/)?([A-Z]:)/ ; private _scheme : string ; private _authority : string ; private _path : string ; private _query : string ; private _fragment : string ; private _formatted : string ; private _fsPath : string ; constructor ( ) { this . _scheme = URI . _empty ; this . _authority = URI . _empty ; this . _path = URI . _empty ; this . _query = URI . _empty ; this . _fragment = URI . _empty ; this . _formatted = null ; this . _fsPath = null ; } /**
     * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'.
     * The part before the first colon.
     */ get scheme ( ) { return this . _scheme ; } /**
     * authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'.
     * The part between the first double slashes and the next slash.
     */ get authority ( ) { return this . _authority ; } /**
     * path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'.
     */ get path ( ) { return this . _path ; } /**
     * query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'.
     */ get query ( ) { return this . _query ; } /**
     * fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'.
     */ get fragment ( ) { return this . _fragment ; } /**
     * Returns a string representing the corresponding file system path of this URI.
     * Will handle UNC paths and normalize windows drive letters to lower-case. Also
     * uses the platform specific path separator. Will *not* validate the path for
     * invalid characters and semantics. Will *not* look at the scheme of this URI.
     */ get fsPath ( ) { if ( ! this . _fsPath ) { var value ; if ( this . _authority && this . scheme === 'file' ) { value = `//${ this . _authority }${ this . _path }` ; } else if ( URI . _driveLetterPath . test ( this . _path ) ) { value = this . _path [ 1 ] . toLowerCase ( ) + this . _path . substr ( 2 ) ; } else { value = this . _path ; } if ( process . platform === 'win32' ) { value = value . replace ( /\//g , '\\' ) ; } this . _fsPath = value ; } return this . _fsPath ; } public with ( scheme , authority , path , query , fragment ) { var ret = new URI ( ) ; ret . _scheme = scheme || this . scheme ; ret . _authority = authority || this . authority ; ret . _path = path || this . path ; ret . _query = query || this . query ; ret . _fragment = fragment || this . fragment ; URI . _validate ( ret ) ; return ret ; } public withScheme ( value ) { return this . with ( value , undefined , undefined , undefined , undefined ) ; } public withAuthority ( value ) { return this . with ( undefined , value , undefined , undefined , undefined ) ; } public withPath ( value ) { return this . with ( undefined , undefined , value , undefined , undefined ) ; } public withQuery ( value ) { return this . with ( undefined , undefined , undefined , value , undefined ) ; } public withFragment ( value ) { return this . with ( undefined , undefined , undefined , undefined , value ) ; } public static parse ( value ) { const ret = new URI ( ) ; const data = URI . _parseComponents ( value ) ; ret . _scheme = data . scheme ; ret . _authority = decodeURIComponent ( data . authority ) ; ret . _path = decodeURIComponent ( data . path ) ; ret . _query = decodeURIComponent ( data . query ) ; ret . _fragment = decodeURIComponent ( data . fragment ) ; URI . _validate ( ret ) ; return ret ; } public static file ( path ) { const ret = new URI ( ) ; ret . _scheme = 'file' ; path = path . replace ( /\\/g , URI . _slash ) ; if ( path [ 0 ] === URI . _slash && path [ 0 ] === path [ 1 ] ) { let idx = path . indexOf ( URI . _slash , 2 ) ; if ( idx === - 1 ) { ret . _authority = path . substring ( 2 ) ; } else { ret . _authority = path . substring ( 2 , idx ) ; ret . _path = path . substring ( idx ) ; } } else { ret . _path = path ; } if ( ret . _path [ 0 ] !== URI . _slash ) { ret . _path = URI . _slash + ret . _path ; } URI . _validate ( ret ) ; return ret ; } private static _parseComponents ( value ) { const ret = { scheme : URI . _empty , authority : URI . _empty , path : URI . _empty , query : URI . _empty , fragment : URI . _empty , } ; const match = URI . _regexp . exec ( value ) ; if ( match ) { ret . scheme = match [ 2 ] || ret . scheme ; ret . authority = match [ 4 ] || ret . authority ; ret . path = match [ 5 ] || ret . path ; ret . query = match [ 7 ] || ret . query ; ret . fragment = match [ 9 ] || ret . fragment ; } return ret ; } public static create ( scheme ? , authority ? , path ? , query ? , fragment ? ) { return new URI ( ) . with ( scheme , authority , path , query , fragment ) ; } private static _validate ( ret ) { if ( ret . authority && ret . path && ret . path [ 0 ] !== '/' ) { throw new Error ( '[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character' ) ; } if ( ! ret . authority && ret . path . indexOf ( '//' ) === 0 ) { throw new Error ( '[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")' ) ; } } param skipEncoding public toString ( skipEncoding = false ) { if ( ! skipEncoding ) { if ( ! this . _formatted ) { this . _formatted = URI . _asFormatted ( this , false ) ; } return this . _formatted ; } else { return URI . _asFormatted ( this , true ) ; } } private static _asFormatted ( uri , skipEncoding ) { const encoder = ! skipEncoding ? encodeURIComponent2 : encodeNoop ; const parts = [ ] ; let { scheme , authority , path , query , fragment } = uri ; if ( scheme ) { parts . push ( scheme , ':' ) ; } if ( authority || scheme === 'file' ) { parts . push ( '//' ) ; } if ( authority ) { authority = authority . toLowerCase ( ) ; let idx = authority . indexOf ( ':' ) ; if ( idx === - 1 ) { parts . push ( encoder ( authority ) ) ; } else { parts . push ( encoder ( authority . substr ( 0 , idx ) ) , authority . substr ( idx ) ) ; } } if ( path ) { const m = URI . _upperCaseDrive . exec ( path ) ; if ( m ) { path = m [ 1 ] + m [ 2 ] . toLowerCase ( ) + path . substr ( m [ 1 ] . length + m [ 2 ] . length ) ; } let lastIdx = 0 ; while ( true ) { let idx = path . indexOf ( URI . _slash , lastIdx ) ; if ( idx === - 1 ) { parts . push ( encoder ( path . substring ( lastIdx ) ) . replace ( /[#?]/ , _encode ) ) ; break ; } parts . push ( encoder ( path . substring ( lastIdx , idx ) ) . replace ( /[#?]/ , _encode ) , URI . _slash ) ; lastIdx = idx + 1 ; } ; } if ( query ) { parts . push ( '?' , encoder ( query ) ) ; } if ( fragment ) { parts . push ( '#' , encoder ( fragment ) ) ; } return parts . join ( URI . _empty ) ; } public toJSON ( ) { return < UriState > { scheme : this . scheme , authority : this . authority , path : this . path , fsPath : this . fsPath , query : this . query , fragment : this . fragment , external : this . toString ( ) , $mid : 1 } ; } } interface UriComponents { scheme : string ; authority : string ; path : string ; query : string ; fragment : string ; } interface UriState extends UriComponents { $mid : number ; fsPath : string ; external : string ; }