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}