import Type from "typescript-dotnet-core/Types" ; import UriComponent from "./UriComponent" ; import Scheme from "./Scheme" ; import SchemeValue from "./SchemeValue" ; import QueryParam from "./QueryParam" ; import { encode , parseToMap , Separator } from "./QueryParams" ; import { trim } from "typescript-dotnet-core/Text/Utility" ; import Exception from "typescript-dotnet-core/Exception" ; import ArgumentException from "typescript-dotnet-core/Exceptions/ArgumentException" ; import ArgumentOutOfRangeException from "typescript-dotnet-core/Exceptions/ArgumentOutOfRangeException" ; import IUri from "./IUri" ; import IMap from "typescript-dotnet-core/IMap" ; import Primitive from "typescript-dotnet-core/Primitive" ; import IEquatable from "typescript-dotnet-core/IEquatable" ; import { Action } from "typescript-dotnet-core/FunctionTypes" ; const VOID0 = void 0 ; /**
 * Provides an read-only model representation of a uniform resource identifier (URI) and easy access to the parts of the URI.
 *
 * The read-only model (frozen) is easier for debugging than exposing accessors for each property.
 * ICloneable&lt;Uri&gt; is not used to prevent unnecessary copying of values that won't change.
 */ export class Uri implements IUri , IEquatable < IUri > { readonly scheme : SchemeValue . Any | null ; readonly userInfo : string | null ; readonly host : string | null ; readonly port : number | null ; readonly path : string | null ; readonly query : string | null ; readonly fragment : string | null ; readonly queryParams : IMap < Primitive | Primitive [ ] > ; param scheme param userInfo param host param port param path param query param fragment constructor ( scheme , userInfo , host , port , path , query ? , fragment ? ) { const _ = this ; this . scheme = getScheme ( scheme ) || null ; this . userInfo = userInfo || null ; this . host = host || null ; this . port = getPort ( port ) ; this . authority = _ . getAuthority ( ) || null ; this . path = path || null ; if ( ! Type . isString ( query ) ) query = encode ( < UriComponent . Map | QueryParam . EnumerableOrArray > query ) ; this . query = formatQuery ( < string > query ) || null ; Object . freeze ( this . queryParams = _ . query ? parseToMap ( _ . query ) : { } ) ; this . pathAndQuery = _ . getPathAndQuery ( ) || null ; this . fragment = formatFragment ( fragment ) || null ; this . absoluteUri = _ . getAbsoluteUri ( ) ; this . baseUri = _ . absoluteUri . replace ( /[?#].*/ , '' ) ; Object . freeze ( this ) ; } param other returns { boolean } equals ( other ) { return this === other || this . absoluteUri == Uri . toString ( other ) ; } param uri param defaults returns { Uri } static from ( uri , defaults ? ) { const u = Type . isString ( uri ) ? Uri . parse ( < string > uri ) : < IUri > uri ; return new Uri ( u && u . scheme || defaults && < any > defaults . scheme , u && u . userInfo || defaults && < any > defaults . userInfo , u && u . host || defaults && < any > defaults . host , u && Type . isNumber ( u . port , true ) ? u . port : defaults && < any > defaults . port , u && u . path || defaults && < any > defaults . path , u && u . query || defaults && < any > defaults . query , u && u . fragment || defaults && < any > defaults . fragment ) ; } param url returns { IUri } static parse ( url ) ; static parse ( url , throwIfInvalid ) ; param url param throwIfInvalid returns { IUri } static parse ( url , throwIfInvalid ) ; static parse ( url , throwIfInvalid = true ) { let result = null ; const ex = tryParse ( url , ( out ) => { result = out ; } ) ; if ( throwIfInvalid && ex ) throw ex ; return result ; } param url param out returns { boolean } static tryParse ( url , out ) { return ! tryParse ( url , out ) ; } static copyOf ( map ) { return copyUri ( map ) ; } copyTo ( map ) { return copyUri ( this , map ) ; } updateQuery ( query ) { const map = this . toMap ( ) ; map . query = < any > query ; return Uri . from ( map ) ; } /**
     * Is provided for sub classes to override this value.
     */ protected getAbsoluteUri ( ) { return uriToString ( this ) ; } /**
     * Is provided for sub classes to override this value.
     */ protected getAuthority ( ) { return getAuthority ( this ) ; } /**
     * Is provided for sub classes to override this value.
     */ protected getPathAndQuery ( ) { return getPathAndQuery ( this ) ; } /**
     * The absolute URI.
     */ absoluteUri : string ; /**
     * Gets the Domain Name System (DNS) host name or IP address and the port number for a server.
     */ readonly authority : string | null ; /**
     * Gets the path and Query properties separated by a question mark (?).
     */ readonly pathAndQuery : string | null ; /**
     * Gets the full path without the query or fragment.
     */ readonly baseUri : string ; returns { string [ ] } get pathSegments ( ) : string [ ] { return this . path && this . path . match ( /^[/]|[^/]*[/]|[^/]+$/g ) || [ ] ; } returns { IUri } toMap ( ) { return this . copyTo ( { } ) ; } returns { string } toString ( ) { return this . absoluteUri ; } param uri returns { string } static toString ( uri ) { return uri instanceof < any > Uri ? ( < Uri > uri ) . absoluteUri : uriToString ( uri ) ; } param uri returns { string } static getAuthority ( uri ) { return getAuthority ( uri ) ; } } export enum Fields { scheme , userInfo , host , port , path , query , fragment } Object . freeze ( Fields ) ; function copyUri ( from , to ? ) { let i = 0 , field ; if ( ! to ) to = { } ; while ( ( field = Fields [ i ++ ] ) ) { const value = ( < any > from ) [ field ] ; if ( value ) ( < any > to ) [ field ] = value ; } return to ; } const SLASH = '/' , SLASH2 = '//' , QM = Separator . Query , HASH = '#' , EMPTY = '' , AT = '@' ; function getScheme ( scheme ) { let s = scheme ; if ( Type . isString ( s ) ) { if ( ! s ) return null ; s = trim ( s ) . toLowerCase ( ) . replace ( /[^a-z0-9+.-]+$/g , EMPTY ) ; if ( ! s ) return null ; if ( Scheme . isValid ( s ) ) return s ; } else { if ( s == null ) return s ; } throw new ArgumentOutOfRangeException ( 'scheme' , scheme , 'Invalid scheme.' ) ; } function getPort ( port ) { if ( port === 0 ) return < number > port ; if ( ! port ) return null ; let p ; if ( Type . isNumber ( port ) ) { p = < number > port ; if ( p >= 0 && isFinite ( p ) ) return p ; } else if ( Type . isString ( port ) && ( p = parseInt ( < string > port ) ) && ! isNaN ( p ) ) { return getPort ( p ) ; } throw new ArgumentException ( "port" , "invalid value" ) ; } function getAuthority ( uri ) { if ( ! uri . host ) { if ( uri . userInfo ) throw new ArgumentException ( 'host' , 'Cannot include user info when there is no host.' ) ; if ( Type . isNumber ( uri . port , true ) ) throw new ArgumentException ( 'host' , 'Cannot include a port when there is no host.' ) ; } let result = uri . host || EMPTY ; if ( result ) { if ( uri . userInfo ) result = uri . userInfo + AT + result ; if ( ! isNaN ( < any > ( uri . port ) ) ) result += ':' + uri . port ; result = SLASH2 + result ; } return result ; } function formatQuery ( query ) { return query && ( ( query . indexOf ( QM ) !== 0 ? QM : EMPTY ) + query ) ; } function formatFragment ( fragment ) { return fragment && ( ( fragment . indexOf ( HASH ) !== 0 ? HASH : EMPTY ) + fragment ) ; } function getPathAndQuery ( uri ) { const path = uri . path , query = uri . query ; return EMPTY + ( path || EMPTY ) + ( formatQuery ( query ) || EMPTY ) ; } function uriToString ( uri ) { const scheme = getScheme ( uri . scheme ) ; let authority = getAuthority ( uri ) ; const pathAndQuery = getPathAndQuery ( uri ) , fragment = formatFragment ( uri . fragment ) ; const part1 = EMPTY + ( ( scheme && ( scheme + ':' ) ) || EMPTY ) + ( authority || EMPTY ) ; let part2 = EMPTY + ( pathAndQuery || EMPTY ) + ( fragment || EMPTY ) ; if ( part1 && part2 && scheme && ! authority ) throw new ArgumentException ( 'authority' , "Cannot format schemed Uri with missing authority." ) ; if ( part1 && pathAndQuery && pathAndQuery . indexOf ( SLASH ) !== 0 ) part2 = SLASH + part2 ; return part1 + part2 ; } function tryParse ( url , out ) { if ( ! url ) return new ArgumentException ( 'url' , 'Nothing to parse.' ) ; let i ; const result = { } ; i = url . indexOf ( HASH ) ; if ( i != - 1 ) { result . fragment = url . substring ( i + 1 ) || VOID0 ; url = url . substring ( 0 , i ) ; } i = url . indexOf ( QM ) ; if ( i != - 1 ) { result . query = url . substring ( i + 1 ) || VOID0 ; url = url . substring ( 0 , i ) ; } i = url . indexOf ( SLASH2 ) ; if ( i != - 1 ) { let scheme = trim ( url . substring ( 0 , i ) ) ; const c = /:$/ ; if ( ! c . test ( scheme ) ) return new ArgumentException ( 'url' , 'Scheme was improperly formatted' ) ; scheme = trim ( scheme . replace ( c , EMPTY ) ) ; try { result . scheme = getScheme ( scheme ) || VOID0 ; } catch ( ex ) { return ex ; } url = url . substring ( i + 2 ) ; } i = url . indexOf ( SLASH ) ; if ( i != - 1 ) { result . path = url . substring ( i ) ; url = url . substring ( 0 , i ) ; } i = url . indexOf ( AT ) ; if ( i != - 1 ) { result . userInfo = url . substring ( 0 , i ) || VOID0 ; url = url . substring ( i + 1 ) ; } i = url . indexOf ( ':' ) ; if ( i != - 1 ) { const port = parseInt ( trim ( url . substring ( i + 1 ) ) ) ; if ( isNaN ( port ) ) return new ArgumentException ( 'url' , 'Port was invalid.' ) ; result . port = port ; url = url . substring ( 0 , i ) ; } url = trim ( url ) ; if ( url ) result . host = url ; out ( copyUri ( result ) ) ; return null ; } export default Uri ;