use lightningcss::{
stylesheet::{MinifyOptions, ParserOptions, StyleSheet},
targets::{Browsers, Targets},
};
use std::{fs, path::Path};
use crate::{
buffer::add_message,
core::{CssOptimizer, GrimoireCssError},
};
pub struct LightningCssOptimizer {
targets: Targets,
printer_minify: bool,
}
impl LightningCssOptimizer {
fn from_content(
browserslist_content: &str,
printer_minify: bool,
) -> Result<Self, GrimoireCssError> {
let browsers = Browsers::from_browserslist(browserslist_content.lines()).map_err(|e| {
GrimoireCssError::InvalidInput(format!("Failed to parse browserslist: {e}"))
})?;
Ok(Self {
targets: Targets {
browsers,
include: Default::default(),
exclude: Default::default(),
},
printer_minify,
})
}
pub fn new(current_dir: &Path) -> Result<Self, GrimoireCssError> {
let browserslist_config_path = current_dir.join(".browserslistrc");
if !browserslist_config_path.exists() {
fs::write(&browserslist_config_path, "defaults")
.expect("Failed to create '.browserslistrc' with defaults");
add_message("Created missing '.browserslistrc' file with 'defaults'".to_string());
}
let content = fs::read_to_string(&browserslist_config_path)
.expect("Failed to read '.browserslistrc' file");
Self::from_content(&content, true)
}
pub fn new_from(browserslist_content: &str) -> Result<Self, GrimoireCssError> {
Self::from_content(browserslist_content, true)
}
pub fn new_from_with_printer_minify(
browserslist_content: &str,
printer_minify: bool,
) -> Result<Self, GrimoireCssError> {
Self::from_content(browserslist_content, printer_minify)
}
}
impl CssOptimizer for LightningCssOptimizer {
fn optimize(&self, raw_css: &str) -> Result<String, GrimoireCssError> {
let mut stylesheet = StyleSheet::parse(raw_css, ParserOptions::default()).map_err(|e| {
GrimoireCssError::OptimizationError(format!("Failed to parse CSS: {e}"))
})?;
stylesheet
.minify(MinifyOptions {
targets: self.targets,
unused_symbols: Default::default(),
})
.map_err(|e| {
GrimoireCssError::OptimizationError(format!("Failed to minify CSS: {e}"))
})?;
stylesheet
.to_css(lightningcss::printer::PrinterOptions {
minify: self.printer_minify,
..Default::default()
})
.map(|res| res.code)
.map_err(|e| {
GrimoireCssError::OptimizationError(format!("Failed to generate CSS: {e}"))
})
}
fn validate(&self, raw_css: &str) -> Result<(), GrimoireCssError> {
StyleSheet::parse(raw_css, ParserOptions::default())
.map(|_| ())
.map_err(|e| GrimoireCssError::OptimizationError(format!("Failed to parse CSS: {e}")))
}
}