finish rework

This commit is contained in:
annieversary 2022-07-02 14:30:40 +01:00
parent 8613e712e7
commit 761af37ba7
6 changed files with 77 additions and 139 deletions

View File

@ -1,10 +1,10 @@
use crate::{modifiers::Modifiers, name::Name, Zephyr};
use crate::Zephyr;
#[derive(PartialEq, Debug)]
pub(crate) struct Class<'a> {
pub name: Name<'a>,
pub name: &'a str,
pub value: Option<&'a str>,
pub modifiers: Modifiers<'a>,
pub modifiers: Vec<&'a str>,
pub pseudo: Option<&'a str>,
/// the original unparsed value
/// needed to generate the css selector
@ -12,7 +12,7 @@ pub(crate) struct Class<'a> {
}
impl<'a> Class<'a> {
pub(crate) fn selector(&self) -> String {
pub(crate) fn selector(&self, z: &Zephyr) -> String {
let Class {
modifiers,
pseudo,
@ -20,16 +20,22 @@ impl<'a> Class<'a> {
..
} = self;
let mut rest = if let Some(mods) = modifiers.get() {
format!(":{mods}")
} else {
"".to_string()
};
let mut rest = modifiers
.iter()
.map(|m| -> &str { z.modifiers.get(*m).map(AsRef::as_ref).unwrap_or(m) })
.collect::<Vec<_>>()
.join(":");
if let Some(pseudo) = pseudo {
rest.push_str("::");
rest.push_str(pseudo);
}
// TODO we can probably skip the format here, we just need to push the char at the start
if !rest.is_empty() {
rest = format!(":{rest}");
}
format!(".{original}{rest}")
.replace('[', "\\[")
.replace(']', "\\]")
@ -45,12 +51,16 @@ impl<'a> Class<'a> {
/// TODO return result
pub(crate) fn generate(&self, z: &Zephyr) -> String {
let name = self.name.as_str();
let name = z
.names
.get(self.name)
.map(AsRef::as_ref)
.unwrap_or(self.name);
let selector = self.selector(z);
if let Some(val) = self.value {
let selector = self.selector();
format!("{selector} {{ {name}: {val}; }}",)
} else if let Some(v) = z.rules.get(name) {
let selector = self.selector();
format!("{selector} {{ {v} }}",)
} else {
panic!("{name} is not a no-variable rule, and no variables were provided");

View File

@ -13,3 +13,38 @@ pub(crate) fn default_rules() -> HashMap<String, String> {
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
}
pub(crate) fn default_names() -> HashMap<String, String> {
vec![
("m", "margin"),
("mt", "margin-top"),
("mb", "margin-bottom"),
("ml", "margin-left"),
("mr", "margin-right"),
("p", "padding"),
("pt", "padding-top"),
("pb", "padding-bottom"),
("pl", "padding-left"),
("pr", "padding-right"),
("bg", "background"),
("bgc", "background-color"),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
}
pub(crate) fn default_modifiers() -> HashMap<String, String> {
vec![
("odd", "nth-child(odd)"),
("even", "nth-child(even)"),
("first", "first-child"),
("last", "last-child"),
("only", "only-child"),
// TODO
]
.into_iter()
.map(|(a, b)| (a.to_string(), b.to_string()))
.collect()
}

View File

@ -1,13 +1,14 @@
use std::collections::HashMap;
use defaults::default_rules;
use defaults::default_modifiers;
use crate::parse::*;
use crate::{
defaults::{default_names, default_rules},
parse::*,
};
mod class;
mod defaults;
mod modifiers;
mod name;
mod parse;
// pub fn generate_and_write(classes: &[&str], path: impl AsRef<Path>) -> Result<(), std::io::Error> {
@ -19,6 +20,8 @@ mod parse;
pub struct Zephyr {
pub rules: HashMap<String, String>,
pub names: HashMap<String, String>,
pub modifiers: HashMap<String, String>,
}
impl Zephyr {
@ -26,13 +29,17 @@ impl Zephyr {
pub fn new() -> Self {
Self {
rules: default_rules(),
names: default_names(),
modifiers: default_modifiers(),
}
}
/// builds a `Zephyr` without the default ruleset
pub fn new_without_rules() -> Self {
pub fn new_without_defaults() -> Self {
Self {
rules: HashMap::new(),
names: HashMap::new(),
modifiers: HashMap::new(),
}
}
@ -59,7 +66,7 @@ mod tests {
let z = Zephyr::new();
let class = Class {
name: "m".into(),
name: "m",
value: Some("1rem"),
modifiers: vec![].into(),
pseudo: None,
@ -69,7 +76,7 @@ mod tests {
assert_eq!(css, r#".m\[1rem\] { margin: 1rem; }"#);
let class = Class {
name: "m".into(),
name: "m",
value: Some("1rem"),
modifiers: vec!["focus"].into(),
pseudo: None,
@ -79,7 +86,7 @@ mod tests {
assert_eq!(css, r#".m\[1rem\]focus:focus { margin: 1rem; }"#);
let class = Class {
name: "m".into(),
name: "m",
value: Some("1rem"),
modifiers: vec!["focus", "hover", "odd"].into(),
pseudo: None,

View File

@ -1,65 +0,0 @@
use once_cell::sync::Lazy;
use std::collections::HashMap;
static REPLACEMENTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
[
("odd", "nth-child(odd)"),
("even", "nth-child(even)"),
("first", "first-child"),
("last", "last-child"),
("only", "only-child"),
]
.into()
});
#[derive(Default, PartialEq, Debug)]
pub(crate) struct Modifiers<'a>(Vec<Modifier<'a>>);
impl<'a> Modifiers<'a> {
pub(crate) fn get(&self) -> Option<String> {
if self.is_empty() {
None
} else {
Some(
self.0
.iter()
.map(Modifier::as_str)
.collect::<Vec<_>>()
.join(":"),
)
}
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<'a> From<Vec<&'a str>> for Modifiers<'a> {
fn from(v: Vec<&'a str>) -> Self {
Modifiers(v.into_iter().map(Modifier::new).collect())
}
}
#[derive(Debug, PartialEq)]
enum Modifier<'a> {
Converted { from: &'a str, to: &'static str },
Unknown(&'a str),
}
impl<'a> Modifier<'a> {
fn new(s: &'a str) -> Self {
if let Some(to) = REPLACEMENTS.get(s) {
Self::Converted { from: s, to }
} else {
Self::Unknown(s)
}
}
fn as_str(&self) -> &str {
match self {
Self::Converted { to, .. } => to,
Self::Unknown(v) => v,
}
}
}

View File

@ -1,49 +0,0 @@
use once_cell::sync::Lazy;
use std::collections::HashMap;
static REPLACEMENTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
[
("m", "margin"),
("mt", "margin-top"),
("mb", "margin-bottom"),
("ml", "margin-left"),
("mr", "margin-right"),
("p", "padding"),
("pt", "padding-top"),
("pb", "padding-bottom"),
("pl", "padding-left"),
("pr", "padding-right"),
("bg", "background"),
("bgc", "background-color"),
]
.into()
});
#[derive(Debug, PartialEq)]
pub(crate) enum Name<'a> {
Converted { from: &'a str, to: &'static str },
Unknown(&'a str),
}
impl<'a> Name<'a> {
pub(crate) fn new(s: &'a str) -> Self {
if let Some(to) = REPLACEMENTS.get(s) {
Self::Converted { from: s, to }
} else {
Self::Unknown(s)
}
}
pub(crate) fn as_str(&self) -> &str {
match self {
Self::Converted { to, .. } => to,
Self::Unknown(v) => v,
}
}
}
impl<'a> From<&'a str> for Name<'a> {
fn from(s: &'a str) -> Self {
Name::new(s)
}
}

View File

@ -1,4 +1,4 @@
use crate::{class::Class, name::Name};
use crate::class::Class;
pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
let (class, pseudo) = if let Some((class, pseudo)) = original.split_once('$') {
@ -15,7 +15,7 @@ pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
};
return Some(Class {
name: Name::new(&class[0..p]),
name: &class[0..p],
value: None,
modifiers: mods.into(),
pseudo,
@ -32,7 +32,7 @@ pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
};
return Some(Class {
name: Name::new(&class[0..start]),
name: &class[0..start],
value: Some(&class[start + 1..end]),
modifiers: mods.into(),
pseudo,
@ -41,7 +41,7 @@ pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
}
_ => {
return Some(Class {
name: Name::new(&class[0..]),
name: &class[0..],
value: None,
modifiers: vec![].into(),
pseudo,
@ -66,7 +66,7 @@ mod tests {
assert_eq!(
parse_class(class),
Some(Class {
name: Name::new(name),
name,
value,
modifiers: modifiers.into(),
pseudo,