1pub mod arbitrary;
61pub mod ast_parser;
62pub mod class_scanner;
63pub mod classes;
64pub mod color;
65pub mod config;
66pub mod css_generator;
67pub mod css_optimizer;
68pub mod custom_variant;
69pub mod dark_mode;
70pub mod error;
71pub mod enhanced_variants;
73pub mod performance;
74pub mod plugin_system;
75#[cfg(feature = "postcss")]
76pub mod postcss_integration;
77pub mod responsive;
78
79pub mod theme;
80pub mod theme_new;
81pub mod tree_shaker;
82pub mod utilities;
83pub mod utils;
84pub mod validation;
85
86#[cfg(test)]
87mod api_stability;
88
89pub mod api_contracts;
91
92pub use arbitrary::{ArbitraryValue, ArbitraryValueError, ArbitraryValueUtilities};
94pub use ast_parser::AstParser;
95pub use class_scanner::{ClassScanner, ScanConfig, ScanResults, ScanStats};
96pub use classes::{ClassBuilder, ClassSet};
97pub use color::Color;
98pub use config::parser::ConfigParser;
99pub use config::{BuildConfig, TailwindConfig};
100pub use css_generator::{CssGenerationConfig, CssGenerator, CssProperty, CssRule};
102
103pub use css_generator::parsers::{
105 SpacingParser, AdvancedSpacingParser, ColorParser, AdvancedColorParser,
106 TypographyParser, LayoutParser, PositioningParser, SizingParser,
107 FlexboxParser, GridParser, AdvancedGridParser, BorderParser, AdvancedBorderParser,
108 BorderUtilitiesParser, RingParser, ShadowParser, EffectsParser, EffectsUtilitiesParser,
109 TransformParser, FractionalTransformsParser, AnimationParser, TransitionParser,
110 TransitionPropertiesParser, InteractiveParser, SvgParser, ProseParser, DivideParser,
111 GradientParser, ObjectFitParser, ArbitraryParser, DataAttributeParser,
112 BackgroundPropertiesParser, AspectRatioParser, ColumnsParser, BreakControlParser,
113 BoxUtilitiesParser, LayoutUtilitiesParser, OverflowParser, OverscrollParser,
114 PositionParser, InsetParser, VisibilityParser, ZIndexParser, FlexBasisParser,
115 FlexDirectionParser, FlexWrapParser, FlexParser, FlexGrowParser, FlexShrinkParser,
116 OrderParser, GridTemplateColumnsParser, GridColumnParser, GridTemplateRowsParser,
117 GridRowParser, GridAutoFlowParser, GridAutoColumnsParser, GridAutoRowsParser,
118 GapParser, JustifyContentParser, JustifyItemsParser, JustifySelfParser,
119 AlignContentParser, AlignItemsParser, AlignSelfParser, PlaceContentParser,
120 PlaceItemsParser, PlaceSelfParser, BackgroundParser, FilterUtilitiesParser,
121 BackdropFilterUtilitiesParser, AccessibilityParser, TableParser, MaskUtilitiesParser,
122 AccentColorParser, UtilityParser, ParserCategory
123};
124pub use css_optimizer::{OptimizationConfig, OptimizationResults, OptimizationStats};
125pub use custom_variant::{CustomVariant, CustomVariantManager, CustomVariantType};
126pub use dark_mode::{DarkModeVariant, DarkModeVariantError, DarkModeVariantUtilities};
127pub use error::{Result, TailwindError};
128pub use performance::{CacheStats, ClassCache, OptimizationLevel, PerformanceOptimizer};
130pub use plugin_system::{Plugin, PluginContext, PluginHook, PluginRegistry};
131pub use responsive::{
132 AlignItems, Breakpoint, FlexDirection, FlexWrap, JustifyContent, Responsive, ResponsiveBuilder,
133 ResponsiveFlex, ResponsiveGrid, ResponsiveValue, State,
134};
135pub use theme::{BorderRadius, BoxShadow, Spacing, Theme, ThemeValue};
136pub use theme_new::{
137 AnimationScale, BorderScale, FontFamily, FontSizeScale, FontWeightScale, LetterSpacingScale,
138 LineHeightScale, ShadowScale, SpacingScale, SpacingSize, Theme as NewTheme, ThemePreset,
139 ThemeVariant, ThemedComponent, TypographyScale,
140};
141pub use tree_shaker::{TreeShakeConfig, TreeShakeResults, TreeShakeStats, TreeShaker};
142pub use utilities::*;
143pub use validation::*;
144
145pub use enhanced_variants::{
146 CustomVariant as EnhancedCustomVariant, EnhancedVariantParser, ParsedVariant,
147 VariantCombination, VariantDefinition, VariantMetadata, VariantParseResult, VariantType,
148};
149
150#[cfg(feature = "postcss")]
151pub use postcss_integration::{EnhancedCssGenerator, EnhancedCssResult, PostCSSIntegrationConfig};
152
153pub fn generate_css_file(output_path: &str, classes: Option<&ClassSet>) -> Result<()> {
186 let mut generator = CssGenerator::new();
187
188 if let Some(class_set) = classes {
190 for class in &class_set.classes {
192 generator.add_class(class)?;
193 }
194
195 for (breakpoint, responsive_classes) in &class_set.responsive {
197 for class in responsive_classes {
198 generator.add_responsive_class(*breakpoint, class)?;
199 }
200 }
201
202 for conditional_classes in class_set.conditional.values() {
204 for class in conditional_classes {
205 generator.add_class(class)?;
208 }
209 }
210 } else {
211 let config = CssGenerationConfig::default();
213 generator.generate_comprehensive_css(&config)?;
214 }
215
216 let css = generator.generate_css();
218
219 if let Some(parent) = std::path::Path::new(output_path).parent() {
221 std::fs::create_dir_all(parent)?;
222 }
223
224 std::fs::write(output_path, css)?;
226
227 println!("β
CSS generated successfully at {}", output_path);
228 println!("π Generated {} CSS rules", generator.rule_count());
229
230 Ok(())
231}
232
233pub fn generate_comprehensive_css(output_path: &str, config: &CssGenerationConfig) -> Result<()> {
260 let mut generator = CssGenerator::new();
261
262 let css = generator.generate_comprehensive_css(config)?;
264
265 if let Some(parent) = std::path::Path::new(output_path).parent() {
267 std::fs::create_dir_all(parent)?;
268 }
269
270 std::fs::write(output_path, css)?;
272
273 println!(
274 "β
Comprehensive CSS generated successfully at {}",
275 output_path
276 );
277 println!("π Generated {} CSS rules", generator.rule_count());
278
279 Ok(())
280}
281
282#[cfg(test)]
283mod tests {
284 mod sync_api_tests;
285 use super::*;
288
289 #[test]
290 fn test_version_constant() {
291 assert!(!VERSION.is_empty());
292 assert!(VERSION.chars().any(|c| c.is_ascii_digit()));
293 }
294
295 #[test]
296 fn test_defaults() {
297 assert_eq!(defaults::DEFAULT_THEME, "default");
298 assert_eq!(defaults::DEFAULT_BREAKPOINT, Breakpoint::Base);
299 assert_eq!(defaults::default_color(), Color::Blue);
300 }
301}
302
303pub struct TailwindBuilder {
305 source_paths: Vec<std::path::PathBuf>,
306 output_path: Option<std::path::PathBuf>,
307 config_path: Option<std::path::PathBuf>,
308 tree_shaking: bool,
309 minification: bool,
310 source_maps: bool,
311}
312
313impl Default for TailwindBuilder {
314 fn default() -> Self {
315 Self::new()
316 }
317}
318
319impl TailwindBuilder {
320 pub fn new() -> Self {
321 Self {
322 source_paths: Vec::new(),
323 output_path: None,
324 config_path: None,
325 tree_shaking: false,
326 minification: false,
327 source_maps: false,
328 }
329 }
330
331 pub fn scan_source(mut self, path: &std::path::Path) -> Self {
332 self.source_paths.push(path.to_path_buf());
333 self
334 }
335
336 pub fn output_css(mut self, path: &std::path::Path) -> Self {
337 self.output_path = Some(path.to_path_buf());
338 self
339 }
340
341 pub fn config_file(mut self, path: &std::path::Path) -> Self {
342 self.config_path = Some(path.to_path_buf());
343 self
344 }
345
346 pub fn enable_tree_shaking(mut self) -> Self {
347 self.tree_shaking = true;
348 self
349 }
350
351 pub fn enable_minification(mut self) -> Self {
352 self.minification = true;
353 self
354 }
355
356 pub fn enable_source_maps(mut self) -> Self {
357 self.source_maps = true;
358 self
359 }
360
361 pub fn build(self) -> Result<()> {
362 let mut generator = CssGenerator::new();
364
365 if !self.source_paths.is_empty() {
367 for path in &self.source_paths {
368 if path.is_file() {
369 self.scan_file_for_classes(path, &mut generator)?;
370 } else if path.is_dir() {
371 self.scan_directory_for_classes(path, &mut generator)?;
372 }
373 }
374 } else {
375 generator.add_class("p-4")?;
377 generator.add_class("bg-blue-500")?;
378 generator.add_class("text-white")?;
379 generator.add_class("rounded-md")?;
380 }
381
382 let css = if self.minification {
384 generator.generate_minified_css()
385 } else {
386 generator.generate_css()
387 };
388
389 let output_path = self
391 .output_path
392 .unwrap_or_else(|| std::path::PathBuf::from("dist/styles.css"));
393
394 if let Some(parent) = output_path.parent() {
396 std::fs::create_dir_all(parent)?;
397 }
398
399 std::fs::write(&output_path, css)?;
401
402 println!("β
CSS generated successfully at {}", output_path.display());
403 println!("π Generated {} CSS rules", generator.rule_count());
404
405 if self.tree_shaking {
406 println!("π³ Tree shaking enabled");
407 }
408
409 if self.minification {
410 println!("ποΈ Minification enabled");
411 }
412
413 if self.source_maps {
414 println!("πΊοΈ Source maps enabled");
415 }
416
417 Ok(())
418 }
419
420 fn scan_file_for_classes(
422 &self,
423 path: &std::path::Path,
424 generator: &mut CssGenerator,
425 ) -> Result<()> {
426 let content = std::fs::read_to_string(path)?;
427
428 let class_pattern = regex::Regex::new(r#"class\s*=\s*["']([^"']+)["']"#)?;
430
431 for cap in class_pattern.captures_iter(&content) {
432 if let Some(class_attr) = cap.get(1) {
433 let classes = class_attr.as_str();
434 for class in classes.split_whitespace() {
435 if !class.is_empty() {
436 let _ = generator.add_class(class);
437 }
438 }
439 }
440 }
441
442 Ok(())
443 }
444
445 fn scan_directory_for_classes(
447 &self,
448 dir: &std::path::Path,
449 generator: &mut CssGenerator,
450 ) -> Result<()> {
451 for entry in std::fs::read_dir(dir)? {
452 let entry = entry?;
453 let path = entry.path();
454
455 if path.is_file() {
456 if let Some(ext) = path.extension() {
457 if ext == "rs"
458 || ext == "html"
459 || ext == "js"
460 || ext == "ts"
461 || ext == "jsx"
462 || ext == "tsx"
463 {
464 self.scan_file_for_classes(&path, generator)?;
465 }
466 }
467 } else if path.is_dir() {
468 self.scan_directory_for_classes(&path, generator)?;
469 }
470 }
471
472 Ok(())
473 }
474}
475
476pub const VERSION: &str = env!("CARGO_PKG_VERSION");
478
479pub mod defaults {
481 use super::*;
482
483 pub const DEFAULT_THEME: &str = "default";
484 pub const DEFAULT_BREAKPOINT: Breakpoint = Breakpoint::Base;
485 pub const DEFAULT_SPACING: Spacing = Spacing::Rem(1.0);
486
487 pub fn default_color() -> Color {
488 Color::Blue
489 }
490}