use alloc::{format, vec::Vec};
use super::{LintFinding, LintSeverity};
use crate::chemicals::svhc::{
CandidateList, SVHC_THRESHOLD_PCT, SvhcFindingKind, SvhcInput, check_svhc_declarations,
};
#[must_use]
pub fn lint_svhc_declarations(
substances: &[SvhcInput<'_>],
list: &CandidateList<'_>,
) -> Vec<LintFinding> {
let mut findings = Vec::new();
for f in check_svhc_declarations(substances, list) {
match f.kind {
SvhcFindingKind::MustDeclare => findings.push(LintFinding {
code: "svhc.article_33_communication_owed",
field: "svhcSubstances",
severity: LintSeverity::Notice,
message: format!(
"{} (CAS {}) is on the ECHA Candidate List as of {} and is declared at \
{:.3}% w/w, at or above the REACH Art. 33 threshold of {SVHC_THRESHOLD_PCT}% \
— is the downstream communication in place?",
f.substance_name, f.cas_number, list.as_of, f.concentration_pct
),
}),
SvhcFindingKind::NotOnCheckedList => findings.push(LintFinding {
code: "svhc.not_on_checked_list",
field: "svhcSubstances",
severity: LintSeverity::Notice,
message: format!(
"{} (CAS {}) is not on the Candidate List this node checked against \
({} of {} substances, as of {}) — it may still be an SVHC, or the CAS \
may be mistyped. Worth a manual check.",
f.substance_name,
f.cas_number,
list.entry_count(),
list.official_count,
list.as_of
),
}),
SvhcFindingKind::BelowThreshold => {}
}
}
if !substances.is_empty() && !list.is_complete() {
findings.push(LintFinding {
code: "svhc.candidate_list_partial",
field: "svhcSubstances",
severity: LintSeverity::Notice,
message: format!(
"these declarations were checked against {} of the {} substances on the ECHA \
Candidate List as of {} — a clean result means nothing matched the substances \
this list knows about, not that no SVHCs are present.",
list.entry_count(),
list.official_count,
list.as_of
),
});
}
findings
}