summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/main.rs2
-rw-r--r--cli/proc_state.rs222
2 files changed, 124 insertions, 100 deletions
diff --git a/cli/main.rs b/cli/main.rs
index 9dd7a354e..d36145bea 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -548,7 +548,7 @@ async fn cache_command(
Permissions::allow_all(),
)
.await?;
- if let Some(graph_error) = ps.maybe_graph_error.lock().take() {
+ if let Some(graph_error) = ps.take_graph_error() {
return Err(graph_error.into());
}
}
diff --git a/cli/proc_state.rs b/cli/proc_state.rs
index 461599fc4..a633e3f9d 100644
--- a/cli/proc_state.rs
+++ b/cli/proc_state.rs
@@ -52,31 +52,35 @@ use std::sync::Arc;
#[derive(Clone)]
pub struct ProcState(Arc<Inner>);
+#[derive(Default)]
+struct GraphData {
+ modules: HashMap<ModuleSpecifier, Result<ModuleSource, AnyError>>,
+ // because the graph detects resolution issues early, but is build and dropped
+ // during the `prepare_module_load` method, we need to extract out the module
+ // resolution map so that those errors can be surfaced at the appropriate time
+ resolution_map:
+ HashMap<ModuleSpecifier, HashMap<String, deno_graph::Resolved>>,
+ // in some cases we want to provide the span where the resolution error
+ // occurred but need to surface it on load, but on load we don't know who the
+ // referrer and span was, so we need to cache those
+ resolved_map: HashMap<ModuleSpecifier, deno_graph::Span>,
+ // deno_graph detects all sorts of issues at build time (prepare_module_load)
+ // but if they are errors at that stage, the don't cause the correct behaviors
+ // so we cache the error and then surface it when appropriate (e.g. load)
+ maybe_graph_error: Option<deno_graph::ModuleGraphError>,
+}
+
pub struct Inner {
/// Flags parsed from `argv` contents.
pub flags: flags::Flags,
pub dir: deno_dir::DenoDir,
pub coverage_dir: Option<String>,
pub file_fetcher: FileFetcher,
- modules: Arc<Mutex<HashMap<ModuleSpecifier, Result<ModuleSource, AnyError>>>>,
+ graph_data: Arc<Mutex<GraphData>>,
pub lockfile: Option<Arc<Mutex<Lockfile>>>,
pub maybe_config_file: Option<ConfigFile>,
pub maybe_import_map: Option<ImportMap>,
pub maybe_inspector_server: Option<Arc<InspectorServer>>,
- // deno_graph detects all sorts of issues at build time (prepare_module_load)
- // but if they are errors at that stage, the don't cause the correct behaviors
- // so we cache the error and then surface it when appropriate (e.g. load)
- pub(crate) maybe_graph_error:
- Arc<Mutex<Option<deno_graph::ModuleGraphError>>>,
- // because the graph detects resolution issues early, but is build and dropped
- // during the `prepare_module_load` method, we need to extract out the module
- // resolution map so that those errors can be surfaced at the appropriate time
- resolution_map:
- Arc<Mutex<HashMap<ModuleSpecifier, HashMap<String, deno_graph::Resolved>>>>,
- // in some cases we want to provide the span where the resolution error
- // occurred but need to surface it on load, but on load we don't know who the
- // referrer and span was, so we need to cache those
- resolved_map: Arc<Mutex<HashMap<ModuleSpecifier, deno_graph::Span>>>,
pub root_cert_store: Option<RootCertStore>,
pub blob_store: BlobStore,
pub broadcast_channel: InMemoryBroadcastChannel,
@@ -233,14 +237,11 @@ impl ProcState {
coverage_dir,
flags,
file_fetcher,
- modules: Default::default(),
+ graph_data: Default::default(),
lockfile,
maybe_config_file,
maybe_import_map,
maybe_inspector_server,
- maybe_graph_error: Default::default(),
- resolution_map: Default::default(),
- resolved_map: Default::default(),
root_cert_store: Some(root_cert_store.clone()),
blob_store,
broadcast_channel,
@@ -249,6 +250,12 @@ impl ProcState {
})))
}
+ pub(crate) fn take_graph_error(
+ &self,
+ ) -> Option<deno_graph::ModuleGraphError> {
+ self.graph_data.lock().maybe_graph_error.take()
+ }
+
/// Return any imports that should be brought into the scope of the module
/// graph.
fn get_maybe_imports(&self) -> Option<Vec<(ModuleSpecifier, Vec<String>)>> {
@@ -325,8 +332,8 @@ impl ProcState {
// Determine any modules that have already been emitted this session and
// should be skipped.
let reload_exclusions: HashSet<ModuleSpecifier> = {
- let modules = self.modules.lock();
- modules.keys().cloned().collect()
+ let graph_data = self.graph_data.lock();
+ graph_data.modules.keys().cloned().collect()
};
let config_type = if self.flags.no_check {
@@ -409,26 +416,23 @@ impl ProcState {
}
}
- // we iterate over the graph, looking for any modules that were emitted, or
- // should be loaded as their un-emitted source and add them to the in memory
- // cache of modules for loading by deno_core.
- {
- let mut modules = self.modules.lock();
- modules.extend(emit::to_module_sources(graph.as_ref(), &cache));
- }
-
- // since we can't store the graph in proc state, because proc state needs to
- // be thread safe because of the need to provide source map resolution and
- // the graph needs to not be thread safe (due to wasmbind_gen constraints),
- // we have no choice but to extract out other meta data from the graph to
- // provide the correct loading behaviors for CLI
{
- let mut resolution_map = self.resolution_map.lock();
- resolution_map.extend(graph.resolution_map());
- }
- {
- let mut self_maybe_graph_error = self.maybe_graph_error.lock();
- *self_maybe_graph_error = maybe_graph_error;
+ let mut graph_data = self.graph_data.lock();
+ // we iterate over the graph, looking for any modules that were emitted, or
+ // should be loaded as their un-emitted source and add them to the in memory
+ // cache of modules for loading by deno_core.
+ graph_data
+ .modules
+ .extend(emit::to_module_sources(graph.as_ref(), &cache));
+
+ // since we can't store the graph in proc state, because proc state needs to
+ // be thread safe because of the need to provide source map resolution and
+ // the graph needs to not be thread safe (due to wasmbind_gen constraints),
+ // we have no choice but to extract out other meta data from the graph to
+ // provide the correct loading behaviors for CLI
+ graph_data.resolution_map.extend(graph.resolution_map());
+
+ graph_data.maybe_graph_error = maybe_graph_error;
}
// any updates to the lockfile should be updated now
@@ -445,17 +449,22 @@ impl ProcState {
specifier: &str,
referrer: &str,
) -> Result<ModuleSpecifier, AnyError> {
- let resolution_map = self.resolution_map.lock();
- if let Some((_, Some(map))) = deno_core::resolve_url_or_path(referrer)
- .ok()
- .map(|s| (s.clone(), resolution_map.get(&s)))
- {
- if let Some(resolved) = map.get(specifier) {
+ if let Ok(s) = deno_core::resolve_url_or_path(referrer) {
+ let maybe_resolved = {
+ let graph_data = self.graph_data.lock();
+ let resolved_specifier = graph_data
+ .resolution_map
+ .get(&s)
+ .and_then(|map| map.get(specifier));
+ resolved_specifier.cloned()
+ };
+
+ if let Some(resolved) = maybe_resolved {
match resolved {
Some(Ok((specifier, span))) => {
- let mut resolved_map = self.resolved_map.lock();
- resolved_map.insert(specifier.clone(), span.clone());
- return Ok(specifier.clone());
+ let mut graph_data = self.graph_data.lock();
+ graph_data.resolved_map.insert(specifier.clone(), span);
+ return Ok(specifier);
}
Some(Err(err)) => {
return Err(custom_error(
@@ -467,6 +476,7 @@ impl ProcState {
}
}
}
+
// FIXME(bartlomieju): hacky way to provide compatibility with repl
let referrer = if referrer.is_empty() && self.flags.repl {
deno_core::DUMMY_SPECIFIER
@@ -497,60 +507,74 @@ impl ProcState {
.unwrap_or_else(|| "<none>".to_string()),
is_dynamic
);
- let modules = self.modules.lock();
- modules
- .get(&specifier)
- .map(|r| match r {
- Ok(module_source) => Ok(module_source.clone()),
- Err(err) => {
- // this is the "pending" error we will return
- let err = if let Some(error_class) = get_custom_error_class(err) {
- if error_class == "NotFound" && maybe_referrer.is_some() && !is_dynamic {
- let resolved_map = self.resolved_map.lock();
- // in situations where we were to try to load a module that wasn't
- // emitted and we can't run the original source code (it isn't)
- // JavaScript, we will load a blank module instead. This is
- // usually caused by people exporting type only exports and not
- // type checking.
- if let Some(span) = resolved_map.get(&specifier) {
- log::warn!("{}: Cannot load module \"{}\".\n at {}\n If the source module contains only types, use `import type` and `export type` to import it instead.", colors::yellow("warning"), specifier, span);
- return Ok(ModuleSource {
- code: "".to_string(),
- module_url_found: specifier.to_string(),
- module_url_specified: specifier.to_string(),
- });
- }
- }
- custom_error(error_class, err.to_string())
- } else {
- anyhow!(err.to_string())
- };
- // if there is a pending graph error though we haven't returned, we
- // will return that one
- let mut maybe_graph_error = self.maybe_graph_error.lock();
- if let Some(graph_error) = maybe_graph_error.take() {
- log::debug!("returning cached graph error");
- let resolved_map = self.resolved_map.lock();
- if let Some(span) = resolved_map.get(&specifier) {
- if !span.specifier.as_str().contains("$deno") {
- return Err(custom_error(get_module_graph_error_class(&graph_error), format!("{}\n at {}", graph_error, span)));
- }
- }
- Err(graph_error.into())
- } else {
- Err(err)
- }
+
+ {
+ let graph_data = self.graph_data.lock();
+ if let Some(module_result) = graph_data.modules.get(&specifier) {
+ if let Ok(module_source) = module_result {
+ return Ok(module_source.clone());
}
- })
- .unwrap_or_else(|| {
+ } else {
if maybe_referrer.is_some() && !is_dynamic {
- let resolved_map = self.resolved_map.lock();
- if let Some(span) = resolved_map.get(&specifier) {
- return Err(custom_error("NotFound", format!("Cannot load module \"{}\".\n at {}", specifier, span)));
+ if let Some(span) = graph_data.resolved_map.get(&specifier) {
+ return Err(custom_error(
+ "NotFound",
+ format!("Cannot load module \"{}\".\n at {}", specifier, span),
+ ));
}
}
- Err(custom_error("NotFound", format!("Cannot load module \"{}\".", specifier)))
- })
+ return Err(custom_error(
+ "NotFound",
+ format!("Cannot load module \"{}\".", specifier),
+ ));
+ }
+ }
+
+ // If we're this far it means that there was an error for this module load.
+ let mut graph_data = self.graph_data.lock();
+ let err = graph_data
+ .modules
+ .get(&specifier)
+ .unwrap()
+ .as_ref()
+ .unwrap_err();
+ // this is the "pending" error we will return
+ let err = if let Some(error_class) = get_custom_error_class(err) {
+ if error_class == "NotFound" && maybe_referrer.is_some() && !is_dynamic {
+ // in situations where we were to try to load a module that wasn't
+ // emitted and we can't run the original source code (it isn't)
+ // JavaScript, we will load a blank module instead. This is
+ // usually caused by people exporting type only exports and not
+ // type checking.
+ if let Some(span) = graph_data.resolved_map.get(&specifier) {
+ log::warn!("{}: Cannot load module \"{}\".\n at {}\n If the source module contains only types, use `import type` and `export type` to import it instead.", colors::yellow("warning"), specifier, span);
+ return Ok(ModuleSource {
+ code: "".to_string(),
+ module_url_found: specifier.to_string(),
+ module_url_specified: specifier.to_string(),
+ });
+ }
+ }
+ custom_error(error_class, err.to_string())
+ } else {
+ anyhow!(err.to_string())
+ };
+ // if there is a pending graph error though we haven't returned, we
+ // will return that one
+ if let Some(graph_error) = graph_data.maybe_graph_error.take() {
+ log::debug!("returning cached graph error");
+ if let Some(span) = graph_data.resolved_map.get(&specifier) {
+ if !span.specifier.as_str().contains("$deno") {
+ return Err(custom_error(
+ get_module_graph_error_class(&graph_error),
+ format!("{}\n at {}", graph_error, span),
+ ));
+ }
+ }
+ Err(graph_error.into())
+ } else {
+ Err(err)
+ }
}
// TODO(@kitsonk) this should be refactored to get it from the module graph