summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2021-11-15 23:25:52 +0000
committerGitHub <noreply@github.com>2021-11-16 10:25:52 +1100
commitcd9193f126c229f3457ada1cf9a05897fdebb77d (patch)
tree070342089d3a40300f49ba254afd43994ac2a377 /cli
parent243d3ba755265dc2cdc5cd0aaffdf9da57d7a931 (diff)
fix(cli): short-circuit in prepare_module_load() (#12604)
Diffstat (limited to 'cli')
-rw-r--r--cli/Cargo.toml4
-rw-r--r--cli/emit.rs148
-rw-r--r--cli/main.rs4
-rw-r--r--cli/module_loader.rs1
-rw-r--r--cli/proc_state.rs366
-rw-r--r--cli/tests/integration/run_tests.rs34
-rw-r--r--cli/tests/testdata/095_cache_with_bare_import.ts.out1
-rw-r--r--cli/tests/testdata/disallow_http_from_https_js.out1
-rw-r--r--cli/tests/testdata/disallow_http_from_https_ts.out1
-rw-r--r--cli/tests/testdata/error_011_bad_module_specifier.ts.out1
-rw-r--r--cli/tests/testdata/error_014_catch_dynamic_import_error.js.out1
-rw-r--r--cli/tests/testdata/error_015_dynamic_import_permissions.out1
-rw-r--r--cli/tests/testdata/error_016_dynamic_import_permissions2.out1
-rw-r--r--cli/tests/testdata/error_local_static_import_from_remote.js.out1
-rw-r--r--cli/tests/testdata/error_local_static_import_from_remote.ts.out1
-rw-r--r--cli/tests/testdata/error_missing_module_named_import.ts.out1
-rw-r--r--cli/tests/testdata/import_blob_url_import_relative.ts.out1
-rw-r--r--cli/tests/testdata/import_data_url_import_relative.ts.out1
-rw-r--r--cli/tests/testdata/localhost_unsafe_ssl.ts.out1
-rw-r--r--cli/tests/testdata/ts_type_only_import.ts.out3
-rw-r--r--cli/tests/testdata/workers/permissions_dynamic_remote.ts.out1
-rw-r--r--cli/tools/coverage.rs1
-rw-r--r--cli/tools/test.rs2
23 files changed, 264 insertions, 313 deletions
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 9f9e1ea26..e7709ecd6 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -41,8 +41,8 @@ winres = "0.1.11"
[dependencies]
deno_ast = { version = "0.5.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
deno_core = { version = "0.107.0", path = "../core" }
-deno_doc = "0.20.0"
-deno_graph = "0.11.1"
+deno_doc = "0.21.0"
+deno_graph = "0.12.0"
deno_lint = { version = "0.19.0", features = ["docs"] }
deno_runtime = { version = "0.33.0", path = "../runtime" }
deno_tls = { version = "0.12.0", path = "../ext/tls" }
diff --git a/cli/emit.rs b/cli/emit.rs
index 9bd005b2a..a189b8202 100644
--- a/cli/emit.rs
+++ b/cli/emit.rs
@@ -17,7 +17,6 @@ use crate::version;
use deno_ast::swc;
use deno_core::error::anyhow;
-use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::error::Context;
use deno_core::serde::Deserialize;
@@ -26,7 +25,6 @@ use deno_core::serde::Serialize;
use deno_core::serde::Serializer;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
-use deno_core::ModuleSource;
use deno_core::ModuleSpecifier;
use deno_graph::MediaType;
use deno_graph::ModuleGraph;
@@ -43,7 +41,7 @@ use std::time::Instant;
/// Represents the "default" type library that should be used when type
/// checking the code in the module graph. Note that a user provided config
/// of `"lib"` would override this value.
-#[derive(Debug, Clone, Eq, PartialEq)]
+#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub(crate) enum TypeLib {
DenoWindow,
DenoWorker,
@@ -76,8 +74,6 @@ impl Serialize for TypeLib {
}
}
-type Modules = HashMap<ModuleSpecifier, Result<ModuleSource, AnyError>>;
-
/// A structure representing stats from an emit operation for a graph.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub(crate) struct Stats(pub Vec<(String, u32)>);
@@ -790,74 +786,9 @@ pub(crate) fn to_file_map(
files
}
-/// Convert a module graph to a map of module sources, which are used by
-/// `deno_core` to load modules into V8.
-pub(crate) fn to_module_sources(
- graph: &ModuleGraph,
- cache: &dyn Cacher,
-) -> Modules {
- graph
- .specifiers()
- .into_iter()
- .map(|(requested_specifier, r)| match r {
- Err(err) => (requested_specifier, Err(err.into())),
- Ok((found_specifier, media_type)) => {
- // First we check to see if there is an emitted file in the cache.
- if let Some(code) = cache.get(CacheType::Emit, &found_specifier) {
- (
- requested_specifier.clone(),
- Ok(ModuleSource {
- code,
- module_url_found: found_specifier.to_string(),
- module_url_specified: requested_specifier.to_string(),
- }),
- )
- // Then if the file is JavaScript (or unknown) and wasn't emitted, we
- // will load the original source code in the module.
- } else if matches!(
- media_type,
- MediaType::JavaScript
- | MediaType::Unknown
- | MediaType::Cjs
- | MediaType::Mjs
- ) {
- if let Some(module) = graph.get(&found_specifier) {
- (
- requested_specifier.clone(),
- Ok(ModuleSource {
- code: module.source.as_str().to_string(),
- module_url_found: module.specifier.to_string(),
- module_url_specified: requested_specifier.to_string(),
- }),
- )
- } else {
- unreachable!(
- "unexpected module missing from graph: {}",
- found_specifier
- )
- }
- // Otherwise we will add a not found error.
- } else {
- (
- requested_specifier.clone(),
- Err(custom_error(
- "NotFound",
- format!(
- "Emitted code for \"{}\" not found.",
- requested_specifier
- ),
- )),
- )
- }
- }
- })
- .collect()
-}
-
#[cfg(test)]
mod tests {
use super::*;
- use crate::cache::MemoryCacher;
#[test]
fn test_is_emittable() {
@@ -873,81 +804,4 @@ mod tests {
assert!(is_emittable(&MediaType::Jsx, false));
assert!(!is_emittable(&MediaType::Json, false));
}
-
- async fn setup<S: AsRef<str>>(
- root: S,
- sources: Vec<(S, S)>,
- ) -> (ModuleGraph, MemoryCacher) {
- let roots = vec![ModuleSpecifier::parse(root.as_ref()).unwrap()];
- let sources = sources
- .into_iter()
- .map(|(s, c)| (s.as_ref().to_string(), Arc::new(c.as_ref().to_string())))
- .collect();
- let mut cache = MemoryCacher::new(sources);
- let graph = deno_graph::create_graph(
- roots, false, None, &mut cache, None, None, None,
- )
- .await;
- (graph, cache)
- }
-
- #[tokio::test]
- async fn test_to_module_sources_emitted() {
- let (graph, mut cache) = setup(
- "https://example.com/a.ts",
- vec![("https://example.com/a.ts", r#"console.log("hello deno");"#)],
- )
- .await;
- let (ts_config, _) = get_ts_config(ConfigType::Emit, None, None).unwrap();
- emit(
- &graph,
- &mut cache,
- EmitOptions {
- ts_config,
- reload_exclusions: HashSet::default(),
- reload: false,
- },
- )
- .unwrap();
- let modules = to_module_sources(&graph, &cache);
- assert_eq!(modules.len(), 1);
- let root = ModuleSpecifier::parse("https://example.com/a.ts").unwrap();
- let maybe_result = modules.get(&root);
- assert!(maybe_result.is_some());
- let result = maybe_result.unwrap();
- assert!(result.is_ok());
- let module_source = result.as_ref().unwrap();
- assert!(module_source
- .code
- .starts_with(r#"console.log("hello deno");"#));
- }
-
- #[tokio::test]
- async fn test_to_module_sources_not_emitted() {
- let (graph, mut cache) = setup(
- "https://example.com/a.js",
- vec![("https://example.com/a.js", r#"console.log("hello deno");"#)],
- )
- .await;
- let (ts_config, _) = get_ts_config(ConfigType::Emit, None, None).unwrap();
- emit(
- &graph,
- &mut cache,
- EmitOptions {
- ts_config,
- reload_exclusions: HashSet::default(),
- reload: false,
- },
- )
- .unwrap();
- let modules = to_module_sources(&graph, &cache);
- assert_eq!(modules.len(), 1);
- let root = ModuleSpecifier::parse("https://example.com/a.js").unwrap();
- let maybe_result = modules.get(&root);
- assert!(maybe_result.is_some());
- let result = maybe_result.unwrap();
- assert!(result.is_ok());
- let module_source = result.as_ref().unwrap();
- assert_eq!(module_source.code, r#"console.log("hello deno");"#);
- }
}
diff --git a/cli/main.rs b/cli/main.rs
index da7848834..5afb34f02 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -582,11 +582,9 @@ async fn cache_command(
lib.clone(),
Permissions::allow_all(),
Permissions::allow_all(),
+ false,
)
.await?;
- if let Some(graph_error) = ps.take_graph_error() {
- return Err(graph_error.into());
- }
}
Ok(())
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index e66e4e4fc..2d37e07a3 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -116,6 +116,7 @@ impl ModuleLoader for CliModuleLoader {
lib,
root_permissions,
dynamic_permissions,
+ false,
)
.await
}
diff --git a/cli/proc_state.rs b/cli/proc_state.rs
index ddfd43034..7a42b6219 100644
--- a/cli/proc_state.rs
+++ b/cli/proc_state.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::cache;
+use crate::cache::Cacher;
use crate::colors;
use crate::compat;
use crate::compat::NodeEsmResolver;
@@ -8,7 +9,7 @@ use crate::config_file::ConfigFile;
use crate::config_file::MaybeImportsResult;
use crate::deno_dir;
use crate::emit;
-use crate::errors::get_module_graph_error_class;
+use crate::errors::get_error_class_name;
use crate::file_fetcher::CacheSetting;
use crate::file_fetcher::FileFetcher;
use crate::flags;
@@ -22,7 +23,6 @@ use crate::version;
use deno_core::error::anyhow;
use deno_core::error::custom_error;
-use deno_core::error::get_custom_error_class;
use deno_core::error::AnyError;
use deno_core::error::Context;
use deno_core::parking_lot::Mutex;
@@ -32,6 +32,11 @@ use deno_core::CompiledWasmModuleStore;
use deno_core::ModuleSource;
use deno_core::ModuleSpecifier;
use deno_core::SharedArrayBufferStore;
+use deno_graph::create_graph;
+use deno_graph::Dependency;
+use deno_graph::MediaType;
+use deno_graph::ModuleGraphError;
+use deno_graph::Range;
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_web::BlobStore;
use deno_runtime::inspector_server::InspectorServer;
@@ -40,8 +45,10 @@ use deno_tls::rustls::RootCertStore;
use deno_tls::rustls_native_certs::load_native_certs;
use deno_tls::webpki_roots::TLS_SERVER_ROOTS;
use import_map::ImportMap;
+use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::HashSet;
+use std::collections::VecDeque;
use std::env;
use std::fs::File;
use std::io::BufReader;
@@ -56,20 +63,79 @@ 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 range 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::Range>,
- // 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>,
+ modules: HashMap<ModuleSpecifier, Result<ModuleSource, ModuleGraphError>>,
+ dependency_map: HashMap<ModuleSpecifier, BTreeMap<String, Dependency>>,
+ /// A set of type libs that each module has passed a type check with this
+ /// session. This would consist of window, worker or both.
+ checked_libs_map: HashMap<ModuleSpecifier, HashSet<emit::TypeLib>>,
+ /// Map of first known referrer locations for each module. Used to enhance
+ /// error messages.
+ referrer_map: HashMap<ModuleSpecifier, Range>,
+}
+
+impl GraphData {
+ /// Check if `roots` are ready to be loaded by V8. Returns `Some(Ok(()))` if
+ /// prepared. Returns `Some(Err(_))` if there is a known module graph error
+ /// statically reachable from `roots`. Returns `None` if sufficient graph data
+ /// is yet to supplied.
+ fn check_if_prepared(
+ &self,
+ roots: &[ModuleSpecifier],
+ ) -> Option<Result<(), AnyError>> {
+ let mut seen = HashSet::<&ModuleSpecifier>::new();
+ let mut visiting = VecDeque::<&ModuleSpecifier>::new();
+ for root in roots {
+ visiting.push_back(root);
+ }
+ while let Some(specifier) = visiting.pop_front() {
+ match self.modules.get(specifier) {
+ Some(Ok(_)) => {
+ let deps = self.dependency_map.get(specifier).unwrap();
+ for (_, dep) in deps.iter().rev() {
+ for resolved in [&dep.maybe_code, &dep.maybe_type] {
+ if !dep.is_dynamic {
+ match resolved {
+ Some(Ok((dep_specifier, _))) => {
+ if !dep.is_dynamic && !seen.contains(dep_specifier) {
+ seen.insert(dep_specifier);
+ visiting.push_front(dep_specifier);
+ }
+ }
+ Some(Err(error)) => {
+ let range = error.range();
+ if !range.specifier.as_str().contains("$deno") {
+ return Some(Err(custom_error(
+ get_error_class_name(&error.clone().into()),
+ format!("{}\n at {}", error.to_string(), range),
+ )));
+ }
+ return Some(Err(error.clone().into()));
+ }
+ None => {}
+ }
+ }
+ }
+ }
+ }
+ Some(Err(error)) => {
+ if !roots.contains(specifier) {
+ if let Some(range) = self.referrer_map.get(specifier) {
+ if !range.specifier.as_str().contains("$deno") {
+ let message = error.to_string();
+ return Some(Err(custom_error(
+ get_error_class_name(&error.clone().into()),
+ format!("{}\n at {}", message, range),
+ )));
+ }
+ }
+ }
+ return Some(Err(error.clone().into()));
+ }
+ None => return None,
+ }
+ }
+ Some(Ok(()))
+ }
}
pub struct Inner {
@@ -252,12 +318,6 @@ 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) -> MaybeImportsResult {
@@ -277,13 +337,10 @@ impl ProcState {
}
}
- /// This method is called when a module requested by the `JsRuntime` is not
- /// available, or in other sub-commands that need to "load" a module graph.
- /// The method will collect all the dependencies of the provided specifier,
- /// optionally checks their integrity, optionally type checks them, and
- /// ensures that any modules that needs to be transpiled is transpiled.
- ///
- /// It then populates the `loadable_modules` with what can be loaded into v8.
+ /// This method must be called for a module or a static importer of that
+ /// module before attempting to `load()` it from a `JsRuntime`. It will
+ /// populate `self.graph_data` in memory with the necessary source code or
+ /// report any module graph / type checking errors.
pub(crate) async fn prepare_module_load(
&self,
roots: Vec<ModuleSpecifier>,
@@ -291,7 +348,32 @@ impl ProcState {
lib: emit::TypeLib,
root_permissions: Permissions,
dynamic_permissions: Permissions,
+ reload_on_watch: bool,
) -> Result<(), AnyError> {
+ // TODO(bartlomieju): this is very make-shift, is there an existing API
+ // that we could include it like with "maybe_imports"?
+ let roots = if self.flags.compat {
+ let mut r = vec![compat::GLOBAL_URL.clone()];
+ r.extend(roots);
+ r
+ } else {
+ roots
+ };
+ if !reload_on_watch {
+ let graph_data = self.graph_data.lock();
+ if self.flags.no_check
+ || roots.iter().all(|root| {
+ graph_data
+ .checked_libs_map
+ .get(root)
+ .map_or(false, |checked_libs| checked_libs.contains(&lib))
+ })
+ {
+ if let Some(result) = graph_data.check_if_prepared(&roots) {
+ return result;
+ }
+ }
+ }
let mut cache = cache::FetchCacher::new(
self.dir.gen_cache.clone(),
self.file_fetcher.clone(),
@@ -324,17 +406,8 @@ impl ProcState {
.as_ref()
.map(|im| im.as_resolver())
};
- // TODO(bartlomieju): this is very make-shift, is there an existing API
- // that we could include it like with "maybe_imports"?
- let roots = if self.flags.compat {
- let mut r = vec![compat::GLOBAL_URL.clone()];
- r.extend(roots);
- r
- } else {
- roots
- };
- let graph = deno_graph::create_graph(
- roots,
+ let graph = create_graph(
+ roots.clone(),
is_dynamic,
maybe_imports,
&mut cache,
@@ -359,7 +432,7 @@ impl ProcState {
} else {
emit::ConfigType::Check {
tsc_emit: true,
- lib,
+ lib: lib.clone(),
}
};
@@ -367,9 +440,7 @@ impl ProcState {
emit::get_ts_config(config_type, self.maybe_config_file.as_ref(), None)?;
let graph = Arc::new(graph);
- // we will store this in proc state later, as if we were to return it from
- // prepare_load, some dynamic errors would not be catchable
- let maybe_graph_error = graph.valid().err();
+ let mut type_check_result = Ok(());
if emit::valid_emit(
graph.as_ref(),
@@ -413,11 +484,11 @@ impl ProcState {
};
for root in &graph.roots {
let root_str = root.to_string();
- // `$deno$` specifiers are internal specifiers, printing out that
+ // `$deno` specifiers are internal specifiers, printing out that
// they are being checked is confusing to a user, since they don't
// actually exist, so we will simply indicate that a generated module
// is being checked instead of the cryptic internal module
- if !root_str.contains("$deno$") {
+ if !root_str.contains("$deno") {
log::info!("{} {}", colors::green("Check"), root);
} else {
log::info!("{} a generated module", colors::green("Check"))
@@ -426,31 +497,93 @@ impl ProcState {
emit::check_and_maybe_emit(graph.clone(), &mut cache, options)?
};
log::debug!("{}", emit_result.stats);
- // if the graph is not valid then the diagnostics returned are bogus and
- // should just be ignored so that module loading can proceed to allow the
- // "real" error to be surfaced
- if !emit_result.diagnostics.is_empty() && maybe_graph_error.is_none() {
- return Err(anyhow!(emit_result.diagnostics));
+ if !emit_result.diagnostics.is_empty() {
+ type_check_result = Err(anyhow!(emit_result.diagnostics));
}
}
{
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;
+ let mut specifiers = graph.specifiers();
+ // Set specifier results for redirects.
+ // TODO(nayeemrmn): This should be done in `ModuleGraph::specifiers()`.
+ for (specifier, found) in &graph.redirects {
+ let actual = specifiers.get(found).unwrap().clone();
+ specifiers.insert(specifier.clone(), actual);
+ }
+ for (specifier, result) in &specifiers {
+ match result {
+ Ok((found_specifier, media_type)) => {
+ let module = graph.get(found_specifier).unwrap();
+ // If there was a type check error, supply dummy code. It shouldn't
+ // be used since preparation will fail.
+ let code = if type_check_result.is_err() {
+ "".to_string()
+ // Check to see if there is an emitted file in the cache.
+ } else if let Some(code) =
+ cache.get(cache::CacheType::Emit, found_specifier)
+ {
+ code
+ // Then if the file is JavaScript (or unknown) and wasn't emitted,
+ // we will load the original source code in the module.
+ } else if matches!(
+ media_type,
+ MediaType::JavaScript
+ | MediaType::Unknown
+ | MediaType::Cjs
+ | MediaType::Mjs
+ ) {
+ module.source.as_str().to_string()
+ // The emit may also be missing when a `.dts` file is in the
+ // graph. There shouldn't be any runtime statements in the source
+ // file and if there was, users would be shown a `TS1036`
+ // diagnostic. So just return an empty emit.
+ } else if media_type == &MediaType::Dts {
+ "".to_string()
+ } else {
+ unreachable!("unexpected missing emit: {}", found_specifier)
+ };
+ graph_data.modules.insert(
+ specifier.clone(),
+ Ok(ModuleSource {
+ code,
+ module_url_found: found_specifier.to_string(),
+ module_url_specified: specifier.to_string(),
+ }),
+ );
+ graph_data
+ .dependency_map
+ .insert(specifier.clone(), module.dependencies.clone());
+ for dep in module.dependencies.values() {
+ #[allow(clippy::manual_flatten)]
+ for resolved in [&dep.maybe_code, &dep.maybe_type] {
+ if let Some(Ok((specifier, referrer_range))) = resolved {
+ let entry = graph_data.referrer_map.entry(specifier.clone());
+ entry.or_insert_with(|| referrer_range.clone());
+ }
+ }
+ }
+ }
+ Err(error) => {
+ graph_data
+ .modules
+ .insert(specifier.clone(), Err(error.clone()));
+ }
+ }
+ }
+
+ graph_data.check_if_prepared(&roots).unwrap()?;
+ type_check_result?;
+
+ if !self.flags.no_check {
+ for specifier in specifiers.keys() {
+ let checked_libs = graph_data
+ .checked_libs_map
+ .entry(specifier.clone())
+ .or_default();
+ checked_libs.insert(lib.clone());
+ }
+ }
}
// any updates to the lockfile should be updated now
@@ -470,18 +603,16 @@ impl ProcState {
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
+ graph_data
+ .dependency_map
.get(&s)
- .and_then(|map| map.get(specifier));
- resolved_specifier.cloned()
+ .and_then(|map| map.get(specifier))
+ .map(|dep| dep.maybe_code.clone())
};
if let Some(resolved) = maybe_resolved {
match resolved {
- Some(Ok((specifier, span))) => {
- let mut graph_data = self.graph_data.lock();
- graph_data.resolved_map.insert(specifier.clone(), span);
+ Some(Ok((specifier, _))) => {
return Ok(specifier);
}
Some(Err(err)) => {
@@ -526,85 +657,20 @@ impl ProcState {
is_dynamic
);
- {
- 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());
- }
- } else {
- if maybe_referrer.is_some() && !is_dynamic {
- if let Some(span) = graph_data.resolved_map.get(&specifier) {
- return Err(custom_error(
- "NotFound",
- format!("Cannot load module \"{}\".\n at {}", specifier, span),
- ));
- }
- }
- 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)
+ let graph_data = self.graph_data.lock();
+ match graph_data.modules.get(&specifier) {
+ Some(Ok(module_source)) => Ok(module_source.clone()),
+ // This is an edge case usually hit when loading source lines for error
+ // stacks with synthetic locations. Users shouldn't see this error.
+ _ => Err(anyhow!(
+ "Loading unprepared module: {}",
+ specifier.to_string()
+ )),
}
}
// TODO(@kitsonk) this should be refactored to get it from the module graph
fn get_emit(&self, url: &Url) -> Option<(Vec<u8>, Option<Vec<u8>>)> {
- match url.scheme() {
- // we should only be looking for emits for schemes that denote external
- // modules, which the disk_cache supports
- "wasm" | "file" | "http" | "https" | "data" | "blob" => (),
- _ => {
- return None;
- }
- }
let emit_path = self
.dir
.gen_cache
@@ -631,6 +697,12 @@ impl ProcState {
impl SourceMapGetter for ProcState {
fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>> {
if let Ok(specifier) = resolve_url(file_name) {
+ match specifier.scheme() {
+ // we should only be looking for emits for schemes that denote external
+ // modules, which the disk_cache supports
+ "wasm" | "file" | "http" | "https" | "data" | "blob" => (),
+ _ => return None,
+ }
if let Some((code, maybe_map)) = self.get_emit(&specifier) {
let code = String::from_utf8(code).unwrap();
source_map_from_code(code).or(maybe_map)
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs
index 214eb8ece..2d96fab8f 100644
--- a/cli/tests/integration/run_tests.rs
+++ b/cli/tests/integration/run_tests.rs
@@ -2271,3 +2271,37 @@ fn issue12453() {
.unwrap();
assert!(status.success());
}
+
+/// Regression test for https://github.com/denoland/deno/issues/12740.
+#[test]
+fn issue12740() {
+ let mod_dir = TempDir::new().expect("tempdir fail");
+ let mod1_path = mod_dir.path().join("mod1.ts");
+ let mod2_path = mod_dir.path().join("mod2.ts");
+ let mut deno_cmd = util::deno_cmd();
+ std::fs::write(&mod1_path, "").unwrap();
+ let status = deno_cmd
+ .current_dir(util::testdata_path())
+ .arg("run")
+ .arg(&mod1_path)
+ .stderr(std::process::Stdio::null())
+ .stdout(std::process::Stdio::null())
+ .spawn()
+ .unwrap()
+ .wait()
+ .unwrap();
+ assert!(status.success());
+ std::fs::write(&mod1_path, "export { foo } from \"./mod2.ts\";").unwrap();
+ std::fs::write(&mod2_path, "(").unwrap();
+ let status = deno_cmd
+ .current_dir(util::testdata_path())
+ .arg("run")
+ .arg(&mod1_path)
+ .stderr(std::process::Stdio::null())
+ .stdout(std::process::Stdio::null())
+ .spawn()
+ .unwrap()
+ .wait()
+ .unwrap();
+ assert!(!status.success());
+}
diff --git a/cli/tests/testdata/095_cache_with_bare_import.ts.out b/cli/tests/testdata/095_cache_with_bare_import.ts.out
index f424f4c3e..ef4820386 100644
--- a/cli/tests/testdata/095_cache_with_bare_import.ts.out
+++ b/cli/tests/testdata/095_cache_with_bare_import.ts.out
@@ -1 +1,2 @@
[WILDCARD]error: Relative import path "foo" not prefixed with / or ./ or ../ from "file:///[WILDCARD]/095_cache_with_bare_import.ts"
+ at file:///[WILDCARD]/095_cache_with_bare_import.ts:[WILDCARD]
diff --git a/cli/tests/testdata/disallow_http_from_https_js.out b/cli/tests/testdata/disallow_http_from_https_js.out
index 428078399..e4f9e8d59 100644
--- a/cli/tests/testdata/disallow_http_from_https_js.out
+++ b/cli/tests/testdata/disallow_http_from_https_js.out
@@ -1,4 +1,3 @@
error: Modules imported via https are not allowed to import http modules.
Importing: http://localhost:4545/001_hello.js
at https://localhost:5545/disallow_http_from_https.js:2:8
-
diff --git a/cli/tests/testdata/disallow_http_from_https_ts.out b/cli/tests/testdata/disallow_http_from_https_ts.out
index bd986cbce..3f885001f 100644
--- a/cli/tests/testdata/disallow_http_from_https_ts.out
+++ b/cli/tests/testdata/disallow_http_from_https_ts.out
@@ -1,4 +1,3 @@
error: Modules imported via https are not allowed to import http modules.
Importing: http://localhost:4545/001_hello.js
at https://localhost:5545/disallow_http_from_https.ts:2:8
-
diff --git a/cli/tests/testdata/error_011_bad_module_specifier.ts.out b/cli/tests/testdata/error_011_bad_module_specifier.ts.out
index 9ee9fd4d1..7d46f6bc8 100644
--- a/cli/tests/testdata/error_011_bad_module_specifier.ts.out
+++ b/cli/tests/testdata/error_011_bad_module_specifier.ts.out
@@ -1,3 +1,2 @@
[WILDCARD]error: Relative import path "bad-module.ts" not prefixed with / or ./ or ../ from "[WILDCARD]/error_011_bad_module_specifier.ts"
at [WILDCARD]/error_011_bad_module_specifier.ts:1:28
-
diff --git a/cli/tests/testdata/error_014_catch_dynamic_import_error.js.out b/cli/tests/testdata/error_014_catch_dynamic_import_error.js.out
index b19d87515..67cf0e0bb 100644
--- a/cli/tests/testdata/error_014_catch_dynamic_import_error.js.out
+++ b/cli/tests/testdata/error_014_catch_dynamic_import_error.js.out
@@ -6,7 +6,6 @@ TypeError: Relative import path "does not exist" not prefixed with / or ./ or ..
Caught indirect direct dynamic import error.
TypeError: Relative import path "does not exist either" not prefixed with / or ./ or ../ from "[WILDCARD]/subdir/indirect_import_error.js"
at [WILDCARD]/subdir/indirect_import_error.js:1:15
-
at async [WILDCARD]/error_014_catch_dynamic_import_error.js:10:5
Caught error thrown by dynamically imported module.
Error: An error
diff --git a/cli/tests/testdata/error_015_dynamic_import_permissions.out b/cli/tests/testdata/error_015_dynamic_import_permissions.out
index 42fb0a15d..ef54f331b 100644
--- a/cli/tests/testdata/error_015_dynamic_import_permissions.out
+++ b/cli/tests/testdata/error_015_dynamic_import_permissions.out
@@ -1,5 +1,4 @@
error: Uncaught (in promise) TypeError: Requires net access to "localhost:4545", run again with the --allow-net flag
- at file://[WILDCARD]/error_015_dynamic_import_permissions.js:2:16
await import("http://localhost:4545/subdir/mod4.js");
^
at async file://[WILDCARD]/error_015_dynamic_import_permissions.js:2:3
diff --git a/cli/tests/testdata/error_016_dynamic_import_permissions2.out b/cli/tests/testdata/error_016_dynamic_import_permissions2.out
index bdfddb9ed..710871f41 100644
--- a/cli/tests/testdata/error_016_dynamic_import_permissions2.out
+++ b/cli/tests/testdata/error_016_dynamic_import_permissions2.out
@@ -2,7 +2,6 @@
error: Uncaught (in promise) TypeError: Remote modules are not allowed to import local modules. Consider using a dynamic import instead.
Importing: file:///c:/etc/passwd
at http://localhost:4545/subdir/evil_remote_import.js:3:15
-
await import("http://localhost:4545/subdir/evil_remote_import.js");
^
at async file://[WILDCARD]/error_016_dynamic_import_permissions2.js:4:3
diff --git a/cli/tests/testdata/error_local_static_import_from_remote.js.out b/cli/tests/testdata/error_local_static_import_from_remote.js.out
index 8904bae29..1ea10bd88 100644
--- a/cli/tests/testdata/error_local_static_import_from_remote.js.out
+++ b/cli/tests/testdata/error_local_static_import_from_remote.js.out
@@ -2,4 +2,3 @@
error: Remote modules are not allowed to import local modules. Consider using a dynamic import instead.
Importing: file:///some/dir/file.js
at http://localhost:4545/error_local_static_import_from_remote.js:1:8
-
diff --git a/cli/tests/testdata/error_local_static_import_from_remote.ts.out b/cli/tests/testdata/error_local_static_import_from_remote.ts.out
index b06a12454..7308c6f9d 100644
--- a/cli/tests/testdata/error_local_static_import_from_remote.ts.out
+++ b/cli/tests/testdata/error_local_static_import_from_remote.ts.out
@@ -2,4 +2,3 @@
error: Remote modules are not allowed to import local modules. Consider using a dynamic import instead.
Importing: file:///some/dir/file.ts
at http://localhost:4545/error_local_static_import_from_remote.ts:1:8
-
diff --git a/cli/tests/testdata/error_missing_module_named_import.ts.out b/cli/tests/testdata/error_missing_module_named_import.ts.out
index c6867130e..d1162ab52 100644
--- a/cli/tests/testdata/error_missing_module_named_import.ts.out
+++ b/cli/tests/testdata/error_missing_module_named_import.ts.out
@@ -1,2 +1,3 @@
[WILDCARD]
error: Cannot load module "file://[WILDCARD]/does_not_exist.js".
+ at file:///[WILDCARD]/error_missing_module_named_import.ts:[WILDCARD]
diff --git a/cli/tests/testdata/import_blob_url_import_relative.ts.out b/cli/tests/testdata/import_blob_url_import_relative.ts.out
index 75e5fe811..59a6f07fb 100644
--- a/cli/tests/testdata/import_blob_url_import_relative.ts.out
+++ b/cli/tests/testdata/import_blob_url_import_relative.ts.out
@@ -1,6 +1,5 @@
error: Uncaught (in promise) TypeError: invalid URL: relative URL with a cannot-be-a-base base
at blob:null/[WILDCARD]:1:19
-
const a = await import(url);
^
at async file://[WILDCARD]/import_blob_url_import_relative.ts:6:11
diff --git a/cli/tests/testdata/import_data_url_import_relative.ts.out b/cli/tests/testdata/import_data_url_import_relative.ts.out
index ed1a37208..821c3e4df 100644
--- a/cli/tests/testdata/import_data_url_import_relative.ts.out
+++ b/cli/tests/testdata/import_data_url_import_relative.ts.out
@@ -1,3 +1,2 @@
error: invalid URL: relative URL with a cannot-be-a-base base
at data:application/javascript;base64,ZXhwb3J0IHsgYSB9IGZyb20gIi4vYS50cyI7Cg==:1:19
-
diff --git a/cli/tests/testdata/localhost_unsafe_ssl.ts.out b/cli/tests/testdata/localhost_unsafe_ssl.ts.out
index e92e5e819..66c199417 100644
--- a/cli/tests/testdata/localhost_unsafe_ssl.ts.out
+++ b/cli/tests/testdata/localhost_unsafe_ssl.ts.out
@@ -1,2 +1,3 @@
DANGER: TLS certificate validation is disabled for: deno.land
error: error sending request for url (https://localhost:5545/subdir/mod2.ts): error trying to connect: invalid certificate: UnknownIssuer
+ at file:///[WILDCARD]/cafile_url_imports.ts:[WILDCARD]
diff --git a/cli/tests/testdata/ts_type_only_import.ts.out b/cli/tests/testdata/ts_type_only_import.ts.out
index 9304a987e..42852cd26 100644
--- a/cli/tests/testdata/ts_type_only_import.ts.out
+++ b/cli/tests/testdata/ts_type_only_import.ts.out
@@ -1,4 +1 @@
Check file://[WILDCARD]/ts_type_only_import.ts
-warning: Cannot load module "file://[WILDCARD]/ts_type_only_import.d.ts".
- at file://[WILDCARD]/ts_type_only_import.ts:1:15
- If the source module contains only types, use `import type` and `export type` to import it instead.
diff --git a/cli/tests/testdata/workers/permissions_dynamic_remote.ts.out b/cli/tests/testdata/workers/permissions_dynamic_remote.ts.out
index 57a922391..e5015abff 100644
--- a/cli/tests/testdata/workers/permissions_dynamic_remote.ts.out
+++ b/cli/tests/testdata/workers/permissions_dynamic_remote.ts.out
@@ -1,5 +1,4 @@
error: Uncaught (in worker "") (in promise) TypeError: Requires net access to "example.com", run again with the --allow-net flag
- at http://localhost:4545/workers/dynamic_remote.ts:2:14
await import("https://example.com/some/file.ts");
^
at async http://localhost:4545/workers/dynamic_remote.ts:2:1
diff --git a/cli/tools/coverage.rs b/cli/tools/coverage.rs
index c34ba22cc..60c87687a 100644
--- a/cli/tools/coverage.rs
+++ b/cli/tools/coverage.rs
@@ -693,6 +693,7 @@ pub async fn cover_files(
emit::TypeLib::UnstableDenoWindow,
Permissions::allow_all(),
Permissions::allow_all(),
+ false,
)
.await?;
diff --git a/cli/tools/test.rs b/cli/tools/test.rs
index 33fb2926d..f2b477bf1 100644
--- a/cli/tools/test.rs
+++ b/cli/tools/test.rs
@@ -732,6 +732,7 @@ async fn check_specifiers(
lib.clone(),
Permissions::allow_all(),
permissions.clone(),
+ false,
)
.await?;
}
@@ -753,6 +754,7 @@ async fn check_specifiers(
lib,
Permissions::allow_all(),
permissions,
+ true,
)
.await?;