diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2021-01-01 08:43:54 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-01 08:43:54 +1100 |
commit | 012f99bd9a0463813653bf8438e09b3247395984 (patch) | |
tree | da00dc71787f564bf1cd8308ebc3fad621fb7771 /cli/module_graph.rs | |
parent | 5f4e1767fea326d507395eafee25ab4ecc4b67b9 (diff) |
refactor(cli): runtime compiler APIs consolidated to Deno.emit() (#8799)
Closes: #4752
Diffstat (limited to 'cli/module_graph.rs')
-rw-r--r-- | cli/module_graph.rs | 223 |
1 files changed, 151 insertions, 72 deletions
diff --git a/cli/module_graph.rs b/cli/module_graph.rs index c8bd3d1f3..d1e51bd4c 100644 --- a/cli/module_graph.rs +++ b/cli/module_graph.rs @@ -497,18 +497,27 @@ impl Module { } #[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct Stats(pub Vec<(String, u128)>); +pub struct Stats(pub Vec<(String, u32)>); impl<'de> Deserialize<'de> for Stats { fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> where D: Deserializer<'de>, { - let items: Vec<(String, u128)> = Deserialize::deserialize(deserializer)?; + let items: Vec<(String, u32)> = Deserialize::deserialize(deserializer)?; Ok(Stats(items)) } } +impl Serialize for Stats { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + Serialize::serialize(&self.0, serializer) + } +} + impl fmt::Display for Stats { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "Compilation statistics:")?; @@ -620,6 +629,10 @@ impl Default for BundleType { #[derive(Debug, Default)] pub struct EmitOptions { + /// If true, then code will be type checked, otherwise type checking will be + /// skipped. If false, then swc will be used for the emit, otherwise tsc will + /// be used. + pub check: bool, /// Indicate the form the result of the emit should take. pub bundle_type: BundleType, /// If `true` then debug logging will be output from the isolate. @@ -769,8 +782,8 @@ impl Graph { let s = self.emit_bundle(&root_specifier, &ts_config.into())?; let stats = Stats(vec![ - ("Files".to_string(), self.modules.len() as u128), - ("Total time".to_string(), start.elapsed().as_millis()), + ("Files".to_string(), self.modules.len() as u32), + ("Total time".to_string(), start.elapsed().as_millis() as u32), ]); Ok((s, stats, maybe_ignored_options)) @@ -918,18 +931,22 @@ impl Graph { /// emitting single modules as well as bundles, using Deno module resolution /// or supplied sources. pub fn emit( - self, + mut self, options: EmitOptions, ) -> Result<(HashMap<String, String>, ResultInfo), AnyError> { let mut config = TsConfig::new(json!({ "allowJs": true, + "checkJs": false, // TODO(@kitsonk) consider enabling this by default // see: https://github.com/denoland/deno/issues/7732 "emitDecoratorMetadata": false, "esModuleInterop": true, "experimentalDecorators": true, + "inlineSourceMap": false, "isolatedModules": true, "jsx": "react", + "jsxFactory": "React.createElement", + "jsxFragmentFactory": "React.Fragment", "lib": TypeLib::DenoWindow, "module": "esnext", "strict": true, @@ -937,11 +954,7 @@ impl Graph { })); let opts = match options.bundle_type { BundleType::Esm => json!({ - "checkJs": false, - "inlineSourceMap": false, "noEmit": true, - "jsxFactory": "React.createElement", - "jsxFragmentFactory": "React.Fragment", }), BundleType::None => json!({ "outDir": "deno://", @@ -957,74 +970,138 @@ impl Graph { None }; - let root_names = self.get_root_names(!config.get_check_js()); - let hash_data = - vec![config.as_bytes(), version::deno().as_bytes().to_owned()]; - let graph = Arc::new(Mutex::new(self)); - - let response = tsc::exec( - js::compiler_isolate_init(), - tsc::Request { - config: config.clone(), - debug: options.debug, - graph: graph.clone(), - hash_data, - maybe_tsbuildinfo: None, - root_names, - }, - )?; + if !options.check && config.get_declaration() { + return Err(anyhow!("The option of `check` is false, but the compiler option of `declaration` is true which is not currently supported.")); + } + if options.bundle_type != BundleType::None && config.get_declaration() { + return Err(anyhow!("The bundle option is set, but the compiler option of `declaration` is true which is not currently supported.")); + } let mut emitted_files = HashMap::new(); - let graph = graph.lock().unwrap(); - match options.bundle_type { - BundleType::Esm => { - assert!( - response.emitted_files.is_empty(), - "No files should have been emitted from tsc." - ); - assert_eq!( - graph.roots.len(), - 1, - "Only a single root module supported." - ); - let specifier = &graph.roots[0]; - let s = graph.emit_bundle(specifier, &config.into())?; - emitted_files.insert("deno:///bundle.js".to_string(), s); - } - BundleType::None => { - for emitted_file in &response.emitted_files { + if options.check { + let root_names = self.get_root_names(!config.get_check_js()); + let hash_data = + vec![config.as_bytes(), version::deno().as_bytes().to_owned()]; + let graph = Arc::new(Mutex::new(self)); + let response = tsc::exec( + js::compiler_isolate_init(), + tsc::Request { + config: config.clone(), + debug: options.debug, + graph: graph.clone(), + hash_data, + maybe_tsbuildinfo: None, + root_names, + }, + )?; + + let graph = graph.lock().unwrap(); + match options.bundle_type { + BundleType::Esm => { assert!( - emitted_file.maybe_specifiers.is_some(), - "Orphaned file emitted." + response.emitted_files.is_empty(), + "No files should have been emitted from tsc." ); - let specifiers = emitted_file.maybe_specifiers.clone().unwrap(); assert_eq!( - specifiers.len(), + graph.roots.len(), 1, - "An unexpected number of specifiers associated with emitted file." + "Only a single root module supported." ); - let specifier = specifiers[0].clone(); - let extension = match emitted_file.media_type { - MediaType::JavaScript => ".js", - MediaType::SourceMap => ".js.map", - MediaType::Dts => ".d.ts", - _ => unreachable!(), - }; - let key = format!("{}{}", specifier, extension); - emitted_files.insert(key, emitted_file.data.clone()); + let specifier = &graph.roots[0]; + let s = graph.emit_bundle(specifier, &config.into())?; + emitted_files.insert("deno:///bundle.js".to_string(), s); + } + BundleType::None => { + for emitted_file in &response.emitted_files { + assert!( + emitted_file.maybe_specifiers.is_some(), + "Orphaned file emitted." + ); + let specifiers = emitted_file.maybe_specifiers.clone().unwrap(); + assert_eq!( + specifiers.len(), + 1, + "An unexpected number of specifiers associated with emitted file." + ); + let specifier = specifiers[0].clone(); + let extension = match emitted_file.media_type { + MediaType::JavaScript => ".js", + MediaType::SourceMap => ".js.map", + MediaType::Dts => ".d.ts", + _ => unreachable!(), + }; + let key = format!("{}{}", specifier, extension); + emitted_files.insert(key, emitted_file.data.clone()); + } + } + }; + + Ok(( + emitted_files, + ResultInfo { + diagnostics: response.diagnostics, + loadable_modules: graph.get_loadable_modules(), + maybe_ignored_options, + stats: response.stats, + }, + )) + } else { + let start = Instant::now(); + let mut emit_count = 0_u32; + match options.bundle_type { + BundleType::Esm => { + assert_eq!( + self.roots.len(), + 1, + "Only a single root module supported." + ); + let specifier = &self.roots[0]; + let s = self.emit_bundle(specifier, &config.into())?; + emit_count += 1; + emitted_files.insert("deno:///bundle.js".to_string(), s); + } + BundleType::None => { + let emit_options: ast::EmitOptions = config.into(); + for (_, module_slot) in self.modules.iter_mut() { + if let ModuleSlot::Module(module) = module_slot { + if !(emit_options.check_js + || module.media_type == MediaType::JSX + || module.media_type == MediaType::TSX + || module.media_type == MediaType::TypeScript) + { + emitted_files + .insert(module.specifier.to_string(), module.source.clone()); + } + let parsed_module = module.parse()?; + let (code, maybe_map) = parsed_module.transpile(&emit_options)?; + emit_count += 1; + emitted_files.insert(format!("{}.js", module.specifier), code); + if let Some(map) = maybe_map { + emitted_files + .insert(format!("{}.js.map", module.specifier), map); + } + } + } + self.flush()?; } } - }; - Ok(( - emitted_files, - ResultInfo { - diagnostics: response.diagnostics, - loadable_modules: graph.get_loadable_modules(), - maybe_ignored_options, - stats: response.stats, - }, - )) + let stats = Stats(vec![ + ("Files".to_string(), self.modules.len() as u32), + ("Emitted".to_string(), emit_count), + ("Total time".to_string(), start.elapsed().as_millis() as u32), + ]); + + Ok(( + emitted_files, + ResultInfo { + diagnostics: Default::default(), + loadable_modules: self.get_loadable_modules(), + maybe_ignored_options, + stats, + }, + )) + } } /// Shared between `bundle()` and `emit()`. @@ -1566,10 +1643,9 @@ impl Graph { let maybe_ignored_options = ts_config.merge_tsconfig(options.maybe_config_path)?; - let emit_options: ast::EmitOptions = ts_config.clone().into(); - - let mut emit_count: u128 = 0; let config = ts_config.as_bytes(); + let emit_options: ast::EmitOptions = ts_config.into(); + let mut emit_count = 0_u32; for (_, module_slot) in self.modules.iter_mut() { if let ModuleSlot::Module(module) = module_slot { // TODO(kitsonk) a lot of this logic should be refactored into `Module` as @@ -1604,9 +1680,9 @@ impl Graph { self.flush()?; let stats = Stats(vec![ - ("Files".to_string(), self.modules.len() as u128), + ("Files".to_string(), self.modules.len() as u32), ("Emitted".to_string(), emit_count), - ("Total time".to_string(), start.elapsed().as_millis()), + ("Total time".to_string(), start.elapsed().as_millis() as u32), ]); Ok(ResultInfo { @@ -2270,6 +2346,7 @@ pub mod tests { .await; let (emitted_files, result_info) = graph .emit(EmitOptions { + check: true, bundle_type: BundleType::None, debug: false, maybe_user_config: None, @@ -2310,6 +2387,7 @@ pub mod tests { .await; let (emitted_files, result_info) = graph .emit(EmitOptions { + check: true, bundle_type: BundleType::Esm, debug: false, maybe_user_config: None, @@ -2347,6 +2425,7 @@ pub mod tests { user_config.insert("declaration".to_string(), json!(true)); let (emitted_files, result_info) = graph .emit(EmitOptions { + check: true, bundle_type: BundleType::None, debug: false, maybe_user_config: Some(user_config), |