use crate::context::CliContext;
use crate::paths;
use anyhow::Result;
#[derive(Debug, Clone)]
pub struct LintArgs {
pub fix: bool,
}
pub async fn handle_lint(ctx: &mut CliContext, args: &LintArgs) -> Result<()> {
println!();
println!("đ Code Linting");
println!("âââââââââââââââââââââââââââââââââââââââââââââââ");
println!();
if !ctx.is_project_initialized() {
return Err(anyhow::anyhow!(
"Not in a Mecha10 project directory.\n\
Run 'mecha10 init' to create a new project."
));
}
let project = ctx.project()?;
println!("Project: {}", project.root().display());
println!();
let mut all_passed = true;
println!("Running Rust linting (clippy)...");
let clippy_result = if args.fix {
std::process::Command::new("cargo")
.args(["clippy", "--fix", "--allow-dirty", "--allow-staged"])
.current_dir(project.root())
.status()
} else {
std::process::Command::new("cargo")
.args(["clippy", "--all-targets", "--", "-D", "warnings"])
.current_dir(project.root())
.status()
};
match clippy_result {
Ok(status) if status.success() => {
println!("â
Rust linting passed");
}
Ok(_) => {
println!("â Rust linting failed");
all_passed = false;
}
Err(e) => {
println!("â ī¸ Could not run clippy: {}", e);
println!(" Install with: rustup component add clippy");
}
}
println!();
println!("Running Python linting (ruff)...");
let python_dir = project.root().join(paths::framework::TASKRUNNER_DIR);
if python_dir.exists() {
let ruff_result = if args.fix {
std::process::Command::new("ruff")
.args(["check", "--fix", "."])
.current_dir(&python_dir)
.status()
} else {
std::process::Command::new("ruff")
.args(["check", "."])
.current_dir(&python_dir)
.status()
};
match ruff_result {
Ok(status) if status.success() => {
println!("â
Python linting passed");
}
Ok(_) => {
println!("â Python linting failed");
all_passed = false;
}
Err(e) => {
println!("â ī¸ Could not run ruff: {}", e);
println!(" Install with: pip install ruff");
}
}
} else {
println!("âšī¸ No Python code found, skipping");
}
println!();
println!("Running GDScript linting...");
let godot_dir = if let Ok(framework_path) = std::env::var("MECHA10_FRAMEWORK_PATH") {
std::path::PathBuf::from(framework_path).join(paths::framework::SIMULATION_GODOT_DIR)
} else {
project.root().join(paths::project::SIMULATION_GODOT_DIR)
};
if godot_dir.exists() {
println!("âšī¸ GDScript linting not yet implemented");
println!(" Consider using gdlint or gdscript-linter");
} else {
println!("âšī¸ No GDScript code found, skipping");
}
println!();
println!("Checking file naming conventions...");
let ls_lint_config = project.root().join(paths::meta::LS_LINT_CONFIG);
if ls_lint_config.exists() {
let ls_lint_result = std::process::Command::new("pnpm")
.args(["lint:ls"])
.current_dir(project.root())
.status();
match ls_lint_result {
Ok(status) if status.success() => {
println!("â
File naming conventions passed");
}
Ok(_) => {
println!("â File naming conventions failed");
all_passed = false;
}
Err(_) => {
println!("âšī¸ ls-lint not available, skipping");
}
}
} else {
println!("âšī¸ No ls-lint config found, skipping");
}
println!();
println!("âââââââââââââââââââââââââââââââââââââââââââââââ");
if all_passed {
println!("â
All linting checks passed!");
} else {
println!("â Some linting checks failed");
if !args.fix {
println!();
println!("Run with --fix to automatically fix issues:");
println!(" mecha10 lint --fix");
}
return Err(anyhow::anyhow!("Linting failed"));
}
println!();
Ok(())
}