procss/ast/selector/
attribute.rs

1// ┌───────────────────────────────────────────────────────────────────────────┐
2// │                                                                           │
3// │  ██████╗ ██████╗  ██████╗   Copyright (C) 2022, The Prospective Company   │
4// │  ██╔══██╗██╔══██╗██╔═══██╗                                                │
5// │  ██████╔╝██████╔╝██║   ██║  This file is part of the Procss library,      │
6// │  ██╔═══╝ ██╔══██╗██║   ██║  distributed under the terms of the            │
7// │  ██║     ██║  ██║╚██████╔╝  Apache License 2.0.  The full license can     │
8// │  ╚═╝     ╚═╝  ╚═╝ ╚═════╝   be found in the LICENSE file.                 │
9// │                                                                           │
10// └───────────────────────────────────────────────────────────────────────────┘
11
12use nom::bytes::complete::{is_not, tag};
13use nom::combinator::opt;
14use nom::error::ParseError;
15use nom::sequence::{preceded, tuple};
16use nom::IResult;
17
18use crate::ast::token::*;
19use crate::parser::*;
20
21/// A selector which matches attributes, optionally against their value as well.
22/// TODO doesn't support comma-separated multiple selectors.
23///
24/// # Example
25///
26/// ```css
27/// div[name=test] {}
28/// div[disabled,data-value="red"] {}
29/// ```
30#[derive(Clone, Debug, Eq, PartialEq, Hash)]
31pub struct SelectorAttr<'a> {
32    pub name: &'a str,
33    pub value: Option<&'a str>,
34}
35
36impl<'a> ParseCss<'a> for SelectorAttr<'a> {
37    fn parse<E>(input: &'a str) -> IResult<&'a str, Self, E>
38    where
39        E: ParseError<&'a str>,
40    {
41        let (rest, (_, name, value, _)) = tuple((
42            tag("["),
43            parse_symbol,
44            opt(preceded(tag("="), is_not("]"))),
45            tag("]"),
46        ))(input)?;
47        Ok((rest, SelectorAttr { name, value }))
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use std::assert_matches::assert_matches;
54
55    use super::*;
56
57    #[test]
58    fn test_bool() {
59        assert_matches!(
60            SelectorAttr::parse::<()>("[disabled]"),
61            Ok(("", SelectorAttr {
62                name: "disabled",
63                value: None
64            }))
65        )
66    }
67
68    #[test]
69    fn test_value_quotes() {
70        assert_matches!(
71            SelectorAttr::parse::<()>("[data-value=\"red\"]"),
72            Ok(("", SelectorAttr {
73                name: "data-value",
74                value: Some("\"red\"")
75            }))
76        )
77    }
78
79    #[ignore]
80    #[test]
81    fn test_multiple() {
82        assert_matches!(
83            SelectorAttr::parse::<()>("[disabled,data-value=\"red\"]"),
84            Ok(("", SelectorAttr {
85                name: "data-value",
86                value: Some("\"red\"")
87            }))
88        )
89    }
90}