use fancy_regex::Regex;
use std::sync::OnceLock;
static HTML_TAG_RE: OnceLock<Regex> = OnceLock::new();
fn html_tag_re() -> &'static Regex {
HTML_TAG_RE.get_or_init(|| {
Regex::new(r"(?s)(</?(?:!(?!--))?)([^\s>!/\[]+)((?:\s[^>]*)?)(\s*/?>)").unwrap()
})
}
pub fn compress(html: &str) -> String {
let html = html.replace("\r\n", "\n").replace('\r', "\n");
html_tag_re()
.replace_all(&html, |caps: &fancy_regex::Captures<'_>| {
let bracket = &caps[1];
let tag = caps[2].to_lowercase();
let attrs_raw = &caps[3];
let close = caps[4].trim_start();
if attrs_raw.contains("{%") {
return caps[0].to_string();
}
if attrs_raw.contains("</style")
|| attrs_raw.contains("</script")
|| attrs_raw.contains("</pre")
{
return caps[0].to_string();
}
let attrs: String = if attrs_raw.trim().is_empty() {
String::new()
} else {
let joined = attrs_raw
.split('\n')
.flat_map(|l| l.split('\r'))
.map(str::trim)
.filter(|s| !s.is_empty())
.collect::<Vec<_>>()
.join(" ");
format!(" {}", joined)
};
let close_out = if close == "/>" {
" />".to_string()
} else {
close.to_string()
};
format!("{}{}{}{}", bracket, tag, attrs, close_out)
})
.into_owned()
}