use serde::{Deserialize, Deserializer, Serialize, de::Error as _};
use std::{fmt, str::FromStr};
pub const BASELINE_RULE_IDS: &[&str] = &["MD001", "MD003", "MD009", "MD010", "MD011", "MD014"];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum RulePreset {
Baseline,
}
impl RulePreset {
pub const fn name(self) -> &'static str {
match self {
Self::Baseline => "baseline",
}
}
pub const fn description(self) -> &'static str {
match self {
Self::Baseline => {
"Low-noise stable structural, syntax, and whitespace checks for incremental CI adoption"
}
}
}
pub const fn rule_ids(self) -> &'static [&'static str] {
match self {
Self::Baseline => BASELINE_RULE_IDS,
}
}
pub fn contains(self, rule_id: &str) -> bool {
self.rule_ids().contains(&rule_id)
}
}
impl fmt::Display for RulePreset {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
impl FromStr for RulePreset {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"baseline" => Ok(Self::Baseline),
_ => Err(format!(
"unknown preset '{value}'; available presets: baseline"
)),
}
}
}
impl<'de> Deserialize<'de> for RulePreset {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
value.parse().map_err(D::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn baseline_membership_is_an_ordered_stable_contract() {
assert_eq!(
RulePreset::Baseline.rule_ids(),
["MD001", "MD003", "MD009", "MD010", "MD011", "MD014"]
);
}
#[test]
fn preset_names_round_trip() {
let preset: RulePreset = "baseline".parse().unwrap();
assert_eq!(preset, RulePreset::Baseline);
assert_eq!(preset.to_string(), "baseline");
}
}