fix(cli): short-circuit in prepare_module_load() (#12604)

This commit is contained in:
Nayeem Rahman 2021-11-15 23:25:52 +00:00 committed by GitHub
parent 243d3ba755
commit cd9193f126
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 266 additions and 315 deletions

8
Cargo.lock generated
View file

@ -782,9 +782,9 @@ dependencies = [
[[package]]
name = "deno_doc"
version = "0.20.0"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2d76b6b75a6fbfda0f529e310fc3cab960f4219403280b430ce93dcf8cf9a2"
checksum = "075b0c1b454eaf90cea9c6efc72ff946aa6c855c85a4209cb717c01424b37e5e"
dependencies = [
"cfg-if 1.0.0",
"deno_ast",
@ -827,9 +827,9 @@ dependencies = [
[[package]]
name = "deno_graph"
version = "0.11.1"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6d84ddee0cf83bf295721be792b6769b92214983bda29d52c2b05a89d1e968f"
checksum = "9ee63197c67746c40911cb3082ca13a29cc5adae1ff1b706397b44f7155d7c57"
dependencies = [
"anyhow",
"cfg-if 1.0.0",

View file

@ -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" }

View file

@ -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");"#);
}
}

View file

@ -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(())

View file

@ -116,6 +116,7 @@ impl ModuleLoader for CliModuleLoader {
lib,
root_permissions,
dynamic_permissions,
false,
)
.await
}

View file

@ -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));
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()));
}
}
}
// 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.check_if_prepared(&roots).unwrap()?;
type_check_result?;
graph_data.maybe_graph_error = maybe_graph_error;
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)

View file

@ -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());
}

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -1,3 +1,2 @@
error: invalid URL: relative URL with a cannot-be-a-base base
at data:application/javascript;base64,ZXhwb3J0IHsgYSB9IGZyb20gIi4vYS50cyI7Cg==:1:19

View file

@ -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]

View file

@ -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.

View file

@ -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

View file

@ -693,6 +693,7 @@ pub async fn cover_files(
emit::TypeLib::UnstableDenoWindow,
Permissions::allow_all(),
Permissions::allow_all(),
false,
)
.await?;

View file

@ -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?;