diff --git a/crates/oxc_linter/src/rules/eslint/arrow_body_style.rs b/crates/oxc_linter/src/rules/eslint/arrow_body_style.rs index d2409b34dce61..13284f433b89b 100644 --- a/crates/oxc_linter/src/rules/eslint/arrow_body_style.rs +++ b/crates/oxc_linter/src/rules/eslint/arrow_body_style.rs @@ -1,27 +1,27 @@ use serde_json::Value; -use oxc_allocator::Box as OxcBox; use oxc_ast::{ AstKind, - ast::{ArrowFunctionExpression, FunctionBody, ReturnStatement}, - ast::{Expression, Statement}, + ast::{ArrowFunctionExpression, Expression, Statement}, }; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; -use oxc_span::Span; +use oxc_span::{GetSpan, Span}; +use oxc_syntax::operator::BinaryOperator; -use crate::{AstNode, context::LintContext, rule::Rule}; +use crate::{ + AstNode, + context::LintContext, + fixer::{RuleFix, RuleFixer}, + rule::Rule, +}; fn arrow_body_style_diagnostic(span: Span, msg: &str) -> OxcDiagnostic { OxcDiagnostic::warn(msg.to_string()).with_label(span) } -fn diagnostic_expected_block(ctx: &LintContext, span: Span) { - ctx.diagnostic(arrow_body_style_diagnostic( - span, - "Expected block statement surrounding arrow body.", - )); -} +const EXPECTED_BLOCK_MSG: &str = "Expected block statement surrounding arrow body."; +const UNEXPECTED_BLOCK_SINGLE_MSG: &str = "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."; #[derive(Debug, Default, PartialEq, Clone)] enum Mode { @@ -180,7 +180,7 @@ declare_oxc_lint!( ArrowBodyStyle, eslint, style, - pending, + fix, ); impl Rule for ArrowBodyStyle { @@ -196,7 +196,7 @@ impl Rule for ArrowBodyStyle { Self { mode, require_return_for_object_literal } } - fn run(&self, node: &AstNode, ctx: &LintContext) { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let AstKind::ArrowFunctionExpression(arrow_func_expr) = node.kind() else { return; }; @@ -204,68 +204,304 @@ impl Rule for ArrowBodyStyle { if arrow_func_expr.expression { self.run_for_arrow_expression(arrow_func_expr, ctx); } else { - self.run_for_arrow_block(&arrow_func_expr.body, ctx); + self.run_for_arrow_block(arrow_func_expr, node, ctx); } } } impl ArrowBodyStyle { - fn run_for_arrow_expression( + /// Handle concise arrow body: `() => expr` + /// Reports when `mode` is "always" or when `mode` is "as-needed" with + /// `requireReturnForObjectLiteral` and the expression is an object literal. + fn run_for_arrow_expression<'a>( &self, - arrow_func_expr: &ArrowFunctionExpression, - ctx: &LintContext, + arrow_func_expr: &ArrowFunctionExpression<'a>, + ctx: &LintContext<'a>, ) { let body = &arrow_func_expr.body; + let inner_expr = arrow_func_expr.get_expression().map(Expression::get_inner_expression); - match ( - &self.mode, - &self.require_return_for_object_literal, - arrow_func_expr.get_expression().map(Expression::get_inner_expression), - ) { - (Mode::Always, _, _) => diagnostic_expected_block(ctx, body.span), - (Mode::AsNeeded, true, Some(Expression::ObjectExpression(_))) => { - diagnostic_expected_block(ctx, body.span); - } - _ => {} - } - } + let should_report = self.mode == Mode::Always + || (self.mode == Mode::AsNeeded + && self.require_return_for_object_literal + && matches!(inner_expr, Some(Expression::ObjectExpression(_)))); - fn run_for_arrow_block_return_statement( - &self, - return_statement: &OxcBox, - body: &FunctionBody, - ctx: &LintContext, - ) { - if self.require_return_for_object_literal - && matches!(return_statement.argument, Some(Expression::ObjectExpression(_))) - { + if !should_report { return; } - ctx.diagnostic(arrow_body_style_diagnostic( - body.span, - "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`.", - )); + ctx.diagnostic_with_fix( + arrow_body_style_diagnostic(body.span, EXPECTED_BLOCK_MSG), + |fixer| Self::fix_concise_to_block(arrow_func_expr, fixer, ctx), + ); } - fn run_for_arrow_block(&self, body: &FunctionBody, ctx: &LintContext) { + /// Handle block arrow body: `() => { ... }` + /// Reports when `mode` is "never" or when `mode` is "as-needed" and the body + /// contains a single return statement (unless `requireReturnForObjectLiteral` + /// is true and the returned value is an object literal). + fn run_for_arrow_block<'a>( + &self, + arrow_func_expr: &ArrowFunctionExpression<'a>, + node: &AstNode<'a>, + ctx: &LintContext<'a>, + ) { + let body = &arrow_func_expr.body; + match self.mode { Mode::Never => { - let msg = if body.statements.is_empty() { - "Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`." - } else { - "Unexpected block statement surrounding arrow body." - }; - ctx.diagnostic(arrow_body_style_diagnostic(body.span, msg)); + // Mode::Never: report any block body + if body.statements.is_empty() { + // TODO: implement a fix for empty block bodies + ctx.diagnostic(arrow_body_style_diagnostic( + body.span, + "Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`.", + )); + return; + } + + // Check if we can fix (single return with argument) + if body.statements.len() == 1 + && let Statement::ReturnStatement(return_statement) = &body.statements[0] + && let Some(return_arg) = &return_statement.argument + { + ctx.diagnostic_with_fix( + arrow_body_style_diagnostic(body.span, UNEXPECTED_BLOCK_SINGLE_MSG), + |fixer| { + Self::fix_block_to_concise( + arrow_func_expr, + return_arg, + node, + fixer, + ctx, + ) + }, + ); + return; + } + + // Cannot auto-fix other cases + ctx.diagnostic(arrow_body_style_diagnostic( + body.span, + "Unexpected block statement surrounding arrow body.", + )); } Mode::AsNeeded if body.statements.len() == 1 => { if let Statement::ReturnStatement(return_statement) = &body.statements[0] { - self.run_for_arrow_block_return_statement(return_statement, body, ctx); + // Skip if requireReturnForObjectLiteral and returning an object + if self.require_return_for_object_literal + && matches!( + return_statement.argument, + Some(Expression::ObjectExpression(_)) + ) + { + return; + } + + // Cannot fix if return has no argument (undefined return) + let Some(return_arg) = &return_statement.argument else { + // TODO: implement a fix for undefined return + ctx.diagnostic(arrow_body_style_diagnostic( + body.span, + UNEXPECTED_BLOCK_SINGLE_MSG, + )); + return; + }; + + ctx.diagnostic_with_fix( + arrow_body_style_diagnostic(body.span, UNEXPECTED_BLOCK_SINGLE_MSG), + |fixer| { + Self::fix_block_to_concise( + arrow_func_expr, + return_arg, + node, + fixer, + ctx, + ) + }, + ); } } _ => {} } } + + /// Fix: Convert concise body to block body + /// `() => expr` → `() => { return expr }` + fn fix_concise_to_block<'a>( + arrow_func_expr: &ArrowFunctionExpression<'a>, + fixer: RuleFixer<'_, 'a>, + ctx: &LintContext<'a>, + ) -> RuleFix { + let body = &arrow_func_expr.body; + + // Get the expression from the concise body + let Some(expr) = arrow_func_expr.get_expression() else { + return fixer.noop(); + }; + + let expr_text = ctx.source_range(expr.span()); + + // Check if the expression is a parenthesized object literal: `() => ({ ... })` + // In that case, we need to remove the outer parens when converting to block: + // `() => ({ ... })` → `() => { return { ... } }` + let inner_expr = expr.get_inner_expression(); + if matches!(inner_expr, Expression::ObjectExpression(_)) { + let inner_text = ctx.source_range(inner_expr.span()); + return fixer.replace(body.span, format!("{{return {inner_text}}}")); + } + + // For all other expressions, just wrap in `{ return ... }` + fixer.replace(body.span, format!("{{return {expr_text}}}")) + } + + /// Fix: Convert block body to concise body + /// `() => { return expr }` → `() => expr` + fn fix_block_to_concise<'a>( + arrow_func_expr: &ArrowFunctionExpression<'a>, + return_arg: &Expression<'a>, + node: &AstNode<'a>, + fixer: RuleFixer<'_, 'a>, + ctx: &LintContext<'a>, + ) -> RuleFix { + let body = &arrow_func_expr.body; + let return_arg_text = ctx.source_range(return_arg.span()); + + // Get the inner expression to handle cases like `return ({ ... })` + // where the return value is already parenthesized + let inner_expr = return_arg.get_inner_expression(); + let is_already_parenthesized = matches!(return_arg, Expression::ParenthesizedExpression(_)); + + // Check if expression starts with `{` - needs parens to avoid ambiguity with blocks + let starts_with_object_literal = Self::starts_with_object_literal(inner_expr); + let is_sequence_expr = matches!(inner_expr, Expression::SequenceExpression(_)); + + if starts_with_object_literal { + if is_already_parenthesized { + // Already parenthesized object: `{ return ({ ... }) }` → `({ ... })` + // Use the full parenthesized text to preserve comments + return fixer.replace(body.span, return_arg_text.to_string()); + } + // Bare object literal or expression starting with object needs parentheses + let inner_text = ctx.source_range(inner_expr.span()); + return fixer.replace(body.span, format!("({inner_text})")); + } + + if is_sequence_expr { + if is_already_parenthesized { + // Already parenthesized sequence: use full text + return fixer.replace(body.span, return_arg_text.to_string()); + } + // Sequence expressions need parentheses: `{ return a, b }` → `(a, b)` + let inner_text = ctx.source_range(inner_expr.span()); + return fixer.replace(body.span, format!("({inner_text})")); + } + + // Check if we need to wrap in parentheses for `in` operator in for-loop init + let needs_parens = Self::needs_parens_for_concise_body(return_arg, node, ctx); + + if needs_parens && !is_already_parenthesized { + // Expression contains `in` and is in for-loop init, needs parentheses + fixer.replace(body.span, format!("({return_arg_text})")) + } else { + // Simple case: just use the return value directly + // (including if it's already parenthesized) + fixer.replace(body.span, return_arg_text.to_string()) + } + } + + /// Check if an expression starts with an object literal. + /// This includes direct ObjectExpression and expressions that have an + /// object literal as their leftmost child (e.g., `{ a: 1 }.b`, `{a: 1}.b + c`) + fn starts_with_object_literal(expr: &Expression) -> bool { + match expr { + Expression::ObjectExpression(_) => true, + Expression::StaticMemberExpression(member) => { + Self::starts_with_object_literal(&member.object) + } + Expression::ComputedMemberExpression(member) => { + Self::starts_with_object_literal(&member.object) + } + Expression::CallExpression(call) => Self::starts_with_object_literal(&call.callee), + Expression::TaggedTemplateExpression(tagged) => { + Self::starts_with_object_literal(&tagged.tag) + } + // Binary/logical expressions: check the leftmost operand + Expression::BinaryExpression(bin) => Self::starts_with_object_literal(&bin.left), + Expression::LogicalExpression(log) => Self::starts_with_object_literal(&log.left), + // Conditional expression: check the test (leftmost part) + Expression::ConditionalExpression(cond) => Self::starts_with_object_literal(&cond.test), + _ => false, + } + } + + /// Check if the expression needs parentheses when converting to concise body. + /// This is needed when the expression contains the `in` operator and the + /// arrow function is inside a for-loop initializer. + fn needs_parens_for_concise_body<'a>( + return_arg: &Expression<'a>, + node: &AstNode<'a>, + ctx: &LintContext<'a>, + ) -> bool { + // Check if the expression contains an `in` operator + if !Self::contains_in_operator(return_arg) { + return false; + } + + // Check if the arrow function is inside a for-loop initializer + Self::is_inside_for_loop_init(node, ctx) + } + + /// Recursively check if an expression contains the `in` binary operator + fn contains_in_operator(expr: &Expression) -> bool { + match expr.get_inner_expression() { + Expression::BinaryExpression(bin) => { + if bin.operator == BinaryOperator::In { + return true; + } + Self::contains_in_operator(&bin.left) || Self::contains_in_operator(&bin.right) + } + Expression::ConditionalExpression(cond) => { + Self::contains_in_operator(&cond.test) + || Self::contains_in_operator(&cond.consequent) + || Self::contains_in_operator(&cond.alternate) + } + Expression::LogicalExpression(log) => { + Self::contains_in_operator(&log.left) || Self::contains_in_operator(&log.right) + } + Expression::AssignmentExpression(assign) => Self::contains_in_operator(&assign.right), + Expression::SequenceExpression(seq) => { + seq.expressions.iter().any(Self::contains_in_operator) + } + _ => false, + } + } + + /// Check if the node is inside a for-loop initializer + fn is_inside_for_loop_init<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> bool { + for ancestor in ctx.nodes().ancestors(node.id()).skip(1) { + match ancestor.kind() { + AstKind::ForStatement(for_stmt) => { + // Check if the arrow function is in the init part + if let Some(init) = &for_stmt.init + && let AstKind::ArrowFunctionExpression(arrow) = node.kind() + && init.span().contains_inclusive(arrow.span) + { + return true; + } + return false; + } + // Stop at function boundaries + AstKind::Function(_) + | AstKind::ArrowFunctionExpression(_) + | AstKind::Program(_) => { + return false; + } + _ => {} + } + } + false + } } #[test] @@ -496,9 +732,16 @@ fn test() { "const createMarker = (color) => ({ latitude, longitude }, index) => {};", Some(serde_json::json!(["always"])), ), + ("var foo = () => { return {a: 1}.b + c };", Some(serde_json::json!(["as-needed"]))), + ("var foo = () => { return {a: 1}.b && c };", Some(serde_json::json!(["as-needed"]))), + ("var foo = () => { return {a: 1}.b || c };", Some(serde_json::json!(["as-needed"]))), + ("var foo = () => { return {a: 1}.b ? c : d };", Some(serde_json::json!(["as-needed"]))), + ("var foo = () => { return {a: 1}.b + c && d };", Some(serde_json::json!(["as-needed"]))), + ("var foo = () => { return {a: 1}.b.c + d };", Some(serde_json::json!(["as-needed"]))), + ("var foo = () => { return {a: 1}.b() + c };", Some(serde_json::json!(["as-needed"]))), ]; - let _fix = vec![ + let fix = vec![ ( "for (var foo = () => { return a in b ? bar : () => {} } ;;);", "for (var foo = () => (a in b ? bar : () => {}) ;;);", @@ -572,12 +815,12 @@ fn test() { ("for ( a = (b) => { return (c in d) }; ;);", "for ( a = (b) => (c in d); ;);", None), ( "for (let a = (b, c, d) => { return vb in dd ; }; ;);", - "for (let a = (b, c, d) => (vb in dd ); ;);", + "for (let a = (b, c, d) => (vb in dd); ;);", None, ), ( "for (let a = (b, c, d) => { return vb in c in dd ; }; ;);", - "for (let a = (b, c, d) => (vb in c in dd ); ;);", + "for (let a = (b, c, d) => (vb in c in dd); ;);", None, ), ( @@ -587,7 +830,7 @@ fn test() { ), ( "do{for (let a = (b, c, d) => { return vb in c in dd ; }; ;);}while(true){}", - "do{for (let a = (b, c, d) => (vb in c in dd ); ;);}while(true){}", + "do{for (let a = (b, c, d) => (vb in c in dd); ;);}while(true){}", None, ), ( @@ -609,11 +852,11 @@ fn test() { ), ( "var foo = () => ( {});", - "var foo = () => {return {}};", + "var foo = () => {return {}};", Some(serde_json::json!(["always"])), ), ("(() => ({}))", "(() => {return {}})", Some(serde_json::json!(["always"]))), - ("(() => ( {}))", "(() => {return {}})", Some(serde_json::json!(["always"]))), + ("(() => ( {}))", "(() => {return {}})", Some(serde_json::json!(["always"]))), ( "var foo = () => { return 0; };", "var foo = () => 0;", @@ -689,7 +932,7 @@ fn test() { ), ( "var foo = /* a */ ( /* b */ ) /* c */ => /* d */ { /* e */ return /* f */ 5 /* g */ ; /* h */ } /* i */ ;", - "var foo = /* a */ ( /* b */ ) /* c */ => /* d */ /* e */ /* f */ 5 /* g */ /* h */ /* i */ ;", + "var foo = /* a */ ( /* b */ ) /* c */ => /* d */ 5 /* i */ ;", Some(serde_json::json!(["as-needed"])), ), ( @@ -748,17 +991,17 @@ fn test() { ), ( "var foo = () => ({foo: 1}).foo();", - "var foo = () => {return {foo: 1}.foo()};", + "var foo = () => {return ({foo: 1}).foo()};", Some(serde_json::json!(["always"])), ), ( "var foo = () => ({foo: 1}.foo());", - "var foo = () => {return {foo: 1}.foo()};", + "var foo = () => {return ({foo: 1}.foo())};", Some(serde_json::json!(["always"])), ), ( "var foo = () => ( {foo: 1} ).foo();", - "var foo = () => {return {foo: 1} .foo()};", + "var foo = () => {return ( {foo: 1} ).foo()};", Some(serde_json::json!(["always"])), ), ( @@ -786,12 +1029,10 @@ fn test() { )); ", " - parsedYears = _map(years, (year) => { - return { + parsedYears = _map(years, (year) => {return { index : year, title : splitYear(year) - } - }); + }}); ", Some(serde_json::json!(["always"])), ), @@ -800,7 +1041,44 @@ fn test() { "const createMarker = (color) => {return ({ latitude, longitude }, index) => {}};", Some(serde_json::json!(["always"])), ), + ( + "var foo = () => { return {a: 1}.b + c };", + "var foo = () => ({a: 1}.b + c);", + Some(serde_json::json!(["as-needed"])), + ), + ( + "var foo = () => { return {a: 1}.b && c };", + "var foo = () => ({a: 1}.b && c);", + Some(serde_json::json!(["as-needed"])), + ), + ( + "var foo = () => { return {a: 1}.b || c };", + "var foo = () => ({a: 1}.b || c);", + Some(serde_json::json!(["as-needed"])), + ), + ( + "var foo = () => { return {a: 1}.b ? c : d };", + "var foo = () => ({a: 1}.b ? c : d);", + Some(serde_json::json!(["as-needed"])), + ), + ( + "var foo = () => { return {a: 1}.b + c && d };", + "var foo = () => ({a: 1}.b + c && d);", + Some(serde_json::json!(["as-needed"])), + ), + ( + "var foo = () => { return {a: 1}.b.c + d };", + "var foo = () => ({a: 1}.b.c + d);", + Some(serde_json::json!(["as-needed"])), + ), + ( + "var foo = () => { return {a: 1}.b() + c };", + "var foo = () => ({a: 1}.b() + c);", + Some(serde_json::json!(["as-needed"])), + ), ]; - Tester::new(ArrowBodyStyle::NAME, ArrowBodyStyle::PLUGIN, pass, fail).test_and_snapshot(); + Tester::new(ArrowBodyStyle::NAME, ArrowBodyStyle::PLUGIN, pass, fail) + .expect_fix(fix) + .test_and_snapshot(); } diff --git a/crates/oxc_linter/src/snapshots/eslint_arrow_body_style.snap b/crates/oxc_linter/src/snapshots/eslint_arrow_body_style.snap index 9e842a30ff6f1..1a28d471cffe9 100644 --- a/crates/oxc_linter/src/snapshots/eslint_arrow_body_style.snap +++ b/crates/oxc_linter/src/snapshots/eslint_arrow_body_style.snap @@ -6,180 +6,210 @@ source: crates/oxc_linter/src/tester.rs 1 │ for (var foo = () => { return a in b ? bar : () => {} } ;;); · ────────────────────────────────── ╰──── + help: Replace `{ return a in b ? bar : () => {} }` with `(a in b ? bar : () => {})`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:28] 1 │ a in b; for (var f = () => { return c };;); · ──────────── ╰──── + help: Replace `{ return c }` with `c`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:15] 1 │ for (a = b => { return c in d ? e : f } ;;); · ───────────────────────── ╰──── + help: Replace `{ return c in d ? e : f }` with `(c in d ? e : f)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:20] 1 │ for (var f = () => { return a };;); · ──────────── ╰──── + help: Replace `{ return a }` with `a`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:22] 1 │ for (var f;f = () => { return a };); · ──────────── ╰──── + help: Replace `{ return a }` with `a`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:20] 1 │ for (var f = () => { return a in c };;); · ───────────────── ╰──── + help: Replace `{ return a in c }` with `(a in c)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:22] 1 │ for (var f;f = () => { return a in c };); · ───────────────── ╰──── + help: Replace `{ return a in c }` with `a in c`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:24] 1 │ for (;;){var f = () => { return a in c }} · ───────────────── ╰──── + help: Replace `{ return a in c }` with `a in c`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:15] 1 │ for (a = b => { return c = d in e } ;;); · ───────────────────── ╰──── + help: Replace `{ return c = d in e }` with `(c = d in e)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:22] 1 │ for (var a;;a = b => { return c = d in e } ); · ───────────────────── ╰──── + help: Replace `{ return c = d in e }` with `c = d in e`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:27] 1 │ for (let a = (b, c, d) => { return vb && c in d; }; ;); · ──────────────────────── ╰──── + help: Replace `{ return vb && c in d; }` with `(vb && c in d)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:27] 1 │ for (let a = (b, c, d) => { return v in b && c in d; }; ;); · ──────────────────────────── ╰──── + help: Replace `{ return v in b && c in d; }` with `(v in b && c in d)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:43] 1 │ function foo(){ for (let a = (b, c, d) => { return v in b && c in d; }; ;); } · ──────────────────────────── ╰──── + help: Replace `{ return v in b && c in d; }` with `(v in b && c in d)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:24] 1 │ for ( a = (b, c, d) => { return v in b && c in d; }; ;); · ──────────────────────────── ╰──── + help: Replace `{ return v in b && c in d; }` with `(v in b && c in d)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:18] 1 │ for ( a = (b) => { return (c in d) }; ;); · ─────────────────── ╰──── + help: Replace `{ return (c in d) }` with `(c in d)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:27] 1 │ for (let a = (b, c, d) => { return vb in dd ; }; ;); · ───────────────────── ╰──── + help: Replace `{ return vb in dd ; }` with `(vb in dd)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:27] 1 │ for (let a = (b, c, d) => { return vb in c in dd ; }; ;); · ────────────────────────── ╰──── + help: Replace `{ return vb in c in dd ; }` with `(vb in c in dd)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:18] 1 │ do{let a = () => {return f in ff}}while(true){} · ──────────────── ╰──── + help: Replace `{return f in ff}` with `f in ff`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:30] 1 │ do{for (let a = (b, c, d) => { return vb in c in dd ; }; ;);}while(true){} · ────────────────────────── ╰──── + help: Replace `{ return vb in c in dd ; }` with `(vb in c in dd)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:21] 1 │ scores.map(score => { return x in +(score / maxScore).toFixed(2)}); · ───────────────────────────────────────────── ╰──── + help: Replace `{ return x in +(score / maxScore).toFixed(2)}` with `x in +(score / maxScore).toFixed(2)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:22] 1 │ const fn = (a, b) => { return a + x in Number(b) }; · ───────────────────────────── ╰──── + help: Replace `{ return a + x in Number(b) }` with `a + x in Number(b)`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => 0 · ─ ╰──── + help: Replace `0` with `{return 0}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => 0; · ─ ╰──── + help: Replace `0` with `{return 0}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ({}); · ──── ╰──── + help: Replace `({})` with `{return {}}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ( {}); · ────── ╰──── + help: Replace `( {})` with `{return {}}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:8] 1 │ (() => ({})) · ──── ╰──── + help: Replace `({})` with `{return {}}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:8] 1 │ (() => ( {})) · ───── ╰──── + help: Replace `( {})` with `{return {}}`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return 0; }; · ───────────── ╰──── + help: Replace `{ return 0; }` with `0`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return 0 }; · ──────────── ╰──── + help: Replace `{ return 0 }` with `0`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return bar(); }; · ───────────────── ╰──── + help: Replace `{ return bar(); }` with `bar()`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] @@ -187,30 +217,36 @@ source: crates/oxc_linter/src/tester.rs · ── ╰──── - ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body. + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ ╭─▶ var foo = () => { 2 │ │ return 0; 3 │ ╰─▶ }; ╰──── + help: Replace `{ + return 0; + }` with `0`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return { bar: 0 }; }; · ────────────────────── ╰──── + help: Replace `{ return { bar: 0 }; }` with `({ bar: 0 })`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return ({ bar: 0 }); }; · ──────────────────────── ╰──── + help: Replace `{ return ({ bar: 0 }); }` with `({ bar: 0 })`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return a, b } · ─────────────── ╰──── + help: Replace `{ return a, b }` with `(a, b)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] @@ -229,18 +265,21 @@ source: crates/oxc_linter/src/tester.rs 1 │ var foo = () => { return ( /* a */ {ok: true} /* b */ ) }; · ───────────────────────────────────────── ╰──── + help: Replace `{ return ( /* a */ {ok: true} /* b */ ) }` with `( /* a */ {ok: true} /* b */ )`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return '{' }; · ────────────── ╰──── + help: Replace `{ return '{' }` with `'{'`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return { bar: 0 }.bar; }; · ────────────────────────── ╰──── + help: Replace `{ return { bar: 0 }.bar; }` with `({ bar: 0 }.bar)`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:27] @@ -261,42 +300,49 @@ source: crates/oxc_linter/src/tester.rs 1 │ var foo = () => { return 0; }; · ───────────── ╰──── + help: Replace `{ return 0; }` with `0`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => { return bar(); }; · ───────────────── ╰──── + help: Replace `{ return bar(); }` with `bar()`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ({}); · ──── ╰──── + help: Replace `({})` with `{return {}}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ({ bar: 0 }); · ──────────── ╰──── + help: Replace `({ bar: 0 })` with `{return { bar: 0 }}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => (((((((5))))))); · ─────────────── ╰──── + help: Replace `(((((((5)))))))` with `{return (((((((5)))))))}`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:50] 1 │ var foo = /* a */ ( /* b */ ) /* c */ => /* d */ { /* e */ return /* f */ 5 /* g */ ; /* h */ } /* i */ ; · ────────────────────────────────────────────── ╰──── + help: Replace `{ /* e */ return /* f */ 5 /* g */ ; /* h */ }` with `5`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:50] 1 │ var foo = /* a */ ( /* b */ ) /* c */ => /* d */ ( /* e */ 5 /* f */ ) /* g */ ; · ───────────────────── ╰──── + help: Replace `( /* e */ 5 /* f */ )` with `{return ( /* e */ 5 /* f */ )}`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] @@ -304,18 +350,25 @@ source: crates/oxc_linter/src/tester.rs 2 │ │ return bar; 3 │ ╰─▶ }; ╰──── + help: Replace `{ + return bar; + }` with `bar`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ ╭─▶ var foo = () => { 2 │ ╰─▶ return bar;}; ╰──── + help: Replace `{ + return bar;}` with `bar`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:1:17] 1 │ ╭─▶ var foo = () => {return bar; 2 │ ╰─▶ }; ╰──── + help: Replace `{return bar; + }` with `bar`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:2:34] @@ -326,6 +379,11 @@ source: crates/oxc_linter/src/tester.rs 5 │ ╰─▶ }; 6 │ ╰──── + help: Replace `{ + return foo + .bar; + }` with `foo + .bar`. ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. ╭─[arrow_body_style.tsx:2:34] @@ -338,24 +396,36 @@ source: crates/oxc_linter/src/tester.rs 7 │ ╰─▶ }; 8 │ ╰──── + help: Replace `{ + return { + bar: 1, + baz: 2 + }; + }` with `({ + bar: 1, + baz: 2 + })`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ({foo: 1}).foo(); · ──────────────── ╰──── + help: Replace `({foo: 1}).foo()` with `{return ({foo: 1}).foo()}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ({foo: 1}.foo()); · ──────────────── ╰──── + help: Replace `({foo: 1}.foo())` with `{return ({foo: 1}.foo())}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:17] 1 │ var foo = () => ( {foo: 1} ).foo(); · ────────────────── ╰──── + help: Replace `( {foo: 1} ).foo()` with `{return ( {foo: 1} ).foo()}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:2:34] @@ -366,6 +436,13 @@ source: crates/oxc_linter/src/tester.rs 5 │ ╰─▶ }); 6 │ ╰──── + help: Replace `({ + bar: 1, + baz: 2 + })` with `{return { + bar: 1, + baz: 2 + }}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:2:54] @@ -378,9 +455,68 @@ source: crates/oxc_linter/src/tester.rs 7 │ ╰─▶ )); 8 │ ╰──── + help: Replace `( + { + index : year, + title : splitYear(year) + } + )` with `{return { + index : year, + title : splitYear(year) + }}`. ⚠ eslint(arrow-body-style): Expected block statement surrounding arrow body. ╭─[arrow_body_style.tsx:1:33] 1 │ const createMarker = (color) => ({ latitude, longitude }, index) => {}; · ────────────────────────────────────── ╰──── + help: Replace `({ latitude, longitude }, index) => {}` with `{return ({ latitude, longitude }, index) => {}}`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b + c }; + · ─────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b + c }` with `({a: 1}.b + c)`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b && c }; + · ──────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b && c }` with `({a: 1}.b && c)`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b || c }; + · ──────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b || c }` with `({a: 1}.b || c)`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b ? c : d }; + · ─────────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b ? c : d }` with `({a: 1}.b ? c : d)`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b + c && d }; + · ──────────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b + c && d }` with `({a: 1}.b + c && d)`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b.c + d }; + · ───────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b.c + d }` with `({a: 1}.b.c + d)`. + + ⚠ eslint(arrow-body-style): Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`. + ╭─[arrow_body_style.tsx:1:17] + 1 │ var foo = () => { return {a: 1}.b() + c }; + · ───────────────────────── + ╰──── + help: Replace `{ return {a: 1}.b() + c }` with `({a: 1}.b() + c)`.