summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/global_state.rs4
-rw-r--r--cli/info.rs471
-rw-r--r--cli/main.rs159
-rw-r--r--cli/module_graph.rs8
-rw-r--r--cli/tests/022_info_flag_script.out21
-rw-r--r--cli/tests/031_info_no_check.out5
-rw-r--r--cli/tests/049_info_flag_script_jsx.out21
-rw-r--r--cli/tests/054_info_local_imports.out11
-rw-r--r--cli/tests/055_info_file_json.out43
-rw-r--r--cli/tests/cafile_info.ts.out21
-rw-r--r--cli/tests/info_recursive_imports_test.out11
-rw-r--r--cli/tests/info_recursive_imports_test.ts5
-rw-r--r--cli/tests/info_type_import.out8
-rw-r--r--cli/tests/integration_tests.rs38
-rw-r--r--cli/tests/recursive_imports/A.ts7
-rw-r--r--cli/tests/recursive_imports/B.ts7
-rw-r--r--cli/tests/recursive_imports/C.ts8
-rw-r--r--cli/tests/recursive_imports/common.ts2
-rw-r--r--cli/tsc.rs8
-rw-r--r--core/lib.rs1
-rw-r--r--core/modules.rs156
-rw-r--r--docs/tools/dependency_inspector.md107
22 files changed, 692 insertions, 430 deletions
diff --git a/cli/global_state.rs b/cli/global_state.rs
index 6add7b7b4..2dfec4a72 100644
--- a/cli/global_state.rs
+++ b/cli/global_state.rs
@@ -160,11 +160,11 @@ impl GlobalState {
if should_compile {
if self.flags.no_check {
- self.ts_compiler.transpile(module_graph).await?;
+ self.ts_compiler.transpile(&module_graph).await?;
} else {
self
.ts_compiler
- .compile(self, &out, target_lib, permissions, module_graph, allow_js)
+ .compile(self, &out, target_lib, permissions, &module_graph, allow_js)
.await?;
}
}
diff --git a/cli/info.rs b/cli/info.rs
new file mode 100644
index 000000000..c876c57d5
--- /dev/null
+++ b/cli/info.rs
@@ -0,0 +1,471 @@
+use crate::colors;
+use crate::global_state::GlobalState;
+use crate::module_graph::{ModuleGraph, ModuleGraphFile, ModuleGraphLoader};
+use crate::msg;
+use crate::ModuleSpecifier;
+use crate::Permissions;
+use deno_core::ErrBox;
+use serde::Serialize;
+use std::collections::{HashMap, HashSet};
+use std::sync::Arc;
+
+// TODO(bartlomieju): rename
+/// Struct containing a module's dependency information.
+#[derive(Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ModuleDepInfo {
+ local: String,
+ file_type: String,
+ compiled: Option<String>,
+ map: Option<String>,
+ dep_count: usize,
+ deps: FileInfoDepTree,
+}
+
+impl ModuleDepInfo {
+ /// Creates a new `ModuleDepInfo` struct for the module with the provided `ModuleSpecifier`.
+ pub async fn new(
+ global_state: &Arc<GlobalState>,
+ module_specifier: ModuleSpecifier,
+ ) -> Result<ModuleDepInfo, ErrBox> {
+ // First load module as if it was to be executed by worker
+ // including compilation step
+ let mut module_graph_loader = ModuleGraphLoader::new(
+ global_state.file_fetcher.clone(),
+ global_state.maybe_import_map.clone(),
+ Permissions::allow_all(),
+ false,
+ true,
+ );
+ module_graph_loader
+ .add_to_graph(&module_specifier, None)
+ .await?;
+ let module_graph = module_graph_loader.get_graph();
+
+ let ts_compiler = &global_state.ts_compiler;
+ let file_fetcher = &global_state.file_fetcher;
+ let out = file_fetcher
+ .fetch_cached_source_file(&module_specifier, Permissions::allow_all())
+ .expect("Source file should already be cached");
+ let local_filename = out.filename.to_string_lossy().to_string();
+ let compiled_filename = ts_compiler
+ .get_compiled_source_file(&out.url)
+ .ok()
+ .map(|file| file.filename.to_string_lossy().to_string());
+ let map_filename = ts_compiler
+ .get_source_map_file(&module_specifier)
+ .ok()
+ .map(|file| file.filename.to_string_lossy().to_string());
+ let file_type = msg::enum_name_media_type(out.media_type).to_string();
+
+ let deps = FileInfoDepTree::new(&module_graph, &module_specifier);
+ let dep_count = get_unique_dep_count(&module_graph) - 1;
+
+ let info = Self {
+ local: local_filename,
+ file_type,
+ compiled: compiled_filename,
+ map: map_filename,
+ dep_count,
+ deps,
+ };
+
+ Ok(info)
+ }
+}
+
+/// Counts the number of dependencies in the graph.
+///
+/// We are counting only the dependencies that are not http redirects to other files.
+fn get_unique_dep_count(graph: &ModuleGraph) -> usize {
+ graph.iter().fold(
+ 0,
+ |acc, e| {
+ if e.1.redirect.is_none() {
+ acc + 1
+ } else {
+ acc
+ }
+ },
+ )
+}
+
+impl std::fmt::Display for ModuleDepInfo {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("{} {}\n", colors::bold("local:"), self.local))?;
+ f.write_fmt(format_args!(
+ "{} {}\n",
+ colors::bold("type:"),
+ self.file_type
+ ))?;
+ if let Some(ref compiled) = self.compiled {
+ f.write_fmt(format_args!(
+ "{} {}\n",
+ colors::bold("compiled:"),
+ compiled
+ ))?;
+ }
+ if let Some(ref map) = self.map {
+ f.write_fmt(format_args!("{} {}\n", colors::bold("map:"), map))?;
+ }
+
+ f.write_fmt(format_args!(
+ "{} {} unique {}\n",
+ colors::bold("deps:"),
+ self.dep_count,
+ colors::gray(&format!(
+ "(total {})",
+ human_size(self.deps.total_size.unwrap_or(0) as f64),
+ ))
+ ))?;
+ f.write_fmt(format_args!(
+ "{} {}\n",
+ self.deps.name,
+ colors::gray(&format!("({})", human_size(self.deps.size as f64)))
+ ))?;
+
+ for (idx, dep) in self.deps.deps.iter().enumerate() {
+ print_file_dep_info(&dep, "", idx == self.deps.deps.len() - 1, f)?;
+ }
+
+ Ok(())
+ }
+}
+
+/// A dependency tree of the basic module information.
+///
+/// Constructed from a `ModuleGraph` and `ModuleSpecifier` that
+/// acts as the root of the tree.
+#[derive(Serialize)]
+#[serde(rename_all = "camelCase")]
+struct FileInfoDepTree {
+ name: String,
+ size: usize,
+ total_size: Option<usize>,
+ deps: Vec<FileInfoDepTree>,
+}
+
+impl FileInfoDepTree {
+ /// Create a `FileInfoDepTree` tree from a `ModuleGraph` and the root `ModuleSpecifier`.
+ pub fn new(
+ module_graph: &ModuleGraph,
+ root_specifier: &ModuleSpecifier,
+ ) -> Self {
+ let mut seen = HashSet::new();
+ let mut total_sizes = HashMap::new();
+
+ Self::visit_module(
+ &mut seen,
+ &mut total_sizes,
+ module_graph,
+ root_specifier,
+ )
+ }
+
+ /// Visit modules recursively.
+ ///
+ /// If currently visited module has not yet been seen it will be annotated with dependencies
+ /// and cumulative size of those deps.
+ fn visit_module(
+ seen: &mut HashSet<String>,
+ total_sizes: &mut HashMap<String, usize>,
+ graph: &ModuleGraph,
+ specifier: &ModuleSpecifier,
+ ) -> Self {
+ let name = specifier.to_string();
+ let never_seen = seen.insert(name.clone());
+ let file = get_resolved_file(&graph, &specifier);
+ let size = file.size();
+ let mut deps = vec![];
+ let mut total_size = None;
+
+ if never_seen {
+ let mut seen_deps = HashSet::new();
+ deps = file
+ .imports
+ .iter()
+ .map(|import| &import.resolved_specifier)
+ .filter(|module_specifier| {
+ seen_deps.insert(module_specifier.as_str().to_string())
+ })
+ .map(|specifier| {
+ Self::visit_module(seen, total_sizes, graph, specifier)
+ })
+ .collect::<Vec<_>>();
+
+ total_size = if let Some(total_size) = total_sizes.get(&name) {
+ Some(total_size.to_owned())
+ } else {
+ let total: usize = deps
+ .iter()
+ .map(|dep| {
+ if let Some(total_size) = dep.total_size {
+ total_size
+ } else {
+ 0
+ }
+ })
+ .sum();
+ let total = size + total;
+
+ total_sizes.insert(name.clone(), total);
+
+ Some(total)
+ };
+ }
+
+ Self {
+ name,
+ size,
+ total_size,
+ deps,
+ }
+ }
+}
+
+/// Returns a `ModuleGraphFile` associated to the provided `ModuleSpecifier`.
+///
+/// If the `specifier` is associated with a file that has a populated redirect field,
+/// it returns the file associated to the redirect, otherwise the file associated to `specifier`.
+fn get_resolved_file<'a>(
+ graph: &'a ModuleGraph,
+ specifier: &ModuleSpecifier,
+) -> &'a ModuleGraphFile {
+ // Note(kc): This code is dependent on how we are injecting a dummy ModuleGraphFile
+ // into the graph with a "redirect" property.
+ let result = graph.get(specifier.as_str()).unwrap();
+
+ if let Some(ref import) = result.redirect {
+ graph.get(import).unwrap()
+ } else {
+ result
+ }
+}
+
+/// Prints the `FileInfoDepTree` tree to stdout.
+fn print_file_dep_info(
+ info: &FileInfoDepTree,
+ prefix: &str,
+ is_last: bool,
+ formatter: &mut std::fmt::Formatter<'_>,
+) -> std::fmt::Result {
+ print_dep(prefix, is_last, info, formatter)?;
+
+ let prefix = &get_new_prefix(prefix, is_last);
+ let child_count = info.deps.len();
+ for (idx, dep) in info.deps.iter().enumerate() {
+ print_file_dep_info(dep, prefix, idx == child_count - 1, formatter)?;
+ }
+
+ Ok(())
+}
+
+/// Prints a single `FileInfoDepTree` to stdout.
+fn print_dep(
+ prefix: &str,
+ is_last: bool,
+ info: &FileInfoDepTree,
+ formatter: &mut std::fmt::Formatter<'_>,
+) -> std::fmt::Result {
+ let has_children = !info.deps.is_empty();
+
+ formatter.write_fmt(format_args!(
+ "{} {}{}\n",
+ colors::gray(&format!(
+ "{}{}─{}",
+ prefix,
+ get_sibling_connector(is_last),
+ get_child_connector(has_children),
+ ))
+ .to_string(),
+ info.name,
+ get_formatted_totals(info)
+ ))
+}
+
+/// Gets the formatted totals for the provided `FileInfoDepTree`.
+///
+/// If the total size is reported as 0 then an empty string is returned.
+fn get_formatted_totals(info: &FileInfoDepTree) -> String {
+ if let Some(_total_size) = info.total_size {
+ colors::gray(&format!(" ({})", human_size(info.size as f64),)).to_string()
+ } else {
+ // This dependency has already been displayed somewhere else in the tree.
+ colors::gray(" *").to_string()
+ }
+}
+
+/// Gets the sibling portion of the tree branch.
+fn get_sibling_connector(is_last: bool) -> char {
+ if is_last {
+ '└'
+ } else {
+ '├'
+ }
+}
+
+/// Gets the child connector for the branch.
+fn get_child_connector(has_children: bool) -> char {
+ if has_children {
+ '┬'
+ } else {
+ '─'
+ }
+}
+
+/// Creates a new prefix for a dependency tree item.
+fn get_new_prefix(prefix: &str, is_last: bool) -> String {
+ let mut prefix = prefix.to_string();
+ if is_last {
+ prefix.push(' ');
+ } else {
+ prefix.push('│');
+ }
+
+ prefix.push(' ');
+ prefix
+}
+
+pub fn human_size(bytse: f64) -> String {
+ let negative = if bytse.is_sign_positive() { "" } else { "-" };
+ let bytse = bytse.abs();
+ let units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
+ if bytse < 1_f64 {
+ return format!("{}{}{}", negative, bytse, "B");
+ }
+ let delimiter = 1024_f64;
+ let exponent = std::cmp::min(
+ (bytse.ln() / delimiter.ln()).floor() as i32,
+ (units.len() - 1) as i32,
+ );
+ let pretty_bytes = format!("{:.2}", bytse / delimiter.powi(exponent))
+ .parse::<f64>()
+ .unwrap()
+ * 1_f64;
+ let unit = units[exponent as usize];
+ format!("{}{}{}", negative, pretty_bytes, unit)
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::module_graph::ImportDescriptor;
+ use crate::swc_util::Location;
+ use crate::MediaType;
+
+ #[test]
+ fn human_size_test() {
+ assert_eq!(human_size(16_f64), "16B");
+ assert_eq!(human_size((16 * 1024) as f64), "16KB");
+ assert_eq!(human_size((16 * 1024 * 1024) as f64), "16MB");
+ assert_eq!(human_size(16_f64 * 1024_f64.powf(3.0)), "16GB");
+ assert_eq!(human_size(16_f64 * 1024_f64.powf(4.0)), "16TB");
+ assert_eq!(human_size(16_f64 * 1024_f64.powf(5.0)), "16PB");
+ assert_eq!(human_size(16_f64 * 1024_f64.powf(6.0)), "16EB");
+ assert_eq!(human_size(16_f64 * 1024_f64.powf(7.0)), "16ZB");
+ assert_eq!(human_size(16_f64 * 1024_f64.powf(8.0)), "16YB");
+ }
+
+ #[test]
+ fn get_new_prefix_adds_spaces_if_is_last() {
+ let prefix = get_new_prefix("", true);
+
+ assert_eq!(prefix, " ".to_string());
+ }
+
+ #[test]
+ fn get_new_prefix_adds_a_vertial_bar_if_not_is_last() {
+ let prefix = get_new_prefix("", false);
+
+ assert_eq!(prefix, "│ ".to_string());
+ }
+
+ fn create_mock_file(
+ name: &str,
+ imports: Vec<ModuleSpecifier>,
+ redirect: Option<ModuleSpecifier>,
+ ) -> (ModuleGraphFile, ModuleSpecifier) {
+ let spec = ModuleSpecifier::from(
+ url::Url::parse(&format!("http://{}", name)).unwrap(),
+ );
+ let file = ModuleGraphFile {
+ filename: "name".to_string(),
+ imports: imports
+ .iter()
+ .map(|import| ImportDescriptor {
+ specifier: import.to_string(),
+ resolved_specifier: import.clone(),
+ resolved_type_directive: None,
+ type_directive: None,
+ location: Location {
+ col: 0,
+ filename: "".to_string(),
+ line: 0,
+ },
+ })
+ .collect(),
+ lib_directives: vec![],
+ media_type: MediaType::TypeScript,
+ redirect: redirect.map(|x| x.to_string()),
+ referenced_files: vec![],
+ source_code: "".to_string(),
+ specifier: spec.to_string(),
+ type_headers: vec![],
+ types_directives: vec![],
+ version_hash: "".to_string(),
+ url: "".to_string(),
+ };
+
+ (file, spec)
+ }
+
+ #[test]
+ fn get_resolved_file_test() {
+ let (test_file_redirect, redirect) =
+ create_mock_file("test_redirect", vec![], None);
+ let (test_file, original) =
+ create_mock_file("test", vec![], Some(redirect.clone()));
+
+ let mut graph = ModuleGraph::new();
+ graph.insert(original.to_string(), test_file);
+ graph.insert(redirect.to_string(), test_file_redirect);
+
+ let file = get_resolved_file(&graph, &original);
+
+ assert_eq!(file.specifier, redirect.to_string());
+ }
+
+ #[test]
+ fn dependency_count_no_redirects() {
+ let (a, aspec) = create_mock_file("a", vec![], None);
+ let (b, bspec) = create_mock_file("b", vec![aspec.clone()], None);
+ let (c, cspec) = create_mock_file("c", vec![bspec.clone()], None);
+
+ let mut graph = ModuleGraph::new();
+
+ graph.insert(aspec.to_string(), a);
+ graph.insert(bspec.to_string(), b);
+ graph.insert(cspec.to_string(), c);
+
+ let count = get_unique_dep_count(&graph);
+
+ assert_eq!(graph.len(), count);
+ }
+
+ #[test]
+ fn dependency_count_with_redirects() {
+ let (a, aspec) = create_mock_file("a", vec![], None);
+ let (b, bspec) = create_mock_file("b", vec![], Some(aspec.clone()));
+ let (c, cspec) = create_mock_file("c", vec![bspec.clone()], None);
+
+ let mut graph = ModuleGraph::new();
+
+ graph.insert(aspec.to_string(), a);
+ graph.insert(bspec.to_string(), b);
+ graph.insert(cspec.to_string(), c);
+
+ let count = get_unique_dep_count(&graph);
+
+ assert_eq!(graph.len() - 1, count);
+ }
+}
diff --git a/cli/main.rs b/cli/main.rs
index 11b12f3fa..d5329eeb4 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -40,6 +40,7 @@ mod global_timer;
pub mod http_cache;
mod http_util;
mod import_map;
+mod info;
mod inspector;
pub mod installer;
mod js;
@@ -76,12 +77,9 @@ use crate::fs as deno_fs;
use crate::global_state::GlobalState;
use crate::msg::MediaType;
use crate::permissions::Permissions;
-use crate::tsc::TargetLib;
use crate::worker::MainWorker;
use deno_core::v8_set_flags;
-use deno_core::Deps;
use deno_core::ErrBox;
-use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_doc as doc;
use deno_doc::parser::DocFileLoader;
@@ -151,114 +149,6 @@ fn print_cache_info(
}
}
-struct FileInfoOutput<'a> {
- local: &'a str,
- file_type: &'a str,
- compiled: Option<String>,
- map: Option<String>,
- deps: Option<Deps>,
-}
-
-// TODO(bartlomieju): this function de facto repeats
-// whole compilation stack. Can this be done better somehow?
-async fn print_file_info(
- worker: &MainWorker,
- module_specifier: ModuleSpecifier,
- json: bool,
-) -> Result<(), ErrBox> {
- let global_state = worker.state.global_state.clone();
-
- let out = global_state
- .file_fetcher
- .fetch_source_file(&module_specifier, None, Permissions::allow_all())
- .await?;
-
- let mut output = FileInfoOutput {
- local: out.filename.to_str().unwrap(),
- file_type: msg::enum_name_media_type(out.media_type),
- compiled: None,
- map: None,
- deps: None,
- };
-
- let module_specifier_ = module_specifier.clone();
-
- global_state
- .prepare_module_load(
- module_specifier_.clone(),
- None,
- TargetLib::Main,
- Permissions::allow_all(),
- false,
- global_state.maybe_import_map.clone(),
- )
- .await?;
- global_state
- .clone()
- .fetch_compiled_module(module_specifier_, None)
- .await?;
-
- if out.media_type == msg::MediaType::TypeScript
- || (out.media_type == msg::MediaType::JavaScript
- && global_state.ts_compiler.compile_js)
- {
- let compiled_source_file = global_state
- .ts_compiler
- .get_compiled_source_file(&out.url)
- .unwrap();
- output.compiled =
- compiled_source_file.filename.to_str().map(|s| s.to_owned());
- }
-
- if let Ok(source_map) = global_state
- .clone()
- .ts_compiler
- .get_source_map_file(&module_specifier)
- {
- output.map = source_map.filename.to_str().map(|s| s.to_owned());
- }
- let es_state_rc = JsRuntime::state(&worker.isolate);
- let es_state = es_state_rc.borrow();
-
- if let Some(deps) = es_state.modules.deps(&module_specifier) {
- output.deps = Some(deps);
- }
-
- if json {
- let output = json!({
- "local": output.local,
- "fileType": output.file_type,
- "compiled": output.compiled,
- "map": output.map,
- "deps": output.deps.map(|x| x.to_json())
- });
- write_json_to_stdout(&output)
- } else {
- println!("{} {}", colors::bold("local:"), output.local);
- println!("{} {}", colors::bold("type:"), output.file_type);
- if let Some(compiled) = output.compiled {
- println!("{} {}", colors::bold("compiled:"), compiled);
- }
- if let Some(map) = output.map {
- println!("{} {}", colors::bold("map:"), map);
- }
- if let Some(deps) = output.deps {
- println!("{}{}", colors::bold("deps:\n"), deps.name);
- if let Some(ref depsdeps) = deps.deps {
- for d in depsdeps {
- println!("{}", d);
- }
- }
- } else {
- println!(
- "{} cannot retrieve full dependency graph",
- colors::bold("deps:"),
- );
- }
- Ok(())
- }
-}
-
fn get_types(unstable: bool) -> String {
let mut types = format!(
"{}\n{}\n{}\n{}",
@@ -289,9 +179,15 @@ async fn info_command(
print_cache_info(&global_state, json)
} else {
let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
- let mut worker = MainWorker::create(&global_state, main_module.clone())?;
- worker.preload_module(&main_module).await?;
- print_file_info(&worker, main_module.clone(), json).await
+ let info =
+ info::ModuleDepInfo::new(&global_state, main_module.clone()).await?;
+
+ if json {
+ write_json_to_stdout(&json!(info))
+ } else {
+ print!("{}", info);
+ Ok(())
+ }
}
}
@@ -414,7 +310,7 @@ async fn bundle_command(
"{} {:?} ({})",
colors::green("Emit"),
out_file_,
- colors::gray(&human_size(output_len as f64))
+ colors::gray(&info::human_size(output_len as f64))
);
} else {
println!("{}", output);
@@ -422,39 +318,6 @@ async fn bundle_command(
Ok(())
}
-fn human_size(bytse: f64) -> String {
- let negative = if bytse.is_sign_positive() { "" } else { "-" };
- let bytse = bytse.abs();
- let units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
- if bytse < 1_f64 {
- return format!("{}{} {}", negative, bytse, "Bytes");
- }
- let delimiter = 1024_f64;
- let exponent = std::cmp::min(
- (bytse.ln() / delimiter.ln()).floor() as i32,
- (units.len() - 1) as i32,
- );
- let pretty_bytes = format!("{:.2}", bytse / delimiter.powi(exponent))
- .parse::<f64>()
- .unwrap()
- * 1_f64;
- let unit = units[exponent as usize];
- format!("{}{} {}", negative, pretty_bytes, unit)
-}
-
-#[test]
-fn human_size_test() {
- assert_eq!(human_size(16_f64), "16 Bytes");
- assert_eq!(human_size((16 * 1024) as f64), "16 KB");
- assert_eq!(human_size((16 * 1024 * 1024) as f64), "16 MB");
- assert_eq!(human_size(16_f64 * 1024_f64.powf(3.0)), "16 GB");
- assert_eq!(human_size(16_f64 * 1024_f64.powf(4.0)), "16 TB");
- assert_eq!(human_size(16_f64 * 1024_f64.powf(5.0)), "16 PB");
- assert_eq!(human_size(16_f64 * 1024_f64.powf(6.0)), "16 EB");
- assert_eq!(human_size(16_f64 * 1024_f64.powf(7.0)), "16 ZB");
- assert_eq!(human_size(16_f64 * 1024_f64.powf(8.0)), "16 YB");
-}
-
async fn doc_command(
flags: Flags,
source_file: Option<String>,
diff --git a/cli/module_graph.rs b/cli/module_graph.rs
index 331f45241..40147c44c 100644
--- a/cli/module_graph.rs
+++ b/cli/module_graph.rs
@@ -197,7 +197,7 @@ const SUPPORTED_MEDIA_TYPES: [MediaType; 4] = [
pub type ModuleGraph = HashMap<String, ModuleGraphFile>;
-#[derive(Debug, Serialize)]
+#[derive(Clone, Debug, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ImportDescriptor {
pub specifier: String,
@@ -241,6 +241,12 @@ pub struct ModuleGraphFile {
pub source_code: String,
}
+impl ModuleGraphFile {
+ pub fn size(&self) -> usize {
+ self.source_code.as_bytes().len()
+ }
+}
+
type SourceFileFuture =
Pin<Box<dyn Future<Output = Result<(ModuleSpecifier, SourceFile), ErrBox>>>>;
diff --git a/cli/tests/022_info_flag_script.out b/cli/tests/022_info_flag_script.out
index d17f31d77..e84c253e9 100644
--- a/cli/tests/022_info_flag_script.out
+++ b/cli/tests/022_info_flag_script.out
@@ -1,14 +1,13 @@
[WILDCARD]
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
type: TypeScript
-compiled: [WILDCARD].js
-deps:
-http://127.0.0.1:4545/cli/tests/019_media_types.ts
- ├── http://localhost:4545/cli/tests/subdir/mt_text_typescript.t1.ts
- ├── http://localhost:4545/cli/tests/subdir/mt_video_vdn.t2.ts
- ├── http://localhost:4545/cli/tests/subdir/mt_video_mp2t.t3.ts
- ├── http://localhost:4545/cli/tests/subdir/mt_application_x_typescript.t4.ts
- ├── http://localhost:4545/cli/tests/subdir/mt_text_javascript.j1.js
- ├── http://localhost:4545/cli/tests/subdir/mt_application_ecmascript.j2.js
- ├── http://localhost:4545/cli/tests/subdir/mt_text_ecmascript.j3.js
- └── http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js
+deps: 8 unique (total [WILDCARD])
+http://127.0.0.1:4545/cli/tests/019_media_types.ts ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_text_typescript.t1.ts ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_video_vdn.t2.ts ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_video_mp2t.t3.ts ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_application_x_typescript.t4.ts ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_text_javascript.j1.js ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_application_ecmascript.j2.js ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_text_ecmascript.j3.js ([WILDCARD])
+└── http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js ([WILDCARD])
diff --git a/cli/tests/031_info_no_check.out b/cli/tests/031_info_no_check.out
index 5b67e3f2f..601490055 100644
--- a/cli/tests/031_info_no_check.out
+++ b/cli/tests/031_info_no_check.out
@@ -1,6 +1,5 @@
[WILDCARD]
local: [WILDCARD]031_info_no_check.ts
type: TypeScript
-compiled: [WILDCARD].js
-deps:
-[WILDCARD]031_info_no_check.ts
+deps: 0 unique (total [WILDCARD])
+[WILDCARD]031_info_no_check.ts ([WILDCARD])
diff --git a/cli/tests/049_info_flag_script_jsx.out b/cli/tests/049_info_flag_script_jsx.out
index fd5b511dc..b5fdd980a 100644
--- a/cli/tests/049_info_flag_script_jsx.out
+++ b/cli/tests/049_info_flag_script_jsx.out
@@ -1,14 +1,13 @@
[WILDCARD]
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
type: TypeScript
-compiled: [WILDCARD].js
-deps:
-http://127.0.0.1:4545/cli/tests/048_media_types_jsx.ts
- ├── http://localhost:4545/cli/tests/subdir/mt_text_typescript_tsx.t1.tsx
- ├── http://localhost:4545/cli/tests/subdir/mt_video_vdn_tsx.t2.tsx
- ├── http://localhost:4545/cli/tests/subdir/mt_video_mp2t_tsx.t3.tsx
- ├── http://localhost:4545/cli/tests/subdir/mt_application_x_typescript_tsx.t4.tsx
- ├── http://localhost:4545/cli/tests/subdir/mt_text_javascript_jsx.j1.jsx
- ├── http://localhost:4545/cli/tests/subdir/mt_application_ecmascript_jsx.j2.jsx
- ├── http://localhost:4545/cli/tests/subdir/mt_text_ecmascript_jsx.j3.jsx
- └── http://localhost:4545/cli/tests/subdir/mt_application_x_javascript_jsx.j4.jsx
+deps: 8 unique (total [WILDCARD])
+http://127.0.0.1:4545/cli/tests/048_media_types_jsx.ts ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_text_typescript_tsx.t1.tsx ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_video_vdn_tsx.t2.tsx ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_video_mp2t_tsx.t3.tsx ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_application_x_typescript_tsx.t4.tsx ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_text_javascript_jsx.j1.jsx ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_application_ecmascript_jsx.j2.jsx ([WILDCARD])
+├── http://localhost:4545/cli/tests/subdir/mt_text_ecmascript_jsx.j3.jsx ([WILDCARD])
+└── http://localhost:4545/cli/tests/subdir/mt_application_x_javascript_jsx.j4.jsx ([WILDCARD])
diff --git a/cli/tests/054_info_local_imports.out b/cli/tests/054_info_local_imports.out
index fdf2f44a6..d199dccb3 100644
--- a/cli/tests/054_info_local_imports.out
+++ b/cli/tests/054_info_local_imports.out
@@ -1,8 +1,7 @@
local: [WILDCARD]005_more_imports.ts
type: TypeScript
-compiled: [WILDCARD].js
-deps:
-file://[WILDCARD]/005_more_imports.ts
- └─┬ file://[WILDCARD]/subdir/mod1.ts
- └─┬ file://[WILDCARD]/subdir/subdir2/mod2.ts
- └── file://[WILDCARD]/subdir/print_hello.ts
+deps: 3 unique (total [WILDCARD])
+file://[WILDCARD]/005_more_imports.ts ([WILDCARD])
+└─┬ file://[WILDCARD]/subdir/mod1.ts ([WILDCARD])
+ └─┬ file://[WILDCARD]/subdir/subdir2/mod2.ts ([WILDCARD])
+ └── file://[WILDCARD]/subdir/print_hello.ts ([WILDCARD])
diff --git a/cli/tests/055_info_file_json.out b/cli/tests/055_info_file_json.out
index 08dc73790..5c5da8836 100644
--- a/cli/tests/055_info_file_json.out
+++ b/cli/tests/055_info_file_json.out
@@ -1,25 +1,34 @@
{
"local": "[WILDCARD]005_more_imports.ts",
"fileType": "TypeScript",
- "compiled": "[WILDCARD].js",
+ "compiled": null,
"map": null,
- "deps": [
- "file://[WILDCARD]/005_more_imports.ts",
- [
- [
- "file://[WILDCARD]/subdir/mod1.ts",
- [
- [
- "file://[WILDCARD]/subdir/subdir2/mod2.ts",
- [
- [
- "file://[WILDCARD]/subdir/print_hello.ts",
- []
- ]
+ "depCount": 3,
+ "deps": {
+ "name": "file://[WILDCARD]/005_more_imports.ts",
+ "size": 211,
+ "totalSize": 757,
+ "deps": [
+ {
+ "name": "file://[WILDCARD]/subdir/mod1.ts",
+ "size": 320,
+ "totalSize": 546,
+ "deps": [
+ {
+ "name": "file://[WILDCARD]/subdir/subdir2/mod2.ts",
+ "size": 163,
+ "totalSize": 226,
+ "deps": [
+ {
+ "name": "file://[WILDCARD]/subdir/print_hello.ts",
+ "size": 63,
+ "totalSize": 63,
+ "deps": []
+ }
]
- ]
+ }
]
- ]
+ }
]
- ]
+ }
} \ No newline at end of file
diff --git a/cli/tests/cafile_info.ts.out b/cli/tests/cafile_info.ts.out
index f39f381d7..98b82df38 100644
--- a/cli/tests/cafile_info.ts.out
+++ b/cli/tests/cafile_info.ts.out
@@ -1,13 +1,12 @@
local: [WILDCARD]https[WILDCARD]localhost_PORT5545[WILDCARD]
type: TypeScript
-compiled: [WILDCARD].js
-deps:
-https://localhost:5545/cli/tests/cafile_info.ts
- ├── https://localhost:5545/cli/tests/subdir/mt_text_typescript.t1.ts
- ├── https://localhost:5545/cli/tests/subdir/mt_video_vdn.t2.ts
- ├── https://localhost:5545/cli/tests/subdir/mt_video_mp2t.t3.ts
- ├── https://localhost:5545/cli/tests/subdir/mt_application_x_typescript.t4.ts
- ├── https://localhost:5545/cli/tests/subdir/mt_text_javascript.j1.js
- ├── https://localhost:5545/cli/tests/subdir/mt_application_ecmascript.j2.js
- ├── https://localhost:5545/cli/tests/subdir/mt_text_ecmascript.j3.js
- └── https://localhost:5545/cli/tests/subdir/mt_application_x_javascript.j4.js
+deps: 8 unique (total [WILDCARD])
+https://localhost:5545/cli/tests/cafile_info.ts ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_text_typescript.t1.ts ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_video_vdn.t2.ts ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_video_mp2t.t3.ts ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_application_x_typescript.t4.ts ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_text_javascript.j1.js ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_application_ecmascript.j2.js ([WILDCARD])
+├── https://localhost:5545/cli/tests/subdir/mt_text_ecmascript.j3.js ([WILDCARD])
+└── https://localhost:5545/cli/tests/subdir/mt_application_x_javascript.j4.js ([WILDCARD])
diff --git a/cli/tests/info_recursive_imports_test.out b/cli/tests/info_recursive_imports_test.out
new file mode 100644
index 000000000..12fb0e7d3
--- /dev/null
+++ b/cli/tests/info_recursive_imports_test.out
@@ -0,0 +1,11 @@
+local: [WILDCARD]info_recursive_imports_test.ts
+type: TypeScript
+deps: 4 unique (total [WILDCARD])
+file://[WILDCARD]cli/tests/info_recursive_imports_test.ts ([WILDCARD])
+└─┬ file://[WILDCARD]cli/tests/recursive_imports/A.ts ([WILDCARD])
+ ├─┬ file://[WILDCARD]cli/tests/recursive_imports/B.ts ([WILDCARD])
+ │ ├─┬ file://[WILDCARD]cli/tests/recursive_imports/C.ts ([WILDCARD])
+ │ │ ├── file://[WILDCARD]cli/tests/recursive_imports/A.ts *
+ │ │ └── file://[WILDCARD]cli/tests/recursive_imports/common.ts ([WILDCARD])
+ │ └── file://[WILDCARD]cli/tests/recursive_imports/common.ts *
+ └── file://[WILDCARD]cli/tests/recursive_imports/common.ts *
diff --git a/cli/tests/info_recursive_imports_test.ts b/cli/tests/info_recursive_imports_test.ts
new file mode 100644
index 000000000..0937bf4a5
--- /dev/null
+++ b/cli/tests/info_recursive_imports_test.ts
@@ -0,0 +1,5 @@
+import { A } from "./recursive_imports/A.ts";
+
+export function test(): void {
+ A();
+}
diff --git a/cli/tests/info_type_import.out b/cli/tests/info_type_import.out
index 4096090b3..dc2a3dfe8 100644
--- a/cli/tests/info_type_import.out
+++ b/cli/tests/info_type_import.out
@@ -1,7 +1,5 @@
-Check [WILDCARD]info_type_import.ts
local: [WILDCARD]info_type_import.ts
type: TypeScript
-compiled: [WILDCARD]
-deps:
-[WILDCARD]info_type_import.ts
- └── [WILDCARD]type_and_code.ts
+deps: 1 unique (total [WILDCARD])
+[WILDCARD]info_type_import.ts ([WILDCARD])
+└── [WILDCARD]type_and_code.ts ([WILDCARD])
diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs
index 94d410dcc..4b1b67f7f 100644
--- a/cli/tests/integration_tests.rs
+++ b/cli/tests/integration_tests.rs
@@ -950,6 +950,38 @@ fn bundle_import_map() {
}
#[test]
+fn info_with_compiled_source() {
+ let _g = util::http_server();
+ let module_path = "http://127.0.0.1:4545/cli/tests/048_media_types_jsx.ts";
+ let t = TempDir::new().expect("tempdir fail");
+
+ let mut deno = util::deno_cmd()
+ .env("DENO_DIR", t.path())
+ .current_dir(util::root_path())
+ .arg("cache")
+ .arg(&module_path)
+ .spawn()
+ .expect("failed to spawn script");
+ let status = deno.wait().expect("failed to wait for the child process");
+ assert!(status.success());
+
+ let output = util::deno_cmd()
+ .env("DENO_DIR", t.path())
+ .env("NO_COLOR", "1")
+ .current_dir(util::root_path())
+ .arg("info")
+ .arg(&module_path)
+ .output()
+ .expect("failed to spawn script");
+
+ let str_output = std::str::from_utf8(&output.stdout).unwrap().trim();
+ eprintln!("{}", str_output);
+ // check the output of the test.ts program.
+ assert!(str_output.contains("compiled: "));
+ assert_eq!(output.stderr, b"");
+}
+
+#[test]
fn repl_test_console_log() {
let (out, err) = util::run_and_collect_output(
true,
@@ -2289,6 +2321,12 @@ itest!(import_file_with_colon {
http_server: true,
});
+itest!(info_recursive_modules {
+ args: "info --quiet info_recursive_imports_test.ts",
+ output: "info_recursive_imports_test.out",
+ exit_code: 0,
+});
+
itest!(info_type_import {
args: "info info_type_import.ts",
output: "info_type_import.out",
diff --git a/cli/tests/recursive_imports/A.ts b/cli/tests/recursive_imports/A.ts
new file mode 100644
index 000000000..04ef61581
--- /dev/null
+++ b/cli/tests/recursive_imports/A.ts
@@ -0,0 +1,7 @@
+import { B } from "./B.ts";
+import { thing } from "./common.ts";
+
+export function A(): void {
+ thing();
+ B();
+}
diff --git a/cli/tests/recursive_imports/B.ts b/cli/tests/recursive_imports/B.ts
new file mode 100644
index 000000000..a6e6917fd
--- /dev/null
+++ b/cli/tests/recursive_imports/B.ts
@@ -0,0 +1,7 @@
+import { C } from "./C.ts";
+import { thing } from "./common.ts";
+
+export function B(): void {
+ thing();
+ C();
+}
diff --git a/cli/tests/recursive_imports/C.ts b/cli/tests/recursive_imports/C.ts
new file mode 100644
index 000000000..be6ef9240
--- /dev/null
+++ b/cli/tests/recursive_imports/C.ts
@@ -0,0 +1,8 @@
+import { A } from "./A.ts";
+import { thing } from "./common.ts";
+
+export function C(): void {
+ if (A != null) {
+ thing();
+ }
+}
diff --git a/cli/tests/recursive_imports/common.ts b/cli/tests/recursive_imports/common.ts
new file mode 100644
index 000000000..d0f41395d
--- /dev/null
+++ b/cli/tests/recursive_imports/common.ts
@@ -0,0 +1,2 @@
+export function thing(): void {
+}
diff --git a/cli/tsc.rs b/cli/tsc.rs
index ec2a5c43e..0e2e19a9c 100644
--- a/cli/tsc.rs
+++ b/cli/tsc.rs
@@ -570,7 +570,7 @@ impl TsCompiler {
source_file: &SourceFile,
target: TargetLib,
permissions: Permissions,
- module_graph: ModuleGraph,
+ module_graph: &ModuleGraph,
allow_js: bool,
) -> Result<(), ErrBox> {
let module_url = source_file.url.clone();
@@ -790,7 +790,7 @@ impl TsCompiler {
pub async fn transpile(
&self,
- module_graph: ModuleGraph,
+ module_graph: &ModuleGraph,
) -> Result<(), ErrBox> {
let mut source_files: Vec<TranspileSourceFile> = Vec::new();
for (_, value) in module_graph.iter() {
@@ -1700,7 +1700,7 @@ mod tests {
&out,
TargetLib::Main,
Permissions::allow_all(),
- module_graph,
+ &module_graph,
false,
)
.await;
@@ -1770,7 +1770,7 @@ mod tests {
)
.unwrap();
- let result = ts_compiler.transpile(module_graph).await;
+ let result = ts_compiler.transpile(&module_graph).await;
assert!(result.is_ok());
let compiled_file = ts_compiler.get_compiled_module(&out.url).unwrap();
let source_code = compiled_file.code;
diff --git a/core/lib.rs b/core/lib.rs
index 2c70f0f87..b27419ff5 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -31,7 +31,6 @@ pub use crate::errors::JsError;
pub use crate::flags::v8_set_flags;
pub use crate::module_specifier::ModuleResolutionError;
pub use crate::module_specifier::ModuleSpecifier;
-pub use crate::modules::Deps;
pub use crate::modules::ModuleId;
pub use crate::modules::ModuleLoadId;
pub use crate::modules::ModuleLoader;
diff --git a/core/modules.rs b/core/modules.rs
index 2b914fd1e..3caeab7b1 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -8,10 +8,8 @@ use futures::future::FutureExt;
use futures::stream::FuturesUnordered;
use futures::stream::Stream;
use futures::stream::TryStreamExt;
-use serde_json::Value;
use std::collections::HashMap;
use std::collections::HashSet;
-use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
@@ -437,108 +435,6 @@ impl Modules {
}
self.info.get(&id)
}
-
- pub fn deps(&self, module_specifier: &ModuleSpecifier) -> Option<Deps> {
- Deps::new(self, module_specifier)
- }
-}
-
-/// This is a tree structure representing the dependencies of a given module.
-/// Use Modules::deps to construct it. The 'deps' member is None if this module
-/// was already seen elsewhere in the tree.
-#[derive(Debug, PartialEq)]
-pub struct Deps {
- pub name: String,
- pub deps: Option<Vec<Deps>>,
- prefix: String,
- is_last: bool,
-}
-
-impl Deps {
- fn new(
- modules: &Modules,
- module_specifier: &ModuleSpecifier,
- ) -> Option<Deps> {
- let mut seen = HashSet::new();
- Self::helper(&mut seen, "".to_string(), true, modules, module_specifier)
- }
-
- fn helper(
- seen: &mut HashSet<String>,
- prefix: String,
- is_last: bool,
- modules: &Modules,
- module_specifier: &ModuleSpecifier,
- ) -> Option<Deps> {
- let name = module_specifier.to_string();
- if seen.contains(&name) {
- Some(Deps {
- name,
- prefix,
- deps: None,
- is_last,
- })
- } else {
- let mod_id = modules.get_id(&name)?;
- let children = modules.get_children(mod_id).unwrap();
- seen.insert(name.to_string());
- let child_count = children.len();
- let deps: Vec<Deps> = children
- .iter()
- .enumerate()
- .map(|(index, dep_specifier)| {
- let new_is_last = index == child_count - 1;
- let mut new_prefix = prefix.clone();
- new_prefix.push(if is_last { ' ' } else { '│' });
- new_prefix.push(' ');
-
- Self::helper(seen, new_prefix, new_is_last, modules, dep_specifier)
- })
- // If any of the children are missing, return None.
- .collect::<Option<_>>()?;
-
- Some(Deps {
- name,
- prefix,
- deps: Some(deps),
- is_last,
- })
- }
- }
-
- pub fn to_json(&self) -> Value {
- let children;
- if let Some(deps) = &self.deps {
- children = deps.iter().map(|c| c.to_json()).collect();
- } else {
- children = Vec::new()
- }
- serde_json::json!([&self.name, children])
- }
-}
-
-impl fmt::Display for Deps {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let mut has_children = false;
- if let Some(ref deps) = self.deps {
- has_children = !deps.is_empty();
- }
- write!(
- f,
- "{}{}─{} {}",
- self.prefix,
- if self.is_last { "└" } else { "├" },
- if has_children { "┬" } else { "─" },
- self.name
- )?;
-
- if let Some(ref deps) = self.deps {
- for d in deps {
- write!(f, "\n{}", d)?;
- }
- }
- Ok(())
- }
}
#[cfg(test)]
@@ -1072,56 +968,4 @@ mod tests {
);
assert_eq!(modules.get_children(d_id), Some(&vec![]));
}
-
- #[test]
- fn empty_deps() {
- let modules = Modules::new();
- let specifier = ModuleSpecifier::resolve_url("file:///foo").unwrap();
- assert!(modules.deps(&specifier).is_none());
- }
-
- #[test]
- fn deps_to_json() {
- fn dep(name: &str, deps: Option<Vec<Deps>>) -> Deps {
- Deps {
- name: name.to_string(),
- deps,
- prefix: "".to_string(),
- is_last: false,
- }
- }
- let deps = dep(
- "a",
- Some(vec![
- dep("b", Some(vec![dep("b2", None)])),
- dep("c", Some(vec![])),
- ]),
- );
- assert_eq!(
- serde_json::json!(["a", [["b", [["b2", []]]], ["c", []]]]),
- deps.to_json()
- );
- }
-
- /* TODO(bartlomieju): reenable
- #[test]
- fn deps() {
- // "foo" -> "bar"
- let mut modules = Modules::new();
- modules.register(1, "foo");
- modules.register(2, "bar");
- modules.add_child(1, "bar");
- let maybe_deps = modules.deps("foo");
- assert!(maybe_deps.is_some());
- let mut foo_deps = maybe_deps.unwrap();
- assert_eq!(foo_deps.name, "foo");
- assert!(foo_deps.deps.is_some());
- let foo_children = foo_deps.deps.take().unwrap();
- assert_eq!(foo_children.len(), 1);
- let bar_deps = &foo_children[0];
- assert_eq!(bar_deps.name, "bar");
- assert_eq!(bar_deps.deps, Some(vec![]));
- }
-
- */
}
diff --git a/docs/tools/dependency_inspector.md b/docs/tools/dependency_inspector.md
index 55e80154e..80b747b3c 100644
--- a/docs/tools/dependency_inspector.md
+++ b/docs/tools/dependency_inspector.md
@@ -3,62 +3,61 @@
`deno info [URL]` will inspect ES module and all of its dependencies.
```shell
-deno info https://deno.land/std@0.52.0/http/file_server.ts
-Download https://deno.land/std@0.52.0/http/file_server.ts
+deno info https://deno.land/std@0.67.0/http/file_server.ts
+Download https://deno.land/std@0.67.0/http/file_server.ts
...
-local: /Users/deno/Library/Caches/deno/deps/https/deno.land/5bd138988e9d20db1a436666628ffb3f7586934e0a2a9fe2a7b7bf4fb7f70b98
+local: /home/deno/.cache/deno/deps/https/deno.land/f57792e36f2dbf28b14a75e2372a479c6392780d4712d76698d5031f943c0020
type: TypeScript
-compiled: /Users/deno/Library/Caches/deno/gen/https/deno.land/std@0.52.0/http/file_server.ts.js
-map: /Users/deno/Library/Caches/deno/gen/https/deno.land/std@0.52.0/http/file_server.ts.js.map
-deps:
-https://deno.land/std@0.52.0/http/file_server.ts
- ├─┬ https://deno.land/std@0.52.0/path/mod.ts
- │ ├─┬ https://deno.land/std@0.52.0/path/win32.ts
- │ │ ├── https://deno.land/std@0.52.0/path/_constants.ts
- │ │ ├─┬ https://deno.land/std@0.52.0/path/_util.ts
- │ │ │ └── https://deno.land/std@0.52.0/path/_constants.ts
- │ │ └─┬ https://deno.land/std@0.52.0/testing/asserts.ts
- │ │ ├── https://deno.land/std@0.52.0/fmt/colors.ts
- │ │ └── https://deno.land/std@0.52.0/testing/diff.ts
- │ ├─┬ https://deno.land/std@0.52.0/path/posix.ts
- │ │ ├── https://deno.land/std@0.52.0/path/_constants.ts
- │ │ └── https://deno.land/std@0.52.0/path/_util.ts
- │ ├─┬ https://deno.land/std@0.52.0/path/common.ts
- │ │ └── https://deno.land/std@0.52.0/path/separator.ts
- │ ├── https://deno.land/std@0.52.0/path/separator.ts
- │ ├── https://deno.land/std@0.52.0/path/interface.ts
- │ └─┬ https://deno.land/std@0.52.0/path/glob.ts
- │ ├── https://deno.land/std@0.52.0/path/separator.ts
- │ ├── https://deno.land/std@0.52.0/path/_globrex.ts
- │ ├── https://deno.land/std@0.52.0/path/mod.ts
- │ └── https://deno.land/std@0.52.0/testing/asserts.ts
- ├─┬ https://deno.land/std@0.52.0/http/server.ts
- │ ├── https://deno.land/std@0.52.0/encoding/utf8.ts
- │ ├─┬ https://deno.land/std@0.52.0/io/bufio.ts
- │ │ ├─┬ https://deno.land/std@0.52.0/io/util.ts
- │ │ │ ├── https://deno.land/std@0.52.0/path/mod.ts
- │ │ │ └── https://deno.land/std@0.52.0/encoding/utf8.ts
- │ │ └── https://deno.land/std@0.52.0/testing/asserts.ts
- │ ├── https://deno.land/std@0.52.0/testing/asserts.ts
- │ ├─┬ https://deno.land/std@0.52.0/async/mod.ts
- │ │ ├── https://deno.land/std@0.52.0/async/deferred.ts
- │ │ ├── https://deno.land/std@0.52.0/async/delay.ts
- │ │ └─┬ https://deno.land/std@0.52.0/async/mux_async_iterator.ts
- │ │ └── https://deno.land/std@0.52.0/async/deferred.ts
- │ └─┬ https://deno.land/std@0.52.0/http/_io.ts
- │ ├── https://deno.land/std@0.52.0/io/bufio.ts
- │ ├─┬ https://deno.land/std@0.52.0/textproto/mod.ts
- │ │ ├── https://deno.land/std@0.52.0/io/util.ts
- │ │ ├─┬ https://deno.land/std@0.52.0/bytes/mod.ts
- │ │ │ └── https://deno.land/std@0.52.0/io/util.ts
- │ │ └── https://deno.land/std@0.52.0/encoding/utf8.ts
- │ ├── https://deno.land/std@0.52.0/testing/asserts.ts
- │ ├── https://deno.land/std@0.52.0/encoding/utf8.ts
- │ ├── https://deno.land/std@0.52.0/http/server.ts
- │ └── https://deno.land/std@0.52.0/http/http_status.ts
- ├─┬ https://deno.land/std@0.52.0/flags/mod.ts
- │ └── https://deno.land/std@0.52.0/testing/asserts.ts
- └── https://deno.land/std@0.52.0/testing/asserts.ts
+compiled: /home/deno/.cache/deno/gen/https/deno.land/f57792e36f2dbf28b14a75e2372a479c6392780d4712d76698d5031f943c0020.js
+deps: 23 unique (total 139.89KB)
+https://deno.land/std@0.67.0/http/file_server.ts (10.49KB)
+├─┬ https://deno.land/std@0.67.0/path/mod.ts (717B)
+│ ├── https://deno.land/std@0.67.0/path/_constants.ts (2.35KB)
+│ ├─┬ https://deno.land/std@0.67.0/path/win32.ts (27.36KB)
+│ │ ├── https://deno.land/std@0.67.0/path/_interface.ts (657B)
+│ │ ├── https://deno.land/std@0.67.0/path/_constants.ts *
+│ │ ├─┬ https://deno.land/std@0.67.0/path/_util.ts (3.3KB)
+│ │ │ ├── https://deno.land/std@0.67.0/path/_interface.ts *
+│ │ │ └── https://deno.land/std@0.67.0/path/_constants.ts *
+│ │ └── https://deno.land/std@0.67.0/_util/assert.ts (405B)
+│ ├─┬ https://deno.land/std@0.67.0/path/posix.ts (12.67KB)
+│ │ ├── https://deno.land/std@0.67.0/path/_interface.ts *
+│ │ ├── https://deno.land/std@0.67.0/path/_constants.ts *
+│ │ └── https://deno.land/std@0.67.0/path/_util.ts *
+│ ├─┬ https://deno.land/std@0.67.0/path/common.ts (1.14KB)
+│ │ └─┬ https://deno.land/std@0.67.0/path/separator.ts (264B)
+│ │ └── https://deno.land/std@0.67.0/path/_constants.ts *
+│ ├── https://deno.land/std@0.67.0/path/separator.ts *
+│ ├── https://deno.land/std@0.67.0/path/_interface.ts *
+│ └─┬ https://deno.land/std@0.67.0/path/glob.ts (8.12KB)
+│ ├── https://deno.land/std@0.67.0/path/_constants.ts *
+│ ├── https://deno.land/std@0.67.0/path/mod.ts *
+│ └── https://deno.land/std@0.67.0/path/separator.ts *
+├─┬ https://deno.land/std@0.67.0/http/server.ts (10.23KB)
+│ ├── https://deno.land/std@0.67.0/encoding/utf8.ts (433B)
+│ ├─┬ https://deno.land/std@0.67.0/io/bufio.ts (21.15KB)
+│ │ ├── https://deno.land/std@0.67.0/bytes/mod.ts (4.34KB)
+│ │ └── https://deno.land/std@0.67.0/_util/assert.ts *
+│ ├── https://deno.land/std@0.67.0/_util/assert.ts *
+│ ├─┬ https://deno.land/std@0.67.0/async/mod.ts (202B)
+│ │ ├── https://deno.land/std@0.67.0/async/deferred.ts (1.03KB)
+│ │ ├── https://deno.land/std@0.67.0/async/delay.ts (279B)
+│ │ ├─┬ https://deno.land/std@0.67.0/async/mux_async_iterator.ts (1.98KB)
+│ │ │ └── https://deno.land/std@0.67.0/async/deferred.ts *
+│ │ └── https://deno.land/std@0.67.0/async/pool.ts (1.58KB)
+│ └─┬ https://deno.land/std@0.67.0/http/_io.ts (11.25KB)
+│ ├── https://deno.land/std@0.67.0/io/bufio.ts *
+│ ├─┬ https://deno.land/std@0.67.0/textproto/mod.ts (4.52KB)
+│ │ ├── https://deno.land/std@0.67.0/io/bufio.ts *
+│ │ ├── https://deno.land/std@0.67.0/bytes/mod.ts *
+│ │ └── https://deno.land/std@0.67.0/encoding/utf8.ts *
+│ ├── https://deno.land/std@0.67.0/_util/assert.ts *
+│ ├── https://deno.land/std@0.67.0/encoding/utf8.ts *
+│ ├── https://deno.land/std@0.67.0/http/server.ts *
+│ └── https://deno.land/std@0.67.0/http/http_status.ts (5.93KB)
+├─┬ https://deno.land/std@0.67.0/flags/mod.ts (9.54KB)
+│ └── https://deno.land/std@0.67.0/_util/assert.ts *
+└── https://deno.land/std@0.67.0/_util/assert.ts *
```
Dependency inspector works with any local or remote ES modules.