summaryrefslogtreecommitdiff
path: root/cli/graph_util.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-12-01 15:12:10 -0500
committerGitHub <noreply@github.com>2023-12-01 20:12:10 +0000
commita1d823e27d1b605b5658fddc1c9273667f0e9e84 (patch)
tree213f35fb40b5c70832b1d9473947b3de48d4ec9e /cli/graph_util.rs
parentd8e8497eb3049f58632e4d7507090ef9915b3af6 (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.rs88
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;