namespace pxt { export interface SimpleDriverCallbacks { cacheGet : ( key : string ) => Promise < string > ; cacheSet : ( key : string , val : string ) => Promise < void > ; httpRequestAsync ? : ( options : Util . HttpRequestOptions ) => Promise < Util . HttpResponse > ; pkgOverrideAsync ? : ( id : string ) => Promise < Map < string > > ; } let callbacks ; let ghSetup = false ; class CachedGithubDb implements pxt . github . IGithubDb { constructor ( public readonly db ) { } private loadAsync < T > ( repopath , tag , suffix , loader ) { if ( ! /^v\d+\.\d+\.\d+$/ . test ( tag ) ) return loader ( repopath , tag ) ; const key = `gh-${ suffix }-${ repopath }#${ tag }` ; return callbacks . cacheGet ( key ) . then ( json => { if ( json ) { const p = pxt . Util . jsonTryParse ( json ) as T ; if ( p ) { pxt . debug ( `cache hit ${ key }` ) ; return Promise . resolve ( p ) ; } } return loader ( repopath , tag ) . then ( p => { if ( p ) { pxt . debug ( `cached ${ key }` ) ; return callbacks . cacheSet ( key , JSON . stringify ( p ) ) . then ( ( ) => p ) ; } return p ; } ) ; } ) ; } loadConfigAsync ( repopath , tag ) { return this . loadAsync ( repopath , tag , "pxt" , ( r , t ) => this . db . loadConfigAsync ( r , t ) ) ; } loadPackageAsync ( repopath , tag ) { return this . loadAsync ( repopath , tag , "pkg" , ( r , t ) => this . db . loadPackageAsync ( r , t ) ) ; } } function pkgOverrideAsync ( pkg ) { const f = callbacks ?. pkgOverrideAsync ; const v = f ? f ( pkg . id ) : Promise . resolve ( undefined as Map < string > ) ; return v . then ( r => r ? r : pkg . commonDownloadAsync ( ) ) ; } export class SimpleHost implements pxt . Host { constructor ( public packageFiles ) { } resolve ( module , filename ) { return "" ; } readFile ( module , filename ) { const fid = module . id == "this" ? filename : "pxt_modules/" + module . id + "/" + filename ; if ( this . packageFiles [ fid ] !== undefined ) { return this . packageFiles [ fid ] ; } else if ( pxt . appTarget . bundledpkgs [ module . id ] ) { return pxt . appTarget . bundledpkgs [ module . id ] [ filename ] ; } else { return null ; } } writeFile ( module , filename , contents ) { const pref = module . id == "this" ? "" : "pxt_modules/" + module . id + "/" ; pxt . debug ( `write file ${ pref + filename }` ) ; this . packageFiles [ pref + filename ] = contents ; } getHexInfoAsync ( extInfo ) { return Promise . resolve < any > ( { hex : [ "SKIP" ] } ) ; } cacheStoreAsync ( id , val ) { if ( callbacks ?. cacheSet ) return callbacks . cacheSet ( id , val ) ; return Promise . resolve ( ) ; } cacheGetAsync ( id ) { if ( callbacks ?. cacheGet ) return callbacks . cacheGet ( id ) ; return Promise . resolve ( "" ) ; } downloadPackageAsync ( pkg ) { if ( ghSetup ) return pkgOverrideAsync ( pkg ) . then ( resp => { if ( resp ) { U . iterMap ( resp , ( fn , cont ) => { this . writeFile ( pkg , fn , cont ) ; } ) ; } } ) ; return Promise . resolve ( ) ; } resolveVersionAsync ( pkg ) { return Promise . resolve ( "*" ) ; } } export function prepPythonOptions ( opts ) { if ( opts . target . preferredEditor == pxt . PYTHON_PROJECT_NAME ) { const opts2 = U . clone ( opts ) ; opts2 . ast = true ; opts2 . target . preferredEditor = pxt . JAVASCRIPT_PROJECT_NAME ; for ( let f of opts2 . sourceFiles ) { if ( U . endsWith ( f , ".py" ) ) opts2 . fileSystem [ f . slice ( 0 , - 3 ) + ".ts" ] = " " ; } const res = pxtc . compile ( opts2 ) ; opts . apisInfo = pxtc . getApiInfo ( res . ast , opts2 . jres ) ; } } export interface CompileResultWithErrors extends pxtc . CompileResult { errors ? : string ; } export interface SimpleCompileOptions { native ? : boolean ; } export function simpleInstallPackagesAsync ( files ) { const host = new SimpleHost ( files ) ; const mainPkg = new MainPackage ( host ) ; return mainPkg . loadAsync ( true ) ; } export function simpleGetCompileOptionsAsync ( files , simpleOptions ) { const host = new SimpleHost ( files ) ; const mainPkg = new MainPackage ( host ) ; return mainPkg . loadAsync ( ) . then ( ( ) => { let target = mainPkg . getTargetOptions ( ) ; if ( target . hasHex ) target . isNative = simpleOptions . native ; return mainPkg . getCompileOptionsAsync ( target ) ; } ) . then ( opts => { patchTS ( mainPkg . targetVersion ( ) , opts ) ; prepPythonOptions ( opts ) ; return opts ; } ) ; } export function simpleCompileAsync ( files , optionsOrNative ? ) { const options = typeof optionsOrNative == "boolean" ? { native : optionsOrNative } : optionsOrNative || { } ; return simpleGetCompileOptionsAsync ( files , options ) . then ( opts => pxtc . compile ( opts ) ) . then ( ( r ) => { if ( ! r . success ) r . errors = r . diagnostics . map ( ts . pxtc . getDiagnosticString ) . join ( "" ) || "Unknown error." ; return r ; } ) ; } export function patchTS ( version , opts ) { if ( ! version ) return ; pxt . debug ( `applying TS patches relative to ${ version }` ) ; for ( let fn of Object . keys ( opts . fileSystem ) ) { if ( fn . indexOf ( "/" ) == - 1 && U . endsWith ( fn , ".ts" ) ) { const ts = opts . fileSystem [ fn ] ; const ts2 = pxt . patching . patchJavaScript ( version , ts ) ; if ( ts != ts2 ) { pxt . debug ( `applying TS patch to ${ fn }` ) ; opts . fileSystem [ fn ] = ts2 ; } } } } declare var global ; declare var Buffer ; declare var pxtTargetBundle ; export function setupSimpleCompile ( cfg ? ) { if ( typeof global != "undefined" && ! global . btoa ) { global . btoa = function ( str ) { return Buffer . from ( str , "binary" ) . toString ( "base64" ) ; } ; global . atob = function ( str ) { return Buffer . from ( str , "base64" ) . toString ( "binary" ) ; } ; } if ( typeof pxtTargetBundle != "undefined" ) { pxt . debug ( "setup app bundle" ) ; pxt . setAppTarget ( pxtTargetBundle ) ; } if ( cfg ) { callbacks = cfg ; ghSetup = true ; if ( cfg . httpRequestAsync ) Util . httpRequestCoreAsync = cfg . httpRequestAsync ; pxt . github . forceProxy = true ; pxt . github . db = new CachedGithubDb ( new pxt . github . MemoryGithubDb ( ) ) ; } pxt . debug ( "simple setup done" ) ; } }