diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/compiler.rs | 102 | ||||
-rw-r--r-- | cli/flags.rs | 33 | ||||
-rw-r--r-- | cli/main.rs | 22 | ||||
-rw-r--r-- | cli/state.rs | 8 | ||||
-rw-r--r-- | cli/worker.rs | 5 |
5 files changed, 162 insertions, 8 deletions
diff --git a/cli/compiler.rs b/cli/compiler.rs index 3a036a627..4233262a3 100644 --- a/cli/compiler.rs +++ b/cli/compiler.rs @@ -50,16 +50,22 @@ impl ModuleMetaData { type CompilerConfig = Option<(String, Vec<u8>)>; /// Creates the JSON message send to compiler.ts's onmessage. -fn req(root_names: Vec<String>, compiler_config: CompilerConfig) -> Buf { +fn req( + root_names: Vec<String>, + compiler_config: CompilerConfig, + bundle: Option<String>, +) -> Buf { let j = if let Some((config_path, config_data)) = compiler_config { json!({ "rootNames": root_names, + "bundle": bundle, "configPath": config_path, "config": str::from_utf8(&config_data).unwrap(), }) } else { json!({ "rootNames": root_names, + "bundle": bundle, }) }; j.to_string().into_boxed_str().into_boxed_bytes() @@ -82,6 +88,67 @@ pub fn get_compiler_config( } } +pub fn bundle_async( + state: ThreadSafeState, + module_name: String, + out_file: String, +) -> impl Future<Item = (), Error = Diagnostic> { + debug!( + "Invoking the compiler to bundle. module_name: {}", + module_name + ); + + let root_names = vec![module_name.clone()]; + let compiler_config = get_compiler_config(&state, "typescript"); + let req_msg = req(root_names, compiler_config, Some(out_file)); + + // Count how many times we start the compiler worker. + state.metrics.compiler_starts.fetch_add(1, Ordering::SeqCst); + + let mut worker = Worker::new( + "TS".to_string(), + startup_data::compiler_isolate_init(), + // TODO(ry) Maybe we should use a separate state for the compiler. + // as was done previously. + state.clone(), + ); + js_check(worker.execute("denoMain()")); + js_check(worker.execute("workerMain()")); + js_check(worker.execute("compilerMain()")); + + let resource = worker.state.resource.clone(); + let compiler_rid = resource.rid; + let first_msg_fut = resources::post_message_to_worker(compiler_rid, req_msg) + .then(move |_| worker) + .then(move |result| { + if let Err(err) = result { + // TODO(ry) Need to forward the error instead of exiting. + eprintln!("{}", err.to_string()); + std::process::exit(1); + } + debug!("Sent message to worker"); + let stream_future = + resources::get_message_stream_from_worker(compiler_rid).into_future(); + stream_future.map(|(f, _rest)| f).map_err(|(f, _rest)| f) + }); + + first_msg_fut.map_err(|_| panic!("not handled")).and_then( + move |maybe_msg: Option<Buf>| { + debug!("Received message from worker"); + + if let Some(msg) = maybe_msg { + let json_str = std::str::from_utf8(&msg).unwrap(); + debug!("Message: {}", json_str); + if let Some(diagnostics) = Diagnostic::from_emit_result(json_str) { + return Err(diagnostics); + } + } + + Ok(()) + }, + ) +} + pub fn compile_async( state: ThreadSafeState, module_meta_data: &ModuleMetaData, @@ -95,7 +162,7 @@ pub fn compile_async( let root_names = vec![module_name.clone()]; let compiler_config = get_compiler_config(&state, "typescript"); - let req_msg = req(root_names, compiler_config); + let req_msg = req(root_names, compiler_config, None); // Count how many times we start the compiler worker. state.metrics.compiler_starts.fetch_add(1, Ordering::SeqCst); @@ -197,7 +264,13 @@ mod tests { maybe_source_map: None, }; - out = compile_sync(ThreadSafeState::mock(), &out).unwrap(); + out = compile_sync( + ThreadSafeState::mock(vec![ + String::from("./deno"), + String::from("hello.js"), + ]), + &out, + ).unwrap(); assert!( out .maybe_output_code @@ -210,8 +283,29 @@ mod tests { #[test] fn test_get_compiler_config_no_flag() { let compiler_type = "typescript"; - let state = ThreadSafeState::mock(); + let state = ThreadSafeState::mock(vec![ + String::from("./deno"), + String::from("hello.js"), + ]); let out = get_compiler_config(&state, compiler_type); assert_eq!(out, None); } + + #[test] + fn test_bundle_async() { + let specifier = "./tests/002_hello.ts"; + use crate::worker; + let module_name = worker::root_specifier_to_url(specifier) + .unwrap() + .to_string(); + + let state = ThreadSafeState::mock(vec![ + String::from("./deno"), + String::from("./tests/002_hello.ts"), + String::from("$deno$/bundle.js"), + ]); + let out = + bundle_async(state, module_name, String::from("$deno$/bundle.js")); + assert_eq!(tokio_util::block_on(out), Ok(())); + } } diff --git a/cli/flags.rs b/cli/flags.rs index a7245eba1..b9a298d28 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -155,6 +155,16 @@ Includes versions of Deno, V8 JavaScript Engine, and the TypeScript compiler.", ), ).subcommand( + SubCommand::with_name("bundle") + .setting(AppSettings::DisableVersion) + .about("Bundle module and dependnecies into single file") + .long_about( + "Fetch, compile, and output to a single file a module and its dependencies. +" + ) + .arg(Arg::with_name("source_file").takes_value(true).required(true)) + .arg(Arg::with_name("out_file").takes_value(true).required(true)), + ).subcommand( SubCommand::with_name("fetch") .setting(AppSettings::DisableVersion) .about("Fetch the dependencies") @@ -436,6 +446,7 @@ const PRETTIER_URL: &str = "https://deno.land/std@v0.7.0/prettier/main.ts"; /// There is no "Help" subcommand because it's handled by `clap::App` itself. #[derive(Debug, PartialEq)] pub enum DenoSubcommand { + Bundle, Eval, Fetch, Info, @@ -455,6 +466,13 @@ pub fn flags_from_vec( let mut flags = parse_flags(&matches.clone()); let subcommand = match matches.subcommand() { + ("bundle", Some(bundle_match)) => { + flags.allow_write = true; + let source_file: &str = bundle_match.value_of("source_file").unwrap(); + let out_file: &str = bundle_match.value_of("out_file").unwrap(); + argv.extend(vec![source_file.to_string(), out_file.to_string()]); + DenoSubcommand::Bundle + } ("eval", Some(eval_match)) => { flags.allow_net = true; flags.allow_env = true; @@ -1034,4 +1052,19 @@ mod tests { assert_eq!(subcommand, DenoSubcommand::Run); assert_eq!(argv, svec!["deno", "script.ts"]); } + + #[test] + fn test_flags_from_vec_26() { + let (flags, subcommand, argv) = + flags_from_vec(svec!["deno", "bundle", "source.ts", "bundle.js"]); + assert_eq!( + flags, + DenoFlags { + allow_write: true, + ..DenoFlags::default() + } + ); + assert_eq!(subcommand, DenoSubcommand::Bundle); + assert_eq!(argv, svec!["deno", "source.ts", "bundle.js"]) + } } diff --git a/cli/main.rs b/cli/main.rs index cfce2254b..ad0374af2 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -41,6 +41,7 @@ mod tokio_write; pub mod version; pub mod worker; +use crate::compiler::bundle_async; use crate::errors::RustOrJsError; use crate::progress::Progress; use crate::state::ThreadSafeState; @@ -261,6 +262,26 @@ fn xeval_command(flags: DenoFlags, argv: Vec<String>) { tokio_util::run(main_future); } +fn bundle_command(flags: DenoFlags, argv: Vec<String>) { + let (mut _worker, state) = create_worker_and_state(flags, argv); + + let main_module = state.main_module().unwrap(); + let main_url = root_specifier_to_url(&main_module).unwrap(); + assert!(state.argv.len() >= 3); + let out_file = state.argv[2].clone(); + debug!(">>>>> bundle_async START"); + let bundle_future = bundle_async(state, main_url.to_string(), out_file) + .map_err(|e| { + debug!("diagnostics returned, exiting!"); + eprintln!("\n{}", e.to_string()); + std::process::exit(1); + }).and_then(move |_| { + debug!(">>>>> bundle_async END"); + Ok(()) + }); + tokio_util::run(bundle_future); +} + fn run_repl(flags: DenoFlags, argv: Vec<String>) { let (mut worker, _state) = create_worker_and_state(flags, argv); @@ -322,6 +343,7 @@ fn main() { }); match subcommand { + DenoSubcommand::Bundle => bundle_command(flags, argv), DenoSubcommand::Eval => eval_command(flags, argv), DenoSubcommand::Fetch => fetch_or_info_command(flags, argv, false), DenoSubcommand::Info => fetch_or_info_command(flags, argv, true), diff --git a/cli/state.rs b/cli/state.rs index d7681fc79..9a8b1cab2 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -311,8 +311,7 @@ impl ThreadSafeState { } #[cfg(test)] - pub fn mock() -> ThreadSafeState { - let argv = vec![String::from("./deno"), String::from("hello.js")]; + pub fn mock(argv: Vec<String>) -> ThreadSafeState { ThreadSafeState::new( flags::DenoFlags::default(), argv, @@ -349,5 +348,8 @@ impl ThreadSafeState { #[test] fn thread_safe() { fn f<S: Send + Sync>(_: S) {} - f(ThreadSafeState::mock()); + f(ThreadSafeState::mock(vec![ + String::from("./deno"), + String::from("hello.js"), + ])); } diff --git a/cli/worker.rs b/cli/worker.rs index f95826674..99470c2a7 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -280,7 +280,10 @@ mod tests { } fn create_test_worker() -> Worker { - let state = ThreadSafeState::mock(); + let state = ThreadSafeState::mock(vec![ + String::from("./deno"), + String::from("hello.js"), + ]); let mut worker = Worker::new("TEST".to_string(), startup_data::deno_isolate_init(), state); js_check(worker.execute("denoMain()")); |