/* 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<&::NamespaceUrl>, _local_name: &::LocalName, _local_name_lower: &::LocalName, ) -> bool { true } /// Visit a simple selector. fn visit_simple_selector(&mut self, _: &Component) -> 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], ) -> 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) -> 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 ) or /// :nth-last-child(.. of ) const NTH_OF = 1 << 3; } } impl SelectorListKind { /// Construct a SelectorListKind for the corresponding component. pub fn from_component(component: &Component) -> 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 ) or /// :nth-last-child(.. of ) pub fn in_nth_of(&self) -> bool { self.intersects(SelectorListKind::NTH_OF) } }