Skip to main content

css_sanitizer/
policy.rs

1use lightningcss::properties::Property;
2use lightningcss::rules::CssRule;
3use lightningcss::rules::counter_style::CounterStyleRule;
4use lightningcss::rules::font_face::FontFaceProperty;
5use lightningcss::rules::font_feature_values::{FontFeatureSubrule, FontFeatureValuesRule};
6use lightningcss::rules::font_palette_values::FontPaletteValuesProperty;
7use lightningcss::rules::page::{PageMarginRule, PageRule};
8use lightningcss::rules::view_transition::ViewTransitionProperty;
9use lightningcss::rules::viewport::ViewportRule;
10use lightningcss::selector::SelectorList;
11
12/// Controls how the sanitizer should handle the current node.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum NodeAction {
15    /// Continue with the sanitizer's normal traversal for this node.
16    Continue,
17    /// Keep this node, but skip any deeper sanitization for its children.
18    Skip,
19    /// Drop this node entirely.
20    Drop,
21}
22
23/// Context for a CSS rule node.
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct RuleContext {
26    pub depth: usize,
27}
28
29/// Context for a selector list.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct SelectorContext {
32    pub depth: usize,
33}
34
35/// Context for a normal CSS property.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct PropertyContext {
38    pub depth: usize,
39    pub important: bool,
40}
41
42/// Context for descriptor-style properties that are not represented as
43/// [`Property`](lightningcss::properties::Property).
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct DescriptorContext {
46    pub depth: usize,
47}
48
49/// Advanced policy hook interface for sanitizing lightningcss AST nodes.
50///
51/// The default implementation keeps everything and only recurses normally.
52/// Implementors can inspect or mutate AST nodes directly and return
53/// [`NodeAction::Drop`] to remove them or [`NodeAction::Skip`] to keep the node
54/// while bypassing deeper sanitization for its children.
55pub trait CssSanitizationPolicy {
56    /// Called for every [`CssRule`](lightningcss::rules::CssRule).
57    fn visit_rule(&self, _rule: &mut CssRule<'_>, _ctx: RuleContext) -> NodeAction {
58        NodeAction::Continue
59    }
60
61    /// Called for all selector lists unless a more specific selector hook is
62    /// overridden.
63    fn visit_selector_list(
64        &self,
65        _selectors: &mut SelectorList<'_>,
66        _ctx: SelectorContext,
67    ) -> NodeAction {
68        NodeAction::Continue
69    }
70
71    /// Called for selectors on normal style rules.
72    fn visit_style_rule_selectors(
73        &self,
74        selectors: &mut SelectorList<'_>,
75        ctx: SelectorContext,
76    ) -> NodeAction {
77        self.visit_selector_list(selectors, ctx)
78    }
79
80    /// Called for selectors on nesting rules.
81    fn visit_nesting_selectors(
82        &self,
83        selectors: &mut SelectorList<'_>,
84        ctx: SelectorContext,
85    ) -> NodeAction {
86        self.visit_selector_list(selectors, ctx)
87    }
88
89    /// Called for all normal CSS declarations represented as
90    /// [`Property`](lightningcss::properties::Property) unless a more specific
91    /// property hook is overridden.
92    fn visit_property(&self, _property: &mut Property<'_>, _ctx: PropertyContext) -> NodeAction {
93        NodeAction::Continue
94    }
95
96    /// Called for parsed declaration lists such as `style=""` content.
97    fn visit_declaration_list_property(
98        &self,
99        property: &mut Property<'_>,
100        ctx: PropertyContext,
101    ) -> NodeAction {
102        self.visit_property(property, ctx)
103    }
104
105    /// Called for declarations inside normal style rules.
106    fn visit_style_property(
107        &self,
108        property: &mut Property<'_>,
109        ctx: PropertyContext,
110    ) -> NodeAction {
111        self.visit_property(property, ctx)
112    }
113
114    /// Called for declarations inside nested declarations rules.
115    fn visit_nested_declarations_property(
116        &self,
117        property: &mut Property<'_>,
118        ctx: PropertyContext,
119    ) -> NodeAction {
120        self.visit_property(property, ctx)
121    }
122
123    /// Called for declarations inside keyframes.
124    fn visit_keyframe_property(
125        &self,
126        property: &mut Property<'_>,
127        ctx: PropertyContext,
128    ) -> NodeAction {
129        self.visit_property(property, ctx)
130    }
131
132    /// Called for declarations inside `@page`.
133    fn visit_page_property(&self, property: &mut Property<'_>, ctx: PropertyContext) -> NodeAction {
134        self.visit_property(property, ctx)
135    }
136
137    /// Called for declarations inside page margin rules.
138    fn visit_page_margin_property(
139        &self,
140        property: &mut Property<'_>,
141        ctx: PropertyContext,
142    ) -> NodeAction {
143        self.visit_property(property, ctx)
144    }
145
146    /// Called for declarations inside `@counter-style`.
147    fn visit_counter_style_property(
148        &self,
149        property: &mut Property<'_>,
150        ctx: PropertyContext,
151    ) -> NodeAction {
152        self.visit_property(property, ctx)
153    }
154
155    /// Called for declarations inside `@viewport`.
156    fn visit_viewport_property(
157        &self,
158        property: &mut Property<'_>,
159        ctx: PropertyContext,
160    ) -> NodeAction {
161        self.visit_property(property, ctx)
162    }
163
164    /// Called for `@font-face` descriptors.
165    fn visit_font_face_property(
166        &self,
167        _property: &mut FontFaceProperty<'_>,
168        _ctx: DescriptorContext,
169    ) -> NodeAction {
170        NodeAction::Continue
171    }
172
173    /// Called for `@font-palette-values` descriptors.
174    fn visit_font_palette_values_property(
175        &self,
176        _property: &mut FontPaletteValuesProperty<'_>,
177        _ctx: DescriptorContext,
178    ) -> NodeAction {
179        NodeAction::Continue
180    }
181
182    /// Called for `@view-transition` descriptors.
183    fn visit_view_transition_property(
184        &self,
185        _property: &mut ViewTransitionProperty<'_>,
186        _ctx: DescriptorContext,
187    ) -> NodeAction {
188        NodeAction::Continue
189    }
190
191    /// Called for `@page` rules before declaration filtering.
192    fn visit_page_rule(&self, _rule: &mut PageRule<'_>, _ctx: RuleContext) -> NodeAction {
193        NodeAction::Continue
194    }
195
196    /// Called for page margin rules nested inside `@page`.
197    fn visit_page_margin_rule(
198        &self,
199        _rule: &mut PageMarginRule<'_>,
200        _ctx: RuleContext,
201    ) -> NodeAction {
202        NodeAction::Continue
203    }
204
205    /// Called for `@counter-style` rules before declaration filtering.
206    fn visit_counter_style_rule(
207        &self,
208        _rule: &mut CounterStyleRule<'_>,
209        _ctx: RuleContext,
210    ) -> NodeAction {
211        NodeAction::Continue
212    }
213
214    /// Called for `@viewport` rules before declaration filtering.
215    fn visit_viewport_rule(&self, _rule: &mut ViewportRule<'_>, _ctx: RuleContext) -> NodeAction {
216        NodeAction::Continue
217    }
218
219    /// Called for `@font-feature-values` rules.
220    fn visit_font_feature_values_rule(
221        &self,
222        _rule: &mut FontFeatureValuesRule<'_>,
223        _ctx: RuleContext,
224    ) -> NodeAction {
225        NodeAction::Continue
226    }
227
228    /// Called for sub-rules nested inside `@font-feature-values`.
229    fn visit_font_feature_values_subrule(
230        &self,
231        _subrule: &mut FontFeatureSubrule<'_>,
232        _ctx: RuleContext,
233    ) -> NodeAction {
234        NodeAction::Continue
235    }
236}