use anyhow::Result;
use clap::Parser;
mod check;
mod parallel;
mod php_parser;
#[derive(Parser)]
#[command(name = "similarity-php")]
#[command(about = "PHP code similarity analyzer")]
#[command(version)]
struct Cli {
#[arg(default_value = ".")]
paths: Vec<String>,
#[arg(short, long)]
print: bool,
#[arg(short, long, default_value = "0.85")]
threshold: f64,
#[arg(short, long, value_delimiter = ',')]
extensions: Option<Vec<String>>,
#[arg(short, long, default_value = "3")]
min_lines: Option<u32>,
#[arg(long)]
min_tokens: Option<u32>,
#[arg(short, long, default_value = "0.3")]
rename_cost: f64,
#[arg(long)]
no_size_penalty: bool,
#[arg(long)]
filter_function: Option<String>,
#[arg(long)]
filter_function_body: Option<String>,
#[arg(long)]
no_fast: bool,
#[arg(long = "experimental-overlap")]
overlap: bool,
#[arg(long, default_value = "8")]
overlap_min_window: u32,
#[arg(long, default_value = "25")]
overlap_max_window: u32,
#[arg(long, default_value = "0.25")]
overlap_size_tolerance: f64,
}
fn main() -> Result<()> {
let cli = Cli::parse();
let functions_enabled = true; let overlap_enabled = cli.overlap;
println!("Analyzing PHP code similarity...\n");
let separator = "-".repeat(60);
if !overlap_enabled || functions_enabled {
println!("=== Function Similarity ===");
check::check_paths(
cli.paths.clone(),
cli.threshold,
cli.rename_cost,
cli.extensions.as_ref(),
cli.min_lines.unwrap_or(3),
cli.min_tokens,
cli.no_size_penalty,
cli.print,
!cli.no_fast,
cli.filter_function.as_ref(),
cli.filter_function_body.as_ref(),
)?;
}
if overlap_enabled {
if functions_enabled {
println!("\n{separator}");
}
println!("=== Overlap Detection (Experimental) ===");
check::check_overlap(
cli.paths,
cli.threshold,
cli.overlap_min_window,
cli.overlap_max_window,
cli.overlap_size_tolerance,
cli.print,
)?;
}
Ok(())
}