Skip to main content

ferroui_base/utilities/
style_class_parser.rs

1//! Style class name parsing on top of [`CharacterReader`].
2
3use super::character_reader::{is_identifier_part_category, is_letter, CharacterReader};
4
5impl<'a> CharacterReader<'a> {
6    /// Parses a style class name: an identifier that may also contain `-`.
7    /// Returns an empty string (consuming nothing) when the input does not
8    /// start with a class name.
9    pub fn parse_style_class(&mut self) -> &'a str {
10        if self.peek().is_some_and(is_valid_identifier_start) {
11            self.take_while(is_valid_identifier_char)
12        } else {
13            ""
14        }
15    }
16}
17
18fn is_valid_identifier_start(c: char) -> bool {
19    is_letter(c) || c == '_'
20}
21
22fn is_valid_identifier_char(c: char) -> bool {
23    is_valid_identifier_start(c) || c == '-' || is_identifier_part_category(c)
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    #[test]
31    fn parses_style_class_with_dashes() {
32        let mut r = CharacterReader::new("nth-last-child(2)");
33        assert_eq!(r.parse_style_class(), "nth-last-child");
34        assert_eq!(r.peek(), Some('('));
35        assert_eq!(r.position(), 14);
36    }
37
38    #[test]
39    fn style_class_cannot_start_with_dash_digit_or_symbol() {
40        assert_eq!(CharacterReader::new("-foo").parse_style_class(), "");
41        assert_eq!(CharacterReader::new("1foo").parse_style_class(), "");
42        assert_eq!(CharacterReader::new("%foo").parse_style_class(), "");
43        assert_eq!(CharacterReader::new("").parse_style_class(), "");
44    }
45
46    #[test]
47    fn parses_underscored_class_with_digits() {
48        assert_eq!(CharacterReader::new("_foo1 bar").parse_style_class(), "_foo1");
49    }
50}