mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
feat(css/lints): Add selector-max-combinators
rule (#3789)
This commit is contained in:
parent
761fb9c244
commit
e389bef3ad
@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::rules::{
|
use crate::rules::{
|
||||||
at_rule_no_unknown::AtRuleNoUnknownConfig, color_hex_length::ColorHexLengthConfig,
|
at_rule_no_unknown::AtRuleNoUnknownConfig, color_hex_length::ColorHexLengthConfig,
|
||||||
no_invalid_position_at_import_rule::NoInvalidPositionAtImportRuleConfig,
|
no_invalid_position_at_import_rule::NoInvalidPositionAtImportRuleConfig,
|
||||||
selector_max_class::SelectorMaxClassConfig, unit_no_unknown::UnitNoUnknownConfig,
|
selector_max_class::SelectorMaxClassConfig,
|
||||||
|
selector_max_combinators::SelectorMaxCombinatorsConfig, unit_no_unknown::UnitNoUnknownConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
@ -99,6 +100,9 @@ pub struct RulesConfig {
|
|||||||
|
|
||||||
#[serde(default, alias = "unitNoUnknown")]
|
#[serde(default, alias = "unitNoUnknown")]
|
||||||
pub unit_no_unknown: RuleConfig<UnitNoUnknownConfig>,
|
pub unit_no_unknown: RuleConfig<UnitNoUnknownConfig>,
|
||||||
|
|
||||||
|
#[serde(default, alias = "selectorMaxCombinators")]
|
||||||
|
pub selector_max_combinators: RuleConfig<SelectorMaxCombinatorsConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
|
@ -8,7 +8,8 @@ use crate::{
|
|||||||
keyframe_declaration_no_important::keyframe_declaration_no_important,
|
keyframe_declaration_no_important::keyframe_declaration_no_important,
|
||||||
no_empty_source::no_empty_source,
|
no_empty_source::no_empty_source,
|
||||||
no_invalid_position_at_import_rule::no_invalid_position_at_import_rule,
|
no_invalid_position_at_import_rule::no_invalid_position_at_import_rule,
|
||||||
selector_max_class::selector_max_class, unit_no_unknown::unit_no_unknown,
|
selector_max_class::selector_max_class, selector_max_combinators::selector_max_combinators,
|
||||||
|
unit_no_unknown::unit_no_unknown,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ pub mod keyframe_declaration_no_important;
|
|||||||
pub mod no_empty_source;
|
pub mod no_empty_source;
|
||||||
pub mod no_invalid_position_at_import_rule;
|
pub mod no_invalid_position_at_import_rule;
|
||||||
pub mod selector_max_class;
|
pub mod selector_max_class;
|
||||||
|
pub mod selector_max_combinators;
|
||||||
pub mod unit_no_unknown;
|
pub mod unit_no_unknown;
|
||||||
|
|
||||||
pub struct LintParams<'a> {
|
pub struct LintParams<'a> {
|
||||||
@ -53,6 +55,9 @@ pub fn get_rules(LintParams { lint_config }: &LintParams) -> Vec<Box<dyn LintRul
|
|||||||
(&rules_config.color_no_invalid_hex).into(),
|
(&rules_config.color_no_invalid_hex).into(),
|
||||||
));
|
));
|
||||||
rules.push(unit_no_unknown((&rules_config.unit_no_unknown).into()));
|
rules.push(unit_no_unknown((&rules_config.unit_no_unknown).into()));
|
||||||
|
rules.push(selector_max_combinators(
|
||||||
|
(&rules_config.selector_max_combinators).into(),
|
||||||
|
));
|
||||||
|
|
||||||
rules
|
rules
|
||||||
}
|
}
|
||||||
|
49
crates/swc_css_lints/src/rules/selector_max_combinators.rs
Normal file
49
crates/swc_css_lints/src/rules/selector_max_combinators.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use swc_css_ast::*;
|
||||||
|
use swc_css_visit::{Visit, VisitWith};
|
||||||
|
|
||||||
|
use crate::rule::{visitor_rule, LintRule, LintRuleContext};
|
||||||
|
|
||||||
|
pub type SelectorMaxCombinatorsConfig = Option<usize>;
|
||||||
|
|
||||||
|
pub fn selector_max_combinators(
|
||||||
|
ctx: LintRuleContext<SelectorMaxCombinatorsConfig>,
|
||||||
|
) -> Box<dyn LintRule> {
|
||||||
|
let max = ctx.config().unwrap_or(3);
|
||||||
|
visitor_rule(SelectorMaxCombinators { ctx, max })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct SelectorMaxCombinators {
|
||||||
|
ctx: LintRuleContext<SelectorMaxCombinatorsConfig>,
|
||||||
|
max: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectorMaxCombinators {
|
||||||
|
fn build_message(&self, count: usize) -> String {
|
||||||
|
let combinators = if self.max == 1 {
|
||||||
|
"combinator"
|
||||||
|
} else {
|
||||||
|
"combinators"
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"Expected selector to have no more than {} {}, but {} actually.",
|
||||||
|
self.max, combinators, count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visit for SelectorMaxCombinators {
|
||||||
|
fn visit_complex_selector(&mut self, complex_selector: &ComplexSelector) {
|
||||||
|
let count = complex_selector
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.filter(|child| matches!(child, ComplexSelectorChildren::Combinator(..)))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
if count > self.max {
|
||||||
|
self.ctx.report(complex_selector, self.build_message(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
complex_selector.visit_children_with(self);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"selector-max-combinators": ["error", 2]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
.a {}
|
||||||
|
.a .b {}
|
||||||
|
.a .b .c .d {}
|
||||||
|
.a + .b > .c ~ .d {}
|
||||||
|
.a ~ .b || .c + .d {}
|
@ -0,0 +1,18 @@
|
|||||||
|
error: Expected selector to have no more than 2 combinators, but 3 actually.
|
||||||
|
--> $DIR/tests/rules/fail/selector-max-combinators/custom/input.css:3:1
|
||||||
|
|
|
||||||
|
3 | .a .b .c .d {}
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Expected selector to have no more than 2 combinators, but 3 actually.
|
||||||
|
--> $DIR/tests/rules/fail/selector-max-combinators/custom/input.css:4:1
|
||||||
|
|
|
||||||
|
4 | .a + .b > .c ~ .d {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Expected selector to have no more than 2 combinators, but 3 actually.
|
||||||
|
--> $DIR/tests/rules/fail/selector-max-combinators/custom/input.css:5:1
|
||||||
|
|
|
||||||
|
5 | .a ~ .b || .c + .d {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"selector-max-combinators": ["error"]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
.a ~ .b + .c .d > .e {}
|
||||||
|
.a .b .c .d .e {}
|
@ -0,0 +1,12 @@
|
|||||||
|
error: Expected selector to have no more than 3 combinators, but 4 actually.
|
||||||
|
--> $DIR/tests/rules/fail/selector-max-combinators/default/input.css:1:1
|
||||||
|
|
|
||||||
|
1 | .a ~ .b + .c .d > .e {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Expected selector to have no more than 3 combinators, but 4 actually.
|
||||||
|
--> $DIR/tests/rules/fail/selector-max-combinators/default/input.css:2:1
|
||||||
|
|
|
||||||
|
2 | .a .b .c .d .e {}
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"selector-max-combinators": ["error", 5]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
.a {}
|
||||||
|
.a .b {}
|
||||||
|
.a .b .c {}
|
||||||
|
.a .b .c .d {}
|
||||||
|
.a .b .c .d .e {}
|
||||||
|
.a + .b ~ .c > .d .e {}
|
||||||
|
.a + .b ~ .c > .d .e || .f {}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"selector-max-combinators": ["error"]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
.a.b.c.d {}
|
||||||
|
.a .b.c.d {}
|
||||||
|
.a .b .c.d {}
|
||||||
|
.a .b .c .d {}
|
||||||
|
.a + .b .c > .d {}
|
||||||
|
.a ~ .b > .c + .d {}
|
||||||
|
.a .b + .c {}
|
||||||
|
.a + .b ~ .c > .d, .e > .f + .g ~ .h {}
|
Loading…
Reference in New Issue
Block a user