Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions harper-core/src/linting/in_adjective_condition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! Linter for correcting common errors with the phrase "in [adjective] condition".

use crate::{
Token,
expr::{Expr, SequenceExpr},
linting::{ExprLinter, Lint, LintKind, Suggestion},
token_string_ext::TokenStringExt,
};

/// Linter that corrects common errors with phrases like "in good condition".
///
/// Handles two cases:
/// 1. "in [a/an] [adjective] condition" -> "in [adjective] condition"
/// 2. "in [adjective] conditions" -> "in [adjective] condition"
pub struct InAdjectiveCondition {
expr: Box<dyn Expr>,
}

impl Default for InAdjectiveCondition {
fn default() -> Self {
let singular = SequenceExpr::default()
.then_indefinite_article()
.t_ws()
.then_adjective()
.t_ws()
.t_aco("condition");

let plural = SequenceExpr::default()
.then_adjective()
.t_ws()
.t_aco("conditions");

Self {
expr: Box::new(
SequenceExpr::default()
.t_aco("in")
.t_ws()
.then_any_of(vec![Box::new(singular), Box::new(plural)]),
),
}
}
}

impl ExprLinter for InAdjectiveCondition {
fn expr(&self) -> &dyn Expr {
self.expr.as_ref()
}

fn match_to_lint(&self, toks: &[Token], src: &[char]) -> Option<Lint> {
let (span, sugg, msg) = match toks.len() {
5 => (
toks.last()?.span,
Suggestion::replace_with_match_case(
"condition".chars().collect(),
toks.last()?.span.get_content(src),
),
"`Condition` should be singular.",
),
7 => (
toks[1..3].span()?,
Suggestion::Remove,
"An indefinite article should not be used here.",
),
_ => return None,
};

Some(Lint {
span,
lint_kind: LintKind::Grammar,
suggestions: vec![sugg],
message: msg.to_string(),
..Default::default()
})
}

fn description(&self) -> &str {
"Corrects incorrect variants of `in good condition` with an indefinite article or plural."
}
}

#[cfg(test)]
mod tests {
use super::InAdjectiveCondition;
use crate::linting::tests::assert_suggestion_result;

#[test]
fn fix_in_good_conditions() {
assert_suggestion_result(
"in good conditions",
InAdjectiveCondition::default(),
"in good condition",
);
}

#[test]
fn fix_in_a_bad_condition() {
assert_suggestion_result(
"in a bad condition",
InAdjectiveCondition::default(),
"in bad condition",
);
}

#[test]
fn fix_great_condition_all_caps() {
assert_suggestion_result(
"YEAH IT'S IN GREAT CONDITIONS REALLY!",
InAdjectiveCondition::default(),
"YEAH IT'S IN GREAT CONDITION REALLY!",
)
}
}
2 changes: 2 additions & 0 deletions harper-core/src/linting/lint_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ use super::hop_hope::HopHope;
use super::how_to::HowTo;
use super::hyphenate_number_day::HyphenateNumberDay;
use super::i_am_agreement::IAmAgreement;
use super::in_adjective_condition::InAdjectiveCondition;
use super::in_on_the_cards::InOnTheCards;
use super::inflected_verb_after_to::InflectedVerbAfterTo;
use super::interested_in::InterestedIn;
Expand Down Expand Up @@ -446,6 +447,7 @@ impl LintGroup {
insert_struct_rule!(HowTo, true);
insert_expr_rule!(HyphenateNumberDay, true);
insert_expr_rule!(IAmAgreement, true);
insert_expr_rule!(InAdjectiveCondition, true);
insert_expr_rule!(InterestedIn, true);
insert_struct_rule!(ItsContraction, true);
insert_struct_rule!(ItsPossessive, true);
Expand Down
2 changes: 2 additions & 0 deletions harper-core/src/linting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ mod hope_youre;
mod how_to;
mod hyphenate_number_day;
mod i_am_agreement;
mod in_adjective_condition;
mod in_on_the_cards;
mod inflected_verb_after_to;
mod initialism_linter;
Expand Down Expand Up @@ -182,6 +183,7 @@ pub use hop_hope::HopHope;
pub use how_to::HowTo;
pub use hyphenate_number_day::HyphenateNumberDay;
pub use i_am_agreement::IAmAgreement;
pub use in_adjective_condition::InAdjectiveCondition;
pub use in_on_the_cards::InOnTheCards;
pub use inflected_verb_after_to::InflectedVerbAfterTo;
pub use initialism_linter::InitialismLinter;
Expand Down
Loading