use crate::parser::CssProperty;
pub fn parse(utility: &str) -> Option<Vec<CssProperty>> {
match utility {
"block" => return Some(vec![CssProperty::new("display", "block")]),
"inline-block" => return Some(vec![CssProperty::new("display", "inline-block")]),
"inline" => return Some(vec![CssProperty::new("display", "inline")]),
"flex" => return Some(vec![CssProperty::new("display", "flex")]),
"inline-flex" => return Some(vec![CssProperty::new("display", "inline-flex")]),
"grid" => return Some(vec![CssProperty::new("display", "grid")]),
"inline-grid" => return Some(vec![CssProperty::new("display", "inline-grid")]),
"contents" => return Some(vec![CssProperty::new("display", "contents")]),
"hidden" => return Some(vec![CssProperty::new("display", "none")]),
_ => {}
}
match utility {
"flex-row" => return Some(vec![CssProperty::new("flex-direction", "row")]),
"flex-row-reverse" => return Some(vec![CssProperty::new("flex-direction", "row-reverse")]),
"flex-col" => return Some(vec![CssProperty::new("flex-direction", "column")]),
"flex-col-reverse" => {
return Some(vec![CssProperty::new("flex-direction", "column-reverse")])
}
_ => {}
}
match utility {
"flex-wrap" => return Some(vec![CssProperty::new("flex-wrap", "wrap")]),
"flex-wrap-reverse" => return Some(vec![CssProperty::new("flex-wrap", "wrap-reverse")]),
"flex-nowrap" => return Some(vec![CssProperty::new("flex-wrap", "nowrap")]),
_ => {}
}
match utility {
"flex-1" => return Some(vec![CssProperty::new("flex", "1")]),
"flex-auto" => return Some(vec![CssProperty::new("flex", "1")]),
"flex-initial" => return Some(vec![CssProperty::new("flex", "0")]),
"flex-none" => {
return Some(vec![
CssProperty::new("flex", "0"),
CssProperty::new("flex-shrink", "0"),
])
}
"grow" => return Some(vec![CssProperty::new("flex-grow", "1")]),
"grow-0" => return Some(vec![CssProperty::new("flex-grow", "0")]),
"shrink" => return Some(vec![CssProperty::new("flex-shrink", "1")]),
"shrink-0" => return Some(vec![CssProperty::new("flex-shrink", "0")]),
_ => {}
}
if let Some(val) = utility.strip_prefix("justify-") {
let value = match val {
"normal" => "normal",
"start" => "start",
"end" => "end",
"center" => "center",
"between" => "space-between",
"around" => "space-around",
"evenly" => "space-evenly",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("justify-content", value)]);
}
if let Some(val) = utility.strip_prefix("items-") {
let value = match val {
"start" => "start",
"end" => "end",
"center" => "center",
"baseline" => "baseline",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("align-items", value)]);
}
if let Some(val) = utility.strip_prefix("self-") {
let value = match val {
"auto" => "auto",
"start" => "start",
"end" => "end",
"center" => "center",
"stretch" => "stretch",
"baseline" => "baseline",
_ => return None,
};
return Some(vec![CssProperty::new("align-self", value)]);
}
if let Some(val) = utility.strip_prefix("content-") {
let value = match val {
"normal" => "normal",
"start" => "start",
"end" => "end",
"center" => "center",
"between" => "space-between",
"around" => "space-around",
"evenly" => "space-evenly",
"baseline" => "baseline",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("align-content", value)]);
}
if let Some(val) = utility.strip_prefix("grid-cols-") {
let value = match val {
"1" => "repeat(1, minmax(0, 1fr))",
"2" => "repeat(2, minmax(0, 1fr))",
"3" => "repeat(3, minmax(0, 1fr))",
"4" => "repeat(4, minmax(0, 1fr))",
"5" => "repeat(5, minmax(0, 1fr))",
"6" => "repeat(6, minmax(0, 1fr))",
"7" => "repeat(7, minmax(0, 1fr))",
"8" => "repeat(8, minmax(0, 1fr))",
"9" => "repeat(9, minmax(0, 1fr))",
"10" => "repeat(10, minmax(0, 1fr))",
"11" => "repeat(11, minmax(0, 1fr))",
"12" => "repeat(12, minmax(0, 1fr))",
"none" => "none",
"subgrid" => "subgrid",
_ => return None,
};
return Some(vec![CssProperty::new("grid-template-columns", value)]);
}
if let Some(val) = utility.strip_prefix("grid-rows-") {
let value = match val {
"1" => "repeat(1, minmax(0, 1fr))",
"2" => "repeat(2, minmax(0, 1fr))",
"3" => "repeat(3, minmax(0, 1fr))",
"4" => "repeat(4, minmax(0, 1fr))",
"5" => "repeat(5, minmax(0, 1fr))",
"6" => "repeat(6, minmax(0, 1fr))",
"none" => "none",
"subgrid" => "subgrid",
_ => return None,
};
return Some(vec![CssProperty::new("grid-template-rows", value)]);
}
if let Some(val) = utility.strip_prefix("col-span-") {
let value = match val {
"1" => "span 1 / span 1",
"2" => "span 2 / span 2",
"3" => "span 3 / span 3",
"4" => "span 4 / span 4",
"5" => "span 5 / span 5",
"6" => "span 6 / span 6",
"7" => "span 7 / span 7",
"8" => "span 8 / span 8",
"9" => "span 9 / span 9",
"10" => "span 10 / span 10",
"11" => "span 11 / span 11",
"12" => "span 12 / span 12",
"full" => "1 / -1",
_ => return None,
};
return Some(vec![CssProperty::new("grid-column", value)]);
}
if let Some(val) = utility.strip_prefix("col-start-") {
let value = match val {
"1" => "1",
"2" => "2",
"3" => "3",
"4" => "4",
"5" => "5",
"6" => "6",
"7" => "7",
"8" => "8",
"9" => "9",
"10" => "10",
"11" => "11",
"12" => "12",
"13" => "13",
"auto" => "auto",
_ => return None,
};
return Some(vec![CssProperty::new("grid-column-start", value)]);
}
if let Some(val) = utility.strip_prefix("col-end-") {
let value = match val {
"1" => "1",
"2" => "2",
"3" => "3",
"4" => "4",
"5" => "5",
"6" => "6",
"7" => "7",
"8" => "8",
"9" => "9",
"10" => "10",
"11" => "11",
"12" => "12",
"13" => "13",
"auto" => "auto",
_ => return None,
};
return Some(vec![CssProperty::new("grid-column-end", value)]);
}
if let Some(val) = utility.strip_prefix("row-span-") {
let value = match val {
"1" => "span 1 / span 1",
"2" => "span 2 / span 2",
"3" => "span 3 / span 3",
"4" => "span 4 / span 4",
"5" => "span 5 / span 5",
"6" => "span 6 / span 6",
"full" => "1 / -1",
_ => return None,
};
return Some(vec![CssProperty::new("grid-row", value)]);
}
if let Some(val) = utility.strip_prefix("row-start-") {
let value = match val {
"1" => "1",
"2" => "2",
"3" => "3",
"4" => "4",
"5" => "5",
"6" => "6",
"7" => "7",
"auto" => "auto",
_ => return None,
};
return Some(vec![CssProperty::new("grid-row-start", value)]);
}
if let Some(val) = utility.strip_prefix("row-end-") {
let value = match val {
"1" => "1",
"2" => "2",
"3" => "3",
"4" => "4",
"5" => "5",
"6" => "6",
"7" => "7",
"auto" => "auto",
_ => return None,
};
return Some(vec![CssProperty::new("grid-row-end", value)]);
}
if let Some(val) = utility.strip_prefix("grid-flow-") {
let value = match val {
"row" => "row",
"col" => "column",
"dense" => "dense",
"row-dense" => "row dense",
"col-dense" => "column dense",
_ => return None,
};
return Some(vec![CssProperty::new("grid-auto-flow", value)]);
}
if let Some(val) = utility.strip_prefix("auto-cols-") {
let value = match val {
"auto" => "auto",
"min" => "min-content",
"max" => "max-content",
"fr" => "minmax(0, 1fr)",
_ => return None,
};
return Some(vec![CssProperty::new("grid-auto-columns", value)]);
}
if let Some(val) = utility.strip_prefix("auto-rows-") {
let value = match val {
"auto" => "auto",
"min" => "min-content",
"max" => "max-content",
"fr" => "minmax(0, 1fr)",
_ => return None,
};
return Some(vec![CssProperty::new("grid-auto-rows", value)]);
}
match utility {
"static" => return Some(vec![CssProperty::new("position", "static")]),
"fixed" => return Some(vec![CssProperty::new("position", "fixed")]),
"absolute" => return Some(vec![CssProperty::new("position", "absolute")]),
"relative" => return Some(vec![CssProperty::new("position", "relative")]),
"sticky" => return Some(vec![CssProperty::new("position", "sticky")]),
_ => {}
}
if let Some(val) = utility.strip_prefix("inset-") {
let value = inset_value(val)?;
return Some(vec![CssProperty::new("inset", value)]);
}
if let Some(val) = utility.strip_prefix("top-") {
let value = inset_value(val)?;
return Some(vec![CssProperty::new("top", value)]);
}
if let Some(val) = utility.strip_prefix("right-") {
let value = inset_value(val)?;
return Some(vec![CssProperty::new("right", value)]);
}
if let Some(val) = utility.strip_prefix("bottom-") {
let value = inset_value(val)?;
return Some(vec![CssProperty::new("bottom", value)]);
}
if let Some(val) = utility.strip_prefix("left-") {
let value = inset_value(val)?;
return Some(vec![CssProperty::new("left", value)]);
}
if let Some(val) = utility.strip_prefix("z-") {
let value = match val {
"0" => "0",
"10" => "10",
"20" => "20",
"30" => "30",
"40" => "40",
"50" => "50",
"auto" => "auto",
_ => return None,
};
return Some(vec![CssProperty::new("z-index", value)]);
}
if let Some(val) = utility.strip_prefix("overflow-") {
let value = match val {
"auto" => "auto",
"hidden" => "hidden",
"clip" => "clip",
"visible" => "visible",
"scroll" => "scroll",
"x-auto" => return Some(vec![CssProperty::new("overflow-x", "auto")]),
"y-auto" => return Some(vec![CssProperty::new("overflow-y", "auto")]),
"x-hidden" => return Some(vec![CssProperty::new("overflow-x", "hidden")]),
"y-hidden" => return Some(vec![CssProperty::new("overflow-y", "hidden")]),
"x-scroll" => return Some(vec![CssProperty::new("overflow-x", "scroll")]),
"y-scroll" => return Some(vec![CssProperty::new("overflow-y", "scroll")]),
"x-clip" => return Some(vec![CssProperty::new("overflow-x", "clip")]),
"y-clip" => return Some(vec![CssProperty::new("overflow-y", "clip")]),
"x-visible" => return Some(vec![CssProperty::new("overflow-x", "visible")]),
"y-visible" => return Some(vec![CssProperty::new("overflow-y", "visible")]),
_ => return None,
};
return Some(vec![CssProperty::new("overflow", value)]);
}
if let Some(val) = utility.strip_prefix("overscroll-") {
match val {
"auto" => return Some(vec![CssProperty::new("overscroll-behavior", "auto")]),
"contain" => return Some(vec![CssProperty::new("overscroll-behavior", "contain")]),
"none" => return Some(vec![CssProperty::new("overscroll-behavior", "none")]),
"y-auto" => return Some(vec![CssProperty::new("overscroll-behavior-y", "auto")]),
"y-contain" => return Some(vec![CssProperty::new("overscroll-behavior-y", "contain")]),
"y-none" => return Some(vec![CssProperty::new("overscroll-behavior-y", "none")]),
"x-auto" => return Some(vec![CssProperty::new("overscroll-behavior-x", "auto")]),
"x-contain" => return Some(vec![CssProperty::new("overscroll-behavior-x", "contain")]),
"x-none" => return Some(vec![CssProperty::new("overscroll-behavior-x", "none")]),
_ => return None,
};
}
if let Some(val) = utility.strip_prefix("columns-") {
let value = match val {
"1" => "1",
"2" => "2",
"3" => "3",
"4" => "4",
"5" => "5",
"6" => "6",
"7" => "7",
"8" => "8",
"9" => "9",
"10" => "10",
"11" => "11",
"12" => "12",
"auto" => "auto",
"3xs" => "16rem",
"2xs" => "18rem",
"xs" => "20rem",
"sm" => "24rem",
"md" => "28rem",
"lg" => "32rem",
"xl" => "36rem",
"2xl" => "42rem",
"3xl" => "48rem",
"4xl" => "56rem",
"5xl" => "64rem",
"6xl" => "72rem",
"7xl" => "80rem",
_ => return None,
};
return Some(vec![CssProperty::new("columns", value)]);
}
if let Some(val) = utility.strip_prefix("break-after-") {
let value = match val {
"auto" => "auto",
"avoid" => "avoid",
"all" => "all",
"avoid-page" => "avoid-page",
"page" => "page",
"left" => "left",
"right" => "right",
"column" => "column",
_ => return None,
};
return Some(vec![CssProperty::new("break-after", value)]);
}
if let Some(val) = utility.strip_prefix("break-before-") {
let value = match val {
"auto" => "auto",
"avoid" => "avoid",
"all" => "all",
"avoid-page" => "avoid-page",
"page" => "page",
"left" => "left",
"right" => "right",
"column" => "column",
_ => return None,
};
return Some(vec![CssProperty::new("break-before", value)]);
}
if let Some(val) = utility.strip_prefix("break-inside-") {
let value = match val {
"auto" => "auto",
"avoid" => "avoid",
"avoid-page" => "avoid-page",
"avoid-column" => "avoid-column",
_ => return None,
};
return Some(vec![CssProperty::new("break-inside", value)]);
}
match utility {
"box-decoration-clone" => {
return Some(vec![CssProperty::new("box-decoration-break", "clone")])
}
"box-decoration-slice" => {
return Some(vec![CssProperty::new("box-decoration-break", "slice")])
}
_ => {}
}
match utility {
"isolate" => return Some(vec![CssProperty::new("isolation", "isolate")]),
"isolation-auto" => return Some(vec![CssProperty::new("isolation", "auto")]),
_ => {}
}
if let Some(val) = utility.strip_prefix("basis-") {
let value = match val {
"0" => "0px",
"1" => "0.25rem",
"2" => "0.5rem",
"3" => "0.75rem",
"4" => "1rem",
"5" => "1.25rem",
"6" => "1.5rem",
"7" => "1.75rem",
"8" => "2rem",
"9" => "2.25rem",
"10" => "2.5rem",
"11" => "2.75rem",
"12" => "3rem",
"14" => "3.5rem",
"16" => "4rem",
"20" => "5rem",
"24" => "6rem",
"28" => "7rem",
"32" => "8rem",
"36" => "9rem",
"40" => "10rem",
"44" => "11rem",
"48" => "12rem",
"52" => "13rem",
"56" => "14rem",
"60" => "15rem",
"64" => "16rem",
"72" => "18rem",
"80" => "20rem",
"96" => "24rem",
"auto" => "auto",
"px" => "1px",
"0.5" => "0.125rem",
"1.5" => "0.375rem",
"2.5" => "0.625rem",
"3.5" => "0.875rem",
"1/2" => "50%",
"1/3" => "33.333333%",
"2/3" => "66.666667%",
"1/4" => "25%",
"2/4" => "50%",
"3/4" => "75%",
"1/5" => "20%",
"2/5" => "40%",
"3/5" => "60%",
"4/5" => "80%",
"1/6" => "16.666667%",
"5/6" => "83.333333%",
"1/12" => "8.333333%",
"full" => "100%",
_ => return None,
};
return Some(vec![CssProperty::new("flex-basis", value)]);
}
if let Some(val) = utility.strip_prefix("order-") {
let value = match val {
"1" => "1",
"2" => "2",
"3" => "3",
"4" => "4",
"5" => "5",
"6" => "6",
"7" => "7",
"8" => "8",
"9" => "9",
"10" => "10",
"11" => "11",
"12" => "12",
"first" => "-9999",
"last" => "9999",
"none" => "0",
_ => return None,
};
return Some(vec![CssProperty::new("order", value)]);
}
if let Some(val) = utility.strip_prefix("place-content-") {
let value = match val {
"center" => "center",
"start" => "start",
"end" => "end",
"between" => "space-between",
"around" => "space-around",
"evenly" => "space-evenly",
"baseline" => "baseline",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("place-content", value)]);
}
if let Some(val) = utility.strip_prefix("place-items-") {
let value = match val {
"start" => "start",
"end" => "end",
"center" => "center",
"baseline" => "baseline",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("place-items", value)]);
}
if let Some(val) = utility.strip_prefix("place-self-") {
let value = match val {
"auto" => "auto",
"start" => "start",
"end" => "end",
"center" => "center",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("place-self", value)]);
}
if let Some(val) = utility.strip_prefix("justify-items-") {
let value = match val {
"start" => "start",
"end" => "end",
"center" => "center",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("justify-items", value)]);
}
if let Some(val) = utility.strip_prefix("justify-self-") {
let value = match val {
"auto" => "auto",
"start" => "start",
"end" => "end",
"center" => "center",
"stretch" => "stretch",
_ => return None,
};
return Some(vec![CssProperty::new("justify-self", value)]);
}
None
}
fn inset_value(key: &str) -> Option<&'static str> {
match key {
"0" => Some("0px"),
"px" => Some("1px"),
"0.5" => Some("0.125rem"),
"1" => Some("0.25rem"),
"1.5" => Some("0.375rem"),
"2" => Some("0.5rem"),
"2.5" => Some("0.625rem"),
"3" => Some("0.75rem"),
"3.5" => Some("0.875rem"),
"4" => Some("1rem"),
"5" => Some("1.25rem"),
"6" => Some("1.5rem"),
"7" => Some("1.75rem"),
"8" => Some("2rem"),
"9" => Some("2.25rem"),
"10" => Some("2.5rem"),
"11" => Some("2.75rem"),
"12" => Some("3rem"),
"14" => Some("3.5rem"),
"16" => Some("4rem"),
"20" => Some("5rem"),
"24" => Some("6rem"),
"28" => Some("7rem"),
"32" => Some("8rem"),
"36" => Some("9rem"),
"40" => Some("10rem"),
"44" => Some("11rem"),
"48" => Some("12rem"),
"52" => Some("13rem"),
"56" => Some("14rem"),
"60" => Some("15rem"),
"64" => Some("16rem"),
"72" => Some("18rem"),
"80" => Some("20rem"),
"96" => Some("24rem"),
"auto" => Some("auto"),
"1/2" => Some("50%"),
"1/3" => Some("33.333333%"),
"2/3" => Some("66.666667%"),
"1/4" => Some("25%"),
"3/4" => Some("75%"),
"full" => Some("100%"),
_ => None,
}
}
pub fn parse_arbitrary(prefix: &str, value: &str) -> Option<Vec<CssProperty>> {
let property = match prefix {
"top" => "top",
"right" => "right",
"bottom" => "bottom",
"left" => "left",
"inset" => "inset",
_ => return None,
};
Some(vec![CssProperty::new(property, value)])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flex() {
let props = parse("flex").unwrap();
assert_eq!(props[0].property, "display");
assert_eq!(props[0].value, "flex");
}
#[test]
fn test_justify_center() {
let props = parse("justify-center").unwrap();
assert_eq!(props[0].property, "justify-content");
assert_eq!(props[0].value, "center");
}
#[test]
fn test_justify_between() {
let props = parse("justify-between").unwrap();
assert_eq!(props[0].property, "justify-content");
assert_eq!(props[0].value, "space-between");
}
#[test]
fn test_justify_start_uses_native_value() {
let props = parse("justify-start").unwrap();
assert_eq!(props[0].value, "start"); }
#[test]
fn test_items_center() {
let props = parse("items-center").unwrap();
assert_eq!(props[0].property, "align-items");
assert_eq!(props[0].value, "center");
}
#[test]
fn test_items_start_uses_native_value() {
let props = parse("items-start").unwrap();
assert_eq!(props[0].value, "start"); }
#[test]
fn test_flex_1_emits_native_flex() {
let props = parse("flex-1").unwrap();
assert_eq!(props.len(), 1);
assert_eq!(props[0].property, "flex");
assert_eq!(props[0].value, "1");
}
#[test]
fn test_grid_cols() {
let props = parse("grid-cols-3").unwrap();
assert_eq!(props[0].property, "grid-template-columns");
}
#[test]
fn test_position() {
let props = parse("absolute").unwrap();
assert_eq!(props[0].property, "position");
assert_eq!(props[0].value, "absolute");
}
#[test]
fn test_top() {
let props = parse("top-0").unwrap();
assert_eq!(props[0].property, "top");
assert_eq!(props[0].value, "0px");
}
}