feat(linter): unicorn/switch-cases-braces support options (#8704)

close #8492
This commit is contained in:
1zumii 2025-01-25 17:30:01 +08:00 committed by GitHub
parent 6589c3bbb3
commit e8e69179d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 102 additions and 30 deletions

View file

@ -5,16 +5,33 @@ use oxc_span::{GetSpan, Span};
use crate::{context::LintContext, rule::Rule, AstNode};
fn switch_case_braces_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(
" Empty switch case shouldn't have braces and not-empty case should have braces around it.",
)
.with_help("There is less visual clutter for empty cases and proper scope for non-empty cases.")
#[derive(Clone, Copy)]
enum Diagnostic {
EmptyClause,
MissingBraces,
UnnecessaryBraces,
}
fn switch_case_braces_diagnostic(span: Span, diagnostic_type: Diagnostic) -> OxcDiagnostic {
(match diagnostic_type {
Diagnostic::EmptyClause => OxcDiagnostic::warn("Unexpected braces in empty case clause.")
.with_help("Remove braces in empty case clause."),
Diagnostic::MissingBraces => OxcDiagnostic::warn("Missing braces in case clause.")
.with_help("Add Braces for case clause."),
Diagnostic::UnnecessaryBraces => OxcDiagnostic::warn("Unnecessary braces in case clause.")
.with_help("Remove Braces for case clause."),
})
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct SwitchCaseBraces;
pub struct SwitchCaseBraces {
// true - "always" (default)
// - Always report when clause is not a BlockStatement
// false - "avoid"
// - Only allow braces when there are variable declaration or function declaration which requires a scope.
always_braces: bool,
}
declare_oxc_lint!(
/// ### What it does
@ -41,6 +58,12 @@ declare_oxc_lint!(
);
impl Rule for SwitchCaseBraces {
fn from_configuration(value: serde_json::Value) -> Self {
let always = value.get(0).map_or(true, |v| v.as_str() != Some("avoid"));
Self { always_braces: always }
}
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::SwitchStatement(switch) = node.kind() else {
return;
@ -56,13 +79,54 @@ impl Rule for SwitchCaseBraces {
Statement::BlockStatement(case_block) => {
if case_block.body.is_empty() {
ctx.diagnostic_with_fix(
switch_case_braces_diagnostic(case_block.span),
switch_case_braces_diagnostic(
case_block.span,
Diagnostic::EmptyClause,
),
|fixer| fixer.delete_range(case_block.span),
);
}
if !self.always_braces
&& !case_block.body.iter().any(|stmt| {
matches!(
stmt,
Statement::VariableDeclaration(_)
| Statement::FunctionDeclaration(_)
)
})
{
ctx.diagnostic_with_fix(
switch_case_braces_diagnostic(
case_block.span(),
Diagnostic::UnnecessaryBraces,
),
|fixer| {
fixer.replace(
case_block.span,
fixer.source_range(Span::new(
case_block.span.start + 1,
case_block.span.end - 1,
)),
)
},
);
}
}
Statement::EmptyStatement(_) => {}
_ => {
if !self.always_braces
&& !&case.consequent.iter().any(|stmt| {
matches!(
stmt,
Statement::VariableDeclaration(_)
| Statement::FunctionDeclaration(_)
)
})
{
return;
}
let Some(first_statement) = &case.consequent.first() else {
return;
};
@ -74,7 +138,10 @@ impl Rule for SwitchCaseBraces {
Span::new(first_statement.span().start, last_statement.span().end);
ctx.diagnostic_with_fix(
switch_case_braces_diagnostic(case_body_span),
switch_case_braces_diagnostic(
case_body_span,
Diagnostic::MissingBraces,
),
|fixer| {
let modified_code = {
let mut formatter = fixer.codegen();
@ -155,6 +222,11 @@ fn test() {
None,
),
("switch(s){case'':/]/}", "switch(s){case '': {/]/}}", None),
(
"switch(foo) { default: {doSomething();} }",
"switch(foo) { default: doSomething(); }",
Some(serde_json::json!(["avoid"])),
),
];
Tester::new(SwitchCaseBraces::NAME, SwitchCaseBraces::PLUGIN, pass, fail)

View file

@ -1,79 +1,79 @@
---
source: crates/oxc_linter/src/tester.rs
---
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
╭─[switch_case_braces.tsx:1:18]
1 │ switch(s){case'':/]/}
· ───
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Add Braces for case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
╭─[switch_case_braces.tsx:1:29]
1 │ switch(something) { case 1: {} case 2: {console.log('something'); break;}}
· ──
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Remove braces in empty case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
╭─[switch_case_braces.tsx:1:37]
1 │ switch(something) { case 1: case 2: console.log('something'); break;}
· ────────────────────────────────
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Add Braces for case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
╭─[switch_case_braces.tsx:1:23]
1 │ switch(foo) { case 1: {} case 2: {} default: { doSomething(); } }
· ──
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Remove braces in empty case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
╭─[switch_case_braces.tsx:1:34]
1 │ switch(foo) { case 1: {} case 2: {} default: { doSomething(); } }
· ──
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Remove braces in empty case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
╭─[switch_case_braces.tsx:1:23]
1 │ switch(foo) { case 1: { /* fallthrough */ } default: {}/* fallthrough */ case 3: { doSomething(); break; } }
· ─────────────────────
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Remove braces in empty case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
╭─[switch_case_braces.tsx:1:54]
1 │ switch(foo) { case 1: { /* fallthrough */ } default: {}/* fallthrough */ case 3: { doSomething(); break; } }
· ──
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Remove braces in empty case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
╭─[switch_case_braces.tsx:1:24]
1 │ switch(foo) { default: doSomething(); }
· ──────────────
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Add Braces for case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
╭─[switch_case_braces.tsx:1:23]
1 │ switch(foo) { case 1: { doSomething(); } break; /* <-- This should be between braces */ }
· ─────────────────────────
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Add Braces for case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
╭─[switch_case_braces.tsx:1:24]
1 │ switch(foo) { default: label: {} }
· ─────────
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Add Braces for case clause.
⚠ eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
⚠ eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
╭─[switch_case_braces.tsx:1:82]
1 │ switch(something) { case 1: case 2: { console.log('something'); break; } case 3: console.log('something else'); }
· ──────────────────────────────
╰────
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
help: Add Braces for case clause.