diff --git a/Cargo.lock b/Cargo.lock index 61dc1405..1b94ff1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown", @@ -425,7 +425,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scraper" -version = "0.19.1" +version = "0.20.0" dependencies = [ "ahash", "cssparser", diff --git a/Cargo.toml b/Cargo.toml index bdf64242..3e4e356f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scraper" -version = "0.19.1" +version = "0.20.0" edition = "2021" description = "HTML parsing and querying with CSS selectors" @@ -19,7 +19,7 @@ html5ever = "0.27" selectors = "0.25.0" tendril = "0.4.3" ahash = "0.8" -indexmap = { version = "2.2.6", optional = true } +indexmap = { version = "2.3.0", optional = true } once_cell = "1.19" [dependencies.getopts] diff --git a/src/element_ref/mod.rs b/src/element_ref/mod.rs index 7357f620..accccbfd 100644 --- a/src/element_ref/mod.rs +++ b/src/element_ref/mod.rs @@ -1,6 +1,6 @@ //! Element references. -use std::fmt; +use std::fmt::{self, Debug}; use std::ops::Deref; use ego_tree::iter::{Edge, Traverse}; @@ -15,7 +15,7 @@ use crate::{Node, Selector}; /// /// This wrapper implements the `Element` trait from the `selectors` crate, which allows it to be /// matched against CSS selectors. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct ElementRef<'a> { node: NodeRef<'a, Node>, } @@ -116,6 +116,12 @@ impl<'a> ElementRef<'a> { } } +impl<'a> Debug for ElementRef<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(self.value(), f) + } +} + impl<'a> Deref for ElementRef<'a> { type Target = NodeRef<'a, Node>; fn deref(&self) -> &NodeRef<'a, Node> { @@ -131,7 +137,7 @@ pub struct Select<'a, 'b> { nth_index_cache: NthIndexCache, } -impl fmt::Debug for Select<'_, '_> { +impl Debug for Select<'_, '_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Select") .field("scope", &self.scope) diff --git a/src/selector.rs b/src/selector.rs index 7ef13f2f..1e6da7df 100644 --- a/src/selector.rs +++ b/src/selector.rs @@ -86,6 +86,14 @@ pub struct Parser; impl<'i> parser::Parser<'i> for Parser { type Impl = Simple; type Error = SelectorParseErrorKind<'i>; + + fn parse_is_and_where(&self) -> bool { + true + } + + fn parse_has(&self) -> bool { + true + } } /// A simple implementation of `SelectorImpl` with no pseudo-classes or pseudo-elements. @@ -222,4 +230,22 @@ mod tests { let s = ""; let _sel: Selector = s.try_into().unwrap(); } + + #[test] + fn has_selector() { + let s = ":has(a)"; + let _sel: Selector = s.try_into().unwrap(); + } + + #[test] + fn is_selector() { + let s = ":is(a)"; + let _sel: Selector = s.try_into().unwrap(); + } + + #[test] + fn where_selector() { + let s = ":where(a)"; + let _sel: Selector = s.try_into().unwrap(); + } } diff --git a/src/test.rs b/src/test.rs index 199d450f..86d498dc 100644 --- a/src/test.rs +++ b/src/test.rs @@ -20,3 +20,27 @@ fn tag_with_newline() { Some("https://github.com/causal-agent/scraper") ); } + +#[test] +fn has_selector() { + let document = Html::parse_fragment( + r#" +
+
+ Hi There! +
+
+ + "#, + ); + + let selector = Selector::parse("div:has(div#foo) + ul > li:nth-child(2)").unwrap(); + + let mut iter = document.select(&selector); + let li = iter.next().unwrap(); + assert_eq!(li.inner_html(), "second"); +}