Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collision Fixes #16

Merged
merged 3 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 11 additions & 18 deletions fuse/src/core/merge/get_collision_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,9 @@ pub fn get_collision_id(classes: &[&str], arbitrary: &str) -> Result<&'static st
["stroke"] if is_valid_length(arbitrary) => Ok("stroke-width"),

// https://tailwindcss.com/docs/stroke
["stroke", ..] => Ok("stroke"),
["stroke", ..]=> {
Ok("stroke")
},

// https://tailwindcss.com/docs/screen-readers
["sr", "only"] | ["not", "sr", "only"] => Ok("screen-readers"),
Expand Down Expand Up @@ -798,7 +800,7 @@ fn valid_top_right_bottom_left(mode: &str) -> bool {
mode == "auto"
|| mode == "full"
|| mode == "px"
|| parse_single_digit_decimal(mode).is_some()
|| validators::parse_single_digit_decimal(mode)
|| parse_fraction(mode).is_some()
}

Expand All @@ -809,30 +811,21 @@ fn valid_break_after(mode: &str) -> bool {
)
}

// Need starts_with for this https://tailwindcss.com/docs/font-size#setting-the-line-height
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")
}

// parses 1.5 but not 1.55
fn parse_single_digit_decimal(input: &str) -> Option<()> {
if input.len() == 1 {
let _ = input.parse::<usize>().ok()?;
Some(())
} else if input.len() == 3 {
let (l, r) = input.split_once('.')?;
let _ = l.parse::<usize>().ok()?;
let _ = r.parse::<usize>().ok()?;
Some(())
} else {
None
}
}

fn parse_fraction_or_usize(input: &str) -> bool {
parse_fraction(input)
.map(|_| ())
Expand Down Expand Up @@ -909,8 +902,8 @@ mod test {
assert!(is_valid_length("10%"));
assert!(is_valid_length("100rem"));

assert!(!is_valid_length("10"), "needs unit");
assert!(!is_valid_length("hsl(350_80%_0%)"), "no color");
assert!(!is_valid_length("--my-0"), "double negative");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion fuse/src/core/merge/get_collisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub(crate) fn get_collisions(collision_id: &str) -> Option<Vec<&'static str>> {
"margin-x" => Some(vec!["margin-right", "margin-left"]),
"margin-y" => Some(vec!["margin-top", "margin-bottom"]),
"size" => Some(vec!["width", "height"]),
"font-size" => Some(vec!["leading"]),
"font-size" => Some(vec!["line-height"]),
"fvn-normal" => Some(vec![
"fvn-ordinal",
"fvn-slashed-zero",
Expand Down
58 changes: 50 additions & 8 deletions fuse/src/core/merge/merge_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,19 @@ pub fn tw_merge_with_override(
});

match result {
Err(error) => {
#[cfg(debug)]
println!("No Instance found: {style:?} {error:?}");
let _ = error;
valid_styles.push(Ok(style));
}
Err(error) => match Collision::check_arbitrary(style.clone()) {
Some(collision) => {
if collision_styles.contains(&collision) {
continue;
}
collision_styles.insert(collision);
}
None => {
#[cfg(debug)]
println!("No Instance found: {style:?} {error:?}");
let _ = error;
}
},
Ok(collision_id) => {
// hover:md:focus
let all_variants: Vec<&str> = style.variants.clone();
Expand Down Expand Up @@ -75,10 +82,9 @@ pub fn tw_merge_with_override(
collision_styles.insert(collision);
});
}

valid_styles.push(Ok(style));
}
}
valid_styles.push(Ok(style));
}

valid_styles.reverse();
Expand All @@ -99,3 +105,39 @@ struct Collision<'a> {
variants: Vec<&'a str>,
collision_id: &'a str,
}

// For [color:blue] => label = "color"
impl<'a> Collision<'a> {
fn check_arbitrary(style: AstStyle<'a>) -> Option<Self> {
let arbitrary = style.arbitrary?;
if arbitrary.contains(':') {
let mut parts = arbitrary.split(':');
let collision_id = parts.next()?;
Some(Self {
collision_id,
important: style.important,
variants: style.variants,
})
} else {
None
}
}
}

#[test]
fn check_arbitrary() {
let style = crate::ast::parse_tailwind(&["[color:blue]"], Default::default())
.into_iter()
.next()
.unwrap()
.unwrap();

assert_eq!(
Collision::check_arbitrary(style),
Some(Collision {
important: false,
variants: vec![],
collision_id: "color"
})
);
}
73 changes: 70 additions & 3 deletions fuse/src/core/merge/validators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ pub mod length {
use super::*;

pub fn parse(input: &str) -> IResult<&str, &str> {
alt((tag("0"), number, unit, functional_notation))(input)
alt((tag("0"), number, functional_notation))(input)
}

// Parser for numeric values
fn number(input: &str) -> IResult<&str, &str> {
recognize(pair(
take_while1(|c: char| c.is_ascii_digit() || c == '.' || c == '-'),
unit,
pair(
opt(char('-')),
take_while1(|c: char| c.is_ascii_digit() || c == '.'),
),
opt(unit),
))(input)
}

Expand Down Expand Up @@ -74,6 +77,14 @@ pub mod length {
let (_, result) = parse(input).unwrap();
assert_eq!(result, "theme(fontSize.4xl)/1.125");
}

#[test]
fn num_len() {
let input = "1";
assert!('1'.is_ascii_digit());
let result = number(input).unwrap();
assert_eq!(result, ("", "1"));
}
}

