Skip to content

Conversation

arendjr
Copy link
Contributor

@arendjr arendjr commented Sep 15, 2025

Summary

Added nursery rule noUnusedExpressions to flag expressions used as a statement that is neither an assignment nor a function call. See #7364

The rule is a port of the no-unused-expressions rule from ESLint. No options have been implemented yet. The only difference is that the ESLint rule has enforceForJSX by default set to false, while I opted to set it to true by default. I couldn't think of any reason not to enable it.

Invalid examples

f // intended to call `f()` instead
function foo() {
    0 // intended to `return 0` instead
}

Valid examples

f()
function foo() {
    return 0;
}

Test Plan

Tests added.

Docs

Rule documentation is included in the rule itself.

@arendjr arendjr requested review from a team September 15, 2025 14:41
Copy link

changeset-bot bot commented Sep 15, 2025

🦋 Changeset detected

Latest commit: 3407340

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-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Sep 15, 2025
@github-actions github-actions bot added the A-CLI Area: CLI label Sep 15, 2025
Copy link
Contributor

coderabbitai bot commented Sep 15, 2025

Walkthrough

Adds a new nursery lint rule noUnusedExpressions to biome_js_analyze that flags standalone expression statements unless they are whitelisted (e.g., function calls, assignments, certain directives). Implements rule metadata, analysis logic (directive prologue detection, TS wrapper unwrapping, recursive expression checks) and diagnostics. Introduces NoUnusedExpressionsOptions and exposes it via biome_rule_options. Adds tests: invalid cases, valid cases, and valid directive-prologue cases. Includes a changeset entry and documentation link.

Suggested reviewers

  • ematipico
  • siketyan
  • dyc3

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat(linter): implement noUnusedExpressions" is concise, follows conventional commit style, and accurately captures the primary change (adding the noUnusedExpressions lint rule), so it effectively summarises the changeset.
Description Check ✅ Passed The description is on-topic and directly matches the changeset: it explains the new rule, notes the behavioural difference from ESLint, provides examples, and mentions tests and documentation, meeting the lenient requirement for this check.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

Copy link
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: 0

🧹 Nitpick comments (2)
.changeset/unused-underlings-underperform.md (1)

5-5: Use past tense in changeset description.

Per the coding guidelines, changeset descriptions should use past tense for what you did.

