#[derive(
Clone,
Copy,
Debug,
Default,
Eq,
PartialEq,
serde::Deserialize,
serde::Serialize,
)]
#[serde(rename_all = "snake_case")]
pub enum Grammar {
#[default]
Delimited,
Bracketed,
}
#[derive(
Clone,
Copy,
Debug,
Default,
Eq,
PartialEq,
serde::Deserialize,
serde::Serialize,
)]
#[serde(rename_all = "snake_case")]
pub enum Renderer {
#[default]
Markdown,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Configuration {
pub delimiter: String,
pub grammar: Grammar,
pub buckets: Vec<String>,
pub fallback_bucket: Option<String>,
pub renderer: Renderer,
}
impl Configuration {
pub fn parse(&self, subject: &str) -> Option<(String, String)> {
let named = match self.grammar {
Grammar::Delimited => subject.split_once(self.delimiter.as_str()),
Grammar::Bracketed => subject
.trim_start()
.strip_prefix('[')
.and_then(|rest| rest.split_once(']')),
};
let (named, text) = named.map_or_else(
|| (None, subject.trim()),
|(a, b)| (Some(a.trim()), b.trim()),
);
if text.is_empty() {
return None;
}
named
.filter(|bucket| self.buckets.iter().any(|known| known == bucket))
.map(str::to_owned)
.or_else(|| self.fallback_bucket.clone())
.map(|bucket| (bucket, text.to_owned()))
}
}
impl Default for Configuration {
fn default() -> Self {
Self {
delimiter: "::=".to_owned(),
grammar: Grammar::Delimited,
buckets: [
"Added",
"Changed",
"Deprecated",
"Fixed",
"Removed",
"Security",
]
.iter()
.map(|bucket| (*bucket).to_owned())
.collect(),
fallback_bucket: None,
renderer: Renderer::Markdown,
}
}
}