csskit_transform/
reduce_urls.rs

1use crate::prelude::*;
2use css_ast::{Url, UrlOrString, Visitable};
3
4pub struct ReduceUrls<'a, 'ctx, N: Visitable + NodeWithMetadata<CssMetadata>> {
5	pub transformer: &'ctx Transformer<'a, CssMetadata, N, CssMinifierFeature>,
6}
7
8impl<'a, 'ctx, N> Transform<'a, 'ctx, CssMetadata, N, CssMinifierFeature> for ReduceUrls<'a, 'ctx, N>
9where
10	N: Visitable + NodeWithMetadata<CssMetadata>,
11{
12	fn may_change(features: CssMinifierFeature, _node: &N) -> bool {
13		features.contains(CssMinifierFeature::ReduceUrls)
14	}
15
16	fn new(transformer: &'ctx Transformer<'a, CssMetadata, N, CssMinifierFeature>) -> Self {
17		Self { transformer }
18	}
19}
20
21impl<'a, 'ctx, N> Visit for ReduceUrls<'a, 'ctx, N>
22where
23	N: Visitable + NodeWithMetadata<CssMetadata>,
24{
25	fn visit_url_or_string(&mut self, url_or_string: &UrlOrString) {
26		let url = match url_or_string {
27			UrlOrString::Url(url) => url,
28			UrlOrString::String(_) => return,
29		};
30		match url {
31			Url::UrlFunction(_, string, _) | Url::SrcFunction(_, string, _) => {
32				self.transformer.replace_parsed::<UrlOrString>(
33					url_or_string.to_span(),
34					&format!("\"{}\"", {
35						let sc = self.transformer.to_source_cursor((*string).into());
36						let token = sc.token();
37						let start = token.leading_len() as usize;
38						let end = sc.source().len() - token.trailing_len() as usize;
39						&sc.source()[start..end]
40					}),
41				);
42			}
43			Url::Url(url_token) => {
44				let sc = self.transformer.to_source_cursor((*url_token).into());
45				let token = sc.token();
46				let leading_len = token.leading_len() as usize;
47				let trailing_len = token.trailing_len() as usize;
48				let url_content = &sc.source()[leading_len..(sc.source().len() - trailing_len)];
49				let url_content = url_content.trim();
50				self.transformer
51					.replace_parsed::<UrlOrString>(url_or_string.to_span(), &format!("\"{}\"", url_content));
52			}
53		}
54	}
55}
56
57#[cfg(test)]
58mod tests {
59	use crate::test_helpers::{assert_no_transform, assert_transform};
60	use css_ast::{CssAtomSet, StyleSheet};
61
62	#[test]
63	fn reduces_url_function_to_string_in_import() {
64		assert_transform!(
65			CssMinifierFeature::ReduceUrls,
66			CssAtomSet,
67			StyleSheet,
68			"@import url(\"foo.css\");",
69			"@import \"foo.css\";"
70		);
71	}
72
73	#[test]
74	fn reduces_url_function_single_quotes_to_string_in_import() {
75		assert_transform!(
76			CssMinifierFeature::ReduceUrls,
77			CssAtomSet,
78			StyleSheet,
79			"@import url('foo.css');",
80			"@import \"foo.css\";"
81		);
82	}
83
84	#[test]
85	fn reduces_bare_url_to_string_in_import() {
86		assert_transform!(
87			CssMinifierFeature::ReduceUrls,
88			CssAtomSet,
89			StyleSheet,
90			"@import url(foo.css);",
91			"@import \"foo.css\";"
92		);
93	}
94
95	#[test]
96	fn reduces_url_with_media_query() {
97		assert_transform!(
98			CssMinifierFeature::ReduceUrls,
99			CssAtomSet,
100			StyleSheet,
101			"@import url(\"foo.css\") screen;",
102			"@import \"foo.css\" screen;"
103		);
104	}
105
106	#[test]
107	fn reduces_url_with_layer() {
108		assert_transform!(
109			CssMinifierFeature::ReduceUrls,
110			CssAtomSet,
111			StyleSheet,
112			"@import url(\"foo.css\") layer;",
113			"@import \"foo.css\" layer;"
114		);
115	}
116
117	#[test]
118	fn reduces_url_with_supports() {
119		assert_transform!(
120			CssMinifierFeature::ReduceUrls,
121			CssAtomSet,
122			StyleSheet,
123			"@import url(\"foo.css\") supports(not (display: flex));",
124			"@import \"foo.css\" supports(not (display: flex));"
125		);
126	}
127
128	#[test]
129	fn reduces_url_with_layer_and_supports() {
130		assert_transform!(
131			CssMinifierFeature::ReduceUrls,
132			CssAtomSet,
133			StyleSheet,
134			"@import url(\"foo.css\") layer(base) supports(not (display: flex));",
135			"@import \"foo.css\" layer(base) supports(not (display: flex));"
136		);
137	}
138
139	#[test]
140	fn does_not_transform_bare_string() {
141		assert_no_transform!(CssMinifierFeature::ReduceUrls, CssAtomSet, StyleSheet, "@import \"foo.css\";");
142	}
143
144	#[test]
145	fn reduces_namespace_url_to_string() {
146		assert_transform!(
147			CssMinifierFeature::ReduceUrls,
148			CssAtomSet,
149			StyleSheet,
150			"@namespace url(\"http://www.w3.org/1999/xhtml\");",
151			"@namespace \"http://www.w3.org/1999/xhtml\";"
152		);
153	}
154
155	#[test]
156	fn reduces_namespace_url_with_prefix() {
157		assert_transform!(
158			CssMinifierFeature::ReduceUrls,
159			CssAtomSet,
160			StyleSheet,
161			"@namespace html url(\"http://www.w3.org/1999/xhtml\");",
162			"@namespace html \"http://www.w3.org/1999/xhtml\";"
163		);
164	}
165}