diff --git a/cli/build.rs b/cli/build.rs index 7e073c8ff6..e75b09d749 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use deno_core::include_crate_modules; use deno_core::CoreOp; use deno_core::Isolate; use deno_core::Op; @@ -47,6 +48,8 @@ fn main() { deno_typescript::ts_version() ); + let extern_crate_modules = include_crate_modules![deno_core]; + // The generation of snapshots is slow and often unnecessary. Until we figure // out how to speed it up, or avoid it when unnecessary, this env var provides // an escape hatch for the impatient hacker in need of faster incremental @@ -65,9 +68,12 @@ fn main() { let bundle_path = o.join("CLI_SNAPSHOT.js"); let snapshot_path = o.join("CLI_SNAPSHOT.bin"); - let main_module_name = - deno_typescript::compile_bundle(&bundle_path, root_names) - .expect("Bundle compilation failed"); + let main_module_name = deno_typescript::compile_bundle( + &bundle_path, + root_names, + Some(extern_crate_modules.clone()), + ) + .expect("Bundle compilation failed"); assert!(bundle_path.exists()); let runtime_isolate = &mut Isolate::new(StartupData::None, true); @@ -102,9 +108,12 @@ fn main() { c.join("js/lib.deno.ns.d.ts"), ); - let main_module_name = - deno_typescript::compile_bundle(&bundle_path, root_names) - .expect("Bundle compilation failed"); + let main_module_name = deno_typescript::compile_bundle( + &bundle_path, + root_names, + Some(extern_crate_modules), + ) + .expect("Bundle compilation failed"); assert!(bundle_path.exists()); let runtime_isolate = &mut Isolate::new(StartupData::None, true); diff --git a/core/lib.rs b/core/lib.rs index 91f91a1c98..2fcfa178b9 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -45,3 +45,5 @@ pub fn v8_version() -> &'static str { fn test_v8_version() { assert!(v8_version().len() > 3); } + +crate_modules!(); diff --git a/core/modules.rs b/core/modules.rs index 21c2481dd3..c02bd4cab6 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -449,6 +449,26 @@ impl fmt::Display for Deps { } } +#[macro_export] +macro_rules! crate_modules { + () => { + pub const DENO_CRATE_PATH: &'static str = env!("CARGO_MANIFEST_DIR"); + }; +} + +#[macro_export] +macro_rules! include_crate_modules { + ( $( $x:ident ),* ) => { + { + let mut temp: HashMap = HashMap::new(); + $( + temp.insert(stringify!($x).to_string(), $x::DENO_CRATE_PATH.to_string()); + )* + temp + } + }; +} + #[cfg(test)] mod tests { use super::*; diff --git a/deno_typescript/compiler_main.js b/deno_typescript/compiler_main.js index 94b38e070c..013d6e157d 100644 --- a/deno_typescript/compiler_main.js +++ b/deno_typescript/compiler_main.js @@ -184,8 +184,8 @@ class Host { fileName = moduleMap.get(fileName); } - const { sourceCode, moduleName } = dispatch("readFile", { - fileName, + const { sourceCode, moduleName } = dispatch("loadModule", { + moduleUrl: fileName, languageVersion, shouldCreateNewSourceFile }); diff --git a/deno_typescript/lib.rs b/deno_typescript/lib.rs index 1bf6eb351f..7977b7cfe1 100644 --- a/deno_typescript/lib.rs +++ b/deno_typescript/lib.rs @@ -16,6 +16,7 @@ use deno_core::StartupData; use deno_core::ZeroCopyBuf; pub use ops::EmitResult; use ops::WrittenFile; +use std::collections::HashMap; use std::fs; use std::path::Path; use std::path::PathBuf; @@ -32,6 +33,8 @@ pub fn ts_version() -> String { pkg["version"].as_str().unwrap().to_string() } +type ExternCrateModules = HashMap; + #[derive(Debug)] pub struct TSState { bundle: bool, @@ -40,6 +43,7 @@ pub struct TSState { /// A list of files emitted by typescript. WrittenFile is tuple of the form /// (url, corresponding_module, source_code) written_files: Vec, + extern_crate_modules: ExternCrateModules, } fn compiler_op( @@ -62,21 +66,27 @@ pub struct TSIsolate { } impl TSIsolate { - fn new(bundle: bool) -> TSIsolate { + fn new( + bundle: bool, + maybe_extern_crate_modules: Option, + ) -> TSIsolate { let mut isolate = Isolate::new(StartupData::None, false); js_check(isolate.execute("assets/typescript.js", TYPESCRIPT_CODE)); js_check(isolate.execute("compiler_main.js", COMPILER_CODE)); + let extern_crate_modules = maybe_extern_crate_modules.unwrap_or_default(); + let state = Arc::new(Mutex::new(TSState { bundle, exit_code: 0, emit_result: None, written_files: Vec::new(), + extern_crate_modules, })); isolate.register_op( - "readFile", - compiler_op(state.clone(), ops::json_op(ops::read_file)), + "loadModule", + compiler_op(state.clone(), ops::json_op(ops::load_module)), ); isolate .register_op("exit", compiler_op(state.clone(), ops::json_op(ops::exit))); @@ -125,8 +135,9 @@ impl TSIsolate { pub fn compile_bundle( bundle_filename: &Path, root_names: Vec, + extern_crate_modules: Option, ) -> Result { - let ts_isolate = TSIsolate::new(true); + let ts_isolate = TSIsolate::new(true, extern_crate_modules); let config_json = serde_json::json!({ "compilerOptions": { diff --git a/deno_typescript/ops.rs b/deno_typescript/ops.rs index f76662620d..f9b244397e 100644 --- a/deno_typescript/ops.rs +++ b/deno_typescript/ops.rs @@ -35,16 +35,16 @@ pub fn json_op(d: Dispatcher) -> impl Fn(&mut TSState, &[u8]) -> CoreOp { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -struct ReadFile { - file_name: String, +struct LoadModule { + module_url: String, language_version: Option, should_create_new_source_file: bool, } -pub fn read_file(_s: &mut TSState, v: Value) -> Result { - let v: ReadFile = serde_json::from_value(v)?; - let (module_name, source_code) = if v.file_name.starts_with("$asset$/") { - let asset = v.file_name.replace("$asset$/", ""); +pub fn load_module(s: &mut TSState, v: Value) -> Result { + let v: LoadModule = serde_json::from_value(v)?; + let (module_name, source_code) = if v.module_url.starts_with("$asset$/") { + let asset = v.module_url.replace("$asset$/", ""); let source_code = match crate::get_asset(&asset) { Some(code) => code.to_string(), @@ -58,14 +58,31 @@ pub fn read_file(_s: &mut TSState, v: Value) -> Result { (asset, source_code) } else { - assert!(!v.file_name.starts_with("$assets$"), "you meant $asset$"); - let module_specifier = ModuleSpecifier::resolve_url_or_path(&v.file_name)?; - let path = module_specifier.as_url().to_file_path().unwrap(); - println!("cargo:rerun-if-changed={}", path.display()); - ( - module_specifier.as_str().to_string(), - std::fs::read_to_string(&path)?, - ) + assert!(!v.module_url.starts_with("$assets$"), "you meant $asset$"); + let module_specifier = ModuleSpecifier::resolve_url_or_path(&v.module_url)?; + let module_url = module_specifier.as_url(); + match module_url.scheme() { + "file" => { + let path = module_url.to_file_path().unwrap(); + println!("cargo:rerun-if-changed={}", path.display()); + ( + module_specifier.as_str().to_string(), + std::fs::read_to_string(&path)?, + ) + } + "crate" => { + let crate_name = module_url.host_str().unwrap(); + // TODO(afinch7) turn failures here into real error messages. + let path_prefix = s.extern_crate_modules.get(crate_name).unwrap(); + let path = + std::path::Path::new(path_prefix).join(&module_url.path()[1..]); + ( + module_specifier.as_str().to_string(), + std::fs::read_to_string(&path)?, + ) + } + _ => unimplemented!(), + } }; Ok(json!({ "moduleName": module_name,