Skip to content

feat(lint): rule useExplicitReturnType#9429

Open
ematipico wants to merge 6 commits intomainfrom
feat/use-explicit-return-type
Open

feat(lint): rule useExplicitReturnType#9429
ematipico wants to merge 6 commits intomainfrom
feat/use-explicit-return-type

Conversation

@ematipico
Copy link
Member

Summary

Part of #2017

We eventually decided to split the original function into specialised functions, same as typescript eslint. This PR starts with useExplicitReturnType

I used AI to extract the logic from what we have to day, and copy over the tests from typescript eslint.

Test Plan

Added new tests

Docs

Part of the rule

@changeset-bot
Copy link

changeset-bot bot commented Mar 10, 2026

🦋 Changeset detected

Latest commit: b898d6a

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 Mar 10, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 10, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 156 skipped benchmarks1


Comparing feat/use-explicit-return-type (b898d6a) with main (61e2a02)

Open in CodSpeed

Footnotes

  1. 156 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.

@github-actions github-actions bot added the A-CLI Area: CLI label Mar 10, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

Walkthrough

Adds a new nursery lint rule useExplicitReturnType for TypeScript (skipping .d.ts) that reports functions, methods and getters lacking explicit return types. Implements the rule in Rust with an AST union for function-like nodes, diagnostic emission, and options (allow_iifes, allowed_names, allow_expressions). Introduces the corresponding options struct, exposes the rule and option module in public crates, and adds extensive test fixtures (valid/invalid cases and options files) covering expressions, IIFEs, allowed names and many edge cases.

Suggested reviewers

  • arendjr
  • dyc3
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(lint): rule useExplicitReturnType' clearly and concisely summarises the primary change: introducing a new lint rule for enforcing explicit return types.
Description check ✅ Passed The description adequately relates to the changeset, explaining that this PR implements the useExplicitReturnType rule as part of issue #2017, with tests extracted from typescript-eslint.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/use-explicit-return-type

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: 6

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

6-18: Add a rustdoc summary to the options type.

The fields are documented, but the public UseExplicitReturnTypeOptions type itself is not. A one-liner here keeps the generated docs from starting mid-sentence.

📝 Suggested tweak
 #[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize, Merge)]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 #[serde(rename_all = "camelCase", deny_unknown_fields, default)]
+/// Options for the `useExplicitReturnType` rule.
 pub struct UseExplicitReturnTypeOptions {

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/use_explicit_return_type.rs` around lines 6 -
18, Add a one-line rustdoc summary for the public struct
UseExplicitReturnTypeOptions by placing a short descriptive comment (/// ...)
immediately above the struct declaration; ensure it succinctly describes the
purpose of the options type (e.g., "Options for the `use_explicit_return_type`
rule") so generated docs have a proper summary and follow the project's inline
rustdoc guideline.
🤖 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/calm-impalas-stare.md:
- Around line 5-13: The changeset line mentioning internal extraction and the
misspelled word "sunsuet" exposes implementation details and should be removed;
edit the .changeset text to keep only a short, user-facing description (1–3
sentences) of the new lint rule useExplicitReturnType and its impact plus the
example snippet, and drop any mention of the previous rule useExplicitType or
internal migration details so the note reads as a concise release note for
users.

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs`:
- Around line 191-205: Docs and implementation disagree: the allowExpressions
option is meant to skip function expressions but current code still flags
variable-assigned functions and never checks object members against the option.
Update the rule so that the allow_expressions config (often accessed as
allowExpressions or allow_expressions) is consulted in the branches that handle
ArrowFunctionExpression and FunctionExpression (e.g., the handlers/visitors
named visit_arrow_function / visit_function_expression or
check_assigned_function) and also in the object-member handling (e.g.,
visit_property / check_object_member / object_literal branch) so that when
allow_expressions == true those expression-based functions are skipped, and when
false they are still enforced; ensure the option name used matches the config
struct/field (e.g., UseExplicitReturnType::allow_expressions) and add tests
covering const foo = () => {}, const foo = function(){}, and object members to
validate behavior.
- Around line 265-267: The metadata incorrectly uses
RuleSource::EslintTypeScript("explicit-function-return-type").same() even though
this rule narrows the typescript-eslint option surface; replace .same() with
.inspired() on the RuleSource::EslintTypeScript("explicit-function-return-type")
entry so the rule is marked as inspired (not identical) to the upstream
eslint-typescript rule.

In
`@crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.ts`:
- Around line 14-17: The current test uses a duplicated binding "let [test,
test]" which causes a parser/binding error instead of exercising the
allowedNames path; replace the duplicated identifier in the array destructuring
with two distinct identifiers and make sure exactly one of those identifiers is
not in the allowedNames list so the fixture stays parseable and triggers the
allowedNames check (update the array pattern in the let declaration that
currently reads "let [test, test]" to use two unique names, leaving one
intentionally unlisted).

