use serde::Deserialize;
use std::collections::{HashMap, HashSet};
use std::sync::LazyLock;
#[derive(Debug, Deserialize)]
struct TermsJson {
languages: Vec<String>,
r_packages: Vec<String>,
canonical: HashMap<String, String>,
publisher_canonical: HashMap<String, String>,
journal_canonical: HashMap<String, String>,
publisher_prefix_canonical: Vec<[String; 2]>,
}
pub struct Terms {
pub languages: HashSet<String>,
pub r_packages: HashSet<String>,
pub canonical: HashMap<String, String>,
pub publisher_canonical: HashMap<String, String>,
pub journal_canonical: HashMap<String, String>,
pub publisher_prefix_canonical: Vec<(String, String)>,
}
const TERMS_JSON: &str = include_str!(concat!(env!("OUT_DIR"), "/terms.json"));
pub static TERMS: LazyLock<Terms> = LazyLock::new(|| {
let raw: TermsJson = serde_json::from_str(TERMS_JSON)
.expect("terms.json must parse (generated by tools/generate_terms_json.py)");
Terms {
languages: raw.languages.into_iter().collect(),
r_packages: raw.r_packages.into_iter().collect(),
canonical: raw.canonical,
publisher_canonical: raw.publisher_canonical,
journal_canonical: raw.journal_canonical,
publisher_prefix_canonical: raw
.publisher_prefix_canonical
.into_iter()
.map(|[prefix, canon]| (prefix, canon))
.collect(),
}
});
impl Terms {
pub fn canonical_form(&self, token: &str) -> Option<String> {
if token.trim().is_empty() {
return None;
}
if let Some(canon) = self.canonical.get(token) {
return Some(canon.clone());
}
if self.languages.contains(token) {
return Some(token.to_string());
}
if self.r_packages.contains(token) {
return Some(token.to_string());
}
None
}
}