use camino::Utf8PathBuf;
use cordance_core::advise::{AdviseFinding, Severity};
use cordance_core::pack::CordancePack;
use cordance_core::source::SourceClass;
use super::AdviseRule;
pub struct RContracts1;
impl AdviseRule for RContracts1 {
fn id(&self) -> &'static str {
"R-contracts-1"
}
fn doctrine_anchor(&self) -> &'static str {
"doctrine/principles/event-contracts.md"
}
fn check(&self, pack: &CordancePack) -> Vec<AdviseFinding> {
let mut findings = Vec::new();
let schemas: Vec<_> = pack
.sources
.iter()
.filter(|r| {
r.class == SourceClass::ProjectSchema && r.path.as_str().ends_with(".schema.json")
})
.collect();
for schema in schemas {
let path_str = schema.path.as_str();
let stem = path_str
.rsplit('/')
.next()
.unwrap_or(path_str)
.trim_end_matches(".schema.json");
let has_fixture = pack
.sources
.iter()
.any(|r| r.path.as_str() != path_str && r.path.as_str().contains(stem));
if !has_fixture {
findings.push(AdviseFinding {
id: self.id().into(),
severity: Severity::Warning,
summary: format!("Schema {path_str} has no example fixture."),
doctrine_anchor: Utf8PathBuf::from(self.doctrine_anchor()),
project_paths: vec![schema.path.clone()],
remediation: format!(
"Add a fixture file alongside the schema: {stem}.example.json or \
tests/{stem}.json."
),
});
}
}
findings
}
}