swc_css_lints/rules/
selector_max_combinators.rs1use swc_css_ast::*;
2use swc_css_visit::{Visit, VisitWith};
3
4use crate::rule::{visitor_rule, LintRule, LintRuleContext};
5
6pub type SelectorMaxCombinatorsConfig = Option<usize>;
7
8pub fn selector_max_combinators(
9 ctx: LintRuleContext<SelectorMaxCombinatorsConfig>,
10) -> Box<dyn LintRule> {
11 let max = ctx.config().unwrap_or(3);
12 visitor_rule(ctx.reaction(), SelectorMaxCombinators { ctx, max })
13}
14
15#[derive(Debug, Default)]
16struct SelectorMaxCombinators {
17 ctx: LintRuleContext<SelectorMaxCombinatorsConfig>,
18 max: usize,
19}
20
21impl SelectorMaxCombinators {
22 fn build_message(&self, count: usize) -> String {
23 let combinators = if self.max == 1 {
24 "combinator"
25 } else {
26 "combinators"
27 };
28 format!(
29 "Expected selector to have no more than {} {}, but {} actually.",
30 self.max, combinators, count
31 )
32 }
33}
34
35impl Visit for SelectorMaxCombinators {
36 fn visit_complex_selector(&mut self, complex_selector: &ComplexSelector) {
37 let count = complex_selector
38 .children
39 .iter()
40 .filter(|child| matches!(child, ComplexSelectorChildren::Combinator(..)))
41 .count();
42
43 if count > self.max {
44 self.ctx.report(complex_selector, self.build_message(count));
45 }
46
47 complex_selector.visit_children_with(self);
48 }
49}