pub mod arbitrary {
Expand Down Expand Up @@ -173,3 +184,59 @@ pub mod image {
take_while1(|c: char| c != ')')(input)
}
}

pub fn parse_single_digit_decimal(input: &str) -> bool {
if input.is_empty() {
return false;
}

let mut dot_index = None;
for (i, c) in input.char_indices() {
if c == '.' {
if dot_index.is_some() || i == 0 || i == input.len() - 1 || input.len() - i != 2 {
return false;
}
dot_index = Some(i);
} else if !c.is_ascii_digit() {
return false;
}
}

true
}

#[test]
fn test_valid_single_digit_decimal() {
assert!(parse_single_digit_decimal("1.5"));
assert!(parse_single_digit_decimal("11.5"));
assert!(parse_single_digit_decimal("0.0"));
assert!(parse_single_digit_decimal("9.9"));
assert!(parse_single_digit_decimal("123"));
assert!(parse_single_digit_decimal("0"));
assert!(parse_single_digit_decimal("1"));
assert!(parse_single_digit_decimal("12345"));
assert!(parse_single_digit_decimal("9.0"));
assert!(parse_single_digit_decimal("0.9"));
}

#[test]
fn test_invalid_single_digit_decimal() {
assert!(!parse_single_digit_decimal(""));
assert!(!parse_single_digit_decimal("1.55"));
assert!(!parse_single_digit_decimal("11.55"));
assert!(!parse_single_digit_decimal("1."));
assert!(!parse_single_digit_decimal(".5"));
assert!(!parse_single_digit_decimal("1.5.5"));
assert!(!parse_single_digit_decimal("a.5"));
assert!(!parse_single_digit_decimal("1.a"));
assert!(!parse_single_digit_decimal("1 .5"));
assert!(!parse_single_digit_decimal("1. 5"));
assert!(!parse_single_digit_decimal("-1.5"));
assert!(!parse_single_digit_decimal("+1.5"));
assert!(!parse_single_digit_decimal("1.5e3"));
assert!(!parse_single_digit_decimal("1.5E3"));
assert!(!parse_single_digit_decimal("1.5f"));
assert!(!parse_single_digit_decimal("1.5d"));
assert!(!parse_single_digit_decimal("1,5"));
assert!(!parse_single_digit_decimal("1..5"));
}
31 changes: 31 additions & 0 deletions fuse/tests/group-conflicts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,34 @@ fn line_clamp_classes_do_create_conflicts_correctly() {
"line-clamp-1 overflow-auto inline"
);
}

#[test]
fn test_line_height_font_size() {
assert_eq!(tw_merge("leading-9 text-lg"), "text-lg");
}

#[test]
fn text_color_font_size() {
assert_eq!(tw_merge("text-red-500 text-lg"), "text-red-500 text-lg");

// https://tailwindcss.com/docs/font-size#setting-the-line-height
assert_eq!(
tw_merge("text-red-500/10 text-lg/9"),
"text-red-500/10 text-lg/9"
);
}

#[test]
fn stroke_width() {
assert_eq!(tw_merge("stroke-2 stroke-[3]"), "stroke-[3]");
}

#[test]
fn handles_negative_value_conflicts_correctly() {
assert_eq!(tw_merge("-top-12 -top-2000"), "-top-2000");
}

#[test]
fn tailwind_3_4() {
assert_eq!(tw_merge("text-red text-lg/8"), "text-red text-lg/8");
}
26 changes: 26 additions & 0 deletions fuse/tests/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,3 +436,29 @@ fn columns() {
let result = tw_merge(class);
assert_eq!(result, "columns-[2rem]");
}

#[test]
fn arbitrary_property_conflicts() {
let class = "[&>*]:[color:red] [&>*]:[color:blue]";
let result = tw_merge(class);
assert_eq!(result, "[&>*]:[color:blue]");

let class = "![some:prop] [some:other] [some:one] ![some:another]";
let result = tw_merge(class);
assert_eq!(result, "[some:one] ![some:another]");

let class = "hover:[paint-order:markers] hover:[paint-order:normal]";
let result = tw_merge(class);
assert_eq!(result, "hover:[paint-order:normal]");
}

#[test]
fn test_negative_values() {
let class = "top-12 -top-69";
let result = tw_merge(class);
assert_eq!(result, "-top-69");

let class = "-top-12 -top-2000";
let result = tw_merge(class);
assert_eq!(result, "-top-2000");
}
Loading