rumdl_lib/rules/md036_no_emphasis_only_first/
md036_config.rs1use crate::rule_config_serde::RuleConfig;
2use crate::types::HeadingLevel;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7#[serde(rename_all = "snake_case")]
8pub enum HeadingStyle {
9 #[default]
11 Atx,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "kebab-case")]
17pub struct MD036Config {
18 #[serde(default = "default_punctuation")]
23 pub punctuation: String,
24
25 #[serde(default)]
32 pub fix: bool,
33
34 #[serde(default, rename = "heading-style", alias = "heading_style")]
37 pub heading_style: HeadingStyle,
38
39 #[serde(default = "default_heading_level", rename = "heading-level", alias = "heading_level")]
43 pub heading_level: HeadingLevel,
44}
45
46fn default_punctuation() -> String {
47 ".,;:!?".to_string()
48}
49
50fn default_heading_level() -> HeadingLevel {
51 HeadingLevel::new(2).unwrap()
53}
54
55impl Default for MD036Config {
56 fn default() -> Self {
57 Self {
58 punctuation: default_punctuation(),
59 fix: false,
60 heading_style: HeadingStyle::default(),
61 heading_level: default_heading_level(),
62 }
63 }
64}
65
66impl RuleConfig for MD036Config {
67 const RULE_NAME: &'static str = "MD036";
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn test_default_values() {
76 let config = MD036Config::default();
77 assert_eq!(config.punctuation, ".,;:!?");
78 assert!(!config.fix);
79 assert_eq!(config.heading_style, HeadingStyle::Atx);
80 assert_eq!(config.heading_level.get(), 2);
81 }
82
83 #[test]
84 fn test_kebab_case_config() {
85 let toml_str = r#"
86 punctuation = ".,;:"
87 fix = true
88 heading-style = "atx"
89 heading-level = 3
90 "#;
91 let config: MD036Config = toml::from_str(toml_str).unwrap();
92 assert_eq!(config.punctuation, ".,;:");
93 assert!(config.fix);
94 assert_eq!(config.heading_style, HeadingStyle::Atx);
95 assert_eq!(config.heading_level.get(), 3);
96 }
97
98 #[test]
99 fn test_snake_case_backwards_compatibility() {
100 let toml_str = r#"
101 punctuation = "."
102 fix = true
103 heading_style = "atx"
104 heading_level = 4
105 "#;
106 let config: MD036Config = toml::from_str(toml_str).unwrap();
107 assert_eq!(config.punctuation, ".");
108 assert!(config.fix);
109 assert_eq!(config.heading_style, HeadingStyle::Atx);
110 assert_eq!(config.heading_level.get(), 4);
111 }
112
113 #[test]
114 fn test_invalid_heading_level_rejected() {
115 let toml_str = r#"
117 heading-level = 0
118 "#;
119 let result: Result<MD036Config, _> = toml::from_str(toml_str);
120 assert!(result.is_err());
121 let err = result.unwrap_err().to_string();
122 assert!(err.contains("must be between 1 and 6"));
123
124 let toml_str = r#"
126 heading-level = 7
127 "#;
128 let result: Result<MD036Config, _> = toml::from_str(toml_str);
129 assert!(result.is_err());
130 let err = result.unwrap_err().to_string();
131 assert!(err.contains("must be between 1 and 6"));
132 }
133
134 #[test]
135 fn test_all_valid_heading_levels() {
136 for level in 1..=6 {
137 let toml_str = format!("heading-level = {level}");
138 let config: MD036Config = toml::from_str(&toml_str).unwrap();
139 assert_eq!(config.heading_level.get(), level);
140 }
141 }
142}