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 if second_word[0].is_uppercase() {
57 return None;
58 }
59
60 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}