use crate::review::{CodeReviewer, CodeReviewRequest, ReviewType, DeveloperPatterns, NamingPatterns, ConventionType, StylePreferences, IndentStyle, QuoteStyle, BraceStyle};
use anyhow::Result;
use clap::Parser;
use std::fs;
#[derive(Parser)]
pub struct ReviewCommand {
#[arg(short, long)]
pub file: Option<String>,
#[arg(short, long)]
pub code: Option<String>,
#[arg(short, long, default_value = "rust")]
pub language: String,
#[arg(short, long, default_value = "self")]
pub review_type: String,
#[arg(short, long)]
pub context: Option<String>,
#[arg(short, long)]
pub use_patterns: bool,
}
impl ReviewCommand {
pub async fn run(&self) -> Result<()> {
let code = if let Some(ref file) = self.file {
fs::read_to_string(file)?
} else if let Some(ref code) = self.code {
code.clone()
} else {
println!("Please provide --file or --code");
return Ok(());
};
let review_type = match self.review_type.as_str() {
"pre-commit" => ReviewType::PreCommit,
"pr" | "pull-request" => ReviewType::PullRequest,
"security" => ReviewType::Security,
_ => ReviewType::SelfReview,
};
let request = CodeReviewRequest {
code: code.clone(),
language: self.language.clone(),
context: self.context.clone(),
file_path: self.file.clone(),
review_type,
};
let reviewer = if self.use_patterns {
let patterns = get_sample_patterns();
CodeReviewer::with_patterns(patterns)
} else {
CodeReviewer::new()
};
let result = reviewer.review(&request);
println!("\n=== Code Review Results ===\n");
println!("Score: {:.0}/100\n", result.score);
println!("{}\n", result.summary);
if !result.positive_observations.is_empty() {
println!("â Positive Observations:");
for obs in &result.positive_observations {
println!(" - {}", obs);
}
println!();
}
if !result.issues.is_empty() {
println!("Issues Found:");
for issue in &result.issues {
let severity_icon = match issue.severity {
crate::review::IssueSeverity::Critical => "đ´",
crate::review::IssueSeverity::Error => "â",
crate::review::IssueSeverity::Warning => "â ī¸",
crate::review::IssueSeverity::Info => "âšī¸",
};
println!(" {} [{}] {}", severity_icon, format!("{:?}", issue.severity), issue.message);
if let Some(line) = issue.line {
println!(" Line: {}", line);
}
if let Some(ref suggestion) = issue.suggestion {
println!(" Suggestion: {}", suggestion);
}
}
println!();
}
if !result.patterns_detected.is_empty() {
println!("Patterns Detected:");
for pattern in &result.patterns_detected {
println!(" - {}", pattern);
}
println!();
}
if !result.suggestions.is_empty() {
println!("Suggestions:");
for suggestion in &result.suggestions {
println!(" âĸ {}", suggestion);
}
}
Ok(())
}
}
fn get_sample_patterns() -> DeveloperPatterns {
DeveloperPatterns {
naming_conventions: NamingPatterns {
variables: ConventionType::SnakeCase,
functions: ConventionType::SnakeCase,
constants: ConventionType::SnakeCase,
classes: ConventionType::PascalCase,
files: ConventionType::SnakeCase,
},
style_preferences: StylePreferences {
indent_style: IndentStyle::Spaces,
indent_size: 4,
quote_style: QuoteStyle::Double,
semicolon_usage: false,
brace_style: BraceStyle::KR,
},
common_patterns: vec![
"async/await".to_string(),
"error propagation".to_string(),
"derive macros".to_string(),
],
test_approaches: vec![
"unit tests".to_string(),
"integration tests".to_string(),
],
documentation_style: Some("doc comments".to_string()),
}
}