diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2021-11-15 23:25:52 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-16 10:25:52 +1100 |
commit | cd9193f126c229f3457ada1cf9a05897fdebb77d (patch) | |
tree | 070342089d3a40300f49ba254afd43994ac2a377 /cli | |
parent | 243d3ba755265dc2cdc5cd0aaffdf9da57d7a931 (diff) |
fix(cli): short-circuit in prepare_module_load() (#12604)
Diffstat (limited to 'cli')
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?; |