1use serde::Deserialize;
7use std::collections::{HashMap, HashSet};
8use std::sync::LazyLock;
9
10#[derive(Debug, Deserialize)]
11struct TermsJson {
12 languages: Vec<String>,
13 r_packages: Vec<String>,
14 canonical: HashMap<String, String>,
15 publisher_canonical: HashMap<String, String>,
16 journal_canonical: HashMap<String, String>,
17 publisher_prefix_canonical: Vec<[String; 2]>,
20}
21
22pub struct Terms {
23 pub languages: HashSet<String>,
24 pub r_packages: HashSet<String>,
25 pub canonical: HashMap<String, String>,
26 pub publisher_canonical: HashMap<String, String>,
27 pub journal_canonical: HashMap<String, String>,
28 pub publisher_prefix_canonical: Vec<(String, String)>,
29}
30
31const TERMS_JSON: &str = include_str!(concat!(env!("OUT_DIR"), "/terms.json"));
36
37pub static TERMS: LazyLock<Terms> = LazyLock::new(|| {
38 let raw: TermsJson = serde_json::from_str(TERMS_JSON)
39 .expect("terms.json must parse (generated by tools/generate_terms_json.py)");
40 Terms {
41 languages: raw.languages.into_iter().collect(),
42 r_packages: raw.r_packages.into_iter().collect(),
43 canonical: raw.canonical,
44 publisher_canonical: raw.publisher_canonical,
45 journal_canonical: raw.journal_canonical,
46 publisher_prefix_canonical: raw
47 .publisher_prefix_canonical
48 .into_iter()
49 .map(|[prefix, canon]| (prefix, canon))
50 .collect(),
51 }
52});
53
54impl Terms {
55 pub fn canonical_form(&self, token: &str) -> Option<String> {
58 if token.trim().is_empty() {
59 return None;
60 }
61 if let Some(canon) = self.canonical.get(token) {
62 return Some(canon.clone());
63 }
64 if self.languages.contains(token) {
65 return Some(token.to_string());
66 }
67 if self.r_packages.contains(token) {
68 return Some(token.to_string());
69 }
70 None
71 }
72}