summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/args/flags.rs2
-rw-r--r--cli/fs_util.rs24
-rw-r--r--cli/npm/resolution.rs7
-rw-r--r--cli/npm/resolvers/common.rs3
-rw-r--r--cli/npm/resolvers/global.rs6
-rw-r--r--cli/npm/resolvers/local.rs16
-rw-r--r--cli/npm/resolvers/mod.rs15
-rw-r--r--cli/tests/integration/npm_tests.rs25
-rw-r--r--cli/tests/testdata/cert/cafile_info.ts.out3
-rw-r--r--cli/tests/testdata/info/031_info_ts_error.out4
-rw-r--r--cli/tests/testdata/info/049_info_flag_script_jsx.out3
-rw-r--r--cli/tests/testdata/info/054_info_local_imports.out3
-rw-r--r--cli/tests/testdata/info/065_import_map_info.out4
-rw-r--r--cli/tests/testdata/info/data_null_error/data_null_error.out3
-rw-r--r--cli/tests/testdata/info/info_missing_module.out3
-rw-r--r--cli/tests/testdata/info/info_recursive_imports_test.out3
-rw-r--r--cli/tests/testdata/info/info_type_import.out4
-rw-r--r--cli/tests/testdata/info/multiple_imports.out3
-rw-r--r--cli/tests/testdata/info/types_header.out3
-rw-r--r--cli/tests/testdata/info/with_config/with_config.out3
-rw-r--r--cli/tests/testdata/npm/cjs_with_deps/main.info.out22
-rw-r--r--cli/tests/testdata/npm/deno_info_chalk.out10
-rw-r--r--cli/tests/testdata/run/017_import_redirect_info.out3
-rw-r--r--cli/tools/info.rs947
24 files changed, 577 insertions, 542 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index c313515e3..90899704e 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -1212,6 +1212,7 @@ TypeScript compiler cache: Subdirectory containing TS compiler output.",
.arg(no_config_arg())
.arg(config_arg())
.arg(import_map_arg())
+ .arg(local_npm_arg())
.arg(
Arg::new("json")
.long("json")
@@ -2512,6 +2513,7 @@ fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
import_map_arg_parse(flags, matches);
location_arg_parse(flags, matches);
ca_file_arg_parse(flags, matches);
+ local_npm_args_parse(flags, matches);
let json = matches.is_present("json");
flags.subcommand = DenoSubcommand::Info(InfoFlags {
file: matches.value_of("file").map(|f| f.to_string()),
diff --git a/cli/fs_util.rs b/cli/fs_util.rs
index 365c9b430..fa1535469 100644
--- a/cli/fs_util.rs
+++ b/cli/fs_util.rs
@@ -1,7 +1,8 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::anyhow::Context;
-use deno_core::error::{uri_error, AnyError};
+use deno_core::error::uri_error;
+use deno_core::error::AnyError;
pub use deno_core::normalize_path;
use deno_core::ModuleSpecifier;
use deno_runtime::deno_crypto::rand;
@@ -9,8 +10,11 @@ use deno_runtime::deno_node::PathClean;
use std::borrow::Cow;
use std::env::current_dir;
use std::fs::OpenOptions;
-use std::io::{Error, ErrorKind, Write};
-use std::path::{Path, PathBuf};
+use std::io::Error;
+use std::io::ErrorKind;
+use std::io::Write;
+use std::path::Path;
+use std::path::PathBuf;
use walkdir::WalkDir;
pub fn atomic_write_file<T: AsRef<[u8]>>(
@@ -573,6 +577,20 @@ pub fn root_url_to_safe_local_dirname(root: &ModuleSpecifier) -> PathBuf {
result
}
+/// Gets the total size (in bytes) of a directory.
+pub fn dir_size(path: &Path) -> std::io::Result<u64> {
+ let entries = std::fs::read_dir(path)?;
+ let mut total = 0;
+ for entry in entries {
+ let entry = entry?;
+ total += match entry.metadata()? {
+ data if data.is_dir() => dir_size(&entry.path())?,
+ data => data.len(),
+ };
+ }
+ Ok(total)
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/cli/npm/resolution.rs b/cli/npm/resolution.rs
index 7cd4df124..28a42bc33 100644
--- a/cli/npm/resolution.rs
+++ b/cli/npm/resolution.rs
@@ -697,6 +697,13 @@ impl NpmResolution {
Ok(snapshot)
}
+ pub fn resolve_package_from_id(
+ &self,
+ id: &NpmPackageId,
+ ) -> Option<NpmResolutionPackage> {
+ self.snapshot.read().package_from_id(id).cloned()
+ }
+
pub fn resolve_package_from_package(
&self,
name: &str,
diff --git a/cli/npm/resolvers/common.rs b/cli/npm/resolvers/common.rs
index e114f3f8a..07996c4e1 100644
--- a/cli/npm/resolvers/common.rs
+++ b/cli/npm/resolvers/common.rs
@@ -15,6 +15,7 @@ use crate::lockfile::Lockfile;
use crate::npm::cache::should_sync_download;
use crate::npm::resolution::NpmResolutionSnapshot;
use crate::npm::NpmCache;
+use crate::npm::NpmPackageId;
use crate::npm::NpmPackageReq;
use crate::npm::NpmResolutionPackage;
@@ -36,6 +37,8 @@ pub trait InnerNpmPackageResolver: Send + Sync {
specifier: &ModuleSpecifier,
) -> Result<PathBuf, AnyError>;
+ fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError>;
+
fn has_packages(&self) -> bool;
fn add_package_reqs(
diff --git a/cli/npm/resolvers/global.rs b/cli/npm/resolvers/global.rs
index 996f55c2d..42090415a 100644
--- a/cli/npm/resolvers/global.rs
+++ b/cli/npm/resolvers/global.rs
@@ -15,6 +15,7 @@ use deno_core::url::Url;
use deno_runtime::deno_node::PackageJson;
use deno_runtime::deno_node::TYPES_CONDITIONS;
+use crate::fs_util;
use crate::lockfile::Lockfile;
use crate::npm::resolution::NpmResolution;
use crate::npm::resolution::NpmResolutionSnapshot;
@@ -110,6 +111,11 @@ impl InnerNpmPackageResolver for GlobalNpmPackageResolver {
Ok(self.package_folder(&pkg_id))
}
+ fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> {
+ let package_folder = self.package_folder(package_id);
+ Ok(fs_util::dir_size(&package_folder)?)
+ }
+
fn has_packages(&self) -> bool {
self.resolution.has_packages()
}
diff --git a/cli/npm/resolvers/local.rs b/cli/npm/resolvers/local.rs
index 6c4c4ef6c..cad940d56 100644
--- a/cli/npm/resolvers/local.rs
+++ b/cli/npm/resolvers/local.rs
@@ -177,6 +177,22 @@ impl InnerNpmPackageResolver for LocalNpmPackageResolver {
Ok(package_root_path)
}
+ fn package_size(&self, package_id: &NpmPackageId) -> Result<u64, AnyError> {
+ match self.resolution.resolve_package_from_id(package_id) {
+ Some(package) => Ok(fs_util::dir_size(
+ // package is stored at:
+ // node_modules/.deno/<package_id>/node_modules/<package_name>
+ &self
+ .root_node_modules_path
+ .join(".deno")
+ .join(package.id.to_string())
+ .join("node_modules")
+ .join(package.id.name),
+ )?),
+ None => bail!("Could not find package folder for '{}'", package_id),
+ }
+ }
+
fn has_packages(&self) -> bool {
self.resolution.has_packages()
}
diff --git a/cli/npm/resolvers/mod.rs b/cli/npm/resolvers/mod.rs
index 3d55170ac..71c2abc00 100644
--- a/cli/npm/resolvers/mod.rs
+++ b/cli/npm/resolvers/mod.rs
@@ -27,6 +27,7 @@ use crate::lockfile::Lockfile;
use self::common::InnerNpmPackageResolver;
use self::local::LocalNpmPackageResolver;
use super::NpmCache;
+use super::NpmPackageId;
use super::NpmPackageReq;
use super::NpmRegistryApi;
use super::NpmResolutionSnapshot;
@@ -212,6 +213,14 @@ impl NpmPackageResolver {
Ok(path)
}
+ /// Attempts to get the package size in bytes.
+ pub fn package_size(
+ &self,
+ package_id: &NpmPackageId,
+ ) -> Result<u64, AnyError> {
+ self.inner.package_size(package_id)
+ }
+
/// Gets if the provided specifier is in an npm package.
pub fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
self
@@ -301,10 +310,14 @@ impl NpmPackageResolver {
self.unstable,
self.no_npm,
self.local_node_modules_path.clone(),
- Some(self.inner.snapshot()),
+ Some(self.snapshot()),
)
}
+ pub fn snapshot(&self) -> NpmResolutionSnapshot {
+ self.inner.snapshot()
+ }
+
pub fn lock(&self, lockfile: &mut Lockfile) -> Result<(), AnyError> {
self.inner.lock(lockfile)
}
diff --git a/cli/tests/integration/npm_tests.rs b/cli/tests/integration/npm_tests.rs
index 9e3ef5678..0ca1ae910 100644
--- a/cli/tests/integration/npm_tests.rs
+++ b/cli/tests/integration/npm_tests.rs
@@ -733,6 +733,31 @@ itest!(compile_errors {
http_server: true,
});
+itest!(info_chalk {
+ args: "info --quiet --unstable npm/cjs_with_deps/main.js",
+ output: "npm/cjs_with_deps/main.info.out",
+ exit_code: 0,
+ envs: env_vars(),
+ http_server: true,
+});
+
+itest!(info_chalk_node_modules_dir {
+ args: "info --quiet --unstable --node-modules-dir $TESTDATA/npm/cjs_with_deps/main.js",
+ output: "npm/cjs_with_deps/main.info.out",
+ exit_code: 0,
+ envs: env_vars(),
+ http_server: true,
+ temp_cwd: true,
+});
+
+itest!(info_cli_chalk {
+ args: "info --quiet --unstable npm:chalk@4",
+ output: "npm/deno_info_chalk.out",
+ exit_code: 0,
+ envs: env_vars(),
+ http_server: true,
+});
+
fn env_vars_no_sync_download() -> Vec<(String, String)> {
vec![
("DENO_NODE_COMPAT_URL".to_string(), util::std_file_url()),
diff --git a/cli/tests/testdata/cert/cafile_info.ts.out b/cli/tests/testdata/cert/cafile_info.ts.out
index 4c7e6c6c7..ddece3019 100644
--- a/cli/tests/testdata/cert/cafile_info.ts.out
+++ b/cli/tests/testdata/cert/cafile_info.ts.out
@@ -1,6 +1,7 @@
local: [WILDCARD]https[WILDCARD]localhost_PORT5545[WILDCARD]
type: TypeScript
-dependencies: 8 unique (total [WILDCARD])
+dependencies: 8 unique
+size: [WILDCARD]
https://localhost:5545/cert/cafile_info.ts ([WILDCARD])
├── https://localhost:5545/subdir/mt_application_ecmascript.j2.js ([WILDCARD])
diff --git a/cli/tests/testdata/info/031_info_ts_error.out b/cli/tests/testdata/info/031_info_ts_error.out
index 2dc7bb4e8..49df50012 100644
--- a/cli/tests/testdata/info/031_info_ts_error.out
+++ b/cli/tests/testdata/info/031_info_ts_error.out
@@ -1,5 +1,7 @@
[WILDCARD]
local: [WILDCARD]031_info_ts_error.ts
type: TypeScript
-dependencies: 0 unique (total [WILDCARD])
+dependencies: 0 unique
+size: [WILDCARD]
+
[WILDCARD]031_info_ts_error.ts ([WILDCARD])
diff --git a/cli/tests/testdata/info/049_info_flag_script_jsx.out b/cli/tests/testdata/info/049_info_flag_script_jsx.out
index 16736c893..244541696 100644
--- a/cli/tests/testdata/info/049_info_flag_script_jsx.out
+++ b/cli/tests/testdata/info/049_info_flag_script_jsx.out
@@ -1,7 +1,8 @@
[WILDCARD]
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
type: TypeScript
-dependencies: 8 unique (total [WILDCARD])
+dependencies: 8 unique
+size: [WILDCARD]
http://127.0.0.1:4545/run/048_media_types_jsx.ts ([WILDCARD])
├── http://localhost:4545/subdir/mt_application_ecmascript_jsx.j2.jsx ([WILDCARD])
diff --git a/cli/tests/testdata/info/054_info_local_imports.out b/cli/tests/testdata/info/054_info_local_imports.out
index cde5ff3ab..ee1773b76 100644
--- a/cli/tests/testdata/info/054_info_local_imports.out
+++ b/cli/tests/testdata/info/054_info_local_imports.out
@@ -1,6 +1,7 @@
local: [WILDCARD]005_more_imports.ts
type: TypeScript
-dependencies: 3 unique (total [WILDCARD])
+dependencies: 3 unique
+size: [WILDCARD]
file://[WILDCARD]/005_more_imports.ts ([WILDCARD])
└─┬ file://[WILDCARD]/subdir/mod1.ts ([WILDCARD])
diff --git a/cli/tests/testdata/info/065_import_map_info.out b/cli/tests/testdata/info/065_import_map_info.out
index 8771d0594..657510b89 100644
--- a/cli/tests/testdata/info/065_import_map_info.out
+++ b/cli/tests/testdata/info/065_import_map_info.out
@@ -1,5 +1,7 @@
[WILDCARD]
local: [WILDCARD]test.ts
type: TypeScript
-dependencies: 7 unique (total [WILDCARD])
+dependencies: 7 unique
+size: [WILDCARD]
+
[WILDCARD]
diff --git a/cli/tests/testdata/info/data_null_error/data_null_error.out b/cli/tests/testdata/info/data_null_error/data_null_error.out
index 89961be65..065396f18 100644
--- a/cli/tests/testdata/info/data_null_error/data_null_error.out
+++ b/cli/tests/testdata/info/data_null_error/data_null_error.out
@@ -1,6 +1,7 @@
local: [WILDCARD]mod.ts
type: TypeScript
-dependencies: 1 unique (total [WILDCARD])
+dependencies: 1 unique
+size: [WILDCARD]
file://[WILDCARD]/mod.ts ([WILDCARD])
└── file://[WILDCARD]/types.d.ts ([WILDCARD])
diff --git a/cli/tests/testdata/info/info_missing_module.out b/cli/tests/testdata/info/info_missing_module.out
index 07f893eec..c62d690c1 100644
--- a/cli/tests/testdata/info/info_missing_module.out
+++ b/cli/tests/testdata/info/info_missing_module.out
@@ -1,6 +1,7 @@
local: [WILDCARD]error_009_missing_js_module.js
type: JavaScript
-dependencies: 0 unique (total 26B)
+dependencies: 0 unique
+size: 26B
file://[WILDCARD]/error_009_missing_js_module.js (26B)
└── file://[WILDCARD]/bad-module.js (missing)
diff --git a/cli/tests/testdata/info/info_recursive_imports_test.out b/cli/tests/testdata/info/info_recursive_imports_test.out
index 10ee54534..3340f3859 100644
--- a/cli/tests/testdata/info/info_recursive_imports_test.out
+++ b/cli/tests/testdata/info/info_recursive_imports_test.out
@@ -1,6 +1,7 @@
local: [WILDCARD]info_recursive_imports_test.ts
type: TypeScript
-dependencies: 4 unique (total [WILDCARD])
+dependencies: 4 unique
+size: [WILDCARD]
file://[WILDCARD]/info_recursive_imports_test.ts ([WILDCARD])
└─┬ file://[WILDCARD]/recursive_imports/A.ts ([WILDCARD])
diff --git a/cli/tests/testdata/info/info_type_import.out b/cli/tests/testdata/info/info_type_import.out
index 6b9869f1f..0423efe82 100644
--- a/cli/tests/testdata/info/info_type_import.out
+++ b/cli/tests/testdata/info/info_type_import.out
@@ -1,5 +1,7 @@
local: [WILDCARD]info_type_import.ts
type: TypeScript
-dependencies: 1 unique (total [WILDCARD])
+dependencies: 1 unique
+size: [WILDCARD]
+
[WILDCARD]info_type_import.ts ([WILDCARD])
└── [WILDCARD]type_and_code.ts ([WILDCARD])
diff --git a/cli/tests/testdata/info/multiple_imports.out b/cli/tests/testdata/info/multiple_imports.out
index d4e315397..ea35e69c8 100644
--- a/cli/tests/testdata/info/multiple_imports.out
+++ b/cli/tests/testdata/info/multiple_imports.out
@@ -1,7 +1,8 @@
[WILDCARD]
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
type: TypeScript
-dependencies: 8 unique (total [WILDCARD])
+dependencies: 8 unique
+size: [WILDCARD]
http://127.0.0.1:4545/run/019_media_types.ts ([WILDCARD])
├── http://localhost:4545/subdir/mt_application_ecmascript.j2.js ([WILDCARD])
diff --git a/cli/tests/testdata/info/types_header.out b/cli/tests/testdata/info/types_header.out
index d3b6e8c4e..722e02f77 100644
--- a/cli/tests/testdata/info/types_header.out
+++ b/cli/tests/testdata/info/types_header.out
@@ -1,7 +1,8 @@
[WILDCARD]
local: [WILDCARD]type_directives_01.ts
type: TypeScript
-dependencies: 2 unique (total [WILDCARD])
+dependencies: 2 unique
+size: [WILDCARD]
[WILDCARD]/type_directives_01.ts ([WILDCARD])
└─┬ http://127.0.0.1:4545/xTypeScriptTypes.js ([WILDCARD])
diff --git a/cli/tests/testdata/info/with_config/with_config.out b/cli/tests/testdata/info/with_config/with_config.out
index b707c24d0..95a1f30bc 100644
--- a/cli/tests/testdata/info/with_config/with_config.out
+++ b/cli/tests/testdata/info/with_config/with_config.out
@@ -1,6 +1,7 @@
Warning the configuration file "[WILDCARD]/deno-override.json" contains an entry for "importMap" that is being ignored.
local: [WILDCARD]test.ts
type: TypeScript
-dependencies: 0 unique (total [WILDCARD])
+dependencies: 0 unique
+size: [WILDCARD]
file:///[WILDCARD]/test.ts ([WILDCARD])
diff --git a/cli/tests/testdata/npm/cjs_with_deps/main.info.out b/cli/tests/testdata/npm/cjs_with_deps/main.info.out
new file mode 100644
index 000000000..345583a90
--- /dev/null
+++ b/cli/tests/testdata/npm/cjs_with_deps/main.info.out
@@ -0,0 +1,22 @@
+local: [WILDCARD]main.js
+type: JavaScript
+dependencies: 14 unique
+size: [WILDCARD]
+
+file:///[WILDCARD]/npm/cjs_with_deps/main.js ([WILDCARD])
+├─┬ npm:chai@4.3 - 4.3.6 ([WILDCARD])
+│ ├── npm:assertion-error@1.1.0 ([WILDCARD])
+│ ├── npm:check-error@1.0.2 ([WILDCARD])
+│ ├─┬ npm:deep-eql@3.0.1 ([WILDCARD])
+│ │ └── npm:type-detect@4.0.8 ([WILDCARD])
+│ ├── npm:get-func-name@2.0.0 ([WILDCARD])
+│ ├─┬ npm:loupe@2.3.4 ([WILDCARD])
+│ │ └── npm:get-func-name@2.0.0 ([WILDCARD])
+│ ├── npm:pathval@1.1.1 ([WILDCARD])
+│ └── npm:type-detect@4.0.8 ([WILDCARD])
+└─┬ npm:chalk@4 - 4.1.2 ([WILDCARD])
+ ├─┬ npm:ansi-styles@4.3.0 ([WILDCARD])
+ │ └─┬ npm:color-convert@2.0.1 ([WILDCARD])
+ │ └── npm:color-name@1.1.4 ([WILDCARD])
+ └─┬ npm:supports-color@7.2.0 ([WILDCARD])
+ └── npm:has-flag@4.0.0 ([WILDCARD])
diff --git a/cli/tests/testdata/npm/deno_info_chalk.out b/cli/tests/testdata/npm/deno_info_chalk.out
new file mode 100644
index 000000000..89ea05e71
--- /dev/null
+++ b/cli/tests/testdata/npm/deno_info_chalk.out
@@ -0,0 +1,10 @@
+type: Unknown
+dependencies: 5 unique
+size: [WILDCARD]
+
+npm:chalk@4 - 4.1.2 ([WILDCARD])
+├─┬ npm:ansi-styles@4.3.0 ([WILDCARD])
+│ └─┬ npm:color-convert@2.0.1 ([WILDCARD])
+│ └── npm:color-name@1.1.4 ([WILDCARD])
+└─┬ npm:supports-color@7.2.0 ([WILDCARD])
+ └── npm:has-flag@4.0.0 ([WILDCARD])
diff --git a/cli/tests/testdata/run/017_import_redirect_info.out b/cli/tests/testdata/run/017_import_redirect_info.out
index d3a2e86fc..d1850ccb5 100644
--- a/cli/tests/testdata/run/017_import_redirect_info.out
+++ b/cli/tests/testdata/run/017_import_redirect_info.out
@@ -1,6 +1,7 @@
local: [WILDCARD]017_import_redirect.ts
type: TypeScript
-dependencies: 1 unique (total 278B)
+dependencies: 1 unique
+size: 278B
file:///[WILDCARD]/017_import_redirect.ts ([WILDCARD])
└── https://gist.githubusercontent.com/ry/f12b2aa3409e6b52645bc346a9e22929/raw/79318f239f51d764384a8bded8d7c6a833610dde/print_hello.ts ([WILDCARD])
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()
}