Skip to main content

xbp_analysis/ports/
inbound.rs

1//! Inbound ports (application API).
2
3use crate::domain::capabilities::CapabilitySet;
4use crate::domain::model::{FileModel, LanguageModel, ParseResult};
5use crate::domain::report::AnalysisReport;
6use crate::domain::request::{AnalysisConfig, AnalysisRequest};
7use crate::domain::rule::{Rule, RuleSelection};
8use crate::domain::types::{Finding, LanguageId, SourceFile};
9use std::path::Path;
10
11/// Primary application service.
12pub trait AnalysisService: Send + Sync {
13    fn analyze(&self, request: &AnalysisRequest) -> Result<AnalysisReport, String>;
14}
15
16/// Load analysis configuration from project/global sources.
17pub trait ConfigPort: Send + Sync {
18    fn load(&self, root: &Path) -> Result<AnalysisConfig, String>;
19}
20
21/// Select which rules run for a request.
22pub trait RuleSelector: Send + Sync {
23    fn select(&self, selection: &RuleSelection, caps: &CapabilitySet) -> Vec<Box<dyn Rule>>;
24}
25
26/// Filter files / workspace roots.
27pub trait FileFilter: Send + Sync {
28    fn include(&self, path: &Path, config: &AnalysisConfig) -> bool;
29}
30
31/// Apply safe fixes (only when unambiguous).
32pub trait FixService: Send + Sync {
33    fn apply_safe_fixes(
34        &self,
35        findings: &[Finding],
36        sources: &[(SourceFile, String)],
37    ) -> Result<Vec<AppliedFix>, String>;
38}
39
40#[derive(Debug, Clone)]
41pub struct AppliedFix {
42    pub path: std::path::PathBuf,
43    pub description: String,
44}
45
46/// Query registered language adapters.
47pub trait LanguageRegistry: Send + Sync {
48    fn supported(&self) -> Vec<LanguageId>;
49    fn get(&self, id: &LanguageId) -> Option<&dyn LanguageAdapter>;
50}
51
52/// Per-language analysis contract.
53pub trait LanguageAdapter: Send + Sync {
54    fn id(&self) -> LanguageId;
55    fn capabilities(&self) -> CapabilitySet;
56    fn detect(&self, path: &Path) -> bool;
57    fn parse(&self, source: &SourceFile) -> ParseResult;
58    fn build_model(&self, sources: &[SourceFile]) -> Result<LanguageModel, String>;
59    fn analyze_language(
60        &self,
61        model: &LanguageModel,
62        rules: &[Box<dyn Rule>],
63    ) -> Vec<Finding> {
64        let mut out = Vec::new();
65        for rule in rules {
66            out.extend(rule.evaluate(model));
67        }
68        out
69    }
70    /// Optional adapter-local findings (Rust-specific rules).
71    fn language_specific_findings(&self, _model: &LanguageModel) -> Vec<Finding> {
72        Vec::new()
73    }
74    /// Map one parsed file into a FileModel (used by build_model).
75    fn extract_file_model(&self, source: &SourceFile) -> Result<FileModel, String>;
76}