tauri_plugin_typegen/interface/
output.rs

1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum LogLevel {
5    Error,
6    Warning,
7    Info,
8    Debug,
9    Verbose,
10}
11
12impl fmt::Display for LogLevel {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        match self {
15            LogLevel::Error => write!(f, "ERROR"),
16            LogLevel::Warning => write!(f, "WARN"),
17            LogLevel::Info => write!(f, "INFO"),
18            LogLevel::Debug => write!(f, "DEBUG"),
19            LogLevel::Verbose => write!(f, "VERBOSE"),
20        }
21    }
22}
23
24#[derive(Debug, Clone)]
25pub struct Logger {
26    verbose: bool,
27    debug: bool,
28}
29
30impl Logger {
31    pub fn new(verbose: bool, debug: bool) -> Self {
32        Self { verbose, debug }
33    }
34
35    pub fn should_log(&self, level: LogLevel) -> bool {
36        match level {
37            LogLevel::Error | LogLevel::Warning | LogLevel::Info => true,
38            LogLevel::Debug => self.debug || self.verbose,
39            LogLevel::Verbose => self.verbose,
40        }
41    }
42
43    pub fn log(&self, level: LogLevel, message: &str) {
44        if self.should_log(level) {
45            let icon = match level {
46                LogLevel::Error => "❌",
47                LogLevel::Warning => "⚠️",
48                LogLevel::Info => "ℹ️",
49                LogLevel::Debug => "🔍",
50                LogLevel::Verbose => "💬",
51            };
52            println!("{} {}", icon, message);
53        }
54    }
55
56    pub fn error(&self, message: &str) {
57        self.log(LogLevel::Error, message);
58    }
59
60    pub fn warning(&self, message: &str) {
61        self.log(LogLevel::Warning, message);
62    }
63
64    pub fn info(&self, message: &str) {
65        self.log(LogLevel::Info, message);
66    }
67
68    pub fn debug(&self, message: &str) {
69        self.log(LogLevel::Debug, message);
70    }
71
72    pub fn verbose(&self, message: &str) {
73        self.log(LogLevel::Verbose, message);
74    }
75}
76
77pub struct ProgressReporter {
78    logger: Logger,
79    current_step: usize,
80    total_steps: usize,
81    step_name: String,
82}
83
84impl ProgressReporter {
85    pub fn new(logger: Logger, total_steps: usize) -> Self {
86        Self {
87            logger,
88            current_step: 0,
89            total_steps,
90            step_name: String::new(),
91        }
92    }
93
94    pub fn start_step(&mut self, step_name: &str) {
95        self.current_step += 1;
96        self.step_name = step_name.to_string();
97
98        if self.logger.should_log(LogLevel::Info) {
99            let progress = if self.total_steps > 0 {
100                format!(" ({}/{})", self.current_step, self.total_steps)
101            } else {
102                String::new()
103            };
104            self.logger.info(&format!("🚀 {}{}", step_name, progress));
105        }
106    }
107
108    pub fn complete_step(&self, message: Option<&str>) {
109        if let Some(msg) = message {
110            self.logger
111                .info(&format!("✅ {} - {}", self.step_name, msg));
112        } else {
113            self.logger.info(&format!("✅ {}", self.step_name));
114        }
115    }
116
117    pub fn fail_step(&self, error: &str) {
118        self.logger
119            .error(&format!("Failed {}: {}", self.step_name, error));
120    }
121
122    pub fn update_progress(&self, message: &str) {
123        self.logger.verbose(&format!("  → {}", message));
124    }
125
126    pub fn finish(&self, total_message: &str) {
127        self.logger.info(&format!("🎉 {}", total_message));
128    }
129}
130
131pub fn print_usage_info(output_path: &str, generated_files: &[String]) {
132    println!("\n💡 Usage in your frontend:");
133    for file in generated_files {
134        if file.ends_with("index.ts") || file.ends_with("index.js") {
135            println!(
136                "  import {{ /* your commands */ }} from '{}/{}'",
137                output_path.trim_end_matches('/'),
138                file.trim_end_matches(".ts").trim_end_matches(".js")
139            );
140            break;
141        }
142    }
143
144    println!("\n📁 Generated files:");
145    for file in generated_files {
146        println!("  📄 {}/{}", output_path, file);
147    }
148}
149
150pub fn print_dependency_visualization_info(output_path: &str) {
151    println!("\n🌐 Dependency visualization generated:");
152    println!("  📄 {}/dependency-graph.txt", output_path);
153    println!("  📄 {}/dependency-graph.dot", output_path);
154    println!(
155        "\n💡 To generate a visual graph: dot -Tpng {}/dependency-graph.dot -o graph.png",
156        output_path
157    );
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn test_logger_verbose_mode() {
166        let logger = Logger::new(true, false);
167        assert!(logger.should_log(LogLevel::Verbose));
168        assert!(logger.should_log(LogLevel::Info));
169        assert!(logger.should_log(LogLevel::Error));
170        assert!(logger.should_log(LogLevel::Debug)); // Verbose enables debug
171    }
172
173    #[test]
174    fn test_logger_normal_mode() {
175        let logger = Logger::new(false, false);
176        assert!(!logger.should_log(LogLevel::Verbose));
177        assert!(!logger.should_log(LogLevel::Debug));
178        assert!(logger.should_log(LogLevel::Info));
179        assert!(logger.should_log(LogLevel::Error));
180    }
181
182    #[test]
183    fn test_logger_debug_mode() {
184        let logger = Logger::new(false, true);
185        assert!(!logger.should_log(LogLevel::Verbose));
186        assert!(logger.should_log(LogLevel::Debug));
187        assert!(logger.should_log(LogLevel::Info));
188    }
189
190    #[test]
191    fn test_progress_reporter() {
192        let logger = Logger::new(false, false);
193        let mut reporter = ProgressReporter::new(logger, 3);
194
195        // Test step progression
196        assert_eq!(reporter.current_step, 0);
197
198        reporter.start_step("First Step");
199        assert_eq!(reporter.current_step, 1);
200        assert_eq!(reporter.step_name, "First Step");
201
202        reporter.start_step("Second Step");
203        assert_eq!(reporter.current_step, 2);
204        assert_eq!(reporter.step_name, "Second Step");
205    }
206}