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)]
31 pub fix: bool,
32
33 #[serde(default, rename = "heading-style", alias = "heading_style")]
36 pub heading_style: HeadingStyle,
37
38 #[serde(default = "default_heading_level", rename = "heading-level", alias = "heading_level")]
42 pub heading_level: HeadingLevel,
43}
44
45fn default_punctuation() -> String {
46 ".,;:!?".to_string()
47}
48
49fn default_heading_level() -> HeadingLevel {
50 HeadingLevel::new(2).unwrap()
52}
53
54impl Default for MD036Config {
55 fn default() -> Self {
56 Self {
57 punctuation: default_punctuation(),
58 fix: false,
59 heading_style: HeadingStyle::default(),
60 heading_level: default_heading_level(),
61 }
62 }
63}
64
65impl RuleConfig for MD036Config {
66 const RULE_NAME: &'static str = "MD036";
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_default_values() {
75 let config = MD036Config::default();
76 assert_eq!(config.punctuation, ".,;:!?");
77 assert!(!config.fix);
78 assert_eq!(config.heading_style, HeadingStyle::Atx);
79 assert_eq!(config.heading_level.get(), 2);
80 }
81
82 #[test]
83 fn test_kebab_case_config() {
84 let toml_str = r#"
85 punctuation = ".,;:"
86 fix = true
87 heading-style = "atx"
88 heading-level = 3
89 "#;
90 let config: MD036Config = toml::from_str(toml_str).unwrap();
91 assert_eq!(config.punctuation, ".,;:");
92 assert!(config.fix);
93 assert_eq!(config.heading_style, HeadingStyle::Atx);
94 assert_eq!(config.heading_level.get(), 3);
95 }
96
97 #[test]
98 fn test_snake_case_backwards_compatibility() {
99 let toml_str = r#"
100 punctuation = "."
101 fix = true
102 heading_style = "atx"
103 heading_level = 4
104 "#;
105 let config: MD036Config = toml::from_str(toml_str).unwrap();
106 assert_eq!(config.punctuation, ".");
107 assert!(config.fix);
108 assert_eq!(config.heading_style, HeadingStyle::Atx);
109 assert_eq!(config.heading_level.get(), 4);
110 }
111
112 #[test]
113 fn test_invalid_heading_level_rejected() {
114 let toml_str = r#"
116 heading-level = 0
117 "#;
118 let result: Result<MD036Config, _> = toml::from_str(toml_str);
119 assert!(result.is_err());
120 let err = result.unwrap_err().to_string();
121 assert!(err.contains("must be between 1 and 6"));
122
123 let toml_str = r#"
125 heading-level = 7
126 "#;
127 let result: Result<MD036Config, _> = toml::from_str(toml_str);
128 assert!(result.is_err());
129 let err = result.unwrap_err().to_string();
130 assert!(err.contains("must be between 1 and 6"));
131 }
132
133 #[test]
134 fn test_all_valid_heading_levels() {
135 for level in 1..=6 {
136 let toml_str = format!("heading-level = {level}");
137 let config: MD036Config = toml::from_str(&toml_str).unwrap();
138 assert_eq!(config.heading_level.get(), level);
139 }
140 }
141}