Skip to content

feat(lint/nursery): new rule - noInvertedTernary#9312

Closed
js2me wants to merge 4 commits intobiomejs:mainfrom
js2me:main
Closed

feat(lint/nursery): new rule - noInvertedTernary#9312
js2me wants to merge 4 commits intobiomejs:mainfrom
js2me:main

Conversation

@js2me
Copy link
Copy Markdown

@js2me js2me commented Mar 3, 2026

This PR was written primarily by GPT-5.3 Codex

Summary

Added a new nursery lint rule: noInvertedTernary.

The rule reports inverted ternary conditions such as A !== B ? C : D (and A != B ? C : D) and provides an auto-fix that rewrites them to the direct form: A === B ? D : C (or A == B ? D : C).
This improves readability by avoiding negated ternary tests.

Also added rule tests (valid / invalid) and updated snapshots.

Test Plan

  • Ran:
    • cargo test -p biome_js_analyze no_inverted_ternary -- --nocapture
    • INSTA_UPDATE=always cargo test -p biome_js_analyze no_inverted_ternary
  • Verified:
    • diagnostics are reported for inverted ternaries
    • safe auto-fix rewrites them to the direct form
    • snapshots were updated accordingly

Docs

  • Added rustdoc documentation and examples in the rule implementation (invalid and valid cases).
  • No separate website documentation PR was needed for this change.

This PR was created with AI assistance (Cursor AI assistant).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 3, 2026

🦋 Changeset detected

Latest commit: 646c8e9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages L-JSON Language: JSON and super languages A-Diagnostic Area: diagnostocis labels Mar 3, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78ece89 and 646c8e9.

📒 Files selected for processing (2)
  • .changeset/cuddly-cougars-hope.md
  • crates/biome_js_analyze/src/lint/nursery/no_inverted_ternary.rs

Walkthrough

Adds a new ESLint-style lint rule noInvertedTernary to the biome JS analysis crate that detects ternary expressions using inequality tests with flipped branches and provides a safe automatic fix that flips the operator and swaps branches. Includes rule declaration, diagnostics, fix implementation, options type and export, tests (valid/invalid), and minor message ownership fixes in two existing diagnostics.

Suggested labels

A-Project

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a new nursery lint rule named noInvertedTernary.
Description check ✅ Passed The description is well-related to the changeset, detailing the new rule, its purpose, test coverage, and verification steps performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/biome_rule_options/src/no_inverted_ternary.rs (1)

3-6: Add a short rustdoc block for the options type.

The struct is correct; it just needs inline docs to match repository convention for rule options.

📝 Suggested patch
+/// Options for `noInvertedTernary`.
+///
+/// This rule currently has no configurable options.
 pub struct NoInvertedTernaryOptions {}

