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}