use super::validators;
pub type Result<T> = std::result::Result<T, &'static str>;
pub fn get_collision_id(classes: &[&str], arbitrary: &str) -> Result<&'static str> {
match classes {
["aspect", "auto" | "square" | "video"] => Ok("aspect"),
["aspect", n] if parse_fraction(n).is_some() => Ok("aspect"),
["aspect"] if parse_fraction(arbitrary).is_some() => Ok("aspect"),
["container"] => Ok("container"),
["columns", "auto"] => Ok("columns"),
["columns", rest] if is_t_shirt_size(rest) || rest.parse::<usize>().is_ok() => {
Ok("columns")
}
["columns"] if is_arbitrary_len(arbitrary) => {
Ok("columns")
}
["break", "after", rest] if valid_break_after(rest) => Ok("break-after"),
["break", "before", rest] if valid_break_after(rest) => {
Ok("break-before")
}
["break", "inside", rest] => {
if valid_break_after(rest) {
Ok("break-inside")
} else {
Err("Invalid break-inside")
}
}
["box", "decoration", "clone" | "slice"] => {
Ok("box-decoration-break")
}
["box", "border" | "content"] => Ok("box-sizing"),
["block"]
| ["inline", "block"]
| ["inline"]
| ["flex"]
| ["inline","flex"]
| ["table"]
| ["inline","table"]
| ["table","caption"]
| ["table","cell"]
| ["table","column"]
| ["table","column","group"]
| ["table","footer","group"]
| ["table","header","group"]
| ["table","row","group"]
| ["table","row"]
| ["flow","root"]
| ["grid"]
| ["inline","grid"]
| ["contents"]
| ["hidden"]
if arbitrary.is_empty() =>
{
Ok("display")
}
["float", "start" | "end" | "right" | "none"] => {
Ok("float")
}
["clear", "start" | "end" | "right" | "both" | "none"] => Ok("clear"),
["isolation"] | ["isolation", "auto"] => Ok("isolation"),
["object", "contain"]
| ["object", "cover"]
| ["object", "fill"]
| ["object", "none"]
| ["object", "scale", "down"] => Ok("object-fit"),
["object", "bottom"]
| ["object", "center"]
| ["object", "left"]
| ["object", "left", "bottom"]
| ["object", "left", "top"]
| ["object", "right"]
| ["object", "right", "bottom"]
| ["object", "right", "top"]
| ["object", "top"] => Ok("object-position"),
["overflow", "auto"]
| ["overflow", "hidden"]
| ["overflow", "clip"]
| ["overflow", "visible"]
| ["overflow", "scroll"]
| ["overflow", "x", "auto"]
| ["overflow", "y", "auto"]
| ["overflow","x", "hidden"]
| ["overflow","y", "hidden"]
| ["overflow", "x", "clip"]
| ["overflow", "y","clip"]
| ["overflow","x", "visible"]
| ["overflow", "y", "visible"]
| ["overflow","x", "scroll"]
| ["overflow","y", "scroll"] => Ok("overflow"),
["overscroll", "auto"]
| ["overscroll", "contain"]
| ["overscroll", "none"]
| ["overscroll", "y", "auto"]
| ["overscroll", "y", "contain"]
| ["overscroll", "y", "none"]
| ["overscroll", "x", "auto"]
| ["overscroll", "x", "contain"]
| ["overscroll", "x", "none"] => Ok("overscroll-behavior"),
["static"] | ["fixed"] | ["absolute"] | ["relative"] | ["sticky"] => Ok("position"),
["inset", "x", rest @ ..] => valid_trbl(rest, arbitrary, "inset-x", "Invalid inset-x"),
["inset", "y", rest @ ..] => valid_trbl(rest, arbitrary, "inset-y", "Invalid inset-y"),
["inset", rest @ ..] => valid_trbl(rest, arbitrary, "inset", "Invalid inset"),
["top", rest @ ..] => valid_trbl(rest, arbitrary, "top", "Invalid top"),
["right", rest @ ..] => valid_trbl(rest, arbitrary, "right", "Invalid right"),
["bottom", rest @ ..] => valid_trbl(rest, arbitrary, "bottom", "Invalid bottom"),
["left", rest @ ..] => valid_trbl(rest, arbitrary, "left", "Invalid left"),
["start", rest @ ..] => valid_trbl(rest, arbitrary, "start", "Invalid start"),
["end", rest @ ..] => valid_trbl(rest, arbitrary, "end", "Invalid end"),
["visible" | "invisible" | "collapse"] => Ok("visibility"),
["z", "auto"] => Ok("z-index"),
["z", index] => match index.parse::<usize>().ok() {
Some(_) => Ok("z-index"),
None => Err("Invalid z index"),
},
["z"] => match arbitrary.parse::<usize>().ok() {
Some(_) => Ok("z-index"),
None => Err("Invalid z index"),
},
["basis", "full" | "auto" | "px" ] => Ok("flex-basis"),
["basis", rest] => {
if parse_fraction_or_usize(rest) {
Ok("flex-basis")
} else {
Err("Invalid flex-basis")
}
}
["basis"] => {
if parse_fraction_or_usize(arbitrary) {
Ok("flex-basis")
} else {
Err("Invalid flex-basis")
}
}
["flex", "row"]
| ["flex", "row", "reverse"]
| ["flex", "col"]
| ["flex", "col", "reverse"] => Ok("flex-direction"),
["flex", "wrap"] | ["flex", "wrap", "reverse"] | ["flex", "nowrap"] => Ok("flex-wrap"),
["flex", "1"] | ["flex", "auto"] | ["flex", "initial"] | ["flex", "none"] => Ok("flex"),
["flex", _] => Ok("flex"),
["flex"] if !arbitrary.is_empty() => Ok("flex"),
["grow", ..] => Ok("flex-grow"),
["shrink", ..] => Ok("flex-shrink"),
["order", "first" | "last" | "none"] => Ok("order"),
["order", rest] if rest.parse::<isize>().is_ok() => Ok("order"),
["order"] if arbitrary.parse::<isize>().is_ok() => Ok("order"),
["grid", "cols", ..] => Ok("grid-template-columns"),
["col", "auto"] | ["col", "span", ..] => Ok("col-start-end"),
["col", "start", ..] => Ok("col-start"),
["col", "end", ..] => Ok("col-end"),
["grid", "rows", ..] => Ok("grid-template-rows"),
["row", "auto"] | ["row", "span", ..] => Ok("row-start-end"),
["row", "start", ..] => Ok("row-start"),
["row", "end", ..] => Ok("row-end"),
["grid", "flow", "row"]
| ["grid", "flow", "col"]
| ["grid", "flow", "dense"]
| ["grid", "flow", "row", "dense"]
| ["grid", "flow", "col", "dense"] => Ok("grid-auto-flow"),
["auto", "cols", ..] => Ok("auto-cols"),
["auto", "rows", ..] => Ok("auto-rows"),
["gap", "x", ..] => Ok("gap-x"),
["gap", "y", ..] => Ok("gap-y"),
["gap", ..] => Ok("gap"),
["justify", "normal" | "start" | "end" | "center" | "between" | "around" | "evenly" | "stretch"] => Ok("justify-content"),
["justify", "items", "start" | "end" | "center" | "stretch"] => Ok("justify-items"),
["justify", "self", "start" | "end" | "center" | "stretch"] => Ok("justify-self"),
["content", "normal" | "center" | "start" | "end" | "between" | "around" | "evenly" | "baseline" | "stretch"] => Ok("align-content"),
["items", "start" | "end" | "center" | "baseline" | "stretch"] => Ok("align-items"),
["self", "auto" | "start" | "end" | "center" | "stretch" | "baseline"] => Ok("align-self"),
["place", "content", "center" | "start" | "end" | "between" | "around" | "evenly" | "baseline" | "stretch"] => Ok("place-content"),
["place", "items", "start" | "end" | "center" | "baseline" | "stretch"] => Ok("place-items"),
["place", "self", "start" | "end" | "center" | "baseline" | "stretch"] => Ok("place-self"),
["p", ..] => Ok("padding"),
["pl", ..] => Ok("padding-left"),
["pr", ..] => Ok("padding-right"),
["pt", ..] => Ok("padding-top"),
["pb", ..] => Ok("padding-bottom"),
["px", ..] => Ok("padding-x"),
["py", ..] => Ok("padding-y"),
["m", ..] => Ok("margin"),
["ml", ..] => Ok("margin-left"),
["mr", ..] => Ok("margin-right"),
["mt", ..] => Ok("margin-top"),
["mb", ..] => Ok("margin-bottom"),
["mx", ..] => Ok("margin-x"),
["my", ..] => Ok("margin-y"),
["ms", ..] => Ok("margin-start"),
["me", ..] => Ok("margin-end"),
["space", "x", "reverse"] => Ok("space-x-reverse"),
["space", "y", "reverse"] => Ok("space-y-reverse"),
["space", "x", ..] => Ok("space-x"),
["space", "y", ..] => Ok("space-y"),
["w", ..] => Ok("width"),
["min", "w", ..] => Ok("min-width"),
["max", "w", ..] => Ok("max-width"),
["h", ..] => Ok("height"),
["min", "h", ..] => Ok("min-height"),
["max", "h", ..] => Ok("max-height"),
["size", ..] => Ok("size"),
["font", "sans"] | ["font", "serif"] | ["font", "mono"] => Ok("font-family"),
["text", "left" | "center" | "right" | "justify" | "start" | "end"] => Ok("text-align"),
["text", "ellipsis" | "clip"] => Ok("text-overflow"),
["text", "wrap" | "nowrap" | "balance" | "pretty"] => Ok("text-wrap"),
["text", rest] if valid_text_size(rest) => Ok("font-size"),
["text"] if is_arbitrary_len(arbitrary) => Ok("font-size"),
["text", ..] => Ok("text-color"),
["antialiased"] | ["subpixel", "antialiased"] => Ok("font-smoothing"),
["italic"] | ["not","italic"] => Ok("font-style"),
["font", ..] => Ok("font-weight"),
["normal", "nums"] => Ok("fvn-normal"),
["ordinal"] => Ok("fvn-ordinal"),
["slashed", "zero"] => Ok("fvn-slashed-zero"),
["lining", "nums"] | ["oldstyle", "nums"] => Ok("fvn-figure"),
["proportional", "nums"] | ["tabular","nums"] => Ok("fvn-spacing"),
["diagonal", "fractions"] | ["stacked","fractions"] => Ok("fvn-fraction"),
["tracking", ..] => Ok("letter-spacing"),
["line", "clamp", ..] => Ok("line-clamp"),
["leading", ..] => Ok("line-height"),
["list", "image", ..] => Ok("list-style-image"),
["list", "inside"] | ["list", "outside"] => Ok("list-style-position"),
["list", ..] => Ok("list-style-type"),
["underline"] | ["overline"] | ["line", "through"] | ["no", "underline"] => Ok("text-decoration"),
["decoration", "solid" | "double" | "dotted" | "dashed" | "wavy"] => Ok("text-decoration-style"),
["decoration", "auto"] | ["decoration", "from-font"] => Ok("text-decoration-thickness"),
["decoration", rest] => {
if rest.parse::<usize>().is_ok() {
Ok("text-decoration-thickness")
} else {
Err("Invalid text-decoration-thickness")
}
}
["decoration"] if arbitrary.parse::<usize>().is_ok() => Ok("text-decoration-thickness"),
["decoration", ..] => Ok("text-decoration-color"),
["underline", "offset", ..] => Ok("text-underline-offset"),
["uppercase" | "lowercase" | "capitalize" | "normal-case"] => Ok("text-transform"),
["truncate"] => Ok("text-overflow"),
["indent", ..] => Ok("text-indent"),
["align", ..] => Ok("vertical-align"),
["whitespace", "normal"]
| ["whitespace", "nowrap"]
| ["whitespace", "pre"]
| ["whitespace", "pre", "line"]
| ["whitespace", "pre", "wrap"]
| ["whitespace", "break", "spaces"] => Ok("whitespace"),
["break", "normal" | "words" | "all" | "keep"] => {
Ok("word-break")
}
["hyphens", "none" | "manual" | "auto"] => Ok("hyphens"),
["content", "none"] => Ok("content"),
["content"] if is_arbitrary_value(arbitrary) => Ok("content"),
["bg", "fixed" | "local" | "scroll"] => Ok("background-attachment"),
["bg", "clip", "border" | "padding" | "content" | "text"] => Ok("background-clip"),
["bg", "origin", "border" | "padding" | "content"] => {
Ok("background-origin")
}
["bg", "repeat"]
| ["bg", "no","repeat"]
| ["bg", "repeat", "x" | "y" | "round" | "space"] => Ok("background-repeat"),
["bg", "bottom"]
| ["bg", "center"]
| ["bg", "left"]
| ["bg", "left", "bottom"]
| ["bg", "left", "top"]
| ["bg", "right"]
| ["bg", "right", "bottom"]
| ["bg", "right", "top"]
| ["bg", "top"] => Ok("background-position"),
["bg", "auto" | "cover" | "contain"] => Ok("background-size"),
["bg"] if is_arbitrary_size(arbitrary) => Ok("background-size"),
["bg", "none"] | ["bg", "gradient", "to", ..] => Ok("background-image"),
["bg"] if is_arbitrary_bg_image(arbitrary) => Ok("background-image"),
["bg", "blend", mode @ ..] if valid_blend(mode) => Ok("background-blend-mode"),
["bg", ..] => Ok("background-color"),
["from", ..] => Ok("from"),
["via", ..] => Ok("via"),
["to", ..] => Ok("to"),
["rounded", "t", ..] => Ok("rounded-t"),
["rounded", "r", ..] => Ok("rounded-r"),
["rounded", "b", ..] => Ok("rounded-b"),
["rounded", "l", ..] => Ok("rounded-l"),
["rounded", "tl", ..] => Ok("rounded-tl"),
["rounded", "tr", ..] => Ok("rounded-tr"),
["rounded", "bl", ..] => Ok("rounded-bl"),
["rounded", "br", ..] => Ok("rounded-br"),
["rounded", "s", ..] => Ok("rounded-s"),
["rounded", "e", ..] => Ok("rounded-e"),
["rounded", "ss", ..] => Ok("rounded-ss"),
["rounded", "se", ..] => Ok("rounded-se"),
["rounded", "ee", ..] => Ok("rounded-ee"),
["rounded", "es", ..] => Ok("rounded-es"),
["rounded", ..] => Ok("rounded"),
["border", "x", rest] if is_valid_length(rest) => Ok("border-w-x"),
["border", "x"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-x"),
["border", "y", rest] if is_valid_length(rest) => Ok("border-w-y"),
["border", "y"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-y"),
["border", "t", rest] if is_valid_length(rest) => Ok("border-w-t"),
["border", "t"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-t"),
["border", "r", rest] if arbitrary.is_empty() ||is_valid_length(rest) => Ok("border-w-r"),
["border", "r"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-r"),
["border", "b", rest] if arbitrary.is_empty() ||is_valid_length(rest) => Ok("border-w-b"),
["border", "b"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-b"),
["border", "l", rest] if is_valid_length(rest) => Ok("border-w-l"),
["border", "l"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-l"),
["border", "s", rest] if is_valid_length(rest) => Ok("border-w-s"),
["border", "s"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w-s"),
["border", rest] if is_valid_length(rest) => Ok("border-w"),
["border"] if arbitrary.is_empty() || is_arbitrary_len(arbitrary) => Ok("border-w"),
["border", "solid" | "dashed" | "dotted" | "double" | "hidden" | "none"] => {
Ok("border-style")
}
["border", "collapse" | "separate"] => Ok("border-collapse"),
["border", "spacing", "x", ..] => Ok("border-spacing-x"),
["border", "spacing", "y", ..] => Ok("border-spacing-y"),
["border", "spacing", ..] => Ok("border-spacing"),
["border", "t", ..] => Ok("border-color-t"),
["border", "r", ..] => Ok("border-color-r"),
["border", "b", ..] => Ok("border-color-b"),
["border", "l", ..] => Ok("border-color-l"),
["border", "s", ..] => Ok("border-color-s"),
["border", "e", ..] => Ok("border-color-e"),
["border", "x", ..] => Ok("border-color-x"),
["border", "y", ..] => Ok("border-color-y"),
["border", ..] => Ok("border-color"),
["divide", "solid" | "dashed" | "dotted" | "double" | "none"] => Ok("divide-style"),
["divide", "x", "reverse"] => Ok("divide-x-reverse"),
["divide", "y", "reverse"] => Ok("divide-y-reverse"),
["divide", "x", ..] => Ok("divide-x"),
["divide", "y", ..] => Ok("divide-y"),
["divide", ..] => Ok("divide-color"),
| ["outline"]
| ["outline", "none" | "solid" | "dashed" | "dotted" | "double"]
if arbitrary.is_empty() =>
{
Ok("outline-style")
}
["outline"] if arbitrary.parse::<usize>().is_ok() => Ok("outline-width"),
["outline", rest] if rest.parse::<usize>().is_ok() => Ok("outline-width"),
["outline", "offset", ..] => Ok("outline-offset"),
["outline", ..] => Ok("outline-color"),
["ring", "inset"] => Ok("ring-width"),
["ring", rest] if rest.parse::<usize>().is_ok() => Ok("ring-width"),
["ring"] if arbitrary.parse::<usize>().is_ok() => Ok("ring-width"),
["ring", "offset", rest] if rest.parse::<usize>().is_ok() => Ok("ring-offset-width"),
["ring", "offset"] if arbitrary.parse::<usize>().is_ok() => Ok("ring-offset-width"),
["ring", "offset", ..] => Ok("ring-offset-color"),
["ring", ..] => Ok("ring-color"),
["shadow"] | ["shadow", "inner" | "none"] if arbitrary.is_empty() => Ok("box-shadow"),
["shadow", size] if is_t_shirt_size(size) => Ok("box-shadow"),
["shadow", ..] => Ok("box-shadow-color"),
["opacity", ..] => Ok("opacity"),
["mix", "blend", mode @ ..] if valid_blend(mode)=> Ok("mix-blend-mode"),
["blur", ..] => Ok("blur"),
["brightness", ..] => Ok("brightness"),
["contrast", ..] => Ok("contrast"),
["drop", "shadow", ..] => Ok("drop-shadow"),
["grayscale", ..] => Ok("grayscale"),
["hue", "rotate", ..] => Ok("hue-rotate"),
["invert", ..] => Ok("invert"),
["saturate", ..] => Ok("saturate"),
["sepia", ..] => Ok("sepia"),
["backdrop", "blur", ..] => Ok("backdrop-blur"),
["backdrop", "brightness", ..] => Ok("backdrop-brightness"),
["backdrop", "contrast", ..] => Ok("backdrop-contrast"),
["backdrop", "grayscale", ..] => Ok("backdrop-grayscale"),
["backdrop", "hue", "rotate", ..] => Ok("backdrop-hue-rotate"),
["backdrop", "invert", ..] => Ok("backdrop-invert"),
["backdrop", "opacity", ..] => Ok("backdrop-opacity"),
["backdrop", "saturate", ..] => Ok("backdrop-saturate"),
["backdrop", "sepia", ..] => Ok("backdrop-sepia"),
["table", "auto" | "fixed"] => Ok("table-layout"),
["caption", "top" | "bottom"] => Ok("caption-side"),
["transition", ..] => Ok("transition-property"),
["duration", rest] if rest.parse::<usize>().is_ok() => Ok("transition-duration"),
["duration"] if arbitrary.parse::<usize>().is_ok() => Ok("transition-duration"),
["ease", ..] => Ok("transition-timing-function"),
["delay", rest] if rest.parse::<usize>().is_ok() => Ok("transition-delay"),
["delay"] if arbitrary.parse::<usize>().is_ok() => Ok("transition-delay"),
["animate", ..] => Ok("animate"),
["scale", "x", rest] if rest.parse::<usize>().is_ok() => Ok("scale-x"),
["scale", "x"] if arbitrary.parse::<usize>().is_ok() => Ok("scale-x"),
["scale", "y", rest] if rest.parse::<usize>().is_ok() => Ok("scale-y"),
["scale", "y"] if arbitrary.parse::<usize>().is_ok() => Ok("scale-y"),
["scale", rest] if rest.parse::<usize>().is_ok() => Ok("scale"),
["scale"] if arbitrary.parse::<f32>().is_ok() => Ok("scale"),
["rotate", rest] if rest.parse::<usize>().is_ok() => Ok("rotate"),
["rotate"] if arbitrary.parse::<usize>().is_ok() => Ok("rotate"),
["translate", "x", ..] => Ok("translate-x"),
["translate", "y", ..] => Ok("translate-y"),
["skew", "x", ..] => Ok("skew-x"),
["skew", "y", ..] => Ok("skew-y"),
["origin", ..] => Ok("transform-origin"),
["accent", ..] => Ok("accent-color"),
["appearance", "none" | "auto"] => Ok("appearance"),
["cursor", ..] => Ok("cursor"),
["caret", ..] => Ok("caret-color"),
["pointer", "events", "none" | "auto"] => Ok("pointer-events"),
["resize"] | ["resize", "none" | "y" |"x"] => Ok("resize"),
["scroll", "auto" | "smooth"] => Ok("scroll-behavior"),
["scroll", rest, ..] if rest.starts_with('m') => Ok("scroll-margin"),
["scroll", rest, ..] if rest.starts_with('p') => Ok("scroll-padding"),
["snap", "none" | "start" | "end" | "center" | "align", "none"] => Ok("scroll-snap-align"),
["snap", "normal"] | ["snap", "always"] => Ok("scroll-snap-stop"),
["snap", "none" | "x" | "y" | "both" | "mandatory" | "proximity"] => {
Ok("scroll-snap-type")
}
["touch", "auto" | "none" | "manipulation"] => Ok("touch"),
["touch", "pan", "x" | "left" | "right"] => Ok("touch-x"),
["touch", "pan", "y"| "up"| "down"] => Ok("touch-y"),
["touch", "pinch", "zoom"] => Ok("touch-pz"),
["select" , "none" | "text" | "all" | "auto"] => Ok("user-select"),
["will", "change", ..] => Ok("will-change"),
["fill", ..] => Ok("fill"),
["stroke", rest] if rest.parse::<usize>().is_ok() => Ok("stroke-width"),
["stroke"] if is_valid_length(arbitrary) => Ok("stroke-width"),
["stroke", ..]=> {
Ok("stroke")
},
["sr", "only"] | ["not", "sr", "only"] => Ok("screen-readers"),
["forced", "color", "adjust", "auto" | "none"] => Ok("forced-color-adjust"),
_ => Err("Invalid Tailwind class"),
}
}
fn valid_blend(mode: &[&str]) -> bool {
matches!(
mode,
["normal"]
| ["multiply"]
| ["screen"]
| ["overlay"]
| ["darken"]
| ["lighten"]
| ["color", "dodge"]
| ["color", "burn"]
| ["hard", "light"]
| ["soft", "light"]
| ["difference"]
| ["exclusion"]
| ["hue"]
| ["saturation"]
| ["color"]
| ["luminosity"]
| ["lighter"]
)
}
fn valid_trbl(
mode: &[&str],
arbitrary: &str,
success: &'static str,
error: &'static str,
) -> Result<&'static str> {
if mode.len() == 1 && valid_top_right_bottom_left(mode[0]) {
return Ok(success);
}
if is_valid_length(arbitrary) {
return Ok(success);
}
Err(error)
}
fn valid_top_right_bottom_left(mode: &str) -> bool {
mode == "auto"
|| mode == "full"
|| mode == "px"
|| validators::parse_single_digit_decimal(mode)
|| parse_fraction(mode).is_some()
}
fn valid_break_after(mode: &str) -> bool {
matches!(
mode,
"auto" | "avoid" | "all" | "avoid-page" | "page" | "left" | "right" | "column"
)
}
fn valid_text_size(mode: &str) -> bool {
mode == "base"
|| mode.starts_with("xs")
|| mode.ends_with("xs")
|| mode.starts_with("sm")
|| mode.ends_with("sm")
|| mode.starts_with("md")
|| mode.ends_with("md")
|| mode.starts_with("lg")
|| mode.ends_with("lg")
|| mode.starts_with("xl")
|| mode.ends_with("xl")
}
fn parse_fraction_or_usize(input: &str) -> bool {
parse_fraction(input)
.map(|_| ())
.or_else(|| input.parse::<usize>().ok().map(|_| ()))
.is_some()
}
fn parse_fraction(input: &str) -> Option<(usize, usize)> {
let (a, b) = input.split_once('/')?;
let a = a.parse::<usize>().ok()?;
let b = b.parse::<usize>().ok()?;
Some((a, b))
}
fn is_t_shirt_size(input: &str) -> bool {
input.ends_with("xs")
|| input.ends_with("sm")
|| input.ends_with("md")
|| input.ends_with("lg")
|| input.ends_with("xl")
}
fn is_valid_length(input: &str) -> bool {
validators::length::parse(input).is_ok() && !is_valid_color(input)
}
fn is_valid_color(input: &str) -> bool {
validators::color::parse(input).is_ok()
}
fn is_arbitrary_value(input: &str) -> bool {
validators::arbitrary::parse(input).is_ok()
}
fn is_arbitrary_len(input: &str) -> bool {
is_valid_arbitrary_value(input, |label| label == "length", is_valid_length)
}
fn is_arbitrary_bg_image(input: &str) -> bool {
is_valid_arbitrary_value(
input,
|label| label == "image" || label == "url",
|string| validators::image::parse(string).is_ok(),
)
}
fn is_arbitrary_size(input: &str) -> bool {
is_valid_arbitrary_value(
input,
|label| label == "length" || label == "size" || label == "percentage",
|_| false,
)
}
fn is_valid_arbitrary_value(
input: &str,
label: impl Fn(&str) -> bool,
func: impl Fn(&str) -> bool,
) -> bool {
match validators::arbitrary::parse(input).ok() {
Some((_, (Some(captured_label), _))) => label(captured_label),
Some((_, (None, rest))) => func(rest),
None => false,
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_len() {
assert!(is_valid_length("10px"));
assert!(is_valid_length("10%"));
assert!(is_valid_length("100rem"));
assert!(!is_valid_length("hsl(350_80%_0%)"), "no color");
assert!(!is_valid_length("--my-0"), "double negative");
}
#[test]
fn parse_stroke() {
let result = get_collision_id(&["stroke"], "10px");
assert_eq!(result, Ok("stroke-width"));
let result = get_collision_id(&["stroke"], "hsl(350_80%_0%)");
assert_eq!(result, Ok("stroke"));
}
#[test]
fn parse_margin() {
let result = get_collision_id(&["my", "2"], "");
assert_eq!(result, Ok("margin-y"));
let result = get_collision_id(&["m", "2"], "");
assert_eq!(result, Ok("margin"));
let result = get_collision_id(&["m"], "2px");
assert_eq!(result, Ok("margin"));
let result = get_collision_id(&["my"], "10rem");
assert_eq!(result, Ok("margin-y"));
}
#[test]
fn parse_inset() {
let result = get_collision_id(&["inset", "auto"], "");
assert_eq!(result, Ok("inset"));
let result = get_collision_id(&["inset", "0"], "");
assert_eq!(result, Ok("inset"));
let result = get_collision_id(&["inset"], "10px");
assert_eq!(result, Ok("inset"));
}
#[test]
fn parse_len() {
assert!(is_valid_length("calc(theme(fontSize.4xl)/1.125)"));
let result = get_collision_id(&["text"], "length:theme(someScale.someValue)");
assert_eq!(result, Ok("font-size"));
assert!(is_valid_length("calc(theme(fontSize.4xl)/1.125)"));
let result = get_collision_id(&["text"], "calc(theme(fontSize.4xl)/1.125)");
assert_eq!(result, Ok("font-size"));
}
#[test]
fn parse_text_color() {
assert!(!is_arbitrary_len("color:0"), "shouldn't be a length");
let result = get_collision_id(&["text"], "color:0");
assert_eq!(result, Ok("text-color"));
}
#[test]
fn parse_margin_arb() {
let result = get_collision_id(&["m"], "length:var(--c)");
assert_eq!(result, Ok("margin"));
}
#[test]
fn parse_border_color_arb() {
assert!(!is_arbitrary_len(
"color:rgb(var(--color-gray-500-rgb)/50%)"
));
let result = get_collision_id(&["border"], "color:rgb(var(--color-gray-500-rgb)/50%)");
assert_eq!(result, Ok("border-color"));
let result = get_collision_id(&["border", "some", "color"], "");
assert_eq!(result, Ok("border-color"));
let result = get_collision_id(&["border", "b"], "");
assert_eq!(result, Ok("border-w-b"));
}
}