Skip to content

Commit

Permalink
feat(es/lints): Add default-case-last rule (#4913)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArturAralin committed Jun 10, 2022
1 parent 3997f9f commit 4fb932d
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"jsc": {
"lints": {
"default-case-last": [
"error"
]
}
}
}
39 changes: 39 additions & 0 deletions crates/swc/tests/errors/lints/default-case-last/default/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
switch (foo) { default: bar(); break; case 1: baz(); break; }
switch (foo) { default: break; case 1: break; }
switch (foo) { default: break; case 1: }
switch (foo) { default: case 1: break; }
switch (foo) { default: case 1: }
switch (foo) { default: break; case 1: break; case 2: break; }
switch (foo) { default: case 1: break; case 2: break; }
switch (foo) { default: case 1: case 2: break; }
switch (foo) { default: case 1: case 2: }
switch (foo) { case 1: break; default: break; case 2: break; }
switch (foo) { case 1: default: break; case 2: break; }
switch (foo) { case 1: break; default: case 2: break; }
switch (foo) { case 1: default: case 2: break; }
switch (foo) { case 1: default: case 2: }

// valid
switch (foo) { }
switch (foo) { case 1: bar(); break; }
switch (foo) { case 1: break; }
switch (foo) { case 1: }
switch (foo) { case 1: bar(); break; case 2: baz(); break; }
switch (foo) { case 1: break; case 2: break; }
switch (foo) { case 1: case 2: break; }
switch (foo) { case 1: case 2: }
switch (foo) { default: bar(); break; }
switch (foo) { default: bar(); }
switch (foo) { default: break; }
switch (foo) { default: }
switch (foo) { case 1: break; default: break; }
switch (foo) { case 1: break; default: }
switch (foo) { case 1: default: break; }
switch (foo) { case 1: default: }
switch (foo) { case 1: baz(); break; case 2: quux(); break; default: quuux(); break; }
switch (foo) { case 1: break; case 2: break; default: break; }
switch (foo) { case 1: break; case 2: break; default: }
switch (foo) { case 1: case 2: break; default: break; }
switch (foo) { case 1: break; case 2: default: break; }
switch (foo) { case 1: break; case 2: default: }
switch (foo) { case 1: case 2: default: }
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

x Default clause should be the last clause
,----
1 | switch (foo) { default: bar(); break; case 1: baz(); break; }
: ^^^^^^^^^^^^^^^^^^^^^^
`----

x Default clause should be the last clause
,----
2 | switch (foo) { default: break; case 1: break; }
: ^^^^^^^^^^^^^^^
`----

x Default clause should be the last clause
,----
3 | switch (foo) { default: break; case 1: }
: ^^^^^^^^^^^^^^^
`----

x Default clause should be the last clause
,----
4 | switch (foo) { default: case 1: break; }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
5 | switch (foo) { default: case 1: }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
6 | switch (foo) { default: break; case 1: break; case 2: break; }
: ^^^^^^^^^^^^^^^
`----

x Default clause should be the last clause
,----
7 | switch (foo) { default: case 1: break; case 2: break; }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
8 | switch (foo) { default: case 1: case 2: break; }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
9 | switch (foo) { default: case 1: case 2: }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
10 | switch (foo) { case 1: break; default: break; case 2: break; }
: ^^^^^^^^^^^^^^^
`----

x Default clause should be the last clause
,----
11 | switch (foo) { case 1: default: break; case 2: break; }
: ^^^^^^^^^^^^^^^
`----

x Default clause should be the last clause
,----
12 | switch (foo) { case 1: break; default: case 2: break; }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
13 | switch (foo) { case 1: default: case 2: break; }
: ^^^^^^^^
`----

x Default clause should be the last clause
,----
14 | switch (foo) { case 1: default: case 2: }
: ^^^^^^^^
`----
4 changes: 4 additions & 0 deletions crates/swc_ecma_lints/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,8 @@ pub struct LintConfig {
#[cfg(feature = "non_critical_lints")]
#[serde(default, alias = "noSparseArrays")]
pub no_sparse_arrays: RuleConfig<()>,

#[cfg(feature = "non_critical_lints")]
#[serde(default, alias = "defaultCaseLast")]
pub default_case_last: RuleConfig<()>,
}
66 changes: 66 additions & 0 deletions crates/swc_ecma_lints/src/rules/default_case_last.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use swc_common::{errors::HANDLER, Span};
use swc_ecma_ast::*;
use swc_ecma_visit::{Visit, VisitWith};

use crate::{
config::{LintRuleReaction, RuleConfig},
rule::{visitor_rule, Rule},
};

const MESSAGE: &str = "Default clause should be the last clause";

pub fn default_case_last(config: &RuleConfig<()>) -> Option<Box<dyn Rule>> {
let rule_reaction = config.get_rule_reaction();

match rule_reaction {
LintRuleReaction::Off => None,
_ => Some(visitor_rule(DefaultCaseLast::new(rule_reaction))),
}
}

#[derive(Debug, Default)]
struct DefaultCaseLast {
expected_reaction: LintRuleReaction,
}

impl DefaultCaseLast {
fn new(expected_reaction: LintRuleReaction) -> Self {
Self { expected_reaction }
}

fn emit_report(&self, span: Span) {
HANDLER.with(|handler| match self.expected_reaction {
LintRuleReaction::Error => {
handler.struct_span_err(span, MESSAGE).emit();
}
LintRuleReaction::Warning => {
handler.struct_span_warn(span, MESSAGE).emit();
}
_ => {}
});
}

fn check_case(&self, cases_count: usize, pos: usize, case: &SwitchCase) {
if case.test.is_none() && pos != cases_count {
self.emit_report(case.span);
}
}
}

impl Visit for DefaultCaseLast {
fn visit_switch_stmt(&mut self, switch_stmt: &SwitchStmt) {
let cases_count = switch_stmt.cases.len();

switch_stmt.discriminant.visit_children_with(self);

switch_stmt
.cases
.iter()
.enumerate()
.for_each(|(idx, switch_case)| {
self.check_case(cases_count, idx + 1, switch_case);

switch_case.visit_children_with(self);
});
}
}
5 changes: 5 additions & 0 deletions crates/swc_ecma_lints/src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod utils;
#[cfg(feature = "non_critical_lints")]
#[path = ""]
pub(crate) mod non_critical_lints {
pub mod default_case_last;
pub mod default_param_last;
pub mod dot_notation;
pub mod eqeqeq;
Expand Down Expand Up @@ -176,6 +177,10 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
rules.extend(no_sparse_arrays::no_sparse_arrays(
&lint_config.no_sparse_arrays,
));

rules.extend(default_case_last::default_case_last(
&lint_config.default_case_last,
));
}

rules
Expand Down

1 comment on commit 4fb932d

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 4fb932d Previous: 4f1e046 Ratio
es/full/minify/libraries/antd 2481362458 ns/iter (± 53907924) 2233382360 ns/iter (± 53380412) 1.11
es/full/minify/libraries/d3 570017879 ns/iter (± 30751709) 549080545 ns/iter (± 14918325) 1.04
es/full/minify/libraries/echarts 2756267767 ns/iter (± 40695053) 2582677458 ns/iter (± 14901607) 1.07
es/full/minify/libraries/jquery 129043926 ns/iter (± 12963302) 108833457 ns/iter (± 1242132) 1.19
es/full/minify/libraries/lodash 175304869 ns/iter (± 5812123) 159541800 ns/iter (± 1323965) 1.10
es/full/minify/libraries/moment 70971654 ns/iter (± 1162136) 63738409 ns/iter (± 468360) 1.11
es/full/minify/libraries/react 24515582 ns/iter (± 838444) 20634564 ns/iter (± 105681) 1.19
es/full/minify/libraries/terser 829899856 ns/iter (± 22034345) 544548641 ns/iter (± 12071967) 1.52
es/full/minify/libraries/three 754168117 ns/iter (± 22259138) 780971084 ns/iter (± 11720362) 0.97
es/full/minify/libraries/typescript 5606525605 ns/iter (± 87348267) 5070068953 ns/iter (± 12975794) 1.11
es/full/minify/libraries/victory 1045537116 ns/iter (± 24444044) 1008490634 ns/iter (± 5786864) 1.04
es/full/minify/libraries/vue 194635594 ns/iter (± 11694018) 171912304 ns/iter (± 2156552) 1.13
es/full/codegen/es3 39274 ns/iter (± 2086) 34324 ns/iter (± 359) 1.14
es/full/codegen/es5 38928 ns/iter (± 3294) 34206 ns/iter (± 153) 1.14
es/full/codegen/es2015 37776 ns/iter (± 4771) 34246 ns/iter (± 140) 1.10
es/full/codegen/es2016 37519 ns/iter (± 2053) 34253 ns/iter (± 134) 1.10
es/full/codegen/es2017 38530 ns/iter (± 1826) 34254 ns/iter (± 162) 1.12
es/full/codegen/es2018 37923 ns/iter (± 2742) 34258 ns/iter (± 145) 1.11
es/full/codegen/es2019 36855 ns/iter (± 2178) 34218 ns/iter (± 159) 1.08
es/full/codegen/es2020 37452 ns/iter (± 1660) 34211 ns/iter (± 147) 1.09
es/full/all/es3 224520732 ns/iter (± 7577631) 192526616 ns/iter (± 541731) 1.17
es/full/all/es5 213096300 ns/iter (± 6395150) 182362115 ns/iter (± 685792) 1.17
es/full/all/es2015 168329335 ns/iter (± 8173054) 144903030 ns/iter (± 502551) 1.16
es/full/all/es2016 166624042 ns/iter (± 5264369) 144180921 ns/iter (± 936204) 1.16
es/full/all/es2017 166371852 ns/iter (± 6870183) 143264998 ns/iter (± 545609) 1.16
es/full/all/es2018 160758832 ns/iter (± 6660463) 141098273 ns/iter (± 964207) 1.14
es/full/all/es2019 164893386 ns/iter (± 6577377) 140652596 ns/iter (± 543978) 1.17
es/full/all/es2020 155740147 ns/iter (± 5645549) 136178140 ns/iter (± 603649) 1.14
es/full/parser 721885 ns/iter (± 76783) 587917 ns/iter (± 55954) 1.23
es/full/base/fixer 37137 ns/iter (± 1882) 26928 ns/iter (± 183) 1.38
es/full/base/resolver_and_hygiene 170357 ns/iter (± 9470) 140449 ns/iter (± 2314) 1.21
serialization of ast node 194 ns/iter (± 12) 178 ns/iter (± 1) 1.09
serialization of serde 197 ns/iter (± 11) 180 ns/iter (± 0) 1.09

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.