In
`@crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts`:
- Around line 12-15: The file contains two top-level default exports ("export
default () => {}" and "export default function () {}") in the same module which
causes an unrelated module-level diagnostic; split them so each snippet/module
contains only one default export — move "export default () => {}" and "export
default function () {}" into separate test snippets/files (or separate code
blocks) so each test focuses on the explicit-return-type rule for a single
export.

In
`@crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.ts`:
- Around line 22-27: The setter in class Test (`set prop() {}`) is syntactically
invalid because JS setters require exactly one parameter; update the setter for
the Test class (the `set prop` method) to accept a single parameter (e.g.,
`value`) so the fixture remains valid and does not produce unrelated parser
diagnostics that pollute the useExplicitReturnType snapshot test.

---

Nitpick comments:
In `@crates/biome_rule_options/src/use_explicit_return_type.rs`:
- Around line 6-18: Add a one-line rustdoc summary for the public struct
UseExplicitReturnTypeOptions by placing a short descriptive comment (/// ...)
immediately above the struct declaration; ensure it succinctly describes the
purpose of the options type (e.g., "Options for the `use_explicit_return_type`
rule") so generated docs have a proper summary and follow the project's inline
rustdoc guideline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2c42d2fd-9939-45b1-b9d5-f49301e66aff

📥 Commits

Reviewing files that changed from the base of the PR and between 1555948 and bb20a0e.

⛔ Files ignored due to path filters (11)
  • 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/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/valid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowIifes/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowIifes/valid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/valid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/valid.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/valid.ts.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (19)
  • .changeset/calm-impalas-stare.md
  • crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/valid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowIifes/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowIifes/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowIifes/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowIifes/valid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/valid.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/valid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/valid.js
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/valid.ts
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/use_explicit_return_type.rs

Comment on lines +191 to +205
/// ### `allowExpressions`
///
/// When set to `true`, only function declarations and class methods are checked.
/// Function expressions (assigned to variables, passed as arguments, etc.) are allowed
/// without return types.
///
/// Default: `false`
///
/// ```json,options
/// {
/// "options": {
/// "allowExpressions": true
/// }
/// }
/// ```
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 | 🟠 Major

allowExpressions and the implementation are pulling in different directions.

Lines 193-195 say only function declarations and class methods stay checked when this option is true, but the variable-assigned path below still flags const foo = () => {} / const foo = function () {}, and the object-member branches never consult the option at all. Please reconcile the docs and behaviour before this goes user-facing.

Also applies to: 320-345, 831-867

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

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 191 - 205, Docs and implementation disagree: the allowExpressions option
is meant to skip function expressions but current code still flags
variable-assigned functions and never checks object members against the option.
Update the rule so that the allow_expressions config (often accessed as
allowExpressions or allow_expressions) is consulted in the branches that handle
ArrowFunctionExpression and FunctionExpression (e.g., the handlers/visitors
named visit_arrow_function / visit_function_expression or
check_assigned_function) and also in the object-member handling (e.g.,
visit_property / check_object_member / object_literal branch) so that when
allow_expressions == true those expression-based functions are skipped, and when
false they are still enforced; ensure the option name used matches the config
struct/field (e.g., UseExplicitReturnType::allow_expressions) and add tests
covering const foo = () => {}, const foo = function(){}, and object members to
validate behavior.

Comment on lines +12 to +15
// Export default without return type
export default () => {};
export default function () {}

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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts | head -20

Repository: biomejs/biome

Length of output: 691


🏁 Script executed:

# Check other useExplicitReturnType test fixtures
find crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType -name "invalid.ts" -o -name "valid.ts" | head -10

Repository: biomejs/biome

Length of output: 746


🏁 Script executed:

# Search for other multiple export default patterns in test files
rg "export default.*\n.*export default" crates/biome_js_analyze/tests/specs/nursery/ -A 1 | head -40

Repository: biomejs/biome

Length of output: 248


🏁 Script executed:

# Check the main invalid.ts file to see full test case coverage
cat -n crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.ts

Repository: biomejs/biome

Length of output: 4060


🏁 Script executed:

# Search for multiple export default patterns across test fixtures
rg "export default" crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/ -U -A 1 | grep -E "^[^:]+:\s*(export default|--)" | head -30

Repository: biomejs/biome

Length of output: 803


Separate the default exports into different snippets.

Lines 13–14 have two default exports in the same module, which violates module semantics. This will trigger an unrelated module diagnostic in the snapshot, muddying what the rule actually catches. Split them to keep the test focused.

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

In
`@crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts`
around lines 12 - 15, The file contains two top-level default exports ("export
default () => {}" and "export default function () {}") in the same module which
causes an unrelated module-level diagnostic; split them so each snippet/module
contains only one default export — move "export default () => {}" and "export
default function () {}" into separate test snippets/files (or separate code
blocks) so each test focuses on the explicit-return-type rule for a single
export.

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: 1

🧹 Nitpick comments (2)
crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs (2)

78-79: Documentation wording is misleading.

The phrase "We only check whether the first statement is a function return" doesn't match the implementation. The all_returns_are_functions helper (lines 542-556) checks that all return statements in the body return function expressions, not just the first one. Consider rephrasing to clarify the actual behaviour.

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

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 78 - 79, The doc comment is misleading: instead of saying "We only check
whether the first statement is a function return", update the wording to reflect
the actual behavior implemented by the helper all_returns_are_functions (which
inspects all return statements in the function body to ensure they return
function expressions). Edit the comment near the higher-order function example
to state that the lint verifies every return in the body is a function
expression (referencing the all_returns_are_functions helper) rather than only
checking the first statement.

512-516: Consider handling alternative IIFE patterns.

This only detects (function(){})(). Patterns like !function(){}(), void function(){}(), etc., won't be recognised. These are less common but still valid IIFEs that users might expect allowIifes to cover.

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

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 512 - 516, The is_iife detection currently only checks for a
JsParenthesizedExpression followed by a JsCallExpression, so it misses IIFEs
wrapped by unary operators (e.g., !function(){}, void function(){},
+function(){}). Update is_iife (function is_iife and its use of AnyJsFunction,
JsParenthesizedExpression, JsCallExpression) to also consider when the
function's parent is a JsUnaryExpression (check for operators like !, void, +,
-) possibly wrapped in a JsParenthesizedExpression, and then has a
JsCallExpression as an ancestor; in short, extend the parent-chain checks to
include JsUnaryExpression (and optional parenthesized wrapper) before the call
so patterns like !function(){}() and void function(){}() are recognized by
allowIifes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs`:
- Around line 572-604: collect_returns_from_stmt currently only recurses into
if/blocks/switches and therefore misses return statements inside
try/catch/finally and loop constructs; update collect_returns_from_stmt to match
and handle AnyJsTryStatement (descend into its try block, any catch clause
bodies, and finally block via collect_returns_from_stmts) and to handle loop
node kinds (AnyJsForStatement, AnyJsForInStatement, AnyJsForOfStatement,
AnyJsWhileStatement, AnyJsDoWhileStatement) by extracting each loop's body and
calling collect_returns_from_stmt or collect_returns_from_stmts as appropriate;
keep using the existing helper collect_returns_from_stmts and the function name
collect_returns_from_stmt to locate where to add these new match arms.

---

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs`:
- Around line 78-79: The doc comment is misleading: instead of saying "We only
check whether the first statement is a function return", update the wording to
reflect the actual behavior implemented by the helper all_returns_are_functions
(which inspects all return statements in the function body to ensure they return
function expressions). Edit the comment near the higher-order function example
to state that the lint verifies every return in the body is a function
expression (referencing the all_returns_are_functions helper) rather than only
checking the first statement.
- Around line 512-516: The is_iife detection currently only checks for a
JsParenthesizedExpression followed by a JsCallExpression, so it misses IIFEs
wrapped by unary operators (e.g., !function(){}, void function(){},
+function(){}). Update is_iife (function is_iife and its use of AnyJsFunction,
JsParenthesizedExpression, JsCallExpression) to also consider when the
function's parent is a JsUnaryExpression (check for operators like !, void, +,
-) possibly wrapped in a JsParenthesizedExpression, and then has a
JsCallExpression as an ancestor; in short, extend the parent-chain checks to
include JsUnaryExpression (and optional parenthesized wrapper) before the call
so patterns like !function(){}() and void function(){}() are recognized by
allowIifes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2ae0aaa7-1a6c-43ae-85c6-7ee4982fecaa

