1pub mod analyzers;
9pub mod baseline;
10pub mod blame;
11pub mod config;
12pub mod context;
13pub mod domain;
14pub mod error;
15pub mod llm;
16pub mod parsers;
17pub mod reporters;
18pub mod sources;
19pub mod suppress;
20pub mod workspace;
21
22pub use config::Config;
23pub use context::ProjectContext;
24pub use domain::{
25 Attribution, ClaimKind, CodeFact, Confidence, Divergence, FactKind, Location, RuleId,
26 Severity, SpecClaim,
27};
28pub use error::SpecDriftError;
29
30use analyzers::DriftAnalyzer;
31use rayon::prelude::*;
32
33pub fn run(ctx: &ProjectContext, analyzers: &[Box<dyn DriftAnalyzer>]) -> Vec<Divergence> {
42 let mut all: Vec<Divergence> = analyzers
43 .par_iter()
44 .flat_map_iter(|a| a.analyze(ctx))
45 .collect();
46
47 all.sort_by(|a, b| {
48 a.location
49 .file
50 .cmp(&b.location.file)
51 .then_with(|| a.location.line.cmp(&b.location.line))
52 .then_with(|| a.rule.as_str().cmp(b.rule.as_str()))
53 });
54 all
55}
56
57pub fn apply_config(
60 mut divs: Vec<Divergence>,
61 cfg: &Config,
62 root: &std::path::Path,
63) -> Vec<Divergence> {
64 divs.retain(|d| !cfg.is_suppressed(d, root));
65 cfg.apply_severity_overrides(&mut divs);
66 divs
67}
68
69pub fn apply_strict(divs: &mut [Divergence]) {
73 for d in divs.iter_mut() {
74 if d.rule.confidence() != Confidence::Deterministic {
75 d.severity = d.severity.promoted();
76 }
77 }
78}