0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-10-31 09:14:20 -04:00
denoland-deno/src/compiler.rs

157 lines
4.3 KiB
Rust
Raw Normal View History

// 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()));
}
}