1#![warn(missing_docs)]
2
3use nargo_ir::IRModule;
4use nargo_transformer::{CallCountPass, ConstantFoldingPass, DeadCodeEliminationPass, I18nPass, ScopedCssPass, StaticHoistingPass, StyleAnalysisPass, Transformer, TreeShakingPass};
5use nargo_types::{NargoValue, Result};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub enum TargetEnvironment {
10 Browser,
12 SSR,
14 Mobile,
16 Desktop,
18 Embedded,
20}
21
22impl Default for TargetEnvironment {
23 fn default() -> Self {
24 Self::Browser
25 }
26}
27
28#[derive(Debug, Clone, Default)]
30pub struct EnvironmentOptimizationConfig {
31 pub target: TargetEnvironment,
33 pub memory_optimization: bool,
35 pub performance_optimization: bool,
37 pub size_optimization: bool,
39 pub extra_config: std::collections::HashMap<String, String>,
41}
42
43#[derive(Debug, Clone, PartialEq)]
45pub enum OptimizationLevel {
46 None,
48 Basic,
50 Standard,
52 Aggressive,
54}
55
56pub struct Optimizer {
60 pub last_css: String,
62 pub optimization_level: OptimizationLevel,
64 pub environment_config: EnvironmentOptimizationConfig,
66}
67
68impl Default for Optimizer {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74impl Optimizer {
75 pub fn new() -> Self {
77 Self { last_css: String::new(), optimization_level: OptimizationLevel::Standard, environment_config: EnvironmentOptimizationConfig::default() }
78 }
79
80 pub fn set_optimization_level(&mut self, level: OptimizationLevel) {
86 self.optimization_level = level;
87 }
88
89 pub fn set_environment_config(&mut self, config: EnvironmentOptimizationConfig) {
95 self.environment_config = config;
96 }
97
98 pub fn set_target_environment(&mut self, target: TargetEnvironment) {
104 self.environment_config.target = target;
105 }
106
107 pub fn optimize(&mut self, ir: &mut IRModule, locale: Option<&str>, is_prod: bool) {
115 match self.optimization_level {
116 OptimizationLevel::None => {
117 return;
119 }
120 OptimizationLevel::Basic => {
121 self.apply_basic_optimizations(ir, locale);
123 }
124 OptimizationLevel::Standard => {
125 self.apply_basic_optimizations(ir, locale);
127 self.apply_standard_optimizations(ir);
128 }
129 OptimizationLevel::Aggressive => {
130 self.apply_basic_optimizations(ir, locale);
132 self.apply_standard_optimizations(ir);
133 self.apply_aggressive_optimizations(ir);
134 }
135 }
136
137 self.apply_environment_specific_optimizations(ir);
139
140 if is_prod {
141 self.apply_production_optimizations(ir);
143 }
144 }
145
146 fn apply_basic_optimizations(&self, ir: &mut IRModule, locale: Option<&str>) {
153 let mut transformer = Transformer::new();
154
155 let mut folding_pass = ConstantFoldingPass::new();
157 let _ = transformer.apply(ir, &mut folding_pass);
158
159 let mut dce_pass = DeadCodeEliminationPass::new();
161 let _ = transformer.apply(ir, &mut dce_pass);
162
163 if let Some(locale_val) = locale {
165 if let Some(i18n_map) = &ir.i18n {
166 if let Some(messages) = i18n_map.get(locale_val) {
167 let mut i18n_pass = I18nPass::new(messages.clone());
168 let _ = transformer.apply(ir, &mut i18n_pass);
169 }
170 }
171 }
172 }
173
174 fn apply_standard_optimizations(&self, ir: &mut IRModule) {
180 let mut transformer = Transformer::new();
181
182 let mut hoisting_pass = StaticHoistingPass::new();
184 let _ = transformer.apply(ir, &mut hoisting_pass);
185
186 let mut style_pass = StyleAnalysisPass::new();
188 let _ = transformer.apply(ir, &mut style_pass);
189
190 let mut call_count_pass = CallCountPass::new();
192 let _ = transformer.apply(ir, &mut call_count_pass);
193 }
194
195 fn apply_aggressive_optimizations(&self, ir: &mut IRModule) {
201 let mut transformer = Transformer::new();
202
203 let mut tree_shaking_pass = TreeShakingPass::new();
205 let _ = transformer.apply(ir, &mut tree_shaking_pass);
206 }
207
208 fn apply_production_optimizations(&self, ir: &mut IRModule) {
214 let mut transformer = Transformer::new();
215
216 let mut dce_pass = DeadCodeEliminationPass::new();
218 let _ = transformer.apply(ir, &mut dce_pass);
219
220 let mut tree_shaking_pass = TreeShakingPass::new();
222 let _ = transformer.apply(ir, &mut tree_shaking_pass);
223
224 ir.cleanup();
226 }
227
228 fn apply_environment_specific_optimizations(&self, ir: &mut IRModule) {
234 match self.environment_config.target {
235 TargetEnvironment::Browser => {
236 self.apply_browser_optimizations(ir);
237 }
238 TargetEnvironment::SSR => {
239 self.apply_ssr_optimizations(ir);
240 }
241 TargetEnvironment::Mobile => {
242 self.apply_mobile_optimizations(ir);
243 }
244 TargetEnvironment::Desktop => {
245 self.apply_desktop_optimizations(ir);
246 }
247 TargetEnvironment::Embedded => {
248 self.apply_embedded_optimizations(ir);
249 }
250 }
251 }
252
253 fn apply_browser_optimizations(&self, ir: &mut IRModule) {
259 let mut transformer = Transformer::new();
260
261 if self.environment_config.size_optimization {
263 let mut tree_shaking_pass = TreeShakingPass::new();
265 let _ = transformer.apply(ir, &mut tree_shaking_pass);
266 }
267
268 if self.environment_config.performance_optimization {
270 let mut hoisting_pass = StaticHoistingPass::new();
272 let _ = transformer.apply(ir, &mut hoisting_pass);
273 }
274 }
275
276 fn apply_ssr_optimizations(&self, ir: &mut IRModule) {
282 let mut transformer = Transformer::new();
283
284 if self.environment_config.memory_optimization {
286 let mut dce_pass = DeadCodeEliminationPass::new();
288 let _ = transformer.apply(ir, &mut dce_pass);
289 }
290
291 if self.environment_config.performance_optimization {
293 let mut folding_pass = ConstantFoldingPass::new();
295 let _ = transformer.apply(ir, &mut folding_pass);
296 }
297 }
298
299 fn apply_mobile_optimizations(&self, ir: &mut IRModule) {
305 let mut transformer = Transformer::new();
306
307 if self.environment_config.size_optimization {
309 let mut tree_shaking_pass = TreeShakingPass::new();
311 let _ = transformer.apply(ir, &mut tree_shaking_pass);
312 }
313
314 if self.environment_config.memory_optimization {
316 let mut dce_pass = DeadCodeEliminationPass::new();
318 let _ = transformer.apply(ir, &mut dce_pass);
319 }
320 }
321
322 fn apply_desktop_optimizations(&self, ir: &mut IRModule) {
328 let mut transformer = Transformer::new();
329
330 if self.environment_config.performance_optimization {
332 let mut hoisting_pass = StaticHoistingPass::new();
334 let _ = transformer.apply(ir, &mut hoisting_pass);
335
336 let mut call_count_pass = CallCountPass::new();
338 let _ = transformer.apply(ir, &mut call_count_pass);
339 }
340 }
341
342 fn apply_embedded_optimizations(&self, ir: &mut IRModule) {
348 let mut transformer = Transformer::new();
349
350 if self.environment_config.size_optimization {
352 let mut tree_shaking_pass = TreeShakingPass::new();
354 let _ = transformer.apply(ir, &mut tree_shaking_pass);
355 }
356
357 if self.environment_config.memory_optimization {
359 let mut dce_pass = DeadCodeEliminationPass::new();
361 let _ = transformer.apply(ir, &mut dce_pass);
362 }
363
364 if self.environment_config.performance_optimization {
366 let mut folding_pass = ConstantFoldingPass::new();
368 let _ = transformer.apply(ir, &mut folding_pass);
369 }
370 }
371
372 pub fn process_styles(&mut self, ir: &IRModule) -> Result<()> {
382 let mut final_css = String::new();
383
384 for style in &ir.styles {
386 final_css.push_str(&style.code);
387 final_css.push('\n');
388 }
389
390 if let Some(NargoValue::String(classes)) = ir.metadata.get("collected_styles") {
392 final_css.push_str(&self.generate_tailwind_css(classes));
394 }
395
396 self.last_css = final_css;
397 Ok(())
398 }
399
400 fn generate_tailwind_css(&self, classes: &str) -> String {
410 let mut css = String::new();
411
412 let class_map = std::collections::HashMap::from([("p-4", "padding: 1rem;"), ("p-6", "padding: 1.5rem;"), ("m-2", "margin: 0.5rem;"), ("m-4", "margin: 1rem;"), ("flex", "display: flex;"), ("items-center", "align-items: center;"), ("bg-blue", "background-color: #0000ff;"), ("text-white", "color: #ffffff;"), ("text-blue", "color: #0000ff;"), ("rounded-lg", "border-radius: 0.5rem;"), ("shadow-sm", "box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);"), ("font-bold", "font-weight: 700;"), ("text-2xl", "font-size: 1.5rem;"), ("text-center", "text-align: center;"), ("mx-4", "margin-left: 1rem; margin-right: 1rem;")]);
414
415 for class in classes.split_whitespace() {
416 if let Some(style) = class_map.get(class) {
417 css.push_str(&format!(".{} {{ {} }}\n", class, style));
418 }
419 }
420
421 css
422 }
423
424 pub fn get_css(&self) -> String {
430 self.last_css.clone()
431 }
432
433 pub fn apply_scope_id(&mut self, ir: &mut IRModule, scope_id: &str) {
440 let mut transformer = Transformer::new();
441 let mut pass = ScopedCssPass::new(scope_id.to_string());
442 let _ = transformer.apply(ir, &mut pass);
443 }
444
445 pub fn generate_scope_id(&self, name: &str) -> String {
455 use std::{
456 collections::hash_map::DefaultHasher,
457 hash::{Hash, Hasher},
458 };
459 let mut hasher = DefaultHasher::new();
460 name.hash(&mut hasher);
461 let hash = hasher.finish();
462 format!("data-h-{:x}", hash)
463 }
464
465 pub fn set_detailed_optimizations(&mut self, enabled: bool) {
471 if enabled {
472 self.optimization_level = OptimizationLevel::Aggressive;
473 }
474 else {
475 self.optimization_level = OptimizationLevel::Basic;
476 }
477 }
478}