📥 Commits

Reviewing files that changed from the base of the PR and between bb20a0e and a739a65.

⛔ Files ignored due to path filters (6)
  • 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_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.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 (5)
  • .changeset/calm-impalas-stare.md
  • crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowExpressions/invalid.ts
  • .changeset/calm-impalas-stare.md
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/allowedNames/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExplicitReturnType/invalid.ts

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: 1

♻️ Duplicate comments (2)
crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs (2)

867-906: ⚠️ Potential issue | 🟠 Major

allowExpressions documentation/implementation mismatch persists.

The documentation (lines 183-185) states: "only function declarations and class methods are checked. Function expressions... are allowed without return types."

But the implementation (lines 890-905) still requires return types for:

  • const foo = () => {} (variable-assigned)
  • class { public a = () => {} } (class property)
  • export default () => {} (export-default)

The inline comments explain this is intentional, but it contradicts the user-facing docs. Either update the documentation to reflect the actual behaviour, or adjust the implementation.

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

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 867 - 906, The code enforces that when allow_expressions is true,
variable-assigned functions, class property functions, and export-default
expressions still require return types (logic around is_function_expression,
is_variable_assigned using
JsInitializerClause/JsVariableDeclarator/JsPropertyClassMember, and
is_export_default matching AnyJsFunction::JsFunctionExportDefaultDeclaration),
but the user-facing docs claim only function declarations and class methods are
checked; update the documentation to accurately reflect the implementation:
state that allowExpressions permits bare expression
callbacks/parenthesized/IIFEs but still requires explicit return types for
variable-assigned functions (const foo = ...), class property arrow/function
members, and export default function expressions, and include the same
examples/comments from the code so docs and implementation match.