As per coding guidelines: "Use inline rustdoc documentation for rules, assists, and their options".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_rule_options/src/no_inverted_ternary.rs` around lines 3 - 6, Add
an inline rustdoc comment above the NoInvertedTernaryOptions struct describing
what this options type controls (e.g., options for the "no inverted ternary"
lint/rule), include a short one-line summary and, if applicable, list any fields
or default behavior; place the doc comment (/// ...) directly above pub struct
NoInvertedTernaryOptions {} to match repository convention for rule options.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/cuddly-cougars-hope.md:
- Line 5: Update the changeset note for the new rule "noInvertedTernary" to be
user-facing: describe in one sentence what patterns the rule catches (e.g.,
ternary expressions with inverted condition/result order that reduce
readability), explain the intended fix, and include one inline invalid example
such as `const x = condition ? falseValue : trueValue;` (or a short code block)
showing the problematic inverted ternary; ensure the changeset text is clear for
end users and replaces the minimal "new rule noInvertedTernary" line with this
expanded description.

In `@crates/biome_js_analyze/src/lint/nursery/no_inverted_ternary.rs`:
- Around line 56-57: The current code casts node.test() directly to a
JsBinaryExpression (via test_expression.as_js_binary_expression()), which fails
for parenthesised tests like `(a !== b) ? c : d`; update both run() and action()
to unwrap parenthesised expressions first by calling .inner_expression() on the
test_expression before attempting .as_js_binary_expression(), and do the same
for the similar usage around the other occurrence (the test variable at lines
83-84) so parenthesised binary tests are correctly detected and handled.

---

Nitpick comments:
In `@crates/biome_rule_options/src/no_inverted_ternary.rs`:
- Around line 3-6: Add an inline rustdoc comment above the
NoInvertedTernaryOptions struct describing what this options type controls
(e.g., options for the "no inverted ternary" lint/rule), include a short
one-line summary and, if applicable, list any fields or default behavior; place
the doc comment (/// ...) directly above pub struct NoInvertedTernaryOptions {}
to match repository convention for rule options.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 753be72 and 78ece89.

⛔ Files ignored due to path filters (3)
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInvertedTernary/invalid.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInvertedTernary/valid.js.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (8)
  • .changeset/cuddly-cougars-hope.md
  • crates/biome_js_analyze/src/lint/correctness/use_exhaustive_dependencies.rs
  • crates/biome_js_analyze/src/lint/nursery/no_inverted_ternary.rs
  • crates/biome_js_analyze/tests/specs/nursery/noInvertedTernary/invalid.js
  • crates/biome_js_analyze/tests/specs/nursery/noInvertedTernary/valid.js
  • crates/biome_json_analyze/src/lint/nursery/use_required_scripts.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_inverted_ternary.rs

Comment thread .changeset/cuddly-cougars-hope.md Outdated
"@biomejs/biome": patch
---

new rule noInvertedTernary
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Please expand the changeset note for end users.

new rule noInvertedTernary is a bit too minimal for release notes; include what it catches and one invalid example.

✍️ Suggested rewrite
-new rule noInvertedTernary
+Add the nursery rule `noInvertedTernary`, which flags inverted ternaries like
+`a !== b ? x : y` and auto-fixes them to `a === b ? y : x`.

As per coding guidelines: "Create changeset files ... with ... end-user-focused descriptions". Based on learnings: "For new lint rules in changesets, show an example of invalid case in inline code or code block".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
new rule noInvertedTernary
Add the nursery rule `noInvertedTernary`, which flags inverted ternaries like
`a !== b ? x : y` and auto-fixes them to `a === b ? y : x`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/cuddly-cougars-hope.md at line 5, Update the changeset note for
the new rule "noInvertedTernary" to be user-facing: describe in one sentence
what patterns the rule catches (e.g., ternary expressions with inverted
condition/result order that reduce readability), explain the intended fix, and
include one inline invalid example such as `const x = condition ? falseValue :
trueValue;` (or a short code block) showing the problematic inverted ternary;
ensure the changeset text is clear for end users and replaces the minimal "new
rule noInvertedTernary" line with this expanded description.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed

Comment thread crates/biome_js_analyze/src/lint/nursery/no_inverted_ternary.rs Outdated
Copy link
Copy Markdown
Member

@Netail Netail left a comment

Choose a reason for hiding this comment

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

Seems very related to https://biomejs.dev/linter/rules/no-negation-else/, could be a feature in that rule. (Does already cover != & !== for if statements & full negative in ternaries)

Also some generated schema data is missing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated to new rule

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated to new rule

Comment on lines +39 to +45
pub NoInvertedTernary {
version: "next",
name: "noInvertedTernary",
language: "js",
recommended: false,
fix_kind: FixKind::Safe,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are there existing eslint rules that do this? If so, add them as rule sources

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

https://eslint.org/docs/latest/rules/no-negated-condition does, which we already "implemented" (https://biomejs.dev/linter/rules/no-negation-else/), but our implementation does not seem to cover this yet. Created #9351

},
)
.note(markup! {
"Use an equality check in the test and swap the two branches for better readability."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow the rule pillars. The messages must say:

  1. What the error is (in diagnostic)
  2. Why it is an error (in diagnostic)
  3. How to fix the error (action message)


Some(JsRuleAction::new(
ctx.metadata().action_category(ctx.category(), ctx.group()),
Applicability::Always,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
Applicability::Always,
ctx.metadata().applicability(),

Comment on lines +29 to +37
/// ### Valid
///
/// ```js
/// const value = i === data.depth - 1 ? 0 : 18;
/// ```
///
/// ```js
/// const result = foo === bar ? second : first;
/// ```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: these valid cases can be combined

@Netail
Copy link
Copy Markdown
Member

Netail commented Mar 5, 2026

Will be covered by noNegationElse with #9351

@Netail Netail closed this Mar 5, 2026
@js2me
Copy link
Copy Markdown
Author

js2me commented Mar 5, 2026

Thank you, this thing is really useful

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

Labels

A-Diagnostic Area: diagnostocis A-Linter Area: linter L-JavaScript Language: JavaScript and super languages L-JSON Language: JSON and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants