swc_css_lints/rules/
at_rule_no_unknown.rs1use serde::{Deserialize, Serialize};
2use swc_css_ast::*;
3use swc_css_visit::{Visit, VisitWith};
4
5use crate::{
6 pattern::NamePattern,
7 rule::{visitor_rule, LintRule, LintRuleContext},
8 ConfigError,
9};
10
11#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub struct AtRuleNoUnknownConfig {
14 ignore_at_rules: Option<Vec<String>>,
15}
16
17pub fn at_rule_no_unknown(
18 ctx: LintRuleContext<AtRuleNoUnknownConfig>,
19) -> Result<Box<dyn LintRule>, ConfigError> {
20 let ignored = ctx
21 .config()
22 .ignore_at_rules
23 .clone()
24 .unwrap_or_default()
25 .into_iter()
26 .map(NamePattern::try_from)
27 .collect::<Result<_, _>>()?;
28 Ok(visitor_rule(
29 ctx.reaction(),
30 AtRuleNoUnknown { ctx, ignored },
31 ))
32}
33
34#[derive(Debug, Default)]
35struct AtRuleNoUnknown {
36 ctx: LintRuleContext<AtRuleNoUnknownConfig>,
37 ignored: Vec<NamePattern>,
38}
39
40impl Visit for AtRuleNoUnknown {
41 fn visit_at_rule(&mut self, at_rule: &AtRule) {
42 if let AtRuleName::Ident(Ident { value, .. }) = &at_rule.name {
43 if let Some(AtRulePrelude::ListOfComponentValues(_)) = at_rule.prelude.as_deref() {
44 if self.ignored.iter().all(|item| !item.is_match(value)) {
45 let message = format!("Unexpected unknown at-rule \"@{}\".", &value);
46
47 self.ctx.report(&at_rule.name, message);
48 }
49 }
50 }
51
52 at_rule.visit_children_with(self);
53 }
54}