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
6 changes: 6 additions & 0 deletions harper-core/src/linting/lint_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ use super::sentence_capitalization::SentenceCapitalization;
use super::shoot_oneself_in_the_foot::ShootOneselfInTheFoot;
use super::simple_past_to_past_participle::SimplePastToPastParticiple;
use super::since_duration::SinceDuration;
use super::sneaked_snuck::SneakedSnuck;
use super::some_without_article::SomeWithoutArticle;
use super::something_is::SomethingIs;
use super::somewhat_something::SomewhatSomething;
Expand Down Expand Up @@ -584,6 +585,7 @@ impl LintGroup {
insert_expr_rule!(ShootOneselfInTheFoot, true);
insert_expr_rule!(SimplePastToPastParticiple, true);
insert_expr_rule!(SinceDuration, true);
// insert_struct_rule!(SneakedSnuck, true);
insert_expr_rule!(SomeWithoutArticle, true);
insert_expr_rule!(SomethingIs, true);
insert_expr_rule!(SomewhatSomething, true);
Expand Down Expand Up @@ -650,6 +652,10 @@ impl LintGroup {
out.add("MassPlurals", MassPlurals::new(dictionary.clone()));
out.config.set_rule_enabled("MassPlurals", true);

out.add("SneakedSnuck", SneakedSnuck::default());
out.config.set_rule_enabled("PreferSneaked", true);
out.config.set_rule_enabled("PreferSnuck", false);

out
}

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 @@ -155,6 +155,7 @@ mod sentence_capitalization;
mod shoot_oneself_in_the_foot;
mod simple_past_to_past_participle;
mod since_duration;
mod sneaked_snuck;
mod some_without_article;
mod something_is;
mod somewhat_something;
Expand Down Expand Up @@ -330,6 +331,7 @@ pub use sentence_capitalization::SentenceCapitalization;
pub use shoot_oneself_in_the_foot::ShootOneselfInTheFoot;
pub use simple_past_to_past_participle::SimplePastToPastParticiple;
pub use since_duration::SinceDuration;
pub use sneaked_snuck::SneakedSnuck;
pub use some_without_article::SomeWithoutArticle;
pub use something_is::SomethingIs;
pub use somewhat_something::SomewhatSomething;
Expand Down
14 changes: 14 additions & 0 deletions harper-core/src/linting/sneaked_snuck/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
mod prefer_sneaked;
mod prefer_snuck;

use super::merge_linters::merge_linters;

use prefer_sneaked::PreferSneaked;
use prefer_snuck::PreferSnuck;

merge_linters! {
SneakedSnuck =>
PreferSneaked,
PreferSnuck
=> "Enforces `sneaked` v `snuck` preferences."
}
54 changes: 54 additions & 0 deletions harper-core/src/linting/sneaked_snuck/prefer_sneaked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::expr::Expr;
use crate::linting::{ExprLinter, LintKind, Suggestion};
use crate::patterns::Word;
use crate::{Lint, Token};

pub struct PreferSneaked {
expr: Box<dyn Expr>,
}

impl Default for PreferSneaked {
fn default() -> Self {
Self {
expr: Box::new(Word::new("snuck")),
}
}
}

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

fn match_to_lint(&self, toks: &[Token], src: &[char]) -> Option<Lint> {
Some(Lint {
span: toks[0].span,
lint_kind: LintKind::Usage,
suggestions: vec![Suggestion::replace_with_match_case(
['s', 'n', 'e', 'a', 'k', 'e', 'd'].to_vec(),
toks[0].span.get_content(src),
)],
message: "Use `sneaked` instead of `snuck`.".to_string(),
..Default::default()
})
}

fn description(&self) -> &str {
"Prefer 'sneaked' over 'snuck'"
}
}

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

#[test]
fn correct_snuck_to_sneaked() {
assert_suggestion_result(
"He snuck in around the back.",
PreferSneaked::default(),
"He sneaked in around the back.",
);
}
}
54 changes: 54 additions & 0 deletions harper-core/src/linting/sneaked_snuck/prefer_snuck.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::expr::Expr;
use crate::linting::{ExprLinter, LintKind, Suggestion};
use crate::patterns::Word;
use crate::{Lint, Token};

pub struct PreferSnuck {
expr: Box<dyn Expr>,
}

