rs_hack/commands/
summary.rs1use std::path::PathBuf;
4
5use anyhow::{Context, Result};
6
7#[derive(Debug)]
8pub struct SummaryReport {
9 pub path: PathBuf,
10 pub module_doc: Option<String>,
11 pub public_items: Vec<String>,
12 pub struct_count: usize,
13 pub enum_count: usize,
14 pub type_alias_count: usize,
15 pub function_names: Vec<String>,
16 pub reexports: Vec<String>,
17}
18
19pub fn run(path: &PathBuf) -> Result<SummaryReport> {
20 let content = std::fs::read_to_string(path)
21 .with_context(|| format!("Failed to read file: {:?}", path))?;
22
23 let syntax = syn::parse_file(&content)
24 .with_context(|| format!("Failed to parse file: {:?}", path))?;
25
26 let mut module_doc_parts: Vec<String> = Vec::new();
28 for attr in &syntax.attrs {
29 if let syn::AttrStyle::Inner(_) = attr.style {
30 if attr.path().is_ident("doc") {
31 if let Ok(syn::MetaNameValue { value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(s), .. }), .. }) =
32 attr.meta.require_name_value().cloned()
33 {
34 let text = s.value().trim().to_string();
35 if !text.is_empty() {
36 module_doc_parts.push(text);
37 }
38 }
39 }
40 }
41 }
42 let module_doc = if module_doc_parts.is_empty() {
43 None
44 } else {
45 Some(module_doc_parts.join(" "))
46 };
47
48 let mut public_items: Vec<String> = Vec::new();
49 let mut struct_count = 0usize;
50 let mut enum_count = 0usize;
51 let mut type_alias_count = 0usize;
52 let mut function_names: Vec<String> = Vec::new();
53 let mut reexports: Vec<String> = Vec::new();
54
55 for item in &syntax.items {
56 match item {
57 syn::Item::Struct(s) => {
58 struct_count += 1;
59 if is_public(&s.vis) {
60 public_items.push(s.ident.to_string());
61 }
62 }
63 syn::Item::Enum(e) => {
64 enum_count += 1;
65 if is_public(&e.vis) {
66 public_items.push(e.ident.to_string());
67 }
68 }
69 syn::Item::Type(t) => {
70 type_alias_count += 1;
71 if is_public(&t.vis) {
72 public_items.push(t.ident.to_string());
73 }
74 }
75 syn::Item::Fn(f) => {
76 function_names.push(f.sig.ident.to_string());
77 if is_public(&f.vis) {
78 public_items.push(f.sig.ident.to_string());
79 }
80 }
81 syn::Item::Trait(t) => {
82 if is_public(&t.vis) {
83 public_items.push(t.ident.to_string());
84 }
85 }
86 syn::Item::Const(c) => {
87 if is_public(&c.vis) {
88 public_items.push(c.ident.to_string());
89 }
90 }
91 syn::Item::Static(s) => {
92 if is_public(&s.vis) {
93 public_items.push(s.ident.to_string());
94 }
95 }
96 syn::Item::Mod(m) => {
97 if is_public(&m.vis) {
98 public_items.push(m.ident.to_string());
99 }
100 }
101 syn::Item::Use(u) => {
102 if is_public(&u.vis) {
103 let tokens = quote::quote!(#u);
104 reexports.push(tokens.to_string().replace(" :: ", "::").replace(" as ", " as "));
105 }
106 }
107 _ => {}
108 }
109 }
110
111 Ok(SummaryReport {
112 path: path.clone(),
113 module_doc,
114 public_items,
115 struct_count,
116 enum_count,
117 type_alias_count,
118 function_names,
119 reexports,
120 })
121}
122
123pub fn render(report: &SummaryReport) {
124 println!("Module: {}", report.path.display());
125
126 if report.public_items.is_empty() {
127 println!("Public items: (none)");
128 } else {
129 println!("Public items: {}", report.public_items.join(", "));
130 }
131
132 println!(
133 "Types: {} struct{}, {} enum{}, {} type alias{}",
134 report.struct_count,
135 if report.struct_count == 1 { "" } else { "s" },
136 report.enum_count,
137 if report.enum_count == 1 { "" } else { "s" },
138 report.type_alias_count,
139 if report.type_alias_count == 1 { "" } else { "es" },
140 );
141
142 if report.function_names.is_empty() {
143 println!("Functions: (none)");
144 } else {
145 println!("Functions: {}", report.function_names.join(", "));
146 }
147
148 if report.reexports.is_empty() {
149 println!("Re-exports: (none)");
150 } else {
151 for r in &report.reexports {
152 println!("Re-exports: {}", r);
153 }
154 }
155
156 match &report.module_doc {
157 Some(doc) => println!("Doc: {:?}", doc),
158 None => println!("Doc: (none)"),
159 }
160}
161
162fn is_public(vis: &syn::Visibility) -> bool {
163 matches!(vis, syn::Visibility::Public(_) | syn::Visibility::Restricted(_))
164}