pub(super) fn print_already_up_to_date() {
if clx::progress::output() == clx::progress::ProgressOutput::Text {
return;
}
use clx::style;
use std::io::Write;
let msg = format!(
"{} {}",
style::egreen("✓").bold(),
style::ebold("Already up to date"),
);
let line = crate::progress::aube_prefix_line(&msg);
let _ = writeln!(std::io::stderr(), "{line}");
}
pub(super) fn print_direct_dependency_summary(
graph: &aube_lockfile::LockfileGraph,
manifests: &[(String, aube_manifest::PackageJson)],
direct_dep_info: &std::collections::HashMap<String, aube_resolver::DirectDepInfo>,
) {
use clx::style;
let importers: Vec<(&String, &Vec<aube_lockfile::DirectDep>)> = graph
.importers
.iter()
.filter(|(_, deps)| !deps.is_empty())
.collect();
if importers.is_empty() {
return;
}
let show_importer_headers = importers.len() > 1;
for (idx, (importer, deps)) in importers.iter().enumerate() {
if idx > 0 {
eprintln!();
}
if show_importer_headers {
let label = direct_dependency_importer_label(importer, manifests);
eprintln!("{}{}", style::ebold(&label), style::edim(":"));
}
print_direct_dependency_section(
graph,
deps,
aube_lockfile::DepType::Production,
direct_dep_info,
);
print_direct_dependency_section(
graph,
deps,
aube_lockfile::DepType::Optional,
direct_dep_info,
);
print_direct_dependency_section(graph, deps, aube_lockfile::DepType::Dev, direct_dep_info);
}
eprintln!();
}
fn direct_dependency_importer_label(
importer: &str,
manifests: &[(String, aube_manifest::PackageJson)],
) -> String {
manifests
.iter()
.find(|(path, _)| path == importer)
.and_then(|(_, manifest)| manifest.name.clone())
.unwrap_or_else(|| importer.to_string())
}
pub(super) fn should_print_human_install_summary() -> bool {
let flags = super::super::global_output_flags();
!flags.silent && !flags.ndjson
}
fn print_direct_dependency_section(
graph: &aube_lockfile::LockfileGraph,
deps: &[aube_lockfile::DirectDep],
dep_type: aube_lockfile::DepType,
direct_dep_info: &std::collections::HashMap<String, aube_resolver::DirectDepInfo>,
) {
use clx::style;
let mut deps: Vec<&aube_lockfile::DirectDep> =
deps.iter().filter(|dep| dep.dep_type == dep_type).collect();
if deps.is_empty() {
return;
}
deps.sort_by(|a, b| a.name.cmp(&b.name));
let label = aube_lockfile::dep_type_label(dep_type);
eprintln!("{}{}", style::ebold(label), style::edim(":"));
for dep in deps {
let version = graph
.get_package(&dep.dep_path)
.map(|pkg| pkg.version.as_str())
.unwrap_or("?");
let badges = render_direct_dep_badges(direct_dep_info.get(&dep.dep_path));
eprintln!(
"{} {}{}{}",
style::egreen("+").bold(),
dep.name,
style::edim(format!("@{version}")),
badges,
);
}
}
fn render_direct_dep_badges(info: Option<&aube_resolver::DirectDepInfo>) -> String {
use clx::style;
let Some(info) = info else {
return String::new();
};
let mut parts: Vec<String> = Vec::new();
if info.deprecated {
parts.push(style::eyellow("deprecated").to_string());
}
if let Some(latest) = &info.latest {
parts.push(style::eyellow(format!("latest {latest}")).to_string());
}
let sep = style::edim(" · ").to_string();
format!(" {}", parts.join(&sep))
}