1use crate::class_dictionary::{ClassDictionary, ClassDictionaryError};
2use crate::color::{ColorName, CssColor};
3use crate::font::FontName;
4use crate::{Classes, ConfigLookup, SunbeamConfig};
5use syn::parse::{Parse, ParseStream};
6use syn::LitStr;
7
8struct AlwaysSucceedsConfigLookup {
17 color: CssColor,
18 font_families: Vec<String>,
19}
20impl ConfigLookup for AlwaysSucceedsConfigLookup {
21 fn get_color(&self, _color_name: &ColorName) -> Option<&CssColor> {
22 Some(&self.color)
23 }
24
25 fn get_font(&self, _font_name: &FontName) -> Option<&Vec<String>> {
26 Some(&self.font_families)
27 }
28}
29
30impl Classes {
31 pub fn parse_str(
33 classes: &str,
34 config: &SunbeamConfig,
35 ) -> Result<Self, Vec<ClassDictionaryError>> {
36 Self::impl_parse_str(&classes, config)
37 }
38}
39
40impl Parse for Classes {
41 fn parse(input: ParseStream) -> syn::Result<Self> {
42 let classes_lit_str: LitStr = input.parse()?;
43 let classes: String = classes_lit_str.value();
44
45 let config_lookup = AlwaysSucceedsConfigLookup {
46 color: CssColor::new("some-color".to_string()).unwrap(),
47 font_families: vec![],
48 };
49
50 Self::impl_parse_str(&classes, &config_lookup).map_err(|errors| {
51 let mut errors = errors.into_iter();
52
53 let mut combined = syn::Error::new(classes_lit_str.span(), errors.next().unwrap());
54
55 while let Some(err) = errors.next() {
56 combined.combine(syn::Error::new(classes_lit_str.span(), err));
57 }
58
59 combined
60 })
61 }
62}
63
64impl Classes {
65 fn impl_parse_str(
66 classes: &str,
67 config_lookup: &dyn ConfigLookup,
68 ) -> Result<Classes, Vec<ClassDictionaryError>> {
69 let classes_split = classes.trim().split_whitespace();
70
71 let class_dict = ClassDictionary::new();
72
73 let mut classes = vec![];
74 let mut errors = vec![];
75
76 for class in classes_split {
77 match class_dict.get_class_definition(class, config_lookup) {
78 Ok(class_definition) => {
79 classes.push(class_definition);
80 }
81 Err(err) => {
82 errors.push(err);
83 }
84 };
85 }
86
87 if errors.len() > 0 {
88 return Err(errors);
89 }
90
91 Ok(Classes { classes })
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
101 fn parse_multi_line_string() {
102 let css = r#"
103ml5
104mb6
105"#;
106 let config_lookup = always_succeeds_config();
107
108 let classes = Classes::impl_parse_str(css, &config_lookup).unwrap();
109 assert_eq!(classes.len(), 2);
110 }
111
112 fn always_succeeds_config() -> AlwaysSucceedsConfigLookup {
113 AlwaysSucceedsConfigLookup {
114 color: CssColor::new("some-color".to_string()).unwrap(),
115 font_families: vec![],
116 }
117 }
118}