1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-26 16:09:27 -05:00
denoland-deno/cli/ops/runtime_compiler.rs

130 lines
4.1 KiB
Rust

// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::import_map::ImportMap;
use crate::module_graph::BundleType;
use crate::module_graph::EmitOptions;
use crate::module_graph::GraphBuilder;
use crate::program_state::ProgramState;
use crate::specifier_handler::FetchHandler;
use crate::specifier_handler::MemoryHandler;
use crate::specifier_handler::SpecifierHandler;
use deno_core::error::generic_error;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::error::Context;
use deno_core::resolve_url_or_path;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use deno_runtime::permissions::Permissions;
use serde::Deserialize;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::Mutex;
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_async(rt, "op_emit", op_emit);
}
#[derive(Debug, Deserialize)]
enum RuntimeBundleType {
#[serde(rename = "module")]
Module,
#[serde(rename = "classic")]
Classic,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
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>>,
}
async fn op_emit(
state: Rc<RefCell<OpState>>,
args: Value,
_data: Option<ZeroCopyBuf>,
) -> Result<Value, AnyError> {
deno_runtime::ops::check_unstable2(&state, "Deno.emit");
let args: EmitArgs = serde_json::from_value(args)?;
let root_specifier = args.root_specifier;
let program_state = state.borrow().borrow::<Arc<ProgramState>>().clone();
let mut 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 {
Arc::new(Mutex::new(MemoryHandler::new(sources)))
} else {
is_dynamic = true;
Arc::new(Mutex::new(FetchHandler::new(
&program_state,
runtime_permissions.clone(),
)?))
};
let maybe_import_map = if let Some(import_map_str) = args.import_map_path {
let import_map_specifier = resolve_url_or_path(&import_map_str)
.context(format!("Bad URL (\"{}\") for import map.", import_map_str))?;
let import_map = if let Some(value) = args.import_map {
ImportMap::from_json(import_map_specifier.as_str(), &value.to_string())?
} else {
let file = program_state
.file_fetcher
.fetch(&import_map_specifier, &mut runtime_permissions)
.await?;
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?
};
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 {
None
};
let mut builder = GraphBuilder::new(handler, maybe_import_map, None);
let root_specifier = resolve_url_or_path(&root_specifier)?;
builder
.add(&root_specifier, is_dynamic)
.await
.map_err(|_| {
type_error(format!(
"Unable to handle the given specifier: {}",
&root_specifier
))
})?;
let bundle_type = match args.bundle {
Some(RuntimeBundleType::Module) => BundleType::Module,
Some(RuntimeBundleType::Classic) => BundleType::Classic,
None => BundleType::None,
};
let graph = builder.get_graph();
let debug = program_state.flags.log_level == Some(log::Level::Debug);
let (files, result_info) = graph.emit(EmitOptions {
bundle_type,
check: args.check.unwrap_or(true),
debug,
maybe_user_config: args.compiler_options,
})?;
Ok(json!({
"diagnostics": result_info.diagnostics,
"files": files,
"ignoredOptions": result_info.maybe_ignored_options,
"stats": result_info.stats,
}))
}