Skip to main content

ferrous_forge/commands/fix/
mod.rs

1//! Auto-fix command for Ferrous Forge violations
2#![allow(clippy::too_many_lines)]
3//!
4//! This module implements intelligent auto-fixing for common Rust anti-patterns.
5//! It analyzes code context to ensure fixes are safe and won't break compilation.
6
7mod context;
8mod execution;
9mod file_processing;
10mod strategies;
11mod types;
12mod utils;
13
14use execution::execute_fix_process;
15pub use types::{FileContext, FilterOptions, FixConfig, FixResult, FunctionSignature};
16
17use crate::Result;
18use console::style;
19use std::collections::HashSet;
20use std::path::{Path, PathBuf};
21
22/// Execute the fix command
23///
24/// # Errors
25///
26/// Returns an error if the fix process encounters an I/O error or a
27/// violation cannot be applied.
28pub async fn execute(
29    path: Option<PathBuf>,
30    only: Option<String>,
31    skip: Option<String>,
32    dry_run: bool,
33    _limit: Option<usize>,
34) -> Result<()> {
35    execute_with_ai(path, only, skip, dry_run, _limit, false).await
36}
37
38/// Execute the fix command with optional AI analysis
39///
40/// # Errors
41///
42/// Returns an error if the fix process encounters an I/O error or a
43/// violation cannot be applied.
44pub async fn execute_with_ai(
45    path: Option<PathBuf>,
46    only: Option<String>,
47    skip: Option<String>,
48    dry_run: bool,
49    _limit: Option<usize>,
50    ai_analysis: bool,
51) -> Result<()> {
52    let project_path = path.unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
53
54    print_startup_banner(&project_path, dry_run);
55
56    let filter_options = parse_filter_options(only, skip);
57    execute_fix_process(&project_path, dry_run, filter_options, ai_analysis).await
58}
59
60/// Print startup banner with project information
61fn print_startup_banner(project_path: &Path, dry_run: bool) {
62    println!(
63        "{}",
64        style("🔧 Running Ferrous Forge auto-fix...").bold().cyan()
65    );
66    println!("📁 Project: {}", project_path.display());
67
68    if dry_run {
69        println!(
70            "{}",
71            style("â„šī¸ Dry-run mode - no changes will be made").yellow()
72        );
73    }
74}
75
76/// Parse filter options from command line arguments
77fn parse_filter_options(only: Option<String>, skip: Option<String>) -> FilterOptions {
78    let only_types: Option<HashSet<String>> = only
79        .as_ref()
80        .map(|s| s.split(',').map(|t| t.trim().to_uppercase()).collect());
81
82    let skip_types: Option<HashSet<String>> = skip
83        .as_ref()
84        .map(|s| s.split(',').map(|t| t.trim().to_uppercase()).collect());
85
86    FilterOptions {
87        only_types,
88        skip_types,
89    }
90}