feat: typo every → ever (#2311)

* feat: typo every → ever

* test: one more unit test
This commit is contained in:
Andrew Dunbar 2025-12-10 21:54:41 +00:00 committed by GitHub
parent 2330456311
commit 37ae9b4c69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 233 additions and 0 deletions

View file

@ -0,0 +1,230 @@
use crate::{
Lint, Token,
expr::{Expr, OwnedExprExt, SequenceExpr},
linting::{ExprLinter, LintKind, Suggestion, expr_linter::Chunk},
patterns::{ModalVerb, WordSet},
};
pub struct EverEvery {
expr: Box<dyn Expr>,
}
impl Default for EverEvery {
fn default() -> Self {
Self {
expr: Box::new(
SequenceExpr::any_of(vec![
Box::new(WordSet::new(&[
"are", "aren't", "arent", "did", "didn't", "didnt", "do", "does",
"doesn't", "doesnt", "dont", "don't", "had", "hadn't", "hadnt", "has",
"hasn't", "hasnt", "have", "haven't", "havent", "is", "isn't", "isnt",
"was", "wasn't", "wasnt", "were", "weren't", "werent",
])),
Box::new(ModalVerb::with_common_errors()),
])
.t_ws()
.then_subject_pronoun()
.t_ws()
.t_aco("every")
.and_not(SequenceExpr::anything().t_any().t_aco("it")),
),
}
}
}
impl ExprLinter for EverEvery {
type Unit = Chunk;
fn expr(&self) -> &dyn Expr {
self.expr.as_ref()
}
fn match_to_lint(&self, toks: &[Token], src: &[char]) -> Option<Lint> {
let span = toks[4].span;
let content = span.get_content(src);
Some(Lint {
span,
lint_kind: LintKind::Typo,
suggestions: vec![Suggestion::replace_with_match_case(
content[..content.len() - 1].to_vec(),
content,
)],
message: "Is this `every` a typo that should be `ever`?".to_string(),
..Default::default()
})
}
fn description(&self) -> &str {
"Tries to correct typos of `every` instead of `ever`."
}
}
#[cfg(test)]
mod tests {
use super::EverEvery;
use crate::linting::tests::{assert_no_lints, assert_suggestion_result};
#[test]
fn fix_can_i_every() {
assert_suggestion_result(
"Odd, how can i every become negative in that case?",
EverEvery::default(),
"Odd, how can i ever become negative in that case?",
);
}
#[test]
fn fix_can_they_every() {
assert_suggestion_result(
"if each component has its own instance of NameService, how can they every share state?",
EverEvery::default(),
"if each component has its own instance of NameService, how can they ever share state?",
)
}
#[test]
fn fix_can_we_every() {
assert_suggestion_result(
"can we every have a good dev UX?",
EverEvery::default(),
"can we ever have a good dev UX?",
);
}
#[test]
fn fix_did_we_every() {
assert_suggestion_result(
"Did we every fix that?",
EverEvery::default(),
"Did we ever fix that?",
)
}
#[test]
fn fix_did_you_every() {
assert_suggestion_result(
"Did you every get vtsls working properly?",
EverEvery::default(),
"Did you ever get vtsls working properly?",
)
}
#[test]
fn fix_do_i_every() {
assert_suggestion_result(
"Rarely do I every look forward to the new ui.",
EverEvery::default(),
"Rarely do I ever look forward to the new ui.",
)
}
#[test]
fn fix_do_we_every() {
assert_suggestion_result(
"do we every stop learning new things?",
EverEvery::default(),
"do we ever stop learning new things?",
)
}
#[test]
fn fix_do_you_every() {
assert_suggestion_result(
"Do you every faced the issue or have any idea why this could happen?",
EverEvery::default(),
"Do you ever faced the issue or have any idea why this could happen?",
)
}
#[test]
fn fix_dont_i_every() {
assert_suggestion_result(
"WHY DONT I EVERY SEE OR HEAR ABOUT THINGS HAPPENING IN SOUTHPORT?",
EverEvery::default(),
"WHY DONT I EVER SEE OR HEAR ABOUT THINGS HAPPENING IN SOUTHPORT?",
)
}
#[test]
fn fix_dont_they_every() {
assert_suggestion_result(
"And why dont they every smile first?",
EverEvery::default(),
"And why dont they ever smile first?",
)
}
#[test]
fn fix_dont_you_every() {
assert_suggestion_result(
"Dont you every forget this and believe nothing else.",
EverEvery::default(),
"Dont you ever forget this and believe nothing else.",
)
}
#[test]
fn fix_have_you_every() {
assert_suggestion_result(
"Have you every wanted to generate geometric structures from data.frames",
EverEvery::default(),
"Have you ever wanted to generate geometric structures from data.frames",
)
}
#[test]
fn fix_should_i_every() {
assert_suggestion_result(
"I.e. why would I every use deepcopy ?",
EverEvery::default(),
"I.e. why would I ever use deepcopy ?",
)
}
#[test]
fn fix_should_we_every() {
assert_suggestion_result(
"Should we every meet, I'll get you a beverage of your choosing!",
EverEvery::default(),
"Should we ever meet, I'll get you a beverage of your choosing!",
)
}
#[test]
fn fix_should_you_every() {
assert_suggestion_result(
"but you will always have a place in his home should you every truly desire it",
EverEvery::default(),
"but you will always have a place in his home should you ever truly desire it",
)
}
#[test]
fn fix_would_i_every() {
assert_suggestion_result(
"Why would I every do that?",
EverEvery::default(),
"Why would I ever do that?",
)
}
#[test]
fn fix_would_they_every() {
assert_suggestion_result(
"Would they every be installed together?",
EverEvery::default(),
"Would they ever be installed together?",
)
}
// known false positive - future contributors: please feel free to tackle this!
#[test]
#[ignore = "unusual but not wrong position of time phrase, maybe should have commas?"]
fn dont_flag_should_we_every() {
assert_no_lints(
"MM: should we every month or two have a roundup of what's been happening in WGSL",
EverEvery::default(),
)
}
}

View file

@ -56,6 +56,7 @@ use super::double_click::DoubleClick;
use super::double_modal::DoubleModal;
use super::ellipsis_length::EllipsisLength;
use super::else_possessive::ElsePossessive;
use super::ever_every::EverEvery;
use super::everyday::Everyday;
use super::expand_memory_shorthands::ExpandMemoryShorthands;
use super::expand_time_shorthands::ExpandTimeShorthands;
@ -528,6 +529,7 @@ impl LintGroup {
insert_expr_rule!(DoubleModal, true);
insert_struct_rule!(EllipsisLength, true);
insert_expr_rule!(ElsePossessive, true);
insert_expr_rule!(EverEvery, true);
insert_expr_rule!(Everyday, true);
insert_expr_rule!(ExpandMemoryShorthands, true);
insert_expr_rule!(ExpandTimeShorthands, true);

View file

@ -51,6 +51,7 @@ mod double_click;
mod double_modal;
mod ellipsis_length;
mod else_possessive;
mod ever_every;
mod everyday;
mod expand_memory_shorthands;
mod expand_time_shorthands;