selectors/visitor.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Visitor traits for selectors.
#![deny(missing_docs)]
use crate::attr::NamespaceConstraint;
use crate::parser::{Combinator, Component, Selector, SelectorImpl};
/// A trait to visit selector properties.
///
/// All the `visit_foo` methods return a boolean indicating whether the
/// traversal should continue or not.
pub trait SelectorVisitor: Sized {
/// The selector implementation this visitor wants to visit.
type Impl: SelectorImpl;
/// Visit an attribute selector that may match (there are other selectors
/// that may never match, like those containing whitespace or the empty
/// string).
fn visit_attribute_selector(
&mut self,
_namespace: &NamespaceConstraint<&<Self::Impl as SelectorImpl>::NamespaceUrl>,
_local_name: &<Self::Impl as SelectorImpl>::LocalName,
_local_name_lower: &<Self::Impl as SelectorImpl>::LocalName,
) -> bool {
true
}
/// Visit a simple selector.
fn visit_simple_selector(&mut self, _: &Component<Self::Impl>) -> bool {
true
}
/// Visit a nested selector list. The caller is responsible to call visit
/// into the internal selectors if / as needed.
///
/// The default implementation does this.
fn visit_selector_list(
&mut self,
_list_kind: SelectorListKind,
list: &[Selector<Self::Impl>],
) -> bool {
for nested in list {
if !nested.visit(self) {
return false;
}
}
true
}
/// Visits a complex selector.
///
/// Gets the combinator to the right of the selector, or `None` if the
/// selector is the rightmost one.
fn visit_complex_selector(&mut self, _combinator_to_right: Option<Combinator>) -> bool {
true
}
}
bitflags! {
/// The kinds of components the visitor is visiting the selector list of, if any
#[derive(Clone, Copy, Default)]
pub struct SelectorListKind: u8 {
/// The visitor is inside :not(..)
const NEGATION = 1 << 0;
/// The visitor is inside :is(..)
const IS = 1 << 1;
/// The visitor is inside :where(..)
const WHERE = 1 << 2;
/// The visitor is inside :nth-child(.. of <selector list>) or
/// :nth-last-child(.. of <selector list>)
const NTH_OF = 1 << 3;
}
}
impl SelectorListKind {
/// Construct a SelectorListKind for the corresponding component.
pub fn from_component<Impl: SelectorImpl>(component: &Component<Impl>) -> Self {
match component {
Component::Negation(_) => SelectorListKind::NEGATION,
Component::Is(_) => SelectorListKind::IS,
Component::Where(_) => SelectorListKind::WHERE,
Component::NthOf(_) => SelectorListKind::NTH_OF,
_ => SelectorListKind::empty(),
}
}
/// Whether the visitor is inside :not(..)
pub fn in_negation(&self) -> bool {
self.intersects(SelectorListKind::NEGATION)
}
/// Whether the visitor is inside :is(..)
pub fn in_is(&self) -> bool {
self.intersects(SelectorListKind::IS)
}
/// Whether the visitor is inside :where(..)
pub fn in_where(&self) -> bool {
self.intersects(SelectorListKind::WHERE)
}
/// Whether the visitor is inside :nth-child(.. of <selector list>) or
/// :nth-last-child(.. of <selector list>)
pub fn in_nth_of(&self) -> bool {
self.intersects(SelectorListKind::NTH_OF)
}
}