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