use std::fmt::Write; use std::path::Path; use fancy_regex::Regex; use once_cell::sync::Lazy; use rustypipe::timeago::TimeUnit; use crate::util; const TARGET_PATH: &str = "src/dictionary.rs"; fn parse_tu(tu: &str) -> (u8, Option) { static TU_PATTERN: Lazy = Lazy::new(|| Regex::new(r"^(\d*)(\w?)$").unwrap()); match TU_PATTERN.captures(tu).unwrap() { Some(cap) => ( cap.get(1).unwrap().as_str().parse().unwrap_or(1), match cap.get(2).unwrap().as_str() { "s" => Some(TimeUnit::Second), "m" => Some(TimeUnit::Minute), "h" => Some(TimeUnit::Hour), "D" => Some(TimeUnit::Day), "W" => Some(TimeUnit::Week), "M" => Some(TimeUnit::Month), "Y" => Some(TimeUnit::Year), "" => None, _ => panic!("invalid time unit: {}", tu), }, ), None => panic!("invalid time unit: {}", tu), } } pub fn generate_dictionary(project_root: &Path) { let dict = util::read_dict(project_root); let code_head = r#"// This file is automatically generated. DO NOT EDIT. use crate::{ model::Language, timeago::{DateCmp, TaToken, TimeUnit}, }; pub struct Entry { pub by_char: bool, pub timeago_tokens: phf::Map<&'static str, TaToken>, pub date_order: &'static [DateCmp], pub months: phf::Map<&'static str, u8>, pub timeago_nd_tokens: phf::Map<&'static str, TaToken>, } "#; let mut code_timeago_tokens = r#"#[rustfmt::skip] pub fn entry(lang: Language) -> Entry { match lang { "# .to_owned(); dict.iter().for_each(|(lang, entry)| { // Match selector let mut selector = format!("Language::{:?}", lang); entry.equivalent.iter().for_each(|eq| { let _ = write!(selector, " | Language::{:?}", eq); }); // Timeago tokens let mut ta_tokens = phf_codegen::Map::<&str>::new(); entry.timeago_tokens.iter().for_each(|(txt, tu_str)| { let (n, unit) = parse_tu(tu_str); match unit { Some(unit) => ta_tokens.entry( txt, &format!("TaToken {{ n: {}, unit: Some(TimeUnit::{:?}) }}", n, unit), ), None => ta_tokens.entry(txt, &format!("TaToken {{ n: {}, unit: None }}", n)), }; }); // Months let mut months = phf_codegen::Map::<&str>::new(); entry.months.iter().for_each(|(txt, n_mon)| { months.entry(txt, &n_mon.to_string()); }); // Timeago(ND) tokens let mut ta_nd_tokens = phf_codegen::Map::<&str>::new(); entry.timeago_nd_tokens.iter().for_each(|(txt, tu_str)| { let (n, unit) = parse_tu(tu_str); match unit { Some(unit) => ta_nd_tokens.entry( txt, &format!("TaToken {{ n: {}, unit: Some(TimeUnit::{:?}) }}", n, unit), ), None => ta_nd_tokens.entry(txt, &format!("TaToken {{ n: {}, unit: None }}", n)), }; }); // Date order let mut date_order = "&[".to_owned(); entry.date_order.chars().for_each(|c| { let _ = write!(date_order, "DateCmp::{}, ", c); }); date_order = date_order.trim_end_matches([' ', ',']).to_owned() + "]"; let code_ta_tokens = &ta_tokens.build().to_string().replace('\n', "\n "); let code_ta_nd_tokens = &ta_nd_tokens.build().to_string().replace('\n', "\n "); let code_months = &months.build().to_string().replace('\n', "\n "); let _ = write!(code_timeago_tokens, "{} => Entry {{\n by_char: {:?},\n timeago_tokens: {},\n date_order: {},\n months: {},\n timeago_nd_tokens: {},\n }},\n ", selector, entry.by_char, code_ta_tokens, date_order, code_months, code_ta_nd_tokens); }); code_timeago_tokens = code_timeago_tokens.trim_end().to_owned() + "\n }\n}\n"; let code = format!("{}\n{}", code_head, code_timeago_tokens); let mut target_path = project_root.to_path_buf(); target_path.push(TARGET_PATH); std::fs::write(target_path, code).unwrap(); }