use hexser::prelude::*;
#[derive(HexDomain, HexEntity)]
struct Customer {
id: String,
name: String,
email: String,
}
#[derive(HexDomain, HexEntity)]
struct Order {
id: String,
customer_id: String,
total: f64,
}
#[derive(HexDomain, HexEntity)]
struct Product {
id: String,
name: String,
price: f64,
}
#[derive(HexPort, HexRepository)]
struct CustomerRepository;
#[derive(HexPort, HexRepository)]
struct OrderRepository;
#[derive(HexPort, HexRepository)]
struct ProductRepository;
#[derive(HexAdapter)]
struct PostgresCustomerRepository {
connection_string: String,
}
#[derive(HexAdapter)]
struct PostgresOrderRepository {
connection_string: String,
}
#[derive(HexAdapter)]
struct RedisProductCache {
redis_url: String,
}
#[derive(HexDirective)]
struct CreateOrderDirective {
customer_id: String,
products: Vec<String>,
}
#[derive(HexQuery)]
struct GetCustomerOrdersQuery {
customer_id: String,
}
fn main() {
println!("ποΈ hex Architecture Visualization\n");
println!("{}", "β".repeat(70));
let graph = HexGraph::current();
println!("\nπ ARCHITECTURE OVERVIEW");
println!("{}", "β".repeat(70));
graph.pretty_print();
println!("\nποΈ LAYER-BY-LAYER BREAKDOWN");
println!("{}", "β".repeat(70));
visualize_layer(&graph, Layer::Domain, "π¦ Domain Layer (Business Logic)");
visualize_layer(&graph, Layer::Port, "π Port Layer (Interfaces)");
visualize_layer(&graph, Layer::Adapter, "π§ Adapter Layer (Implementations)");
visualize_layer(
&graph,
Layer::Application,
"β‘ Application Layer (Use Cases)",
);
println!("\nπ¨ ASCII ARCHITECTURE DIAGRAM");
println!("{}", "β".repeat(70));
print_ascii_architecture(&graph);
println!("\nπ ARCHITECTURE METRICS");
println!("{}", "β".repeat(70));
println!("Total Components: {}", graph.node_count());
println!(
"Domain Entities: {}",
graph.nodes_by_role(Role::Entity).len()
);
println!(
"Repository Ports: {}",
graph.nodes_by_layer(Layer::Port).len()
);
println!(
"Adapter Implementations: {}",
graph.nodes_by_layer(Layer::Adapter).len()
);
println!("Directives: {}", graph.nodes_by_role(Role::Directive).len());
println!("Queries: {}", graph.nodes_by_role(Role::Query).len());
println!("\nβ
ARCHITECTURE HEALTH CHECK");
println!("{}", "β".repeat(70));
health_check(&graph);
println!("{}", "β".repeat(70));
println!("π Your architecture is automatically documented and visualized!");
println!("{}", "β".repeat(70));
}
fn visualize_layer(graph: &HexGraph, layer: Layer, title: &str) {
println!("\n{title}");
let nodes: Vec<_> = graph.nodes_by_layer(layer).into_iter().collect();
if nodes.is_empty() {
println!(" (no components)");
return;
}
for node in nodes {
println!(" β’ {} ({:?})", node.short_name(), node.role());
}
}
fn print_ascii_architecture(graph: &HexGraph) {
let domain_count = graph.nodes_by_layer(Layer::Domain).len();
let port_count = graph.nodes_by_layer(Layer::Port).len();
let adapter_count = graph.nodes_by_layer(Layer::Adapter).len();
let app_count = graph.nodes_by_layer(Layer::Application).len();
println!(
r#"
ββββββββββββββββββββββββββββββββββββββ
β Application Layer ({app_count:2}) β
β [Directives, Queries] β
βββββββββββββ¬βββββββββββββββββββββββββ
β
βββββββββββββΌβββββββββββββββββββββββββ
β Port Layer ({port_count:2}) β
β [Repository Interfaces] β
βββββββββββββ¬βββββββββββββββββββββββββ
β
βββββββββΌββββββββ
β β β
βββββΌβββ ββββΌβββ ββββΌβββββ
βDomainβ βAdaptβ βInfrastβ
β ({domain_count:2}) β β ({adapter_count:2})β β (0) β
ββββββββ βββββββ βββββββββ
"#
);
}
fn health_check(graph: &HexGraph) {
let domain_count = graph.nodes_by_layer(Layer::Domain).len();
let port_count = graph.nodes_by_layer(Layer::Port).len();
let adapter_count = graph.nodes_by_layer(Layer::Adapter).len();
if domain_count > 0 {
println!("β
Domain layer present ({domain_count} entities)");
} else {
println!("β οΈ No domain entities found");
}
if port_count > 0 {
println!("β
Port layer present ({port_count} ports)");
} else {
println!("β οΈ No ports defined");
}
if adapter_count > 0 {
println!("β
Adapter layer present ({adapter_count} adapters)");
} else {
println!("β οΈ No adapters implemented");
}
if port_count > 0 && adapter_count == 0 {
println!("π‘ Tip: Ports without adapters need implementations!");
}
if domain_count == 0 && port_count == 0 && adapter_count == 0 {
println!("π Getting started: Check out the tutorials!");
}
}