diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2023-12-01 15:12:10 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-01 20:12:10 +0000 |
commit | a1d823e27d1b605b5658fddc1c9273667f0e9e84 (patch) | |
tree | 213f35fb40b5c70832b1d9473947b3de48d4ec9e /cli/graph_util.rs | |
parent | d8e8497eb3049f58632e4d7507090ef9915b3af6 (diff) |
feat(compile): support discovering modules for more dynamic arguments (#21381)
This PR causes Deno to include more files in the graph based on how a
template literal looks that's provided to a dynamic import:
```ts
const file = await import(`./dir/${expr}`);
```
In this case, it will search the `dir` directory and descendant
directories for any .js/jsx/etc modules and include them in the graph.
To opt out of this behaviour, move the template literal to a separate
line:
```ts
const specifier = `./dir/${expr}`
const file = await import(specifier);
```
Diffstat (limited to 'cli/graph_util.rs')
-rw-r--r-- | cli/graph_util.rs | 88 |
1 files changed, 82 insertions, 6 deletions
diff --git a/cli/graph_util.rs b/cli/graph_util.rs index 727037748..445f269e3 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -35,6 +35,7 @@ use deno_graph::ModuleGraph; use deno_graph::ModuleGraphError; use deno_graph::ResolutionError; use deno_graph::SpecifierError; +use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node; use deno_runtime::permissions::PermissionsContainer; use deno_semver::package::PackageNv; @@ -116,12 +117,8 @@ pub fn graph_valid( if let Some(range) = error.maybe_range() { if !is_root && !range.specifier.as_str().contains("/$deno$eval") { - message.push_str(&format!( - "\n at {}:{}:{}", - colors::cyan(range.specifier.as_str()), - colors::yellow(&(range.start.line + 1).to_string()), - colors::yellow(&(range.start.character + 1).to_string()) - )); + message.push_str("\n at "); + message.push_str(&format_range_with_colors(range)); } } @@ -194,6 +191,7 @@ pub struct CreateGraphOptions<'a> { pub struct ModuleGraphBuilder { options: Arc<CliOptions>, + fs: Arc<dyn FileSystem>, resolver: Arc<CliGraphResolver>, npm_resolver: Arc<dyn CliNpmResolver>, module_info_cache: Arc<ModuleInfoCache>, @@ -210,6 +208,7 @@ impl ModuleGraphBuilder { #[allow(clippy::too_many_arguments)] pub fn new( options: Arc<CliOptions>, + fs: Arc<dyn FileSystem>, resolver: Arc<CliGraphResolver>, npm_resolver: Arc<dyn CliNpmResolver>, module_info_cache: Arc<ModuleInfoCache>, @@ -223,6 +222,7 @@ impl ModuleGraphBuilder { ) -> Self { Self { options, + fs, resolver, npm_resolver, module_info_cache, @@ -295,6 +295,7 @@ impl ModuleGraphBuilder { is_dynamic: false, imports: maybe_imports, resolver: Some(graph_resolver), + file_system: Some(&DenoGraphFsAdapter(self.fs.as_ref())), npm_resolver: Some(graph_npm_resolver), module_analyzer: Some(options.analyzer), reporter: maybe_file_watcher_reporter, @@ -344,6 +345,7 @@ impl ModuleGraphBuilder { deno_graph::BuildOptions { is_dynamic: false, imports: maybe_imports, + file_system: Some(&DenoGraphFsAdapter(self.fs.as_ref())), resolver: Some(graph_resolver), npm_resolver: Some(graph_npm_resolver), module_analyzer: Some(&analyzer), @@ -770,6 +772,80 @@ fn workspace_member_config_try_into_workspace_member( }) } +pub struct DenoGraphFsAdapter<'a>( + pub &'a dyn deno_runtime::deno_fs::FileSystem, +); + +impl<'a> deno_graph::source::FileSystem for DenoGraphFsAdapter<'a> { + fn read_dir( + &self, + dir_url: &deno_graph::ModuleSpecifier, + ) -> Vec<deno_graph::source::DirEntry> { + use deno_core::anyhow; + use deno_graph::source::DirEntry; + use deno_graph::source::DirEntryKind; + + let dir_path = match dir_url.to_file_path() { + Ok(path) => path, + // ignore, treat as non-analyzable + Err(()) => return vec![], + }; + let entries = match self.0.read_dir_sync(&dir_path) { + Ok(dir) => dir, + Err(err) + if matches!( + err.kind(), + std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::NotFound + ) => + { + return vec![]; + } + Err(err) => { + return vec![DirEntry { + kind: DirEntryKind::Error( + anyhow::Error::from(err) + .context("Failed to read directory.".to_string()), + ), + url: dir_url.clone(), + }]; + } + }; + let mut dir_entries = Vec::with_capacity(entries.len()); + for entry in entries { + let entry_path = dir_path.join(&entry.name); + dir_entries.push(if entry.is_directory { + DirEntry { + kind: DirEntryKind::Dir, + url: ModuleSpecifier::from_directory_path(&entry_path).unwrap(), + } + } else if entry.is_file { + DirEntry { + kind: DirEntryKind::File, + url: ModuleSpecifier::from_file_path(&entry_path).unwrap(), + } + } else if entry.is_symlink { + DirEntry { + kind: DirEntryKind::Symlink, + url: ModuleSpecifier::from_file_path(&entry_path).unwrap(), + } + } else { + continue; + }); + } + + dir_entries + } +} + +pub fn format_range_with_colors(range: &deno_graph::Range) -> String { + format!( + "{}:{}:{}", + colors::cyan(range.specifier.as_str()), + colors::yellow(&(range.start.line + 1).to_string()), + colors::yellow(&(range.start.character + 1).to_string()) + ) +} + #[cfg(test)] mod test { use std::sync::Arc; |