1use omena_cascade::{
2 CascadeValue, CustomPropertyLeastFixedPointSummaryV0,
3 summarize_custom_property_least_fixed_point,
4};
5use omena_parser::{StyleDialect, lex};
6
7use crate::domains::{
8 calc::reduce_css_calc_with_lexer,
9 cascade_flatten::{flatten_css_layers_with_lexer, flatten_css_scopes_with_lexer},
10 color::compress_css_colors_with_lexer,
11 color_lowering::{
12 lower_css_color_function_with_lexer, lower_css_color_mix_with_lexer,
13 lower_css_light_dark_with_lexer, lower_css_oklab_oklch_with_lexer,
14 },
15 css_modules_classes::{
16 local_css_module_composes_resolutions_with_lexer,
17 reachable_class_names_with_local_composes, rewrite_css_module_class_names_with_lexer,
18 strip_resolved_css_module_composes_with_lexer, tree_shake_css_class_rules_with_lexer,
19 },
20 css_modules_values::{
21 resolve_static_css_modules_values_with_lexer, tree_shake_css_modules_values_with_lexer,
22 },
23 custom_property::{
24 collect_static_root_custom_property_env, parse_static_custom_property_env_value,
25 substitute_static_css_custom_properties_with_lexer,
26 tree_shake_css_custom_properties_with_lexer,
27 },
28 design_token::route_design_token_values_with_lexer,
29 import_inline::{
30 inline_css_imports_for_static_module_evaluation_with_lexer, inline_css_imports_with_lexer,
31 restore_less_inline_literal_placeholders as restore_less_inline_literal_placeholders_with_lexer,
32 },
33 keyframes::tree_shake_css_keyframes_with_lexer,
34 logical::lower_css_logical_to_physical_with_lexer,
35 nesting::unwrap_css_nesting_with_lexer,
36 number::compress_css_numbers_with_lexer,
37 reachability::class_name_is_reachable,
38 rule_cleanup::{dedupe_exact_css_rules_with_lexer, remove_empty_css_rules_with_lexer},
39 rule_merge::{
40 merge_adjacent_same_block_css_selectors_with_lexer,
41 merge_adjacent_same_selector_css_rules_with_lexer,
42 },
43 selector::compress_css_is_where_selectors_with_lexer,
44 shorthand::combine_css_shorthands_with_lexer,
45 static_eval::{
46 StaticMediaEvaluationOptions, evaluate_static_media_rules_with_lexer,
47 evaluate_static_supports_rules_with_lexer,
48 },
49 text::{
50 normalize_css_font_declarations_with_lexer, normalize_css_string_quotes_with_lexer,
51 strip_css_url_quotes_with_lexer,
52 },
53 trivia::{normalize_css_whitespace_with_lexer, strip_css_comments_with_lexer},
54 unit::normalize_css_units_with_lexer,
55 vendor_prefix::add_css_vendor_prefixes_with_lexer,
56};
57use crate::helpers::rules::collect_top_level_ordinary_rule_slices;
58use crate::model::{
59 TransformClassNameRewriteV0, TransformCssModuleComposesResolutionV0,
60 TransformCssModuleValueResolutionV0, TransformDesignTokenRouteV0, TransformExecutionContextV0,
61 TransformImportInlineV0, TransformLessInlineLiteralPlaceholderV0,
62 TransformSemanticRemovalCandidate,
63};
64
65pub(crate) fn strip_css_comments(source: &str, dialect: StyleDialect) -> (String, usize) {
66 strip_css_comments_with_lexer(source, dialect)
67}
68
69pub(crate) fn compress_css_numbers(source: &str, dialect: StyleDialect) -> (String, usize) {
70 compress_css_numbers_with_lexer(source, dialect)
71}
72
73pub(crate) fn compress_css_colors(source: &str, dialect: StyleDialect) -> (String, usize) {
74 compress_css_colors_with_lexer(source, dialect)
75}
76
77pub(crate) fn normalize_css_units(source: &str, dialect: StyleDialect) -> (String, usize) {
78 normalize_css_units_with_lexer(source, dialect)
79}
80
81pub(crate) fn strip_css_url_quotes(source: &str, dialect: StyleDialect) -> (String, usize) {
82 strip_css_url_quotes_with_lexer(source, dialect)
83}
84
85pub(crate) fn normalize_css_string_quotes(source: &str, dialect: StyleDialect) -> (String, usize) {
86 let (source, font_declaration_mutations) =
87 normalize_css_font_declarations_with_lexer(source, dialect);
88 let (source, token_mutations) = normalize_css_string_quotes_with_lexer(&source, dialect);
89 (source, font_declaration_mutations + token_mutations)
90}
91
92pub(crate) fn compress_css_is_where_selectors(
93 source: &str,
94 dialect: StyleDialect,
95) -> (String, usize) {
96 compress_css_is_where_selectors_with_lexer(source, dialect)
97}
98
99pub(crate) fn remove_empty_css_rules(source: &str, dialect: StyleDialect) -> (String, usize) {
100 remove_empty_css_rules_with_lexer(source, dialect)
101}
102
103pub(crate) fn combine_css_shorthands(source: &str, dialect: StyleDialect) -> (String, usize) {
104 combine_css_shorthands_with_lexer(source, dialect)
105}
106
107pub(crate) fn dedupe_exact_css_rules(source: &str, dialect: StyleDialect) -> (String, usize) {
108 dedupe_exact_css_rules_with_lexer(source, dialect)
109}
110
111pub(crate) fn merge_adjacent_same_selector_css_rules(
112 source: &str,
113 dialect: StyleDialect,
114) -> (String, usize) {
115 merge_adjacent_same_selector_css_rules_with_lexer(source, dialect)
116}
117
118pub(crate) fn merge_adjacent_same_block_css_selectors(
119 source: &str,
120 dialect: StyleDialect,
121) -> (String, usize) {
122 merge_adjacent_same_block_css_selectors_with_lexer(source, dialect)
123}
124
125pub(crate) fn add_css_vendor_prefixes(source: &str, dialect: StyleDialect) -> (String, usize) {
126 add_css_vendor_prefixes_with_lexer(source, dialect)
127}
128
129pub(crate) fn lower_css_light_dark(source: &str, dialect: StyleDialect) -> (String, usize) {
130 lower_css_light_dark_with_lexer(source, dialect)
131}
132
133pub(crate) fn lower_css_color_mix(source: &str, dialect: StyleDialect) -> (String, usize) {
134 lower_css_color_mix_with_lexer(source, dialect)
135}
136
137pub(crate) fn lower_css_oklab_oklch(source: &str, dialect: StyleDialect) -> (String, usize) {
138 lower_css_oklab_oklch_with_lexer(source, dialect)
139}
140
141pub(crate) fn lower_css_color_function(source: &str, dialect: StyleDialect) -> (String, usize) {
142 lower_css_color_function_with_lexer(source, dialect)
143}
144
145pub(crate) fn lower_css_logical_to_physical(
146 source: &str,
147 dialect: StyleDialect,
148) -> (String, usize) {
149 lower_css_logical_to_physical_with_lexer(source, dialect)
150}
151
152pub(crate) fn unwrap_css_nesting(source: &str, dialect: StyleDialect) -> (String, usize) {
153 unwrap_css_nesting_with_lexer(source, dialect)
154}
155
156pub(crate) fn flatten_css_scopes(source: &str, dialect: StyleDialect) -> (String, usize) {
157 flatten_css_scopes_with_lexer(source, dialect)
158}
159
160pub(crate) fn flatten_css_layers(
161 source: &str,
162 dialect: StyleDialect,
163 closed_bundle: bool,
164) -> (String, usize) {
165 flatten_css_layers_with_lexer(source, dialect, closed_bundle)
166}
167
168pub(crate) fn evaluate_static_supports_rules(
169 source: &str,
170 dialect: StyleDialect,
171) -> (String, usize) {
172 evaluate_static_supports_rules_with_lexer(source, dialect)
173}
174
175pub(crate) fn evaluate_static_media_rules(source: &str, dialect: StyleDialect) -> (String, usize) {
176 evaluate_static_media_rules_with_lexer(source, dialect, StaticMediaEvaluationOptions::default())
177}
178
179pub(crate) fn evaluate_dead_media_branch_rules(
180 source: &str,
181 dialect: StyleDialect,
182 context: &TransformExecutionContextV0,
183) -> (String, usize) {
184 evaluate_static_media_rules_with_lexer(
185 source,
186 dialect,
187 StaticMediaEvaluationOptions {
188 drop_dark_mode_media_queries: context.drop_dark_mode_media_queries,
189 },
190 )
191}
192
193pub fn inline_css_imports(
195 source: &str,
196 dialect: StyleDialect,
197 inlines: &[TransformImportInlineV0],
198) -> (String, usize) {
199 inline_css_imports_with_lexer(source, dialect, inlines)
200}
201
202pub fn inline_css_imports_for_static_module_evaluation(
204 source: &str,
205 dialect: StyleDialect,
206 inlines: &[TransformImportInlineV0],
207) -> (String, usize, Vec<TransformLessInlineLiteralPlaceholderV0>) {
208 inline_css_imports_for_static_module_evaluation_with_lexer(source, dialect, inlines)
209}
210
211pub fn restore_less_inline_literal_placeholders(
213 source: &str,
214 placeholders: &[TransformLessInlineLiteralPlaceholderV0],
215) -> String {
216 restore_less_inline_literal_placeholders_with_lexer(source, placeholders)
217}
218
219pub(crate) fn resolve_static_css_modules_values(
220 source: &str,
221 dialect: StyleDialect,
222 resolutions: &[TransformCssModuleValueResolutionV0],
223) -> (String, usize) {
224 resolve_static_css_modules_values_with_lexer(source, dialect, resolutions)
225}
226
227pub(crate) fn resolve_css_module_composes(
228 source: &str,
229 dialect: StyleDialect,
230 resolutions: &[TransformCssModuleComposesResolutionV0],
231) -> (String, usize) {
232 strip_resolved_css_module_composes_with_lexer(source, dialect, resolutions)
233}
234
235pub(crate) fn css_module_composes_resolutions_for_source(
236 source: &str,
237 dialect: StyleDialect,
238 resolutions: &[TransformCssModuleComposesResolutionV0],
239) -> Vec<TransformCssModuleComposesResolutionV0> {
240 let mut merged = local_css_module_composes_resolutions_with_lexer(source, dialect);
241 for resolution in resolutions {
242 let Some(existing) = merged
243 .iter_mut()
244 .find(|existing| existing.local_class_name == resolution.local_class_name)
245 else {
246 merged.push(resolution.clone());
247 continue;
248 };
249 for exported_class_name in &resolution.exported_class_names {
250 if !existing
251 .exported_class_names
252 .iter()
253 .any(|existing| existing == exported_class_name)
254 {
255 existing
256 .exported_class_names
257 .push(exported_class_name.clone());
258 }
259 }
260 }
261 merged.sort_by(|left, right| left.local_class_name.cmp(&right.local_class_name));
262 merged
263}
264
265pub(crate) fn route_design_token_values(
266 source: &str,
267 dialect: StyleDialect,
268 routes: &[TransformDesignTokenRouteV0],
269) -> (String, usize) {
270 route_design_token_values_with_lexer(source, dialect, routes)
271}
272
273pub(crate) fn tree_shake_css_class_rules_with_removals(
274 source: &str,
275 dialect: StyleDialect,
276 reachable_class_names: &[String],
277) -> (String, Vec<TransformSemanticRemovalCandidate>) {
278 tree_shake_css_class_rules_with_lexer(source, dialect, reachable_class_names)
279}
280
281pub(crate) fn reachable_class_names_with_composes_exports(
282 source: &str,
283 dialect: StyleDialect,
284 reachable_class_names: &[String],
285 resolutions: &[TransformCssModuleComposesResolutionV0],
286) -> Vec<String> {
287 let mut expanded = reachable_class_names.to_vec();
288 let mut changed = true;
289
290 while changed {
291 changed = false;
292 for resolution in resolutions {
293 if !class_name_is_reachable(&resolution.local_class_name, &expanded) {
294 continue;
295 }
296 for exported_class_name in &resolution.exported_class_names {
297 if !class_name_is_reachable(exported_class_name, &expanded) {
298 expanded.push(exported_class_name.clone());
299 changed = true;
300 }
301 }
302 }
303 }
304
305 expanded.sort();
306 expanded.dedup();
307 reachable_class_names_with_local_composes(source, dialect, &expanded)
308}
309
310pub(crate) fn tree_shake_css_keyframes_with_removals(
311 source: &str,
312 dialect: StyleDialect,
313 reachable_keyframe_names: &[String],
314 reachable_class_names: &[String],
315) -> (String, Vec<TransformSemanticRemovalCandidate>) {
316 tree_shake_css_keyframes_with_lexer(
317 source,
318 dialect,
319 reachable_keyframe_names,
320 reachable_class_names,
321 )
322}
323
324pub(crate) fn tree_shake_css_modules_values_with_removals(
325 source: &str,
326 dialect: StyleDialect,
327 reachable_value_names: &[String],
328 reachable_keyframe_names: &[String],
329 reachable_class_names: &[String],
330) -> (String, Vec<TransformSemanticRemovalCandidate>) {
331 tree_shake_css_modules_values_with_lexer(
332 source,
333 dialect,
334 reachable_value_names,
335 reachable_keyframe_names,
336 reachable_class_names,
337 )
338}
339
340pub(crate) fn tree_shake_css_custom_properties_with_removals(
341 source: &str,
342 dialect: StyleDialect,
343 reachable_custom_property_names: &[String],
344 reachable_keyframe_names: &[String],
345 reachable_class_names: &[String],
346) -> (String, Vec<TransformSemanticRemovalCandidate>) {
347 tree_shake_css_custom_properties_with_lexer(
348 source,
349 dialect,
350 reachable_custom_property_names,
351 reachable_keyframe_names,
352 reachable_class_names,
353 )
354}
355
356pub(crate) fn rewrite_css_module_class_names(
357 source: &str,
358 dialect: StyleDialect,
359 rewrites: &[TransformClassNameRewriteV0],
360) -> (String, usize) {
361 rewrite_css_module_class_names_with_lexer(source, dialect, rewrites)
362}
363
364pub(crate) fn substitute_static_css_custom_properties(
365 source: &str,
366 dialect: StyleDialect,
367) -> (String, usize) {
368 substitute_static_css_custom_properties_with_lexer(source, dialect)
369}
370
371pub fn summarize_static_css_custom_property_fixed_point_from_source(
373 source: &str,
374 dialect: StyleDialect,
375) -> CustomPropertyLeastFixedPointSummaryV0 {
376 let lexed = lex(source, dialect);
377 let tokens = lexed.tokens();
378 let env_rules = collect_top_level_ordinary_rule_slices(source, tokens);
379 let env = collect_static_root_custom_property_env(tokens, &env_rules);
380 summarize_custom_property_least_fixed_point(&env)
381}
382
383pub fn parse_static_css_cascade_value(value: &str) -> Option<CascadeValue> {
385 match value.trim() {
386 "initial" => Some(CascadeValue::Initial),
387 "inherit" => Some(CascadeValue::Inherit),
388 "unset" => Some(CascadeValue::Unset),
389 value => parse_static_custom_property_env_value(value),
390 }
391}
392
393pub(crate) fn reduce_css_calc(source: &str, dialect: StyleDialect) -> (String, usize) {
394 reduce_css_calc_with_lexer(source, dialect)
395}
396
397pub(crate) fn normalize_css_whitespace(source: &str, dialect: StyleDialect) -> (String, usize) {
398 normalize_css_whitespace_with_lexer(source, dialect)
399}