-Added nursery rule [`noUnusedExpressions`](https://biomejs.dev/linter/rules/no-unused-expressions/) to flag expressions used as a statement that is neither an assignment nor a function call.
+Added nursery rule [`noUnusedExpressions`](https://biomejs.dev/linter/rules/no-unused-expressions/) that flags expressions used as a statement that is neither an assignment nor a function call.
crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (1)

206-229: Consider extracting directive-checking logic for reuse.

The directive detection logic here could potentially be useful for other rules. Consider moving it to a shared utility module if other rules need similar functionality.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8c64f8 and 9f01881.

⛔ Files ignored due to path filters (8)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/src/lint/nursery.rs is excluded by !**/nursery.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/validDirectives.js.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/unused-underlings-underperform.md (1 hunks)
  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx (1 hunks)
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/validDirectives.js (1 hunks)
  • crates/biome_rule_options/src/lib.rs (1 hunks)
  • crates/biome_rule_options/src/no_unused_expressions.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_unused_expressions.rs
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/validDirectives.js
  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format all Rust source files before committing (just f)

Files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_unused_expressions.rs
  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changeset files, only use #### or ##### headers; avoid other header levels
Changeset descriptions should use past tense for what you did (e.g., "Added...")
Describe current Biome behavior in present tense within changesets (e.g., "Biome now supports...")
For bug fixes in changesets, start with a link to the issue (e.g., "Fixed #1234: ...")
When referencing rules or assists in changesets, include links to their documentation pages
Include a minimal code block in the changeset when applicable to demonstrate the change
End every sentence in the changeset description with a period

Files:

  • .changeset/unused-underlings-underperform.md
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/validDirectives.js
  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx
**/tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/validDirectives.js
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx
🧠 Learnings (8)
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Define per-rule options types in `biome_rule_options` crate (one file per rule, e.g., `lib/use_my_rule.rs`)

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Options types must implement serialization/deserialization and schema support using derives: `Serialize`, `Deserialize`, `Deserializable`, and `#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]`

Applied to files:

  • crates/biome_rule_options/src/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : In declare_lint_rule! macros, set `version: "next"` for new or updated rules

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/lib/src/{lint,assist}/**/*.rs : When banning globals (e.g., `noConsoleLog`), check the semantic model to avoid false positives from locally shadowed bindings

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : When deprecating a rule, add `deprecated: "<reason>"` to `declare_lint_rule!`

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Follow rule naming conventions: use `no<Concept>` to forbid and `use<Concept>` to mandate; prefer consistent prefixes (e.g., `noDuplicate<Concept>`, `useConsistent<Concept>`)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Code blocks in rule docs must specify language; invalid snippets require `expect_diagnostic`; use `options`/`full_options`/`use_options` markers as appropriate

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/**/tests/specs/**/*.jsonc : Snapshot test `.jsonc` files must contain an array of code snippets (strings); these run in script mode (no ESM syntax)

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx
  • crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (2)
crates/biome_analyze/src/rule.rs (1)
  • same (241-246)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (142-151)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Check JS Files
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test Node.js API
  • GitHub Check: autofix
🔇 Additional comments (7)
crates/biome_rule_options/src/lib.rs (1)

203-203: LGTM!

The module export is correctly placed in alphabetical order.

crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/validDirectives.js (1)

5-5: LGTM!

Good test coverage for directive prologues. The test correctly verifies that string literals at the beginning of a script are treated as directives and don't trigger the rule.

crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/valid.tsx (1)

1-26: LGTM!

Comprehensive test coverage for valid cases including assignments, function calls, delete operations, void expressions, directives, and JSX elements.

crates/biome_js_analyze/tests/specs/nursery/noUnusedExpressions/invalid.tsx (1)

1-62: LGTM!

Excellent test coverage for invalid cases, properly covering all the edge cases mentioned in the rule documentation.

crates/biome_rule_options/src/no_unused_expressions.rs (1)

1-6: LGTM!

The options struct follows all the required patterns with proper derives and serde attributes. Good foundation for future rule options.

crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (2)

14-167: LGTM!

Well-documented rule with comprehensive examples covering both invalid and valid cases, plus clear explanation of directive handling.


252-301: Solid pattern matching for expression types.

The exhaustive match on expression types with clear categorisation of allowed vs disallowed expressions is well-structured. The recursive handling of TypeScript wrapper expressions is particularly neat.

Copy link

codspeed-hq bot commented Sep 15, 2025

CodSpeed Performance Report

Merging #7511 will not alter performance

Comparing arendjr:no-unused-expressions (3407340) with main (002cded)1

Summary

✅ 133 untouched

Footnotes

  1. No successful run was found on main (a8c64f8) during the generation of this report, so 002cded was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copy link
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_js_analyze/src/lint/nursery/no_unused_expressions.rs (1)

204-206: Tiny docs nit: spelling.

“preceeded” → “preceded”.

Apply this diff:

-/// preceeded by any non-directive nodes.
+/// preceded by any non-directive nodes.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f01881 and 3407340.

⛔ Files ignored due to path filters (4)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs 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 (1)
  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format all Rust source files before committing (just f)

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
🧠 Learnings (7)
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : In declare_lint_rule! macros, set `version: "next"` for new or updated rules

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/lib/src/{lint,assist}/**/*.rs : When banning globals (e.g., `noConsoleLog`), check the semantic model to avoid false positives from locally shadowed bindings

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Code blocks in rule docs must specify language; invalid snippets require `expect_diagnostic`; use `options`/`full_options`/`use_options` markers as appropriate

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Follow rule naming conventions: use `no<Concept>` to forbid and `use<Concept>` to mandate; prefer consistent prefixes (e.g., `noDuplicate<Concept>`, `useConsistent<Concept>`)

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : When deprecating a rule, add `deprecated: "<reason>"` to `declare_lint_rule!`

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Set the `language` field in `declare_lint_rule!` to the primary language (`js`, `jsx`, `ts`, or `tsx`) the rule targets

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Recommended rules with domains are enabled only when users enable the matching domains; use `domains` metadata judiciously

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (2)
crates/biome_analyze/src/rule.rs (3)
  • sources (569-572)
  • same (241-246)
  • recommended (554-557)
crates/biome_rowan/src/ast/mod.rs (1)
  • cast_ref (142-151)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test Node.js API
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: autofix
  • GitHub Check: Check JS Files
🔇 Additional comments (1)
crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs (1)

160-166: Rule metadata looks spot on.

version: "next", sources: …same(), and recommended: false all align with the project conventions.

Comment on lines +231 to +241
/// Determines if a node exists at the top-level based on its `parent` node.
fn is_at_top_level(parent: &JsSyntaxNode) -> bool {
AnyJsRoot::can_cast(parent.kind())
|| TsModuleBlock::can_cast(parent.kind())
|| JsBlockStatement::cast_ref(parent).is_some_and(|block| {
block
.syntax()
.parent()
.is_some_and(|parent: JsSyntaxNode| AnyJsFunction::can_cast(parent.kind()))
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don’t treat TS namespace/module blocks as directive contexts.

Directive prologues exist only for Script/Module roots and Function bodies. Allowing them inside TsModuleBlock deviates from JS semantics and can hide unused string expressions in namespace/module bodies.

Apply this diff:

 fn is_at_top_level(parent: &JsSyntaxNode) -> bool {
     AnyJsRoot::can_cast(parent.kind())
-        || TsModuleBlock::can_cast(parent.kind())
         || JsBlockStatement::cast_ref(parent).is_some_and(|block| {
             block
                 .syntax()
                 .parent()
                 .is_some_and(|parent: JsSyntaxNode| AnyJsFunction::can_cast(parent.kind()))
         })
 }
📝 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
/// Determines if a node exists at the top-level based on its `parent` node.
fn is_at_top_level(parent: &JsSyntaxNode) -> bool {
AnyJsRoot::can_cast(parent.kind())
|| TsModuleBlock::can_cast(parent.kind())
|| JsBlockStatement::cast_ref(parent).is_some_and(|block| {
block
.syntax()
.parent()
.is_some_and(|parent: JsSyntaxNode| AnyJsFunction::can_cast(parent.kind()))
})
}
/// Determines if a node exists at the top-level based on its `parent` node.
fn is_at_top_level(parent: &JsSyntaxNode) -> bool {
AnyJsRoot::can_cast(parent.kind())
|| JsBlockStatement::cast_ref(parent).is_some_and(|block| {
block
.syntax()
.parent()
.is_some_and(|parent: JsSyntaxNode| AnyJsFunction::can_cast(parent.kind()))
})
}
🤖 Prompt for AI Agents
In crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs around
lines 231-241, the current is_at_top_level function incorrectly treats
TsModuleBlock as a directive-context; remove the
TsModuleBlock::can_cast(parent.kind()) check so only AnyJsRoot and function-body
block checks count as top-level/directive contexts, ensuring namespace/module
bodies are not treated as directive prologues.

@arendjr arendjr merged commit a0039fd into biomejs:main Sep 15, 2025
31 checks passed
@github-actions github-actions bot mentioned this pull request Sep 15, 2025
TheAlexLichter pushed a commit to TheAlexLichter/biome that referenced this pull request Sep 18, 2025
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
kedevked pushed a commit to kedevked/biome that referenced this pull request Sep 22, 2025
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-JavaScript Language: JavaScript and super languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant