Skip to content

Commit e8e6917

Browse files
authored
feat(linter): unicorn/switch-cases-braces support options (#8704)
close #8492
1 parent 6589c3b commit e8e6917

File tree

2 files changed

+102
-30
lines changed

2 files changed

+102
-30
lines changed

crates/oxc_linter/src/rules/unicorn/switch_case_braces.rs

+80-8
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,33 @@ use oxc_span::{GetSpan, Span};
55

66
use crate::{context::LintContext, rule::Rule, AstNode};
77

8-
fn switch_case_braces_diagnostic(span: Span) -> OxcDiagnostic {
9-
OxcDiagnostic::warn(
10-
" Empty switch case shouldn't have braces and not-empty case should have braces around it.",
11-
)
12-
.with_help("There is less visual clutter for empty cases and proper scope for non-empty cases.")
8+
#[derive(Clone, Copy)]
9+
enum Diagnostic {
10+
EmptyClause,
11+
MissingBraces,
12+
UnnecessaryBraces,
13+
}
14+
15+
fn switch_case_braces_diagnostic(span: Span, diagnostic_type: Diagnostic) -> OxcDiagnostic {
16+
(match diagnostic_type {
17+
Diagnostic::EmptyClause => OxcDiagnostic::warn("Unexpected braces in empty case clause.")
18+
.with_help("Remove braces in empty case clause."),
19+
Diagnostic::MissingBraces => OxcDiagnostic::warn("Missing braces in case clause.")
20+
.with_help("Add Braces for case clause."),
21+
Diagnostic::UnnecessaryBraces => OxcDiagnostic::warn("Unnecessary braces in case clause.")
22+
.with_help("Remove Braces for case clause."),
23+
})
1324
.with_label(span)
1425
}
1526

1627
#[derive(Debug, Default, Clone)]
17-
pub struct SwitchCaseBraces;
28+
pub struct SwitchCaseBraces {
29+
// true - "always" (default)
30+
// - Always report when clause is not a BlockStatement
31+
// false - "avoid"
32+
// - Only allow braces when there are variable declaration or function declaration which requires a scope.
33+
always_braces: bool,
34+
}
1835

1936
declare_oxc_lint!(
2037
/// ### What it does
@@ -41,6 +58,12 @@ declare_oxc_lint!(
4158
);
4259

4360
impl Rule for SwitchCaseBraces {
61+
fn from_configuration(value: serde_json::Value) -> Self {
62+
let always = value.get(0).map_or(true, |v| v.as_str() != Some("avoid"));
63+
64+
Self { always_braces: always }
65+
}
66+
4467
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
4568
let AstKind::SwitchStatement(switch) = node.kind() else {
4669
return;
@@ -56,13 +79,54 @@ impl Rule for SwitchCaseBraces {
5679
Statement::BlockStatement(case_block) => {
5780
if case_block.body.is_empty() {
5881
ctx.diagnostic_with_fix(
59-
switch_case_braces_diagnostic(case_block.span),
82+
switch_case_braces_diagnostic(
83+
case_block.span,
84+
Diagnostic::EmptyClause,
85+
),
6086
|fixer| fixer.delete_range(case_block.span),
6187
);
6288
}
89+
90+
if !self.always_braces
91+
&& !case_block.body.iter().any(|stmt| {
92+
matches!(
93+
stmt,
94+
Statement::VariableDeclaration(_)
95+
| Statement::FunctionDeclaration(_)
96+
)
97+
})
98+
{
99+
ctx.diagnostic_with_fix(
100+
switch_case_braces_diagnostic(
101+
case_block.span(),
102+
Diagnostic::UnnecessaryBraces,
103+
),
104+
|fixer| {
105+
fixer.replace(
106+
case_block.span,
107+
fixer.source_range(Span::new(
108+
case_block.span.start + 1,
109+
case_block.span.end - 1,
110+
)),
111+
)
112+
},
113+
);
114+
}
63115
}
64116
Statement::EmptyStatement(_) => {}
65117
_ => {
118+
if !self.always_braces
119+
&& !&case.consequent.iter().any(|stmt| {
120+
matches!(
121+
stmt,
122+
Statement::VariableDeclaration(_)
123+
| Statement::FunctionDeclaration(_)
124+
)
125+
})
126+
{
127+
return;
128+
}
129+
66130
let Some(first_statement) = &case.consequent.first() else {
67131
return;
68132
};
@@ -74,7 +138,10 @@ impl Rule for SwitchCaseBraces {
74138
Span::new(first_statement.span().start, last_statement.span().end);
75139

76140
ctx.diagnostic_with_fix(
77-
switch_case_braces_diagnostic(case_body_span),
141+
switch_case_braces_diagnostic(
142+
case_body_span,
143+
Diagnostic::MissingBraces,
144+
),
78145
|fixer| {
79146
let modified_code = {
80147
let mut formatter = fixer.codegen();
@@ -155,6 +222,11 @@ fn test() {
155222
None,
156223
),
157224
("switch(s){case'':/]/}", "switch(s){case '': {/]/}}", None),
225+
(
226+
"switch(foo) { default: {doSomething();} }",
227+
"switch(foo) { default: doSomething(); }",
228+
Some(serde_json::json!(["avoid"])),
229+
),
158230
];
159231

160232
Tester::new(SwitchCaseBraces::NAME, SwitchCaseBraces::PLUGIN, pass, fail)
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,79 @@
11
---
22
source: crates/oxc_linter/src/tester.rs
33
---
4-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
4+
eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
55
╭─[switch_case_braces.tsx:1:18]
66
1switch(s){case'':/]/}
77
· ───
88
╰────
9-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
9+
help: Add Braces for case clause.
1010

11-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
11+
eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
1212
╭─[switch_case_braces.tsx:1:29]
1313
1switch(something) { case 1: {} case 2: {console.log('something'); break;}}
1414
· ──
1515
╰────
16-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
16+
help: Remove braces in empty case clause.
1717

18-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
18+
eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
1919
╭─[switch_case_braces.tsx:1:37]
2020
1switch(something) { case 1: case 2: console.log('something'); break;}
2121
· ────────────────────────────────
2222
╰────
23-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
23+
help: Add Braces for case clause.
2424

25-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
25+
eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
2626
╭─[switch_case_braces.tsx:1:23]
2727
1switch(foo) { case 1: {} case 2: {} default: { doSomething(); } }
2828
· ──
2929
╰────
30-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
30+
help: Remove braces in empty case clause.
3131

32-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
32+
eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
3333
╭─[switch_case_braces.tsx:1:34]
3434
1switch(foo) { case 1: {} case 2: {} default: { doSomething(); } }
3535
· ──
3636
╰────
37-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
37+
help: Remove braces in empty case clause.
3838

39-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
39+
eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
4040
╭─[switch_case_braces.tsx:1:23]
4141
1switch(foo) { case 1: { /* fallthrough */ } default: {}/* fallthrough */ case 3: { doSomething(); break; } }
4242
· ─────────────────────
4343
╰────
44-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
44+
help: Remove braces in empty case clause.
4545

46-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
46+
eslint-plugin-unicorn(switch-case-braces): Unexpected braces in empty case clause.
4747
╭─[switch_case_braces.tsx:1:54]
4848
1switch(foo) { case 1: { /* fallthrough */ } default: {}/* fallthrough */ case 3: { doSomething(); break; } }
4949
· ──
5050
╰────
51-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
51+
help: Remove braces in empty case clause.
5252

53-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
53+
eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
5454
╭─[switch_case_braces.tsx:1:24]
5555
1switch(foo) { default: doSomething(); }
5656
· ──────────────
5757
╰────
58-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
58+
help: Add Braces for case clause.
5959

60-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
60+
eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
6161
╭─[switch_case_braces.tsx:1:23]
6262
1switch(foo) { case 1: { doSomething(); } break; /* <-- This should be between braces */ }
6363
· ─────────────────────────
6464
╰────
65-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
65+
help: Add Braces for case clause.
6666

67-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
67+
eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
6868
╭─[switch_case_braces.tsx:1:24]
6969
1switch(foo) { default: label: {} }
7070
· ─────────
7171
╰────
72-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
72+
help: Add Braces for case clause.
7373

74-
eslint-plugin-unicorn(switch-case-braces): Empty switch case shouldn't have braces and not-empty case should have braces around it.
74+
eslint-plugin-unicorn(switch-case-braces): Missing braces in case clause.
7575
╭─[switch_case_braces.tsx:1:82]
7676
1switch(something) { case 1: case 2: { console.log('something'); break; } case 3: console.log('something else'); }
7777
· ──────────────────────────────
7878
╰────
79-
help: There is less visual clutter for empty cases and proper scope for non-empty cases.
79+
help: Add Braces for case clause.

0 commit comments

Comments
 (0)