rust_relations_explorer/cli/mod.rs
1use clap::{Parser, Subcommand};
2
3#[derive(Debug, Parser)]
4#[command(
5 name = "rust-relations-explorer",
6 version,
7 about = "Rust Knowledge Graph System",
8 long_about = "Parse Rust projects into a knowledge graph and run queries. File discovery respects .gitignore and .ignore with parent traversal. Global git excludes are disabled for determinism. Use --no-ignore to bypass ignore rules."
9)]
10pub struct Cli {
11 #[command(subcommand)]
12 pub command: Commands,
13}
14
15#[derive(Debug, Subcommand)]
16pub enum Commands {
17 /// Build the knowledge graph from a source directory
18 Build {
19 /// Path to the Rust project root (directory containing src/)
20 #[arg(short, long, default_value = ".")]
21 path: String,
22 /// Path to a TOML configuration file
23 #[arg(long)]
24 config: Option<String>,
25 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
26 #[arg(
27 long,
28 default_value_t = false,
29 help = "Include files even if matched by .gitignore/.ignore. Global git excludes are always disabled for determinism."
30 )]
31 no_ignore: bool,
32 /// Ignore cache when building (do not reuse cached files)
33 #[arg(long, default_value_t = false)]
34 no_cache: bool,
35 /// Rebuild cache from scratch (clears previous cache)
36 #[arg(long, default_value_t = false)]
37 rebuild: bool,
38 /// Output JSON file path
39 #[arg(long)]
40 json: Option<String>,
41 /// Output DOT file path
42 #[arg(long)]
43 dot: Option<String>,
44 /// Output SVG file path
45 #[arg(long)]
46 svg: Option<String>,
47 /// DOT: enable/disable hierarchical clusters (default: on)
48 #[arg(long, value_parser = ["on", "off"], default_value = "on")]
49 dot_clusters: String,
50 /// DOT: include legend (default: on)
51 #[arg(long, value_parser = ["on", "off"], default_value = "on")]
52 dot_legend: String,
53 /// DOT: theme (light or dark)
54 #[arg(long, value_parser = ["light", "dark"], default_value = "light")]
55 dot_theme: String,
56 /// DOT: rank direction (LR or TB)
57 #[arg(long, value_parser = ["LR", "TB"], default_value = "LR")]
58 dot_rankdir: String,
59 /// DOT: edge splines style (curved, ortho, polyline)
60 #[arg(long, value_parser = ["curved", "ortho", "polyline"], default_value = "curved")]
61 dot_splines: String,
62 /// DOT: rounded node corners (on/off)
63 #[arg(long, value_parser = ["on", "off"], default_value = "on")]
64 dot_rounded: String,
65 /// SVG: add interactive enhancements (on/off)
66 #[arg(long, value_parser = ["on", "off"], default_value = "on")]
67 svg_interactive: String,
68 /// Save built graph to JSON file path
69 #[arg(long)]
70 save: Option<String>,
71 },
72 /// Run queries over the knowledge graph
73 Query {
74 #[command(subcommand)]
75 query: QueryCommands,
76 },
77}
78
79#[derive(Debug, Subcommand)]
80pub enum QueryCommands {
81 /// List files connected to the given file via relationships
82 ConnectedFiles {
83 /// Path to project root (directory containing src/)
84 #[arg(short, long, default_value = ".")]
85 path: String,
86 /// Path to a TOML configuration file
87 #[arg(long)]
88 config: Option<String>,
89 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
90 #[arg(
91 long,
92 default_value_t = false,
93 help = "Include files even if matched by .gitignore/.ignore. Global git excludes are always disabled for determinism."
94 )]
95 no_ignore: bool,
96 /// The file to analyze (absolute or relative)
97 #[arg(long)]
98 file: String,
99 /// Optional path to a prebuilt graph JSON (skips rebuild)
100 #[arg(long)]
101 graph: Option<String>,
102 /// Output format: text or json
103 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
104 format: String,
105 },
106 /// Show a single item's definition and relations by ItemId
107 ItemInfo {
108 /// Path to project root (directory containing src/)
109 #[arg(short, long, default_value = ".")]
110 path: String,
111 /// Path to a TOML configuration file
112 #[arg(long)]
113 config: Option<String>,
114 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
115 #[arg(long, default_value_t = false)]
116 no_ignore: bool,
117 /// ItemId (e.g., fn:createIcons:6)
118 #[arg(long, value_name = "ID")]
119 item_id: String,
120 /// Optional path to a prebuilt graph JSON (skips rebuild)
121 #[arg(long)]
122 graph: Option<String>,
123 /// Include code snippet of the item's definition
124 #[arg(long, default_value_t = true)]
125 show_code: bool,
126 /// Output format: text or json
127 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
128 format: String,
129 },
130 /// List files that call or are called by a given function name
131 FunctionUsage {
132 /// Path to project root (directory containing src/)
133 #[arg(short, long, default_value = ".")]
134 path: String,
135 /// Path to a TOML configuration file
136 #[arg(long)]
137 config: Option<String>,
138 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
139 #[arg(long, default_value_t = false)]
140 no_ignore: bool,
141 /// Function name to analyze
142 #[arg(long)]
143 function: String,
144 /// Direction: callers or callees
145 #[arg(long, value_parser = ["callers", "callees"], default_value = "callers")]
146 direction: String,
147 /// Optional path to a prebuilt graph JSON (skips rebuild)
148 #[arg(long)]
149 graph: Option<String>,
150 /// Output format: text or json
151 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
152 format: String,
153 },
154 /// Detect cycles between files
155 Cycles {
156 /// Path to project root (directory containing src/)
157 #[arg(short, long, default_value = ".")]
158 path: String,
159 /// Path to a TOML configuration file
160 #[arg(long)]
161 config: Option<String>,
162 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
163 #[arg(long, default_value_t = false)]
164 no_ignore: bool,
165 /// Optional path to a prebuilt graph JSON (skips rebuild)
166 #[arg(long)]
167 graph: Option<String>,
168 /// Output format: text or json
169 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
170 format: String,
171 },
172 /// Compute shortest path between two files
173 Path {
174 /// Path to project root (directory containing src/)
175 #[arg(short, long, default_value = ".")]
176 path: String,
177 /// Path to a TOML configuration file
178 #[arg(long)]
179 config: Option<String>,
180 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
181 #[arg(long, default_value_t = false)]
182 no_ignore: bool,
183 /// Source file path
184 #[arg(long)]
185 from: String,
186 /// Destination file path
187 #[arg(long)]
188 to: String,
189 /// Optional path to a prebuilt graph JSON (skips rebuild)
190 #[arg(long)]
191 graph: Option<String>,
192 /// Output format: text or json
193 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
194 format: String,
195 },
196 /// List top-N hub files by degree centrality
197 Hubs {
198 /// Path to project root (directory containing src/)
199 #[arg(short, long, default_value = ".")]
200 path: String,
201 /// Path to a TOML configuration file
202 #[arg(long)]
203 config: Option<String>,
204 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
205 #[arg(long, default_value_t = false)]
206 no_ignore: bool,
207 /// Optional path to a prebuilt graph JSON (skips rebuild)
208 #[arg(long)]
209 graph: Option<String>,
210 /// Metric: in, out, total
211 #[arg(long, value_parser = ["in", "out", "total"], default_value = "total")]
212 metric: String,
213 /// Top N results
214 #[arg(long, default_value_t = 10)]
215 top: usize,
216 /// Output format: text or json
217 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
218 format: String,
219 },
220 /// List top-N modules (directories) by degree centrality
221 ModuleCentrality {
222 /// Path to project root (directory containing src/)
223 #[arg(short, long, default_value = ".")]
224 path: String,
225 /// Path to a TOML configuration file
226 #[arg(long)]
227 config: Option<String>,
228 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
229 #[arg(long, default_value_t = false)]
230 no_ignore: bool,
231 /// Optional path to a prebuilt graph JSON (skips rebuild)
232 #[arg(long)]
233 graph: Option<String>,
234 /// Metric: in, out, total
235 #[arg(long, value_parser = ["in", "out", "total"], default_value = "total")]
236 metric: String,
237 /// Top N results
238 #[arg(long, default_value_t = 10)]
239 top: usize,
240 /// Output format: text or json
241 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
242 format: String,
243 },
244 /// List types implementing a trait
245 TraitImpls {
246 /// Path to project root (directory containing src/)
247 #[arg(short, long, default_value = ".")]
248 path: String,
249 /// Path to a TOML configuration file
250 #[arg(long)]
251 config: Option<String>,
252 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
253 #[arg(long, default_value_t = false)]
254 no_ignore: bool,
255 /// Trait name (e.g., Display)
256 #[arg(long, value_name = "NAME")]
257 r#trait: String,
258 /// Optional path to a prebuilt graph JSON (skips rebuild)
259 #[arg(long)]
260 graph: Option<String>,
261 /// Output format: text or json
262 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
263 format: String,
264 },
265 /// List items with no inbound usage edges (potentially dead code)
266 UnreferencedItems {
267 /// Path to project root (directory containing src/)
268 #[arg(short, long, default_value = ".")]
269 path: String,
270 /// Path to a TOML configuration file
271 #[arg(long)]
272 config: Option<String>,
273 /// Bypass ignore rules (.gitignore/.ignore) when discovering files
274 #[arg(long, default_value_t = false)]
275 no_ignore: bool,
276 /// Include public items as well (by default public items are excluded)
277 #[arg(long, default_value_t = false)]
278 include_public: bool,
279 /// Regex to exclude paths (e.g., 'tests|benches|examples')
280 #[arg(long)]
281 exclude: Option<String>,
282 /// Optional path to a prebuilt graph JSON (skips rebuild)
283 #[arg(long)]
284 graph: Option<String>,
285 /// Output format: text or json
286 #[arg(long, value_parser = ["text", "json"], default_value = "text")]
287 format: String,
288 },
289}
290
291#[must_use]
292pub fn parse() -> Cli {
293 Cli::parse()
294}