From 5e7dc25807d9ba68b0303f1cb4eface1503c08cb Mon Sep 17 00:00:00 2001 From: baseballyama Date: Fri, 27 Dec 2024 21:12:05 +0900 Subject: [PATCH 1/7] feat(linter): implement no-lone-blocks --- .idea/.gitignore | 8 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/prettier.xml | 6 + .idea/vcs.xml | 6 + crates/oxc_linter/src/rules.rs | 2 + .../src/rules/eslint/no_lone_blocks.rs | 386 ++++++++++++++++++ .../src/snapshots/eslint_no_lone_blocks.snap | 231 +++++++++++ 7 files changed, 645 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/prettier.xml create mode 100644 .idea/vcs.xml create mode 100644 crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs create mode 100644 crates/oxc_linter/src/snapshots/eslint_no_lone_blocks.snap diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000..13566b81b018a --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000..03d9549ea8e4a --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000000000..b0c1c68fbbad6 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000..35eb1ddfbbc02 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index fc7e7383b400d..c0aa53f178a28 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -92,6 +92,7 @@ mod eslint { pub mod no_iterator; pub mod no_label_var; pub mod no_labels; + pub mod no_lone_blocks; pub mod no_loss_of_precision; pub mod no_magic_numbers; pub mod no_multi_assign; @@ -548,6 +549,7 @@ oxc_macros::declare_all_lint_rules! { eslint::no_multi_assign, eslint::no_nested_ternary, eslint::no_labels, + eslint::no_lone_blocks, eslint::no_restricted_imports, eslint::no_object_constructor, eslint::no_duplicate_imports, diff --git a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs new file mode 100644 index 0000000000000..0ebad6396f673 --- /dev/null +++ b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs @@ -0,0 +1,386 @@ +use oxc_ast::ast::VariableDeclarationKind; +use oxc_ast::AstKind; +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_span::{GetSpan, Span}; + +use crate::{context::LintContext, rule::Rule, AstNode}; + +fn no_lone_blocks_diagnostic(span: Span, is_nested_block: bool) -> OxcDiagnostic { + let message = + if is_nested_block { "Nested block is redundant." } else { "Block is unnecessary." }; + // See for details + OxcDiagnostic::warn(message).with_label(span) +} + +#[derive(Debug, Default, Clone)] +pub struct NoLoneBlocks; + +declare_oxc_lint!( + /// ### What it does + /// + /// Disallows unnecessary standalone block statements. + /// + /// ### Why is this bad? + /// + /// Standalone blocks can be confusing as they do not provide any meaningful purpose when used unnecessarily. + /// They may introduce extra nesting, reducing code readability, and can mislead readers about scope or intent. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```js + /// { + /// var x = 1; + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```js + /// if (condition) { + /// var x = 1; + /// } + /// + /// { + /// let x = 1; // Used to create a valid block scope. + /// } + /// ``` + NoLoneBlocks, + style, +); + +impl Rule for NoLoneBlocks { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + let AstKind::BlockStatement(stmt) = node.kind() else { + return; + }; + + let Some(parent_node) = ctx.nodes().parent_node(node.id()) else { + return; + }; + + let body = &stmt.body; + if body.is_empty() { + report(ctx, node, parent_node); + return; + } + + if body.len() == 1 + && matches!(parent_node.kind(), AstKind::FunctionBody(parent) if parent.statements.len() == 1) + { + report(ctx, node, parent_node); + } + + let mut lone_blocks = Vec::new(); + if is_lone_block(node, parent_node) { + lone_blocks.push(node); + } + + let span = stmt.span(); + let children: Vec<_> = ctx + .nodes() + .iter() + .filter(|n| { + let n_span = n.span(); + span.start < n_span.start && n_span.end < span.end + }) + .collect(); + + for child in children { + if let Some(parent_of_child) = ctx.nodes().parent_node(child.id()) { + match child.kind() { + AstKind::VariableDeclaration(var_decl) + if var_decl.kind != VariableDeclarationKind::Var => + { + mark_lone_block(parent_of_child, &mut lone_blocks); + } + AstKind::Function(_) | AstKind::Class(_) => { + mark_lone_block(parent_of_child, &mut lone_blocks); + } + _ => {} + } + } + } + + if let Some(last) = lone_blocks.last() { + if last.id() == node.id() { + lone_blocks.pop(); + report(ctx, node, parent_node); + } + } else { + match parent_node.kind() { + AstKind::BlockStatement(parent_statement) => { + if parent_statement.body.len() == 1 { + report(ctx, node, parent_node); + } + } + AstKind::StaticBlock(parent_statement) => { + if parent_statement.body.len() == 1 { + report(ctx, node, parent_node); + } + } + _ => {} + } + } + } +} + +fn report(ctx: &LintContext, node: &AstNode, parent_node: &AstNode) { + match parent_node.kind() { + AstKind::BlockStatement(_) | AstKind::StaticBlock(_) => { + ctx.diagnostic(no_lone_blocks_diagnostic(node.span(), true)); + } + _ => ctx.diagnostic(no_lone_blocks_diagnostic(node.span(), false)), + }; +} + +fn is_lone_block(node: &AstNode, parent_node: &AstNode) -> bool { + match parent_node.kind() { + AstKind::BlockStatement(_) | AstKind::StaticBlock(_) | AstKind::Program(_) => true, + AstKind::SwitchCase(parent_node) => { + let consequent = &parent_node.consequent; + if consequent.len() != 1 { + return true; + } + let node_span = node.span(); + let consequent_span = consequent[0].span(); + node_span.start != consequent_span.start || node_span.end != consequent_span.end + } + _ => false, + } +} + +fn mark_lone_block(parent_node: &AstNode, lone_blocks: &mut Vec<&AstNode>) { + if lone_blocks.is_empty() { + return; + } + + if lone_blocks.last().map_or(false, |last| last.id() == parent_node.id()) { + lone_blocks.pop(); + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + "if (foo) { if (bar) { baz(); } }", + "do { bar(); } while (foo)", + "function foo() { while (bar) { baz() } }", + "{ let x = 1; }", // { "ecmaVersion": 6 }, + "{ const x = 1; }", // { "ecmaVersion": 6 }, + "'use strict'; { function bar() {} }", // { "ecmaVersion": 6 }, + "{ function bar() {} }", // { "ecmaVersion": 6, "parserOptions": { "ecmaFeatures": { "impliedStrict": true } } }, + "{ class Bar {} }", // { "ecmaVersion": 6 }, + "{ {let y = 1;} let x = 1; }", // { "ecmaVersion": 6 }, + " + switch (foo) { + case bar: { + baz; + } + } + ", + " + switch (foo) { + case bar: { + baz; + } + case qux: { + boop; + } + } + ", + " + switch (foo) { + case bar: + { + baz; + } + } + ", + "function foo() { { const x = 4 } const x = 3 }", // { "ecmaVersion": 6 }, + "class C { static {} }", // { "ecmaVersion": 2022 }, + "class C { static { foo; } }", // { "ecmaVersion": 2022 }, + "class C { static { if (foo) { block; } } }", // { "ecmaVersion": 2022 }, + "class C { static { lbl: { block; } } }", // { "ecmaVersion": 2022 }, + "class C { static { { let block; } something; } }", // { "ecmaVersion": 2022 }, + "class C { static { something; { const block = 1; } } }", // { "ecmaVersion": 2022 }, + "class C { static { { function block(){} } something; } }", // { "ecmaVersion": 2022 }, + "class C { static { something; { class block {} } } }", // { "ecmaVersion": 2022 }, + " + { + using x = makeDisposable(); + }", // { "parser": require(parser("typescript-parsers/no-lone-blocks/using")), "ecmaVersion": 2022 }, + " + { + await using x = makeDisposable(); + }", // { "parser": require(parser("typescript-parsers/no-lone-blocks/await-using")), "ecmaVersion": 2022 } + ]; + + let fail = vec![ + "{}", + "{var x = 1;}", + "foo(); {} bar();", + "if (foo) { bar(); {} baz(); }", + "{ + { } }", + "function foo() { bar(); {} baz(); }", + "while (foo) { {} }", + // MEMO: Currently, this rule always analyzes in strict mode (as it cannot retrieve ecmaFeatures). + // "{ function bar() {} }", // { "ecmaVersion": 6 }, + "{var x = 1;}", // { "ecmaVersion": 6 }, + "{ + {var x = 1;} + let y = 2; } {let z = 1;}", // { "ecmaVersion": 6 }, + "{ + {let x = 1;} + var y = 2; } {let z = 1;}", // { "ecmaVersion": 6 }, + "{ + {var x = 1;} + var y = 2; } + {var z = 1;}", // { "ecmaVersion": 6 }, + " + switch (foo) { + case 1: + foo(); + { + bar; + } + } + ", + " + switch (foo) { + case 1: + { + bar; + } + foo(); + } + ", + " + function foo () { + { + const x = 4; + } + } + ", // { "ecmaVersion": 6 }, + " + function foo () { + { + var x = 4; + } + } + ", + " + class C { + static { + if (foo) { + { + let block; + } + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + if (foo) { + { + block; + } + something; + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + block; + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + let block; + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + const block = 1; + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + function block() {} + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + class block {} + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + var block; + } + something; + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + something; + { + var block; + } + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + { + block; + } + something; + } + } + ", // { "ecmaVersion": 2022 }, + " + class C { + static { + something; + { + block; + } + } + } + ", // { "ecmaVersion": 2022 } + ]; + + Tester::new(NoLoneBlocks::NAME, NoLoneBlocks::CATEGORY, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/eslint_no_lone_blocks.snap b/crates/oxc_linter/src/snapshots/eslint_no_lone_blocks.snap new file mode 100644 index 0000000000000..a1677b9f013d7 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/eslint_no_lone_blocks.snap @@ -0,0 +1,231 @@ +--- +source: crates/oxc_linter/src/tester.rs +snapshot_kind: text +--- + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:1] + 1 │ {} + · ── + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:1] + 1 │ {var x = 1;} + · ──────────── + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:8] + 1 │ foo(); {} bar(); + · ── + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:1:19] + 1 │ if (foo) { bar(); {} baz(); } + · ── + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:1] + 1 │ ╭─▶ { + 2 │ ╰─▶ { } } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:2:4] + 1 │ { + 2 │ { } } + · ─── + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:25] + 1 │ function foo() { bar(); {} baz(); } + · ── + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:1:15] + 1 │ while (foo) { {} } + · ── + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:1] + 1 │ {var x = 1;} + · ──────────── + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:2:4] + 1 │ { + 2 │ {var x = 1;} + · ──────────── + 3 │ let y = 2; } {let z = 1;} + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:1] + 1 │ ╭─▶ { + 2 │ │ {let x = 1;} + 3 │ ╰─▶ var y = 2; } {let z = 1;} + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:1:1] + 1 │ ╭─▶ { + 2 │ │ {var x = 1;} + 3 │ ╰─▶ var y = 2; } + 4 │ {var z = 1;} + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:2:4] + 1 │ { + 2 │ {var x = 1;} + · ──────────── + 3 │ var y = 2; } + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:4:5] + 3 │ var y = 2; } + 4 │ {var z = 1;} + · ──────────── + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:5:24] + 4 │ foo(); + 5 │ ╭─▶ { + 6 │ │ bar; + 7 │ ╰─▶ } + 8 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:4:20] + 3 │ case 1: + 4 │ ╭─▶ { + 5 │ │ bar; + 6 │ ╰─▶ } + 7 │ foo(); + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:3:20] + 2 │ function foo () { + 3 │ ╭─▶ { + 4 │ │ const x = 4; + 5 │ ╰─▶ } + 6 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Block is unnecessary. + ╭─[no_lone_blocks.tsx:3:20] + 2 │ function foo () { + 3 │ ╭─▶ { + 4 │ │ var x = 4; + 5 │ ╰─▶ } + 6 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:5:24] + 4 │ if (foo) { + 5 │ ╭─▶ { + 6 │ │ let block; + 7 │ ╰─▶ } + 8 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:5:24] + 4 │ if (foo) { + 5 │ ╭─▶ { + 6 │ │ block; + 7 │ ╰─▶ } + 8 │ something; + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ block; + 6 │ ╰─▶ } + 7 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ let block; + 6 │ ╰─▶ } + 7 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ const block = 1; + 6 │ ╰─▶ } + 7 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ function block() {} + 6 │ ╰─▶ } + 7 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ class block {} + 6 │ ╰─▶ } + 7 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ var block; + 6 │ ╰─▶ } + 7 │ something; + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:5:22] + 4 │ something; + 5 │ ╭─▶ { + 6 │ │ var block; + 7 │ ╰─▶ } + 8 │ } + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:4:22] + 3 │ static { + 4 │ ╭─▶ { + 5 │ │ block; + 6 │ ╰─▶ } + 7 │ something; + ╰──── + + ⚠ eslint(no-lone-blocks): Nested block is redundant. + ╭─[no_lone_blocks.tsx:5:22] + 4 │ something; + 5 │ ╭─▶ { + 6 │ │ block; + 7 │ ╰─▶ } + 8 │ } + ╰──── From 6cc3ccfa54ad0d5495209179a2b93c5f9dabac9b Mon Sep 17 00:00:00 2001 From: baseballyama Date: Fri, 27 Dec 2024 22:39:27 +0900 Subject: [PATCH 2/7] perf --- .../src/rules/eslint/no_lone_blocks.rs | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs index 0ebad6396f673..b8cc036ebb39a 100644 --- a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs +++ b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs @@ -1,4 +1,4 @@ -use oxc_ast::ast::VariableDeclarationKind; +use oxc_ast::ast::{Declaration, VariableDeclarationKind}; use oxc_ast::AstKind; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; @@ -76,29 +76,20 @@ impl Rule for NoLoneBlocks { lone_blocks.push(node); } - let span = stmt.span(); - let children: Vec<_> = ctx - .nodes() - .iter() - .filter(|n| { - let n_span = n.span(); - span.start < n_span.start && n_span.end < span.end - }) - .collect(); - - for child in children { - if let Some(parent_of_child) = ctx.nodes().parent_node(child.id()) { - match child.kind() { - AstKind::VariableDeclaration(var_decl) - if var_decl.kind != VariableDeclarationKind::Var => - { - mark_lone_block(parent_of_child, &mut lone_blocks); - } - AstKind::Function(_) | AstKind::Class(_) => { - mark_lone_block(parent_of_child, &mut lone_blocks); - } - _ => {} + for child in &stmt.body { + match child.as_declaration() { + Some(Declaration::VariableDeclaration(decl)) + if decl.kind != VariableDeclarationKind::Var => + { + mark_lone_block(node, &mut lone_blocks); } + Some(Declaration::ClassDeclaration(_)) => { + mark_lone_block(node, &mut lone_blocks); + } + Some(Declaration::FunctionDeclaration(_)) => { + mark_lone_block(node, &mut lone_blocks); + } + _ => {} } } From bb42f25aeb5d09f204c0973d48f1182fa23db24e Mon Sep 17 00:00:00 2001 From: baseballyama Date: Fri, 27 Dec 2024 22:44:27 +0900 Subject: [PATCH 3/7] fix lint --- crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs index b8cc036ebb39a..57f3e9b84b52a 100644 --- a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs +++ b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs @@ -83,10 +83,7 @@ impl Rule for NoLoneBlocks { { mark_lone_block(node, &mut lone_blocks); } - Some(Declaration::ClassDeclaration(_)) => { - mark_lone_block(node, &mut lone_blocks); - } - Some(Declaration::FunctionDeclaration(_)) => { + Some(Declaration::ClassDeclaration(_) | Declaration::FunctionDeclaration(_)) => { mark_lone_block(node, &mut lone_blocks); } _ => {} From 6ff0333f7089e58578cb34f99d7c79d4ad34fa70 Mon Sep 17 00:00:00 2001 From: baseballyama Date: Sat, 28 Dec 2024 04:43:50 +0900 Subject: [PATCH 4/7] split no_lone_blocks_diagnostic --- .../oxc_linter/src/rules/eslint/no_lone_blocks.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs index 57f3e9b84b52a..1e3abc5f2f4c2 100644 --- a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs +++ b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs @@ -6,11 +6,12 @@ use oxc_span::{GetSpan, Span}; use crate::{context::LintContext, rule::Rule, AstNode}; -fn no_lone_blocks_diagnostic(span: Span, is_nested_block: bool) -> OxcDiagnostic { - let message = - if is_nested_block { "Nested block is redundant." } else { "Block is unnecessary." }; - // See for details - OxcDiagnostic::warn(message).with_label(span) +fn no_lone_blocks_diagnostic(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("Block is unnecessary.").with_label(span) +} + +fn no_nested_lone_blocks_diagnostic(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("Nested block is redundant.").with_label(span) } #[derive(Debug, Default, Clone)] @@ -116,9 +117,9 @@ impl Rule for NoLoneBlocks { fn report(ctx: &LintContext, node: &AstNode, parent_node: &AstNode) { match parent_node.kind() { AstKind::BlockStatement(_) | AstKind::StaticBlock(_) => { - ctx.diagnostic(no_lone_blocks_diagnostic(node.span(), true)); + ctx.diagnostic(no_nested_lone_blocks_diagnostic(node.span())); } - _ => ctx.diagnostic(no_lone_blocks_diagnostic(node.span(), false)), + _ => ctx.diagnostic(no_lone_blocks_diagnostic(node.span())), }; } From a06b0ebefd9f77bcca6076d5a02e7eaa95c191bd Mon Sep 17 00:00:00 2001 From: baseballyama Date: Mon, 13 Jan 2025 10:06:38 +0900 Subject: [PATCH 5/7] rm .idea --- .idea/.gitignore | 8 -------- .idea/inspectionProfiles/Project_Default.xml | 6 ------ .idea/prettier.xml | 6 ------ .idea/vcs.xml | 6 ------ 4 files changed, 26 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/prettier.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b81b018a..0000000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 03d9549ea8e4a..0000000000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml deleted file mode 100644 index b0c1c68fbbad6..0000000000000 --- a/.idea/prettier.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfbbc02..0000000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From c3bdab028b45e3f299595f778454df572afbf34a Mon Sep 17 00:00:00 2001 From: baseballyama Date: Mon, 13 Jan 2025 10:09:15 +0900 Subject: [PATCH 6/7] merge 8353 --- crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs index 1e3abc5f2f4c2..a5ba397567745 100644 --- a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs +++ b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs @@ -47,6 +47,7 @@ declare_oxc_lint!( /// } /// ``` NoLoneBlocks, + eslint, style, ); @@ -371,5 +372,5 @@ fn test() { ", // { "ecmaVersion": 2022 } ]; - Tester::new(NoLoneBlocks::NAME, NoLoneBlocks::CATEGORY, pass, fail).test_and_snapshot(); + Tester::new(NoLoneBlocks::NAME, NoLoneBlocks::PLUGIN, pass, fail).test_and_snapshot(); } From cd187e0ffe4d3b1344875f7fdaf4eab0364c1267 Mon Sep 17 00:00:00 2001 From: baseballyama Date: Mon, 13 Jan 2025 10:18:09 +0900 Subject: [PATCH 7/7] fix lint --- crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs index a5ba397567745..0f016eff87507 100644 --- a/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs +++ b/crates/oxc_linter/src/rules/eslint/no_lone_blocks.rs @@ -145,7 +145,7 @@ fn mark_lone_block(parent_node: &AstNode, lone_blocks: &mut Vec<&AstNode>) { return; } - if lone_blocks.last().map_or(false, |last| last.id() == parent_node.id()) { + if lone_blocks.last().is_some_and(|last| last.id() == parent_node.id()) { lone_blocks.pop(); } }