tailwind_css/systems/builder/
mod.rs

1use std::{collections::BTreeSet, fmt::Debug};
2
3use crate::{systems::instruction::TailwindInstruction, *};
4
5pub use self::base62::{Base62, BASE62};
6
7mod base62;
8mod methods;
9mod setter;
10
11///
12#[derive(Debug)]
13pub struct TailwindBuilder {
14    ///
15    pub preflight: PreflightSystem,
16    /// All dynamic color properties
17    ///
18    /// Only determined when packing
19    pub palettes: PaletteSystem,
20    /// All dynamic break points
21    ///
22    /// Only determined when packing
23    pub screens: BreakPointSystem,
24    /// All dynamically registered font properties
25    ///
26    /// Only determined when packing
27    pub fonts: FontSystem,
28    /// All dynamically registered effect properties
29    ///
30    /// Only determined when packing
31    pub effects: EffectSystem,
32    pub(crate) objects: BTreeSet<CssInstance>,
33    pub(crate) bundles: BTreeSet<CssBundle>,
34}
35
36impl TailwindBuilder {
37    /// ## Trace mode
38    ///
39    ///
40    /// # Returns
41    /// **Not all instructions can be inline, if not, it will fall back to trace mode**
42    ///
43    /// - Anonymous style sheets, which can be placed inside `style` tags
44    ///
45    /// ## Example
46    /// - input
47    /// ```html
48    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
49    /// ```
50    /// - output
51    /// ```html
52    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
53    /// <style> {} </style>
54    /// ```
55    #[inline]
56    pub fn trace(&mut self, style: &str, obfuscate: bool) -> Result<String> {
57        let out = try_trace(self, style, obfuscate)?;
58        Ok(out.as_traced())
59    }
60    /// ## Inline mode
61    ///
62    ///
63    /// # Returns
64    /// **Not all instructions can be inline, if not, it will fall back to trace mode**
65    ///
66    /// - Anonymous style sheets, which can be placed inside `style` tags
67    ///
68    /// ## Example
69    /// - input
70    /// ```html
71    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
72    /// ```
73    /// - output
74    /// ```html
75    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
76    /// <style> {} </style>
77    /// ```
78    #[inline]
79    pub fn inline(&mut self, style: &str) -> Result<(String, String)> {
80        let out = try_inline(self, style, CssInlineMode::Inline)?;
81        Ok(out.as_inlined())
82    }
83    /// ## Inline mode
84    ///
85    ///
86    /// # Returns
87    /// **Not all instructions can be inline, if not, it will fall back to trace mode**
88    ///
89    /// - Anonymous style sheets, which can be placed inside `style` tags
90    ///
91    /// ## Example
92    /// - input
93    /// ```html
94    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
95    /// ```
96    /// - output
97    /// ```html
98    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
99    /// <style> {} </style>
100    /// ```
101    #[inline]
102    pub fn scope(&mut self, style: &str) -> Result<(String, String)> {
103        let out = try_inline(self, style, CssInlineMode::Scoped)?;
104        Ok(out.as_scope())
105    }
106    /// ## Inline mode
107    ///
108    ///
109    /// # Returns
110    /// **Not all instructions can be inline, if not, it will fall back to trace mode**
111    ///
112    /// - Anonymous style sheets, which can be placed inside `style` tags
113    ///
114    /// ## Example
115    /// - input
116    /// ```html
117    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
118    /// ```
119    /// - output
120    /// ```html
121    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
122    /// <style> {} </style>
123    /// ```
124    #[inline]
125    pub fn data_key(&mut self, style: &str) -> Result<(String, String)> {
126        let out = try_inline(self, style, CssInlineMode::DataKey)?;
127        Ok(out.as_dataset())
128    }
129    /// ## Inline mode
130    ///
131    ///
132    /// # Returns
133    /// **Not all instructions can be inline, if not, it will fall back to trace mode**
134    ///
135    /// - Anonymous style sheets, which can be placed inside `style` tags
136    ///
137    /// ## Example
138    /// - input
139    /// ```html
140    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
141    /// ```
142    /// - output
143    /// ```html
144    /// <div class="p-auto px-px pt-2 pb-2">Test</div>
145    /// <style> {} </style>
146    /// ```
147    #[inline]
148    pub fn data_value(&mut self, style: &str) -> Result<(String, String)> {
149        let out = try_inline(self, style, CssInlineMode::DataValue)?;
150        Ok(out.as_dataset())
151    }
152    /// Bundle all used stylesheets
153    pub fn bundle(&self) -> Result<String> {
154        let mut out = String::with_capacity(1024 * 10);
155        if !self.preflight.disable {
156            out.push_str(&self.preflight.to_string());
157        }
158        for item in &self.objects {
159            item.write_css(&mut out)?;
160        }
161        for item in &self.bundles {
162            item.write_css(&mut out)?;
163        }
164        Ok(out)
165    }
166}
167
168fn parse_tailwind(input: &str) -> Result<Vec<TailwindInstruction>> {
169    let styles = tailwind_ast::parse_tailwind(input)?;
170    Ok(styles.into_iter().map(TailwindInstruction::from).collect())
171}
172
173fn try_trace(tw: &mut TailwindBuilder, style: &str, obfuscate: bool) -> Result<CssBundle> {
174    let parsed = parse_tailwind(style)?;
175    let mut out = CssBundle::default();
176    for item in parsed {
177        let i = CssInstance::new(&*item.get_instance()?, tw, obfuscate);
178        out.add_trace(&i);
179        tw.objects.insert(i);
180    }
181    Ok(out)
182}
183
184fn try_inline(tw: &mut TailwindBuilder, style: &str, mode: CssInlineMode) -> Result<CssBundle> {
185    let parsed = parse_tailwind(style)?;
186    let mut out = CssBundle::default();
187    for item in parsed {
188        let i = CssInstance::new(&*item.get_instance()?, tw, true);
189        match &i.inlineable {
190            true => out.add_inline(i),
191            false => {
192                out.add_trace(&i);
193                tw.objects.insert(i);
194            },
195        };
196    }
197    out.set_mode(mode);
198    tw.bundles.insert(out.to_owned());
199    Ok(out)
200}