impl Default for PreferSnuck {
fn default() -> Self {
Self {
expr: Box::new(Word::new("sneaked")),
}
}
}

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

fn match_to_lint(&self, toks: &[Token], src: &[char]) -> Option<Lint> {
Some(Lint {
span: toks[0].span,
lint_kind: LintKind::Usage,
suggestions: vec![Suggestion::replace_with_match_case(
['s', 'n', 'u', 'c', 'k'].to_vec(),
toks[0].span.get_content(src),
)],
message: "Use `snuck` instead of `sneaked`.".to_string(),
..Default::default()
})
}

fn description(&self) -> &str {
"Prefer `snuck` over `sneaked`."
}
}

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

#[test]
fn correct_sneaked_to_snuck() {
assert_suggestion_result(
"He sneaked in around the back.",
PreferSnuck::default(),
"He snuck in around the back.",
);
}
}
16 changes: 15 additions & 1 deletion packages/obsidian-plugin/src/State.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,27 @@
expect(settings.lintSettings.RepeatedWords).toBe(null);
});

// packages/obsidian-plugin/src/State.test.ts (use ref 5173e96f5c9f6fea80c2fabf7c2940672090ec5f)
test('Lint settings and descriptions have the same keys', async () => {
const state = createEphemeralState();

const settings = await state.getSettings();
const descriptions = await state.getDescriptionHTML();

expect(Object.keys(descriptions).sort()).toStrictEqual(Object.keys(settings.lintSettings).sort());
const lintKeys = Object.keys(settings.lintSettings).sort();
const descKeys = Object.keys(descriptions).sort();

const missingInDescriptions = lintKeys.filter((k) => !descKeys.includes(k));
const extraInDescriptions = descKeys.filter((k) => !lintKeys.includes(k));

if (missingInDescriptions.length || extraInDescriptions.length) {
// Print the diffs so CI/local run shows the exact keys
console.error('Missing in descriptions (present in lintSettings):', missingInDescriptions);
console.error('Extra in descriptions (not in lintSettings):', extraInDescriptions);
}

expect(missingInDescriptions.length).toBe(0);

Check failure on line 105 in packages/obsidian-plugin/src/State.test.ts

View workflow job for this annotation

GitHub Actions / just test-obsidian

src/State.test.ts > Lint settings and descriptions have the same keys

AssertionError: expected 2 to be +0 // Object.is equality - Expected + Received - 0 + 2 ❯ src/State.test.ts:105:38

Check failure on line 105 in packages/obsidian-plugin/src/State.test.ts

View workflow job for this annotation

GitHub Actions / just test-obsidian

src/State.test.ts > Lint settings and descriptions have the same keys

AssertionError: expected 2 to be +0 // Object.is equality - Expected + Received - 0 + 2 ❯ src/State.test.ts:105:38

Check failure on line 105 in packages/obsidian-plugin/src/State.test.ts

View workflow job for this annotation

GitHub Actions / just test-obsidian

src/State.test.ts > Lint settings and descriptions have the same keys

AssertionError: expected 2 to be +0 // Object.is equality - Expected + Received - 0 + 2 ❯ src/State.test.ts:105:38

Check failure on line 105 in packages/obsidian-plugin/src/State.test.ts

View workflow job for this annotation

GitHub Actions / just test-obsidian

src/State.test.ts > Lint settings and descriptions have the same keys

AssertionError: expected 2 to be +0 // Object.is equality - Expected + Received - 0 + 2 ❯ src/State.test.ts:105:38

Check failure on line 105 in packages/obsidian-plugin/src/State.test.ts

View workflow job for this annotation

GitHub Actions / just test-obsidian

src/State.test.ts > Lint settings and descriptions have the same keys

AssertionError: expected 2 to be +0 // Object.is equality - Expected + Received - 0 + 2 ❯ src/State.test.ts:105:38

Check failure on line 105 in packages/obsidian-plugin/src/State.test.ts

View workflow job for this annotation

GitHub Actions / just test-obsidian

src/State.test.ts > Lint settings and descriptions have the same keys

AssertionError: expected 2 to be +0 // Object.is equality - Expected + Received - 0 + 2 ❯ src/State.test.ts:105:38
expect(extraInDescriptions.length).toBe(0);
});

test('Can be initialized with incomplete lint settings and retain default state.', async () => {
Expand Down
Loading