diff options
Diffstat (limited to 'src/compiler.rs')
-rw-r--r-- | src/compiler.rs | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 000000000..627be0a44 --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,156 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +use isolate::Buf; +use isolate::IsolateState; +use msg; +use resources; +use resources::Resource; +use resources::ResourceId; +use workers; + +use futures::Future; +use serde_json; +use std::sync::Arc; +use std::sync::Mutex; + +lazy_static! { + static ref c_rid: Mutex<Option<ResourceId>> = Mutex::new(None); +} + +// This corresponds to JS ModuleMetaData. +// TODO Rename one or the other so they correspond. +#[derive(Debug)] +pub struct CodeFetchOutput { + pub module_name: String, + pub filename: String, + pub media_type: msg::MediaType, + pub source_code: String, + pub maybe_output_code: Option<String>, + pub maybe_source_map: Option<String>, +} + +impl CodeFetchOutput { + pub fn js_source<'a>(&'a self) -> String { + if self.media_type == msg::MediaType::Json { + return String::from(format!("export default {};", self.source_code)); + } + match self.maybe_output_code { + None => self.source_code.clone(), + Some(ref output_code) => output_code.clone(), + } + } +} + +impl CodeFetchOutput { + // TODO Use serde_derive? Use flatbuffers? + fn from_json(json_str: &str) -> Option<Self> { + match serde_json::from_str::<serde_json::Value>(json_str) { + Ok(serde_json::Value::Object(map)) => { + let module_name = match map["moduleId"].as_str() { + None => return None, + Some(s) => s.to_string(), + }; + + let filename = match map["fileName"].as_str() { + None => return None, + Some(s) => s.to_string(), + }; + + let source_code = match map["sourceCode"].as_str() { + None => return None, + Some(s) => s.to_string(), + }; + + let maybe_output_code = + map["outputCode"].as_str().map(|s| s.to_string()); + + let maybe_source_map = map["sourceMap"].as_str().map(|s| s.to_string()); + + Some(CodeFetchOutput { + module_name, + filename, + media_type: msg::MediaType::JavaScript, // TODO + source_code, + maybe_output_code, + maybe_source_map, + }) + } + _ => None, + } + } +} + +fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource { + let mut cell = c_rid.lock().unwrap(); + let rid = cell.get_or_insert_with(|| { + let resource = + workers::spawn(parent_state.clone(), "compilerMain()".to_string()); + resource.rid + }); + Resource { rid: *rid } +} + +fn req(specifier: &str, referrer: &str) -> Buf { + json!({ + "specifier": specifier, + "referrer": referrer, + }).to_string() + .into_boxed_str() + .into_boxed_bytes() +} + +pub fn compile_sync( + parent_state: &Arc<IsolateState>, + specifier: &str, + referrer: &str, +) -> Option<CodeFetchOutput> { + let req_msg = req(specifier, referrer); + + let compiler = lazy_start(parent_state); + + let send_future = resources::worker_post_message(compiler.rid, req_msg); + send_future.wait().unwrap(); + + let recv_future = resources::worker_recv_message(compiler.rid); + let res_msg = recv_future.wait().unwrap().unwrap(); + + let res_json = std::str::from_utf8(&res_msg).unwrap(); + CodeFetchOutput::from_json(res_json) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_compile_sync() { + let cwd = std::env::current_dir().unwrap(); + let cwd_string = cwd.to_str().unwrap().to_owned(); + + let specifier = "./tests/002_hello.ts"; + let referrer = cwd_string + "/"; + + let cfo = + compile_sync(&IsolateState::mock(), specifier, &referrer).unwrap(); + let output_code = cfo.maybe_output_code.unwrap(); + assert!(output_code.starts_with("console.log(\"Hello World\");")); + } + + #[test] + fn code_fetch_output_from_json() { + let json = r#"{ + "moduleId":"/Users/rld/src/deno/tests/002_hello.ts", + "fileName":"/Users/rld/src/deno/tests/002_hello.ts", + "mediaType":1, + "sourceCode":"console.log(\"Hello World\");\n", + "outputCode":"yyy", + "sourceMap":"xxx", + "scriptVersion":"1" + }"#; + let actual = CodeFetchOutput::from_json(json).unwrap(); + assert_eq!(actual.filename, "/Users/rld/src/deno/tests/002_hello.ts"); + assert_eq!(actual.module_name, "/Users/rld/src/deno/tests/002_hello.ts"); + assert_eq!(actual.source_code, "console.log(\"Hello World\");\n"); + assert_eq!(actual.maybe_output_code, Some("yyy".to_string())); + assert_eq!(actual.maybe_source_map, Some("xxx".to_string())); + } +} |