use std::collections::HashMap;
#[cfg(feature = "schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::grouping;
use crate::options::BibliographyOptions;
use crate::template::{
LocalizedTemplateSpec, Template, TemplateReference, TemplateVariants, locale_matches,
};
fn default_true() -> bool {
true
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub struct BibliographySpec {
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<BibliographyOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template_ref: Option<TemplateReference>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub template: Option<Template>,
#[serde(skip_serializing_if = "Option::is_none")]
pub locales: Option<Vec<LocalizedTemplateSpec>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_variants: Option<TemplateVariants>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sort: Option<grouping::GroupSortEntry>,
#[serde(default = "default_true")]
pub groups_enabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub groups: Option<Vec<grouping::BibliographyGroup>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom: Option<HashMap<String, serde_json::Value>>,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_yaml::Value>,
}
impl Default for BibliographySpec {
fn default() -> Self {
Self {
options: None,
template_ref: None,
template: None,
locales: None,
type_variants: None,
sort: None,
groups_enabled: true,
groups: None,
custom: None,
unknown_fields: std::collections::BTreeMap::new(),
}
}
}
impl BibliographySpec {
pub fn resolve_template(&self) -> Option<Template> {
self.template.clone().or_else(|| {
self.template_ref
.as_ref()
.and_then(TemplateReference::bibliography_template)
})
}
pub fn resolve_template_for_language(&self, language: Option<&str>) -> Option<Template> {
if let Some(language) = language
&& let Some(locales) = &self.locales
&& let Some(matched) = locales.iter().find(|spec| {
spec.locale
.as_ref()
.is_some_and(|targets| locale_matches(targets, language))
})
{
return Some(matched.template.clone());
}
self.locales
.as_ref()
.and_then(|locales| {
locales
.iter()
.find(|spec| spec.default.unwrap_or(false))
.map(|spec| spec.template.clone())
})
.or_else(|| self.resolve_template())
}
}