rusty_react_flow/
cli.rs

1use std::path::{Path, PathBuf};
2use std::fs;
3use clap::{Parser, ArgAction};
4use inquire::{Select, MultiSelect};
5
6#[derive(Parser, Debug)]
7#[command(author, version, about = "Analyzes TypeScript/JavaScript modules for imports and exports")]
8pub struct Cli {
9    /// Directory path to analyze (default: current directory)
10    #[arg(short, long, value_name = "PATH", default_value = ".")]
11    pub path: String,
12
13    /// Run in interactive mode
14    #[arg(short, long, action = ArgAction::SetTrue)]
15    pub interactive: bool,
16
17    /// Output JSON file (default: print to stdout)
18    #[arg(short, long, value_name = "FILE")]
19    pub output: Option<String>,
20}
21
22pub fn get_subdirectories(dir: &Path) -> Vec<PathBuf> {
23    let mut subdirs = Vec::new();
24
25    if let Ok(entries) = fs::read_dir(dir) {
26        for entry in entries.filter_map(|e| e.ok()) {
27            let path = entry.path();
28            if path.is_dir() {
29                subdirs.push(path);
30            }
31        }
32    }
33
34    subdirs
35}
36
37pub fn select_directory(interactive: bool, path: &str) -> PathBuf {
38    if !interactive {
39        return PathBuf::from(path);
40    }
41
42    let current_dir = std::env::current_dir().expect("Failed to get current directory");
43    let mut dirs = get_subdirectories(&current_dir);
44
45    if dirs.is_empty() {
46        println!("No subdirectories found in current directory.");
47        return current_dir;
48    }
49
50    dirs.insert(0, current_dir.clone());
51
52    let options: Vec<String> = dirs.iter()
53        .map(|p| p.to_string_lossy().to_string())
54        .collect();
55
56    let default_option = options[0].clone();
57
58    let selection = Select::new("Select directory to analyze:", options)
59        .prompt()
60        .unwrap_or_else(|_| default_option);
61
62    PathBuf::from(selection)
63}
64
65pub fn select_files(interactive: bool, target_dir: &Path, all_files: Vec<PathBuf>) -> Vec<PathBuf> {
66    if !interactive || all_files.is_empty() {
67        return all_files;
68    }
69
70    let file_options: Vec<String> = all_files.iter()
71        .map(|p| p.strip_prefix(target_dir).unwrap_or(p).to_string_lossy().to_string())
72        .collect();
73
74    let selected = MultiSelect::new(
75        "Select files to analyze (Space to select, Enter to confirm):",
76        file_options
77    )
78        .prompt()
79        .unwrap_or_else(|_| Vec::new());
80
81    if selected.is_empty() {
82        println!("No files selected, analyzing all files");
83        all_files
84    } else {
85        selected.into_iter()
86            .map(|s| target_dir.join(s))
87            .collect()
88    }
89}