mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 21:50:00 -05:00
refactor(cli): move info subcommand over to new module graph (#7892)
This commit is contained in:
parent
fede13f2eb
commit
e877b36072
11 changed files with 556 additions and 546 deletions
644
cli/info.rs
644
cli/info.rs
|
@ -1,404 +1,197 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::global_state::GlobalState;
|
use crate::media_type::serialize_media_type;
|
||||||
use crate::module_graph::{ModuleGraph, ModuleGraphFile, ModuleGraphLoader};
|
use crate::MediaType;
|
||||||
use crate::ModuleSpecifier;
|
use crate::ModuleSpecifier;
|
||||||
use crate::Permissions;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use serde::ser::Serializer;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
use serde::Serializer;
|
||||||
use std::sync::Arc;
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
// TODO(bartlomieju): rename
|
/// The core structure representing information about a specific "root" file in
|
||||||
/// Struct containing a module's dependency information.
|
/// a module graph. This is used to represent information as part of the `info`
|
||||||
#[derive(Serialize)]
|
/// subcommand.
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ModuleDepInfo {
|
pub struct ModuleGraphInfo {
|
||||||
module: String,
|
pub compiled: Option<PathBuf>,
|
||||||
local: String,
|
pub dep_count: usize,
|
||||||
file_type: String,
|
#[serde(serialize_with = "serialize_media_type")]
|
||||||
compiled: Option<String>,
|
pub file_type: MediaType,
|
||||||
map: Option<String>,
|
pub files: ModuleInfoMap,
|
||||||
dep_count: usize,
|
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
deps: FileInfoDepTree,
|
pub info: ModuleInfo,
|
||||||
total_size: Option<usize>,
|
pub local: PathBuf,
|
||||||
files: FileInfoDepFlatGraph,
|
pub map: Option<PathBuf>,
|
||||||
|
pub module: ModuleSpecifier,
|
||||||
|
pub total_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleDepInfo {
|
impl fmt::Display for ModuleGraphInfo {
|
||||||
/// Creates a new `ModuleDepInfo` struct for the module with the provided `ModuleSpecifier`.
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
pub async fn new(
|
writeln!(
|
||||||
global_state: &Arc<GlobalState>,
|
f,
|
||||||
module_specifier: ModuleSpecifier,
|
"{} {}",
|
||||||
) -> Result<Self, AnyError> {
|
colors::bold("local:"),
|
||||||
// First load module as if it was to be executed by worker
|
self.local.to_string_lossy()
|
||||||
// including compilation step
|
)?;
|
||||||
let mut module_graph_loader = ModuleGraphLoader::new(
|
writeln!(f, "{} {}", colors::bold("type:"), self.file_type)?;
|
||||||
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 =
|
|
||||||
crate::media_type::enum_name_media_type(out.media_type).to_string();
|
|
||||||
|
|
||||||
let deps = FileInfoDepTree::new(&module_graph, &module_specifier);
|
|
||||||
let total_size = deps.total_size;
|
|
||||||
let dep_count = get_unique_dep_count(&module_graph) - 1;
|
|
||||||
let files = FileInfoDepFlatGraph::new(&module_graph);
|
|
||||||
|
|
||||||
let info = Self {
|
|
||||||
module: module_specifier.to_string(),
|
|
||||||
local: local_filename,
|
|
||||||
file_type,
|
|
||||||
compiled: compiled_filename,
|
|
||||||
map: map_filename,
|
|
||||||
dep_count,
|
|
||||||
deps,
|
|
||||||
total_size,
|
|
||||||
files,
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
if let Some(ref compiled) = self.compiled {
|
||||||
f.write_fmt(format_args!(
|
writeln!(
|
||||||
"{} {}\n",
|
f,
|
||||||
|
"{} {}",
|
||||||
colors::bold("compiled:"),
|
colors::bold("compiled:"),
|
||||||
compiled
|
compiled.to_string_lossy()
|
||||||
))?;
|
)?;
|
||||||
}
|
}
|
||||||
if let Some(ref map) = self.map {
|
if let Some(ref map) = self.map {
|
||||||
f.write_fmt(format_args!("{} {}\n", colors::bold("map:"), map))?;
|
writeln!(f, "{} {}", colors::bold("map:"), map.to_string_lossy())?;
|
||||||
}
|
}
|
||||||
|
writeln!(
|
||||||
f.write_fmt(format_args!(
|
f,
|
||||||
"{} {} unique {}\n",
|
"{} {} unique {}",
|
||||||
colors::bold("deps:"),
|
colors::bold("deps:"),
|
||||||
self.dep_count,
|
self.dep_count,
|
||||||
colors::gray(&format!(
|
colors::gray(&format!(
|
||||||
"(total {})",
|
"(total {})",
|
||||||
human_size(self.deps.total_size.unwrap_or(0) as f64),
|
human_size(self.info.total_size.unwrap_or(0) as f64)
|
||||||
))
|
))
|
||||||
))?;
|
)?;
|
||||||
f.write_fmt(format_args!(
|
writeln!(f)?;
|
||||||
"{} {}\n",
|
writeln!(
|
||||||
self.deps.name,
|
f,
|
||||||
colors::gray(&format!("({})", human_size(self.deps.size as f64)))
|
"{} {}",
|
||||||
))?;
|
self.info.name,
|
||||||
|
colors::gray(&format!("({})", human_size(self.info.size as f64)))
|
||||||
|
)?;
|
||||||
|
|
||||||
for (idx, dep) in self.deps.deps.iter().enumerate() {
|
let dep_count = self.info.deps.len();
|
||||||
print_file_dep_info(&dep, "", idx == self.deps.deps.len() - 1, f)?;
|
for (idx, dep) in self.info.deps.iter().enumerate() {
|
||||||
|
dep.write_info(f, "", idx == dep_count - 1)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A dependency tree of the basic module information.
|
/// Represents a unique dependency within the graph of the the dependencies for
|
||||||
///
|
/// a given module.
|
||||||
/// Constructed from a `ModuleGraph` and `ModuleSpecifier` that
|
#[derive(Debug, Serialize, Eq, PartialEq)]
|
||||||
/// acts as the root of the tree.
|
|
||||||
#[derive(Serialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct FileInfoDepTree {
|
pub struct ModuleInfo {
|
||||||
name: String,
|
pub deps: Vec<ModuleInfo>,
|
||||||
size: usize,
|
pub name: ModuleSpecifier,
|
||||||
total_size: Option<usize>,
|
pub size: usize,
|
||||||
deps: Vec<FileInfoDepTree>,
|
pub total_size: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileInfoDepTree {
|
impl PartialOrd for ModuleInfo {
|
||||||
/// Create a `FileInfoDepTree` tree from a `ModuleGraph` and the root `ModuleSpecifier`.
|
fn partial_cmp(&self, other: &ModuleInfo) -> Option<Ordering> {
|
||||||
pub fn new(
|
Some(self.cmp(other))
|
||||||
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.
|
impl Ord for ModuleInfo {
|
||||||
///
|
fn cmp(&self, other: &ModuleInfo) -> Ordering {
|
||||||
/// If currently visited module has not yet been seen it will be annotated with dependencies
|
self.name.to_string().cmp(&other.name.to_string())
|
||||||
/// 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 {
|
impl ModuleInfo {
|
||||||
let mut seen_deps = HashSet::new();
|
pub fn write_info(
|
||||||
deps = file
|
&self,
|
||||||
.imports
|
f: &mut fmt::Formatter<'_>,
|
||||||
.iter()
|
prefix: &str,
|
||||||
.map(|import| &import.resolved_specifier)
|
last: bool,
|
||||||
.filter(|module_specifier| {
|
) -> fmt::Result {
|
||||||
seen_deps.insert(module_specifier.as_str().to_string())
|
let sibling_connector = if last { '└' } else { '├' };
|
||||||
})
|
let child_connector = if self.deps.is_empty() { '─' } else { '┬' };
|
||||||
.map(|specifier| {
|
let totals = if self.total_size.is_some() {
|
||||||
Self::visit_module(seen, total_sizes, graph, specifier)
|
colors::gray(&format!(" ({})", human_size(self.size as f64)))
|
||||||
})
|
} else {
|
||||||
.collect::<Vec<_>>();
|
colors::gray(" *")
|
||||||
|
};
|
||||||
|
|
||||||
total_size = if let Some(total_size) = total_sizes.get(&name) {
|
writeln!(
|
||||||
Some(total_size.to_owned())
|
f,
|
||||||
} else {
|
"{} {}{}",
|
||||||
let total: usize = deps
|
colors::gray(&format!(
|
||||||
.iter()
|
"{}{}─{}",
|
||||||
.map(|dep| {
|
prefix, sibling_connector, child_connector
|
||||||
if let Some(total_size) = dep.total_size {
|
)),
|
||||||
total_size
|
self.name,
|
||||||
} else {
|
totals
|
||||||
0
|
)?;
|
||||||
}
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
let total = size + total;
|
|
||||||
|
|
||||||
total_sizes.insert(name.clone(), total);
|
let mut prefix = prefix.to_string();
|
||||||
|
if last {
|
||||||
|
prefix.push(' ');
|
||||||
|
} else {
|
||||||
|
prefix.push('│');
|
||||||
|
}
|
||||||
|
prefix.push(' ');
|
||||||
|
|
||||||
Some(total)
|
let dep_count = self.deps.len();
|
||||||
};
|
for (idx, dep) in self.deps.iter().enumerate() {
|
||||||
|
dep.write_info(f, &prefix, idx == dep_count - 1)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Ok(())
|
||||||
name,
|
|
||||||
size,
|
|
||||||
total_size,
|
|
||||||
deps,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flat graph vertex with all shallow dependencies
|
/// A flat map of dependencies for a given module graph.
|
||||||
#[derive(Serialize)]
|
#[derive(Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
pub struct ModuleInfoMap(pub HashMap<ModuleSpecifier, ModuleInfoMapItem>);
|
||||||
struct FileInfoVertex {
|
|
||||||
size: usize,
|
|
||||||
deps: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FileInfoVertex {
|
impl ModuleInfoMap {
|
||||||
/// Creates new `FileInfoVertex` that is a single vertex dependency module
|
pub fn new(map: HashMap<ModuleSpecifier, ModuleInfoMapItem>) -> Self {
|
||||||
fn new(size: usize, deps: Vec<String>) -> Self {
|
ModuleInfoMap(map)
|
||||||
Self { size, deps }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileInfoDepFlatGraph(HashMap<String, FileInfoVertex>);
|
impl Serialize for ModuleInfoMap {
|
||||||
|
|
||||||
impl FileInfoDepFlatGraph {
|
|
||||||
/// Creates new `FileInfoDepFlatGraph`, flat graph of a shallow module dependencies
|
|
||||||
///
|
|
||||||
/// Each graph vertex represents unique dependency with its all shallow dependencies
|
|
||||||
fn new(module_graph: &ModuleGraph) -> Self {
|
|
||||||
let mut inner = HashMap::new();
|
|
||||||
module_graph
|
|
||||||
.iter()
|
|
||||||
.for_each(|(module_name, module_graph_file)| {
|
|
||||||
let size = module_graph_file.size();
|
|
||||||
let mut deps = Vec::new();
|
|
||||||
module_graph_file.imports.iter().for_each(|import| {
|
|
||||||
deps.push(import.resolved_specifier.to_string());
|
|
||||||
});
|
|
||||||
inner.insert(module_name.clone(), FileInfoVertex::new(size, deps));
|
|
||||||
});
|
|
||||||
Self(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for FileInfoDepFlatGraph {
|
|
||||||
/// Serializes inner hash map which is ordered by the key
|
/// Serializes inner hash map which is ordered by the key
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
let ordered: BTreeMap<_, _> = self.0.iter().collect();
|
let ordered: BTreeMap<_, _> =
|
||||||
|
self.0.iter().map(|(k, v)| (k.to_string(), v)).collect();
|
||||||
ordered.serialize(serializer)
|
ordered.serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a `ModuleGraphFile` associated to the provided `ModuleSpecifier`.
|
/// An entry in the `ModuleInfoMap` the provides the size of the module and
|
||||||
///
|
/// a vector of its dependencies, which should also be available as entries
|
||||||
/// If the `specifier` is associated with a file that has a populated redirect field,
|
/// in the map.
|
||||||
/// it returns the file associated to the redirect, otherwise the file associated to `specifier`.
|
#[derive(Debug, Serialize)]
|
||||||
fn get_resolved_file<'a>(
|
#[serde(rename_all = "camelCase")]
|
||||||
graph: &'a ModuleGraph,
|
pub struct ModuleInfoMapItem {
|
||||||
specifier: &ModuleSpecifier,
|
pub deps: Vec<ModuleSpecifier>,
|
||||||
) -> &'a ModuleGraphFile {
|
pub size: usize,
|
||||||
// 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.
|
/// A function that converts a float to a string the represents a human
|
||||||
fn print_file_dep_info(
|
/// readable version of that number.
|
||||||
info: &FileInfoDepTree,
|
pub fn human_size(size: f64) -> String {
|
||||||
prefix: &str,
|
let negative = if size.is_sign_positive() { "" } else { "-" };
|
||||||
is_last: bool,
|
let size = size.abs();
|
||||||
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"];
|
let units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
if bytse < 1_f64 {
|
if size < 1_f64 {
|
||||||
return format!("{}{}{}", negative, bytse, "B");
|
return format!("{}{}{}", negative, size, "B");
|
||||||
}
|
}
|
||||||
let delimiter = 1024_f64;
|
let delimiter = 1024_f64;
|
||||||
let exponent = std::cmp::min(
|
let exponent = std::cmp::min(
|
||||||
(bytse.ln() / delimiter.ln()).floor() as i32,
|
(size.ln() / delimiter.ln()).floor() as i32,
|
||||||
(units.len() - 1) as i32,
|
(units.len() - 1) as i32,
|
||||||
);
|
);
|
||||||
let pretty_bytes = format!("{:.2}", bytse / delimiter.powi(exponent))
|
let pretty_bytes = format!("{:.2}", size / delimiter.powi(exponent))
|
||||||
.parse::<f64>()
|
.parse::<f64>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
* 1_f64;
|
* 1_f64;
|
||||||
|
@ -409,10 +202,7 @@ pub fn human_size(bytse: f64) -> String {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::Location;
|
use deno_core::serde_json::json;
|
||||||
use crate::media_type::MediaType;
|
|
||||||
use crate::module_graph::ImportDescriptor;
|
|
||||||
use deno_core::url::Url;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn human_size_test() {
|
fn human_size_test() {
|
||||||
|
@ -427,105 +217,89 @@ mod test {
|
||||||
assert_eq!(human_size(16_f64 * 1024_f64.powf(8.0)), "16YB");
|
assert_eq!(human_size(16_f64 * 1024_f64.powf(8.0)), "16YB");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn get_fixture() -> ModuleGraphInfo {
|
||||||
fn get_new_prefix_adds_spaces_if_is_last() {
|
let spec_c =
|
||||||
let prefix = get_new_prefix("", true);
|
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/a/b/c.ts")
|
||||||
|
.unwrap();
|
||||||
assert_eq!(prefix, " ".to_string());
|
let spec_d =
|
||||||
}
|
ModuleSpecifier::resolve_url_or_path("https://deno.land/x/a/b/c.ts")
|
||||||
|
.unwrap();
|
||||||
#[test]
|
let deps = vec![ModuleInfo {
|
||||||
fn get_new_prefix_adds_a_vertical_bar_if_not_is_last() {
|
deps: Vec::new(),
|
||||||
let prefix = get_new_prefix("", false);
|
name: spec_d.clone(),
|
||||||
|
size: 12345,
|
||||||
assert_eq!(prefix, "│ ".to_string());
|
total_size: None,
|
||||||
}
|
}];
|
||||||
|
let info = ModuleInfo {
|
||||||
fn create_mock_file(
|
deps,
|
||||||
name: &str,
|
name: spec_c.clone(),
|
||||||
imports: Vec<ModuleSpecifier>,
|
size: 12345,
|
||||||
redirect: Option<ModuleSpecifier>,
|
total_size: Some(12345),
|
||||||
) -> (ModuleGraphFile, ModuleSpecifier) {
|
|
||||||
let spec =
|
|
||||||
ModuleSpecifier::from(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(),
|
|
||||||
};
|
};
|
||||||
|
let mut items = HashMap::new();
|
||||||
|
items.insert(
|
||||||
|
spec_c,
|
||||||
|
ModuleInfoMapItem {
|
||||||
|
deps: vec![spec_d.clone()],
|
||||||
|
size: 12345,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
items.insert(
|
||||||
|
spec_d,
|
||||||
|
ModuleInfoMapItem {
|
||||||
|
deps: Vec::new(),
|
||||||
|
size: 12345,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let files = ModuleInfoMap(items);
|
||||||
|
|
||||||
(file, spec)
|
ModuleGraphInfo {
|
||||||
|
compiled: Some(PathBuf::from("/a/b/c.js")),
|
||||||
|
dep_count: 99,
|
||||||
|
file_type: MediaType::TypeScript,
|
||||||
|
files,
|
||||||
|
info,
|
||||||
|
local: PathBuf::from("/a/b/c.ts"),
|
||||||
|
map: None,
|
||||||
|
module: ModuleSpecifier::resolve_url_or_path(
|
||||||
|
"https://deno.land/x/a/b/c.ts",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
total_size: 999999,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_resolved_file_test() {
|
fn test_module_graph_info_display() {
|
||||||
let (test_file_redirect, redirect) =
|
let fixture = get_fixture();
|
||||||
create_mock_file("test_redirect", vec![], None);
|
let actual = format!("{}", fixture);
|
||||||
let (test_file, original) =
|
assert!(actual.contains(" /a/b/c.ts"));
|
||||||
create_mock_file("test", vec![], Some(redirect.clone()));
|
assert!(actual.contains(" 99 unique"));
|
||||||
|
assert!(actual.contains("(12.06KB)"));
|
||||||
let mut graph = ModuleGraph::new();
|
assert!(actual.contains("\n\nhttps://deno.land/x/a/b/c.ts"));
|
||||||
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]
|
#[test]
|
||||||
fn dependency_count_no_redirects() {
|
fn test_module_graph_info_json() {
|
||||||
let (a, aspec) = create_mock_file("a", vec![], None);
|
let fixture = get_fixture();
|
||||||
let (b, bspec) = create_mock_file("b", vec![aspec.clone()], None);
|
let actual = json!(fixture);
|
||||||
let (c, cspec) = create_mock_file("c", vec![bspec.clone()], None);
|
assert_eq!(
|
||||||
|
actual,
|
||||||
let mut graph = ModuleGraph::new();
|
json!({
|
||||||
|
"compiled": "/a/b/c.js",
|
||||||
graph.insert(aspec.to_string(), a);
|
"depCount": 99,
|
||||||
graph.insert(bspec.to_string(), b);
|
"fileType": "TypeScript",
|
||||||
graph.insert(cspec.to_string(), c);
|
"files": {
|
||||||
|
"https://deno.land/x/a/b/c.ts":{
|
||||||
let count = get_unique_dep_count(&graph);
|
"deps": [],
|
||||||
|
"size": 12345
|
||||||
assert_eq!(graph.len(), count);
|
}
|
||||||
}
|
},
|
||||||
|
"local": "/a/b/c.ts",
|
||||||
#[test]
|
"map": null,
|
||||||
fn dependency_count_with_redirects() {
|
"module": "https://deno.land/x/a/b/c.ts",
|
||||||
let (a, aspec) = create_mock_file("a", vec![], None);
|
"totalSize": 999999
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
cli/main.rs
33
cli/main.rs
|
@ -81,12 +81,14 @@ use global_state::exit_unstable;
|
||||||
use import_map::ImportMap;
|
use import_map::ImportMap;
|
||||||
use log::Level;
|
use log::Level;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use upgrade::upgrade_command;
|
use upgrade::upgrade_command;
|
||||||
|
|
||||||
|
@ -159,27 +161,36 @@ fn get_types(unstable: bool) -> String {
|
||||||
|
|
||||||
async fn info_command(
|
async fn info_command(
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
file: Option<String>,
|
maybe_specifier: Option<String>,
|
||||||
json: bool,
|
json: bool,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
if json && !flags.unstable {
|
if json && !flags.unstable {
|
||||||
exit_unstable("--json");
|
exit_unstable("--json");
|
||||||
}
|
}
|
||||||
let global_state = GlobalState::new(flags)?;
|
let global_state = GlobalState::new(flags)?;
|
||||||
// If it was just "deno info" print location of caches and exit
|
if let Some(specifier) = maybe_specifier {
|
||||||
if file.is_none() {
|
let specifier = ModuleSpecifier::resolve_url_or_path(&specifier)?;
|
||||||
print_cache_info(&global_state, json)
|
let handler = Rc::new(RefCell::new(specifier_handler::FetchHandler::new(
|
||||||
} else {
|
&global_state,
|
||||||
let main_module = ModuleSpecifier::resolve_url_or_path(&file.unwrap())?;
|
Permissions::allow_all(),
|
||||||
let info =
|
)?));
|
||||||
info::ModuleDepInfo::new(&global_state, main_module.clone()).await?;
|
let mut builder = module_graph2::GraphBuilder2::new(
|
||||||
|
handler,
|
||||||
|
global_state.maybe_import_map.clone(),
|
||||||
|
);
|
||||||
|
builder.insert(&specifier).await?;
|
||||||
|
let graph = builder.get_graph(&global_state.lockfile)?;
|
||||||
|
let info = graph.info()?;
|
||||||
|
|
||||||
if json {
|
if json {
|
||||||
write_json_to_stdout(&json!(info))
|
write_json_to_stdout(&json!(info))?;
|
||||||
} else {
|
} else {
|
||||||
write_to_stdout_ignore_sigpipe(format!("{}", info).as_bytes())
|
write_to_stdout_ignore_sigpipe(format!("{}", info).as_bytes())?;
|
||||||
.map_err(AnyError::from)
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
// If it was just "deno info" print location of caches and exit
|
||||||
|
print_cache_info(&global_state, json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::Serializer;
|
use serde::Serializer;
|
||||||
|
use std::fmt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -22,6 +23,23 @@ pub enum MediaType {
|
||||||
Unknown = 8,
|
Unknown = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MediaType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let value = match self {
|
||||||
|
MediaType::JavaScript => "JavaScript",
|
||||||
|
MediaType::JSX => "JSX",
|
||||||
|
MediaType::TypeScript => "TypeScript",
|
||||||
|
MediaType::Dts => "Dts",
|
||||||
|
MediaType::TSX => "TSX",
|
||||||
|
MediaType::Json => "Json",
|
||||||
|
MediaType::Wasm => "Wasm",
|
||||||
|
MediaType::BuildInfo => "BuildInfo",
|
||||||
|
MediaType::Unknown => "Unknown",
|
||||||
|
};
|
||||||
|
write!(f, "{}", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Path> for MediaType {
|
impl<'a> From<&'a Path> for MediaType {
|
||||||
fn from(path: &'a Path) -> Self {
|
fn from(path: &'a Path) -> Self {
|
||||||
MediaType::from_path(path)
|
MediaType::from_path(path)
|
||||||
|
@ -103,45 +121,74 @@ impl Serialize for MediaType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enum_name_media_type(mt: MediaType) -> &'static str {
|
/// Serialize a `MediaType` enum into a human readable string. The default
|
||||||
match mt {
|
/// serialization for media types is and integer.
|
||||||
MediaType::JavaScript => "JavaScript",
|
///
|
||||||
MediaType::JSX => "JSX",
|
/// TODO(@kitsonk) remove this once we stop sending MediaType into tsc.
|
||||||
MediaType::TypeScript => "TypeScript",
|
pub fn serialize_media_type<S>(mt: &MediaType, s: S) -> Result<S::Ok, S::Error>
|
||||||
MediaType::Dts => "Dts",
|
where
|
||||||
MediaType::TSX => "TSX",
|
S: Serializer,
|
||||||
MediaType::Json => "Json",
|
{
|
||||||
MediaType::Wasm => "Wasm",
|
s.serialize_str(&format!("{}", mt))
|
||||||
MediaType::BuildInfo => "BuildInfo",
|
|
||||||
MediaType::Unknown => "Unknown",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_map_file_extension() {
|
mod tests {
|
||||||
assert_eq!(
|
use super::*;
|
||||||
MediaType::from(Path::new("foo/bar.ts")),
|
use deno_core::serde_json::json;
|
||||||
MediaType::TypeScript
|
|
||||||
);
|
#[test]
|
||||||
assert_eq!(MediaType::from(Path::new("foo/bar.tsx")), MediaType::TSX);
|
fn test_map_file_extension() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MediaType::from(Path::new("foo/bar.d.ts")),
|
MediaType::from(Path::new("foo/bar.ts")),
|
||||||
MediaType::TypeScript
|
MediaType::TypeScript
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(MediaType::from(Path::new("foo/bar.tsx")), MediaType::TSX);
|
||||||
MediaType::from(Path::new("foo/bar.js")),
|
assert_eq!(
|
||||||
MediaType::JavaScript
|
MediaType::from(Path::new("foo/bar.d.ts")),
|
||||||
);
|
MediaType::TypeScript
|
||||||
assert_eq!(MediaType::from(Path::new("foo/bar.jsx")), MediaType::JSX);
|
);
|
||||||
assert_eq!(MediaType::from(Path::new("foo/bar.json")), MediaType::Json);
|
assert_eq!(
|
||||||
assert_eq!(MediaType::from(Path::new("foo/bar.wasm")), MediaType::Wasm);
|
MediaType::from(Path::new("foo/bar.js")),
|
||||||
assert_eq!(
|
MediaType::JavaScript
|
||||||
MediaType::from(Path::new("foo/bar.cjs")),
|
);
|
||||||
MediaType::JavaScript
|
assert_eq!(MediaType::from(Path::new("foo/bar.jsx")), MediaType::JSX);
|
||||||
);
|
assert_eq!(MediaType::from(Path::new("foo/bar.json")), MediaType::Json);
|
||||||
assert_eq!(
|
assert_eq!(MediaType::from(Path::new("foo/bar.wasm")), MediaType::Wasm);
|
||||||
MediaType::from(Path::new("foo/bar.txt")),
|
assert_eq!(
|
||||||
MediaType::Unknown
|
MediaType::from(Path::new("foo/bar.cjs")),
|
||||||
);
|
MediaType::JavaScript
|
||||||
assert_eq!(MediaType::from(Path::new("foo/bar")), MediaType::Unknown);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
MediaType::from(Path::new("foo/bar.txt")),
|
||||||
|
MediaType::Unknown
|
||||||
|
);
|
||||||
|
assert_eq!(MediaType::from(Path::new("foo/bar")), MediaType::Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization() {
|
||||||
|
assert_eq!(json!(MediaType::JavaScript), json!(0));
|
||||||
|
assert_eq!(json!(MediaType::JSX), json!(1));
|
||||||
|
assert_eq!(json!(MediaType::TypeScript), json!(2));
|
||||||
|
assert_eq!(json!(MediaType::Dts), json!(3));
|
||||||
|
assert_eq!(json!(MediaType::TSX), json!(4));
|
||||||
|
assert_eq!(json!(MediaType::Json), json!(5));
|
||||||
|
assert_eq!(json!(MediaType::Wasm), json!(6));
|
||||||
|
assert_eq!(json!(MediaType::BuildInfo), json!(7));
|
||||||
|
assert_eq!(json!(MediaType::Unknown), json!(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_display() {
|
||||||
|
assert_eq!(format!("{}", MediaType::JavaScript), "JavaScript");
|
||||||
|
assert_eq!(format!("{}", MediaType::JSX), "JSX");
|
||||||
|
assert_eq!(format!("{}", MediaType::TypeScript), "TypeScript");
|
||||||
|
assert_eq!(format!("{}", MediaType::Dts), "Dts");
|
||||||
|
assert_eq!(format!("{}", MediaType::TSX), "TSX");
|
||||||
|
assert_eq!(format!("{}", MediaType::Json), "Json");
|
||||||
|
assert_eq!(format!("{}", MediaType::Wasm), "Wasm");
|
||||||
|
assert_eq!(format!("{}", MediaType::BuildInfo), "BuildInfo");
|
||||||
|
assert_eq!(format!("{}", MediaType::Unknown), "Unknown");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@ use crate::ast::parse;
|
||||||
use crate::ast::Location;
|
use crate::ast::Location;
|
||||||
use crate::ast::ParsedModule;
|
use crate::ast::ParsedModule;
|
||||||
use crate::import_map::ImportMap;
|
use crate::import_map::ImportMap;
|
||||||
|
use crate::info::ModuleGraphInfo;
|
||||||
|
use crate::info::ModuleInfo;
|
||||||
|
use crate::info::ModuleInfoMap;
|
||||||
|
use crate::info::ModuleInfoMapItem;
|
||||||
use crate::lockfile::Lockfile;
|
use crate::lockfile::Lockfile;
|
||||||
use crate::media_type::MediaType;
|
use crate::media_type::MediaType;
|
||||||
use crate::specifier_handler::CachedModule;
|
use crate::specifier_handler::CachedModule;
|
||||||
|
@ -30,6 +34,7 @@ use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
@ -162,13 +167,16 @@ struct Module {
|
||||||
is_dirty: bool,
|
is_dirty: bool,
|
||||||
is_hydrated: bool,
|
is_hydrated: bool,
|
||||||
is_parsed: bool,
|
is_parsed: bool,
|
||||||
|
maybe_emit_path: Option<PathBuf>,
|
||||||
maybe_import_map: Option<Rc<RefCell<ImportMap>>>,
|
maybe_import_map: Option<Rc<RefCell<ImportMap>>>,
|
||||||
|
maybe_map_path: Option<PathBuf>,
|
||||||
maybe_parsed_module: Option<ParsedModule>,
|
maybe_parsed_module: Option<ParsedModule>,
|
||||||
maybe_types: Option<(String, ModuleSpecifier)>,
|
maybe_types: Option<(String, ModuleSpecifier)>,
|
||||||
maybe_version: Option<String>,
|
maybe_version: Option<String>,
|
||||||
media_type: MediaType,
|
media_type: MediaType,
|
||||||
specifier: ModuleSpecifier,
|
specifier: ModuleSpecifier,
|
||||||
source: String,
|
source: String,
|
||||||
|
source_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Module {
|
impl Default for Module {
|
||||||
|
@ -179,13 +187,16 @@ impl Default for Module {
|
||||||
is_dirty: false,
|
is_dirty: false,
|
||||||
is_hydrated: false,
|
is_hydrated: false,
|
||||||
is_parsed: false,
|
is_parsed: false,
|
||||||
|
maybe_emit_path: None,
|
||||||
maybe_import_map: None,
|
maybe_import_map: None,
|
||||||
|
maybe_map_path: None,
|
||||||
maybe_parsed_module: None,
|
maybe_parsed_module: None,
|
||||||
maybe_types: None,
|
maybe_types: None,
|
||||||
maybe_version: None,
|
maybe_version: None,
|
||||||
media_type: MediaType::Unknown,
|
media_type: MediaType::Unknown,
|
||||||
specifier: ModuleSpecifier::resolve_url("https://deno.land/x/").unwrap(),
|
specifier: ModuleSpecifier::resolve_url("https://deno.land/x/").unwrap(),
|
||||||
source: "".to_string(),
|
source: "".to_string(),
|
||||||
|
source_path: PathBuf::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,6 +226,9 @@ impl Module {
|
||||||
pub fn hydrate(&mut self, cached_module: CachedModule) {
|
pub fn hydrate(&mut self, cached_module: CachedModule) {
|
||||||
self.media_type = cached_module.media_type;
|
self.media_type = cached_module.media_type;
|
||||||
self.source = cached_module.source;
|
self.source = cached_module.source;
|
||||||
|
self.source_path = cached_module.source_path;
|
||||||
|
self.maybe_emit_path = cached_module.maybe_emit_path;
|
||||||
|
self.maybe_map_path = cached_module.maybe_map_path;
|
||||||
if self.maybe_import_map.is_none() {
|
if self.maybe_import_map.is_none() {
|
||||||
if let Some(dependencies) = cached_module.maybe_dependencies {
|
if let Some(dependencies) = cached_module.maybe_dependencies {
|
||||||
self.dependencies = dependencies;
|
self.dependencies = dependencies;
|
||||||
|
@ -359,6 +373,10 @@ impl Module {
|
||||||
pub fn set_version(&mut self, config: &[u8]) {
|
pub fn set_version(&mut self, config: &[u8]) {
|
||||||
self.maybe_version = Some(get_version(&self.source, version::DENO, config))
|
self.maybe_version = Some(get_version(&self.source, version::DENO, config))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.source.as_bytes().len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -421,6 +439,115 @@ impl Graph2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_info(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
seen: &mut HashSet<ModuleSpecifier>,
|
||||||
|
totals: &mut HashMap<ModuleSpecifier, usize>,
|
||||||
|
) -> ModuleInfo {
|
||||||
|
let not_seen = seen.insert(specifier.clone());
|
||||||
|
let module = self.modules.get(specifier).unwrap();
|
||||||
|
let mut deps = Vec::new();
|
||||||
|
let mut total_size = None;
|
||||||
|
|
||||||
|
if not_seen {
|
||||||
|
let mut seen_deps = HashSet::new();
|
||||||
|
// TODO(@kitsonk) https://github.com/denoland/deno/issues/7927
|
||||||
|
for (_, dep) in module.dependencies.iter() {
|
||||||
|
// Check the runtime code dependency
|
||||||
|
if let Some(code_dep) = &dep.maybe_code {
|
||||||
|
if seen_deps.insert(code_dep.clone()) {
|
||||||
|
deps.push(self.get_info(code_dep, seen, totals));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deps.sort();
|
||||||
|
total_size = if let Some(total) = totals.get(specifier) {
|
||||||
|
Some(total.to_owned())
|
||||||
|
} else {
|
||||||
|
let mut total = deps
|
||||||
|
.iter()
|
||||||
|
.map(|d| {
|
||||||
|
if let Some(total_size) = d.total_size {
|
||||||
|
total_size
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
total += module.size();
|
||||||
|
totals.insert(specifier.clone(), total);
|
||||||
|
Some(total)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleInfo {
|
||||||
|
deps,
|
||||||
|
name: specifier.clone(),
|
||||||
|
size: module.size(),
|
||||||
|
total_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_info_map(&self) -> ModuleInfoMap {
|
||||||
|
let map = self
|
||||||
|
.modules
|
||||||
|
.iter()
|
||||||
|
.map(|(specifier, module)| {
|
||||||
|
let mut deps = HashSet::new();
|
||||||
|
for (_, dep) in module.dependencies.iter() {
|
||||||
|
if let Some(code_dep) = &dep.maybe_code {
|
||||||
|
deps.insert(code_dep.clone());
|
||||||
|
}
|
||||||
|
if let Some(type_dep) = &dep.maybe_type {
|
||||||
|
deps.insert(type_dep.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((_, types_dep)) = &module.maybe_types {
|
||||||
|
deps.insert(types_dep.clone());
|
||||||
|
}
|
||||||
|
let item = ModuleInfoMapItem {
|
||||||
|
deps: deps.into_iter().collect(),
|
||||||
|
size: module.size(),
|
||||||
|
};
|
||||||
|
(specifier.clone(), item)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ModuleInfoMap::new(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a structure which provides information about the module graph and
|
||||||
|
/// the relationship of the modules in the graph. This structure is used to
|
||||||
|
/// provide information for the `info` subcommand.
|
||||||
|
pub fn info(&self) -> Result<ModuleGraphInfo, AnyError> {
|
||||||
|
if self.roots.is_empty() || self.roots.len() > 1 {
|
||||||
|
return Err(NotSupported(format!("Info is only supported when there is a single root module in the graph. Found: {}", self.roots.len())).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let module = self.roots[0].clone();
|
||||||
|
let m = self.modules.get(&module).unwrap();
|
||||||
|
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
let mut totals = HashMap::new();
|
||||||
|
let info = self.get_info(&module, &mut seen, &mut totals);
|
||||||
|
|
||||||
|
let files = self.get_info_map();
|
||||||
|
let total_size = totals.get(&module).unwrap_or(&m.size()).to_owned();
|
||||||
|
|
||||||
|
Ok(ModuleGraphInfo {
|
||||||
|
compiled: m.maybe_emit_path.clone(),
|
||||||
|
dep_count: self.modules.len() - 1,
|
||||||
|
file_type: m.media_type,
|
||||||
|
files,
|
||||||
|
info,
|
||||||
|
local: m.source_path.clone(),
|
||||||
|
map: m.maybe_map_path.clone(),
|
||||||
|
module,
|
||||||
|
total_size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the handler with any modules that are marked as _dirty_ and update
|
/// Update the handler with any modules that are marked as _dirty_ and update
|
||||||
/// any build info if present.
|
/// any build info if present.
|
||||||
fn flush(&mut self, emit_type: &EmitType) -> Result<(), AnyError> {
|
fn flush(&mut self, emit_type: &EmitType) -> Result<(), AnyError> {
|
||||||
|
@ -713,25 +840,26 @@ mod tests {
|
||||||
.replace(":///", "_")
|
.replace(":///", "_")
|
||||||
.replace("://", "_")
|
.replace("://", "_")
|
||||||
.replace("/", "-");
|
.replace("/", "-");
|
||||||
let specifier_path = self.fixtures.join(specifier_text);
|
let source_path = self.fixtures.join(specifier_text);
|
||||||
let media_type =
|
let media_type = match source_path.extension().unwrap().to_str().unwrap()
|
||||||
match specifier_path.extension().unwrap().to_str().unwrap() {
|
{
|
||||||
"ts" => {
|
"ts" => {
|
||||||
if specifier_path.to_string_lossy().ends_with(".d.ts") {
|
if source_path.to_string_lossy().ends_with(".d.ts") {
|
||||||
MediaType::Dts
|
MediaType::Dts
|
||||||
} else {
|
} else {
|
||||||
MediaType::TypeScript
|
MediaType::TypeScript
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"tsx" => MediaType::TSX,
|
}
|
||||||
"js" => MediaType::JavaScript,
|
"tsx" => MediaType::TSX,
|
||||||
"jsx" => MediaType::JSX,
|
"js" => MediaType::JavaScript,
|
||||||
_ => MediaType::Unknown,
|
"jsx" => MediaType::JSX,
|
||||||
};
|
_ => MediaType::Unknown,
|
||||||
let source = fs::read_to_string(specifier_path)?;
|
};
|
||||||
|
let source = fs::read_to_string(&source_path)?;
|
||||||
|
|
||||||
Ok(CachedModule {
|
Ok(CachedModule {
|
||||||
source,
|
source,
|
||||||
|
source_path,
|
||||||
specifier,
|
specifier,
|
||||||
media_type,
|
media_type,
|
||||||
..CachedModule::default()
|
..CachedModule::default()
|
||||||
|
@ -879,6 +1007,37 @@ mod tests {
|
||||||
assert_eq!(module.maybe_version, expected);
|
assert_eq!(module.maybe_version, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_graph_info() {
|
||||||
|
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
let fixtures = c.join("tests/module_graph");
|
||||||
|
let handler = Rc::new(RefCell::new(MockSpecifierHandler {
|
||||||
|
fixtures,
|
||||||
|
..MockSpecifierHandler::default()
|
||||||
|
}));
|
||||||
|
let mut builder = GraphBuilder2::new(handler.clone(), None);
|
||||||
|
let specifier =
|
||||||
|
ModuleSpecifier::resolve_url_or_path("file:///tests/main.ts")
|
||||||
|
.expect("could not resolve module");
|
||||||
|
builder
|
||||||
|
.insert(&specifier)
|
||||||
|
.await
|
||||||
|
.expect("module not inserted");
|
||||||
|
let graph = builder.get_graph(&None).expect("could not get graph");
|
||||||
|
let info = graph.info().expect("could not get info");
|
||||||
|
assert!(info.compiled.is_none());
|
||||||
|
assert_eq!(info.dep_count, 6);
|
||||||
|
assert_eq!(info.file_type, MediaType::TypeScript);
|
||||||
|
assert_eq!(info.files.0.len(), 7);
|
||||||
|
assert!(info.local.to_string_lossy().ends_with("file_tests-main.ts"));
|
||||||
|
assert!(info.map.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
info.module,
|
||||||
|
ModuleSpecifier::resolve_url_or_path("file:///tests/main.ts").unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(info.total_size, 344);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_graph_transpile() {
|
async fn test_graph_transpile() {
|
||||||
// This is a complex scenario of transpiling, where we have TypeScript
|
// This is a complex scenario of transpiling, where we have TypeScript
|
||||||
|
|
|
@ -18,6 +18,7 @@ use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -30,10 +31,13 @@ pub type FetchFuture =
|
||||||
pub struct CachedModule {
|
pub struct CachedModule {
|
||||||
pub emits: EmitMap,
|
pub emits: EmitMap,
|
||||||
pub maybe_dependencies: Option<DependencyMap>,
|
pub maybe_dependencies: Option<DependencyMap>,
|
||||||
|
pub maybe_emit_path: Option<PathBuf>,
|
||||||
|
pub maybe_map_path: Option<PathBuf>,
|
||||||
pub maybe_types: Option<String>,
|
pub maybe_types: Option<String>,
|
||||||
pub maybe_version: Option<String>,
|
pub maybe_version: Option<String>,
|
||||||
pub media_type: MediaType,
|
pub media_type: MediaType,
|
||||||
pub source: String,
|
pub source: String,
|
||||||
|
pub source_path: PathBuf,
|
||||||
pub specifier: ModuleSpecifier,
|
pub specifier: ModuleSpecifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,10 +47,13 @@ impl Default for CachedModule {
|
||||||
CachedModule {
|
CachedModule {
|
||||||
emits: HashMap::new(),
|
emits: HashMap::new(),
|
||||||
maybe_dependencies: None,
|
maybe_dependencies: None,
|
||||||
|
maybe_emit_path: None,
|
||||||
|
maybe_map_path: None,
|
||||||
maybe_types: None,
|
maybe_types: None,
|
||||||
maybe_version: None,
|
maybe_version: None,
|
||||||
media_type: MediaType::Unknown,
|
media_type: MediaType::Unknown,
|
||||||
source: "".to_string(),
|
source: "".to_string(),
|
||||||
|
source_path: PathBuf::new(),
|
||||||
specifier: ModuleSpecifier::resolve_url("https://deno.land/x/mod.ts")
|
specifier: ModuleSpecifier::resolve_url("https://deno.land/x/mod.ts")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
}
|
||||||
|
@ -242,27 +249,34 @@ impl SpecifierHandler for FetchHandler {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let filename =
|
let mut maybe_map_path: Option<PathBuf> = None;
|
||||||
|
let map_path =
|
||||||
disk_cache.get_cache_filename_with_extension(&url, "js.map");
|
disk_cache.get_cache_filename_with_extension(&url, "js.map");
|
||||||
let maybe_map: Option<String> = if let Ok(map) = disk_cache.get(&filename)
|
let maybe_map: Option<String> = if let Ok(map) = disk_cache.get(&map_path)
|
||||||
{
|
{
|
||||||
|
maybe_map_path = Some(disk_cache.location.join(map_path));
|
||||||
Some(String::from_utf8(map)?)
|
Some(String::from_utf8(map)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mut emits = HashMap::new();
|
let mut emits = HashMap::new();
|
||||||
let filename = disk_cache.get_cache_filename_with_extension(&url, "js");
|
let mut maybe_emit_path: Option<PathBuf> = None;
|
||||||
if let Ok(code) = disk_cache.get(&filename) {
|
let emit_path = disk_cache.get_cache_filename_with_extension(&url, "js");
|
||||||
|
if let Ok(code) = disk_cache.get(&emit_path) {
|
||||||
|
maybe_emit_path = Some(disk_cache.location.join(emit_path));
|
||||||
emits.insert(EmitType::Cli, (String::from_utf8(code)?, maybe_map));
|
emits.insert(EmitType::Cli, (String::from_utf8(code)?, maybe_map));
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(CachedModule {
|
Ok(CachedModule {
|
||||||
emits,
|
emits,
|
||||||
maybe_dependencies: None,
|
maybe_dependencies: None,
|
||||||
|
maybe_emit_path,
|
||||||
|
maybe_map_path,
|
||||||
maybe_types: source_file.types_header,
|
maybe_types: source_file.types_header,
|
||||||
maybe_version,
|
maybe_version,
|
||||||
media_type: source_file.media_type,
|
media_type: source_file.media_type,
|
||||||
source: source_file.source_code,
|
source: source_file.source_code,
|
||||||
|
source_path: source_file.filename,
|
||||||
specifier,
|
specifier,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
|
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
|
||||||
type: TypeScript
|
type: TypeScript
|
||||||
deps: 8 unique (total [WILDCARD])
|
deps: 8 unique (total [WILDCARD])
|
||||||
|
|
||||||
http://127.0.0.1:4545/cli/tests/019_media_types.ts ([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_application_ecmascript.j2.js ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_application_x_typescript.t4.ts ([WILDCARD])
|
||||||
├── http://localhost:4545/cli/tests/subdir/mt_text_ecmascript.j3.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])
|
├── http://localhost:4545/cli/tests/subdir/mt_text_javascript.j1.js ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_text_typescript.t1.ts ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_video_mp2t.t3.ts ([WILDCARD])
|
||||||
|
└── http://localhost:4545/cli/tests/subdir/mt_video_vdn.t2.ts ([WILDCARD])
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
|
local: [WILDCARD]http[WILDCARD]127.0.0.1_PORT4545[WILDCARD]
|
||||||
type: TypeScript
|
type: TypeScript
|
||||||
deps: 8 unique (total [WILDCARD])
|
deps: 8 unique (total [WILDCARD])
|
||||||
|
|
||||||
http://127.0.0.1:4545/cli/tests/048_media_types_jsx.ts ([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_application_ecmascript_jsx.j2.jsx ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_application_x_javascript_jsx.j4.jsx ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_application_x_typescript_tsx.t4.tsx ([WILDCARD])
|
||||||
├── http://localhost:4545/cli/tests/subdir/mt_text_ecmascript_jsx.j3.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])
|
├── http://localhost:4545/cli/tests/subdir/mt_text_javascript_jsx.j1.jsx ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_text_typescript_tsx.t1.tsx ([WILDCARD])
|
||||||
|
├── http://localhost:4545/cli/tests/subdir/mt_video_mp2t_tsx.t3.tsx ([WILDCARD])
|
||||||
|
└── http://localhost:4545/cli/tests/subdir/mt_video_vdn_tsx.t2.tsx ([WILDCARD])
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
local: [WILDCARD]005_more_imports.ts
|
local: [WILDCARD]005_more_imports.ts
|
||||||
type: TypeScript
|
type: TypeScript
|
||||||
deps: 3 unique (total [WILDCARD])
|
deps: 3 unique (total [WILDCARD])
|
||||||
|
|
||||||
file://[WILDCARD]/005_more_imports.ts ([WILDCARD])
|
file://[WILDCARD]/005_more_imports.ts ([WILDCARD])
|
||||||
└─┬ file://[WILDCARD]/subdir/mod1.ts ([WILDCARD])
|
└─┬ file://[WILDCARD]/subdir/mod1.ts ([WILDCARD])
|
||||||
└─┬ file://[WILDCARD]/subdir/subdir2/mod2.ts ([WILDCARD])
|
└─┬ file://[WILDCARD]/subdir/subdir2/mod2.ts ([WILDCARD])
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
{
|
{
|
||||||
"module": "file://[WILDCARD]005_more_imports.ts",
|
|
||||||
"local": "[WILDCARD]005_more_imports.ts",
|
|
||||||
"fileType": "TypeScript",
|
|
||||||
"compiled": null,
|
"compiled": null,
|
||||||
"map": null,
|
|
||||||
"depCount": 3,
|
"depCount": 3,
|
||||||
"totalSize": 757,
|
"fileType": "TypeScript",
|
||||||
"files": {
|
"files": {
|
||||||
"file://[WILDCARD]005_more_imports.ts": {
|
"file:///[WILDCARD]/cli/tests/005_more_imports.ts": {
|
||||||
"size": 211,
|
|
||||||
"deps": [
|
"deps": [
|
||||||
"file://[WILDCARD]/subdir/mod1.ts"
|
"file:///[WILDCARD]/cli/tests/subdir/mod1.ts"
|
||||||
]
|
],
|
||||||
|
"size": 211
|
||||||
},
|
},
|
||||||
"file://[WILDCARD]/subdir/mod1.ts": {
|
"file:///[WILDCARD]/cli/tests/subdir/mod1.ts": {
|
||||||
"size": 320,
|
|
||||||
"deps": [
|
"deps": [
|
||||||
"file://[WILDCARD]/subdir/subdir2/mod2.ts"
|
"file:///[WILDCARD]/cli/tests/subdir/subdir2/mod2.ts"
|
||||||
]
|
],
|
||||||
|
"size": 320
|
||||||
},
|
},
|
||||||
"file://[WILDCARD]/subdir/print_hello.ts": {
|
"file:///[WILDCARD]/cli/tests/subdir/print_hello.ts": {
|
||||||
"size": 63,
|
"deps": [],
|
||||||
"deps": []
|
"size": 63
|
||||||
},
|
},
|
||||||
"file://[WILDCARD]/subdir/subdir2/mod2.ts": {
|
"file:///[WILDCARD]/cli/tests/subdir/subdir2/mod2.ts": {
|
||||||
"size": 163,
|
|
||||||
"deps": [
|
"deps": [
|
||||||
"file://[WILDCARD]/subdir/print_hello.ts"
|
"file:///[WILDCARD]/cli/tests/subdir/print_hello.ts"
|
||||||
]
|
],
|
||||||
|
"size": 163
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"local": "[WILDCARD]005_more_imports.ts",
|
||||||
|
"map": null,
|
||||||
|
"module": "file:///[WILDCARD]/cli/tests/005_more_imports.ts",
|
||||||
|
"totalSize": 757
|
||||||
}
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
local: [WILDCARD]https[WILDCARD]localhost_PORT5545[WILDCARD]
|
local: [WILDCARD]https[WILDCARD]localhost_PORT5545[WILDCARD]
|
||||||
type: TypeScript
|
type: TypeScript
|
||||||
deps: 8 unique (total [WILDCARD])
|
deps: 8 unique (total [WILDCARD])
|
||||||
|
|
||||||
https://localhost:5545/cli/tests/cafile_info.ts ([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_application_ecmascript.j2.js ([WILDCARD])
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_application_x_javascript.j4.js ([WILDCARD])
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_application_x_typescript.t4.ts ([WILDCARD])
|
||||||
├── https://localhost:5545/cli/tests/subdir/mt_text_ecmascript.j3.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])
|
├── https://localhost:5545/cli/tests/subdir/mt_text_javascript.j1.js ([WILDCARD])
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_text_typescript.t1.ts ([WILDCARD])
|
||||||
|
├── https://localhost:5545/cli/tests/subdir/mt_video_mp2t.t3.ts ([WILDCARD])
|
||||||
|
└── https://localhost:5545/cli/tests/subdir/mt_video_vdn.t2.ts ([WILDCARD])
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
local: [WILDCARD]info_recursive_imports_test.ts
|
local: [WILDCARD]info_recursive_imports_test.ts
|
||||||
type: TypeScript
|
type: TypeScript
|
||||||
deps: 4 unique (total [WILDCARD])
|
deps: 4 unique (total [WILDCARD])
|
||||||
|
|
||||||
file://[WILDCARD]cli/tests/info_recursive_imports_test.ts ([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/A.ts ([WILDCARD])
|
||||||
├─┬ file://[WILDCARD]cli/tests/recursive_imports/B.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/C.ts ([WILDCARD])
|
||||||
│ │ ├── file://[WILDCARD]cli/tests/recursive_imports/A.ts *
|
│ │ ├── 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 [WILDCARD]
|
||||||
│ └── file://[WILDCARD]cli/tests/recursive_imports/common.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 [WILDCARD]
|
||||||
|
|
Loading…
Add table
Reference in a new issue