Skip to content

fix(linting): add LifetimeLife rule to catch 'lifetime' where 'life' is meant#3772

Open
jlaportebot wants to merge 3 commits into
Automattic:masterfrom
jlaportebot:pr-3765
Open

fix(linting): add LifetimeLife rule to catch 'lifetime' where 'life' is meant#3772
jlaportebot wants to merge 3 commits into
Automattic:masterfrom
jlaportebot:pr-3765

Conversation

@jlaportebot

Copy link
Copy Markdown
Contributor

This PR adds a new lint rule that flags the use of 'lifetime' after superlatives where 'life' (lived experience) is the conventional word choice.

Examples:

  • "best day of my lifetime" → "best day of my life"
  • "worst experience of your lifetime" → "worst experience of your life"
  • "biggest change in our lifetime" → "biggest change in our life"

The rule correctly avoids flagging established idioms:

  • "once in a lifetime"
  • "lifetime achievement"
  • "lifetime warranty/guarantee/access/membership/subscription"

This is a rebased version of PR #3650 with the latest changes from master, plus a biome formatting fix for default_config.json.

@hippietrail hippietrail left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking reasonable but I have some tips for Harper style and avoiding allocations and conversion.

" in our lifetime",
" in their lifetime",
" of lifetime",
" in lifetime",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These look too repetitive and regular to list in longhand in my opinion. It looks like a pattern along the lines of

SequenceExpr::word_set(&["of", "in"]).t_ws().then_optional(SequenceExpr::default().then_possessive_determiner().t_ws()).t_aco("lifetime")

This is untested, typed off the top of my head.

// Check for exception phrases — if the matched region includes
// "once in a lifetime" or "lifetime achievement/warranty/guarantee/access",
// skip it.
let matched_text = toks.span()?.get_content_string(src).to_lowercase();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to avoid allocating new Strings whenever possible, which .to_lowercase() here will do. You can call things like toks.get_ch(src) and toks.span()?.get_content() which return &[char] which has methods on it such as .eq_ignore_ascii_case() using iteration thus avoiding allocations and conversions. (Again off the top of my head so may be a bit wrong.)

|| matched_text.contains("lifetime guarantee")
|| matched_text.contains("lifetime access")
|| matched_text.contains("lifetime membership")
|| matched_text.contains("lifetime subscription")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look for something like &[char].eq_any_ignore_ascii_case()

@hippietrail

Copy link
Copy Markdown
Collaborator

@elijah-potter Would like to try this one on your fuzzer? It's looking reasonable but needs data thrown at it to see how close it's getting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants