Repository: biomejs/biome (language: rust)

Issue:
🐛 noConsole not reporting when using console in arrow function
### Environment information

```block
CLI:
  Version:                      1.9.4
  Color support:                true

Platform:
  CPU Architecture:             aarch64
  OS:                           macos

Environment:
  BIOME_LOG_PATH:               unset
  BIOME_LOG_PREFIX_NAME:        unset
  BIOME_CONFIG_PATH:            unset
  NO_COLOR:                     unset
  TERM:                         "xterm-256color"
  JS_RUNTIME_VERSION:           "v22.13.0"
  JS_RUNTIME_NAME:              "node"
  NODE_PACKAGE_MANAGER:         "npm/10.9.2"

Biome Configuration:
  Status:                       Loaded successfully
  Formatter disabled:           false
  Linter disabled:              false
  Organize imports disabled:    false
  VCS disabled:                 false

Workspace:
  Open Documents:               0
```

### What happened?

Something as simple as 
```ts
[].forEach(() => console.log("test"))
```
doesn't trigger the noConsole rule.

https://biomejs.dev/playground/?lintRules=all&code=WwBdAC4AZgBvAHIARQBhAGMAaAAoACgAKQAgAD0APgAgAGMAbwBuAHMAbwBsAGUALgBsAG8AZwAoACIAdABlAHMAdAAiACkAKQAKAAoAYwBvAG4AcwB0ACAAeAAgAD0AIAAoACkAIAA9AD4AIABjAG8AbgBzAG8AbABlAC4AbABvAGcAKAAiAHQAZQBzAHQAIgApAA%3D%3D

### Expected result

It creates a diagnostic for the noConsole rule

### Code of Conduct

- [x] I agree to follow Biome's Code of Conduct


Discussion / hints:

Fix patch:
diff --git a/.changeset/lemon-flies-jam.md b/.changeset/lemon-flies-jam.md
new file mode 100644
index 000000000000..6daba88a91ca
--- /dev/null
+++ b/.changeset/lemon-flies-jam.md
@@ -0,0 +1,5 @@
+---
+"@biomejs/biome": patch
+---
+
+Fix [#5053](https://github.com/biomejs/biome/issues/5053), now the rule correctly handles `console.log` inside arrow function expressions.
diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_console.rs b/crates/biome_js_analyze/src/lint/suspicious/no_console.rs
index bc2c7e053fbc..859d1208e4b8 100644
--- a/crates/biome_js_analyze/src/lint/suspicious/no_console.rs
+++ b/crates/biome_js_analyze/src/lint/suspicious/no_console.rs
@@ -4,8 +4,10 @@ use biome_analyze::{
 };
 use biome_console::markup;
 use biome_deserialize_macros::Deserializable;
+use biome_js_factory::make::{js_directive_list, js_function_body, js_statement_list, token};
 use biome_js_syntax::{
-    global_identifier, AnyJsMemberExpression, JsCallExpression, JsExpressionStatement,
+    global_identifier, AnyJsMemberExpression, JsArrowFunctionExpression, JsCallExpression,
+    JsExpressionStatement, T,
 };
 use biome_rowan::{AstNode, BatchMutationExt};
 
@@ -85,11 +87,13 @@ impl Rule for NoConsole {
 
     fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
         let node = ctx.query();
-        let node = JsExpressionStatement::cast(node.syntax().parent()?)?;
+        let parent = node.clone().syntax().parent()?;
+        let range = JsExpressionStatement::cast_ref(&parent)
+            .map_or(node.range(), |node| node.syntax().text_trimmed_range());
         Some(
             RuleDiagnostic::new(
                 rule_category!(),
-                node.syntax().text_trimmed_range(),
+                range,
                 markup! {
                     "Don't use "<Emphasis>"console"</Emphasis>"."
                 },
@@ -103,14 +107,23 @@ impl Rule for NoConsole {
     fn action(ctx: &RuleContext<Self>, _: &Self::State) -> Option<JsRuleAction> {
         let call_expression = ctx.query();
         let mut mutation = ctx.root().begin();
-        match JsExpressionStatement::cast(call_expression.syntax().parent()?) {
-            Some(stmt) if stmt.semicolon_token().is_some() => {
+        let parent = call_expression.syntax().parent()?;
+        if let Some(stmt) = JsExpressionStatement::cast(parent.clone()) {
+            if stmt.semicolon_token().is_some() {
                 mutation.remove_node(stmt);
-            }
-            _ => {
+            } else {
                 mutation.remove_node(call_expression.clone());
             }
+        } else if JsArrowFunctionExpression::cast(parent).is_some() {
+            let new_body = js_function_body(
+                token(T!['{']),
+                js_directive_list(vec![]),
+                js_statement_list(vec![]),
+                token(T!['}']),
+            );
+            mutation.replace_element(call_expression.clone().into(), new_body.into());
         }
+
         Some(JsRuleAction::new(
             ctx.metadata().action_category(ctx.category(), ctx.group()),
             ctx.metadata().applicability(),


Test patch:
diff --git a/crates/biome_js_analyze/tests/spec_tests.rs b/crates/biome_js_analyze/tests/spec_tests.rs
index 0dd9d0656075..c83004ef4957 100644
--- a/crates/biome_js_analyze/tests/spec_tests.rs
+++ b/crates/biome_js_analyze/tests/spec_tests.rs
@@ -250,7 +250,11 @@ fn check_code_action(
 
     // Checks that applying the text edits returned by the BatchMutation
     // returns the same code as printing the modified syntax tree
-    assert_eq!(new_tree.to_string(), output);
+    assert_eq!(
+        new_tree.to_string(),
+        output,
+        "Code action and syntax tree differ"
+    );
 
     if has_bogus_nodes_or_empty_slots(&new_tree) {
         panic!("modified tree has bogus nodes or empty slots:\n{new_tree:#?} \n\n {new_tree}")
diff --git a/crates/biome_js_analyze/tests/specs/suspicious/noConsole/issue_5053.js b/crates/biome_js_analyze/tests/specs/suspicious/noConsole/issue_5053.js
new file mode 100644
index 000000000000..87b4aff8022b
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/suspicious/noConsole/issue_5053.js
@@ -0,0 +1,2 @@
+const x = () => console.log("test");
+[].forEach(() => console.log("test"));
diff --git a/crates/biome_js_analyze/tests/specs/suspicious/noConsole/issue_5053.js.snap b/crates/biome_js_analyze/tests/specs/suspicious/noConsole/issue_5053.js.snap
new file mode 100644
index 000000000000..b65fe82a5dd3
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/suspicious/noConsole/issue_5053.js.snap
@@ -0,0 +1,56 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: issue_5053.js
+snapshot_kind: text
+---
+# Input
+```js
+const x = () => console.log("test");
+[].forEach(() => console.log("test"));
+
+```
+
+# Diagnostics
+```
+issue_5053.js:1:17 lint/suspicious/noConsole  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use console.
+  
+  > 1 │ const x = () => console.log("test");
+      │                 ^^^^^^^^^^^^^^^^^^^
+    2 │ [].forEach(() => console.log("test"));
+    3 │ 
+  
+  i The use of console is often reserved for debugging.
+  
+  i Unsafe fix: Remove console.
+  
+    1   │ - const·x·=·()·=>·console.log("test");
+      1 │ + const·x·=·()·=>·{};
+    2 2 │   [].forEach(() => console.log("test"));
+    3 3 │   
+  
+
+```
+
+```
+issue_5053.js:2:18 lint/suspicious/noConsole  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use console.
+  
+    1 │ const x = () => console.log("test");
+  > 2 │ [].forEach(() => console.log("test"));
+      │                  ^^^^^^^^^^^^^^^^^^^
+    3 │ 
+  
+  i The use of console is often reserved for debugging.
+  
+  i Unsafe fix: Remove console.
+  
+    1 1 │   const x = () => console.log("test");
+    2   │ - [].forEach(()·=>·console.log("test"));
+      2 │ + [].forEach(()·=>·{});
+    3 3 │   
+  
+
+```