rustui_merge/core/merge/
merge_impl.rs1use std::collections::HashSet;
2
3use crate::ast::AstStyle;
4
5use super::{CollisionIdFn, GetCollisionsFn, MergeOptions};
6use crate::core::merge::get_collisions::get_collisions;
7
8pub fn tw_merge_override(
11 class: &[&str],
12 options: MergeOptions,
13 collision_id_fn: impl CollisionIdFn,
14 collisions_fn: impl GetCollisionsFn,
15) -> String {
16 let styles: Vec<Result<AstStyle, &str>> = crate::ast::parse_tailwind(class, options.into());
17
18 let mut valid_styles: Vec<Result<AstStyle, &str>> = vec![];
19 let mut collision_styles: HashSet<Collision> = HashSet::new();
20
21 for style in styles.into_iter().rev() {
22 let style = match style {
23 Ok(style) => style,
24 Err(s) => {
25 valid_styles.push(Err(s));
26 continue;
27 }
28 };
29
30 let elements = style.elements.as_slice();
31 let result = collision_id_fn
32 .apply(elements, style.arbitrary)
33 .map(Ok)
34 .unwrap_or_else(|| {
35 let arbitrary = style.arbitrary.unwrap_or_default();
36 super::get_collision_id::get_collision_id(elements, arbitrary)
37 });
38
39 match result {
40 Err(error) => match Collision::check_arbitrary(style.clone()) {
41 Some(collision) => {
42 if collision_styles.contains(&collision) {
43 continue;
44 }
45 collision_styles.insert(collision);
46 }
47 None => {
48 #[cfg(debug)]
49 println!("No Instance found: {style:?} {error:?}");
50 let _ = error;
51 }
52 },
53 Ok(collision_id) => {
54 let all_variants: Vec<&str> = style.variants.clone();
56
57 let collision = Collision {
58 important: style.important,
59 variants: all_variants.clone(),
60 collision_id,
61 };
62
63 if collision_styles.contains(&collision) {
64 continue;
65 }
66
67 collision_styles.insert(collision);
69
70 let collisions = collisions_fn
71 .apply(collision_id)
72 .or_else(|| get_collisions(collision_id));
73
74 if let Some(collisions) = collisions {
75 collisions.into_iter().for_each(|collision_id| {
76 let collision = Collision {
77 important: style.important,
78 variants: all_variants.clone(),
79 collision_id,
80 };
81
82 collision_styles.insert(collision);
83 });
84 }
85 }
86 }
87 valid_styles.push(Ok(style));
88 }
89
90 valid_styles.reverse();
91
92 valid_styles
93 .into_iter()
94 .map(|s| match s {
95 Ok(style) => style.source,
96 Err(s) => s,
97 })
98 .collect::<Vec<_>>()
99 .join(" ")
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Hash)]
103struct Collision<'a> {
104 important: bool,
105 variants: Vec<&'a str>,
106 collision_id: &'a str,
107}
108
109impl<'a> Collision<'a> {
111 fn check_arbitrary(style: AstStyle<'a>) -> Option<Self> {
112 let arbitrary = style.arbitrary?;
113 let index = arbitrary.find(':')?;
114 let (collision_id, _) = arbitrary.split_at(index);
115 Some(Self {
116 collision_id,
117 important: style.important,
118 variants: style.variants,
119 })
120 }
121}
122
123#[test]
124fn check_arbitrary() {
125 let style = crate::ast::parse_tailwind(&["[color:blue]"], Default::default())
126 .into_iter()
127 .next()
128 .unwrap()
129 .unwrap();
130
131 assert_eq!(
132 Collision::check_arbitrary(style),
133 Some(Collision {
134 important: false,
135 variants: vec![],
136 collision_id: "color"
137 })
138 );
139}