use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use std::{collections::BTreeMap, fs}; pub fn build() -> TokenStream { let java_json: BTreeMap = serde_json::from_str( &fs::read_to_string("../../assets/en_us_java.json").expect("en_us_java is missing"), ) .unwrap(); let mut java_constants = TokenStream::new(); let mut java_match_arms = TokenStream::new(); for (name, value) in &java_json { let ident = to_valid_ident(name); let ident_str = ident.to_string(); let doc = if !value.is_empty() { quote!(#[doc = #value]) } else { quote!() }; java_constants.extend(quote! { #doc pub const #ident: &str = #name; }); java_match_arms.extend(quote! { #ident_str => Some(#ident), }); } let bedrock_content = fs::read_to_string("../../assets/en_us_bedrock.lang").expect("en_us_bedrock is missing"); let mut bedrock_constants = TokenStream::new(); let mut bedrock_match_arms = TokenStream::new(); for line in bedrock_content.lines() { let line = line.trim(); if line.is_empty() || line.starts_with('#') || line.starts_with('/') { continue; } if let Some((name, value)) = line.split_once('=') { let name = name.trim(); let value = value.trim(); let ident = to_valid_ident(name); let ident_str = ident.to_string(); let doc = if !value.is_empty() { quote!(#[doc = #value]) } else { quote!() }; bedrock_constants.extend(quote! { #doc pub const #ident: &str = #name; }); bedrock_match_arms.extend(quote! { #ident_str => Some(#ident), }); } } let mut java_value_match_arms = TokenStream::new(); for (name, value) in &java_json { java_value_match_arms.extend(quote! { #name => Some(#value), }); } let mut bedrock_value_match_arms = TokenStream::new(); for line in bedrock_content.lines() { let line = line.trim(); if line.is_empty() || line.starts_with('#') || line.starts_with('/') { continue; } if let Some((name, value)) = line.split_once('=') { let name = name.trim(); let value = value.trim(); bedrock_value_match_arms.extend(quote! { #name => Some(#value), }); } } // --- Final Assembly --- quote! { #![allow(clippy::doc_markdown)] pub mod java { #java_constants pub fn get(const_name: &str) -> Option<&'static str> { match const_name { #java_match_arms _ => None, } } pub fn get_value(key: &str) -> Option<&'static str> { match key { #java_value_match_arms _ => None, } } } pub mod bedrock { #bedrock_constants pub fn get(const_name: &str) -> Option<&'static str> { match const_name { #bedrock_match_arms _ => None, } } pub fn get_value(key: &str) -> Option<&'static str> { match key { #bedrock_value_match_arms _ => None, } } } } } fn to_valid_ident(name: &str) -> Ident { let mut clean = name.to_uppercase().replace(['.', ':', '-'], "_"); if clean.chars().next().is_some_and(|c| c.is_ascii_digit()) { clean.insert(0, '_'); } format_ident!("{}", clean) }