Files
papercrate/backend/build.rs
T
2025-11-11 01:36:17 +01:00

124 lines
3.3 KiB
Rust

use std::env;
use std::fs;
use std::path::PathBuf;
use regex::escape;
use serde::Deserialize;
#[derive(Deserialize)]
struct CaseSuite {
cases: Vec<CaseName>,
}
#[derive(Deserialize)]
struct CaseName {
name: String,
}
#[derive(Deserialize)]
struct MonthSuite {
months: Vec<MonthDefinition>,
}
#[derive(Deserialize)]
struct MonthDefinition {
name: String,
month: u32,
#[serde(default)]
locales: Vec<String>,
}
fn sanitize(name: &str) -> String {
let mut out = String::with_capacity(name.len());
for ch in name.chars() {
if ch.is_ascii_alphanumeric() {
out.push(ch);
} else {
out.push('_');
}
}
if out.is_empty() {
"case".to_string()
} else if out.chars().next().unwrap().is_ascii_digit() {
format!("_{}", out)
} else {
out
}
}
fn quote(value: &str) -> String {
serde_json::to_string(value).expect("string literal")
}
fn generate_tests() -> Result<String, Box<dyn std::error::Error>> {
let yaml_path = PathBuf::from("tests/data/issued_at_cases.yaml");
let contents = fs::read_to_string(&yaml_path)?;
let suite: CaseSuite = serde_yaml::from_str(&contents)?;
let mut output =
String::from("#[cfg(test)]\npub mod issued_at_generated_tests {\n use super::*;\n");
for case in suite.cases {
let ident = sanitize(&case.name);
output.push_str(&format!(
" #[test]\n fn {}() {{\n run_named_case(\"{}\");\n }}\n",
ident, case.name
));
}
output.push_str("}\n");
Ok(output)
}
fn generate_months() -> Result<String, Box<dyn std::error::Error>> {
let yaml_path = PathBuf::from("resources/issued_at_months.yaml");
let contents = fs::read_to_string(&yaml_path)?;
let suite: MonthSuite = serde_yaml::from_str(&contents)?;
let mut pattern_parts = Vec::with_capacity(suite.months.len());
let mut entries = String::new();
for entry in &suite.months {
pattern_parts.push(escape(&entry.name));
let locales_literal = if entry.locales.is_empty() {
"&[]".to_string()
} else {
let joined = entry
.locales
.iter()
.map(|loc| quote(loc))
.collect::<Vec<_>>()
.join(", ");
format!("&[{}]", joined)
};
entries.push_str(&format!(
" MonthVariant {{ name: {}, month: {}, locales: {} }},\n",
quote(&entry.name),
entry.month,
locales_literal
));
}
let pattern_literal = quote(&pattern_parts.join("|"));
let output = format!(
"pub(super) static MONTH_VARIANTS: &[MonthVariant] = &[\n{entries}];\n\n",
entries = entries
) + &format!(
"pub(super) const MONTH_PATTERN: &str = {};\n",
pattern_literal
);
Ok(output)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=tests/data/issued_at_cases.yaml");
println!("cargo:rerun-if-changed=resources/issued_at_months.yaml");
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
fs::write(
out_dir.join("issued_at_generated_tests.rs"),
generate_tests()?,
)?;
fs::write(out_dir.join("issued_at_months.rs"), generate_months()?)?;
Ok(())
}