summaryrefslogtreecommitdiff
path: root/cli/tools
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools')
-rw-r--r--cli/tools/info.rs947
1 files changed, 422 insertions, 525 deletions
diff --git a/cli/tools/info.rs b/cli/tools/info.rs
index b5cae32ee..e45958b34 100644
--- a/cli/tools/info.rs
+++ b/cli/tools/info.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt;
use std::fmt::Write;
@@ -22,6 +23,12 @@ use crate::args::InfoFlags;
use crate::checksum;
use crate::display;
use crate::lsp;
+use crate::npm::NpmPackageId;
+use crate::npm::NpmPackageReference;
+use crate::npm::NpmPackageReq;
+use crate::npm::NpmPackageResolver;
+use crate::npm::NpmResolutionPackage;
+use crate::npm::NpmResolutionSnapshot;
use crate::proc_state::ProcState;
pub async fn info(flags: Flags, info_flags: InfoFlags) -> Result<(), AnyError> {
@@ -34,7 +41,7 @@ pub async fn info(flags: Flags, info_flags: InfoFlags) -> Result<(), AnyError> {
display::write_json_to_stdout(&json!(graph))?;
} else {
let mut output = String::new();
- fmt_module_graph(&graph, &mut output)?;
+ GraphDisplayContext::write(&graph, &ps.npm_resolver, &mut output)?;
display::write_to_stdout_ignore_sigpipe(output.as_bytes())?;
}
} else {
@@ -121,564 +128,454 @@ fn print_cache_info(
}
}
-const SIBLING_CONNECTOR: char = '├';
-const LAST_SIBLING_CONNECTOR: char = '└';
-const CHILD_DEPS_CONNECTOR: char = '┬';
-const CHILD_NO_DEPS_CONNECTOR: char = '─';
-const VERTICAL_CONNECTOR: char = '│';
-const EMPTY_CONNECTOR: char = ' ';
-
-fn fmt_module_graph(graph: &ModuleGraph, f: &mut impl Write) -> fmt::Result {
- if graph.roots.is_empty() || graph.roots.len() > 1 {
- return writeln!(
- f,
- "{} displaying graphs that have multiple roots is not supported.",
- colors::red("error:")
- );
- }
- let root_specifier = graph.resolve(&graph.roots[0].0);
- match graph.try_get(&root_specifier) {
- Ok(Some(root)) => {
- if let Some(cache_info) = root.maybe_cache_info.as_ref() {
- if let Some(local) = &cache_info.local {
- writeln!(
- f,
- "{} {}",
- colors::bold("local:"),
- local.to_string_lossy()
- )?;
- }
- if let Some(emit) = &cache_info.emit {
- writeln!(f, "{} {}", colors::bold("emit:"), emit.to_string_lossy())?;
- }
- if let Some(map) = &cache_info.map {
- writeln!(f, "{} {}", colors::bold("map:"), map.to_string_lossy())?;
- }
- }
- writeln!(f, "{} {}", colors::bold("type:"), root.media_type)?;
- let modules = graph.modules();
- let total_size: f64 = modules.iter().map(|m| m.size() as f64).sum();
- let dep_count = modules.len() - 1;
- writeln!(
- f,
- "{} {} unique {}",
- colors::bold("dependencies:"),
- dep_count,
- colors::gray(format!("(total {})", display::human_size(total_size)))
- )?;
- writeln!(
- f,
- "\n{} {}",
- root_specifier,
- colors::gray(format!("({})", display::human_size(root.size() as f64)))
- )?;
- let mut seen = HashSet::new();
- let dep_len = root.dependencies.len();
- for (idx, (_, dep)) in root.dependencies.iter().enumerate() {
- fmt_dep_info(
- dep,
- f,
- "",
- idx == dep_len - 1 && root.maybe_types_dependency.is_none(),
- graph,
- &mut seen,
- )?;
- }
- Ok(())
- }
- Err(ModuleGraphError::Missing(_)) => {
- writeln!(f, "{} module could not be found", colors::red("error:"))
- }
- Err(err) => {
- writeln!(f, "{} {}", colors::red("error:"), err)
- }
- Ok(None) => {
- writeln!(f, "{} an internal error occurred", colors::red("error:"))
+struct TreeNode {
+ text: String,
+ children: Vec<TreeNode>,
+}
+
+impl TreeNode {
+ pub fn from_text(text: String) -> Self {
+ Self {
+ text,
+ children: Default::default(),
}
}
}
-fn fmt_dep_info<S: AsRef<str> + fmt::Display + Clone>(
- dep: &Dependency,
- f: &mut impl Write,
- prefix: S,
- last: bool,
- graph: &ModuleGraph,
- seen: &mut HashSet<ModuleSpecifier>,
+fn print_tree_node<TWrite: Write>(
+ tree_node: &TreeNode,
+ writer: &mut TWrite,
) -> fmt::Result {
- if !dep.maybe_code.is_none() {
- fmt_resolved_info(
- &dep.maybe_code,
- f,
- prefix.clone(),
- dep.maybe_type.is_none() && last,
- graph,
- false,
- seen,
- )?;
- }
- if !dep.maybe_type.is_none() {
- fmt_resolved_info(&dep.maybe_type, f, prefix, last, graph, true, seen)?;
+ fn print_children<TWrite: Write>(
+ writer: &mut TWrite,
+ prefix: &str,
+ children: &Vec<TreeNode>,
+ ) -> fmt::Result {
+ const SIBLING_CONNECTOR: char = '├';
+ const LAST_SIBLING_CONNECTOR: char = '└';
+ const CHILD_DEPS_CONNECTOR: char = '┬';
+ const CHILD_NO_DEPS_CONNECTOR: char = '─';
+ const VERTICAL_CONNECTOR: char = '│';
+ const EMPTY_CONNECTOR: char = ' ';
+
+ let child_len = children.len();
+ for (index, child) in children.iter().enumerate() {
+ let is_last = index + 1 == child_len;
+ let sibling_connector = if is_last {
+ LAST_SIBLING_CONNECTOR
+ } else {
+ SIBLING_CONNECTOR
+ };
+ let child_connector = if child.children.is_empty() {
+ CHILD_NO_DEPS_CONNECTOR
+ } else {
+ CHILD_DEPS_CONNECTOR
+ };
+ writeln!(
+ writer,
+ "{} {}",
+ colors::gray(format!(
+ "{}{}─{}",
+ prefix, sibling_connector, child_connector
+ )),
+ child.text
+ )?;
+ let child_prefix = format!(
+ "{}{}{}",
+ prefix,
+ if is_last {
+ EMPTY_CONNECTOR
+ } else {
+ VERTICAL_CONNECTOR
+ },
+ EMPTY_CONNECTOR
+ );
+ print_children(writer, &child_prefix, &child.children)?;
+ }
+
+ Ok(())
}
+
+ writeln!(writer, "{}", tree_node.text)?;
+ print_children(writer, "", &tree_node.children)?;
Ok(())
}
-fn fmt_module_info<S: AsRef<str> + fmt::Display + Clone>(
- module: &Module,
- f: &mut impl Write,
- prefix: S,
- last: bool,
- graph: &ModuleGraph,
- type_dep: bool,
- seen: &mut HashSet<ModuleSpecifier>,
-) -> fmt::Result {
- let was_seen = seen.contains(&module.specifier);
- let children = !((module.dependencies.is_empty()
- && module.maybe_types_dependency.is_none())
- || was_seen);
- let (specifier_str, size_str) = if was_seen {
- let specifier_str = if type_dep {
- colors::italic_gray(&module.specifier).to_string()
- } else {
- colors::gray(&module.specifier).to_string()
- };
- (specifier_str, colors::gray(" *").to_string())
- } else {
- let specifier_str = if type_dep {
- colors::italic(&module.specifier).to_string()
- } else {
- module.specifier.to_string()
- };
- let size_str =
- colors::gray(format!(" ({})", display::human_size(module.size() as f64)))
- .to_string();
- (specifier_str, size_str)
- };
-
- seen.insert(module.specifier.clone());
-
- fmt_info_msg(
- f,
- prefix.clone(),
- last,
- children,
- format!("{}{}", specifier_str, size_str),
- )?;
-
- if !was_seen {
- let mut prefix = prefix.to_string();
- if last {
- prefix.push(EMPTY_CONNECTOR);
- } else {
- prefix.push(VERTICAL_CONNECTOR);
- }
- prefix.push(EMPTY_CONNECTOR);
- let dep_len = module.dependencies.len();
- if let Some((_, type_dep)) = &module.maybe_types_dependency {
- fmt_resolved_info(type_dep, f, &prefix, dep_len == 0, graph, true, seen)?;
+/// Precached information about npm packages that are used in deno info.
+#[derive(Default)]
+struct NpmInfo {
+ package_sizes: HashMap<NpmPackageId, u64>,
+ resolved_reqs: HashMap<NpmPackageReq, NpmPackageId>,
+ packages: HashMap<NpmPackageId, NpmResolutionPackage>,
+ specifiers: HashMap<ModuleSpecifier, NpmPackageReq>,
+}
+
+impl NpmInfo {
+ pub fn build<'a>(
+ graph: &'a ModuleGraph,
+ npm_resolver: &'a NpmPackageResolver,
+ npm_snapshot: &'a NpmResolutionSnapshot,
+ ) -> Self {
+ let mut info = NpmInfo::default();
+ if !npm_resolver.has_packages() {
+ return info; // skip going over the specifiers if there's no npm packages
}
- for (idx, (_, dep)) in module.dependencies.iter().enumerate() {
- fmt_dep_info(
- dep,
- f,
- &prefix,
- idx == dep_len - 1 && module.maybe_types_dependency.is_none(),
- graph,
- seen,
- )?;
+
+ for (specifier, _) in graph.specifiers() {
+ if let Ok(reference) = NpmPackageReference::from_specifier(&specifier) {
+ info
+ .specifiers
+ .insert(specifier.clone(), reference.req.clone());
+ if let Ok(package) =
+ npm_snapshot.resolve_package_from_deno_module(&reference.req)
+ {
+ info.resolved_reqs.insert(reference.req, package.id.clone());
+ if !info.packages.contains_key(&package.id) {
+ info.fill_package_info(package, npm_resolver, npm_snapshot);
+ }
+ }
+ }
}
+
+ info
}
- Ok(())
-}
-fn fmt_error_info<S: AsRef<str> + fmt::Display + Clone>(
- err: &ModuleGraphError,
- f: &mut impl Write,
- prefix: S,
- last: bool,
- specifier: &ModuleSpecifier,
- seen: &mut HashSet<ModuleSpecifier>,
-) -> fmt::Result {
- seen.insert(specifier.clone());
- match err {
- ModuleGraphError::InvalidSource(_, _) => {
- fmt_error_msg(f, prefix, last, specifier, "(invalid source)")
+ fn fill_package_info<'a>(
+ &mut self,
+ package: &NpmResolutionPackage,
+ npm_resolver: &'a NpmPackageResolver,
+ npm_snapshot: &'a NpmResolutionSnapshot,
+ ) {
+ self.packages.insert(package.id.clone(), package.clone());
+ if let Ok(size) = npm_resolver.package_size(&package.id) {
+ self.package_sizes.insert(package.id.clone(), size);
}
- ModuleGraphError::InvalidTypeAssertion { .. } => {
- fmt_error_msg(f, prefix, last, specifier, "(invalid import assertion)")
+ for id in package.dependencies.values() {
+ if !self.packages.contains_key(id) {
+ if let Some(package) = npm_snapshot.package_from_id(id) {
+ self.fill_package_info(package, npm_resolver, npm_snapshot);
+ }
+ }
}
- ModuleGraphError::LoadingErr(_, _) => {
- fmt_error_msg(f, prefix, last, specifier, "(loading error)")
+ }
+
+ pub fn package_from_specifier(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Option<&NpmResolutionPackage> {
+ self
+ .specifiers
+ .get(specifier)
+ .and_then(|package_req| self.resolved_reqs.get(package_req))
+ .and_then(|id| self.packages.get(id))
+ }
+}
+
+struct GraphDisplayContext<'a> {
+ graph: &'a ModuleGraph,
+ npm_info: NpmInfo,
+ seen: HashSet<String>,
+}
+
+impl<'a> GraphDisplayContext<'a> {
+ pub fn write<TWrite: Write>(
+ graph: &'a ModuleGraph,
+ npm_resolver: &'a NpmPackageResolver,
+ writer: &mut TWrite,
+ ) -> fmt::Result {
+ let npm_snapshot = npm_resolver.snapshot();
+ let npm_info = NpmInfo::build(graph, npm_resolver, &npm_snapshot);
+ Self {
+ graph,
+ npm_info,
+ seen: Default::default(),
}
- ModuleGraphError::ParseErr(_, _) => {
- fmt_error_msg(f, prefix, last, specifier, "(parsing error)")
+ .into_writer(writer)
+ }
+
+ fn into_writer<TWrite: Write>(mut self, writer: &mut TWrite) -> fmt::Result {
+ if self.graph.roots.is_empty() || self.graph.roots.len() > 1 {
+ return writeln!(
+ writer,
+ "{} displaying graphs that have multiple roots is not supported.",
+ colors::red("error:")
+ );
}
- ModuleGraphError::ResolutionError(_) => {
- fmt_error_msg(f, prefix, last, specifier, "(resolution error)")
+
+ let root_specifier = self.graph.resolve(&self.graph.roots[0].0);
+ match self.graph.try_get(&root_specifier) {
+ Ok(Some(root)) => {
+ if let Some(cache_info) = root.maybe_cache_info.as_ref() {
+ if let Some(local) = &cache_info.local {
+ writeln!(
+ writer,
+ "{} {}",
+ colors::bold("local:"),
+ local.to_string_lossy()
+ )?;
+ }
+ if let Some(emit) = &cache_info.emit {
+ writeln!(
+ writer,
+ "{} {}",
+ colors::bold("emit:"),
+ emit.to_string_lossy()
+ )?;
+ }
+ if let Some(map) = &cache_info.map {
+ writeln!(
+ writer,
+ "{} {}",
+ colors::bold("map:"),
+ map.to_string_lossy()
+ )?;
+ }
+ }
+ writeln!(writer, "{} {}", colors::bold("type:"), root.media_type)?;
+ let modules = self.graph.modules();
+ let total_modules_size =
+ modules.iter().map(|m| m.size() as f64).sum::<f64>();
+ let total_npm_package_size = self
+ .npm_info
+ .package_sizes
+ .values()
+ .map(|s| *s as f64)
+ .sum::<f64>();
+ let total_size = total_modules_size + total_npm_package_size;
+ let dep_count = modules.len() - 1 + self.npm_info.packages.len()
+ - self.npm_info.resolved_reqs.len();
+ writeln!(
+ writer,
+ "{} {} unique",
+ colors::bold("dependencies:"),
+ dep_count,
+ )?;
+ writeln!(
+ writer,
+ "{} {}",
+ colors::bold("size:"),
+ display::human_size(total_size),
+ )?;
+ writeln!(writer)?;
+ let root_node = self.build_module_info(root, false);
+ print_tree_node(&root_node, writer)?;
+ Ok(())
+ }
+ Err(ModuleGraphError::Missing(_)) => {
+ writeln!(
+ writer,
+ "{} module could not be found",
+ colors::red("error:")
+ )
+ }
+ Err(err) => {
+ writeln!(writer, "{} {}", colors::red("error:"), err)
+ }
+ Ok(None) => {
+ writeln!(
+ writer,
+ "{} an internal error occurred",
+ colors::red("error:")
+ )
+ }
}
- ModuleGraphError::UnsupportedImportAssertionType(_, _) => fmt_error_msg(
- f,
- prefix,
- last,
- specifier,
- "(unsupported import assertion)",
- ),
- ModuleGraphError::UnsupportedMediaType(_, _) => {
- fmt_error_msg(f, prefix, last, specifier, "(unsupported)")
+ }
+
+ fn build_dep_info(&mut self, dep: &Dependency) -> Vec<TreeNode> {
+ let mut children = Vec::with_capacity(2);
+ if !dep.maybe_code.is_none() {
+ if let Some(child) = self.build_resolved_info(&dep.maybe_code, false) {
+ children.push(child);
+ }
}
- ModuleGraphError::Missing(_) => {
- fmt_error_msg(f, prefix, last, specifier, "(missing)")
+ if !dep.maybe_type.is_none() {
+ if let Some(child) = self.build_resolved_info(&dep.maybe_type, true) {
+ children.push(child);
+ }
}
+ children
}
-}
-fn fmt_info_msg<S, M>(
- f: &mut impl Write,
- prefix: S,
- last: bool,
- children: bool,
- msg: M,
-) -> fmt::Result
-where
- S: AsRef<str> + fmt::Display + Clone,
- M: AsRef<str> + fmt::Display,
-{
- let sibling_connector = if last {
- LAST_SIBLING_CONNECTOR
- } else {
- SIBLING_CONNECTOR
- };
- let child_connector = if children {
- CHILD_DEPS_CONNECTOR
- } else {
- CHILD_NO_DEPS_CONNECTOR
- };
- writeln!(
- f,
- "{} {}",
- colors::gray(format!(
- "{}{}─{}",
- prefix, sibling_connector, child_connector
- )),
- msg
- )
-}
+ fn build_module_info(&mut self, module: &Module, type_dep: bool) -> TreeNode {
+ enum PackageOrSpecifier {
+ Package(NpmResolutionPackage),
+ Specifier(ModuleSpecifier),
+ }
-fn fmt_error_msg<S, M>(
- f: &mut impl Write,
- prefix: S,
- last: bool,
- specifier: &ModuleSpecifier,
- error_msg: M,
-) -> fmt::Result
-where
- S: AsRef<str> + fmt::Display + Clone,
- M: AsRef<str> + fmt::Display,
-{
- fmt_info_msg(
- f,
- prefix,
- last,
- false,
- format!("{} {}", colors::red(specifier), colors::red_bold(error_msg)),
- )
-}
+ use PackageOrSpecifier::*;
-fn fmt_resolved_info<S: AsRef<str> + fmt::Display + Clone>(
- resolved: &Resolved,
- f: &mut impl Write,
- prefix: S,
- last: bool,
- graph: &ModuleGraph,
- type_dep: bool,
- seen: &mut HashSet<ModuleSpecifier>,
-) -> fmt::Result {
- match resolved {
- Resolved::Ok { specifier, .. } => {
- let resolved_specifier = graph.resolve(specifier);
- match graph.try_get(&resolved_specifier) {
- Ok(Some(module)) => {
- fmt_module_info(module, f, prefix, last, graph, type_dep, seen)
+ let package_or_specifier =
+ match self.npm_info.package_from_specifier(&module.specifier) {
+ Some(package) => Package(package.clone()),
+ None => Specifier(module.specifier.clone()),
+ };
+ let was_seen = !self.seen.insert(match &package_or_specifier {
+ Package(package) => package.id.to_string(),
+ Specifier(specifier) => specifier.to_string(),
+ });
+ let header_text = if was_seen {
+ let specifier_str = if type_dep {
+ colors::italic_gray(&module.specifier).to_string()
+ } else {
+ colors::gray(&module.specifier).to_string()
+ };
+ format!("{} {}", specifier_str, colors::gray("*"))
+ } else {
+ let specifier_str = if type_dep {
+ colors::italic(&module.specifier).to_string()
+ } else {
+ module.specifier.to_string()
+ };
+ let header_text = match &package_or_specifier {
+ Package(package) => {
+ format!("{} - {}", specifier_str, package.id.version)
+ }
+ Specifier(_) => specifier_str,
+ };
+ let maybe_size = match &package_or_specifier {
+ Package(package) => self
+ .npm_info
+ .package_sizes
+ .get(&package.id)
+ .map(|s| *s as u64),
+ Specifier(_) => module
+ .maybe_source
+ .as_ref()
+ .map(|s| s.as_bytes().len() as u64),
+ };
+ format!("{} {}", header_text, maybe_size_to_text(maybe_size))
+ };
+
+ let mut tree_node = TreeNode::from_text(header_text);
+
+ if !was_seen {
+ if let Some((_, type_dep)) = &module.maybe_types_dependency {
+ if let Some(child) = self.build_resolved_info(type_dep, true) {
+ tree_node.children.push(child);
+ }
+ }
+ match &package_or_specifier {
+ Package(package) => {
+ tree_node.children.extend(self.build_npm_deps(package));
}
- Err(err) => {
- fmt_error_info(&err, f, prefix, last, &resolved_specifier, seen)
+ Specifier(_) => {
+ for dep in module.dependencies.values() {
+ tree_node.children.extend(self.build_dep_info(dep));
+ }
}
- Ok(None) => fmt_info_msg(
- f,
- prefix,
- last,
- false,
- format!(
+ }
+ }
+ tree_node
+ }
+
+ fn build_npm_deps(
+ &mut self,
+ package: &NpmResolutionPackage,
+ ) -> Vec<TreeNode> {
+ let mut deps = package.dependencies.values().collect::<Vec<_>>();
+ deps.sort();
+ let mut children = Vec::with_capacity(deps.len());
+ for dep_id in deps.into_iter() {
+ let maybe_size = self.npm_info.package_sizes.get(dep_id).cloned();
+ let size_str = maybe_size_to_text(maybe_size);
+ let mut child =
+ TreeNode::from_text(format!("npm:{} {}", dep_id, size_str));
+ if let Some(package) = self.npm_info.packages.get(dep_id) {
+ if !package.dependencies.is_empty() {
+ if self.seen.contains(&package.id.to_string()) {
+ child.text = format!("{} {}", child.text, colors::gray("*"));
+ } else {
+ let package = package.clone();
+ child.children.extend(self.build_npm_deps(&package));
+ }
+ }
+ }
+ children.push(child);
+ }
+ children
+ }
+
+ fn build_error_info(
+ &mut self,
+ err: &ModuleGraphError,
+ specifier: &ModuleSpecifier,
+ ) -> TreeNode {
+ self.seen.insert(specifier.to_string());
+ match err {
+ ModuleGraphError::InvalidSource(_, _) => {
+ self.build_error_msg(specifier, "(invalid source)")
+ }
+ ModuleGraphError::InvalidTypeAssertion { .. } => {
+ self.build_error_msg(specifier, "(invalid import assertion)")
+ }
+ ModuleGraphError::LoadingErr(_, _) => {
+ self.build_error_msg(specifier, "(loading error)")
+ }
+ ModuleGraphError::ParseErr(_, _) => {
+ self.build_error_msg(specifier, "(parsing error)")
+ }
+ ModuleGraphError::ResolutionError(_) => {
+ self.build_error_msg(specifier, "(resolution error)")
+ }
+ ModuleGraphError::UnsupportedImportAssertionType(_, _) => {
+ self.build_error_msg(specifier, "(unsupported import assertion)")
+ }
+ ModuleGraphError::UnsupportedMediaType(_, _) => {
+ self.build_error_msg(specifier, "(unsupported)")
+ }
+ ModuleGraphError::Missing(_) => {
+ self.build_error_msg(specifier, "(missing)")
+ }
+ }
+ }
+
+ fn build_error_msg(
+ &self,
+ specifier: &ModuleSpecifier,
+ error_msg: &str,
+ ) -> TreeNode {
+ TreeNode::from_text(format!(
+ "{} {}",
+ colors::red(specifier),
+ colors::red_bold(error_msg)
+ ))
+ }
+
+ fn build_resolved_info(
+ &mut self,
+ resolved: &Resolved,
+ type_dep: bool,
+ ) -> Option<TreeNode> {
+ match resolved {
+ Resolved::Ok { specifier, .. } => {
+ let resolved_specifier = self.graph.resolve(specifier);
+ Some(match self.graph.try_get(&resolved_specifier) {
+ Ok(Some(module)) => self.build_module_info(module, type_dep),
+ Err(err) => self.build_error_info(&err, &resolved_specifier),
+ Ok(None) => TreeNode::from_text(format!(
"{} {}",
colors::red(specifier),
colors::red_bold("(missing)")
- ),
- ),
+ )),
+ })
}
- }
- Resolved::Err(err) => fmt_info_msg(
- f,
- prefix,
- last,
- false,
- format!(
+ Resolved::Err(err) => Some(TreeNode::from_text(format!(
"{} {}",
colors::italic(err.to_string()),
colors::red_bold("(resolve error)")
- ),
- ),
- _ => Ok(()),
+ ))),
+ _ => None,
+ }
}
}
-#[cfg(test)]
-mod tests {
- use deno_graph::source::CacheInfo;
- use deno_graph::source::MemoryLoader;
- use deno_graph::source::Source;
- use test_util::strip_ansi_codes;
-
- use super::*;
- use std::path::PathBuf;
-
- #[tokio::test]
- async fn test_info_graph() {
- let mut loader = MemoryLoader::new(
- vec![
- (
- "https://deno.land/x/example/a.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/a.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"import * as b from "./b.ts";
- import type { F } from "./f.d.ts";
- import * as g from "./g.js";
- "#,
- },
- ),
- (
- "https://deno.land/x/example/b.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/b.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"
- // @deno-types="./c.d.ts"
- import * as c from "./c.js";
- import * as d from "./d.ts";"#,
- },
- ),
- (
- "https://deno.land/x/example/c.js",
- Source::Module {
- specifier: "https://deno.land/x/example/c.js",
- maybe_headers: Some(vec![(
- "content-type",
- "application/javascript",
- )]),
- content: r#"export const c = "c";"#,
- },
- ),
- (
- "https://deno.land/x/example/c.d.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/c.d.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"export const c: "c";"#,
- },
- ),
- (
- "https://deno.land/x/example/d.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/d.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"import * as e from "./e.ts";
- export const d = "d";"#,
- },
- ),
- (
- "https://deno.land/x/example/e.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/e.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"import * as b from "./b.ts";
- export const e = "e";"#,
- },
- ),
- (
- "https://deno.land/x/example/f.d.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/f.d.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"export interface F { }"#,
- },
- ),
- (
- "https://deno.land/x/example/g.js",
- Source::Module {
- specifier: "https://deno.land/x/example/g.js",
- maybe_headers: Some(vec![
- ("content-type", "application/javascript"),
- ("x-typescript-types", "./g.d.ts"),
- ]),
- content: r#"export const g = "g";"#,
- },
- ),
- (
- "https://deno.land/x/example/g.d.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/g.d.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"export const g: "g";"#,
- },
- ),
- ],
- vec![(
- "https://deno.land/x/example/a.ts",
- CacheInfo {
- local: Some(PathBuf::from(
- "/cache/deps/https/deno.land/x/example/a.ts",
- )),
- emit: Some(PathBuf::from(
- "/cache/deps/https/deno.land/x/example/a.js",
- )),
- ..Default::default()
- },
- )],
- );
- let root_specifier =
- ModuleSpecifier::parse("https://deno.land/x/example/a.ts").unwrap();
- let graph = deno_graph::create_graph(
- vec![(root_specifier, ModuleKind::Esm)],
- &mut loader,
- deno_graph::GraphOptions {
- is_dynamic: false,
- imports: None,
- resolver: None,
- locker: None,
- module_analyzer: None,
- reporter: None,
- },
- )
- .await;
- let mut output = String::new();
- fmt_module_graph(&graph, &mut output).unwrap();
- assert_eq!(
- strip_ansi_codes(&output),
- r#"local: /cache/deps/https/deno.land/x/example/a.ts
-emit: /cache/deps/https/deno.land/x/example/a.js
-type: TypeScript
-dependencies: 8 unique (total 477B)
-
-https://deno.land/x/example/a.ts (129B)
-├─┬ https://deno.land/x/example/b.ts (120B)
-│ ├── https://deno.land/x/example/c.js (21B)
-│ ├── https://deno.land/x/example/c.d.ts (20B)
-│ └─┬ https://deno.land/x/example/d.ts (62B)
-│ └─┬ https://deno.land/x/example/e.ts (62B)
-│ └── https://deno.land/x/example/b.ts *
-├── https://deno.land/x/example/f.d.ts (22B)
-└─┬ https://deno.land/x/example/g.js (21B)
- └── https://deno.land/x/example/g.d.ts (20B)
-"#
- );
- }
-
- #[tokio::test]
- async fn test_info_graph_import_assertion() {
- let mut loader = MemoryLoader::new(
- vec![
- (
- "https://deno.land/x/example/a.ts",
- Source::Module {
- specifier: "https://deno.land/x/example/a.ts",
- maybe_headers: Some(vec![(
- "content-type",
- "application/typescript",
- )]),
- content: r#"import b from "./b.json" assert { type: "json" };
- const c = await import("./c.json", { assert: { type: "json" } });
- "#,
- },
- ),
- (
- "https://deno.land/x/example/b.json",
- Source::Module {
- specifier: "https://deno.land/x/example/b.json",
- maybe_headers: Some(vec![("content-type", "application/json")]),
- content: r#"{"b":"c"}"#,
- },
- ),
- (
- "https://deno.land/x/example/c.json",
- Source::Module {
- specifier: "https://deno.land/x/example/c.json",
- maybe_headers: Some(vec![("content-type", "application/json")]),
- content: r#"{"c":1}"#,
- },
- ),
- ],
- vec![(
- "https://deno.land/x/example/a.ts",
- CacheInfo {
- local: Some(PathBuf::from(
- "/cache/deps/https/deno.land/x/example/a.ts",
- )),
- emit: Some(PathBuf::from(
- "/cache/deps/https/deno.land/x/example/a.js",
- )),
- ..Default::default()
- },
- )],
- );
- let root_specifier =
- ModuleSpecifier::parse("https://deno.land/x/example/a.ts").unwrap();
- let graph = deno_graph::create_graph(
- vec![(root_specifier, ModuleKind::Esm)],
- &mut loader,
- deno_graph::GraphOptions {
- is_dynamic: false,
- imports: None,
- resolver: None,
- locker: None,
- module_analyzer: None,
- reporter: None,
- },
- )
- .await;
- let mut output = String::new();
- fmt_module_graph(&graph, &mut output).unwrap();
- assert_eq!(
- strip_ansi_codes(&output),
- r#"local: /cache/deps/https/deno.land/x/example/a.ts
-emit: /cache/deps/https/deno.land/x/example/a.js
-type: TypeScript
-dependencies: 2 unique (total 156B)
-
-https://deno.land/x/example/a.ts (140B)
-├── https://deno.land/x/example/b.json (9B)
-└── https://deno.land/x/example/c.json (7B)
-"#
- );
- }
+fn maybe_size_to_text(maybe_size: Option<u64>) -> String {
+ colors::gray(format!(
+ "({})",
+ match maybe_size {
+ Some(size) => display::human_size(size as f64),
+ None => "unknown".to_string(),
+ }
+ ))
+ .to_string()
}