use crate::domain::capabilities::CapabilitySet;
use crate::domain::model::{FileModel, LanguageModel, ParseResult};
use crate::domain::report::AnalysisReport;
use crate::domain::request::{AnalysisConfig, AnalysisRequest};
use crate::domain::rule::{Rule, RuleSelection};
use crate::domain::types::{Finding, LanguageId, SourceFile};
use std::path::Path;
pub trait AnalysisService: Send + Sync {
fn analyze(&self, request: &AnalysisRequest) -> Result<AnalysisReport, String>;
}
pub trait ConfigPort: Send + Sync {
fn load(&self, root: &Path) -> Result<AnalysisConfig, String>;
}
pub trait RuleSelector: Send + Sync {
fn select(&self, selection: &RuleSelection, caps: &CapabilitySet) -> Vec<Box<dyn Rule>>;
}
pub trait FileFilter: Send + Sync {
fn include(&self, path: &Path, config: &AnalysisConfig) -> bool;
}
pub trait FixService: Send + Sync {
fn apply_safe_fixes(
&self,
findings: &[Finding],
sources: &[(SourceFile, String)],
) -> Result<Vec<AppliedFix>, String>;
}
#[derive(Debug, Clone)]
pub struct AppliedFix {
pub path: std::path::PathBuf,
pub description: String,
}
pub trait LanguageRegistry: Send + Sync {
fn supported(&self) -> Vec<LanguageId>;
fn get(&self, id: &LanguageId) -> Option<&dyn LanguageAdapter>;
}
pub trait LanguageAdapter: Send + Sync {
fn id(&self) -> LanguageId;
fn capabilities(&self) -> CapabilitySet;
fn detect(&self, path: &Path) -> bool;
fn parse(&self, source: &SourceFile) -> ParseResult;
fn build_model(&self, sources: &[SourceFile]) -> Result<LanguageModel, String>;
fn analyze_language(
&self,
model: &LanguageModel,
rules: &[Box<dyn Rule>],
) -> Vec<Finding> {
let mut out = Vec::new();
for rule in rules {
out.extend(rule.evaluate(model));
}
out
}
fn language_specific_findings(&self, _model: &LanguageModel) -> Vec<Finding> {
Vec::new()
}
fn extract_file_model(&self, source: &SourceFile) -> Result<FileModel, String>;
}