310-335: ⚠️ Potential issue | 🟡 Minor

allowExpressions not checked for object methods/getters.

The allow_expressions option is consulted for AnyJsFunction via handle_any_function, but object methods (JsMethodObjectMember) and object getters (JsGetterObjectMember) don't check this option. If allowExpressions: true, users would expect { foo() { return 1; } } to be allowed without a return type when passed as an argument or used in an expression context.

Consider adding the allow_expressions check here, or document that it only applies to function expressions.

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

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 310 - 335, The object method/getter branches
(AnyFunctionLikeWithReturnType::JsMethodObjectMember and ::JsGetterObjectMember)
don't honor the allow_expressions option; mirror the logic used in
handle_any_function by checking options.allow_expressions and, when true and the
member is being used as an expression/context (e.g., via
is_member_inside_call_argument or a similar expression-detection helper), return
None so no lint is produced. Update the branches that reference method, getter,
get_method_object_member_name, get_getter_object_member_name and
is_member_inside_call_argument to early-return when allow_expressions is enabled
and the member is in an expression context.
🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs (1)

711-726: Same parenthesis issue as is_function_used_in_argument.

The check at line 719 only looks at the object expression's immediate parent. Consider unwrapping parentheses here too for consistency.

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

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 711 - 726, is_member_inside_call_argument currently checks only the
immediate parent of a JsObjectExpression for JS_CALL_ARGUMENT_LIST; update it to
unwrap/skip any intermediate parenthesized expressions (like
is_function_used_in_argument does) before checking the parent kind. Locate the
function is_member_inside_call_argument and, for each ancestor that is a
JsObjectExpression, walk up parents while
JsParenthesizedExpression::can_cast(parent.kind()) to reach the real enclosing
node, then test that node.kind() == JsSyntaxKind::JS_CALL_ARGUMENT_LIST
(referencing JsObjectExpression, JsParenthesizedExpression::can_cast, and
JS_CALL_ARGUMENT_LIST) so calls wrapped in parentheses are detected correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs`:
- Around line 399-404: The function is_function_used_in_argument currently only
inspects the immediate parent and misses cases where the function is wrapped in
JsParenthesizedExpression; update is_function_used_in_argument (working on
AnyJsFunction) to walk up ancestors/unwrap parenthesized nodes until a
non-parenthesized ancestor is reached, then check if that ancestor's kind()
matches JsSyntaxKind::JS_CALL_ARGUMENT_LIST (or return false if no such
ancestor), so calls like foo(((() => {}))) are correctly detected as call
arguments.

---

Duplicate comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs`:
- Around line 867-906: The code enforces that when allow_expressions is true,
variable-assigned functions, class property functions, and export-default
expressions still require return types (logic around is_function_expression,
is_variable_assigned using
JsInitializerClause/JsVariableDeclarator/JsPropertyClassMember, and
is_export_default matching AnyJsFunction::JsFunctionExportDefaultDeclaration),
but the user-facing docs claim only function declarations and class methods are
checked; update the documentation to accurately reflect the implementation:
state that allowExpressions permits bare expression
callbacks/parenthesized/IIFEs but still requires explicit return types for
variable-assigned functions (const foo = ...), class property arrow/function
members, and export default function expressions, and include the same
examples/comments from the code so docs and implementation match.
- Around line 310-335: The object method/getter branches
(AnyFunctionLikeWithReturnType::JsMethodObjectMember and ::JsGetterObjectMember)
don't honor the allow_expressions option; mirror the logic used in
handle_any_function by checking options.allow_expressions and, when true and the
member is being used as an expression/context (e.g., via
is_member_inside_call_argument or a similar expression-detection helper), return
None so no lint is produced. Update the branches that reference method, getter,
get_method_object_member_name, get_getter_object_member_name and
is_member_inside_call_argument to early-return when allow_expressions is enabled
and the member is in an expression context.

