mirror of
https://github.com/Automattic/harper.git
synced 2025-12-05 19:26:55 -06:00
* feat: implement #1036 join prefix to word * fix: appease clippy * fix: act on advice in review
This commit is contained in:
@@ -9,7 +9,7 @@ object hello extends ScalaModule {
|
||||
ivy"com.lihaoyi::mainargs:0.6.2" // for CLI argument parsing
|
||||
)
|
||||
|
||||
// Define an test sub-module using a test framework.
|
||||
// Define an test submodule using a test framework.
|
||||
object test extends ScalaTests {
|
||||
def testFramework = "utest.runner.Framework"
|
||||
def ivyDeps = Agg(
|
||||
|
||||
@@ -53949,6 +53949,7 @@ U-turn/NgSVdG
|
||||
uh-huh
|
||||
uh-oh
|
||||
un-American/J
|
||||
up front/JR
|
||||
use case/NgS
|
||||
user-friendly/J
|
||||
UTF-16/Ng
|
||||
|
||||
@@ -80,6 +80,13 @@ impl Expr for SequenceExpr {
|
||||
impl SequenceExpr {
|
||||
// Constructor methods
|
||||
|
||||
// Single token methods
|
||||
|
||||
/// Construct a new sequence with an [`AnyPattern`] at the beginning of the operation list.
|
||||
pub fn anything() -> Self {
|
||||
Self::default().then_anything()
|
||||
}
|
||||
|
||||
// Single word token methods
|
||||
|
||||
/// Construct a new sequence with a [`Word`] at the beginning of the operation list.
|
||||
@@ -166,11 +173,21 @@ impl SequenceExpr {
|
||||
self.then(WordSet::new(words))
|
||||
}
|
||||
|
||||
/// Shorthand for [`Self::then_word_set`].
|
||||
pub fn t_set(self, words: &'static [&'static str]) -> Self {
|
||||
self.then_word_set(words)
|
||||
}
|
||||
|
||||
/// Match against one or more whitespace tokens.
|
||||
pub fn then_whitespace(self) -> Self {
|
||||
self.then(WhitespacePattern)
|
||||
}
|
||||
|
||||
/// Shorthand for [`Self::then_whitespace`].
|
||||
pub fn t_ws(self) -> Self {
|
||||
self.then_whitespace()
|
||||
}
|
||||
|
||||
/// Match against one or more whitespace tokens.
|
||||
pub fn then_whitespace_or_hyphen(self) -> Self {
|
||||
self.then(WhitespacePattern.or(|tok: &Token, _: &[char]| tok.kind.is_hyphen()))
|
||||
@@ -181,11 +198,6 @@ impl SequenceExpr {
|
||||
self.then_whitespace_or_hyphen()
|
||||
}
|
||||
|
||||
/// Shorthand for [`Self::then_whitespace`].
|
||||
pub fn t_ws(self) -> Self {
|
||||
self.then_whitespace()
|
||||
}
|
||||
|
||||
pub fn then_one_or_more(self, expr: impl Expr + 'static) -> Self {
|
||||
self.then(Repeating::new(Box::new(expr), 1))
|
||||
}
|
||||
|
||||
@@ -41,12 +41,7 @@ impl Default for CompoundNounAfterDetAdj {
|
||||
|
||||
let mut expr = All::default();
|
||||
expr.add(context_expr);
|
||||
expr.add(
|
||||
SequenceExpr::default()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.then(split_expr.clone()),
|
||||
);
|
||||
expr.add(SequenceExpr::anything().t_any().then(split_expr.clone()));
|
||||
|
||||
Self {
|
||||
expr: Box::new(expr),
|
||||
|
||||
206
harper-core/src/linting/disjoint_prefixes.rs
Normal file
206
harper-core/src/linting/disjoint_prefixes.rs
Normal file
@@ -0,0 +1,206 @@
|
||||
use crate::{
|
||||
Lint, Token, TokenKind, TokenStringExt,
|
||||
expr::{Expr, OwnedExprExt, SequenceExpr},
|
||||
linting::{ExprLinter, LintKind, Suggestion, expr_linter::Chunk},
|
||||
spell::Dictionary,
|
||||
};
|
||||
|
||||
pub struct DisjointPrefixes<D> {
|
||||
expr: Box<dyn Expr>,
|
||||
dict: D,
|
||||
}
|
||||
|
||||
// Known false positives not to join to these prefixes:
|
||||
const OUT_EXCEPTIONS: &[&str] = &["boxes", "facing", "live", "numbers", "playing"];
|
||||
const OVER_EXCEPTIONS: &[&str] = &["all", "joy", "long", "night", "reading", "steps", "time"];
|
||||
const UNDER_EXCEPTIONS: &[&str] = &["development", "mine"];
|
||||
const UP_EXCEPTIONS: &[&str] = &["loading", "right", "state", "time", "trend"];
|
||||
|
||||
impl<D> DisjointPrefixes<D>
|
||||
where
|
||||
D: Dictionary,
|
||||
{
|
||||
pub fn new(dict: D) -> Self {
|
||||
Self {
|
||||
expr: Box::new(
|
||||
SequenceExpr::word_set(&[
|
||||
// These prefixes rarely cause false positives
|
||||
"anti", "auto", "bi", "counter", "de", "dis", "extra", "fore", "hyper", "il",
|
||||
"im", "inter", "ir", "macro", "mal", "micro", "mid", "mini", "mis", "mono",
|
||||
"multi", "non", "omni", "post", "pre", "pro", "re", "semi", "sub", "super",
|
||||
"trans", "tri", "ultra", "un", "uni",
|
||||
// "co" has one very common false positive: co-op != coop
|
||||
"co",
|
||||
// These prefixes are all also words in their own right, which leads to more false positives.
|
||||
"out", "over", "under",
|
||||
"up",
|
||||
// These prefixes are commented out due to too many false positives
|
||||
// or incorrect transformations:
|
||||
// "a": a live -> alive
|
||||
// "in": in C -> inc; in action -> inaction
|
||||
])
|
||||
.t_ws_h()
|
||||
.then_kind_either(TokenKind::is_verb, TokenKind::is_noun)
|
||||
.then_optional_hyphen()
|
||||
.and_not(SequenceExpr::any_of(vec![
|
||||
// No trailing hyphen. Ex: Custom patterns take precedence over built-in patterns -> overbuilt
|
||||
Box::new(SequenceExpr::anything().t_any().t_any().then_hyphen()),
|
||||
// Don't merge "co op" whether separated by space or hyphen.
|
||||
Box::new(SequenceExpr::aco("co").t_any().t_set(&["op", "ops"])),
|
||||
// Merge these if they're separated by hyphen, but not space.
|
||||
Box::new(SequenceExpr::aco("out").t_ws().t_set(OUT_EXCEPTIONS)),
|
||||
Box::new(SequenceExpr::aco("over").t_ws().t_set(OVER_EXCEPTIONS)),
|
||||
Box::new(SequenceExpr::aco("under").t_ws().t_set(UNDER_EXCEPTIONS)),
|
||||
Box::new(SequenceExpr::aco("up").t_ws().t_set(UP_EXCEPTIONS)),
|
||||
])),
|
||||
),
|
||||
dict,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> ExprLinter for DisjointPrefixes<D>
|
||||
where
|
||||
D: Dictionary,
|
||||
{
|
||||
type Unit = Chunk;
|
||||
|
||||
fn expr(&self) -> &dyn Expr {
|
||||
self.expr.as_ref()
|
||||
}
|
||||
|
||||
fn match_to_lint_with_context(
|
||||
&self,
|
||||
toks: &[Token],
|
||||
src: &[char],
|
||||
ctx: Option<(&[Token], &[Token])>,
|
||||
) -> Option<Lint> {
|
||||
let toks_span = toks.span()?;
|
||||
let (pre, _) = ctx?;
|
||||
|
||||
// Cloud Native Pub-Sub System at Pinterest -> subsystem
|
||||
if pre.last().is_some_and(|p| p.kind.is_hyphen()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Avoid including text from unlintable sections between tokens
|
||||
// that could result from naively using toks.span()?.get_content_string(src)
|
||||
let original = format!(
|
||||
"{}{}{}",
|
||||
toks[0].span.get_content_string(src),
|
||||
if toks[1].kind.is_hyphen() { '-' } else { ' ' },
|
||||
toks[2].span.get_content_string(src)
|
||||
);
|
||||
|
||||
// If the original form is in the dictionary, return None
|
||||
if self.dict.contains_word_str(&original) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut hyphenated = None;
|
||||
if !toks[1].kind.is_hyphen() {
|
||||
hyphenated = Some(format!(
|
||||
"{}-{}",
|
||||
toks[0].span.get_content_string(src),
|
||||
toks[2].span.get_content_string(src)
|
||||
));
|
||||
}
|
||||
let joined = Some(format!(
|
||||
"{}{}",
|
||||
toks[0].span.get_content_string(src),
|
||||
toks[2].span.get_content_string(src)
|
||||
));
|
||||
|
||||
// Check if either joined or hyphenated form is in the dictionary
|
||||
let joined_valid = joined
|
||||
.as_ref()
|
||||
.is_some_and(|j| self.dict.contains_word_str(j));
|
||||
let hyphenated_valid = hyphenated
|
||||
.as_ref()
|
||||
.is_some_and(|h| self.dict.contains_word_str(h));
|
||||
|
||||
if !joined_valid && !hyphenated_valid {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Joining with a hyphen when original is separated by space is more likely correct
|
||||
// if hyphenated form is in the dictionary. So add first if verified.
|
||||
// Joining when separated by a space is more common but also has more false positives, so add them second.
|
||||
let suggestions = [(&hyphenated, hyphenated_valid), (&joined, joined_valid)]
|
||||
.into_iter()
|
||||
.filter_map(|(word, is_valid)| word.as_ref().filter(|_| is_valid))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let suggestions = suggestions
|
||||
.iter()
|
||||
.map(|s| {
|
||||
Suggestion::replace_with_match_case(s.chars().collect(), toks_span.get_content(src))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(Lint {
|
||||
span: toks_span,
|
||||
lint_kind: LintKind::Spelling,
|
||||
suggestions,
|
||||
message: "This looks like a prefix that can be joined with the rest of the word."
|
||||
.to_string(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Looks for words with their prefixes written with a space or hyphen between instead of joined."
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DisjointPrefixes;
|
||||
use crate::{
|
||||
linting::tests::{assert_no_lints, assert_suggestion_result},
|
||||
spell::FstDictionary,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn fix_hyphenated_to_joined() {
|
||||
assert_suggestion_result(
|
||||
"Download pre-built binaries or build from source.",
|
||||
DisjointPrefixes::new(FstDictionary::curated()),
|
||||
"Download prebuilt binaries or build from source.",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fix_open_to_joined() {
|
||||
assert_suggestion_result(
|
||||
"Advanced Nginx configuration available for super users",
|
||||
DisjointPrefixes::new(FstDictionary::curated()),
|
||||
"Advanced Nginx configuration available for superusers",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_join_open_co_op() {
|
||||
assert_no_lints(
|
||||
"They are cheaper at the co op.",
|
||||
DisjointPrefixes::new(FstDictionary::curated()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_join_hyphenated_co_op() {
|
||||
assert_no_lints(
|
||||
"Almost everything is cheaper at the co-op.",
|
||||
DisjointPrefixes::new(FstDictionary::curated()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fix_open_to_hyphenated() {
|
||||
assert_suggestion_result(
|
||||
"My hobby is de extinction of the dinosaurs.",
|
||||
DisjointPrefixes::new(FstDictionary::curated()),
|
||||
"My hobby is de-extinction of the dinosaurs.",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,14 +22,9 @@ impl Default for Everyday {
|
||||
.t_ws()
|
||||
.then_any_word(),
|
||||
),
|
||||
Box::new(
|
||||
SequenceExpr::default()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.then_kind_where(|kind| {
|
||||
!kind.is_noun() && !kind.is_oov() && !kind.is_verb_progressive_form()
|
||||
}),
|
||||
),
|
||||
Box::new(SequenceExpr::anything().t_any().then_kind_where(|kind| {
|
||||
!kind.is_noun() && !kind.is_oov() && !kind.is_verb_progressive_form()
|
||||
})),
|
||||
]);
|
||||
|
||||
let bad_before_every_day = All::new(vec![
|
||||
@@ -56,8 +51,7 @@ impl Default for Everyday {
|
||||
.then_any_word(),
|
||||
),
|
||||
Box::new(
|
||||
SequenceExpr::default()
|
||||
.t_any()
|
||||
SequenceExpr::anything()
|
||||
.t_any()
|
||||
.then_kind_both(TokenKind::is_noun, TokenKind::is_verb)
|
||||
.t_any()
|
||||
@@ -72,7 +66,7 @@ impl Default for Everyday {
|
||||
.then(everyday.clone())
|
||||
.then_punctuation(),
|
||||
),
|
||||
Box::new(SequenceExpr::default().t_any().then_kind_where(|kind| {
|
||||
Box::new(SequenceExpr::anything().then_kind_where(|kind| {
|
||||
matches!(
|
||||
kind,
|
||||
TokenKind::Punctuation(
|
||||
@@ -92,8 +86,7 @@ impl Default for Everyday {
|
||||
.then_punctuation(),
|
||||
),
|
||||
Box::new(
|
||||
SequenceExpr::default()
|
||||
.t_any()
|
||||
SequenceExpr::anything()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.t_any()
|
||||
|
||||
@@ -16,8 +16,7 @@ impl Default for HowTo {
|
||||
fn default() -> Self {
|
||||
let mut pattern = All::default();
|
||||
|
||||
let pos_pattern = SequenceExpr::default()
|
||||
.then_anything()
|
||||
let pos_pattern = SequenceExpr::anything()
|
||||
.then_anything()
|
||||
.t_aco("how")
|
||||
.then_whitespace()
|
||||
|
||||
@@ -18,8 +18,7 @@ impl Default for General {
|
||||
.or(WordSet::new(&["because"])),
|
||||
);
|
||||
|
||||
let exceptions = SequenceExpr::default()
|
||||
.then_anything()
|
||||
let exceptions = SequenceExpr::anything()
|
||||
.then_anything()
|
||||
.then(WordSet::new(&["own", "intended"]));
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ impl Default for Likewise {
|
||||
expr.add(SequenceExpr::aco("like").then_whitespace().t_aco("wise"));
|
||||
expr.add(
|
||||
SequenceExpr::default().then_unless(
|
||||
SequenceExpr::default()
|
||||
.then_anything()
|
||||
SequenceExpr::anything()
|
||||
.then_whitespace()
|
||||
.then_anything()
|
||||
.then_whitespace()
|
||||
|
||||
@@ -50,6 +50,7 @@ use super::currency_placement::CurrencyPlacement;
|
||||
use super::despite_of::DespiteOf;
|
||||
use super::didnt::Didnt;
|
||||
use super::discourse_markers::DiscourseMarkers;
|
||||
use super::disjoint_prefixes::DisjointPrefixes;
|
||||
use super::dot_initialisms::DotInitialisms;
|
||||
use super::double_click::DoubleClick;
|
||||
use super::double_modal::DoubleModal;
|
||||
@@ -690,6 +691,12 @@ impl LintGroup {
|
||||
out.add("MassPlurals", MassPlurals::new(dictionary.clone()));
|
||||
out.config.set_rule_enabled("MassPlurals", true);
|
||||
|
||||
out.add_chunk_expr_linter(
|
||||
"DisjointPrefixes",
|
||||
DisjointPrefixes::new(dictionary.clone()),
|
||||
);
|
||||
out.config.set_rule_enabled("DisjointPrefixes", true);
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
@@ -830,7 +837,7 @@ mod tests {
|
||||
#[test]
|
||||
fn dont_flag_low_hanging_fruit_desc() {
|
||||
assert_no_lints(
|
||||
"Corrects non-standard variants of low-hanging fruit.",
|
||||
"Corrects nonstandard variants of low-hanging fruit.",
|
||||
test_group(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ mod despite_of;
|
||||
mod determiner_without_noun;
|
||||
mod didnt;
|
||||
mod discourse_markers;
|
||||
mod disjoint_prefixes;
|
||||
mod dot_initialisms;
|
||||
mod double_click;
|
||||
mod double_modal;
|
||||
|
||||
@@ -23,8 +23,7 @@ impl Default for MostNumber {
|
||||
),
|
||||
// Context pattern
|
||||
Box::new(
|
||||
SequenceExpr::default()
|
||||
.then_anything()
|
||||
SequenceExpr::anything()
|
||||
.then_anything()
|
||||
.then_anything()
|
||||
.then_anything()
|
||||
|
||||
@@ -27,8 +27,7 @@ impl Default for NeedToNoun {
|
||||
Box::new(WordSet::new(&["about", "it"])),
|
||||
]);
|
||||
|
||||
let exceptions = SequenceExpr::default()
|
||||
.t_any()
|
||||
let exceptions = SequenceExpr::anything()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.t_any()
|
||||
|
||||
@@ -40,16 +40,13 @@ impl Default for OpenCompounds {
|
||||
}
|
||||
let compound = Lrc::new(SequenceExpr::default().then(compound_wordset));
|
||||
|
||||
let with_prev = SequenceExpr::default()
|
||||
.then_anything()
|
||||
.then(compound.clone());
|
||||
let with_prev = SequenceExpr::anything().then(compound.clone());
|
||||
|
||||
let with_next = SequenceExpr::default()
|
||||
.then(compound.clone())
|
||||
.then_anything();
|
||||
|
||||
let with_prev_and_next = SequenceExpr::default()
|
||||
.then_anything()
|
||||
let with_prev_and_next = SequenceExpr::anything()
|
||||
.then(compound.clone())
|
||||
.then_anything();
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ pub fn lint_group() -> LintGroup {
|
||||
["in built", "in-built", "built in"],
|
||||
["built-in"],
|
||||
"Prefer the hyphenated compound `built-in`.",
|
||||
"English convention treats `built-in` as a single, attributive adjective—meaning something integrated from the outset—whereas other forms like `in built` are non-standard and can feel awkward to readers."
|
||||
"English convention treats `built-in` as a single, attributive adjective—meaning something integrated from the outset—whereas other forms like `in built` are nonstandard and can feel awkward to readers."
|
||||
),
|
||||
"ByAccident" => (
|
||||
["on accident"],
|
||||
@@ -756,7 +756,7 @@ pub fn lint_group() -> LintGroup {
|
||||
["low hanging fruit", "low hanging fruits", "low-hanging fruits"],
|
||||
["low-hanging fruit"],
|
||||
"The standard form is `low-hanging fruit` with a hyphen and singular form.",
|
||||
"Corrects non-standard variants of `low-hanging fruit`.",
|
||||
"Corrects nonstandard variants of `low-hanging fruit`.",
|
||||
LintKind::Usage
|
||||
),
|
||||
"ManagerialReins" => (
|
||||
@@ -915,7 +915,7 @@ pub fn lint_group() -> LintGroup {
|
||||
["quite many"],
|
||||
["quite a few"],
|
||||
"Use `quite a few` instead of `quite many`.",
|
||||
"Corrects `quite many` to `quite a few`, which is the more natural and idiomatic phrase in standard English. `Quite many` is considered non-standard usage.",
|
||||
"Corrects `quite many` to `quite a few`, which is the more natural and idiomatic phrase in standard English. `Quite many` is considered nonstandard usage.",
|
||||
LintKind::Nonstandard
|
||||
),
|
||||
"RapidFire" => (
|
||||
|
||||
@@ -23,14 +23,9 @@ where
|
||||
.then_kind_is_but_is_not(TokenKind::is_plural_nominal, TokenKind::is_singular_nominal)
|
||||
.t_ws()
|
||||
.then(UPOSSet::new(&[UPOS::NOUN, UPOS::PROPN]))
|
||||
.then_optional(SequenceExpr::default().t_any().t_any());
|
||||
.then_optional(SequenceExpr::anything().t_any());
|
||||
|
||||
let additional_req = SequenceExpr::default()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.then_noun();
|
||||
let additional_req = SequenceExpr::anything().t_any().t_any().t_any().then_noun();
|
||||
|
||||
let exceptions = SequenceExpr::default()
|
||||
.then_unless(|tok: &Token, _: &[char]| tok.kind.is_demonstrative_determiner())
|
||||
|
||||
@@ -84,7 +84,7 @@ impl ExprLinter for ShootOneselfInTheFoot {
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Corrects non-standard variants of 'shoot oneself in the foot'."
|
||||
"Corrects nonstandard variants of 'shoot oneself in the foot'."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@ impl Default for VerbToAdjective {
|
||||
.t_ws()
|
||||
.then(UPOSSet::new(&[UPOS::NOUN, UPOS::PROPN]));
|
||||
|
||||
let exceptions = SequenceExpr::default()
|
||||
.t_any()
|
||||
let exceptions = SequenceExpr::anything()
|
||||
.t_any()
|
||||
.then_unless(WordSet::new(&["very"]));
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ impl Default for WayTooAdjective {
|
||||
.t_ws()
|
||||
.then(UPOSSet::new(&[UPOS::ADJ]).or(WordSet::new(&["much"])));
|
||||
|
||||
let exceptions = SequenceExpr::default()
|
||||
.t_any()
|
||||
let exceptions = SequenceExpr::anything()
|
||||
.t_any()
|
||||
.t_any()
|
||||
.t_any()
|
||||
|
||||
@@ -68,7 +68,6 @@ macro_rules! create_org_test {
|
||||
}
|
||||
|
||||
create_test!(whack_bullets.md, 1, Dialect::American);
|
||||
create_test!(preexisting.md, 0, Dialect::American);
|
||||
create_test!(issue_109.md, 0, Dialect::American);
|
||||
create_test!(issue_109_ext.md, 0, Dialect::American);
|
||||
create_test!(chinese_lorem_ipsum.md, 2, Dialect::American);
|
||||
@@ -99,7 +98,7 @@ create_test!(issue_2240.md, 0, Dialect::American);
|
||||
create_test!(issue_2151.md, 4, Dialect::British);
|
||||
|
||||
// Make sure it doesn't panic
|
||||
create_test!(lukas_homework.md, 3, Dialect::American);
|
||||
create_test!(lukas_homework.md, 4, Dialect::American);
|
||||
|
||||
// Org mode tests
|
||||
create_org_test!(index.org, 49, Dialect::American);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Usage of pre-existing should be allowed.
|
||||
@@ -12,7 +12,7 @@ Nutritionally, yoghurt is celebrated for its health benefits. It is rich in prot
|
||||
|
||||
The production methods of yoghurt have evolved significantly over time, from traditional artisanal practices to advanced industrial techniques. Modern yoghurt manufacturing employs precise control of temperature, bacterial cultures, and incubation processes to ensure consistent quality, taste, and nutritional content. Additionally, innovations in packaging and preservation have expanded yoghurt's accessibility and convenience, making it an ubiquitous presence in supermarkets worldwide.
|
||||
|
||||
However, yoghurt production and consumption also present certain challenges. Concerns around sustainability, environmental impact, and ethical dairy farming practices have encouraged a shift toward organic and plant-based alternatives. This has spurred market growth for non-dairy yoghurts made from ingredients such as coconut, almond, oat, and soy, reflecting evolving consumer preferences and dietary needs.
|
||||
However, yoghurt production and consumption also present certain challenges. Concerns around sustainability, environmental impact, and ethical dairy farming practices have encouraged a shift toward organic and plant-based alternatives. This has spurred market growth for nondairy yoghurts made from ingredients such as coconut, almond, oat, and soy, reflecting evolving consumer preferences and dietary needs.
|
||||
|
||||
In conclusion, yoghurt is much more than a simple dairy product—it is a cultural and nutritional cornerstone that continues to adapt and thrive across global culinary traditions. Its enduring popularity is a testament to its delicious versatility, health benefits, and adaptability to changing dietary trends, ensuring yoghurt's continued prominence in diets around the world.
|
||||
|
||||
|
||||
@@ -303,6 +303,16 @@ Suggest:
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
122 | science; this is now used for a multi-disciplinary field of data analysis,
|
||||
| ^~~~~~~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
123 | including statistics and databases.
|
||||
Suggest:
|
||||
- Replace with: “multidisciplinary”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
126 | field of computing were suggested (albeit facetiously) in the Communications of
|
||||
@@ -1027,6 +1037,16 @@ Suggest:
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
444 | > easily distinguishable states, such as "on/off", "magnetized/de-magnetized",
|
||||
| ^~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
445 | > "high-voltage/low-voltage", etc.).
|
||||
Suggest:
|
||||
- Replace with: “demagnetized”
|
||||
|
||||
|
||||
|
||||
Lint: Capitalization (31 priority)
|
||||
Message: |
|
||||
456 | - print 1 at current location.
|
||||
|
||||
@@ -71,6 +71,15 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
43 | However, there are clearly many more categories and sub-categories. For nouns,
|
||||
| ^~~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “subcategories”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
49 | tags. For example, NN for singular common nouns, NNS for plural common nouns, NP
|
||||
@@ -371,6 +380,16 @@ Suggest:
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
154 | algorithms one of the most widely used being the bi-directional inference
|
||||
| ^~~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
155 | algorithm.
|
||||
Suggest:
|
||||
- Replace with: “bidirectional”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
159 | In 1987, Steven DeRose and Kenneth W. Church independently developed dynamic
|
||||
@@ -480,6 +499,16 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
184 | The methods already discussed involve working from a pre-existing corpus to
|
||||
| ^~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
185 | learn tag probabilities. It is, however, also possible to bootstrap using
|
||||
Suggest:
|
||||
- Replace with: “preexisting”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
200 | Some current major algorithms for part-of-speech tagging include the Viterbi
|
||||
|
||||
@@ -377,6 +377,16 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
137 | one of those men who reach such an acute limited excellence at twenty-one that
|
||||
138 | everything afterward savors of anti-climax. His family were enormously
|
||||
| ^~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “anticlimax”
|
||||
|
||||
|
||||
|
||||
Lint: Readability (127 priority)
|
||||
Message: |
|
||||
138 | everything afterward savors of anti-climax. His family were enormously
|
||||
@@ -979,6 +989,15 @@ Suggest:
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
775 | Up-stairs, in the solemn echoing drive she let four taxicabs drive away before
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “Upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
784 | We backed up to a gray old man who bore an absurd resemblance to John D.
|
||||
@@ -1453,6 +1472,16 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
1188 | piccolos, and low and high drums. The last swimmers have come in from the beach
|
||||
1189 | now and are dressing up-stairs; the cars from New York are parked five deep in
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
1191 | colors, and hair bobbed in strange new ways, and shawls beyond the dreams of
|
||||
@@ -2059,6 +2088,17 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
1745 | I took dinner usually at the Yale Club—for some reason it was the gloomiest
|
||||
1746 | event of my day—and then I went up-stairs to the library and studied investments
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
1747 | and securities for a conscientious hour. There were generally a few rioters
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Readability (127 priority)
|
||||
Message: |
|
||||
1759 | darkness. At the enchanted metropolitan twilight I felt a haunting loneliness
|
||||
@@ -2120,6 +2160,16 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
1781 | the newspapers—a suggestion that she had moved her ball from a bad lie in the
|
||||
1782 | semi-final round. The thing approached the proportions of a scandal—then died
|
||||
| ^~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “semifinal”
|
||||
|
||||
|
||||
|
||||
Lint: Readability (127 priority)
|
||||
Message: |
|
||||
1789 | thought impossible. She was incurably dishonest. She wasn’t able to endure being
|
||||
@@ -4087,6 +4137,15 @@ Suggest:
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
2789 | Daisy went up-stairs to wash her face—too late I thought with humiliation of my
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Formatting (255 priority)
|
||||
Message: |
|
||||
2806 | was in he answered: ‘‘That’s my affair,” before he realized that it wasn’t an
|
||||
@@ -4149,6 +4208,15 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
2840 | We went up-stairs, through period bedrooms swathed in rose and lavender silk and
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
2842 | sunken baths—intruding into one chamber where a dishevelled man in pajamas was
|
||||
@@ -5259,6 +5327,15 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
3765 | They went up-stairs to get ready while we three men stood there shuffling the
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Capitalization (127 priority)
|
||||
Message: |
|
||||
3795 | song of it. . . . High in a white palace the king’s daughter, the golden girl. .
|
||||
@@ -6483,6 +6560,16 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
4780 | her as his tent out at camp was to him. There was a ripe mystery about it, a
|
||||
4781 | hint of bedrooms up-stairs more beautiful and cool than other bedrooms, of gay
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Readability (127 priority)
|
||||
Message: |
|
||||
4797 | pretenses. I don’t mean that he had traded on his phantom millions, but he had
|
||||
@@ -7136,6 +7223,16 @@ Suggest:
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
5299 | Some one started to ask me questions, but I broke away and going up-stairs
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
5300 | looked hastily through the unlocked parts of his desk—he’d never told me
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
5304 | Next morning I sent the butler to New York with a letter to Wolfshiem, which
|
||||
@@ -7359,6 +7456,15 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
5390 | began to be mixed with an awed pride. I helped him to a bedroom up-stairs; while
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (63 priority)
|
||||
Message: |
|
||||
5396 | “Gatz is my name.”
|
||||
@@ -8083,6 +8189,16 @@ Message: |
|
||||
|
||||
|
||||
|
||||
Lint: Spelling (127 priority)
|
||||
Message: |
|
||||
5764 | ready to leave, and when I sent down word that we weren’t in he tried to force
|
||||
5765 | his way up-stairs. He was crazy enough to kill me if I hadn’t told him who owned
|
||||
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
|
||||
Suggest:
|
||||
- Replace with: “upstairs”
|
||||
|
||||
|
||||
|
||||
Lint: Readability (127 priority)
|
||||
Message: |
|
||||
5775 | “And if you think I didn’t have my share of suffering—look here, when I went to
|
||||
|
||||
Reference in New Issue
Block a user