use super::Claim;
use super::text::normalise;
pub(super) const DERIVATIVE_MARKERS: &[&str] = &[
"reply",
"erratum",
"errata",
"corrigendum",
"correction",
"comment on",
"response to",
"in response",
"faculty opinions recommendation",
"retraction of",
"expression of concern",
];
const LEADING_MARKERS: &[&str] = &["comment on", "response to", "in response", "correction"];
pub fn is_derivative(title: &str) -> bool {
derivative_kind(title).is_some()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum WorkKind {
Reply,
Correction,
Comment,
Retraction,
ExpressionOfConcern,
Recommendation,
}
impl WorkKind {
pub fn as_str(self) -> &'static str {
match self {
WorkKind::Reply => "reply",
WorkKind::Correction => "correction",
WorkKind::Comment => "comment",
WorkKind::Retraction => "retraction",
WorkKind::ExpressionOfConcern => "expression of concern",
WorkKind::Recommendation => "recommendation",
}
}
}
pub fn derivative_kind(title: &str) -> Option<&'static str> {
derivative_work_kind(title).map(WorkKind::as_str)
}
pub fn derivative_work_kind(title: &str) -> Option<WorkKind> {
let norm = normalise(title);
let words = format!(" {norm} ");
let leading = |m: &str| match m {
"correction" => {
norm == "correction"
|| norm.starts_with("correction to ")
|| title
.trim_start()
.get(..11)
.is_some_and(|h| h.eq_ignore_ascii_case("correction:"))
}
_ => words.starts_with(&format!(" {m} ")),
};
let marker = DERIVATIVE_MARKERS
.iter()
.find(|m| match LEADING_MARKERS.contains(m) {
true => leading(m),
false => words.contains(&format!(" {m} ")),
})?;
Some(match *marker {
"reply" | "response to" | "in response" => WorkKind::Reply,
"erratum" | "errata" | "corrigendum" | "correction" => WorkKind::Correction,
"comment on" => WorkKind::Comment,
"retraction of" => WorkKind::Retraction,
"expression of concern" => WorkKind::ExpressionOfConcern,
_ => WorkKind::Recommendation,
})
}
pub fn claim_mentions_derivative(claim: &Claim) -> bool {
[claim.text.as_deref(), claim.title.as_deref()]
.into_iter()
.flatten()
.any(|text| {
let words = format!(" {} ", normalise(text));
DERIVATIVE_MARKERS
.iter()
.any(|m| words.contains(&format!(" {m} ")))
})
}