import * as path from 'path' ; import * as utils from './utils' ; import { ObjectContext } from './object-context' ; export class Uri { public protocol : string = null ; public path : string = null ; private _parameters : { [ key ] : string ; } = { } ; public static parse ( input ) { let result = this . tryParse ( input ) ; if ( ! result . success ) { throw new Error ( "Invalid URI string '" + input + "'" ) ; } return result . uri ; } public static tryParse ( input ) { let start = 0 ; let end = input . indexOf ( ":/" ) ; if ( end <= 0 ) { return { success : false , uri : null } ; } let uri = new Uri ( ) ; uri . protocol = input . substring ( start , end ) ; let path = "" ; start = end + 2 ; end = input . indexOf ( "?" , start ) ; if ( end == - 1 ) { uri . path = input . substring ( start ) ; } else { uri . path = input . substring ( start , end ) ; let kvStrings = input . substring ( end + 1 ) . split ( '&' ) ; for ( let i = 0 ; i < kvStrings . length ; ++ i ) { let cols = kvStrings [ i ] . split ( '=' ) ; if ( cols . length != 2 ) { return { success : false , uri : null } ; } uri . setParameter ( cols [ 0 ] , cols [ 1 ] ) ; } } return { success : true , uri : uri } ; } public getParameter ( name ) { return this . _parameters [ name . toLowerCase ( ) ] ; } public setParameter ( name , value ) { this . _parameters [ name . toLowerCase ( ) ] = value ; } public static isUri ( input ) { return Uri . tryParse ( input ) . success ; } } export type ProviderMethod = ( uri : Uri | Uri [ ] , context ? : ObjectContext ) => any ; export interface ObjectProvider { provide ( uri , context ? ) : any ; supports ( protocol ) : boolean ; } export interface ProviderDef { protocol : string ; description ? : string ; moduleName : string ; functionName : string ; override ? : boolean ; exampleUri ? : string [ ] ; } export class ProviderRegistry implements ObjectProvider { private _protocolToProviderMethod : Map < string , ProviderMethod > = new Map < string , ProviderMethod > ( ) ; public provide ( uri , context ? ) { let protocol ; if ( Array . isArray ( uri ) ) { if ( ( < Uri [ ] > uri ) . length == 0 ) { return null ; } protocol = ( < Uri [ ] > uri ) [ 0 ] . protocol ; for ( let item of uri ) { if ( item . protocol !== protocol ) { throw new Error ( "Protocol must the the same with an array of Uris when calling ObjectContext.create." ) ; } } } else { protocol = ( < Uri > uri ) . protocol ; } let lowerCaseProtocol = protocol . toLowerCase ( ) ; if ( this . supports ( lowerCaseProtocol ) ) { return this . _protocolToProviderMethod . get ( lowerCaseProtocol ) ( uri , context ) ; } throw new Error ( "Unsupported protocol '" + protocol + "'." ) ; } public register ( protocol , loader ) { this . _protocolToProviderMethod . set ( protocol . toLowerCase ( ) , loader ) ; } public supports ( protocol ) { return this . _protocolToProviderMethod . has ( protocol . toLowerCase ( ) ) ; } public static fromDefinition ( providerDefCollection , baseDir ) { let registry = new ProviderRegistry ( ) ; if ( providerDefCollection != null ) { for ( let def of providerDefCollection ) { let moduleName = def . moduleName ; if ( ! path . isAbsolute ( def . moduleName ) ) { moduleName = path . resolve ( baseDir , moduleName ) ; } let creator = utils . loadFunction ( moduleName , def . functionName ) ; registry . register ( def . protocol , creator ) ; } } return registry ; } } const SCHEMA_DIR = path . resolve ( __dirname , '../schema' ) ; export class ProviderConfig { private static readonly OBJECT_PROVIDER_CONFIG_SCHEMA : utils . JsonSchema = new utils . JsonSchema ( path . resolve ( SCHEMA_DIR , "object-provider-config.schema.json" ) ) ; private static _transform : utils . Transform = new utils . SetDefaultValue ( { 'override' : false } ) ; public static fromConfigObject ( jsValue , validateSchema = true ) { if ( validateSchema ) { utils . ensureSchema ( jsValue , this . OBJECT_PROVIDER_CONFIG_SCHEMA ) ; } jsValue . forEach ( obj => { this . _transform . apply ( obj ) ; } ) ; return jsValue ; } public static fromConfig ( objectProviderConfig ) { return utils . appendMessageOnException ( "Error found in object provider definition file '" + objectProviderConfig + "'." , ( ) => { return this . fromConfigObject ( utils . readConfig ( objectProviderConfig ) ) ; } ) ; } }