Skip to content

feat(lint): add ignoreBooleanCoercion option to useNullishCoalescing#10595

Open
pkallos wants to merge 1 commit into
biomejs:mainfrom
pkallos:pk/use-nullish-coalescing-ignore-boolean-coercion
Open

feat(lint): add ignoreBooleanCoercion option to useNullishCoalescing#10595
pkallos wants to merge 1 commit into
biomejs:mainfrom
pkallos:pk/use-nullish-coalescing-ignore-boolean-coercion

Conversation

@pkallos

@pkallos pkallos commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

This PR was created with AI assistance.

Summary

adds the ignoreBooleanCoercion option to useNullishCoalescing, partially addressing #9232. this follows on from #9974 which added ignoreMixedLogicalExpressions.

when enabled, || and ||= are not reported if the value is boolean-coerced by an enclosing Boolean() call, since coalescing on falsy values is intentional in that spot. i kept the scope to just this one option so it stays easy to review. the remaining options from #9232 (ignorePrimitives, ignoreIfStatements) can come as separate PRs.

the detection mirrors how the merged mixed-logical code reads: a small typed helper that scans ancestors, skips parens and logical parents (both || and &&, since the coerced value still flows into the call), and then checks the first other ancestor is the argument of a Boolean() call.

Test Plan

the spec snapshots cover this, but if you want to check it by hand:

  1. drop a biome.json enabling the rule and option:
{ "linter": { "rules": { "nursery": { "useNullishCoalescing": { "level": "error", "options": { "ignoreBooleanCoercion": true } } } } } }
  1. make a test.ts:
declare const a: string | null;
declare const b: string;
declare function identity<T>(v: T): T;

const r1 = Boolean(a || b);        // quiet
const r2 = Boolean(a || b || b);   // quiet (chained)
const r3 = Boolean(b && (a || b)); // quiet (&& inside Boolean)
const r4 = a || b;                 // reports
const r5 = identity(a || b);       // reports (not a Boolean call)
  1. run biome lint test.ts. only r4 and r5 should report.

  2. flip the option to false and re-run. now r1, r2, r3 should report too.

things worth poking at for coverage:

  • ||= inside Boolean() (e.g. Boolean(x ||= y)) should be quiet when the option is on
  • the non-Boolean callee (identity(...)) should still report, to confirm it's keyed on the Boolean name and not just "any call"
  • new Boolean(a || b) still reports. i think that's right since it constructs an object rather than coercing, but worth a sanity check

Docs

the option is documented in the rule's rustdoc with invalid/valid examples and validated by rules_check. no website PR needed while the rule is in nursery.

- suppresses || and ||= when the value is boolean-coerced by an enclosing Boolean() call
- walks out through parens and logical parents, so chained and && cases inside Boolean() are covered too
- partially addresses biomejs#9232, follows on from biomejs#9974
@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b6d02d6

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 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

✅ Organic activity

No automation signals detected in the analyzed events.

View full analysis →

This is an automated analysis by AgentScan

@github-actions github-actions Bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5988df2d-de76-4bda-a5fb-6de16a85e3e6

📥 Commits

Reviewing files that changed from the base of the PR and between 07d5e45 and b6d02d6.

⛔ Files ignored due to path filters (4)
  • crates/biome_js_analyze/tests/specs/nursery/useNullishCoalescing/ignoreBooleanCoercionDisabled.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useNullishCoalescing/ignoreBooleanCoercionEnabled.ts.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (7)
  • .changeset/add-ignore-boolean-coercion.md
  • crates/biome_js_analyze/src/lint/nursery/use_nullish_coalescing.rs
  • crates/biome_js_analyze/tests/specs/nursery/useNullishCoalescing/ignoreBooleanCoercionDisabled.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useNullishCoalescing/ignoreBooleanCoercionDisabled.ts
  • crates/biome_js_analyze/tests/specs/nursery/useNullishCoalescing/ignoreBooleanCoercionEnabled.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useNullishCoalescing/ignoreBooleanCoercionEnabled.ts
  • crates/biome_rule_options/src/use_nullish_coalescing.rs

Walkthrough

This PR adds a new ignoreBooleanCoercion option to the useNullishCoalescing linter rule. When enabled, the rule suppresses diagnostics for || and ||= operators that appear inside a Boolean() call, recognizing intentional boolean coercion. The changes include the options schema definition, AST traversal logic to detect Boolean(...) context, early-exit guards in both logical-or and logical-or-assignment rule handlers, comprehensive test fixtures for both enabled and disabled configurations, and a changeset documenting the release.

Possibly related issues

  • #9842: Requests semantic resolution of the Boolean callee to distinguish global built-ins from shadowed identifiers, building on the detection logic introduced here.

Possibly related PRs

  • biomejs/biome#9974: Modifies the same useNullishCoalescing rule handlers with a similar option-gated early-exit pattern for ignoreMixedLogicalExpressions, suggesting a shared pattern for rule refinement.

Suggested labels

A-Linter, L-JavaScript

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding the ignoreBooleanCoercion option to the useNullishCoalescing linter rule.
Description check ✅ Passed The description clearly relates to the changeset, detailing the new option's purpose, implementation approach, test coverage, and manual verification steps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codspeed-hq

codspeed-hq Bot commented Jun 9, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 196 skipped benchmarks1


Comparing pkallos:pk/use-nullish-coalescing-ignore-boolean-coercion (b6d02d6) with main (a4a294c)

Open in CodSpeed

Footnotes

  1. 196 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant