pydantic model generator for atproto lexicons
at main 1.2 kB view raw
1//! lexicon file parsing 2 3use std::fs; 4use std::io; 5use std::path::Path; 6 7use atrium_lex::LexiconDoc; 8use thiserror::Error; 9 10#[derive(Error, Debug)] 11pub enum ParseError { 12 #[error("not a directory: {0}")] 13 NotADirectory(String), 14 15 #[error("io error: {0}")] 16 Io(#[from] io::Error), 17 18} 19 20/// parse all lexicon files from a directory recursively 21pub fn parse_lexicons(dir: &Path) -> Result<Vec<LexiconDoc>, ParseError> { 22 if !dir.is_dir() { 23 return Err(ParseError::NotADirectory(dir.display().to_string())); 24 } 25 26 let mut docs = Vec::new(); 27 visit_dir(dir, &mut docs)?; 28 docs.sort_by(|a, b| a.id.cmp(&b.id)); 29 Ok(docs) 30} 31 32fn visit_dir(dir: &Path, docs: &mut Vec<LexiconDoc>) -> Result<(), ParseError> { 33 for entry in fs::read_dir(dir)? { 34 let path = entry?.path(); 35 36 if path.is_dir() { 37 visit_dir(&path, docs)?; 38 } else if path.extension().is_some_and(|e| e == "json") { 39 let content = fs::read_to_string(&path)?; 40 41 // skip non-lexicon json files silently 42 if let Ok(doc) = serde_json::from_str::<LexiconDoc>(&content) { 43 docs.push(doc); 44 } 45 } 46 } 47 Ok(()) 48}