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/ops/runtime_compiler.rs | |
parent | 5f4e1767fea326d507395eafee25ab4ecc4b67b9 (diff) |
refactor(cli): runtime compiler APIs consolidated to Deno.emit() (#8799)
Closes: #4752
Diffstat (limited to 'cli/ops/runtime_compiler.rs')
-rw-r--r-- | cli/ops/runtime_compiler.rs | 153 |
1 files changed, 55 insertions, 98 deletions
diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index bb3e47226..774b280ba 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -1,8 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::ast; -use crate::colors; -use crate::media_type::MediaType; +use crate::import_map::ImportMap; use crate::module_graph::BundleType; use crate::module_graph::EmitOptions; use crate::module_graph::GraphBuilder; @@ -10,11 +8,10 @@ use crate::program_state::ProgramState; use crate::specifier_handler::FetchHandler; use crate::specifier_handler::MemoryHandler; use crate::specifier_handler::SpecifierHandler; -use crate::tsc_config; +use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::error::Context; -use deno_core::serde::Serialize; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; @@ -30,37 +27,46 @@ use std::sync::Arc; use std::sync::Mutex; pub fn init(rt: &mut deno_core::JsRuntime) { - super::reg_json_async(rt, "op_compile", op_compile); - super::reg_json_async(rt, "op_transpile", op_transpile); + super::reg_json_async(rt, "op_emit", op_emit); } -#[derive(Deserialize, Debug)] +#[derive(Debug, Deserialize)] +enum RuntimeBundleType { + #[serde(rename = "esm")] + Esm, +} + +#[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -struct CompileArgs { - root_name: String, +struct EmitArgs { + bundle: Option<RuntimeBundleType>, + check: Option<bool>, + compiler_options: Option<HashMap<String, Value>>, + import_map: Option<Value>, + import_map_path: Option<String>, + root_specifier: String, sources: Option<HashMap<String, String>>, - bundle: bool, - options: Option<String>, } -async fn op_compile( +async fn op_emit( state: Rc<RefCell<OpState>>, args: Value, _data: BufVec, ) -> Result<Value, AnyError> { - let args: CompileArgs = serde_json::from_value(args)?; - if args.bundle { - deno_runtime::ops::check_unstable2(&state, "Deno.bundle"); - } else { - deno_runtime::ops::check_unstable2(&state, "Deno.compile"); - } + deno_runtime::ops::check_unstable2(&state, "Deno.emit"); + let args: EmitArgs = serde_json::from_value(args)?; let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone(); let runtime_permissions = { let state = state.borrow(); state.borrow::<Permissions>().clone() }; + // when we are actually resolving modules without provided sources, we should + // treat the root module as a dynamic import so that runtime permissions are + // applied. + let mut is_dynamic = false; let handler: Arc<Mutex<dyn SpecifierHandler>> = if let Some(sources) = args.sources { + is_dynamic = true; Arc::new(Mutex::new(MemoryHandler::new(sources))) } else { Arc::new(Mutex::new(FetchHandler::new( @@ -68,93 +74,44 @@ async fn op_compile( runtime_permissions, )?)) }; - let mut builder = GraphBuilder::new(handler, None, None); - let specifier = ModuleSpecifier::resolve_url_or_path(&args.root_name) - .context("The root specifier is invalid.")?; - builder.add(&specifier, false).await?; - let graph = builder.get_graph(); - let bundle_type = if args.bundle { - BundleType::Esm + let maybe_import_map = if let Some(import_map_str) = args.import_map_path { + let import_map_specifier = + ModuleSpecifier::resolve_url_or_path(&import_map_str).context( + format!("Bad file path (\"{}\") for import map.", import_map_str), + )?; + let import_map_url = import_map_specifier.as_url(); + let import_map = if let Some(value) = args.import_map { + ImportMap::from_json(&import_map_url.to_string(), &value.to_string())? + } else { + ImportMap::load(&import_map_str)? + }; + Some(import_map) + } else if args.import_map.is_some() { + return Err(generic_error("An importMap was specified, but no importMapPath was provided, which is required.")); } else { - BundleType::None + None + }; + let mut builder = GraphBuilder::new(handler, maybe_import_map, None); + let root_specifier = + ModuleSpecifier::resolve_url_or_path(&args.root_specifier)?; + builder.add(&root_specifier, is_dynamic).await?; + let bundle_type = match args.bundle { + Some(RuntimeBundleType::Esm) => BundleType::Esm, + _ => BundleType::None, }; + let graph = builder.get_graph(); let debug = program_state.flags.log_level == Some(log::Level::Debug); - let maybe_user_config: Option<HashMap<String, Value>> = - if let Some(options) = args.options { - Some(serde_json::from_str(&options)?) - } else { - None - }; - let (emitted_files, result_info) = graph.emit(EmitOptions { + let (files, result_info) = graph.emit(EmitOptions { bundle_type, + check: args.check.unwrap_or(true), debug, - maybe_user_config, + maybe_user_config: args.compiler_options, })?; Ok(json!({ - "emittedFiles": emitted_files, "diagnostics": result_info.diagnostics, + "files": files, + "ignoredOptions": result_info.maybe_ignored_options, + "stats": result_info.stats, })) } - -#[derive(Deserialize, Debug)] -struct TranspileArgs { - sources: HashMap<String, String>, - options: Option<String>, -} - -#[derive(Debug, Serialize)] -struct RuntimeTranspileEmit { - source: String, - map: Option<String>, -} - -async fn op_transpile( - state: Rc<RefCell<OpState>>, - args: Value, - _data: BufVec, -) -> Result<Value, AnyError> { - deno_runtime::ops::check_unstable2(&state, "Deno.transpileOnly"); - let args: TranspileArgs = serde_json::from_value(args)?; - - let mut compiler_options = tsc_config::TsConfig::new(json!({ - "checkJs": true, - "emitDecoratorMetadata": false, - "jsx": "react", - "jsxFactory": "React.createElement", - "jsxFragmentFactory": "React.Fragment", - "inlineSourceMap": false, - })); - - let user_options: HashMap<String, Value> = if let Some(options) = args.options - { - serde_json::from_str(&options)? - } else { - HashMap::new() - }; - let maybe_ignored_options = - compiler_options.merge_user_config(&user_options)?; - // TODO(@kitsonk) these really should just be passed back to the caller - if let Some(ignored_options) = maybe_ignored_options { - info!("{}: {}", colors::yellow("warning"), ignored_options); - } - - let emit_options: ast::EmitOptions = compiler_options.into(); - let mut emit_map = HashMap::new(); - - for (specifier, source) in args.sources { - let media_type = MediaType::from(&specifier); - let parsed_module = ast::parse(&specifier, &source, &media_type)?; - let (source, maybe_source_map) = parsed_module.transpile(&emit_options)?; - - emit_map.insert( - specifier.to_string(), - RuntimeTranspileEmit { - source, - map: maybe_source_map, - }, - ); - } - let result = serde_json::to_value(emit_map)?; - Ok(result) -} |