v0.24.7
This commit is contained in:
1 parent
5e23e9af02
commit
3883a21bc4
56 files changed
+1640
-403
No files matched your search
+32
-13
@@ -1,5 +1,13 @@
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum RawElement {
|
||||
Script,
|
||||
Style,
|
||||
Textarea,
|
||||
Pre,
|
||||
}
|
||||
|
||||
/// Conservative HTML minification.
|
||||
///
|
||||
/// HTML whitespace can be semantically significant, especially between inline
|
||||
@@ -11,13 +19,15 @@ pub fn minify(body: &[u8]) -> Result<Vec<u8>> {
|
||||
let bytes = input.as_bytes();
|
||||
let mut out = String::with_capacity(input.len());
|
||||
let mut cursor = 0usize;
|
||||
let mut raw_element: Option<String> = None;
|
||||
let mut raw_element: Option<RawElement> = None;
|
||||
|
||||
while cursor < bytes.len() {
|
||||
if bytes[cursor] == b'<' {
|
||||
if raw_element.is_none() && starts_with_ascii_ci(bytes, cursor, b"<!--[if") {
|
||||
let Some(end) = find_bytes(bytes, cursor + 4, b"-->") else {
|
||||
return Ok(body.to_vec());
|
||||
out.clear();
|
||||
out.push_str(input);
|
||||
return Ok(out.into_bytes());
|
||||
};
|
||||
let end = end + 3;
|
||||
out.push_str(&input[cursor..end]);
|
||||
@@ -26,7 +36,9 @@ pub fn minify(body: &[u8]) -> Result<Vec<u8>> {
|
||||
}
|
||||
if raw_element.is_none() && bytes[cursor..].starts_with(b"<!--") {
|
||||
let Some(end) = find_bytes(bytes, cursor + 4, b"-->") else {
|
||||
return Ok(body.to_vec());
|
||||
out.clear();
|
||||
out.push_str(input);
|
||||
return Ok(out.into_bytes());
|
||||
};
|
||||
cursor = end + 3;
|
||||
continue;
|
||||
@@ -35,15 +47,12 @@ pub fn minify(body: &[u8]) -> Result<Vec<u8>> {
|
||||
if let Some(end) = find_tag_end(bytes, cursor + 1) {
|
||||
let tag = &input[cursor..=end];
|
||||
out.push_str(tag);
|
||||
if let Some((name, closing, self_closing)) = tag_name(tag) {
|
||||
if let Some((name, closing, self_closing)) = raw_tag(tag) {
|
||||
if closing {
|
||||
if raw_element.as_deref() == Some(name.as_str()) {
|
||||
if raw_element == Some(name) {
|
||||
raw_element = None;
|
||||
}
|
||||
} else if !self_closing
|
||||
&& raw_element.is_none()
|
||||
&& matches!(name.as_str(), "script" | "style" | "textarea" | "pre")
|
||||
{
|
||||
} else if !self_closing && raw_element.is_none() {
|
||||
raw_element = Some(name);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +100,7 @@ fn find_tag_end(bytes: &[u8], mut cursor: usize) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
fn tag_name(tag: &str) -> Option<(String, bool, bool)> {
|
||||
fn raw_tag(tag: &str) -> Option<(RawElement, bool, bool)> {
|
||||
let inner = tag.strip_prefix('<')?.strip_suffix('>')?.trim();
|
||||
if inner.starts_with('!') || inner.starts_with('?') {
|
||||
return None;
|
||||
@@ -101,9 +110,19 @@ fn tag_name(tag: &str) -> Option<(String, bool, bool)> {
|
||||
let self_closing = inner.ends_with('/');
|
||||
let name = inner
|
||||
.split(|ch: char| ch.is_ascii_whitespace() || ch == '/' || ch == '>')
|
||||
.next()?
|
||||
.to_ascii_lowercase();
|
||||
(!name.is_empty()).then_some((name, closing, self_closing))
|
||||
.next()?;
|
||||
let name = if name.eq_ignore_ascii_case("script") {
|
||||
RawElement::Script
|
||||
} else if name.eq_ignore_ascii_case("style") {
|
||||
RawElement::Style
|
||||
} else if name.eq_ignore_ascii_case("textarea") {
|
||||
RawElement::Textarea
|
||||
} else if name.eq_ignore_ascii_case("pre") {
|
||||
RawElement::Pre
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
Some((name, closing, self_closing))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in new issue
Block a user