1use crate::attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
6use crate::attr::{NamespaceConstraint, ParsedAttrSelectorOperation};
7use crate::attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE};
8use crate::bloom::BLOOM_HASH_MASK;
9use crate::builder::{SelectorBuilder, SelectorFlags, SpecificityAndFlags};
10use crate::context::QuirksMode;
11use crate::sink::Push;
12pub use crate::visitor::SelectorVisitor;
13use cssparser::parse_nth;
14use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
15use cssparser::{CowRcStr, Delimiter, SourceLocation};
16use cssparser::{Parser as CssParser, ToCss, Token};
17use precomputed_hash::PrecomputedHash;
18use smallvec::{smallvec, SmallVec};
19use std::borrow::Borrow;
20use std::fmt::{self, Debug};
21use std::iter::Rev;
22use std::slice;
23
24pub trait PseudoElement<'i>: Sized + ToCss {
26 type Impl: SelectorImpl<'i>;
28
29 fn accepts_state_pseudo_classes(&self) -> bool {
32 false
33 }
34
35 fn valid_after_slotted(&self) -> bool {
37 false
38 }
39
40 fn is_webkit_scrollbar(&self) -> bool {
41 false
42 }
43
44 fn is_view_transition(&self) -> bool {
45 false
46 }
47
48 fn is_unknown(&self) -> bool {
49 false
50 }
51}
52
53pub trait NonTSPseudoClass<'i>: Sized + ToCss {
55 type Impl: SelectorImpl<'i>;
57
58 fn is_active_or_hover(&self) -> bool;
60
61 fn is_user_action_state(&self) -> bool;
65
66 fn is_valid_before_webkit_scrollbar(&self) -> bool {
67 true
68 }
69
70 fn is_valid_after_webkit_scrollbar(&self) -> bool {
71 false
72 }
73
74 fn visit<V>(&self, _visitor: &mut V) -> bool
75 where
76 V: SelectorVisitor<'i, Impl = Self::Impl>,
77 {
78 true
79 }
80}
81
82fn to_ascii_lowercase<'i>(s: CowRcStr<'i>) -> CowRcStr<'i> {
85 if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
86 let mut string = s.to_string();
87 string[first_uppercase..].make_ascii_lowercase();
88 string.into()
89 } else {
90 s
91 }
92}
93
94bitflags! {
95 #[derive(PartialEq, Eq, Clone, Copy)]
97 struct SelectorParsingState: u16 {
98 const SKIP_DEFAULT_NAMESPACE = 1 << 0;
101
102 const AFTER_SLOTTED = 1 << 1;
107 const AFTER_PART = 1 << 2;
112 const AFTER_PSEUDO_ELEMENT = 1 << 3;
119 const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
124
125 const AFTER_PSEUDO = Self::AFTER_PART.bits() | Self::AFTER_SLOTTED.bits() | Self::AFTER_PSEUDO_ELEMENT.bits();
127
128 const DISALLOW_COMBINATORS = 1 << 5;
130
131 const DISALLOW_PSEUDOS = 1 << 6;
133
134 const AFTER_NESTING = 1 << 7;
136
137 const AFTER_WEBKIT_SCROLLBAR = 1 << 8;
138 const AFTER_VIEW_TRANSITION = 1 << 9;
139 const AFTER_UNKNOWN_PSEUDO_ELEMENT = 1 << 10;
140 }
141}
142
143impl SelectorParsingState {
144 #[inline]
145 fn allows_pseudos(self) -> bool {
146 !self.intersects(Self::AFTER_PSEUDO_ELEMENT | Self::DISALLOW_PSEUDOS)
148 }
149
150 #[inline]
151 fn allows_slotted(self) -> bool {
152 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
153 }
154
155 #[inline]
156 fn allows_part(self) -> bool {
157 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
158 }
159
160 #[inline]
165 fn allows_custom_functional_pseudo_classes(self) -> bool {
166 !self.intersects(Self::AFTER_PSEUDO)
167 }
168
169 #[inline]
170 fn allows_non_functional_pseudo_classes(self) -> bool {
171 !self.intersects(Self::AFTER_SLOTTED | Self::AFTER_NON_STATEFUL_PSEUDO_ELEMENT)
172 }
173
174 #[inline]
175 fn allows_tree_structural_pseudo_classes(self) -> bool {
176 !self.intersects(Self::AFTER_PSEUDO)
177 }
178
179 #[inline]
180 fn allows_combinators(self) -> bool {
181 !self.intersects(Self::DISALLOW_COMBINATORS)
182 }
183}
184
185pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>;
186
187#[derive(Clone, Debug, PartialEq)]
188pub enum SelectorParseErrorKind<'i> {
189 NoQualifiedNameInAttributeSelector(Token<'i>),
190 EmptySelector,
191 DanglingCombinator,
192 InvalidPseudoClassBeforeWebKitScrollbar,
193 InvalidPseudoClassAfterWebKitScrollbar,
194 InvalidPseudoClassAfterPseudoElement,
195 InvalidState,
196 MissingNestingSelector,
197 MissingNestingPrefix,
198 UnexpectedTokenInAttributeSelector(Token<'i>),
199 PseudoElementExpectedIdent(Token<'i>),
200 UnsupportedPseudoElement(CowRcStr<'i>),
201 UnsupportedPseudoClass(CowRcStr<'i>),
202 AmbiguousCssModuleClass(CowRcStr<'i>),
203 UnexpectedIdent(CowRcStr<'i>),
204 ExpectedNamespace(CowRcStr<'i>),
205 ExpectedBarInAttr(Token<'i>),
206 BadValueInAttr(Token<'i>),
207 InvalidQualNameInAttr(Token<'i>),
208 ExplicitNamespaceUnexpectedToken(Token<'i>),
209 ClassNeedsIdent(Token<'i>),
210 UnexpectedSelectorAfterPseudoElement(Token<'i>),
211}
212
213macro_rules! with_all_bounds {
214 (
215 [ $( $InSelector: tt )* ]
216 [ $( $CommonBounds: tt )* ]
217 [ $( $FromStr: tt )* ]
218 ) => {
219 pub trait SelectorImpl<'i>: Clone + Debug + Sized + 'static {
226 type ExtraMatchingData: Sized + Default + 'static;
227 type AttrValue: $($InSelector)*;
228 type Identifier: $($InSelector)*;
229 type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
230 type NamespaceUrl: $($CommonBounds)* + $($FromStr)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
231 type NamespacePrefix: $($InSelector)* + Default;
232 type BorrowedNamespaceUrl: ?Sized + Eq;
233 type BorrowedLocalName: ?Sized + Eq;
234
235 type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass<'i, Impl = Self>;
238 type VendorPrefix: Sized + Eq + $($CommonBounds)* + ToCss;
239
240 type PseudoElement: $($CommonBounds)* + PseudoElement<'i, Impl = Self>;
242
243 fn to_css<W: fmt::Write>(selectors: &SelectorList<'i, Self>, dest: &mut W) -> fmt::Result {
244 serialize_selector_list(selectors.0.iter(), dest)
245 }
246 }
247 }
248}
249
250macro_rules! with_bounds {
251 ( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
252 with_all_bounds! {
253 [$($CommonBounds)* + $($FromStr)* + ToCss]
254 [$($CommonBounds)*]
255 [$($FromStr)*]
256 }
257 }
258}
259
260#[cfg(feature = "serde")]
261with_bounds! {
262 [Clone + PartialEq + Eq + std::hash::Hash]
263 [From<CowRcStr<'i>> + From<std::borrow::Cow<'i, str>> + AsRef<str>]
264}
265
266#[cfg(not(feature = "serde"))]
267with_bounds! {
268 [Clone + PartialEq + Eq + std::hash::Hash]
269 [From<CowRcStr<'i>>]
270}
271
272pub trait Parser<'i> {
273 type Impl: SelectorImpl<'i>;
274 type Error: 'i + From<SelectorParseErrorKind<'i>>;
275
276 fn parse_slotted(&self) -> bool {
278 false
279 }
280
281 fn parse_part(&self) -> bool {
283 false
284 }
285
286 fn parse_is_and_where(&self) -> bool {
288 false
289 }
290
291 fn is_and_where_error_recovery(&self) -> ParseErrorRecovery {
293 ParseErrorRecovery::IgnoreInvalidSelector
294 }
295
296 fn parse_any_prefix(&self, _name: &str) -> Option<<Self::Impl as SelectorImpl<'i>>::VendorPrefix> {
298 None
299 }
300
301 fn parse_host(&self) -> bool {
303 false
304 }
305
306 fn parse_non_ts_pseudo_class(
312 &self,
313 location: SourceLocation,
314 name: CowRcStr<'i>,
315 ) -> Result<<Self::Impl as SelectorImpl<'i>>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
316 Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClass(name)))
317 }
318
319 fn parse_non_ts_functional_pseudo_class<'t>(
320 &self,
321 name: CowRcStr<'i>,
322 arguments: &mut CssParser<'i, 't>,
323 ) -> Result<<Self::Impl as SelectorImpl<'i>>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
324 Err(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClass(name)))
325 }
326
327 fn parse_pseudo_element(
328 &self,
329 location: SourceLocation,
330 name: CowRcStr<'i>,
331 ) -> Result<<Self::Impl as SelectorImpl<'i>>::PseudoElement, ParseError<'i, Self::Error>> {
332 Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoElement(name)))
333 }
334
335 fn parse_functional_pseudo_element<'t>(
336 &self,
337 name: CowRcStr<'i>,
338 arguments: &mut CssParser<'i, 't>,
339 ) -> Result<<Self::Impl as SelectorImpl<'i>>::PseudoElement, ParseError<'i, Self::Error>> {
340 Err(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoElement(name)))
341 }
342
343 fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl<'i>>::NamespaceUrl> {
344 None
345 }
346
347 fn namespace_for_prefix(
348 &self,
349 _prefix: &<Self::Impl as SelectorImpl<'i>>::NamespacePrefix,
350 ) -> Option<<Self::Impl as SelectorImpl<'i>>::NamespaceUrl> {
351 None
352 }
353
354 fn is_nesting_allowed(&self) -> bool {
355 false
356 }
357
358 fn deep_combinator_enabled(&self) -> bool {
359 false
360 }
361}
362
363#[derive(Clone, Debug, PartialEq, Eq, Hash)]
364#[cfg_attr(
365 feature = "serde",
366 derive(serde::Serialize, serde::Deserialize),
367 serde(bound(
368 serialize = "Impl::NonTSPseudoClass: serde::Serialize, Impl::PseudoElement: serde::Serialize, Impl::VendorPrefix: serde::Serialize",
369 deserialize = "Impl::NonTSPseudoClass: serde::Deserialize<'de>, Impl::PseudoElement: serde::Deserialize<'de>, Impl::VendorPrefix: serde::Deserialize<'de>"
370 ))
371)]
372#[cfg_attr(
373 feature = "jsonschema",
374 derive(schemars::JsonSchema),
375 schemars(
376 rename = "SelectorList",
377 bound = "Impl: schemars::JsonSchema, Impl::NonTSPseudoClass: schemars::JsonSchema, Impl::PseudoElement: schemars::JsonSchema, Impl::VendorPrefix: schemars::JsonSchema"
378 )
379)]
380pub struct SelectorList<'i, Impl: SelectorImpl<'i>>(
381 #[cfg_attr(feature = "serde", serde(borrow))] pub SmallVec<[Selector<'i, Impl>; 1]>,
382);
383
384#[cfg(feature = "into_owned")]
385impl<'any, 'i, Impl: SelectorImpl<'i>, NewSel> static_self::IntoOwned<'any> for SelectorList<'i, Impl>
386where
387 Impl: static_self::IntoOwned<'any, Owned = NewSel>,
388 NewSel: SelectorImpl<'any>,
389 Component<'i, Impl>: static_self::IntoOwned<'any, Owned = Component<'any, NewSel>>,
390{
391 type Owned = SelectorList<'any, NewSel>;
392
393 fn into_owned(self) -> Self::Owned {
394 SelectorList(self.0.into_owned())
395 }
396}
397
398pub enum ParseErrorRecovery {
400 DiscardList,
403 IgnoreInvalidSelector,
407}
408
409#[derive(Eq, PartialEq, Clone, Copy)]
410pub enum NestingRequirement {
411 None,
412 Prefixed,
413 Contained,
414 Implicit,
415}
416
417impl<'i, Impl: SelectorImpl<'i>> SelectorList<'i, Impl> {
418 pub fn parse<'t, P>(
423 parser: &P,
424 input: &mut CssParser<'i, 't>,
425 error_recovery: ParseErrorRecovery,
426 nesting_requirement: NestingRequirement,
427 ) -> Result<Self, ParseError<'i, P::Error>>
428 where
429 P: Parser<'i, Impl = Impl>,
430 {
431 Self::parse_with_state(
432 parser,
433 input,
434 &mut SelectorParsingState::empty(),
435 error_recovery,
436 nesting_requirement,
437 )
438 }
439
440 #[inline]
441 fn parse_with_state<'t, P>(
442 parser: &P,
443 input: &mut CssParser<'i, 't>,
444 state: &mut SelectorParsingState,
445 recovery: ParseErrorRecovery,
446 nesting_requirement: NestingRequirement,
447 ) -> Result<Self, ParseError<'i, P::Error>>
448 where
449 P: Parser<'i, Impl = Impl>,
450 {
451 let original_state = *state;
452 let mut values = SmallVec::new();
453 loop {
454 let selector = input.parse_until_before(Delimiter::Comma, |input| {
455 let mut selector_state = original_state;
456 let result = parse_selector(parser, input, &mut selector_state, nesting_requirement);
457 if selector_state.contains(SelectorParsingState::AFTER_NESTING) {
458 state.insert(SelectorParsingState::AFTER_NESTING)
459 }
460 result
461 });
462
463 let was_ok = selector.is_ok();
464 match selector {
465 Ok(selector) => values.push(selector),
466 Err(err) => match recovery {
467 ParseErrorRecovery::DiscardList => return Err(err),
468 ParseErrorRecovery::IgnoreInvalidSelector => {}
469 },
470 }
471
472 loop {
473 match input.next() {
474 Err(_) => return Ok(SelectorList(values)),
475 Ok(&Token::Comma) => break,
476 Ok(_) => {
477 debug_assert!(!was_ok, "Shouldn't have got a selector if getting here");
478 }
479 }
480 }
481 }
482 }
483
484 pub fn parse_relative<'t, P>(
485 parser: &P,
486 input: &mut CssParser<'i, 't>,
487 error_recovery: ParseErrorRecovery,
488 nesting_requirement: NestingRequirement,
489 ) -> Result<Self, ParseError<'i, P::Error>>
490 where
491 P: Parser<'i, Impl = Impl>,
492 {
493 Self::parse_relative_with_state(
494 parser,
495 input,
496 &mut SelectorParsingState::empty(),
497 error_recovery,
498 nesting_requirement,
499 )
500 }
501
502 #[inline]
503 fn parse_relative_with_state<'t, P>(
504 parser: &P,
505 input: &mut CssParser<'i, 't>,
506 state: &mut SelectorParsingState,
507 recovery: ParseErrorRecovery,
508 nesting_requirement: NestingRequirement,
509 ) -> Result<Self, ParseError<'i, P::Error>>
510 where
511 P: Parser<'i, Impl = Impl>,
512 {
513 let original_state = *state;
514 let mut values = SmallVec::new();
515 loop {
516 let selector = input.parse_until_before(Delimiter::Comma, |input| {
517 let mut selector_state = original_state;
518 let result = parse_relative_selector(parser, input, &mut selector_state, nesting_requirement);
519 if selector_state.contains(SelectorParsingState::AFTER_NESTING) {
520 state.insert(SelectorParsingState::AFTER_NESTING)
521 }
522 result
523 });
524
525 let was_ok = selector.is_ok();
526 match selector {
527 Ok(selector) => values.push(selector),
528 Err(err) => match recovery {
529 ParseErrorRecovery::DiscardList => return Err(err),
530 ParseErrorRecovery::IgnoreInvalidSelector => {}
531 },
532 }
533
534 loop {
535 match input.next() {
536 Err(_) => return Ok(SelectorList(values)),
537 Ok(&Token::Comma) => break,
538 Ok(_) => {
539 debug_assert!(!was_ok, "Shouldn't have got a selector if getting here");
540 }
541 }
542 }
543 }
544 }
545
546 pub fn new(v: SmallVec<[Selector<'i, Impl>; 1]>) -> Self {
548 SelectorList(v)
549 }
550
551 pub fn from_vec(v: Vec<Selector<'i, Impl>>) -> Self {
553 SelectorList(SmallVec::from_vec(v))
554 }
555}
556
557impl<'i, Impl: SelectorImpl<'i>> From<Selector<'i, Impl>> for SelectorList<'i, Impl> {
558 fn from(selector: Selector<'i, Impl>) -> Self {
559 SelectorList(smallvec![selector])
560 }
561}
562
563impl<'i, Impl: SelectorImpl<'i>> From<Component<'i, Impl>> for SelectorList<'i, Impl> {
564 fn from(component: Component<'i, Impl>) -> Self {
565 SelectorList::from(Selector::from(component))
566 }
567}
568
569fn parse_inner_compound_selector<'i, 't, P, Impl>(
571 parser: &P,
572 input: &mut CssParser<'i, 't>,
573 state: &mut SelectorParsingState,
574) -> Result<Selector<'i, Impl>, ParseError<'i, P::Error>>
575where
576 P: Parser<'i, Impl = Impl>,
577 Impl: SelectorImpl<'i>,
578{
579 let mut child_state =
580 *state | SelectorParsingState::DISALLOW_PSEUDOS | SelectorParsingState::DISALLOW_COMBINATORS;
581 let result = parse_selector(parser, input, &mut child_state, NestingRequirement::None)?;
582 if child_state.contains(SelectorParsingState::AFTER_NESTING) {
583 state.insert(SelectorParsingState::AFTER_NESTING)
584 }
585 Ok(result)
586}
587
588#[derive(Clone, Debug, Eq, PartialEq)]
604pub struct AncestorHashes {
605 pub packed_hashes: [u32; 3],
606}
607
608fn collect_ancestor_hashes<'i, Impl: SelectorImpl<'i>>(
609 iter: SelectorIter<'_, 'i, Impl>,
610 quirks_mode: QuirksMode,
611 hashes: &mut [u32; 4],
612 len: &mut usize,
613) -> bool
614where
615 Impl::Identifier: PrecomputedHash,
616 Impl::LocalName: PrecomputedHash,
617 Impl::NamespaceUrl: PrecomputedHash,
618{
619 for component in AncestorIter::new(iter) {
620 let hash = match *component {
621 Component::LocalName(LocalName {
622 ref name,
623 ref lower_name,
624 }) => {
625 if name != lower_name {
629 continue;
630 }
631 name.precomputed_hash()
632 }
633 Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => url.precomputed_hash(),
634 Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => id.precomputed_hash(),
637 Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => class.precomputed_hash(),
638 Component::Is(ref list) | Component::Where(ref list) => {
639 if list.len() == 1 && !collect_ancestor_hashes(list[0].iter(), quirks_mode, hashes, len) {
643 return false;
644 }
645 continue;
646 }
647 _ => continue,
648 };
649
650 hashes[*len] = hash & BLOOM_HASH_MASK;
651 *len += 1;
652 if *len == hashes.len() {
653 return false;
654 }
655 }
656 true
657}
658
659impl AncestorHashes {
660 pub fn new<'i, Impl: SelectorImpl<'i>>(selector: &Selector<'i, Impl>, quirks_mode: QuirksMode) -> Self
661 where
662 Impl::Identifier: PrecomputedHash,
663 Impl::LocalName: PrecomputedHash,
664 Impl::NamespaceUrl: PrecomputedHash,
665 {
666 let mut hashes = [0u32; 4];
668 let mut len = 0;
669 collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len);
670 debug_assert!(len <= 4);
671
672 if len == 4 {
675 let fourth = hashes[3];
676 hashes[0] |= (fourth & 0x000000ff) << 24;
677 hashes[1] |= (fourth & 0x0000ff00) << 16;
678 hashes[2] |= (fourth & 0x00ff0000) << 8;
679 }
680
681 AncestorHashes {
682 packed_hashes: [hashes[0], hashes[1], hashes[2]],
683 }
684 }
685
686 pub fn fourth_hash(&self) -> u32 {
688 ((self.packed_hashes[0] & 0xff000000) >> 24)
689 | ((self.packed_hashes[1] & 0xff000000) >> 16)
690 | ((self.packed_hashes[2] & 0xff000000) >> 8)
691 }
692}
693
694pub fn namespace_empty_string<'i, Impl: SelectorImpl<'i>>() -> Impl::NamespaceUrl {
695 Impl::NamespaceUrl::default()
697}
698
699#[derive(Clone, PartialEq, Eq, Hash)]
714pub struct Selector<'i, Impl: SelectorImpl<'i>>(SpecificityAndFlags, Vec<Component<'i, Impl>>);
715
716#[cfg(feature = "into_owned")]
717impl<'any, 'i, Impl: SelectorImpl<'i>, NewSel> static_self::IntoOwned<'any> for Selector<'i, Impl>
718where
719 Impl: static_self::IntoOwned<'any, Owned = NewSel>,
720 NewSel: SelectorImpl<'any>,
721 Component<'i, Impl>: static_self::IntoOwned<'any, Owned = Component<'any, NewSel>>,
722{
723 type Owned = Selector<'any, NewSel>;
724
725 fn into_owned(self) -> Self::Owned {
726 Selector(self.0, self.1.into_owned())
727 }
728}
729
730impl<'i, Impl: SelectorImpl<'i>> Selector<'i, Impl> {
731 #[inline]
732 pub fn specificity(&self) -> u32 {
733 self.0.specificity()
734 }
735
736 #[inline]
737 pub fn has_pseudo_element(&self) -> bool {
738 self.0.has_pseudo_element()
739 }
740
741 #[inline]
742 pub fn is_slotted(&self) -> bool {
743 self.0.is_slotted()
744 }
745
746 #[inline]
747 pub fn is_part(&self) -> bool {
748 self.0.is_part()
749 }
750
751 #[inline]
752 pub fn append(&mut self, component: Component<'i, Impl>) {
753 let index = self
754 .1
755 .iter()
756 .position(|c| matches!(*c, Component::Combinator(..) | Component::PseudoElement(..)))
757 .unwrap_or(self.1.len());
758 self.1.insert(index, component);
759 }
760
761 #[inline]
762 pub fn parts(&self) -> Option<&[Impl::Identifier]> {
763 if !self.is_part() {
764 return None;
765 }
766
767 let mut iter = self.iter();
768 if self.has_pseudo_element() {
769 for _ in &mut iter {}
771
772 let combinator = iter.next_sequence()?;
773 debug_assert_eq!(combinator, Combinator::PseudoElement);
774 }
775
776 for component in iter {
777 if let Component::Part(ref part) = *component {
778 return Some(part);
779 }
780 }
781
782 debug_assert!(false, "is_part() lied somehow?");
783 None
784 }
785
786 #[inline]
787 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
788 if !self.has_pseudo_element() {
789 return None;
790 }
791
792 for component in self.iter() {
793 if let Component::PseudoElement(ref pseudo) = *component {
794 return Some(pseudo);
795 }
796 }
797
798 debug_assert!(false, "has_pseudo_element lied!");
799 None
800 }
801
802 #[inline]
806 pub fn is_universal(&self) -> bool {
807 self.iter_raw_match_order().all(|c| {
808 matches!(
809 *c,
810 Component::ExplicitUniversalType
811 | Component::ExplicitAnyNamespace
812 | Component::Combinator(Combinator::PseudoElement)
813 | Component::PseudoElement(..)
814 )
815 })
816 }
817
818 #[inline]
819 pub fn has_combinator(&self) -> bool {
820 self
821 .iter_raw_match_order()
822 .any(|c| matches!(*c, Component::Combinator(combinator) if combinator.is_tree_combinator()))
823 }
824
825 #[inline]
829 pub fn iter(&self) -> SelectorIter<'_, 'i, Impl> {
830 SelectorIter {
831 iter: self.iter_raw_match_order(),
832 next_combinator: None,
833 }
834 }
835
836 #[inline]
840 pub fn is_featureless_host_selector_or_pseudo_element(&self) -> bool {
841 let mut iter = self.iter();
842 if !self.has_pseudo_element() {
843 return iter.is_featureless_host_selector();
844 }
845
846 for _ in &mut iter {}
848
849 match iter.next_sequence() {
850 None => return false,
851 Some(combinator) => {
852 debug_assert_eq!(combinator, Combinator::PseudoElement);
853 }
854 }
855
856 iter.is_featureless_host_selector()
857 }
858
859 #[inline]
862 pub fn iter_from(&self, offset: usize) -> SelectorIter<'_, 'i, Impl> {
863 let iter = self.1[offset..].iter();
864 SelectorIter {
865 iter,
866 next_combinator: None,
867 }
868 }
869
870 #[inline]
873 pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
874 match self.1[index] {
875 Component::Combinator(c) => c,
876 ref other => panic!("Not a combinator: {:?}, {:?}, index: {}", other, self, index),
877 }
878 }
879
880 #[inline]
883 pub fn iter_raw_match_order(&self) -> slice::Iter<Component<'i, Impl>> {
884 self.1.iter()
885 }
886
887 #[inline]
888 pub fn iter_mut_raw_match_order(&mut self) -> slice::IterMut<Component<'i, Impl>> {
889 self.1.iter_mut()
890 }
891
892 #[inline]
895 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
896 match self.1[self.len() - index - 1] {
897 Component::Combinator(c) => c,
898 ref other => panic!("Not a combinator: {:?}, {:?}, index: {}", other, self, index),
899 }
900 }
901
902 #[inline]
906 pub fn iter_raw_parse_order_from(&self, offset: usize) -> Rev<slice::Iter<Component<'i, Impl>>> {
907 self.1[..self.len() - offset].iter().rev()
908 }
909
910 #[allow(unused)]
912 pub(crate) fn from_vec(vec: Vec<Component<'i, Impl>>, specificity: u32, flags: SelectorFlags) -> Self {
913 let mut builder = SelectorBuilder::default();
914 for component in vec.into_iter() {
915 if let Some(combinator) = component.as_combinator() {
916 builder.push_combinator(combinator);
917 } else {
918 builder.push_simple_selector(component);
919 }
920 }
921 let spec = SpecificityAndFlags { specificity, flags };
922 let (spec, components) = builder.build_with_specificity_and_flags(spec);
923 Selector(spec, components)
924 }
925
926 #[cfg(feature = "serde")]
927 #[inline]
928 pub(crate) fn new(spec: SpecificityAndFlags, components: Vec<Component<'i, Impl>>) -> Self {
929 Selector(spec, components)
930 }
931
932 #[inline]
934 pub fn len(&self) -> usize {
935 self.1.len()
936 }
937
938 pub fn visit<V>(&self, visitor: &mut V) -> bool
957 where
958 V: SelectorVisitor<'i, Impl = Impl>,
959 {
960 let mut current = self.iter();
961 let mut combinator = None;
962 loop {
963 if !visitor.visit_complex_selector(combinator) {
964 return false;
965 }
966
967 for selector in &mut current {
968 if !selector.visit(visitor) {
969 return false;
970 }
971 }
972
973 combinator = current.next_sequence();
974 if combinator.is_none() {
975 break;
976 }
977 }
978
979 true
980 }
981}
982
983impl<'i, Impl: SelectorImpl<'i>> From<Component<'i, Impl>> for Selector<'i, Impl> {
984 fn from(component: Component<'i, Impl>) -> Self {
985 let mut builder = SelectorBuilder::default();
986 if let Some(combinator) = component.as_combinator() {
987 builder.push_combinator(combinator);
988 } else {
989 builder.push_simple_selector(component);
990 }
991 let (spec, components) = builder.build(false, false, false);
992 Selector(spec, components)
993 }
994}
995
996impl<'i, Impl: SelectorImpl<'i>> From<Vec<Component<'i, Impl>>> for Selector<'i, Impl> {
997 fn from(vec: Vec<Component<'i, Impl>>) -> Self {
998 let mut builder = SelectorBuilder::default();
999 for component in vec.into_iter() {
1000 if let Some(combinator) = component.as_combinator() {
1001 builder.push_combinator(combinator);
1002 } else {
1003 builder.push_simple_selector(component);
1004 }
1005 }
1006 let (spec, components) = builder.build(false, false, false);
1007 Selector(spec, components)
1008 }
1009}
1010
1011#[derive(Clone)]
1012pub struct SelectorIter<'a, 'i, Impl: SelectorImpl<'i>> {
1013 iter: slice::Iter<'a, Component<'i, Impl>>,
1014 next_combinator: Option<Combinator>,
1015}
1016
1017impl<'a, 'i, Impl: 'a + SelectorImpl<'i>> SelectorIter<'a, 'i, Impl> {
1018 #[inline]
1021 pub fn next_sequence(&mut self) -> Option<Combinator> {
1022 self.next_combinator.take()
1023 }
1024
1025 #[inline]
1028 pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
1029 self.selector_length() > 0
1030 && self.all(|component| matches!(*component, Component::Host(..)))
1031 && self.next_sequence().is_none()
1032 }
1033
1034 #[inline]
1035 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
1036 let first = match self.next() {
1037 Some(c) => c,
1038 None => return true,
1041 };
1042 self.matches_for_stateless_pseudo_element_internal(first)
1043 }
1044
1045 #[inline(never)]
1046 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<'i, Impl>) -> bool {
1047 if !first.matches_for_stateless_pseudo_element() {
1048 return false;
1049 }
1050 for component in self {
1051 if !component.matches_for_stateless_pseudo_element() {
1055 return false;
1056 }
1057 }
1058 true
1059 }
1060
1061 #[inline]
1063 pub fn selector_length(&self) -> usize {
1064 self.iter.len()
1065 }
1066}
1067
1068impl<'a, 'i, Impl: SelectorImpl<'i>> Iterator for SelectorIter<'a, 'i, Impl> {
1069 type Item = &'a Component<'i, Impl>;
1070
1071 #[inline]
1072 fn next(&mut self) -> Option<Self::Item> {
1073 debug_assert!(self.next_combinator.is_none(), "You should call next_sequence!");
1074 match *self.iter.next()? {
1075 Component::Combinator(c) => {
1076 self.next_combinator = Some(c);
1077 None
1078 }
1079 ref x => Some(x),
1080 }
1081 }
1082}
1083
1084impl<'a, 'i, Impl: SelectorImpl<'i>> fmt::Debug for SelectorIter<'a, 'i, Impl> {
1085 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1086 let iter = self.iter.clone().rev();
1087 for component in iter {
1088 component.to_css(f)?
1089 }
1090 Ok(())
1091 }
1092}
1093
1094struct AncestorIter<'a, 'i, Impl: SelectorImpl<'i>>(SelectorIter<'a, 'i, Impl>);
1096impl<'a, 'i, Impl: 'a + SelectorImpl<'i>> AncestorIter<'a, 'i, Impl> {
1097 fn new(inner: SelectorIter<'a, 'i, Impl>) -> Self {
1100 let mut result = AncestorIter(inner);
1101 result.skip_until_ancestor();
1102 result
1103 }
1104
1105 fn skip_until_ancestor(&mut self) {
1108 loop {
1109 while self.0.next().is_some() {}
1110 if self
1114 .0
1115 .next_sequence()
1116 .map_or(true, |x| matches!(x, Combinator::Child | Combinator::Descendant))
1117 {
1118 break;
1119 }
1120 }
1121 }
1122}
1123
1124impl<'a, 'i, Impl: SelectorImpl<'i>> Iterator for AncestorIter<'a, 'i, Impl> {
1125 type Item = &'a Component<'i, Impl>;
1126 fn next(&mut self) -> Option<Self::Item> {
1127 let next = self.0.next();
1129 if next.is_some() {
1130 return next;
1131 }
1132
1133 if let Some(combinator) = self.0.next_sequence() {
1135 if !matches!(combinator, Combinator::Child | Combinator::Descendant) {
1136 self.skip_until_ancestor();
1137 }
1138 }
1139
1140 self.0.next()
1141 }
1142}
1143
1144#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
1145#[cfg_attr(
1146 feature = "serde",
1147 derive(serde::Serialize, serde::Deserialize),
1148 serde(rename_all = "kebab-case")
1149)]
1150#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
1151#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
1152pub enum Combinator {
1153 Child, Descendant, NextSibling, LaterSibling, PseudoElement,
1164 SlotAssignment,
1167 Part,
1170
1171 DeepDescendant,
1174 Deep,
1179}
1180
1181impl Combinator {
1182 #[inline]
1184 pub fn is_ancestor(&self) -> bool {
1185 matches!(
1186 *self,
1187 Combinator::Child | Combinator::Descendant | Combinator::PseudoElement | Combinator::SlotAssignment
1188 )
1189 }
1190
1191 #[inline]
1193 pub fn is_pseudo_element(&self) -> bool {
1194 matches!(*self, Combinator::PseudoElement)
1195 }
1196
1197 #[inline]
1199 pub fn is_sibling(&self) -> bool {
1200 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1201 }
1202
1203 #[inline]
1204 pub fn is_tree_combinator(&self) -> bool {
1205 matches!(
1206 *self,
1207 Combinator::Child | Combinator::Descendant | Combinator::NextSibling | Combinator::LaterSibling
1208 )
1209 }
1210}
1211
1212#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1214#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
1215pub enum NthType {
1216 Child,
1217 LastChild,
1218 OnlyChild,
1219 OfType,
1220 LastOfType,
1221 OnlyOfType,
1222 Col,
1223 LastCol,
1224}
1225
1226impl NthType {
1227 pub fn is_only(self) -> bool {
1228 self == Self::OnlyChild || self == Self::OnlyOfType
1229 }
1230
1231 pub fn is_of_type(self) -> bool {
1232 self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType
1233 }
1234
1235 pub fn is_from_end(self) -> bool {
1236 self == Self::LastChild || self == Self::LastOfType || self == Self::LastCol
1237 }
1238
1239 pub fn allows_of_selector(self) -> bool {
1240 self == Self::Child || self == Self::LastChild
1241 }
1242}
1243
1244#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1248#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
1249pub struct NthSelectorData {
1250 pub ty: NthType,
1251 pub is_function: bool,
1252 pub a: i32,
1253 pub b: i32,
1254}
1255
1256impl NthSelectorData {
1257 #[inline]
1259 pub const fn only(of_type: bool) -> Self {
1260 Self {
1261 ty: if of_type {
1262 NthType::OnlyOfType
1263 } else {
1264 NthType::OnlyChild
1265 },
1266 is_function: false,
1267 a: 0,
1268 b: 1,
1269 }
1270 }
1271
1272 #[inline]
1274 pub const fn first(of_type: bool) -> Self {
1275 Self {
1276 ty: if of_type { NthType::OfType } else { NthType::Child },
1277 is_function: false,
1278 a: 0,
1279 b: 1,
1280 }
1281 }
1282
1283 #[inline]
1285 pub const fn last(of_type: bool) -> Self {
1286 Self {
1287 ty: if of_type {
1288 NthType::LastOfType
1289 } else {
1290 NthType::LastChild
1291 },
1292 is_function: false,
1293 a: 0,
1294 b: 1,
1295 }
1296 }
1297
1298 #[inline]
1299 pub fn is_function(&self) -> bool {
1300 self.a != 0 || self.b != 1
1301 }
1302
1303 #[inline]
1305 pub fn write_start<W: fmt::Write>(&self, dest: &mut W, is_function: bool) -> fmt::Result {
1306 dest.write_str(match self.ty {
1307 NthType::Child if is_function => ":nth-child(",
1308 NthType::Child => ":first-child",
1309 NthType::LastChild if is_function => ":nth-last-child(",
1310 NthType::LastChild => ":last-child",
1311 NthType::OfType if is_function => ":nth-of-type(",
1312 NthType::OfType => ":first-of-type",
1313 NthType::LastOfType if is_function => ":nth-last-of-type(",
1314 NthType::LastOfType => ":last-of-type",
1315 NthType::OnlyChild => ":only-child",
1316 NthType::OnlyOfType => ":only-of-type",
1317 NthType::Col => ":nth-col(",
1318 NthType::LastCol => ":nth-last-col(",
1319 })
1320 }
1321
1322 #[inline]
1325 pub fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1326 match (self.a, self.b) {
1327 (0, 0) => dest.write_char('0'),
1328
1329 (1, 0) => dest.write_char('n'),
1330 (-1, 0) => dest.write_str("-n"),
1331 (_, 0) => write!(dest, "{}n", self.a),
1332
1333 (2, 1) => dest.write_str("odd"),
1334
1335 (0, _) => write!(dest, "{}", self.b),
1336 (1, _) => write!(dest, "n{:+}", self.b),
1337 (-1, _) => write!(dest, "-n{:+}", self.b),
1338 (_, _) => write!(dest, "{}n{:+}", self.a, self.b),
1339 }
1340 }
1341}
1342
1343#[derive(Clone, PartialEq, Eq, Hash)]
1347pub struct NthOfSelectorData<'i, Impl: SelectorImpl<'i>>(NthSelectorData, Box<[Selector<'i, Impl>]>);
1348
1349#[cfg(feature = "into_owned")]
1350impl<'any, 'i, Impl: SelectorImpl<'i>, NewSel> static_self::IntoOwned<'any> for NthOfSelectorData<'i, Impl>
1351where
1352 Impl: static_self::IntoOwned<'any, Owned = NewSel>,
1353 NewSel: SelectorImpl<'any>,
1354 Component<'i, Impl>: static_self::IntoOwned<'any, Owned = Component<'any, NewSel>>,
1355{
1356 type Owned = NthOfSelectorData<'any, NewSel>;
1357
1358 fn into_owned(self) -> Self::Owned {
1359 NthOfSelectorData(self.0, self.1.into_owned())
1360 }
1361}
1362
1363impl<'i, Impl: SelectorImpl<'i>> NthOfSelectorData<'i, Impl> {
1364 #[inline]
1366 pub fn new(nth_data: NthSelectorData, selectors: Box<[Selector<'i, Impl>]>) -> Self {
1367 Self(nth_data, selectors)
1368 }
1369
1370 #[inline]
1372 pub fn nth_data(&self) -> &NthSelectorData {
1373 &self.0
1374 }
1375
1376 #[inline]
1378 pub fn selectors(&self) -> &[Selector<'i, Impl>] {
1379 &*self.1
1380 }
1381
1382 pub fn clone_selectors(&self) -> Box<[Selector<'i, Impl>]> {
1383 self.1.clone()
1384 }
1385}
1386
1387#[derive(Clone, PartialEq, Eq, Hash)]
1392pub enum Component<'i, Impl: SelectorImpl<'i>> {
1393 Combinator(Combinator),
1394
1395 ExplicitAnyNamespace,
1396 ExplicitNoNamespace,
1397 DefaultNamespace(Impl::NamespaceUrl),
1398 Namespace(Impl::NamespacePrefix, Impl::NamespaceUrl),
1399
1400 ExplicitUniversalType,
1401 LocalName(LocalName<'i, Impl>),
1402
1403 ID(Impl::Identifier),
1404 Class(Impl::Identifier),
1405
1406 AttributeInNoNamespaceExists {
1407 local_name: Impl::LocalName,
1408 local_name_lower: Impl::LocalName,
1409 },
1410 AttributeInNoNamespace {
1412 local_name: Impl::LocalName,
1413 operator: AttrSelectorOperator,
1414 value: Impl::AttrValue,
1415 case_sensitivity: ParsedCaseSensitivity,
1416 never_matches: bool,
1417 },
1418 AttributeOther(Box<AttrSelectorWithOptionalNamespace<'i, Impl>>),
1420
1421 Negation(Box<[Selector<'i, Impl>]>),
1423 Root,
1424 Empty,
1425 Scope,
1426 Nth(NthSelectorData),
1427 NthOf(NthOfSelectorData<'i, Impl>),
1428 NonTSPseudoClass(Impl::NonTSPseudoClass),
1429 Slotted(Selector<'i, Impl>),
1441 Part(Box<[Impl::Identifier]>),
1444 Host(Option<Selector<'i, Impl>>),
1454 Where(Box<[Selector<'i, Impl>]>),
1461 Is(Box<[Selector<'i, Impl>]>),
1467 Any(Impl::VendorPrefix, Box<[Selector<'i, Impl>]>),
1468 Has(Box<[Selector<'i, Impl>]>),
1472 PseudoElement(Impl::PseudoElement),
1474 Nesting,
1480}
1481
1482#[cfg(feature = "into_owned")]
1483impl<'any, 'i, Impl: SelectorImpl<'i>, NewSel> static_self::IntoOwned<'any> for Component<'i, Impl>
1484where
1485 Impl: static_self::IntoOwned<'any, Owned = NewSel>,
1486 NewSel: SelectorImpl<'any>,
1487 Impl::NamespaceUrl: static_self::IntoOwned<'any, Owned = NewSel::NamespaceUrl>,
1488 Impl::NamespacePrefix: static_self::IntoOwned<'any, Owned = NewSel::NamespacePrefix>,
1489 Impl::Identifier: static_self::IntoOwned<'any, Owned = NewSel::Identifier>,
1490 Impl::LocalName: static_self::IntoOwned<'any, Owned = NewSel::LocalName>,
1491 Impl::AttrValue: static_self::IntoOwned<'any, Owned = NewSel::AttrValue>,
1492 Impl::NonTSPseudoClass: static_self::IntoOwned<'any, Owned = NewSel::NonTSPseudoClass>,
1493 Impl::PseudoElement: static_self::IntoOwned<'any, Owned = NewSel::PseudoElement>,
1494 Impl::VendorPrefix: static_self::IntoOwned<'any, Owned = NewSel::VendorPrefix>,
1495{
1496 type Owned = Component<'any, NewSel>;
1497
1498 fn into_owned(self) -> Self::Owned {
1499 match self {
1500 Component::Combinator(c) => Component::Combinator(c.into_owned()),
1501 Component::ExplicitAnyNamespace => Component::ExplicitAnyNamespace,
1502 Component::ExplicitNoNamespace => Component::ExplicitNoNamespace,
1503 Component::DefaultNamespace(c) => Component::DefaultNamespace(c.into_owned()),
1504 Component::Namespace(a, b) => Component::Namespace(a.into_owned(), b.into_owned()),
1505 Component::ExplicitUniversalType => Component::ExplicitUniversalType,
1506 Component::LocalName(c) => Component::LocalName(c.into_owned()),
1507 Component::ID(c) => Component::ID(c.into_owned()),
1508 Component::Class(c) => Component::Class(c.into_owned()),
1509 Component::AttributeInNoNamespaceExists {
1510 local_name,
1511 local_name_lower,
1512 } => Component::AttributeInNoNamespaceExists {
1513 local_name: local_name.into_owned(),
1514 local_name_lower: local_name_lower.into_owned(),
1515 },
1516 Component::AttributeInNoNamespace {
1517 local_name,
1518 operator,
1519 value,
1520 case_sensitivity,
1521 never_matches,
1522 } => {
1523 let value = value.into_owned();
1524 Component::AttributeInNoNamespace {
1525 local_name: local_name.into_owned(),
1526 operator,
1527 value,
1528 case_sensitivity,
1529 never_matches,
1530 }
1531 }
1532 Component::AttributeOther(c) => Component::AttributeOther(c.into_owned()),
1533 Component::Negation(c) => Component::Negation(c.into_owned()),
1534 Component::Root => Component::Root,
1535 Component::Empty => Component::Empty,
1536 Component::Scope => Component::Scope,
1537 Component::Nth(c) => Component::Nth(c.into_owned()),
1538 Component::NthOf(c) => Component::NthOf(c.into_owned()),
1539 Component::NonTSPseudoClass(c) => Component::NonTSPseudoClass(c.into_owned()),
1540 Component::Slotted(c) => Component::Slotted(c.into_owned()),
1541 Component::Part(c) => Component::Part(c.into_owned()),
1542 Component::Host(c) => Component::Host(c.into_owned()),
1543 Component::Where(c) => Component::Where(c.into_owned()),
1544 Component::Is(c) => Component::Is(c.into_owned()),
1545 Component::Any(a, b) => Component::Any(a.into_owned(), b.into_owned()),
1546 Component::Has(c) => Component::Has(c.into_owned()),
1547 Component::PseudoElement(c) => Component::PseudoElement(c.into_owned()),
1548 Component::Nesting => Component::Nesting,
1549 }
1550 }
1551}
1552
1553impl<'i, Impl: SelectorImpl<'i>> Component<'i, Impl> {
1554 pub fn is_combinator(&self) -> bool {
1556 matches!(*self, Component::Combinator(_))
1557 }
1558
1559 pub fn as_combinator(&self) -> Option<Combinator> {
1561 match *self {
1562 Component::Combinator(c) => Some(c),
1563 _ => None,
1564 }
1565 }
1566
1567 pub fn maybe_allowed_after_pseudo_element(&self) -> bool {
1570 match *self {
1571 Component::NonTSPseudoClass(..) => true,
1572 Component::Negation(ref selectors) | Component::Is(ref selectors) | Component::Where(ref selectors) => {
1573 selectors
1574 .iter()
1575 .all(|selector| selector.iter_raw_match_order().all(|c| c.maybe_allowed_after_pseudo_element()))
1576 }
1577 _ => false,
1578 }
1579 }
1580
1581 fn matches_for_stateless_pseudo_element(&self) -> bool {
1588 debug_assert!(
1589 self.maybe_allowed_after_pseudo_element(),
1590 "Someone messed up pseudo-element parsing: {:?}",
1591 *self
1592 );
1593 match *self {
1594 Component::Negation(ref selectors) => !selectors.iter().all(|selector| {
1595 selector
1596 .iter_raw_match_order()
1597 .all(|c| c.matches_for_stateless_pseudo_element())
1598 }),
1599 Component::Is(ref selectors) | Component::Where(ref selectors) => selectors.iter().any(|selector| {
1600 selector
1601 .iter_raw_match_order()
1602 .all(|c| c.matches_for_stateless_pseudo_element())
1603 }),
1604 _ => false,
1605 }
1606 }
1607
1608 pub fn visit<V>(&self, visitor: &mut V) -> bool
1609 where
1610 V: SelectorVisitor<'i, Impl = Impl>,
1611 {
1612 use self::Component::*;
1613 if !visitor.visit_simple_selector(self) {
1614 return false;
1615 }
1616
1617 match *self {
1618 Slotted(ref selector) => {
1619 if !selector.visit(visitor) {
1620 return false;
1621 }
1622 }
1623 Host(Some(ref selector)) => {
1624 if !selector.visit(visitor) {
1625 return false;
1626 }
1627 }
1628 AttributeInNoNamespaceExists {
1629 ref local_name,
1630 ref local_name_lower,
1631 } => {
1632 if !visitor.visit_attribute_selector(
1633 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
1634 local_name,
1635 local_name_lower,
1636 ) {
1637 return false;
1638 }
1639 }
1640 AttributeInNoNamespace {
1641 ref local_name,
1642 never_matches,
1643 ..
1644 } if !never_matches => {
1645 if !visitor.visit_attribute_selector(
1646 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
1647 local_name,
1648 local_name,
1649 ) {
1650 return false;
1651 }
1652 }
1653 AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
1654 let empty_string;
1655 let namespace = match attr_selector.namespace() {
1656 Some(ns) => ns,
1657 None => {
1658 empty_string = crate::parser::namespace_empty_string::<Impl>();
1659 NamespaceConstraint::Specific(&empty_string)
1660 }
1661 };
1662 if !visitor.visit_attribute_selector(
1663 &namespace,
1664 &attr_selector.local_name,
1665 &attr_selector.local_name_lower,
1666 ) {
1667 return false;
1668 }
1669 }
1670
1671 NonTSPseudoClass(ref pseudo_class) => {
1672 if !pseudo_class.visit(visitor) {
1673 return false;
1674 }
1675 }
1676
1677 Negation(ref list) | Is(ref list) | Where(ref list) => {
1678 if !visitor.visit_selector_list(&list) {
1679 return false;
1680 }
1681 }
1682 NthOf(ref nth_of_data) => {
1683 if !visitor.visit_selector_list(nth_of_data.selectors()) {
1684 return false;
1685 }
1686 }
1687 _ => {}
1688 }
1689
1690 true
1691 }
1692}
1693
1694#[derive(Clone, Eq, PartialEq, Hash)]
1695pub struct LocalName<'i, Impl: SelectorImpl<'i>> {
1696 pub name: Impl::LocalName,
1697 pub lower_name: Impl::LocalName,
1698}
1699
1700#[cfg(feature = "into_owned")]
1701impl<'any, 'i, Impl: SelectorImpl<'i>, NewSel> static_self::IntoOwned<'any> for LocalName<'i, Impl>
1702where
1703 Impl: static_self::IntoOwned<'any, Owned = NewSel>,
1704 NewSel: SelectorImpl<'any>,
1705 Impl::LocalName: static_self::IntoOwned<'any, Owned = NewSel::LocalName>,
1706{
1707 type Owned = LocalName<'any, NewSel>;
1708
1709 fn into_owned(self) -> Self::Owned {
1710 LocalName {
1711 name: self.name.into_owned(),
1712 lower_name: self.lower_name.into_owned(),
1713 }
1714 }
1715}
1716
1717impl<'i, Impl: SelectorImpl<'i>> Debug for Selector<'i, Impl> {
1718 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1719 f.write_str("Selector(")?;
1720 self.to_css(f)?;
1721 write!(f, ", specificity = 0x{:x})", self.specificity())
1722 }
1723}
1724
1725impl<'i, Impl: SelectorImpl<'i>> Debug for Component<'i, Impl> {
1726 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1727 self.to_css(f)
1728 }
1729}
1730impl<'i, Impl: SelectorImpl<'i>> Debug for AttrSelectorWithOptionalNamespace<'i, Impl> {
1731 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1732 self.to_css(f)
1733 }
1734}
1735impl<'i, Impl: SelectorImpl<'i>> Debug for LocalName<'i, Impl> {
1736 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1737 self.to_css(f)
1738 }
1739}
1740
1741#[cfg(feature = "serde")]
1742impl<'i, Impl: SelectorImpl<'i>> serde::Serialize for LocalName<'i, Impl>
1743where
1744 Impl::LocalName: serde::Serialize,
1745{
1746 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1747 where
1748 S: serde::Serializer,
1749 {
1750 self.name.serialize(serializer)
1751 }
1752}
1753
1754#[cfg(feature = "serde")]
1755impl<'i, 'de: 'i, Impl: SelectorImpl<'i>> serde::Deserialize<'de> for LocalName<'i, Impl>
1756where
1757 Impl::LocalName: serde::Deserialize<'de>,
1758{
1759 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1760 where
1761 D: serde::Deserializer<'de>,
1762 {
1763 let name = Impl::LocalName::deserialize(deserializer)?;
1764 let lower_name = to_ascii_lowercase(name.as_ref().to_string().into()).into();
1765 Ok(LocalName { name, lower_name })
1766 }
1767}
1768
1769fn serialize_selector_list<'a, 'i: 'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
1770where
1771 Impl: SelectorImpl<'i>,
1772 I: Iterator<Item = &'a Selector<'i, Impl>>,
1773 W: fmt::Write,
1774{
1775 let mut first = true;
1776 for selector in iter {
1777 if !first {
1778 dest.write_str(", ")?;
1779 }
1780 first = false;
1781 selector.to_css(dest)?;
1782 }
1783 Ok(())
1784}
1785
1786impl<'i, Impl: SelectorImpl<'i>> ToCss for SelectorList<'i, Impl> {
1787 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1788 where
1789 W: fmt::Write,
1790 {
1791 serialize_selector_list(self.0.iter(), dest)
1792 }
1793}
1794
1795impl<'i, Impl: SelectorImpl<'i>> fmt::Display for SelectorList<'i, Impl> {
1796 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
1797 Impl::to_css(self, f)
1798 }
1799}
1800
1801impl<'i, Impl: SelectorImpl<'i>> ToCss for Selector<'i, Impl> {
1802 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1803 where
1804 W: fmt::Write,
1805 {
1806 let mut combinators = self.iter_raw_match_order().rev().filter_map(|x| x.as_combinator());
1819 let compound_selectors = self.iter_raw_match_order().as_slice().split(|x| x.is_combinator()).rev();
1820
1821 let mut combinators_exhausted = false;
1822 for compound in compound_selectors {
1823 debug_assert!(!combinators_exhausted);
1824
1825 if compound.is_empty() {
1827 continue;
1828 }
1829
1830 let (can_elide_namespace, first_non_namespace) = match compound[0] {
1841 Component::ExplicitAnyNamespace | Component::ExplicitNoNamespace | Component::Namespace(..) => (false, 1),
1842 Component::DefaultNamespace(..) => (true, 1),
1843 _ => (true, 0),
1844 };
1845 let mut perform_step_2 = true;
1846 let next_combinator = combinators.next();
1847 if first_non_namespace == compound.len() - 1 {
1848 match (next_combinator, &compound[first_non_namespace]) {
1849 (Some(Combinator::PseudoElement), _) | (Some(Combinator::SlotAssignment), _) => (),
1857 (_, &Component::ExplicitUniversalType) => {
1858 for simple in compound.iter() {
1861 simple.to_css(dest)?;
1862 }
1863 perform_step_2 = false;
1865 }
1866 _ => (),
1867 }
1868 }
1869
1870 if perform_step_2 {
1880 for simple in compound.iter() {
1881 if let Component::ExplicitUniversalType = *simple {
1882 if can_elide_namespace {
1887 continue;
1888 }
1889 }
1890 simple.to_css(dest)?;
1891 }
1892 }
1893
1894 match next_combinator {
1900 Some(c) => c.to_css(dest)?,
1901 None => combinators_exhausted = true,
1902 };
1903
1904 }
1910
1911 Ok(())
1912 }
1913}
1914
1915impl ToCss for Combinator {
1916 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1917 where
1918 W: fmt::Write,
1919 {
1920 match *self {
1921 Combinator::Child => dest.write_str(" > "),
1922 Combinator::Descendant => dest.write_str(" "),
1923 Combinator::NextSibling => dest.write_str(" + "),
1924 Combinator::LaterSibling => dest.write_str(" ~ "),
1925 Combinator::DeepDescendant => dest.write_str(" >>> "),
1926 Combinator::Deep => dest.write_str(" /deep/ "),
1927 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => Ok(()),
1928 }
1929 }
1930}
1931
1932impl<'i, Impl: SelectorImpl<'i>> ToCss for Component<'i, Impl> {
1933 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1934 where
1935 W: fmt::Write,
1936 {
1937 use self::Component::*;
1938
1939 match *self {
1940 Combinator(ref c) => c.to_css(dest),
1941 Slotted(ref selector) => {
1942 dest.write_str("::slotted(")?;
1943 selector.to_css(dest)?;
1944 dest.write_char(')')
1945 }
1946 Part(ref part_names) => {
1947 dest.write_str("::part(")?;
1948 for (i, name) in part_names.iter().enumerate() {
1949 if i != 0 {
1950 dest.write_char(' ')?;
1951 }
1952 name.to_css(dest)?;
1953 }
1954 dest.write_char(')')
1955 }
1956 PseudoElement(ref p) => p.to_css(dest),
1957 ID(ref s) => {
1958 dest.write_char('#')?;
1959 s.to_css(dest)
1960 }
1961 Class(ref s) => {
1962 dest.write_char('.')?;
1963 s.to_css(dest)
1964 }
1965 LocalName(ref s) => s.to_css(dest),
1966 ExplicitUniversalType => dest.write_char('*'),
1967
1968 DefaultNamespace(_) => Ok(()),
1969 ExplicitNoNamespace => dest.write_char('|'),
1970 ExplicitAnyNamespace => dest.write_str("*|"),
1971 Namespace(ref prefix, _) => {
1972 prefix.to_css(dest)?;
1973 dest.write_char('|')
1974 }
1975
1976 AttributeInNoNamespaceExists { ref local_name, .. } => {
1977 dest.write_char('[')?;
1978 local_name.to_css(dest)?;
1979 dest.write_char(']')
1980 }
1981 AttributeInNoNamespace {
1982 ref local_name,
1983 operator,
1984 ref value,
1985 case_sensitivity,
1986 ..
1987 } => {
1988 dest.write_char('[')?;
1989 local_name.to_css(dest)?;
1990 operator.to_css(dest)?;
1991 value.to_css(dest)?;
1992 match case_sensitivity {
1993 ParsedCaseSensitivity::CaseSensitive
1994 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {}
1995 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1996 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1997 }
1998 dest.write_char(']')
1999 }
2000 AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
2001
2002 Root => dest.write_str(":root"),
2004 Empty => dest.write_str(":empty"),
2005 Scope => dest.write_str(":scope"),
2006 Host(ref selector) => {
2007 dest.write_str(":host")?;
2008 if let Some(ref selector) = *selector {
2009 dest.write_char('(')?;
2010 selector.to_css(dest)?;
2011 dest.write_char(')')?;
2012 }
2013 Ok(())
2014 }
2015 Nth(ref nth_data) => {
2016 nth_data.write_start(dest, nth_data.is_function())?;
2017 if nth_data.is_function() {
2018 nth_data.write_affine(dest)?;
2019 dest.write_char(')')?;
2020 }
2021 Ok(())
2022 }
2023 NthOf(ref nth_of_data) => {
2024 let nth_data = nth_of_data.nth_data();
2025 nth_data.write_start(dest, true)?;
2026 debug_assert!(
2027 nth_data.is_function,
2028 "A selector must be a function to hold An+B notation"
2029 );
2030 nth_data.write_affine(dest)?;
2031 debug_assert!(
2032 matches!(nth_data.ty, NthType::Child | NthType::LastChild),
2033 "Only :nth-child or :nth-last-child can be of a selector list"
2034 );
2035 debug_assert!(
2036 !nth_of_data.selectors().is_empty(),
2037 "The selector list should not be empty"
2038 );
2039 dest.write_str(" of ")?;
2040 serialize_selector_list(nth_of_data.selectors().iter(), dest)?;
2041 dest.write_char(')')
2042 }
2043 Is(ref list) | Where(ref list) | Negation(ref list) | Has(ref list) | Any(_, ref list) => {
2044 match *self {
2045 Where(..) => dest.write_str(":where(")?,
2046 Is(..) => dest.write_str(":is(")?,
2047 Negation(..) => dest.write_str(":not(")?,
2048 Has(..) => dest.write_str(":has(")?,
2049 Any(ref prefix, _) => {
2050 dest.write_char(':')?;
2051 prefix.to_css(dest)?;
2052 dest.write_str("any(")?;
2053 }
2054 _ => unreachable!(),
2055 }
2056 serialize_selector_list(list.iter(), dest)?;
2057 dest.write_str(")")
2058 }
2059 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
2060 Nesting => dest.write_char('&'),
2061 }
2062 }
2063}
2064
2065impl<'i, Impl: SelectorImpl<'i>> ToCss for AttrSelectorWithOptionalNamespace<'i, Impl> {
2066 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2067 where
2068 W: fmt::Write,
2069 {
2070 dest.write_char('[')?;
2071 match self.namespace {
2072 Some(NamespaceConstraint::Specific((ref prefix, _))) => {
2073 prefix.to_css(dest)?;
2074 dest.write_char('|')?
2075 }
2076 Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
2077 None => {}
2078 }
2079 self.local_name.to_css(dest)?;
2080 match self.operation {
2081 ParsedAttrSelectorOperation::Exists => {}
2082 ParsedAttrSelectorOperation::WithValue {
2083 operator,
2084 case_sensitivity,
2085 ref expected_value,
2086 } => {
2087 operator.to_css(dest)?;
2088 expected_value.to_css(dest)?;
2089 match case_sensitivity {
2090 ParsedCaseSensitivity::CaseSensitive
2091 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {}
2092 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2093 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2094 }
2095 }
2096 }
2097 dest.write_char(']')
2098 }
2099}
2100
2101impl<'i, Impl: SelectorImpl<'i>> ToCss for LocalName<'i, Impl> {
2102 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2103 where
2104 W: fmt::Write,
2105 {
2106 self.name.to_css(dest)
2107 }
2108}
2109
2110fn parse_selector<'i, 't, P, Impl>(
2115 parser: &P,
2116 input: &mut CssParser<'i, 't>,
2117 state: &mut SelectorParsingState,
2118 nesting_requirement: NestingRequirement,
2119) -> Result<Selector<'i, Impl>, ParseError<'i, P::Error>>
2120where
2121 P: Parser<'i, Impl = Impl>,
2122 Impl: SelectorImpl<'i>,
2123{
2124 if nesting_requirement == NestingRequirement::Prefixed {
2125 let state = input.state();
2126 if !input.expect_delim('&').is_ok() {
2127 return Err(input.new_custom_error(SelectorParseErrorKind::MissingNestingPrefix));
2128 }
2129 input.reset(&state);
2130 }
2131
2132 let mut builder = SelectorBuilder::default();
2133
2134 'outer_loop: loop {
2135 let empty = parse_compound_selector(parser, state, input, &mut builder)?;
2137 if empty {
2138 return Err(input.new_custom_error(if builder.has_combinators() {
2139 SelectorParseErrorKind::DanglingCombinator
2140 } else {
2141 SelectorParseErrorKind::EmptySelector
2142 }));
2143 }
2144
2145 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2146 let source_location = input.current_source_location();
2148 if let Ok(next) = input.next() {
2149 let next = next.clone();
2150 return Err(
2151 source_location.new_custom_error(SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(next)),
2152 );
2153 }
2154 break;
2155 }
2156
2157 let combinator;
2159 let mut any_whitespace = false;
2160 loop {
2161 let before_this_token = input.state();
2162 match input.next_including_whitespace() {
2163 Err(_e) => break 'outer_loop,
2164 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
2165 Ok(&Token::Delim('>')) => {
2166 if parser.deep_combinator_enabled()
2167 && input
2168 .try_parse(|input| {
2169 input.expect_delim('>')?;
2170 input.expect_delim('>')
2171 })
2172 .is_ok()
2173 {
2174 combinator = Combinator::DeepDescendant;
2175 } else {
2176 combinator = Combinator::Child;
2177 }
2178 break;
2179 }
2180 Ok(&Token::Delim('+')) => {
2181 combinator = Combinator::NextSibling;
2182 break;
2183 }
2184 Ok(&Token::Delim('~')) => {
2185 combinator = Combinator::LaterSibling;
2186 break;
2187 }
2188 Ok(&Token::Delim('/')) if parser.deep_combinator_enabled() => {
2189 if input
2190 .try_parse(|input| {
2191 input.expect_ident_matching("deep")?;
2192 input.expect_delim('/')
2193 })
2194 .is_ok()
2195 {
2196 combinator = Combinator::Deep;
2197 break;
2198 } else {
2199 break 'outer_loop;
2200 }
2201 }
2202 Ok(_) => {
2203 input.reset(&before_this_token);
2204 if any_whitespace {
2205 combinator = Combinator::Descendant;
2206 break;
2207 } else {
2208 break 'outer_loop;
2209 }
2210 }
2211 }
2212 }
2213
2214 if !state.allows_combinators() {
2215 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2216 }
2217
2218 builder.push_combinator(combinator);
2219 }
2220
2221 if !state.contains(SelectorParsingState::AFTER_NESTING) {
2222 match nesting_requirement {
2223 NestingRequirement::Implicit => {
2224 builder.add_nesting_prefix();
2225 }
2226 NestingRequirement::Contained | NestingRequirement::Prefixed => {
2227 return Err(input.new_custom_error(SelectorParseErrorKind::MissingNestingSelector));
2228 }
2229 _ => {}
2230 }
2231 }
2232
2233 let has_pseudo_element = state
2234 .intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT | SelectorParsingState::AFTER_UNKNOWN_PSEUDO_ELEMENT);
2235 let slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
2236 let part = state.intersects(SelectorParsingState::AFTER_PART);
2237 let (spec, components) = builder.build(has_pseudo_element, slotted, part);
2238 Ok(Selector(spec, components))
2239}
2240
2241impl<'i, Impl: SelectorImpl<'i>> Selector<'i, Impl> {
2242 #[inline]
2244 pub fn parse<'t, P>(parser: &P, input: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i, P::Error>>
2245 where
2246 P: Parser<'i, Impl = Impl>,
2247 {
2248 parse_selector(
2249 parser,
2250 input,
2251 &mut SelectorParsingState::empty(),
2252 NestingRequirement::None,
2253 )
2254 }
2255}
2256
2257fn parse_relative_selector<'i, 't, P, Impl>(
2258 parser: &P,
2259 input: &mut CssParser<'i, 't>,
2260 state: &mut SelectorParsingState,
2261 mut nesting_requirement: NestingRequirement,
2262) -> Result<Selector<'i, Impl>, ParseError<'i, P::Error>>
2263where
2264 P: Parser<'i, Impl = Impl>,
2265 Impl: SelectorImpl<'i>,
2266{
2267 let s = input.state();
2269 let combinator = match input.next()? {
2270 Token::Delim('>') => Some(Combinator::Child),
2271 Token::Delim('+') => Some(Combinator::NextSibling),
2272 Token::Delim('~') => Some(Combinator::LaterSibling),
2273 _ => {
2274 input.reset(&s);
2275 None
2276 }
2277 };
2278
2279 let scope = if nesting_requirement == NestingRequirement::Implicit {
2280 Component::Nesting
2281 } else {
2282 Component::Scope
2283 };
2284
2285 if combinator.is_some() {
2286 nesting_requirement = NestingRequirement::None;
2287 }
2288
2289 let mut selector = parse_selector(parser, input, state, nesting_requirement)?;
2290 if let Some(combinator) = combinator {
2291 selector.1.push(Component::Combinator(combinator));
2293 selector.1.push(scope);
2294 }
2295
2296 Ok(selector)
2297}
2298
2299fn parse_type_selector<'i, 't, P, Impl, S>(
2303 parser: &P,
2304 input: &mut CssParser<'i, 't>,
2305 state: SelectorParsingState,
2306 sink: &mut S,
2307) -> Result<bool, ParseError<'i, P::Error>>
2308where
2309 P: Parser<'i, Impl = Impl>,
2310 Impl: SelectorImpl<'i>,
2311 S: Push<Component<'i, Impl>>,
2312{
2313 match parse_qualified_name(parser, input, false) {
2314 Err(ParseError {
2315 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
2316 ..
2317 })
2318 | Ok(OptionalQName::None(_)) => Ok(false),
2319 Ok(OptionalQName::Some(namespace, local_name)) => {
2320 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2321 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2322 }
2323 match namespace {
2324 QNamePrefix::ImplicitAnyNamespace => {}
2325 QNamePrefix::ImplicitDefaultNamespace(url) => sink.push(Component::DefaultNamespace(url)),
2326 QNamePrefix::ExplicitNamespace(prefix, url) => sink.push(match parser.default_namespace() {
2327 Some(ref default_url) if url == *default_url => Component::DefaultNamespace(url),
2328 _ => Component::Namespace(prefix, url),
2329 }),
2330 QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
2331 QNamePrefix::ExplicitAnyNamespace => {
2332 sink.push(Component::ExplicitAnyNamespace)
2345 }
2346 QNamePrefix::ImplicitNoNamespace => {
2347 unreachable!() }
2349 }
2350 match local_name {
2351 Some(name) => sink.push(Component::LocalName(LocalName {
2352 lower_name: to_ascii_lowercase(name.clone()).into(),
2353 name: name.into(),
2354 })),
2355 None => sink.push(Component::ExplicitUniversalType),
2356 }
2357 Ok(true)
2358 }
2359 Err(e) => Err(e),
2360 }
2361}
2362
2363#[derive(Debug)]
2364enum SimpleSelectorParseResult<'i, Impl: SelectorImpl<'i>> {
2365 SimpleSelector(Component<'i, Impl>),
2366 PseudoElement(Impl::PseudoElement),
2367 SlottedPseudo(Selector<'i, Impl>),
2368 PartPseudo(Box<[Impl::Identifier]>),
2369}
2370
2371#[derive(Debug)]
2372enum QNamePrefix<'i, Impl: SelectorImpl<'i>> {
2373 ImplicitNoNamespace, ImplicitAnyNamespace, ImplicitDefaultNamespace(Impl::NamespaceUrl), ExplicitNoNamespace, ExplicitAnyNamespace, ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), }
2380
2381enum OptionalQName<'i, Impl: SelectorImpl<'i>> {
2382 Some(QNamePrefix<'i, Impl>, Option<CowRcStr<'i>>),
2383 None(Token<'i>),
2384}
2385
2386fn parse_qualified_name<'i, 't, P, Impl>(
2391 parser: &P,
2392 input: &mut CssParser<'i, 't>,
2393 in_attr_selector: bool,
2394) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
2395where
2396 P: Parser<'i, Impl = Impl>,
2397 Impl: SelectorImpl<'i>,
2398{
2399 let default_namespace = |local_name| {
2400 let namespace = match parser.default_namespace() {
2401 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
2402 None => QNamePrefix::ImplicitAnyNamespace,
2403 };
2404 Ok(OptionalQName::Some(namespace, local_name))
2405 };
2406
2407 let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
2408 let location = input.current_source_location();
2409 match input.next_including_whitespace() {
2410 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
2411 Ok(&Token::Ident(ref local_name)) => Ok(OptionalQName::Some(namespace, Some(local_name.clone()))),
2412 Ok(t) if in_attr_selector => {
2413 let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
2414 Err(location.new_custom_error(e))
2415 }
2416 Ok(t) => Err(location.new_custom_error(SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()))),
2417 Err(e) => Err(e.into()),
2418 }
2419 };
2420
2421 let start = input.state();
2422 match input.next_including_whitespace().map(|t| t.clone()) {
2424 Ok(Token::Ident(value)) => {
2425 let after_ident = input.state();
2426 match input.next_including_whitespace() {
2427 Ok(&Token::Delim('|')) => {
2428 let prefix = value.clone().into();
2429 let result = parser.namespace_for_prefix(&prefix);
2430 let url = result.ok_or(
2431 after_ident
2432 .source_location()
2433 .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
2434 )?;
2435 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
2436 }
2437 _ => {
2438 input.reset(&after_ident);
2439 if in_attr_selector {
2440 Ok(OptionalQName::Some(QNamePrefix::ImplicitNoNamespace, Some(value)))
2441 } else {
2442 default_namespace(Some(value))
2443 }
2444 }
2445 }
2446 }
2447 Ok(Token::Delim('*')) => {
2448 let after_star = input.state();
2449 match input.next_including_whitespace().map(|t| t.clone()) {
2451 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace),
2452 result => {
2453 input.reset(&after_star);
2454 if in_attr_selector {
2455 match result {
2456 Ok(t) => Err(
2457 after_star
2458 .source_location()
2459 .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t)),
2460 ),
2461 Err(e) => Err(e.into()),
2462 }
2463 } else {
2464 default_namespace(None)
2465 }
2466 }
2467 }
2468 }
2469 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
2470 Ok(t) => {
2471 input.reset(&start);
2472 Ok(OptionalQName::None(t))
2473 }
2474 Err(e) => {
2475 input.reset(&start);
2476 Err(e.into())
2477 }
2478 }
2479}
2480
2481fn parse_attribute_selector<'i, 't, P, Impl>(
2482 parser: &P,
2483 input: &mut CssParser<'i, 't>,
2484) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
2485where
2486 P: Parser<'i, Impl = Impl>,
2487 Impl: SelectorImpl<'i>,
2488{
2489 let namespace;
2490 let local_name;
2491
2492 input.skip_whitespace();
2493
2494 match parse_qualified_name(parser, input, true)? {
2495 OptionalQName::None(t) => {
2496 return Err(input.new_custom_error(SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t)));
2497 }
2498 OptionalQName::Some(_, None) => unreachable!(),
2499 OptionalQName::Some(ns, Some(ln)) => {
2500 local_name = ln;
2501 namespace = match ns {
2502 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
2503 QNamePrefix::ExplicitNamespace(prefix, url) => Some(NamespaceConstraint::Specific((prefix, url))),
2504 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
2505 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
2506 unreachable!() }
2508 }
2509 }
2510 }
2511
2512 let location = input.current_source_location();
2513 let operator = match input.next() {
2514 Err(_) => {
2516 let local_name_lower = to_ascii_lowercase(local_name.clone()).into();
2517 let local_name = local_name.into();
2518 if let Some(namespace) = namespace {
2519 return Ok(Component::AttributeOther(Box::new(AttrSelectorWithOptionalNamespace {
2520 namespace: Some(namespace),
2521 local_name,
2522 local_name_lower,
2523 operation: ParsedAttrSelectorOperation::Exists,
2524 never_matches: false,
2525 })));
2526 } else {
2527 return Ok(Component::AttributeInNoNamespaceExists {
2528 local_name,
2529 local_name_lower,
2530 });
2531 }
2532 }
2533
2534 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
2536 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
2538 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
2540 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
2542 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
2544 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
2546 Ok(t) => {
2547 return Err(
2548 location.new_custom_error(SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone())),
2549 );
2550 }
2551 };
2552
2553 let value = match input.expect_ident_or_string() {
2554 Ok(t) => t.clone(),
2555 Err(BasicParseError {
2556 kind: BasicParseErrorKind::UnexpectedToken(t),
2557 location,
2558 }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
2559 Err(e) => return Err(e.into()),
2560 };
2561 let never_matches = match operator {
2562 AttrSelectorOperator::Equal | AttrSelectorOperator::DashMatch => false,
2563
2564 AttrSelectorOperator::Includes => value.is_empty() || value.contains(SELECTOR_WHITESPACE),
2565
2566 AttrSelectorOperator::Prefix | AttrSelectorOperator::Substring | AttrSelectorOperator::Suffix => {
2567 value.is_empty()
2568 }
2569 };
2570
2571 let attribute_flags = parse_attribute_flags(input)?;
2572
2573 let value = value.into();
2574 let case_sensitivity;
2575 let (local_name_lower_cow, local_name_is_ascii_lowercase) =
2577 if let Some(first_uppercase) = local_name.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
2578 let mut string = local_name.to_string();
2579 string[first_uppercase..].make_ascii_lowercase();
2580 (string.into(), false)
2581 } else {
2582 (local_name.clone(), true)
2583 };
2584 case_sensitivity = attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
2585 let local_name_lower = local_name_lower_cow.into();
2586 let local_name = local_name.into();
2587 if namespace.is_some() || !local_name_is_ascii_lowercase {
2588 Ok(Component::AttributeOther(Box::new(AttrSelectorWithOptionalNamespace {
2589 namespace,
2590 local_name,
2591 local_name_lower,
2592 never_matches,
2593 operation: ParsedAttrSelectorOperation::WithValue {
2594 operator,
2595 case_sensitivity,
2596 expected_value: value,
2597 },
2598 })))
2599 } else {
2600 Ok(Component::AttributeInNoNamespace {
2601 local_name,
2602 operator,
2603 value,
2604 case_sensitivity,
2605 never_matches,
2606 })
2607 }
2608}
2609
2610enum AttributeFlags {
2612 CaseSensitive,
2614 AsciiCaseInsensitive,
2616 CaseSensitivityDependsOnName,
2618}
2619
2620impl AttributeFlags {
2621 fn to_case_sensitivity(self, local_name: &str, have_namespace: bool) -> ParsedCaseSensitivity {
2622 match self {
2623 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
2624 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
2625 AttributeFlags::CaseSensitivityDependsOnName => {
2626 if !have_namespace
2627 && include!(concat!(env!("OUT_DIR"), "/ascii_case_insensitive_html_attributes.rs")).contains(local_name)
2628 {
2629 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
2630 } else {
2631 ParsedCaseSensitivity::CaseSensitive
2632 }
2633 }
2634 }
2635 }
2636}
2637
2638fn parse_attribute_flags<'i, 't>(input: &mut CssParser<'i, 't>) -> Result<AttributeFlags, BasicParseError<'i>> {
2639 let location = input.current_source_location();
2640 let token = match input.next() {
2641 Ok(t) => t,
2642 Err(..) => {
2643 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
2646 }
2647 };
2648
2649 let ident = match *token {
2650 Token::Ident(ref i) => i,
2651 ref other => return Err(location.new_basic_unexpected_token_error(other.clone())),
2652 };
2653
2654 Ok(match_ignore_ascii_case! {
2655 ident,
2656 "i" => AttributeFlags::AsciiCaseInsensitive,
2657 "s" => AttributeFlags::CaseSensitive,
2658 _ => return Err(location.new_basic_unexpected_token_error(token.clone())),
2659 })
2660}
2661
2662fn parse_negation<'i, 't, P, Impl>(
2665 parser: &P,
2666 input: &mut CssParser<'i, 't>,
2667 state: &mut SelectorParsingState,
2668) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
2669where
2670 P: Parser<'i, Impl = Impl>,
2671 Impl: SelectorImpl<'i>,
2672{
2673 let mut child_state =
2674 *state | SelectorParsingState::SKIP_DEFAULT_NAMESPACE | SelectorParsingState::DISALLOW_PSEUDOS;
2675 let list = SelectorList::parse_with_state(
2676 parser,
2677 input,
2678 &mut child_state,
2679 ParseErrorRecovery::DiscardList,
2680 NestingRequirement::None,
2681 )?;
2682
2683 if child_state.contains(SelectorParsingState::AFTER_NESTING) {
2684 state.insert(SelectorParsingState::AFTER_NESTING)
2685 }
2686
2687 Ok(Component::Negation(list.0.into_vec().into_boxed_slice()))
2688}
2689
2690fn parse_compound_selector<'i, 't, P, Impl>(
2697 parser: &P,
2698 state: &mut SelectorParsingState,
2699 input: &mut CssParser<'i, 't>,
2700 builder: &mut SelectorBuilder<'i, Impl>,
2701) -> Result<bool, ParseError<'i, P::Error>>
2702where
2703 P: Parser<'i, Impl = Impl>,
2704 Impl: SelectorImpl<'i>,
2705{
2706 input.skip_whitespace();
2707
2708 let mut empty = true;
2709 if parser.is_nesting_allowed() && input.try_parse(|input| input.expect_delim('&')).is_ok() {
2710 state.insert(SelectorParsingState::AFTER_NESTING);
2711 builder.push_simple_selector(Component::Nesting);
2712 empty = false;
2713 }
2714
2715 if parse_type_selector(parser, input, *state, builder)? {
2716 empty = false;
2717 }
2718
2719 loop {
2720 let result = match parse_one_simple_selector(parser, input, state)? {
2721 None => break,
2722 Some(result) => result,
2723 };
2724
2725 if empty {
2726 if let Some(url) = parser.default_namespace() {
2727 let ignore_default_ns = state.intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE)
2755 || matches!(result, SimpleSelectorParseResult::SimpleSelector(Component::Host(..)));
2756 if !ignore_default_ns {
2757 builder.push_simple_selector(Component::DefaultNamespace(url));
2758 }
2759 }
2760 }
2761
2762 empty = false;
2763
2764 match result {
2765 SimpleSelectorParseResult::SimpleSelector(s) => {
2766 builder.push_simple_selector(s);
2767 }
2768 SimpleSelectorParseResult::PartPseudo(part_names) => {
2769 state.insert(SelectorParsingState::AFTER_PART);
2770 builder.push_combinator(Combinator::Part);
2771 builder.push_simple_selector(Component::Part(part_names));
2772 }
2773 SimpleSelectorParseResult::SlottedPseudo(selector) => {
2774 state.insert(SelectorParsingState::AFTER_SLOTTED);
2775 builder.push_combinator(Combinator::SlotAssignment);
2776 builder.push_simple_selector(Component::Slotted(selector));
2777 }
2778 SimpleSelectorParseResult::PseudoElement(p) => {
2779 if !p.is_unknown() {
2780 state.insert(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
2781 builder.push_combinator(Combinator::PseudoElement);
2782 } else {
2783 state.insert(SelectorParsingState::AFTER_UNKNOWN_PSEUDO_ELEMENT);
2784 }
2785 if !p.accepts_state_pseudo_classes() {
2786 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
2787 }
2788 if p.is_webkit_scrollbar() {
2789 state.insert(SelectorParsingState::AFTER_WEBKIT_SCROLLBAR);
2790 }
2791 if p.is_view_transition() {
2792 state.insert(SelectorParsingState::AFTER_VIEW_TRANSITION);
2793 }
2794 builder.push_simple_selector(Component::PseudoElement(p));
2795 }
2796 }
2797 }
2798 Ok(empty)
2799}
2800
2801fn parse_is_or_where<'i, 't, P, Impl>(
2802 parser: &P,
2803 input: &mut CssParser<'i, 't>,
2804 state: &mut SelectorParsingState,
2805 component: impl FnOnce(Box<[Selector<'i, Impl>]>) -> Component<'i, Impl>,
2806) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
2807where
2808 P: Parser<'i, Impl = Impl>,
2809 Impl: SelectorImpl<'i>,
2810{
2811 debug_assert!(parser.parse_is_and_where());
2812 let mut child_state =
2818 *state | SelectorParsingState::SKIP_DEFAULT_NAMESPACE | SelectorParsingState::DISALLOW_PSEUDOS;
2819 let inner = SelectorList::parse_with_state(
2820 parser,
2821 input,
2822 &mut child_state,
2823 parser.is_and_where_error_recovery(),
2824 NestingRequirement::None,
2825 )?;
2826 if child_state.contains(SelectorParsingState::AFTER_NESTING) {
2827 state.insert(SelectorParsingState::AFTER_NESTING)
2828 }
2829 Ok(component(inner.0.into_vec().into_boxed_slice()))
2830}
2831
2832fn parse_has<'i, 't, P, Impl>(
2833 parser: &P,
2834 input: &mut CssParser<'i, 't>,
2835 state: &mut SelectorParsingState,
2836) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
2837where
2838 P: Parser<'i, Impl = Impl>,
2839 Impl: SelectorImpl<'i>,
2840{
2841 let mut child_state = *state;
2842 let inner = SelectorList::parse_relative_with_state(
2843 parser,
2844 input,
2845 &mut child_state,
2846 parser.is_and_where_error_recovery(),
2847 NestingRequirement::None,
2848 )?;
2849 if child_state.contains(SelectorParsingState::AFTER_NESTING) {
2850 state.insert(SelectorParsingState::AFTER_NESTING)
2851 }
2852 Ok(Component::Has(inner.0.into_vec().into_boxed_slice()))
2853}
2854
2855fn parse_functional_pseudo_class<'i, 't, P, Impl>(
2856 parser: &P,
2857 input: &mut CssParser<'i, 't>,
2858 name: CowRcStr<'i>,
2859 state: &mut SelectorParsingState,
2860) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
2861where
2862 P: Parser<'i, Impl = Impl>,
2863 Impl: SelectorImpl<'i>,
2864{
2865 match_ignore_ascii_case! { &name,
2866 "nth-child" => return parse_nth_pseudo_class(parser, input, *state, NthType::Child),
2867 "nth-of-type" => return parse_nth_pseudo_class(parser, input, *state, NthType::OfType),
2868 "nth-last-child" => return parse_nth_pseudo_class(parser, input, *state, NthType::LastChild),
2869 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, *state, NthType::LastOfType),
2870 "nth-col" => return parse_nth_pseudo_class(parser, input, *state, NthType::Col),
2871 "nth-last-col" => return parse_nth_pseudo_class(parser, input, *state, NthType::LastCol),
2872 "is" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Is),
2873 "where" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Where),
2874 "has" => return parse_has(parser, input, state),
2875 "host" => {
2876 if !state.allows_tree_structural_pseudo_classes() {
2877 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2878 }
2879 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
2880 },
2881 "not" => {
2882 return parse_negation(parser, input, state)
2883 },
2884 _ => {}
2885 }
2886
2887 if let Some(prefix) = parser.parse_any_prefix(&name) {
2888 return parse_is_or_where(parser, input, state, |selectors| Component::Any(prefix, selectors));
2889 }
2890
2891 if !state.allows_custom_functional_pseudo_classes() {
2892 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2893 }
2894
2895 P::parse_non_ts_functional_pseudo_class(parser, name, input).map(Component::NonTSPseudoClass)
2896}
2897
2898fn parse_nth_pseudo_class<'i, 't, P, Impl>(
2899 parser: &P,
2900 input: &mut CssParser<'i, 't>,
2901 state: SelectorParsingState,
2902 ty: NthType,
2903) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
2904where
2905 P: Parser<'i, Impl = Impl>,
2906 Impl: SelectorImpl<'i>,
2907{
2908 if !state.allows_tree_structural_pseudo_classes() {
2909 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2910 }
2911 let (a, b) = parse_nth(input)?;
2912 let nth_data = NthSelectorData {
2913 ty,
2914 is_function: true,
2915 a,
2916 b,
2917 };
2918 if !ty.allows_of_selector() {
2919 return Ok(Component::Nth(nth_data));
2920 }
2921
2922 if input.try_parse(|i| i.expect_ident_matching("of")).is_err() {
2924 return Ok(Component::Nth(nth_data));
2925 }
2926 let mut child_state =
2929 state | SelectorParsingState::SKIP_DEFAULT_NAMESPACE | SelectorParsingState::DISALLOW_PSEUDOS;
2930 let selectors = SelectorList::parse_with_state(
2931 parser,
2932 input,
2933 &mut child_state,
2934 ParseErrorRecovery::IgnoreInvalidSelector,
2935 NestingRequirement::None,
2936 )?;
2937 Ok(Component::NthOf(NthOfSelectorData::new(
2938 nth_data,
2939 selectors.0.into_vec().into_boxed_slice(),
2940 )))
2941}
2942
2943fn is_css2_pseudo_element(name: &str) -> bool {
2947 match_ignore_ascii_case! { name,
2949 "before" | "after" | "first-line" | "first-letter" => true,
2950 _ => false,
2951 }
2952}
2953
2954fn parse_one_simple_selector<'i, 't, P, Impl>(
2960 parser: &P,
2961 input: &mut CssParser<'i, 't>,
2962 state: &mut SelectorParsingState,
2963) -> Result<Option<SimpleSelectorParseResult<'i, Impl>>, ParseError<'i, P::Error>>
2964where
2965 P: Parser<'i, Impl = Impl>,
2966 Impl: SelectorImpl<'i>,
2967{
2968 let start = input.state();
2969 let token_location = input.current_source_location();
2970 let token = match input.next_including_whitespace().map(|t| t.clone()) {
2971 Ok(t) => t,
2972 Err(..) => {
2973 input.reset(&start);
2974 return Ok(None);
2975 }
2976 };
2977
2978 Ok(Some(match token {
2979 Token::IDHash(id) => {
2980 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2981 return Err(token_location.new_custom_error(
2982 SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(Token::IDHash(id)),
2983 ));
2984 }
2985 let id = Component::ID(id.into());
2986 SimpleSelectorParseResult::SimpleSelector(id)
2987 }
2988 Token::Delim('.') => {
2989 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2990 return Err(token_location.new_custom_error(
2991 SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(Token::Delim('.')),
2992 ));
2993 }
2994 let location = input.current_source_location();
2995 let class = match *input.next_including_whitespace()? {
2996 Token::Ident(ref class) => class.clone(),
2997 ref t => {
2998 let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
2999 return Err(location.new_custom_error(e));
3000 }
3001 };
3002 let class = Component::Class(class.into());
3003 SimpleSelectorParseResult::SimpleSelector(class)
3004 }
3005 Token::SquareBracketBlock => {
3006 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3007 return Err(token_location.new_custom_error(
3008 SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(Token::SquareBracketBlock),
3009 ));
3010 }
3011 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
3012 SimpleSelectorParseResult::SimpleSelector(attr)
3013 }
3014 Token::Colon => {
3015 let location = input.current_source_location();
3016 let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
3017 Token::Colon => (false, input.next_including_whitespace()?.clone()),
3018 t => (true, t),
3019 };
3020 let (name, is_functional) = match next_token {
3021 Token::Ident(name) => (name, false),
3022 Token::Function(name) => (name, true),
3023 t => {
3024 let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t);
3025 return Err(input.new_custom_error(e));
3026 }
3027 };
3028 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
3029 if is_pseudo_element {
3030 if !state.allows_pseudos() {
3031 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3032 }
3033 let pseudo_element = if is_functional {
3034 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
3035 if !state.allows_part() {
3036 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3037 }
3038 let names = input.parse_nested_block(|input| {
3039 let mut result = Vec::with_capacity(1);
3040 result.push(input.expect_ident_cloned()?.into());
3041 while !input.is_exhausted() {
3042 result.push(input.expect_ident_cloned()?.into());
3043 }
3044 Ok(result.into_boxed_slice())
3045 })?;
3046 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
3047 }
3048 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
3049 if !state.allows_slotted() {
3050 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3051 }
3052 let selector =
3053 input.parse_nested_block(|input| parse_inner_compound_selector(parser, input, state))?;
3054 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
3055 }
3056 input.parse_nested_block(|input| P::parse_functional_pseudo_element(parser, name, input))?
3057 } else {
3058 P::parse_pseudo_element(parser, location, name)?
3059 };
3060
3061 if state.intersects(SelectorParsingState::AFTER_SLOTTED) && !pseudo_element.valid_after_slotted() {
3062 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3063 }
3064 SimpleSelectorParseResult::PseudoElement(pseudo_element)
3065 } else {
3066 let pseudo_class = if is_functional {
3067 input.parse_nested_block(|input| parse_functional_pseudo_class(parser, input, name, state))?
3068 } else {
3069 parse_simple_pseudo_class(parser, location, name, *state)?
3070 };
3071 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
3072 }
3073 }
3074 Token::Delim('&') if parser.is_nesting_allowed() => {
3075 *state |= SelectorParsingState::AFTER_NESTING;
3076 SimpleSelectorParseResult::SimpleSelector(Component::Nesting)
3077 }
3078 _ => {
3079 input.reset(&start);
3080 return Ok(None);
3081 }
3082 }))
3083}
3084
3085fn parse_simple_pseudo_class<'i, P, Impl>(
3086 parser: &P,
3087 location: SourceLocation,
3088 name: CowRcStr<'i>,
3089 state: SelectorParsingState,
3090) -> Result<Component<'i, Impl>, ParseError<'i, P::Error>>
3091where
3092 P: Parser<'i, Impl = Impl>,
3093 Impl: SelectorImpl<'i>,
3094{
3095 if !state.allows_non_functional_pseudo_classes() {
3096 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3097 }
3098
3099 if state.allows_tree_structural_pseudo_classes() {
3100 match_ignore_ascii_case! { &name,
3101 "first-child" => return Ok(Component::Nth(NthSelectorData::first(false))),
3102 "last-child" => return Ok(Component::Nth(NthSelectorData::last(false))),
3103 "only-child" => return Ok(Component::Nth(NthSelectorData::only(false))),
3104 "root" => return Ok(Component::Root),
3105 "empty" => return Ok(Component::Empty),
3106 "scope" => return Ok(Component::Scope),
3107 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
3108 "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(true))),
3109 "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(true))),
3110 "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(true))),
3111 _ => {},
3112 }
3113 }
3114
3115 if state.intersects(SelectorParsingState::AFTER_VIEW_TRANSITION) {
3118 match_ignore_ascii_case! { &name,
3119 "only-child" => return Ok(Component::Nth(NthSelectorData::only(false))),
3120 _ => {}
3121 }
3122 }
3123
3124 let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
3125 if state.intersects(SelectorParsingState::AFTER_WEBKIT_SCROLLBAR) {
3126 if !pseudo_class.is_valid_after_webkit_scrollbar() {
3127 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidPseudoClassAfterWebKitScrollbar));
3128 }
3129 } else if state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT) {
3130 if !pseudo_class.is_user_action_state() {
3131 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidPseudoClassAfterPseudoElement));
3132 }
3133 } else if !pseudo_class.is_valid_before_webkit_scrollbar() {
3134 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidPseudoClassBeforeWebKitScrollbar));
3135 }
3136 Ok(Component::NonTSPseudoClass(pseudo_class))
3137}
3138
3139#[cfg(test)]
3141pub mod tests {
3142 use super::*;
3143 use crate::builder::SelectorFlags;
3144 use crate::parser;
3145 use cssparser::{serialize_identifier, serialize_string, Parser as CssParser, ParserInput, ToCss};
3146 use std::collections::HashMap;
3147 use std::fmt;
3148
3149 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
3150 pub enum PseudoClass {
3151 Hover,
3152 Active,
3153 Lang(String),
3154 }
3155
3156 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
3157 pub enum PseudoElement {
3158 Before,
3159 After,
3160 }
3161
3162 impl<'i> parser::PseudoElement<'i> for PseudoElement {
3163 type Impl = DummySelectorImpl;
3164
3165 fn accepts_state_pseudo_classes(&self) -> bool {
3166 true
3167 }
3168
3169 fn valid_after_slotted(&self) -> bool {
3170 true
3171 }
3172 }
3173
3174 impl<'i> parser::NonTSPseudoClass<'i> for PseudoClass {
3175 type Impl = DummySelectorImpl;
3176
3177 #[inline]
3178 fn is_active_or_hover(&self) -> bool {
3179 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
3180 }
3181
3182 #[inline]
3183 fn is_user_action_state(&self) -> bool {
3184 self.is_active_or_hover()
3185 }
3186 }
3187
3188 impl ToCss for PseudoClass {
3189 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3190 where
3191 W: fmt::Write,
3192 {
3193 match *self {
3194 PseudoClass::Hover => dest.write_str(":hover"),
3195 PseudoClass::Active => dest.write_str(":active"),
3196 PseudoClass::Lang(ref lang) => {
3197 dest.write_str(":lang(")?;
3198 serialize_identifier(lang, dest)?;
3199 dest.write_char(')')
3200 }
3201 }
3202 }
3203 }
3204
3205 impl ToCss for PseudoElement {
3206 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3207 where
3208 W: fmt::Write,
3209 {
3210 match *self {
3211 PseudoElement::Before => dest.write_str("::before"),
3212 PseudoElement::After => dest.write_str("::after"),
3213 }
3214 }
3215 }
3216
3217 #[derive(Clone, Debug, PartialEq)]
3218 pub struct DummySelectorImpl;
3219
3220 #[derive(Default)]
3221 pub struct DummyParser {
3222 default_ns: Option<DummyAtom>,
3223 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
3224 }
3225
3226 impl DummyParser {
3227 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
3228 DummyParser {
3229 default_ns: Some(default_ns),
3230 ns_prefixes: Default::default(),
3231 }
3232 }
3233 }
3234
3235 impl<'i> SelectorImpl<'i> for DummySelectorImpl {
3236 type ExtraMatchingData = ();
3237 type AttrValue = DummyAttrValue;
3238 type Identifier = DummyAtom;
3239 type LocalName = DummyAtom;
3240 type NamespaceUrl = DummyAtom;
3241 type NamespacePrefix = DummyAtom;
3242 type BorrowedLocalName = DummyAtom;
3243 type BorrowedNamespaceUrl = DummyAtom;
3244 type NonTSPseudoClass = PseudoClass;
3245 type PseudoElement = PseudoElement;
3246 type VendorPrefix = u8;
3247 }
3248
3249 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3250 pub struct DummyAttrValue(String);
3251
3252 impl ToCss for DummyAttrValue {
3253 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3254 where
3255 W: fmt::Write,
3256 {
3257 serialize_string(&self.0, dest)
3258 }
3259 }
3260
3261 impl AsRef<str> for DummyAttrValue {
3262 fn as_ref(&self) -> &str {
3263 self.0.as_ref()
3264 }
3265 }
3266
3267 impl<'a> From<&'a str> for DummyAttrValue {
3268 fn from(string: &'a str) -> Self {
3269 Self(string.into())
3270 }
3271 }
3272
3273 impl<'a> From<std::borrow::Cow<'a, str>> for DummyAttrValue {
3274 fn from(string: std::borrow::Cow<'a, str>) -> Self {
3275 Self(string.to_string())
3276 }
3277 }
3278
3279 impl<'a> From<CowRcStr<'a>> for DummyAttrValue {
3280 fn from(string: CowRcStr<'a>) -> Self {
3281 Self(string.to_string())
3282 }
3283 }
3284
3285 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3286 pub struct DummyAtom(String);
3287
3288 impl ToCss for DummyAtom {
3289 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3290 where
3291 W: fmt::Write,
3292 {
3293 serialize_identifier(&self.0, dest)
3294 }
3295 }
3296
3297 impl From<String> for DummyAtom {
3298 fn from(string: String) -> Self {
3299 DummyAtom(string)
3300 }
3301 }
3302
3303 impl<'a> From<&'a str> for DummyAtom {
3304 fn from(string: &'a str) -> Self {
3305 DummyAtom(string.into())
3306 }
3307 }
3308
3309 impl<'a> From<CowRcStr<'a>> for DummyAtom {
3310 fn from(string: CowRcStr<'a>) -> Self {
3311 DummyAtom(string.to_string())
3312 }
3313 }
3314
3315 impl AsRef<str> for DummyAtom {
3316 fn as_ref(&self) -> &str {
3317 self.0.as_ref()
3318 }
3319 }
3320
3321 impl<'a> From<std::borrow::Cow<'a, str>> for DummyAtom {
3322 fn from(string: std::borrow::Cow<'a, str>) -> Self {
3323 Self(string.to_string())
3324 }
3325 }
3326
3327 impl<'i> Parser<'i> for DummyParser {
3328 type Impl = DummySelectorImpl;
3329 type Error = SelectorParseErrorKind<'i>;
3330
3331 fn parse_slotted(&self) -> bool {
3332 true
3333 }
3334
3335 fn parse_is_and_where(&self) -> bool {
3336 true
3337 }
3338
3339 fn is_and_where_error_recovery(&self) -> ParseErrorRecovery {
3340 ParseErrorRecovery::DiscardList
3341 }
3342
3343 fn parse_part(&self) -> bool {
3344 true
3345 }
3346
3347 fn parse_non_ts_pseudo_class(
3348 &self,
3349 location: SourceLocation,
3350 name: CowRcStr<'i>,
3351 ) -> Result<PseudoClass, SelectorParseError<'i>> {
3352 match_ignore_ascii_case! { &name,
3353 "hover" => return Ok(PseudoClass::Hover),
3354 "active" => return Ok(PseudoClass::Active),
3355 _ => {}
3356 }
3357 Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClass(name)))
3358 }
3359
3360 fn parse_non_ts_functional_pseudo_class<'t>(
3361 &self,
3362 name: CowRcStr<'i>,
3363 parser: &mut CssParser<'i, 't>,
3364 ) -> Result<PseudoClass, SelectorParseError<'i>> {
3365 match_ignore_ascii_case! { &name,
3366 "lang" => {
3367 let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
3368 return Ok(PseudoClass::Lang(lang));
3369 },
3370 _ => {}
3371 }
3372 Err(parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClass(name)))
3373 }
3374
3375 fn parse_pseudo_element(
3376 &self,
3377 location: SourceLocation,
3378 name: CowRcStr<'i>,
3379 ) -> Result<PseudoElement, SelectorParseError<'i>> {
3380 match_ignore_ascii_case! { &name,
3381 "before" => return Ok(PseudoElement::Before),
3382 "after" => return Ok(PseudoElement::After),
3383 _ => {}
3384 }
3385 Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoElement(name)))
3386 }
3387
3388 fn default_namespace(&self) -> Option<DummyAtom> {
3389 self.default_ns.clone()
3390 }
3391
3392 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
3393 self.ns_prefixes.get(prefix).cloned()
3394 }
3395 }
3396
3397 fn parse<'i>(input: &'i str) -> Result<SelectorList<'i, DummySelectorImpl>, SelectorParseError<'i>> {
3398 parse_ns(input, &DummyParser::default())
3399 }
3400
3401 fn parse_ns<'i>(
3409 input: &'i str,
3410 parser: &DummyParser,
3411 ) -> Result<SelectorList<'i, DummySelectorImpl>, SelectorParseError<'i>> {
3412 parse_ns_expected(input, parser, None)
3413 }
3414
3415 fn parse_ns_expected<'i, 'a>(
3416 input: &'i str,
3417 parser: &DummyParser,
3418 expected: Option<&'a str>,
3419 ) -> Result<SelectorList<'i, DummySelectorImpl>, SelectorParseError<'i>> {
3420 let mut parser_input = ParserInput::new(input);
3421 let result = SelectorList::parse(
3422 parser,
3423 &mut CssParser::new(&mut parser_input),
3424 ParseErrorRecovery::DiscardList,
3425 NestingRequirement::None,
3426 );
3427 if let Ok(ref selectors) = result {
3428 assert_eq!(selectors.0.len(), 1);
3429 assert_eq!(
3433 selectors.0[0].to_css_string(),
3434 match expected {
3435 Some(x) => x,
3436 None => input,
3437 }
3438 );
3439 }
3440 result
3441 }
3442
3443 fn specificity(a: u32, b: u32, c: u32) -> u32 {
3444 a << 20 | b << 10 | c
3445 }
3446
3447 #[test]
3448 fn test_empty() {
3449 let mut input = ParserInput::new(":empty");
3450 let list = SelectorList::parse(
3451 &DummyParser::default(),
3452 &mut CssParser::new(&mut input),
3453 ParseErrorRecovery::DiscardList,
3454 NestingRequirement::None,
3455 );
3456 assert!(list.is_ok());
3457 }
3458
3459 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
3460 const SVG: &str = "http://www.w3.org/2000/svg";
3461
3462 #[test]
3463 fn test_parsing() {
3464 assert!(parse("").is_err());
3465 assert!(parse(":lang(4)").is_err());
3466 assert!(parse(":lang(en US)").is_err());
3467 assert_eq!(
3468 parse("EeÉ"),
3469 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3470 vec![Component::LocalName(LocalName {
3471 name: DummyAtom::from("EeÉ"),
3472 lower_name: DummyAtom::from("eeÉ"),
3473 })],
3474 specificity(0, 0, 1),
3475 Default::default(),
3476 )]))
3477 );
3478 assert_eq!(
3479 parse("|e"),
3480 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3481 vec![
3482 Component::ExplicitNoNamespace,
3483 Component::LocalName(LocalName {
3484 name: DummyAtom::from("e"),
3485 lower_name: DummyAtom::from("e"),
3486 }),
3487 ],
3488 specificity(0, 0, 1),
3489 Default::default(),
3490 )]))
3491 );
3492 assert_eq!(
3527 parse("*"),
3528 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3529 vec![Component::ExplicitUniversalType],
3530 specificity(0, 0, 0),
3531 Default::default(),
3532 )]))
3533 );
3534 assert_eq!(
3535 parse("|*"),
3536 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3537 vec![Component::ExplicitNoNamespace, Component::ExplicitUniversalType,],
3538 specificity(0, 0, 0),
3539 Default::default(),
3540 )]))
3541 );
3542 assert_eq!(
3551 parse_ns(
3552 "*|*",
3553 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
3554 ),
3555 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3556 vec![Component::ExplicitAnyNamespace, Component::ExplicitUniversalType,],
3557 specificity(0, 0, 0),
3558 Default::default(),
3559 )]))
3560 );
3561 assert_eq!(
3562 parse(".foo:lang(en-US)"),
3563 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3564 vec![
3565 Component::Class(DummyAtom::from("foo")),
3566 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
3567 ],
3568 specificity(0, 2, 0),
3569 Default::default(),
3570 )]))
3571 );
3572 assert_eq!(
3573 parse("#bar"),
3574 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3575 vec![Component::ID(DummyAtom::from("bar"))],
3576 specificity(1, 0, 0),
3577 Default::default(),
3578 )]))
3579 );
3580 assert_eq!(
3581 parse("e.foo#bar"),
3582 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3583 vec![
3584 Component::LocalName(LocalName {
3585 name: DummyAtom::from("e"),
3586 lower_name: DummyAtom::from("e"),
3587 }),
3588 Component::Class(DummyAtom::from("foo")),
3589 Component::ID(DummyAtom::from("bar")),
3590 ],
3591 specificity(1, 1, 1),
3592 Default::default(),
3593 )]))
3594 );
3595 assert_eq!(
3596 parse("e.foo #bar"),
3597 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3598 vec![
3599 Component::LocalName(LocalName {
3600 name: DummyAtom::from("e"),
3601 lower_name: DummyAtom::from("e"),
3602 }),
3603 Component::Class(DummyAtom::from("foo")),
3604 Component::Combinator(Combinator::Descendant),
3605 Component::ID(DummyAtom::from("bar")),
3606 ],
3607 specificity(1, 1, 1),
3608 Default::default(),
3609 )]))
3610 );
3611 let mut parser = DummyParser::default();
3614 assert_eq!(
3615 parse_ns("[Foo]", &parser),
3616 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3617 vec![Component::AttributeInNoNamespaceExists {
3618 local_name: DummyAtom::from("Foo"),
3619 local_name_lower: DummyAtom::from("foo"),
3620 }],
3621 specificity(0, 1, 0),
3622 Default::default(),
3623 )]))
3624 );
3625 assert!(parse_ns("svg|circle", &parser).is_err());
3626 parser.ns_prefixes.insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
3627 assert_eq!(
3628 parse_ns("svg|circle", &parser),
3629 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3630 vec![
3631 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
3632 Component::LocalName(LocalName {
3633 name: DummyAtom::from("circle"),
3634 lower_name: DummyAtom::from("circle"),
3635 }),
3636 ],
3637 specificity(0, 0, 1),
3638 Default::default(),
3639 )]))
3640 );
3641 assert_eq!(
3642 parse_ns("svg|*", &parser),
3643 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3644 vec![
3645 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
3646 Component::ExplicitUniversalType,
3647 ],
3648 specificity(0, 0, 0),
3649 Default::default(),
3650 )]))
3651 );
3652 parser.default_ns = Some(MATHML.into());
3657 assert_eq!(
3658 parse_ns("[Foo]", &parser),
3659 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3660 vec![
3661 Component::DefaultNamespace(MATHML.into()),
3662 Component::AttributeInNoNamespaceExists {
3663 local_name: DummyAtom::from("Foo"),
3664 local_name_lower: DummyAtom::from("foo"),
3665 },
3666 ],
3667 specificity(0, 1, 0),
3668 Default::default(),
3669 )]))
3670 );
3671 assert_eq!(
3673 parse_ns("e", &parser),
3674 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3675 vec![
3676 Component::DefaultNamespace(MATHML.into()),
3677 Component::LocalName(LocalName {
3678 name: DummyAtom::from("e"),
3679 lower_name: DummyAtom::from("e"),
3680 }),
3681 ],
3682 specificity(0, 0, 1),
3683 Default::default(),
3684 )]))
3685 );
3686 assert_eq!(
3687 parse_ns("*", &parser),
3688 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3689 vec![
3690 Component::DefaultNamespace(MATHML.into()),
3691 Component::ExplicitUniversalType,
3692 ],
3693 specificity(0, 0, 0),
3694 Default::default(),
3695 )]))
3696 );
3697 assert_eq!(
3698 parse_ns("*|*", &parser),
3699 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3700 vec![Component::ExplicitAnyNamespace, Component::ExplicitUniversalType,],
3701 specificity(0, 0, 0),
3702 Default::default(),
3703 )]))
3704 );
3705 assert_eq!(
3708 parse_ns(":not(.cl)", &parser),
3709 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3710 vec![
3711 Component::DefaultNamespace(MATHML.into()),
3712 Component::Negation(
3713 vec![Selector::from_vec(
3714 vec![Component::Class(DummyAtom::from("cl"))],
3715 specificity(0, 1, 0),
3716 Default::default(),
3717 )]
3718 .into_boxed_slice()
3719 ),
3720 ],
3721 specificity(0, 1, 0),
3722 Default::default(),
3723 )]))
3724 );
3725 assert_eq!(
3726 parse_ns(":not(*)", &parser),
3727 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3728 vec![
3729 Component::DefaultNamespace(MATHML.into()),
3730 Component::Negation(
3731 vec![Selector::from_vec(
3732 vec![
3733 Component::DefaultNamespace(MATHML.into()),
3734 Component::ExplicitUniversalType,
3735 ],
3736 specificity(0, 0, 0),
3737 Default::default(),
3738 )]
3739 .into_boxed_slice(),
3740 ),
3741 ],
3742 specificity(0, 0, 0),
3743 Default::default(),
3744 )]))
3745 );
3746 assert_eq!(
3747 parse_ns(":not(e)", &parser),
3748 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3749 vec![
3750 Component::DefaultNamespace(MATHML.into()),
3751 Component::Negation(
3752 vec![Selector::from_vec(
3753 vec![
3754 Component::DefaultNamespace(MATHML.into()),
3755 Component::LocalName(LocalName {
3756 name: DummyAtom::from("e"),
3757 lower_name: DummyAtom::from("e"),
3758 }),
3759 ],
3760 specificity(0, 0, 1),
3761 Default::default(),
3762 ),]
3763 .into_boxed_slice()
3764 ),
3765 ],
3766 specificity(0, 0, 1),
3767 Default::default(),
3768 )]))
3769 );
3770 assert_eq!(
3771 parse("[attr|=\"foo\"]"),
3772 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3773 vec![Component::AttributeInNoNamespace {
3774 local_name: DummyAtom::from("attr"),
3775 operator: AttrSelectorOperator::DashMatch,
3776 value: DummyAttrValue::from("foo"),
3777 never_matches: false,
3778 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
3779 }],
3780 specificity(0, 1, 0),
3781 Default::default(),
3782 )]))
3783 );
3784 assert_eq!(
3786 parse("::before"),
3787 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3788 vec![
3789 Component::Combinator(Combinator::PseudoElement),
3790 Component::PseudoElement(PseudoElement::Before),
3791 ],
3792 specificity(0, 0, 1),
3793 SelectorFlags::HAS_PSEUDO,
3794 )]))
3795 );
3796 assert_eq!(
3797 parse("::before:hover"),
3798 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3799 vec![
3800 Component::Combinator(Combinator::PseudoElement),
3801 Component::PseudoElement(PseudoElement::Before),
3802 Component::NonTSPseudoClass(PseudoClass::Hover),
3803 ],
3804 specificity(0, 1, 1),
3805 SelectorFlags::HAS_PSEUDO,
3806 )]))
3807 );
3808 assert_eq!(
3809 parse("::before:hover:hover"),
3810 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3811 vec![
3812 Component::Combinator(Combinator::PseudoElement),
3813 Component::PseudoElement(PseudoElement::Before),
3814 Component::NonTSPseudoClass(PseudoClass::Hover),
3815 Component::NonTSPseudoClass(PseudoClass::Hover),
3816 ],
3817 specificity(0, 2, 1),
3818 SelectorFlags::HAS_PSEUDO,
3819 )]))
3820 );
3821 assert!(parse("::before:hover:lang(foo)").is_err());
3822 assert!(parse("::before:hover .foo").is_err());
3823 assert!(parse("::before .foo").is_err());
3824 assert!(parse("::before ~ bar").is_err());
3825 assert!(parse("::before:active").is_ok());
3826
3827 assert!(parse(":: before").is_err());
3829 assert_eq!(
3830 parse("div ::after"),
3831 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3832 vec![
3833 Component::LocalName(LocalName {
3834 name: DummyAtom::from("div"),
3835 lower_name: DummyAtom::from("div"),
3836 }),
3837 Component::Combinator(Combinator::Descendant),
3838 Component::Combinator(Combinator::PseudoElement),
3839 Component::PseudoElement(PseudoElement::After),
3840 ],
3841 specificity(0, 0, 2),
3842 SelectorFlags::HAS_PSEUDO,
3843 )]))
3844 );
3845 assert_eq!(
3846 parse("#d1 > .ok"),
3847 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3848 vec![
3849 Component::ID(DummyAtom::from("d1")),
3850 Component::Combinator(Combinator::Child),
3851 Component::Class(DummyAtom::from("ok")),
3852 ],
3853 (1 << 20) + (1 << 10) + (0 << 0),
3854 Default::default(),
3855 )]))
3856 );
3857 parser.default_ns = None;
3858 assert!(parse(":not(#provel.old)").is_ok());
3859 assert!(parse(":not(#provel > old)").is_ok());
3860 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
3861 assert_eq!(
3863 parse_ns(":not(*)", &parser),
3864 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3865 vec![Component::Negation(
3866 vec![Selector::from_vec(
3867 vec![Component::ExplicitUniversalType],
3868 specificity(0, 0, 0),
3869 Default::default(),
3870 )]
3871 .into_boxed_slice()
3872 )],
3873 specificity(0, 0, 0),
3874 Default::default(),
3875 )]))
3876 );
3877 assert_eq!(
3878 parse_ns(":not(|*)", &parser),
3879 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3880 vec![Component::Negation(
3881 vec![Selector::from_vec(
3882 vec![Component::ExplicitNoNamespace, Component::ExplicitUniversalType,],
3883 specificity(0, 0, 0),
3884 Default::default(),
3885 )]
3886 .into_boxed_slice(),
3887 )],
3888 specificity(0, 0, 0),
3889 Default::default(),
3890 )]))
3891 );
3892 assert!(parse("::slotted()").is_err());
3911 assert!(parse("::slotted(div)").is_ok());
3912 assert!(parse("::slotted(div).foo").is_err());
3913 assert!(parse("::slotted(div + bar)").is_err());
3914 assert!(parse("::slotted(div) + foo").is_err());
3915
3916 assert!(parse("::part()").is_err());
3917 assert!(parse("::part(42)").is_err());
3918 assert!(parse("::part(foo bar)").is_ok());
3919 assert!(parse("::part(foo):hover").is_ok());
3920 assert!(parse("::part(foo) + bar").is_err());
3921
3922 assert!(parse("div ::slotted(div)").is_ok());
3923 assert!(parse("div + slot::slotted(div)").is_ok());
3924 assert!(parse("div + slot::slotted(div.foo)").is_ok());
3925 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
3926 assert!(parse("::slotted(div)::before").is_ok());
3927 assert!(parse("slot::slotted(div,foo)").is_err());
3928
3929 assert!(parse("foo:where()").is_err());
3930 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
3931 assert!(parse("foo:where(::before)").is_err());
3932
3933 assert!(parse("foo::details-content").is_ok());
3934 assert!(parse("foo::target-text").is_ok());
3935
3936 assert!(parse("select::picker").is_err());
3937 assert!(parse("::picker()").is_err());
3938 assert!(parse("::picker(select)").is_ok());
3939 assert!(parse("select::picker-icon").is_ok());
3940 assert!(parse("option::checkmark").is_ok());
3941 }
3942
3943 #[test]
3944 fn test_pseudo_iter() {
3945 let selector = &parse("q::before").unwrap().0[0];
3946 assert!(!selector.is_universal());
3947 let mut iter = selector.iter();
3948 assert_eq!(iter.next(), Some(&Component::PseudoElement(PseudoElement::Before)));
3949 assert_eq!(iter.next(), None);
3950 let combinator = iter.next_sequence();
3951 assert_eq!(combinator, Some(Combinator::PseudoElement));
3952 assert!(matches!(iter.next(), Some(&Component::LocalName(..))));
3953 assert_eq!(iter.next(), None);
3954 assert_eq!(iter.next_sequence(), None);
3955 }
3956
3957 #[test]
3958 fn test_universal() {
3959 let selector = &parse_ns(
3960 "*|*::before",
3961 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
3962 )
3963 .unwrap()
3964 .0[0];
3965 assert!(selector.is_universal());
3966 }
3967
3968 #[test]
3969 fn test_empty_pseudo_iter() {
3970 let selector = &parse("::before").unwrap().0[0];
3971 assert!(selector.is_universal());
3972 let mut iter = selector.iter();
3973 assert_eq!(iter.next(), Some(&Component::PseudoElement(PseudoElement::Before)));
3974 assert_eq!(iter.next(), None);
3975 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
3976 assert_eq!(iter.next(), None);
3977 assert_eq!(iter.next_sequence(), None);
3978 }
3979
3980 struct TestVisitor {
3981 seen: Vec<String>,
3982 }
3983
3984 impl<'i> SelectorVisitor<'i> for TestVisitor {
3985 type Impl = DummySelectorImpl;
3986
3987 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
3988 let mut dest = String::new();
3989 s.to_css(&mut dest).unwrap();
3990 self.seen.push(dest);
3991 true
3992 }
3993 }
3994
3995 #[test]
3996 fn visitor() {
3997 let mut test_visitor = TestVisitor { seen: vec![] };
3998 parse(":not(:hover) ~ label").unwrap().0[0].visit(&mut test_visitor);
3999 assert!(test_visitor.seen.contains(&":hover".into()));
4000
4001 let mut test_visitor = TestVisitor { seen: vec![] };
4002 parse("::before:hover").unwrap().0[0].visit(&mut test_visitor);
4003 assert!(test_visitor.seen.contains(&":hover".into()));
4004 }
4005}