finish rework
This commit is contained in:
parent
8613e712e7
commit
761af37ba7
34
src/class.rs
34
src/class.rs
|
@ -1,10 +1,10 @@
|
||||||
use crate::{modifiers::Modifiers, name::Name, Zephyr};
|
use crate::Zephyr;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub(crate) struct Class<'a> {
|
pub(crate) struct Class<'a> {
|
||||||
pub name: Name<'a>,
|
pub name: &'a str,
|
||||||
pub value: Option<&'a str>,
|
pub value: Option<&'a str>,
|
||||||
pub modifiers: Modifiers<'a>,
|
pub modifiers: Vec<&'a str>,
|
||||||
pub pseudo: Option<&'a str>,
|
pub pseudo: Option<&'a str>,
|
||||||
/// the original unparsed value
|
/// the original unparsed value
|
||||||
/// needed to generate the css selector
|
/// needed to generate the css selector
|
||||||
|
@ -12,7 +12,7 @@ pub(crate) struct Class<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Class<'a> {
|
impl<'a> Class<'a> {
|
||||||
pub(crate) fn selector(&self) -> String {
|
pub(crate) fn selector(&self, z: &Zephyr) -> String {
|
||||||
let Class {
|
let Class {
|
||||||
modifiers,
|
modifiers,
|
||||||
pseudo,
|
pseudo,
|
||||||
|
@ -20,16 +20,22 @@ impl<'a> Class<'a> {
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut rest = if let Some(mods) = modifiers.get() {
|
let mut rest = modifiers
|
||||||
format!(":{mods}")
|
.iter()
|
||||||
} else {
|
.map(|m| -> &str { z.modifiers.get(*m).map(AsRef::as_ref).unwrap_or(m) })
|
||||||
"".to_string()
|
.collect::<Vec<_>>()
|
||||||
};
|
.join(":");
|
||||||
|
|
||||||
if let Some(pseudo) = pseudo {
|
if let Some(pseudo) = pseudo {
|
||||||
rest.push_str("::");
|
rest.push_str("::");
|
||||||
rest.push_str(pseudo);
|
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}")
|
format!(".{original}{rest}")
|
||||||
.replace('[', "\\[")
|
.replace('[', "\\[")
|
||||||
.replace(']', "\\]")
|
.replace(']', "\\]")
|
||||||
|
@ -45,12 +51,16 @@ impl<'a> Class<'a> {
|
||||||
|
|
||||||
/// TODO return result
|
/// TODO return result
|
||||||
pub(crate) fn generate(&self, z: &Zephyr) -> String {
|
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 {
|
if let Some(val) = self.value {
|
||||||
let selector = self.selector();
|
|
||||||
format!("{selector} {{ {name}: {val}; }}",)
|
format!("{selector} {{ {name}: {val}; }}",)
|
||||||
} else if let Some(v) = z.rules.get(name) {
|
} else if let Some(v) = z.rules.get(name) {
|
||||||
let selector = self.selector();
|
|
||||||
format!("{selector} {{ {v} }}",)
|
format!("{selector} {{ {v} }}",)
|
||||||
} else {
|
} else {
|
||||||
panic!("{name} is not a no-variable rule, and no variables were provided");
|
panic!("{name} is not a no-variable rule, and no variables were provided");
|
||||||
|
|
|
@ -13,3 +13,38 @@ pub(crate) fn default_rules() -> HashMap<String, String> {
|
||||||
.map(|(a, b)| (a.to_string(), b.to_string()))
|
.map(|(a, b)| (a.to_string(), b.to_string()))
|
||||||
.collect()
|
.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()
|
||||||
|
}
|
||||||
|
|
23
src/lib.rs
23
src/lib.rs
|
@ -1,13 +1,14 @@
|
||||||
use std::collections::HashMap;
|
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 class;
|
||||||
mod defaults;
|
mod defaults;
|
||||||
mod modifiers;
|
|
||||||
mod name;
|
|
||||||
mod parse;
|
mod parse;
|
||||||
|
|
||||||
// pub fn generate_and_write(classes: &[&str], path: impl AsRef<Path>) -> Result<(), std::io::Error> {
|
// 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 struct Zephyr {
|
||||||
pub rules: HashMap<String, String>,
|
pub rules: HashMap<String, String>,
|
||||||
|
pub names: HashMap<String, String>,
|
||||||
|
pub modifiers: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Zephyr {
|
impl Zephyr {
|
||||||
|
@ -26,13 +29,17 @@ impl Zephyr {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rules: default_rules(),
|
rules: default_rules(),
|
||||||
|
names: default_names(),
|
||||||
|
modifiers: default_modifiers(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// builds a `Zephyr` without the default ruleset
|
/// builds a `Zephyr` without the default ruleset
|
||||||
pub fn new_without_rules() -> Self {
|
pub fn new_without_defaults() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rules: HashMap::new(),
|
rules: HashMap::new(),
|
||||||
|
names: HashMap::new(),
|
||||||
|
modifiers: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +66,7 @@ mod tests {
|
||||||
let z = Zephyr::new();
|
let z = Zephyr::new();
|
||||||
|
|
||||||
let class = Class {
|
let class = Class {
|
||||||
name: "m".into(),
|
name: "m",
|
||||||
value: Some("1rem"),
|
value: Some("1rem"),
|
||||||
modifiers: vec![].into(),
|
modifiers: vec![].into(),
|
||||||
pseudo: None,
|
pseudo: None,
|
||||||
|
@ -69,7 +76,7 @@ mod tests {
|
||||||
assert_eq!(css, r#".m\[1rem\] { margin: 1rem; }"#);
|
assert_eq!(css, r#".m\[1rem\] { margin: 1rem; }"#);
|
||||||
|
|
||||||
let class = Class {
|
let class = Class {
|
||||||
name: "m".into(),
|
name: "m",
|
||||||
value: Some("1rem"),
|
value: Some("1rem"),
|
||||||
modifiers: vec!["focus"].into(),
|
modifiers: vec!["focus"].into(),
|
||||||
pseudo: None,
|
pseudo: None,
|
||||||
|
@ -79,7 +86,7 @@ mod tests {
|
||||||
assert_eq!(css, r#".m\[1rem\]focus:focus { margin: 1rem; }"#);
|
assert_eq!(css, r#".m\[1rem\]focus:focus { margin: 1rem; }"#);
|
||||||
|
|
||||||
let class = Class {
|
let class = Class {
|
||||||
name: "m".into(),
|
name: "m",
|
||||||
value: Some("1rem"),
|
value: Some("1rem"),
|
||||||
modifiers: vec!["focus", "hover", "odd"].into(),
|
modifiers: vec!["focus", "hover", "odd"].into(),
|
||||||
pseudo: None,
|
pseudo: None,
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
49
src/name.rs
49
src/name.rs
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
10
src/parse.rs
10
src/parse.rs
|
@ -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>> {
|
pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
|
||||||
let (class, pseudo) = if let Some((class, pseudo)) = original.split_once('$') {
|
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 {
|
return Some(Class {
|
||||||
name: Name::new(&class[0..p]),
|
name: &class[0..p],
|
||||||
value: None,
|
value: None,
|
||||||
modifiers: mods.into(),
|
modifiers: mods.into(),
|
||||||
pseudo,
|
pseudo,
|
||||||
|
@ -32,7 +32,7 @@ pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some(Class {
|
return Some(Class {
|
||||||
name: Name::new(&class[0..start]),
|
name: &class[0..start],
|
||||||
value: Some(&class[start + 1..end]),
|
value: Some(&class[start + 1..end]),
|
||||||
modifiers: mods.into(),
|
modifiers: mods.into(),
|
||||||
pseudo,
|
pseudo,
|
||||||
|
@ -41,7 +41,7 @@ pub(crate) fn parse_class<'a>(original: &'a str) -> Option<Class<'a>> {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Some(Class {
|
return Some(Class {
|
||||||
name: Name::new(&class[0..]),
|
name: &class[0..],
|
||||||
value: None,
|
value: None,
|
||||||
modifiers: vec![].into(),
|
modifiers: vec![].into(),
|
||||||
pseudo,
|
pseudo,
|
||||||
|
@ -66,7 +66,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_class(class),
|
parse_class(class),
|
||||||
Some(Class {
|
Some(Class {
|
||||||
name: Name::new(name),
|
name,
|
||||||
value,
|
value,
|
||||||
modifiers: modifiers.into(),
|
modifiers: modifiers.into(),
|
||||||
pseudo,
|
pseudo,
|
||||||
|
|
Loading…
Reference in New Issue