---

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs`:
- Around line 711-726: is_member_inside_call_argument currently checks only the
immediate parent of a JsObjectExpression for JS_CALL_ARGUMENT_LIST; update it to
unwrap/skip any intermediate parenthesized expressions (like
is_function_used_in_argument does) before checking the parent kind. Locate the
function is_member_inside_call_argument and, for each ancestor that is a
JsObjectExpression, walk up parents while
JsParenthesizedExpression::can_cast(parent.kind()) to reach the real enclosing
node, then test that node.kind() == JsSyntaxKind::JS_CALL_ARGUMENT_LIST
(referencing JsObjectExpression, JsParenthesizedExpression::can_cast, and
JS_CALL_ARGUMENT_LIST) so calls wrapped in parentheses are detected correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8531421c-090d-4641-af96-aced79b8bd85

📥 Commits

Reviewing files that changed from the base of the PR and between a739a65 and 824f5d7.

📒 Files selected for processing (2)
  • crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs
  • crates/biome_rule_options/src/use_explicit_return_type.rs

Comment on lines +399 to +404
fn is_function_used_in_argument(func: &AnyJsFunction) -> bool {
matches!(
func.syntax().parent().kind(),
Some(JsSyntaxKind::JS_CALL_ARGUMENT_LIST)
)
}
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 | 🟡 Minor

Parenthesised callbacks may not be detected.

is_function_used_in_argument only checks the immediate parent. A function wrapped in parentheses like foo(((() => {}))) won't be detected as a callback because the parent is JsParenthesizedExpression, not JS_CALL_ARGUMENT_LIST.

Consider unwrapping parentheses or walking up ancestors until a non-parenthesised node is found.

Possible approach
 fn is_function_used_in_argument(func: &AnyJsFunction) -> bool {
-    matches!(
-        func.syntax().parent().kind(),
-        Some(JsSyntaxKind::JS_CALL_ARGUMENT_LIST)
-    )
+    let mut current = func.syntax().parent();
+    while let Some(node) = current {
+        if node.kind() == JsSyntaxKind::JS_CALL_ARGUMENT_LIST {
+            return true;
+        }
+        if node.kind() != JsSyntaxKind::JS_PARENTHESIZED_EXPRESSION {
+            break;
+        }
+        current = node.parent();
+    }
+    false
 }
📝 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
fn is_function_used_in_argument(func: &AnyJsFunction) -> bool {
matches!(
func.syntax().parent().kind(),
Some(JsSyntaxKind::JS_CALL_ARGUMENT_LIST)
)
}
fn is_function_used_in_argument(func: &AnyJsFunction) -> bool {
let mut current = func.syntax().parent();
while let Some(node) = current {
if node.kind() == JsSyntaxKind::JS_CALL_ARGUMENT_LIST {
return true;
}
if node.kind() != JsSyntaxKind::JS_PARENTHESIZED_EXPRESSION {
break;
}
current = node.parent();
}
false
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_explicit_return_type.rs` around
lines 399 - 404, The function is_function_used_in_argument currently only
inspects the immediate parent and misses cases where the function is wrapped in
JsParenthesizedExpression; update is_function_used_in_argument (working on
AnyJsFunction) to walk up ancestors/unwrap parenthesized nodes until a
non-parenthesized ancestor is reached, then check if that ancestor's kind()
matches JsSyntaxKind::JS_CALL_ARGUMENT_LIST (or return false if no such
ancestor), so calls like foo(((() => {}))) are correctly detected as call
arguments.

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