mod atproto; mod git; mod http; mod jsonfile; mod local; mod slices; pub use atproto::AtProtoSource; pub use git::GitSource; pub use http::HttpSource; use jacquard_common::IntoStatic; pub use jsonfile::JsonFileSource; pub use local::LocalSource; pub use slices::SlicesSource; use jacquard_lexicon::lexicon::LexiconDoc; use miette::{IntoDiagnostic, Result}; use std::collections::HashMap; use std::future::Future; #[derive(Debug, Clone)] pub struct Source { pub name: String, pub source_type: SourceType, pub explicit_priority: Option, } impl Source { /// Get effective priority based on type and explicit override pub fn priority(&self) -> i32 { if let Some(p) = self.explicit_priority { return p; } // Default priorities match &self.source_type { SourceType::Local(_) => 100, // Highest - dev work SourceType::JsonFile(_) => 75, // High - bundled exports SourceType::Slices(_) => 60, // High-middle - slices network SourceType::AtProto(_) => 50, // Middle - canonical published SourceType::Http(_) => 25, // Lower middle - indexed samples SourceType::Git(_) => 0, // Lowest - might be stale } } pub async fn fetch(&self) -> Result>> { self.source_type.fetch().await } } #[derive(Debug, Clone)] pub enum SourceType { AtProto(AtProtoSource), Git(GitSource), Http(HttpSource), JsonFile(JsonFileSource), Local(LocalSource), Slices(SlicesSource), } pub trait LexiconSource { fn fetch(&self) -> impl Future>>> + Send; } impl LexiconSource for SourceType { async fn fetch(&self) -> Result>> { match self { SourceType::AtProto(s) => s.fetch().await, SourceType::Git(s) => s.fetch().await, SourceType::Http(s) => s.fetch().await, SourceType::JsonFile(s) => s.fetch().await, SourceType::Local(s) => s.fetch().await, SourceType::Slices(s) => s.fetch().await, } } } pub fn parse_from_index_or_lexicon_file( content: &str, ) -> miette::Result<(String, LexiconDoc<'static>)> { let value: serde_json::Value = serde_json::from_str(content).into_diagnostic()?; if let Some(map) = value.as_object() { if map.contains_key("schema") && map.contains_key("authority") { if let Some(schema) = map.get("schema") { let schema = serde_json::to_string(schema).into_diagnostic()?; match serde_json::from_str::(&schema) { Ok(doc) => { let nsid = doc.id.to_string(); let doc = doc.into_static(); Ok((nsid, doc)) } Err(e) => { // Not a lexicon, skip Err(miette::miette!("Invalid lexicon file: {e}")) } } } else { Err(miette::miette!("Invalid lexicon file")) } } else if map.contains_key("id") && map.contains_key("lexicon") { match serde_json::from_str::(&content) { Ok(doc) => { let nsid = doc.id.to_string(); let doc = doc.into_static(); Ok((nsid, doc)) } Err(e) => { // Not a lexicon, skip Err(miette::miette!("Invalid lexicon file: {e}")) } } } else { Err(miette::miette!("Invalid lexicon file")) } } else { Err(miette::miette!("Invalid lexicon file")) } }