harper_core/linting/
the_my.rs

1use super::{Lint, LintKind, PatternLinter, Suggestion};
2use crate::{
3    CharStringExt, Token, TokenStringExt,
4    patterns::{EitherPattern, Pattern, SequencePattern, Word, WordSet},
5};
6
7pub struct TheMy {
8    pattern: Box<dyn Pattern>,
9}
10
11impl Default for TheMy {
12    fn default() -> Self {
13        let the = Word::new("the");
14        let any_possessive = WordSet::new(&["my", "your", "his", "her", "its", "our", "their"]);
15
16        let the_poss = SequencePattern::default()
17            .then(the.clone())
18            .then_whitespace()
19            .then(any_possessive.clone());
20
21        let poss_the = SequencePattern::default()
22            .then(any_possessive)
23            .then_whitespace()
24            .then(the);
25
26        Self {
27            pattern: Box::new(EitherPattern::new(vec![
28                Box::new(the_poss),
29                Box::new(poss_the),
30            ])),
31        }
32    }
33}
34
35impl PatternLinter for TheMy {
36    fn pattern(&self) -> &dyn Pattern {
37        self.pattern.as_ref()
38    }
39
40    fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
41        let span = matched_tokens.span().unwrap();
42        let span_content = span.get_content(source);
43
44        let first_word = matched_tokens[0].span.get_content(source);
45        let second_word = matched_tokens[2].span.get_content(source);
46
47        let first_word_string: String = first_word.to_string();
48
49        let possessive = if first_word_string.eq_ignore_ascii_case("the") {
50            second_word
51        } else {
52            first_word
53        };
54
55        // Don't flag "the My" or "my The" since they could be titles of things
56        if second_word[0].is_uppercase() {
57            return None;
58        }
59
60        // Don't flag "her the" since her is also the object case pronoun: "give her the book"
61        if first_word_string.eq_ignore_ascii_case("her") {
62            return None;
63        }
64
65        let suggestions = vec![
66            Suggestion::replace_with_match_case(possessive.to_vec(), span_content),
67            Suggestion::replace_with_match_case("the".chars().collect(), span_content),
68        ];
69
70        Some(Lint {
71            span,
72            lint_kind: LintKind::Repetition,
73            suggestions,
74            message: "Use either the definite article 'the' or the possessive. Using both together is ungrammatical in English.".to_owned(),
75            priority: 127,
76        })
77    }
78
79    fn description(&self) -> &'static str {
80        "Flags the definite article used together with a possessive."
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::TheMy;
87    use crate::linting::tests::{
88        assert_lint_count, assert_nth_suggestion_result, assert_suggestion_result,
89    };
90
91    #[test]
92    fn correct_the_my_atomic_lowercase() {
93        assert_suggestion_result("the my", TheMy::default(), "my");
94    }
95
96    #[test]
97    fn correct_the_my_atomic_2nd_suggestion() {
98        assert_nth_suggestion_result("the my", TheMy::default(), "the", 1);
99    }
100
101    #[test]
102    fn correct_the_my_atomic_uppercase() {
103        assert_suggestion_result("The my", TheMy::default(), "My");
104    }
105
106    #[test]
107    fn correct_my_the_atomic_lowercase() {
108        assert_suggestion_result("my the", TheMy::default(), "my");
109    }
110
111    #[test]
112    fn correct_my_the_atomic_2nd_suggestion() {
113        assert_nth_suggestion_result("my the", TheMy::default(), "the", 1);
114    }
115
116    #[test]
117    fn correct_my_the_atomic_uppercase() {
118        assert_suggestion_result("My the", TheMy::default(), "My");
119    }
120
121    #[test]
122    fn dont_correct_capitalized_possessive() {
123        assert_lint_count("For some time the My Projects personal page was \"sluggish\" or took some time to generate the miniature depicting the project, now it seems completely stuck ...
124", TheMy::default(), 0);
125    }
126
127    #[test]
128    fn correct_the_my_github() {
129        assert_suggestion_result(
130            "When I try to configure the my react-native app to support koltin file, this library gives these errors",
131            TheMy::default(),
132            "When I try to configure my react-native app to support koltin file, this library gives these errors",
133        );
134    }
135
136    #[test]
137    fn correct_the_our_github() {
138        assert_suggestion_result(
139            "Source codes of the our paper titled \"Multi-level Textual-Visual Alignment and Fusion Network for Multimodal Aspect-based Sentiment Analysis\"",
140            TheMy::default(),
141            "Source codes of our paper titled \"Multi-level Textual-Visual Alignment and Fusion Network for Multimodal Aspect-based Sentiment Analysis\"",
142        );
143    }
144
145    #[test]
146    fn correct_the_their_github() {
147        assert_suggestion_result(
148            "the slider cannot render when i use again the their component on NextJS app",
149            TheMy::default(),
150            "the slider cannot render when i use again their component on NextJS app",
151        );
152    }
153
154    #[test]
155    fn correct_your_the_github() {
156        assert_suggestion_result(
157            "This plugin allows you to view your the information about order and customer from your spree store on zendesk",
158            TheMy::default(),
159            "This plugin allows you to view your information about order and customer from your spree store on zendesk",
160        );
161    }
162
163    #[test]
164    fn correct_my_the_github() {
165        assert_suggestion_result(
166            "Scripts used my the project to collect, process and store social media data from a number of sources",
167            TheMy::default(),
168            "Scripts used my project to collect, process and store social media data from a number of sources",
169        );
170    }
171
172    #[test]
173    fn dont_correct_the_your_github() {
174        assert_lint_count(
175            "What exactly is the sort order of list names on the Your Stars page?",
176            TheMy::default(),
177            0,
178        );
179    }
180
181    #[test]
182    fn dont_correct_my_the_github() {
183        assert_lint_count(
184            "My The Frame TV is not pulling information properly",
185            TheMy::default(),
186            0,
187        )
188    }
189
190    #[test]
191    fn correct_our_the_github() {
192        assert_suggestion_result(
193            "Companion Repository to our the whitepaper \"Towards Reliable and Scalable Linux Kernel CVE Attribution in Automated Static Firmware Analyses\"",
194            TheMy::default(),
195            "Companion Repository to our whitepaper \"Towards Reliable and Scalable Linux Kernel CVE Attribution in Automated Static Firmware Analyses\"",
196        )
197    }
198
199    #[test]
200    fn correct_their_the_github() {
201        assert_suggestion_result(
202            "Types exported by @_exported remember only their the original module",
203            TheMy::default(),
204            "Types exported by @_exported remember only their original module",
205        )
206    }
207
208    #[test]
209    fn dont_correct_her_the_github() {
210        assert_lint_count(
211            "Create an admin role for boba-tan and give her the GoreMaster role only in !gore",
212            TheMy::default(),
213            0,
214        )
215    }
216
217    #[test]
218    fn correct_the_his_github() {
219        assert_suggestion_result(
220            "Allows the user to specify the his last name.",
221            TheMy::default(),
222            "Allows the user to specify his last name.",
223        )
224    }
225
226    #[test]
227    fn correct_his_the_github() {
228        assert_suggestion_result(
229            "One interesting creation was his the Schelling segregation model",
230            TheMy::default(),
231            "One interesting creation was his Schelling segregation model",
232        )
233    }
234
235    #[test]
236    fn correct_the_her_github() {
237        assert_suggestion_result(
238            "In memory of the occasion when our Queen Victoria graciously came to see our Island, and the her Royal Consort Albert landed at Ramsey",
239            TheMy::default(),
240            "In memory of the occasion when our Queen Victoria graciously came to see our Island, and her Royal Consort Albert landed at Ramsey",
241        )
242    }
243}