import { Project , fileTypeForExtension , mimeTypeForFileType } from "../models" ; import { Gulpy } from "../gulpy" ; import { Service } from "../service" ; import { Arc } from "../arc" ; export enum RunTaskExternals { Default , Arc , Setup } function unsafeEval ( code , params ) { const paramKeys = Object . keys ( params ) ; const paramValues = Object . values ( params ) ; const fn = Function . apply ( null , [ ... paramKeys , code ] ) ; return fn . apply ( window , paramValues ) ; } function contextify ( src , sandboxGlobal = window , thisArg = window , context = { } , modules = { } ) { function require ( name , factory ? ) { if ( typeof name === "string" ) { if ( modules . hasOwnProperty ( name ) ) { return modules [ name ] ; } return ( window as any ) . require ( name ) ; } return ( window as any ) . require ( name , factory ) ; } Object . defineProperty ( require , "config" , { value : ( window as any ) . require . config } ) ; const contextParameters = Object . keys ( context ) . concat ( "require" , "exports" , "return ()=>{" + src + "}" ) ; const contextArguments = Object . values ( context ) . concat ( require , { } ) ; const global = sandboxGlobal || window ; return global . Function . apply ( null , contextParameters ) . apply ( thisArg , contextArguments ) ; } async function createSandboxIFrame ( ) { const src = `<!DOCTYPE html>
<html><body>
<script>window.parent.postMessage({type: "taskRunner-sandbox-ready"}, "*");</script>
</body></html>` ; const iframe = document . createElement ( "iframe" ) as HTMLIFrameElement ; iframe . setAttribute ( "width" , "1" ) ; iframe . setAttribute ( "height" , "1" ) ; iframe . setAttribute ( "src" , URL . createObjectURL ( new Blob ( [ src ] , { type : "text/html" } ) ) ) ; const container = document . getElementById ( "task-runner-content" ) ; container . textContent = "" ; container . appendChild ( iframe ) ; return new Promise ( ( resolve ) => { iframeReady . set ( iframe , resolve ) ; } ) ; } const iframeReady = new WeakMap ( ) ; window . addEventListener ( "message" , ( e ) => { if ( typeof e . data !== "object" || ! e . data || e . data . type !== "taskRunner-sandbox-ready" ) { return ; } const contentWindow = e . source as Window ; const iframe = ( contentWindow as Window ) . frameElement as HTMLIFrameElement ; iframeReady . get ( iframe ) ( contentWindow as Window ) ; const originalFetch = window . fetch ; contentWindow . fetch = ( input , init ? ) => { let file = null ; if ( currentRunnerInfo && currentRunnerInfo . global === contentWindow ) { const url = new URL ( input , "https://example.org/src/main.html" ) ; file = currentRunnerInfo . project . getFile ( url . pathname . substr ( 1 ) ) ; } if ( file ) { return Promise . resolve ( new Response ( file . getData ( ) , { status : 200 , statusText : "OK" , headers : { "Content-Type" : mimeTypeForFileType ( file . type ) } } ) ) ; } return originalFetch ( input , init ) ; } ; } ) ; export interface RunnerInfo { global : any ; project : Project ; } let currentRunnerInfo = null ; function clearCurrentRunnerInfoAndIframe ( ) { currentRunnerInfo = null ; const container = document . getElementById ( "task-runner-content" ) ; container . textContent = "" ; } export function getCurrentRunnerInfo ( ) { return currentRunnerInfo ; } export async function runTask ( src , name , optional , project , logLn , externals ) { const currentRunnerGlobal = await createSandboxIFrame ( ) ; currentRunnerInfo = { global : currentRunnerGlobal , project , } ; const gulp = new Gulpy ( ) ; contextify ( src , currentRunnerGlobal , gulp , { gulp , Service , project , logLn , fileTypeForExtension , monaco : externals === RunTaskExternals . Setup ? monaco : undefined , } , { "gulp" : gulp , "@wasm/studio-utils" : { Service , project , logLn , fileTypeForExtension , Arc : externals === RunTaskExternals . Arc ? Arc : undefined , eval : externals === RunTaskExternals . Setup ? unsafeEval : undefined , } } ) ( ) ; if ( gulp . hasTask ( name ) ) { try { logLn ( `Task ${ name } is running...` , "info" ) ; await gulp . run ( name ) ; logLn ( `Task ${ name } is completed` , "info" ) ; } catch ( e ) { logLn ( `Task ${ name } failed: ${ e . message }` , "error" ) ; } } else if ( ! optional ) { logLn ( `Task ${ name } is not optional.` , "error" ) ; } clearCurrentRunnerInfoAndIframe ( ) ; }