#![cfg_attr(coverage_nightly, coverage(off))]
use super::{
AnalyzeComplexityContract, AnalyzeDeadCodeContract, AnalyzeLintHotspotContract,
AnalyzeSatdContract, AnalyzeTdgContract, BaseAnalysisContract, ContractValidation,
OutputFormat, QualityGateContract, QualityProfile, RefactorAutoContract, SatdSeverity,
};
use anyhow::Result;
use serde_json::Value;
use std::path::PathBuf;
pub fn map_mcp_tool(tool_name: &str, params: Value) -> Result<Box<dyn ContractValidation>> {
match tool_name {
"analyze_complexity" => map_complexity_contract(¶ms),
"analyze_satd" => map_satd_contract(¶ms),
"analyze_dead_code" => map_dead_code_contract(¶ms),
"analyze_tdg" => map_tdg_contract(¶ms),
"analyze_lint_hotspot" => map_lint_hotspot_contract(¶ms),
"quality_gate" => map_quality_gate_contract(¶ms),
"refactor_auto" => map_refactor_auto_contract(¶ms),
_ => anyhow::bail!("Unknown MCP tool: {tool_name}"),
}
}
fn map_complexity_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let contract = AnalyzeComplexityContract {
base: parse_base_params(params)?,
max_cyclomatic: params["max_cyclomatic"].as_u64().map(|n| n as u32),
max_cognitive: params["max_cognitive"].as_u64().map(|n| n as u32),
max_halstead: params["max_halstead"].as_f64(),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn map_satd_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let contract = AnalyzeSatdContract {
base: parse_base_params(params)?,
severity: parse_severity(¶ms["severity"]),
critical_only: params["critical_only"].as_bool().unwrap_or(false),
strict: params["strict"].as_bool().unwrap_or(false),
fail_on_violation: params["fail_on_violation"].as_bool().unwrap_or(false),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn map_dead_code_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let contract = AnalyzeDeadCodeContract {
base: parse_base_params(params)?,
include_unreachable: params["include_unreachable"].as_bool().unwrap_or(false),
min_dead_lines: params["min_dead_lines"].as_u64().unwrap_or(10) as usize,
max_percentage: params["max_percentage"].as_f64().unwrap_or(15.0),
fail_on_violation: params["fail_on_violation"].as_bool().unwrap_or(false),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn map_tdg_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let contract = AnalyzeTdgContract {
base: parse_base_params(params)?,
threshold: params["threshold"].as_f64().unwrap_or(1.5),
include_components: params["include_components"].as_bool().unwrap_or(false),
critical_only: params["critical_only"].as_bool().unwrap_or(false),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn map_lint_hotspot_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let contract = AnalyzeLintHotspotContract {
base: parse_base_params(params)?,
file: params["file"].as_str().map(PathBuf::from),
max_density: params["max_density"].as_f64().unwrap_or(5.0),
min_confidence: params["min_confidence"].as_f64().unwrap_or(0.8),
enforce: params["enforce"].as_bool().unwrap_or(false),
dry_run: params["dry_run"].as_bool().unwrap_or(false),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn map_quality_gate_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let contract = QualityGateContract {
base: parse_base_params(params)?,
profile: parse_quality_profile(¶ms["profile"]),
file: params["file"].as_str().map(PathBuf::from),
fail_on_violation: params["fail_on_violation"].as_bool().unwrap_or(false),
verbose: params["verbose"].as_bool().unwrap_or(false),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn map_refactor_auto_contract(params: &Value) -> Result<Box<dyn ContractValidation>> {
let file_path = params["file"]
.as_str()
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: file"))?;
let contract = RefactorAutoContract {
file: PathBuf::from(file_path),
format: parse_output_format(¶ms["format"]),
output: params["output"].as_str().map(PathBuf::from),
target_complexity: params["target_complexity"].as_u64().unwrap_or(8) as u32,
dry_run: params["dry_run"].as_bool().unwrap_or(false),
timeout: params["timeout"].as_u64().unwrap_or(60),
};
contract.validate()?;
Ok(Box::new(contract))
}
fn parse_base_params(params: &Value) -> Result<BaseAnalysisContract> {
let path = params["path"]
.as_str()
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: path"))?;
Ok(BaseAnalysisContract {
path: PathBuf::from(path),
format: parse_output_format(¶ms["format"]),
output: params["output"].as_str().map(PathBuf::from),
top_files: params["top_files"].as_u64().map(|n| n as usize),
include_tests: params["include_tests"].as_bool().unwrap_or(false),
timeout: params["timeout"].as_u64().unwrap_or(60),
})
}
fn parse_output_format(value: &Value) -> OutputFormat {
value
.as_str()
.and_then(|s| match s {
"table" => Some(OutputFormat::Table),
"json" => Some(OutputFormat::Json),
"yaml" => Some(OutputFormat::Yaml),
"markdown" => Some(OutputFormat::Markdown),
"csv" => Some(OutputFormat::Csv),
"summary" => Some(OutputFormat::Summary),
_ => None,
})
.unwrap_or_default()
}
fn parse_severity(value: &Value) -> Option<SatdSeverity> {
value.as_str().and_then(|s| match s {
"low" => Some(SatdSeverity::Low),
"medium" => Some(SatdSeverity::Medium),
"high" => Some(SatdSeverity::High),
"critical" => Some(SatdSeverity::Critical),
_ => None,
})
}
fn parse_quality_profile(value: &Value) -> QualityProfile {
value
.as_str()
.and_then(|s| match s {
"standard" => Some(QualityProfile::Standard),
"strict" => Some(QualityProfile::Strict),
"extreme" => Some(QualityProfile::Extreme),
"toyota" => Some(QualityProfile::Toyota),
_ => None,
})
.unwrap_or_default()
}