Skip to main content

harper_core/linting/
lint_kind.rs

1use std::fmt::Display;
2
3use is_macro::Is;
4use serde::{Deserialize, Serialize};
5
6/// The general category a [`Lint`](super::Lint) falls into.
7/// There's no reason not to add a new item here if you are adding a new rule that doesn't fit
8/// the existing categories.
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, Is, Default, Hash, PartialEq, Eq)]
10pub enum LintKind {
11    Agreement,
12    /// For errors where words are joined or split at the wrong boundaries
13    /// (e.g., "each and everyone" vs. "each and every one")
14    BoundaryError,
15    Capitalization,
16    /// For cases where a word or phrase is misused for a similar-sounding word or phrase,
17    /// where the incorrect version makes logical sense (e.g., 'egg corn' for 'acorn',
18    /// 'on mass' for 'en masse').
19    Eggcorn,
20    /// For suggesting improvements that enhance clarity or impact without fixing errors
21    Enhancement,
22    Formatting,
23    Grammar,
24    /// For cases where a word is mistakenly used for a similar-sounding word with a different meaning
25    /// (e.g., 'eluded to' instead of 'alluded to'). Unlike eggcorns, these don't create new meanings.
26    Malapropism,
27    /// For any other lint that doesn't fit neatly into the other categories
28    #[default]
29    Miscellaneous,
30    Nonstandard,
31    /// For issues with punctuation, including hyphenation in compound adjectives
32    /// (e.g., "face first" vs. "face-first" when used before a noun)
33    Punctuation,
34    Readability,
35    /// For cases where words duplicate meaning that's already expressed
36    /// (e.g., "basic fundamentals" → "fundamentals", "free gift" → "gift")
37    Redundancy,
38    /// For variations that are standard in some regions or dialects but not others
39    Regionalism,
40    Repetition,
41    /// When your brain doesn't know the right spelling.
42    /// This should only be used by linters doing spellcheck on individual words.
43    Spelling,
44    /// For cases where multiple options are correct but one is preferred for style or clarity,
45    /// such as expanding abbreviations in formal writing (e.g., 'min' → 'minimum')
46    Style,
47    /// When your brain knows the right spelling but your fingers made a mistake.
48    /// (e.g., 'can be seem' → 'can be seen')
49    Typo,
50    /// For conventional word usage and standard collocations
51    /// (e.g., 'by accident' vs. 'on accident' in standard English)
52    Usage,
53    /// For choosing between different words or phrases in a given context
54    WordChoice,
55    /// For errors where words are in an unnatural sequence or incorrect syntactic position
56    /// (e.g., "no longer I" vs. "I no longer")
57    WordOrder,
58}
59
60impl LintKind {
61    /// The inverse of [`Self::to_string_key`]
62    pub fn from_string_key(s: &str) -> Option<Self> {
63        match s {
64            "Agreement" => Some(LintKind::Agreement),
65            "BoundaryError" => Some(LintKind::BoundaryError),
66            "Capitalization" => Some(LintKind::Capitalization),
67            "Eggcorn" => Some(LintKind::Eggcorn),
68            "Enhancement" => Some(LintKind::Enhancement),
69            "Formatting" => Some(LintKind::Formatting),
70            "Grammar" => Some(LintKind::Grammar),
71            "Malapropism" => Some(LintKind::Malapropism),
72            "Miscellaneous" => Some(LintKind::Miscellaneous),
73            "Nonstandard" => Some(LintKind::Nonstandard),
74            "Punctuation" => Some(LintKind::Punctuation),
75            "Readability" => Some(LintKind::Readability),
76            "Redundancy" => Some(LintKind::Redundancy),
77            "Regionalism" => Some(LintKind::Regionalism),
78            "Repetition" => Some(LintKind::Repetition),
79            "Spelling" => Some(LintKind::Spelling),
80            "Style" => Some(LintKind::Style),
81            "Typo" => Some(LintKind::Typo),
82            "Usage" => Some(LintKind::Usage),
83            "WordChoice" => Some(LintKind::WordChoice),
84            _ => None,
85        }
86    }
87
88    /// Produce a string representation, which can be used as keys in a map or CSS variables.
89    pub fn to_string_key(&self) -> String {
90        match self {
91            LintKind::Agreement => "Agreement",
92            LintKind::BoundaryError => "BoundaryError",
93            LintKind::Capitalization => "Capitalization",
94            LintKind::Eggcorn => "Eggcorn",
95            LintKind::Enhancement => "Enhancement",
96            LintKind::Formatting => "Formatting",
97            LintKind::Grammar => "Grammar",
98            LintKind::Malapropism => "Malapropism",
99            LintKind::Miscellaneous => "Miscellaneous",
100            LintKind::Nonstandard => "Nonstandard",
101            LintKind::Punctuation => "Punctuation",
102            LintKind::Readability => "Readability",
103            LintKind::Redundancy => "Redundancy",
104            LintKind::Regionalism => "Regionalism",
105            LintKind::Repetition => "Repetition",
106            LintKind::Spelling => "Spelling",
107            LintKind::Style => "Style",
108            LintKind::Typo => "Typo",
109            LintKind::Usage => "Usage",
110            LintKind::WordChoice => "WordChoice",
111            LintKind::WordOrder => "WordOrder",
112        }
113        .to_owned()
114    }
115}
116
117impl Display for LintKind {
118    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119        let s = match self {
120            LintKind::Agreement => "Agreement",
121            LintKind::BoundaryError => "BoundaryError",
122            LintKind::Capitalization => "Capitalization",
123            LintKind::Eggcorn => "Eggcorn",
124            LintKind::Enhancement => "Enhancement",
125            LintKind::Formatting => "Formatting",
126            LintKind::Grammar => "Grammar",
127            LintKind::Malapropism => "Malapropism",
128            LintKind::Miscellaneous => "Miscellaneous",
129            LintKind::Nonstandard => "Nonstandard",
130            LintKind::Punctuation => "Punctuation",
131            LintKind::Readability => "Readability",
132            LintKind::Redundancy => "Redundancy",
133            LintKind::Regionalism => "Regionalism",
134            LintKind::Repetition => "Repetition",
135            LintKind::Spelling => "Spelling",
136            LintKind::Style => "Style",
137            LintKind::Typo => "Typo",
138            LintKind::Usage => "Usage",
139            LintKind::WordChoice => "Word Choice",
140            LintKind::WordOrder => "Word Order",
141        };
142
143        write!(f, "{s}")
144    }
145}