1mod adjacent_code;
34mod bare_url;
35mod duplicate_heading;
36mod duplicate_link_label;
37mod escaped_emphasis;
38mod heading_punctuation;
39mod inconsistent_list_marker;
40mod info_string_typo;
41mod latex_command;
42mod list_tightness_flipped;
43mod math_render;
44mod math_unbalanced_braces;
45mod math_unbalanced_delim;
46mod math_unbalanced_env;
47mod orphan_reference_link;
48mod stray_dollar;
49mod subscript_damage;
50mod trailing_whitespace;
51mod unbalanced_backtick;
52mod unicodeable_subscript;
53
54use crate::rule::LintRule;
55use crate::rule_set::RuleSet;
56
57pub use adjacent_code::AdjacentCodeNoSpace;
58pub use bare_url::BareUrl;
59pub use duplicate_heading::DuplicateHeading;
60pub use duplicate_link_label::DuplicateLinkLabel;
61pub use escaped_emphasis::EscapedEmphasis;
62pub use heading_punctuation::HeadingPunctuation;
63pub use inconsistent_list_marker::InconsistentListMarker;
64pub use info_string_typo::InfoStringTypo;
65pub use latex_command::LatexCommand;
66pub use list_tightness_flipped::ListTightnessFlipped;
67pub use math_render::RenderCompat;
68pub use math_unbalanced_braces::MathUnbalancedBraces;
69pub use math_unbalanced_delim::MathUnbalancedDelim;
70pub use math_unbalanced_env::MathUnbalancedEnv;
71pub use orphan_reference_link::OrphanReferenceLink;
72pub use stray_dollar::StrayDollar;
73pub use subscript_damage::SubscriptDamage;
74pub use trailing_whitespace::TrailingWhitespace;
75pub use unbalanced_backtick::UnbalancedBacktick;
76pub use unicodeable_subscript::UnicodeableSubscript;
77
78pub const NAMES: &[&str] = &[
87 "unbalanced-backtick",
88 "math/unbalanced-delim",
89 "math/unbalanced-env",
90 "math/unbalanced-braces",
91 "math/render-compat",
92 "adjacent-code-no-space",
93 "heading-punctuation",
94 "orphan-reference-link",
95 "duplicate-link-label",
96 "bare-url",
97 "trailing-whitespace",
98 "inconsistent-list-marker",
99 "list-tightness-flipped",
100 "duplicate-heading",
101 "unicodeable-subscript",
102 "info-string-typo",
103 "stray-dollar",
104 "latex-command",
105 "escaped-emphasis",
106 "subscript-damage",
107];
108
109pub fn names() -> impl Iterator<Item = &'static str> {
113 NAMES.iter().copied()
114}
115
116fn all_boxed() -> Vec<Box<dyn LintRule>> {
119 vec![
120 Box::new(UnbalancedBacktick),
121 Box::new(MathUnbalancedDelim),
122 Box::new(MathUnbalancedEnv),
123 Box::new(MathUnbalancedBraces),
124 Box::new(RenderCompat::new()),
125 Box::new(AdjacentCodeNoSpace),
126 Box::new(HeadingPunctuation),
127 Box::new(OrphanReferenceLink),
128 Box::new(DuplicateLinkLabel),
129 Box::new(BareUrl),
130 Box::new(TrailingWhitespace),
131 Box::new(InconsistentListMarker),
132 Box::new(ListTightnessFlipped),
133 Box::new(DuplicateHeading),
134 Box::new(UnicodeableSubscript),
135 Box::new(InfoStringTypo::new()),
136 Box::new(StrayDollar),
137 Box::new(LatexCommand),
138 Box::new(EscapedEmphasis),
139 Box::new(SubscriptDamage),
140 ]
141}
142
143#[must_use]
145pub fn all() -> RuleSet {
146 let mut rs = RuleSet::new();
147 for rule in all_boxed() {
148 let _unused = rs.add(rule);
154 }
155 rs
156}
157
158#[must_use]
160pub fn defaults() -> RuleSet {
161 let mut rs = RuleSet::new();
162 for rule in all_boxed() {
163 if rule.is_default() {
164 let _unused = rs.add(rule);
167 }
168 }
169 rs
170}
171
172#[must_use]
176pub fn by_name(name: &str) -> Option<Box<dyn LintRule>> {
177 all_boxed().into_iter().find(|r| r.name() == name)
178}
179
180#[cfg(test)]
181mod tests {
182 use super::{all, by_name, defaults};
183
184 #[test]
185 fn defaults_excludes_opt_in() {
186 let rs = defaults();
187 assert!(rs.contains("unbalanced-backtick"));
188 assert!(rs.contains("heading-punctuation"));
189 assert!(!rs.contains("stray-dollar"));
190 assert!(!rs.contains("latex-command"));
191 assert!(!rs.contains("escaped-emphasis"));
192 assert!(!rs.contains("subscript-damage"));
193 }
194
195 #[test]
196 fn all_includes_everything() {
197 let rs = all();
198 assert!(rs.contains("stray-dollar"));
199 assert!(rs.contains("subscript-damage"));
200 assert!(rs.contains("math/unbalanced-delim"));
201 assert!(rs.contains("math/unbalanced-env"));
202 assert!(rs.contains("math/unbalanced-braces"));
203 assert!(rs.contains("math/render-compat"));
204 assert!(rs.len() == 20);
205 }
206
207 #[test]
208 fn by_name_known() {
209 assert!(by_name("unbalanced-backtick").is_some());
210 assert!(by_name("escaped-emphasis").is_some());
211 assert!(by_name("does-not-exist").is_none());
212 }
213
214 #[test]
215 fn names_match_all_boxed() {
216 let from_rules: std::collections::BTreeSet<String> =
217 super::all_boxed().iter().map(|r| r.name().to_owned()).collect();
218 let from_const: std::collections::BTreeSet<String> = super::NAMES.iter().map(|s| (*s).to_owned()).collect();
219 assert_eq!(from_rules, from_const, "stdlib::NAMES drift");
220 }
221}