1pub mod arbitrary;
42pub mod ast_parser;
43pub mod classes;
44pub mod class_scanner;
45pub mod color;
46pub mod config;
47pub mod css_generator;
48pub mod css_optimizer;
49pub mod custom_variant;
50pub mod dark_mode;
51pub mod error;
52pub mod performance;
54pub mod plugin_system;
55pub mod responsive;
56#[cfg(feature = "postcss")]
57pub mod postcss_integration;
58pub mod enhanced_variants;
59
60#[cfg(feature = "postcss")]
61#[cfg(test)]
62mod postcss_integration_test;
63pub mod theme;
64pub mod theme_new;
65pub mod tree_shaker;
66pub mod utils;
67pub mod utilities;
68pub mod validation;
69
70#[cfg(test)]
71mod property_tests;
72
73#[cfg(test)]
74mod api_stability;
75
76#[cfg(test)]
77pub mod week18_documentation_tests;
78
79#[cfg(test)]
80pub mod week19_testing_qa_tests;
81
82#[cfg(test)]
83pub mod week20_release_prep_tests;
84
85pub mod api_contracts;
87
88#[cfg(test)]
89mod test_improvements;
90
91pub use arbitrary::{ArbitraryValue, ArbitraryValueError, ArbitraryValueUtilities};
93pub use ast_parser::AstParser;
94pub use classes::{ClassBuilder, ClassSet};
95pub use class_scanner::{ClassScanner, ScanConfig, ScanResults, ScanStats};
96pub use color::Color;
97pub use config::{BuildConfig, TailwindConfig};
98pub use config::parser::ConfigParser;
99pub use css_generator::{CssGenerator, CssProperty, CssRule, CssGenerationConfig};
101pub use css_optimizer::{OptimizationConfig, OptimizationResults, OptimizationStats};
102pub use custom_variant::{CustomVariant, CustomVariantManager, CustomVariantType};
103pub use dark_mode::{DarkModeVariant, DarkModeVariantError, DarkModeVariantUtilities};
104pub use error::{Result, TailwindError};
105pub use performance::{CacheStats, ClassCache, OptimizationLevel, PerformanceOptimizer};
107pub use plugin_system::{Plugin, PluginContext, PluginHook, PluginRegistry};
108pub use responsive::{
109 AlignItems, Breakpoint, FlexDirection, FlexWrap, JustifyContent, Responsive, ResponsiveBuilder,
110 ResponsiveFlex, ResponsiveGrid, ResponsiveValue, State,
111};
112pub use theme::{BorderRadius, BoxShadow, Spacing, Theme, ThemeValue};
113pub use theme_new::{
114 AnimationScale, BorderScale, FontFamily, FontSizeScale, FontWeightScale, LetterSpacingScale,
115 LineHeightScale, ShadowScale, SpacingScale, SpacingSize, Theme as NewTheme, ThemePreset,
116 ThemeVariant, ThemedComponent, TypographyScale,
117};
118pub use tree_shaker::{TreeShaker, TreeShakeConfig, TreeShakeResults, TreeShakeStats};
119pub use utilities::*;
120pub use validation::*;
121
122#[cfg(feature = "postcss")]
123pub use postcss_integration::{EnhancedCssGenerator, EnhancedCssResult, PostCSSIntegrationConfig};
124pub use enhanced_variants::{
125 EnhancedVariantParser, VariantDefinition, VariantType, CustomVariant as EnhancedCustomVariant,
126 VariantCombination, ParsedVariant, VariantParseResult, VariantMetadata
127};
128
129pub fn generate_css_file(output_path: &str, classes: Option<&ClassSet>) -> Result<()> {
162 let mut generator = CssGenerator::new();
163
164 if let Some(class_set) = classes {
166 for class in &class_set.classes {
168 generator.add_class(class)?;
169 }
170
171 for (breakpoint, responsive_classes) in &class_set.responsive {
173 for class in responsive_classes {
174 generator.add_responsive_class(*breakpoint, class)?;
175 }
176 }
177
178 for (_condition, conditional_classes) in &class_set.conditional {
180 for class in conditional_classes {
181 generator.add_class(class)?;
184 }
185 }
186 } else {
187 let config = CssGenerationConfig::default();
189 generator.generate_comprehensive_css(&config)?;
190 }
191
192 let css = generator.generate_css();
194
195 if let Some(parent) = std::path::Path::new(output_path).parent() {
197 std::fs::create_dir_all(parent)?;
198 }
199
200 std::fs::write(output_path, css)?;
202
203 println!("β
CSS generated successfully at {}", output_path);
204 println!("π Generated {} CSS rules", generator.rule_count());
205
206 Ok(())
207}
208
209pub fn generate_comprehensive_css(output_path: &str, config: &CssGenerationConfig) -> Result<()> {
236 let mut generator = CssGenerator::new();
237
238 let css = generator.generate_comprehensive_css(config)?;
240
241 if let Some(parent) = std::path::Path::new(output_path).parent() {
243 std::fs::create_dir_all(parent)?;
244 }
245
246 std::fs::write(output_path, css)?;
248
249 println!("β
Comprehensive CSS generated successfully at {}", output_path);
250 println!("π Generated {} CSS rules", generator.rule_count());
251
252 Ok(())
253}
254
255#[cfg(test)]
256mod tests {
257 mod sync_api_tests;
258 use super::*;
261
262 #[test]
263 fn test_version_constant() {
264 assert!(!VERSION.is_empty());
265 assert!(VERSION.chars().any(|c| c.is_ascii_digit()));
266 }
267
268 #[test]
269 fn test_defaults() {
270 assert_eq!(defaults::DEFAULT_THEME, "default");
271 assert_eq!(defaults::DEFAULT_BREAKPOINT, Breakpoint::Base);
272 assert_eq!(defaults::default_color(), Color::Blue);
273 }
274}
275
276pub struct TailwindBuilder {
278 source_paths: Vec<std::path::PathBuf>,
279 output_path: Option<std::path::PathBuf>,
280 config_path: Option<std::path::PathBuf>,
281 tree_shaking: bool,
282 minification: bool,
283 source_maps: bool,
284}
285
286impl Default for TailwindBuilder {
287 fn default() -> Self {
288 Self::new()
289 }
290}
291
292impl TailwindBuilder {
293 pub fn new() -> Self {
294 Self {
295 source_paths: Vec::new(),
296 output_path: None,
297 config_path: None,
298 tree_shaking: false,
299 minification: false,
300 source_maps: false,
301 }
302 }
303
304 pub fn scan_source(mut self, path: &std::path::Path) -> Self {
305 self.source_paths.push(path.to_path_buf());
306 self
307 }
308
309 pub fn output_css(mut self, path: &std::path::Path) -> Self {
310 self.output_path = Some(path.to_path_buf());
311 self
312 }
313
314 pub fn config_file(mut self, path: &std::path::Path) -> Self {
315 self.config_path = Some(path.to_path_buf());
316 self
317 }
318
319 pub fn enable_tree_shaking(mut self) -> Self {
320 self.tree_shaking = true;
321 self
322 }
323
324 pub fn enable_minification(mut self) -> Self {
325 self.minification = true;
326 self
327 }
328
329 pub fn enable_source_maps(mut self) -> Self {
330 self.source_maps = true;
331 self
332 }
333
334 pub fn build(self) -> Result<()> {
335 let mut generator = CssGenerator::new();
337
338 if !self.source_paths.is_empty() {
340 for path in &self.source_paths {
341 if path.is_file() {
342 self.scan_file_for_classes(path, &mut generator)?;
343 } else if path.is_dir() {
344 self.scan_directory_for_classes(path, &mut generator)?;
345 }
346 }
347 } else {
348 generator.add_class("p-4")?;
350 generator.add_class("bg-blue-500")?;
351 generator.add_class("text-white")?;
352 generator.add_class("rounded-md")?;
353 }
354
355 let css = if self.minification {
357 generator.generate_minified_css()
358 } else {
359 generator.generate_css()
360 };
361
362 let output_path = self.output_path
364 .unwrap_or_else(|| std::path::PathBuf::from("dist/styles.css"));
365
366 if let Some(parent) = output_path.parent() {
368 std::fs::create_dir_all(parent)?;
369 }
370
371 std::fs::write(&output_path, css)?;
373
374 println!("β
CSS generated successfully at {}", output_path.display());
375 println!("π Generated {} CSS rules", generator.rule_count());
376
377 if self.tree_shaking {
378 println!("π³ Tree shaking enabled");
379 }
380
381 if self.minification {
382 println!("ποΈ Minification enabled");
383 }
384
385 if self.source_maps {
386 println!("πΊοΈ Source maps enabled");
387 }
388
389 Ok(())
390 }
391
392 fn scan_file_for_classes(&self, path: &std::path::Path, generator: &mut CssGenerator) -> Result<()> {
394 let content = std::fs::read_to_string(path)?;
395
396 let class_pattern = regex::Regex::new(r#"class\s*=\s*["']([^"']+)["']"#)?;
398
399 for cap in class_pattern.captures_iter(&content) {
400 if let Some(class_attr) = cap.get(1) {
401 let classes = class_attr.as_str();
402 for class in classes.split_whitespace() {
403 if !class.is_empty() {
404 let _ = generator.add_class(class);
405 }
406 }
407 }
408 }
409
410 Ok(())
411 }
412
413 fn scan_directory_for_classes(&self, dir: &std::path::Path, generator: &mut CssGenerator) -> Result<()> {
415 for entry in std::fs::read_dir(dir)? {
416 let entry = entry?;
417 let path = entry.path();
418
419 if path.is_file() {
420 if let Some(ext) = path.extension() {
421 if ext == "rs" || ext == "html" || ext == "js" || ext == "ts" || ext == "jsx" || ext == "tsx" {
422 self.scan_file_for_classes(&path, generator)?;
423 }
424 }
425 } else if path.is_dir() {
426 self.scan_directory_for_classes(&path, generator)?;
427 }
428 }
429
430 Ok(())
431 }
432}
433
434
435pub const VERSION: &str = env!("CARGO_PKG_VERSION");
437
438pub mod defaults {
440 use super::*;
441
442 pub const DEFAULT_THEME: &str = "default";
443 pub const DEFAULT_BREAKPOINT: Breakpoint = Breakpoint::Base;
444 pub const DEFAULT_SPACING: Spacing = Spacing::Rem(1.0);
445
446 pub fn default_color() -> Color {
447 Color::Blue
448 }
449}
450