diff --git a/src/class.rs b/src/class.rs index b544c51..81c9a6f 100644 --- a/src/class.rs +++ b/src/class.rs @@ -120,7 +120,7 @@ impl<'a> Class<'a> { } /// replaces underscores with spaces -fn replace_underscores<'a>(s: &'a str) -> Cow<'a, str> { +fn replace_underscores(s: &str) -> Cow { if s.contains('_') { s.replace('_', " ").into() } else { diff --git a/src/lib.rs b/src/lib.rs index 01cb107..202bbff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,5 @@ use std::collections::HashMap; -use defaults::default_modifiers; - use crate::{defaults::*, parse::*}; mod class; @@ -11,6 +9,9 @@ mod media_queries; mod modifiers; mod parse; +#[cfg(test)] +mod tests; + #[cfg(feature = "inventory")] #[macro_use] pub mod inventory; @@ -19,6 +20,7 @@ pub mod inventory; /// /// contains shorthands and replacements that can be modified /// to customize the css generation +#[derive(Default)] pub struct Zephyr { /// for non-value classes pub declarations: HashMap, @@ -47,30 +49,6 @@ pub enum ZephyrError { } impl Zephyr { - /// builds a `Zephyr` with the default ruleset - pub fn new() -> Self { - Self { - declarations: default_declarations(), - properties: default_properties(), - values: default_values(), - modifiers: default_modifiers(), - pseudos: default_pseudos(), - specials: default_specials(), - } - } - - /// builds a `Zephyr` without the default ruleset - pub fn new_without_defaults() -> Self { - Self { - declarations: HashMap::new(), - properties: HashMap::new(), - values: HashMap::new(), - modifiers: HashMap::new(), - pseudos: HashMap::new(), - specials: HashMap::new(), - } - } - /// generates css rules for all the of the classes that parse correctly pub fn generate_classes<'a>(&self, classes: impl IntoIterator) -> String { // TODO we could return (css, seen_classes) @@ -120,152 +98,16 @@ impl Zephyr { let c = parse_class(class)?; c.generate_with_media_query(self) } -} -#[cfg(test)] -mod tests { - use super::*; - use class::Class; - - #[test] - fn generate_margin_works() { - let z = Zephyr::new(); - - let class = Class { - property: "m", - value: Some("1rem"), - modifiers: vec![].into(), - pseudo: None, - original: "m[1rem]", - value_type: class::ValueType::Normal, - }; - let css = class.generate(&z).unwrap(); - assert_eq!(css, r#".m\[1rem\]{margin:1rem;}"#); - - let class = Class { - property: "m", - value: Some("1rem"), - modifiers: vec!["focus"].into(), - pseudo: None, - original: "m[1rem]focus", - value_type: class::ValueType::Normal, - }; - let css = class.generate(&z).unwrap(); - assert_eq!(css, r#".m\[1rem\]focus:focus{margin:1rem;}"#); - - let class = Class { - property: "m", - value: Some("1rem"), - modifiers: vec!["focus", "hover", "odd"].into(), - pseudo: None, - original: "m[1rem]focus,hover,odd", - value_type: class::ValueType::Normal, - }; - let css = class.generate(&z).unwrap(); - assert_eq!( - css, - r#".m\[1rem\]focus,hover,odd:focus:hover:nth-child\(odd\){margin:1rem;}"# - ); - } - - #[test] - fn generate_classes_works() { - let z = Zephyr::new(); - - let classes = z.generate_classes(["flex-row"]); - assert_eq!(classes, r#".flex-row{display:flex;flex-direction:row}"#); - - let classes = z.generate_classes(["m[3rem]hover,focus$placeholder"]); - assert_eq!( - classes, - r#".m\[3rem\]hover,focus\$placeholder:hover:focus::placeholder{margin:3rem;}"# - ); - - let classes = z.generate_classes(["flex|hover,focus$placeholder"]); - assert_eq!( - classes, - r#".flex\|hover,focus\$placeholder:hover:focus::placeholder{display:flex}"# - ); - - let classes = z.generate_classes(["mr[0.5rem]"]); - assert_eq!(classes, r#".mr\[0\.5rem\]{margin-right:0.5rem;}"#); - } - - #[test] - fn generate_multiple_works() { - let z = Zephyr::new(); - - let classes_joined = z.generate_classes(["flex-row mt[1rem]"]); - let classes_separate = z.generate_classes(["flex-row", "mt[1rem]"]); - assert_eq!( - classes_joined, - r#".flex-row{display:flex;flex-direction:row}.mt\[1rem\]{margin-top:1rem;}"# - ); - assert_eq!(classes_separate, classes_joined); - } - - #[test] - fn generate_specials_works() { - let z = Zephyr::new(); - - let classes = z.generate_classes(["mx[1rem]"]); - assert_eq!( - classes, - r#".mx\[1rem\]{margin-left:1rem;margin-right:1rem;}"# - ); - } - - #[test] - fn generate_with_spaces_works() { - let z = Zephyr::new(); - - let classes = z.generate_classes(["border[1px_solid_black]"]); - assert_eq!( - classes, - r#".border\[1px_solid_black\]{border:1px solid black;}"# - ); - } - - #[test] - fn generate_literals_works() { - let z = Zephyr::new(); - - // the curly brackets indicate that the value should not go through replacements - let classes = z.generate_classes(["border{1px_solid_black}", "w{full}"]); - assert_eq!( - classes, - r#".border\{1px_solid_black\}{border:1px_solid_black;}.w\{full\}{width:full;}"# - ); - } - - #[test] - fn generate_with_media_query() { - let z = Zephyr::new(); - - let classes = z.generate_classes(["m[1rem]sm"]); - assert_eq!( - classes, - r#"@media(min-width:640px){.m\[1rem\]sm{margin:1rem;}}"# - ); - } - - #[test] - fn generate_variable() { - let z = Zephyr::new(); - - // the parens indicate that it should be replaced by `var(--...)` - let classes = z.generate_classes(["m(my-margin)"]); - assert_eq!(classes, r#".m\(my-margin\){margin:var(--my-margin);}"#); - } - - #[test] - fn generate_css_colors() { - let z = Zephyr::new(); - - let classes = z.generate_classes(["white blanchedalmond"]); - assert_eq!( - classes, - r#".white{color:white}.blanchedalmond{color:blanchedalmond}"# - ); + /// builds a `Zephyr` with the default ruleset + pub fn new() -> Self { + Self { + declarations: default_declarations(), + properties: default_properties(), + values: default_values(), + modifiers: default_modifiers(), + pseudos: default_pseudos(), + specials: default_specials(), + } } } diff --git a/src/parse.rs b/src/parse.rs index ac3f0e0..cfbb262 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -3,7 +3,7 @@ use crate::{ ZephyrError, }; -pub(crate) fn parse_class<'a>(original: &'a str) -> Result, ZephyrError> { +pub(crate) fn parse_class(original: &str) -> Result { // this code is kinda repetitive but idk let (class, pseudo) = if let Some((class, pseudo)) = original.split_once('$') { @@ -87,25 +87,23 @@ pub(crate) fn parse_class<'a>(original: &'a str) -> Result, ZephyrErro class[end + 1..].split(',').collect() }; - return Ok(Class { + Ok(Class { property: &class[0..start], value: Some(&class[start + 1..end]), modifiers: mods.into(), pseudo, original, value_type: ValueType::Normal, - }); - } - _ => { - return Ok(Class { - property: &class[0..], - value: None, - modifiers: vec![].into(), - pseudo, - original, - value_type: ValueType::Normal, - }); + }) } + _ => Ok(Class { + property: &class[0..], + value: None, + modifiers: vec![].into(), + pseudo, + original, + value_type: ValueType::Normal, + }), } } diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..ea324cf --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,144 @@ +use super::*; +use class::Class; + +#[test] +fn generate_margin_works() { + let z = Zephyr::new(); + + let class = Class { + property: "m", + value: Some("1rem"), + modifiers: vec![].into(), + pseudo: None, + original: "m[1rem]", + value_type: class::ValueType::Normal, + }; + let css = class.generate(&z).unwrap(); + assert_eq!(css, r#".m\[1rem\]{margin:1rem;}"#); + + let class = Class { + property: "m", + value: Some("1rem"), + modifiers: vec!["focus"].into(), + pseudo: None, + original: "m[1rem]focus", + value_type: class::ValueType::Normal, + }; + let css = class.generate(&z).unwrap(); + assert_eq!(css, r#".m\[1rem\]focus:focus{margin:1rem;}"#); + + let class = Class { + property: "m", + value: Some("1rem"), + modifiers: vec!["focus", "hover", "odd"].into(), + pseudo: None, + original: "m[1rem]focus,hover,odd", + value_type: class::ValueType::Normal, + }; + let css = class.generate(&z).unwrap(); + assert_eq!( + css, + r#".m\[1rem\]focus,hover,odd:focus:hover:nth-child\(odd\){margin:1rem;}"# + ); +} + +#[test] +fn generate_classes_works() { + let z = Zephyr::new(); + + let classes = z.generate_classes(["flex-row"]); + assert_eq!(classes, r#".flex-row{display:flex;flex-direction:row}"#); + + let classes = z.generate_classes(["m[3rem]hover,focus$placeholder"]); + assert_eq!( + classes, + r#".m\[3rem\]hover,focus\$placeholder:hover:focus::placeholder{margin:3rem;}"# + ); + + let classes = z.generate_classes(["flex|hover,focus$placeholder"]); + assert_eq!( + classes, + r#".flex\|hover,focus\$placeholder:hover:focus::placeholder{display:flex}"# + ); + + let classes = z.generate_classes(["mr[0.5rem]"]); + assert_eq!(classes, r#".mr\[0\.5rem\]{margin-right:0.5rem;}"#); +} + +#[test] +fn generate_multiple_works() { + let z = Zephyr::new(); + + let classes_joined = z.generate_classes(["flex-row mt[1rem]"]); + let classes_separate = z.generate_classes(["flex-row", "mt[1rem]"]); + assert_eq!( + classes_joined, + r#".flex-row{display:flex;flex-direction:row}.mt\[1rem\]{margin-top:1rem;}"# + ); + assert_eq!(classes_separate, classes_joined); +} + +#[test] +fn generate_specials_works() { + let z = Zephyr::new(); + + let classes = z.generate_classes(["mx[1rem]"]); + assert_eq!( + classes, + r#".mx\[1rem\]{margin-left:1rem;margin-right:1rem;}"# + ); +} + +#[test] +fn generate_with_spaces_works() { + let z = Zephyr::new(); + + let classes = z.generate_classes(["border[1px_solid_black]"]); + assert_eq!( + classes, + r#".border\[1px_solid_black\]{border:1px solid black;}"# + ); +} + +#[test] +fn generate_literals_works() { + let z = Zephyr::new(); + + // the curly brackets indicate that the value should not go through replacements + let classes = z.generate_classes(["border{1px_solid_black}", "w{full}"]); + assert_eq!( + classes, + r#".border\{1px_solid_black\}{border:1px_solid_black;}.w\{full\}{width:full;}"# + ); +} + +#[test] +fn generate_with_media_query() { + let z = Zephyr::new(); + + let classes = z.generate_classes(["m[1rem]sm"]); + assert_eq!( + classes, + r#"@media(min-width:640px){.m\[1rem\]sm{margin:1rem;}}"# + ); +} + +#[test] +fn generate_variable() { + let z = Zephyr::new(); + + // the parens indicate that it should be replaced by `var(--...)` + let classes = z.generate_classes(["m(my-margin)"]); + assert_eq!(classes, r#".m\(my-margin\){margin:var(--my-margin);}"#); +} + +#[test] +fn generate_css_colors() { + let z = Zephyr::new(); + + let classes = z.generate_classes(["white blanchedalmond"]); + assert_eq!( + classes, + r#".white{color:white}.blanchedalmond{color:blanchedalmond}"# + ); +}