use crate::{
CharStringExt, Dialect, IrregularNouns, Lint, Lrc, Token, TokenStringExt,
expr::{Expr, FirstMatchOf, OwnedExprExt, SequenceExpr, SpelledNumberExpr},
indefinite_article::{InitialSound, starts_with_vowel},
linting::{
ExprLinter, LintKind, Suggestion,
expr_linter::{Sentence, followed_by_hyphen, followed_by_word},
},
regular_nouns,
spell::Dictionary,
};
#[derive(PartialEq, Debug)]
enum Mismatch {
SingularBePluralNoun,
PluralBeSingularNoun,
}
impl Mismatch {
fn from_be(be: &[char]) -> Self {
if be.eq_any_ignore_ascii_case_str(&["are", "were"]) {
PluralBeSingularNoun
} else {
SingularBePluralNoun
}
}
}
use Mismatch::*;
#[derive(PartialEq)]
enum WordOrder {
Statement, Question, }
use WordOrder::*;
#[derive(PartialEq)]
enum Tense {
Present,
Past,
}
use Tense::*;
pub struct ThereIsAgreement<D> {
expr: FirstMatchOf,
dict: D,
}
impl<D: Dictionary> ThereIsAgreement<D> {
pub fn new(dict: D) -> Self {
let plural_noun = Lrc::new(|t: &Token, _: &[char]| t.kind.is_plural_noun());
let singular_noun = Lrc::new(SequenceExpr::default().then_singular_noun().but_not(
FirstMatchOf::new(vec![
Box::new(|t: &Token, s: &[char]| {
t.kind.is_adjective()
|| t.get_ch(s)
.eq_any_ignore_ascii_case_chars(&[&['n', 'o'], &['n', 'o', 't']])
}),
Box::new(SpelledNumberExpr),
]),
));
let first_match_of: Vec<Box<dyn Expr>> = [
(SingularBePluralNoun, Statement, Present),
(SingularBePluralNoun, Statement, Past),
(SingularBePluralNoun, Question, Present),
(SingularBePluralNoun, Question, Past),
(PluralBeSingularNoun, Statement, Present),
(PluralBeSingularNoun, Statement, Past),
(PluralBeSingularNoun, Question, Present),
(PluralBeSingularNoun, Question, Past),
]
.iter()
.map(|(mismatch, word_order, tense)| {
let be = match (mismatch, tense) {
(SingularBePluralNoun, Present) => "is",
(SingularBePluralNoun, Past) => "was",
(PluralBeSingularNoun, Present) => "are",
(PluralBeSingularNoun, Past) => "were",
};
let (first, second) = match word_order {
Statement => ("there", be),
Question => (be, "there"),
};
let seq = SequenceExpr::aco(first).t_ws().t_aco(second).t_ws();
(match mismatch {
SingularBePluralNoun => Box::new(seq.then(plural_noun.clone())),
PluralBeSingularNoun => Box::new(seq.then(singular_noun.clone())),
}) as Box<dyn Expr>
})
.chain(std::iter::once(Box::new(
SequenceExpr::fixed_phrase("there's ").then(plural_noun.clone()),
) as Box<dyn Expr>))
.collect();
Self {
expr: FirstMatchOf::new(first_match_of),
dict,
}
}
}
impl<D: Dictionary> ExprLinter for ThereIsAgreement<D> {
type Unit = Sentence;
fn match_to_lint_with_context(
&self,
toks: &[Token],
src: &[char],
ctx: Option<(&[Token], &[Token])>,
) -> Option<super::Lint> {
match_to_lint(&self.dict, toks, src, ctx)
}
fn expr(&self) -> &dyn Expr {
&self.expr
}
fn description(&self) -> &str {
"Checks for `is there` and its variants agreeing with singular vs plural subjects"
}
}
fn match_to_lint<D: Dictionary>(
dict: &D,
toks: &[Token],
src: &[char],
ctx: Option<(&[Token], &[Token])>,
) -> Option<super::Lint> {
let first = toks[0].span.get_content(src);
let second = toks[2].span.get_content(src);
const BE_FORMS: &[&str] = &["is", "are", "was", "were"];
match (
first.starts_with_ignore_ascii_case_str("there"),
first.last(),
) {
(false, _) if second.eq_str("there") => handle_question(toks, src, ctx, dict),
(true, Some(&'s')) => handle_theres(toks, src, ctx, dict),
(true, _) => handle_statement(toks, src, ctx, dict),
_ => None, }
}
fn get_new_be(orig_be: &[char]) -> &[char] {
let [first, second, ..] = orig_be else {
return orig_be;
};
match (first.to_ascii_lowercase(), second.to_ascii_lowercase()) {
('i', 's') => &['a', 'r', 'e'],
('a', 'r') => &['i', 's'],
('w', 'a') => &['w', 'e', 'r', 'e'],
('w', 'e') => &['w', 'a', 's'],
_ => orig_be,
}
}
type NounFormGetters<D> = (
fn(&[char]) -> Option<Vec<char>>,
fn(&D, &[char]) -> Vec<Vec<char>>,
);
fn get_new_nouns<'a, D: Dictionary>(
dict: &D,
orig_noun: &'a [char],
mismatch_type: &Mismatch,
) -> Vec<(Vec<char>, &'a [char])> {
let (irreg_func, reg_func): NounFormGetters<D> = match mismatch_type {
PluralBeSingularNoun => (get_irregular_plural, regular_nouns::get_plurals),
SingularBePluralNoun => (get_irregular_singular, regular_nouns::get_singulars),
};
let (irregular, regulars) = (irreg_func(orig_noun), reg_func(dict, orig_noun));
irregular
.into_iter()
.chain(regulars)
.collect::<Vec<_>>()
.into_iter()
.map(|n| {
let art = match starts_with_vowel(&n, Dialect::American) {
Some(InitialSound::Vowel) => &['a', 'n'][..],
Some(InitialSound::Consonant) => &['a'][..],
_ => &['a'][..],
};
(n, art)
})
.collect()
}
fn get_irregular_plural(singular: &[char]) -> Option<Vec<char>> {
IrregularNouns::curated()
.get_plural_for_singular_chars(singular)
.map(|s| s.chars().collect())
}
fn get_irregular_singular(plural: &[char]) -> Option<Vec<char>> {
IrregularNouns::curated()
.get_singular_for_plural_chars(plural)
.map(|s| s.chars().collect())
}
fn handle_statement<D: Dictionary>(
toks: &[Token],
src: &[char],
ctx: Option<(&[Token], &[Token])>,
dict: &D,
) -> Option<Lint> {
if followed_by_hyphen(ctx) {
return None;
}
if followed_by_word(ctx, |t| {
(t.kind.is_noun()
&& !t.kind.is_verb_progressive_form()
&& !t
.get_ch(src)
.eq_any_ignore_ascii_case_str(&["but", "in", "like"]))
|| t.get_ch(src).eq_any_ignore_ascii_case_str(&["and", "or"])
}) {
return None;
}
let replacement_template = toks[2..=4].get_ch(src)?;
let orig_be = toks[2].get_ch(src);
let orig_noun = toks[4].get_ch(src);
let mismatch_type = Mismatch::from_be(orig_be);
let new_be = get_new_be(orig_be);
let mut replacement_value: Vec<char> = new_be.to_vec();
if matches!(mismatch_type, PluralBeSingularNoun) {
let article = match starts_with_vowel(orig_noun, Dialect::American) {
Some(InitialSound::Vowel) => &['a', 'n'][..],
Some(InitialSound::Consonant) => &['a'][..],
_ => &['\u{1F170}', '\u{fe0f}', '\u{1F170}', '\u{fe0f}'][..],
};
replacement_value.extend(&[' ']);
replacement_value.extend(article.iter());
}
replacement_value.push(' ');
replacement_value.extend(orig_noun.iter());
let be_suggestion =
Suggestion::replace_with_match_case(replacement_value, replacement_template);
let new_nouns = get_new_nouns(dict, orig_noun, &mismatch_type);
let article_noun_pairs = new_nouns
.iter()
.map(|(noun, article)| {
let mut result: Vec<char> = orig_be.to_vec();
if matches!(mismatch_type, SingularBePluralNoun) {
result.extend(&[' ']);
result.extend(article.iter());
}
result.extend(&[' ']);
result.extend(noun.iter());
result
})
.collect::<Vec<Vec<char>>>();
let noun_suggestions: Vec<Suggestion> = article_noun_pairs
.iter()
.map(|sug_repl_value| {
Suggestion::replace_with_match_case(sug_repl_value.to_vec(), replacement_template)
})
.collect();
Some(Lint {
span: toks[2..=4].span()?,
message: "There is disagreement in number between the verb and the noun.".to_string(),
suggestions: [vec![be_suggestion], noun_suggestions].concat(),
lint_kind: LintKind::Agreement,
..Default::default()
})
}
fn handle_theres<D: Dictionary>(
toks: &[Token],
src: &[char],
_ctx: Option<(&[Token], &[Token])>,
dict: &D,
) -> Option<Lint> {
let replacement_template = toks[0..=2].get_ch(src)?;
let orig_there_be = toks[0].span.get_content(src);
let orig_noun = toks[2].span.get_content(src);
let mismatch_type = SingularBePluralNoun;
let new_there_be = &['t', 'h', 'e', 'r', 'e', ' ', 'a', 'r', 'e'][..];
let replacement_value: Vec<char> = new_there_be
.iter()
.chain(&[' '])
.chain(orig_noun.iter())
.copied()
.collect();
let there_be_suggestion =
Suggestion::replace_with_match_case(replacement_value, replacement_template);
let new_nouns = get_new_nouns(dict, orig_noun, &mismatch_type);
let article_noun_pairs = new_nouns
.iter()
.map(|(noun, article)| {
let mut result: Vec<char> = orig_there_be.to_vec();
result.extend(&[' ']);
result.extend(article.iter());
result.extend(&[' ']);
result.extend(noun.iter());
result
})
.collect::<Vec<Vec<char>>>();
let noun_suggestions: Vec<Suggestion> = article_noun_pairs
.iter()
.map(|sug_repl_value| {
Suggestion::replace_with_match_case(sug_repl_value.to_vec(), replacement_template)
})
.collect();
Some(Lint {
span: toks[0..=2].span()?,
lint_kind: LintKind::Agreement,
suggestions: [vec![there_be_suggestion], noun_suggestions].concat(),
message: "`There's` means `there is`, which requires a singular noun.".to_string(),
..Default::default()
})
}
fn handle_question<D: Dictionary>(
toks: &[Token],
src: &[char],
ctx: Option<(&[Token], &[Token])>,
dict: &D,
) -> Option<Lint> {
if followed_by_word(ctx, |t| {
t.kind.is_noun()
&& !t.kind.is_verb_progressive_form()
&& !t.get_ch(src).eq_any_ignore_ascii_case_str(&["in", "or"])
}) {
return None;
}
let replacement_template = toks[0..=4].get_ch(src)?;
let orig_be = toks[0].get_ch(src);
let orig_noun = toks[4].get_ch(src);
let mismatch_type = Mismatch::from_be(orig_be);
let new_be = get_new_be(orig_be);
let mut replacement_value: Vec<char> = new_be
.iter()
.chain(&[' ', 't', 'h', 'e', 'r', 'e'])
.copied()
.collect();
if matches!(mismatch_type, PluralBeSingularNoun) {
let article = match starts_with_vowel(orig_noun, Dialect::American) {
Some(InitialSound::Vowel) => &['a', 'n'][..],
Some(InitialSound::Consonant) => &['a'][..],
_ => &['\u{1F170}', '\u{fe0f}', '\u{1F170}', '\u{fe0f}'][..],
};
replacement_value.extend(&[' ']);
replacement_value.extend(article.iter());
}
replacement_value.extend(&[' ']);
replacement_value.extend(orig_noun.iter());
let be_suggestion =
Suggestion::replace_with_match_case(replacement_value, replacement_template);
let new_nouns = get_new_nouns(dict, orig_noun, &mismatch_type);
let article_noun_pairs = new_nouns
.iter()
.map(|(noun, article)| {
let mut result: Vec<char> = orig_be
.iter()
.chain(&[' ', 't', 'h', 'e', 'r', 'e'])
.copied()
.collect();
if matches!(mismatch_type, SingularBePluralNoun) {
result.extend(&[' ']);
result.extend(article.iter());
}
result.extend(&[' ']);
result.extend(noun.iter());
result
})
.collect::<Vec<_>>();
let noun_suggestions = article_noun_pairs
.iter()
.map(|replacement_value| {
Suggestion::replace_with_match_case(replacement_value.to_vec(), replacement_template)
})
.collect::<Vec<_>>();
Some(Lint {
span: toks[0..=4].span()?,
lint_kind: LintKind::Agreement,
suggestions: [vec![be_suggestion], noun_suggestions].concat(),
message: "There is disagreement in number between the verb and the noun.".to_string(),
..Default::default()
})
}
#[cfg(test)]
mod tests {
use crate::{
linting::tests::{
assert_good_and_bad_suggestions, assert_no_lints, assert_suggestion_result,
},
spell::FstDictionary,
};
use super::ThereIsAgreement;
#[test]
fn statement_present_pl_regular() {
assert_good_and_bad_suggestions(
"there is things",
ThereIsAgreement::new(FstDictionary::curated()),
&["there are things", "there is a thing"],
&[],
);
}
#[test]
fn statement_present_sg_irregular() {
assert_good_and_bad_suggestions(
"there are person",
ThereIsAgreement::new(FstDictionary::curated()),
&["there are people", "there is a person"],
&[],
);
}
#[test]
fn statement_present_theres_pl() {
assert_good_and_bad_suggestions(
"there's secrets",
ThereIsAgreement::new(FstDictionary::curated()),
&["there are secrets", "there's a secret"],
&[],
);
}
#[test]
fn statement_past_pl_vowel() {
assert_good_and_bad_suggestions(
"there was ideas",
ThereIsAgreement::new(FstDictionary::curated()),
&["there were ideas", "there was an idea"],
&[],
);
}
#[test]
fn statement_past_sg() {
assert_good_and_bad_suggestions(
"there were child",
ThereIsAgreement::new(FstDictionary::curated()),
&["there were children", "there was a child"],
&[],
);
}
#[test]
fn question_pres_sg() {
assert_good_and_bad_suggestions(
"are there man",
ThereIsAgreement::new(FstDictionary::curated()),
&["are there men", "is there a man"],
&[],
);
}
#[test]
fn question_pres_pl() {
assert_good_and_bad_suggestions(
"is there women",
ThereIsAgreement::new(FstDictionary::curated()),
&["are there women", "is there a woman"],
&[],
);
}
#[test]
fn question_past_sg() {
assert_good_and_bad_suggestions(
"were there cow",
ThereIsAgreement::new(FstDictionary::curated()),
&["were there cows", "was there a cow"],
&[],
);
}
#[test]
fn question_past_pl() {
assert_good_and_bad_suggestions(
"were there elephant",
ThereIsAgreement::new(FstDictionary::curated()),
&["were there elephants", "was there an elephant"],
&[],
);
}
#[test]
fn dont_flag_there_are_hyphenated_compound_starts_singular() {
assert_no_lints(
"there are function-like macros",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_there_are_open_compound_starts_singular() {
assert_no_lints(
"there are config errors",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn a_or_an_depends_on_dialect_herb() {
assert_good_and_bad_suggestions(
"there's herbs.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there are herbs.",
"there's an herb.",
],
&[],
)
}
#[test]
fn a_or_an_depends_on_dialect_hotel() {
assert_good_and_bad_suggestions(
"There are hotel.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"There are hotels.",
"There is a hotel.",
],
&[],
)
}
#[test]
fn fix_there_is_errors() {
assert_good_and_bad_suggestions(
"Hi, when I make the code, there is errors",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Hi, when I make the code, there are errors",
"Hi, when I make the code, there is an error",
],
&["Hi, when I make the code, there is a error"],
);
}
#[test]
fn fix_there_is_warnings() {
assert_good_and_bad_suggestions(
"There is warnings from kotlin and dart, as reference: Elvis operator (?:) always returns the left operand of non-nullable type String.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"There are warnings from kotlin and dart, as reference: Elvis operator (?:) always returns the left operand of non-nullable type String.",
"There is a warning from kotlin and dart, as reference: Elvis operator (?:) always returns the left operand of non-nullable type String.",
],
&[],
);
}
#[test]
fn fix_there_is_problems() {
assert_good_and_bad_suggestions(
"Problem is that if there is a project that has a csproj file, then there is problems with the history folder.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Problem is that if there is a project that has a csproj file, then there are problems with the history folder.",
"Problem is that if there is a project that has a csproj file, then there is a problem with the history folder.",
],
&[],
);
}
#[test]
#[ignore = "`replace_with_match_case` matching case char-by-char causes the wrong letters to be uppercased"]
fn fix_there_is_commands() {
assert_good_and_bad_suggestions(
"Additionally if there is Commands that can be used on multiple Resources at the same time.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Additionally if there are Commands that can be used on multiple Resources at the same time.",
"Additionally if there is a Command that can be used on multiple Resources at the same time.",
],
&[],
);
}
#[test]
fn fix_there_is_values() {
assert_suggestion_result(
"This mean there would not be a single cache, but as many caches as there is values for the second argument.",
ThereIsAgreement::new(FstDictionary::curated()),
"This mean there would not be a single cache, but as many caches as there are values for the second argument.",
);
}
#[test]
fn fix_there_is_strings() {
assert_good_and_bad_suggestions(
"I can image other cases (tools different from SPSS) in which there is strings in both sides of the dictionary",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"I can image other cases (tools different from SPSS) in which there are strings in both sides of the dictionary",
"I can image other cases (tools different from SPSS) in which there is a string in both sides of the dictionary",
],
&[],
);
}
#[test]
fn fix_there_is_things() {
assert_good_and_bad_suggestions(
"even though we can check whether there is things running in Node, we can not do it for Chromium's message loops",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"even though we can check whether there are things running in Node, we can not do it for Chromium's message loops",
"even though we can check whether there is a thing running in Node, we can not do it for Chromium's message loops",
],
&[],
);
}
#[test]
fn fix_there_is_people() {
assert_suggestion_result(
"there is people making projects, there is people doing tutorials",
ThereIsAgreement::new(FstDictionary::curated()),
"there are people making projects, there are people doing tutorials",
);
assert_suggestion_result(
"there is people making projects, there is people doing tutorials",
ThereIsAgreement::new(FstDictionary::curated()),
"there is a person making projects, there is a person doing tutorials",
);
}
#[test]
fn fix_there_is_instructions() {
assert_good_and_bad_suggestions(
"I am just wondering if there is instructions somewhere for handling deep linking while using Redux.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"I am just wondering if there are instructions somewhere for handling deep linking while using Redux.",
"I am just wondering if there is an instruction somewhere for handling deep linking while using Redux.",
],
&[],
);
}
#[test]
fn fix_there_is_packages() {
assert_suggestion_result(
"if there is packages that handle such protocols installed",
ThereIsAgreement::new(FstDictionary::curated()),
"if there are packages that handle such protocols installed",
);
}
#[test]
#[ignore = "TODO: abort if next word is a relative pronoun like `who`"]
fn dont_flag_there_is_people_who_have_done_xyz() {
assert_no_lints(
"The main expectation there is people who have a deprecated app installed will then get an error if it's disabled",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
#[ignore = "TODO: abort if next token is `/`"]
fn dont_flag_there_is_packages_part_of_dir() {
assert_no_lints(
"For example there is packages/vite/src/node , but no packages/vite/src/deno",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_there_are_bug() {
assert_good_and_bad_suggestions(
"there are bug in svelte 3.0 that axios from 0.22.0 version undefined",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there is a bug in svelte 3.0 that axios from 0.22.0 version undefined",
"there are bugs in svelte 3.0 that axios from 0.22.0 version undefined",
],
&[],
);
}
#[test]
fn fix_there_are_description() {
assert_good_and_bad_suggestions(
"there are description regarding thread safety in zmq document.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there is a description regarding thread safety in zmq document.",
"there are descriptions regarding thread safety in zmq document.",
],
&[],
);
}
#[test]
fn fix_there_are_issue() {
assert_good_and_bad_suggestions(
"Seems like if there are issue with OpenAI, it is still trying to call chat completion and giving type error.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Seems like if there are issues with OpenAI, it is still trying to call chat completion and giving type error.",
"Seems like if there is an issue with OpenAI, it is still trying to call chat completion and giving type error.",
],
&[],
);
}
#[test]
#[ignore = "TODO: 'problem' is being rejected as an adjective as well as a singular noun"]
fn fix_there_are_problem() {
assert_good_and_bad_suggestions(
"There are problem with official serving docker image gpu version",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"There is a problem with official serving docker image gpu version",
"There are problems with official serving docker image gpu version",
],
&[],
);
}
#[test]
fn dont_flag_there_are_dep_conflicts() {
assert_no_lints(
"Wrong advice when there are dependency conflicts",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_there_are_dep_errs() {
assert_no_lints(
"If there are dependency errors they will be immediately logged out to you.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
#[ignore = "'definition syntax' looks singular but the full np is the plural 'definition syntax errors'"]
fn dont_flag_there_are_def_syntax_errs() {
assert_no_lints(
"New Campaign Properties dialog loses changes if there are definition syntax errors",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_there_are_description_and_instruction_keys() {
assert_no_lints(
"There are description and instruction keys for the classes.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_there_are_function_like() {
assert_no_lints(
"clang-format indents class member functions oddly if there are function-like macro invocations",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_there_was_configs() {
assert_good_and_bad_suggestions(
"I did see that there was configs for it before but it isn't in the configs anymore.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"I did see that there were configs for it before but it isn't in the configs anymore.",
"I did see that there was a config for it before but it isn't in the configs anymore.",
],
&[],
);
}
#[test]
fn fix_there_was_examples() {
assert_good_and_bad_suggestions(
"It would be awesome if there was examples on how to include inline citations",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"It would be awesome if there were examples on how to include inline citations",
"It would be awesome if there was an example on how to include inline citations",
],
&[],
);
}
#[test]
fn fix_there_was_functions() {
assert_good_and_bad_suggestions(
"I noticed in the AXP2101_Class for the unified library that there was functions like \"isPekeyShortPressIrq()\"",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"I noticed in the AXP2101_Class for the unified library that there were functions like \"isPekeyShortPressIrq()\"",
"I noticed in the AXP2101_Class for the unified library that there was a function like \"isPekeyShortPressIrq()\"",
],
&[],
);
}
#[test]
fn fix_there_was_issues() {
assert_good_and_bad_suggestions(
"Restored to a Snapshot, but there was issues with Hyprland.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Restored to a Snapshot, but there were issues with Hyprland.",
"Restored to a Snapshot, but there was an issue with Hyprland.",
],
&[],
);
}
#[test]
fn fix_there_was_settings() {
assert_good_and_bad_suggestions(
"I also tried creating a fresh page on the same site, and there was settings but only 2 pages of settings",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"I also tried creating a fresh page on the same site, and there were settings but only 2 pages of settings",
"I also tried creating a fresh page on the same site, and there was a setting but only 2 pages of settings",
],
&[],
);
}
#[test]
fn fix_there_were_function() {
assert_good_and_bad_suggestions(
"Instead, it would be helpful if there were function in the autoloader capable of taking the a list of names of packages to enable.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Instead, it would be helpful if there were functions in the autoloader capable of taking the a list of names of packages to enable.",
"Instead, it would be helpful if there was a function in the autoloader capable of taking the a list of names of packages to enable.",
],
&[],
);
}
#[test]
fn fix_there_were_hint() {
assert_good_and_bad_suggestions(
"there were hint that this could break the build",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there were hints that this could break the build",
"there was a hint that this could break the build",
],
&[],
);
}
#[test]
fn fix_there_were_issue() {
assert_good_and_bad_suggestions(
"there were issue with using venv and it was pulled",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there were issues with using venv and it was pulled",
"there was an issue with using venv and it was pulled",
],
&[],
);
}
#[test]
#[ignore = "TODO: 'problem' is being rejected as an adjective as well as a singular noun"]
fn fix_there_were_problem_about() {
assert_good_and_bad_suggestions(
"there were problem about version but this error is solved by correcting version in these files",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there were problems about version but this error is solved by correcting version in these files",
"there was a problem about version but this error is solved by correcting version in these files",
],
&[],
);
}
#[test]
#[ignore = "TODO: 'problem' is being rejected as an adjective as well as a singular noun"]
fn fix_there_were_problem_with() {
assert_good_and_bad_suggestions(
"there were problem with page alignment crossing",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there were problems with page alignment crossing",
"there was a problem with page alignment crossing",
],
&[],
);
}
#[test]
fn dont_flag_alice_there_were_two() {
assert_no_lints(
"This time there were two little shrieks, and more sounds of broken glass.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_gatsby_there_were_twinkle_bells() {
assert_no_lints(
"When he realized what I was talking about, that there were twinkle-bells of sunshine in the room, he smiled like a weather man",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
#[ignore = "We can't detect first name + surname, especially for rare surnames like 'Waize'"]
fn dont_flag_gatsby_there_were_a_and_b() {
assert_no_lints(
"Of theatrical people there were Gus Waize and Horace O’Donavan and Lester Myer and George Duckweed and Francis",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_is_there_apps() {
assert_good_and_bad_suggestions(
"Ok, but is there apps that actually do that?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Ok, but are there apps that actually do that?",
"Ok, but is there an app that actually do that?",
],
&[],
);
}
#[test]
fn fix_is_there_ideas() {
assert_suggestion_result(
"Is there ideas to make regular page to listen for api (POST/PUT/.. etc requests)",
ThereIsAgreement::new(FstDictionary::curated()),
"Are there ideas to make regular page to listen for api (POST/PUT/.. etc requests)",
);
}
#[test]
fn fix_is_there_people() {
assert_suggestion_result(
"please guys tell me, is there people really making money with bot?",
ThereIsAgreement::new(FstDictionary::curated()),
"please guys tell me, are there people really making money with bot?",
);
}
#[test]
fn fix_is_there_solutions() {
assert_good_and_bad_suggestions(
"Run-as binary without the suid bit set, is there solutions?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Run-as binary without the suid bit set, are there solutions?",
"Run-as binary without the suid bit set, is there a solution?",
],
&[],
);
}
#[test]
fn fix_is_there_things() {
assert_suggestion_result(
"is there things you could change to make it a more general product",
ThereIsAgreement::new(FstDictionary::curated()),
"are there things you could change to make it a more general product",
);
}
#[test]
fn fix_is_there_tools() {
assert_good_and_bad_suggestions(
"Is there tools or documentation how to recover / rebuild /run fsck on the failed replicas.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Are there tools or documentation how to recover / rebuild /run fsck on the failed replicas.",
"Is there a tool or documentation how to recover / rebuild /run fsck on the failed replicas.",
],
&[],
);
}
#[test]
#[ignore = "TODO: 'problem' is being rejected as an adjective as well as a singular noun"]
fn fix_are_there_problem() {
assert_good_and_bad_suggestions(
"Is it just the namespace or are there problem in the use statements as well?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Is it just the namespace or are there problems in the use statements as well?",
"Is it just the namespace or is there a problem in the use statements as well?",
],
&[],
);
}
#[test]
fn fix_are_there_solution() {
assert_good_and_bad_suggestions(
"Are there solution for making lsws using h2 protocol in client browsers?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Are there solutions for making lsws using h2 protocol in client browsers?",
"Is there a solution for making lsws using h2 protocol in client browsers?",
],
&[],
);
}
#[test]
fn fix_are_there_solution_slash_workaround() {
assert_good_and_bad_suggestions(
"are there solution/workaround ?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"are there solutions/workaround ?",
"is there a solution/workaround ?",
],
&[],
);
}
#[test]
fn fix_are_there_concept() {
assert_good_and_bad_suggestions(
"So, what is a external interface in C++? are there concept of interface in C++?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"So, what is a external interface in C++? are there concepts of interface in C++?",
"So, what is a external interface in C++? is there a concept of interface in C++?",
],
&[],
);
}
#[test]
fn fix_are_there_object() {
assert_good_and_bad_suggestions(
"He check are there object with same id, if there is no object with same id he creates new and add to array",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"He check are there objects with same id, if there is no object with same id he creates new and add to array",
"He check is there an object with same id, if there is no object with same id he creates new and add to array",
],
&[],
);
}
#[test]
#[ignore = "variable is being rejected as an adjective as well as a singular noun"]
fn fix_are_there_variable() {
assert_good_and_bad_suggestions(
"Are there variable in side it or is it some sort of dataset?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Are there variables in side it or is it some sort of dataset?",
"Is there a variable in side it or is it some sort of dataset?",
],
&[],
);
}
#[test]
fn ignore_are_there_answer_generation_errors() {
assert_no_lints(
"Are there Answer Generation Errors?",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn ignore_are_there_application_objects() {
assert_no_lints(
"Are there application objects assigned to non-existent sites",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn ignore_are_there_code_files() {
assert_no_lints(
"Why are there code files more than 10k lines long?",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn ignore_are_there_error_logs() {
assert_no_lints(
"Are there error logs in your worker when flows fail?",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn ignore_are_there_tool_specific() {
assert_no_lints(
"Are there tool specific constraints for RM tool exchange for EA?",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_was_there_bugs() {
assert_good_and_bad_suggestions(
"Was there bugs, and goofed-up quests?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Were there bugs, and goofed-up quests?",
"Was there a bug, and goofed-up quests?",
],
&[],
);
}
#[test]
fn fix_was_there_hints() {
assert_good_and_bad_suggestions(
"Was there hints in the game that points you to it?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Were there hints in the game that points you to it?",
"Was there a hint in the game that points you to it?",
],
&[],
);
}
#[test]
fn fix_was_there_issues() {
assert_good_and_bad_suggestions(
"I saw you closed that PR, was there issues getting it merged upstream?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"I saw you closed that PR, were there issues getting it merged upstream?",
"I saw you closed that PR, was there an issue getting it merged upstream?",
],
&[],
);
}
#[test]
fn fix_was_there_problems() {
assert_good_and_bad_suggestions(
"Was there problems with other files that you had written to the SD card (PRG/CRT)?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Were there problems with other files that you had written to the SD card (PRG/CRT)?",
"Was there a problem with other files that you had written to the SD card (PRG/CRT)?",
],
&[],
);
}
#[test]
fn dont_flag_last_time_i_was_there() {
assert_no_lints(
"Last time I was there flags were on almost every house or fence.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
#[ignore = "Harper cannot detect this construction"]
fn dont_flag_the_grate_was_there() {
assert_no_lints(
"Saying the grate was there helps him avoid a lawsuit.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_when_he_was_there() {
assert_no_lints(
"When he was there tips were going way, way up.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn were_there_description() {
assert_good_and_bad_suggestions(
"Were there pictures of the Primarchs around before then? Were there description?",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Were there pictures of the Primarchs around before then? Were there descriptions?",
"Were there pictures of the Primarchs around before then? Was there a description?",
],
&[],
);
}
#[test]
fn font_flag_were_there_bomb_drills() {
assert_no_lints(
"Were there bomb drills in school?",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_were_there_set_rules() {
assert_no_lints(
"For instance, were there set rules as to the funds that candidates would have to have acquired",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn dont_flag_were_there_tour_buses() {
assert_no_lints(
"Were there tour buses and different hotels and parties each night? Yep.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_theres_children() {
assert_good_and_bad_suggestions(
"now, check whether there's children",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"now, check whether there's a child",
"now, check whether there are children",
],
&[],
);
}
#[test]
fn fix_theres_ideas() {
assert_good_and_bad_suggestions(
"there's ideas how it should behave for some media etc.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there's an idea how it should behave for some media etc.",
"there are ideas how it should behave for some media etc.",
],
&[],
);
}
#[test]
fn fix_theres_people() {
assert_good_and_bad_suggestions(
"Currently there's people helping out, and it's fairly easy to find someone if you need something.",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"Currently there are people helping out, and it's fairly easy to find someone if you need something.",
"Currently there's a person helping out, and it's fairly easy to find someone if you need something.",
],
&[],
);
}
#[test]
fn fix_theres_problems() {
assert_good_and_bad_suggestions(
"there's problems when using WSL::Ubuntu",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"there are problems when using WSL::Ubuntu",
"there's a problem when using WSL::Ubuntu",
],
&[],
);
}
#[test]
fn fix_theres_things() {
assert_good_and_bad_suggestions(
"If there's things you love/hate about Vidstack please let us know",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"If there are things you love/hate about Vidstack please let us know",
"If there's a thing you love/hate about Vidstack please let us know",
],
&[],
);
}
#[test]
fn fix_theres_urls() {
assert_good_and_bad_suggestions(
"so you're not suprised if there's urls missing or your data isn't being refreshed daily",
ThereIsAgreement::new(FstDictionary::curated()),
&[
"so you're not suprised if there are urls missing or your data isn't being refreshed daily",
"so you're not suprised if there's a url missing or your data isn't being refreshed daily",
],
&[],
);
}
#[test]
fn fix_browser_console_3066() {
assert_no_lints(
"Finally, I’ve checked the browser’s developer console for any JavaScript errors, but there are none.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_there_was_none_3066() {
assert_no_lints(
"There were none.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
#[test]
fn fix_none_related_to_3066() {
assert_no_lints(
"I’ve inspected the browser console for JavaScript errors, and there are none related to WooCommerce or the product variation functionality.",
ThereIsAgreement::new(FstDictionary::curated()),
);
}
}