diff --git a/src/lib.rs b/src/lib.rs index 651c68c..582f809 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ use crate::cfg::Cfg; use crate::minify::content::minify_content; -use crate::parse::Code; use crate::parse::content::parse_content; -use crate::spec::tag::EMPTY_TAG_NAME; +use crate::parse::Code; use crate::spec::tag::ns::Namespace; +use crate::spec::tag::EMPTY_TAG_NAME; mod ast; mod cfg; @@ -37,7 +37,13 @@ mod tests; /// ``` pub fn minify(src: &[u8], cfg: &Cfg) -> Vec { let mut code = Code::new(src); - let parsed = parse_content(cfg, &mut code, Namespace::Html, EMPTY_TAG_NAME, EMPTY_TAG_NAME); + let parsed = parse_content( + cfg, + &mut code, + Namespace::Html, + EMPTY_TAG_NAME, + EMPTY_TAG_NAME, + ); let mut out = Vec::with_capacity(src.len()); minify_content(cfg, &mut out, EMPTY_TAG_NAME, &parsed.children); out diff --git a/src/minify/attr.rs b/src/minify/attr.rs index 39a080a..bd2d944 100644 --- a/src/minify/attr.rs +++ b/src/minify/attr.rs @@ -13,7 +13,7 @@ fn build_double_quoted_replacer() -> Replacer { for c in "0123456789;".bytes() { patterns.push(vec![b'"', c]); replacements.push(vec![b'&', b'#', b'3', b'4', b';', c]); - }; + } patterns.push(b"\"".to_vec()); replacements.push(b""".to_vec()); @@ -35,7 +35,7 @@ fn build_single_quoted_replacer() -> Replacer { for c in "0123456789;".bytes() { patterns.push(vec![b'\'', c]); replacements.push(vec![b'&', b'#', b'3', b'9', b';', c]); - }; + } patterns.push(b"'".to_vec()); replacements.push(b"'".to_vec()); @@ -71,12 +71,12 @@ fn build_unquoted_replacer() -> Replacer { ent.push(c); ent }); - }; - }; + } + } for &(ws, rep) in WS { patterns.push(vec![ws]); replacements.push(rep.to_vec()); - }; + } // Replace all `>` with `>`, unless the chevron is followed by a semicolon, // in which case add a semicolon to the encoded entity. @@ -148,11 +148,7 @@ pub fn minify_attr_val(val: &[u8]) -> Vec { }, _ => b"", }; - let start = if !first_char_encoded.is_empty() { - 1 - } else { - 0 - }; + let start = if !first_char_encoded.is_empty() { 1 } else { 0 }; MinifiedVal { prefix: b"", data: res, diff --git a/src/minify/bang.rs b/src/minify/bang.rs index b7ca19b..2f3c882 100644 --- a/src/minify/bang.rs +++ b/src/minify/bang.rs @@ -1,11 +1,6 @@ use crate::cfg::Cfg; -pub fn minify_bang( - cfg: &Cfg, - out: &mut Vec, - code: &[u8], - ended: bool, -) -> () { +pub fn minify_bang(cfg: &Cfg, out: &mut Vec, code: &[u8], ended: bool) -> () { if !cfg.remove_bangs { out.extend_from_slice(b", - code: &[u8], - ended: bool, -) -> () { +pub fn minify_comment(cfg: &Cfg, out: &mut Vec, code: &[u8], ended: bool) -> () { if !cfg.remove_comments { out.extend_from_slice(b""]); diff --git a/src/parse/content.rs b/src/parse/content.rs index ebb504f..77404cd 100644 --- a/src/parse/content.rs +++ b/src/parse/content.rs @@ -3,17 +3,17 @@ use lazy_static::lazy_static; use memchr::memrchr; use crate::ast::NodeData; -use crate::Cfg; use crate::parse::bang::parse_bang; -use crate::parse::Code; use crate::parse::comment::parse_comment; use crate::parse::content::ContentType::*; use crate::parse::element::{parse_element, parse_tag, peek_tag_name}; use crate::parse::instruction::parse_instruction; +use crate::parse::Code; use crate::spec::entity::decode::decode_entities; use crate::spec::tag::ns::Namespace; use crate::spec::tag::omission::{can_omit_as_before, can_omit_as_last_node}; use crate::spec::tag::void::VOID_TAGS; +use crate::Cfg; #[derive(Copy, Clone, Eq, PartialEq)] enum ContentType { @@ -43,7 +43,8 @@ lazy_static! { } // Keep in sync with order of patterns in CONTENT_TYPE_PATTERN. -static CONTENT_TYPE_FROM_PATTERN: &'static [ContentType] = &[OpeningTag, ClosingTag, Instruction, Bang, Comment]; +static CONTENT_TYPE_FROM_PATTERN: &'static [ContentType] = + &[OpeningTag, ClosingTag, Instruction, Bang, Comment]; pub struct ParsedContent { pub children: Vec, @@ -51,7 +52,13 @@ pub struct ParsedContent { } // Use empty slice for `grandparent` or `parent` if none. -pub fn parse_content(cfg: &Cfg, code: &mut Code, ns: Namespace, grandparent: &[u8], parent: &[u8]) -> ParsedContent { +pub fn parse_content( + cfg: &Cfg, + code: &mut Code, + ns: Namespace, + grandparent: &[u8], + parent: &[u8], +) -> ParsedContent { // We assume the closing tag has been omitted until we see one explicitly before EOF (or it has been omitted as per the spec). let mut closing_tag_omitted = true; let mut nodes = Vec::::new(); @@ -80,7 +87,9 @@ pub fn parse_content(cfg: &Cfg, code: &mut Code, ns: Namespace, grandparent: &[u if name.is_empty() { // Malformed code, drop until and including next `>`. typ = MalformedLeftChevronSlash; - } else if grandparent == name.as_slice() && can_omit_as_last_node(grandparent, parent) { + } else if grandparent == name.as_slice() + && can_omit_as_last_node(grandparent, parent) + { // The upcoming closing tag implicitly closes the current element e.g. `(current position)`. // This DOESN'T handle when grandparent doesn't exist (represented by an empty slice). However, in that case it's irrelevant, as it would mean we would be at EOF, and our parser simply auto-closes everything anyway. (Normally we'd have to determine if `

Hello` is an error or allowed.) typ = OmittedClosingTag; @@ -119,7 +128,7 @@ pub fn parse_content(cfg: &Cfg, code: &mut Code, ns: Namespace, grandparent: &[u } ClosingTagForVoidElement => drop(parse_tag(code)), }; - }; + } debug_assert_eq!(text_len, 0); ParsedContent { children: nodes, diff --git a/src/parse/element.rs b/src/parse/element.rs index ba5fa52..8990bed 100644 --- a/src/parse/element.rs +++ b/src/parse/element.rs @@ -1,17 +1,20 @@ use std::collections::HashMap; use crate::ast::{ElementClosingTag, NodeData, ScriptOrStyleLang}; -use crate::Cfg; -use crate::gen::codepoints::{ATTR_QUOTE, DOUBLE_QUOTE, NOT_UNQUOTED_ATTR_VAL_CHAR, SINGLE_QUOTE, TAG_NAME_CHAR, WHITESPACE, WHITESPACE_OR_SLASH}; -use crate::parse::Code; +use crate::gen::codepoints::{ + ATTR_QUOTE, DOUBLE_QUOTE, NOT_UNQUOTED_ATTR_VAL_CHAR, SINGLE_QUOTE, TAG_NAME_CHAR, WHITESPACE, + WHITESPACE_OR_SLASH, +}; use crate::parse::content::{parse_content, ParsedContent}; use crate::parse::script::parse_script_content; use crate::parse::style::parse_style_content; use crate::parse::textarea::parse_textarea_content; +use crate::parse::Code; use crate::spec::entity::decode::decode_entities; use crate::spec::script::JAVASCRIPT_MIME_TYPES; use crate::spec::tag::ns::Namespace; use crate::spec::tag::void::VOID_TAGS; +use crate::Cfg; fn parse_tag_name(code: &mut Code) -> Vec { debug_assert!(code.str().starts_with(b"<")); @@ -66,7 +69,10 @@ pub fn parse_tag(code: &mut Code) -> ParsedTag { None => NOT_UNQUOTED_ATTR_VAL_CHAR, _ => unreachable!(), }; - let attr_value = decode_entities(code.slice_and_shift_while_not_in_lookup(attr_delim_pred), true); + let attr_value = decode_entities( + code.slice_and_shift_while_not_in_lookup(attr_delim_pred), + true, + ); if let Some(c) = attr_delim { // It might not be next if EOF (i.e. attribute value not closed). code.shift_if_next(c); @@ -74,7 +80,7 @@ pub fn parse_tag(code: &mut Code) -> ParsedTag { attr_value }; attributes.insert(attr_name, attr_value); - }; + } ParsedTag { attributes, name: elem_name, @@ -121,12 +127,14 @@ pub fn parse_element(cfg: &Cfg, code: &mut Code, ns: Namespace, parent: &[u8]) - } = match elem_name.as_slice() { // TODO to_vec call allocates every time? b"script" => match attributes.get(&b"type".to_vec()) { - Some(mime) if !JAVASCRIPT_MIME_TYPES.contains(mime.as_slice()) => parse_script_content(cfg, code, ScriptOrStyleLang::Data), + Some(mime) if !JAVASCRIPT_MIME_TYPES.contains(mime.as_slice()) => { + parse_script_content(cfg, code, ScriptOrStyleLang::Data) + } _ => parse_script_content(cfg, code, ScriptOrStyleLang::JS), }, b"style" => parse_style_content(cfg, code), b"textarea" => parse_textarea_content(cfg, code), - _ => parse_content(cfg, code, child_ns, parent, &elem_name) + _ => parse_content(cfg, code, child_ns, parent, &elem_name), }; if !closing_tag_omitted { diff --git a/src/parse/instruction.rs b/src/parse/instruction.rs index 6713a8c..c3ababd 100644 --- a/src/parse/instruction.rs +++ b/src/parse/instruction.rs @@ -2,8 +2,8 @@ use aho_corasick::AhoCorasick; use lazy_static::lazy_static; use crate::ast::NodeData; -use crate::Cfg; use crate::parse::Code; +use crate::Cfg; lazy_static! { static ref INSTRUCTION_END: AhoCorasick = AhoCorasick::new(&["?>"]); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 07d2435..5ce6223 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -19,10 +19,7 @@ pub struct Checkpoint(usize); impl<'c> Code<'c> { pub fn new(code: &[u8]) -> Code { - Code { - code, - next: 0, - } + Code { code, next: 0 } } pub fn str(&self) -> &[u8] { @@ -59,7 +56,12 @@ impl<'c> Code<'c> { } pub fn shift_if_next_seq(&mut self, seq: &'static [u8]) -> bool { - if self.code.get(self.next..self.next + seq.len()).filter(|&n| n == seq).is_some() { + if self + .code + .get(self.next..self.next + seq.len()) + .filter(|&n| n == seq) + .is_some() + { self.next += seq.len(); true } else { @@ -88,7 +90,7 @@ impl<'c> Code<'c> { Some(&c) if lookup[c] => len += 1, _ => break, }; - }; + } self.copy_and_shift(len) } @@ -99,7 +101,7 @@ impl<'c> Code<'c> { Some(&c) if !lookup[c] => len += 1, _ => break, }; - }; + } self.slice_and_shift(len) } @@ -118,7 +120,7 @@ impl<'c> Code<'c> { } _ => break, }; - }; + } last } diff --git a/src/parse/script.rs b/src/parse/script.rs index 972f185..6293b70 100644 --- a/src/parse/script.rs +++ b/src/parse/script.rs @@ -3,9 +3,9 @@ use aho_corasick::AhoCorasickBuilder; use lazy_static::lazy_static; use crate::ast::{NodeData, ScriptOrStyleLang}; -use crate::Cfg; -use crate::parse::Code; use crate::parse::content::ParsedContent; +use crate::parse::Code; +use crate::Cfg; lazy_static! { static ref END: AhoCorasick = AhoCorasickBuilder::new() @@ -20,6 +20,9 @@ pub fn parse_script_content(cfg: &Cfg, code: &mut Code, lang: ScriptOrStyleLang) }; ParsedContent { closing_tag_omitted, - children: vec![NodeData::ScriptOrStyleContent { code: code.copy_and_shift(len), lang }], + children: vec![NodeData::ScriptOrStyleContent { + code: code.copy_and_shift(len), + lang, + }], } } diff --git a/src/parse/style.rs b/src/parse/style.rs index c396418..0716dd3 100644 --- a/src/parse/style.rs +++ b/src/parse/style.rs @@ -3,9 +3,9 @@ use aho_corasick::AhoCorasickBuilder; use lazy_static::lazy_static; use crate::ast::{NodeData, ScriptOrStyleLang}; -use crate::Cfg; -use crate::parse::Code; use crate::parse::content::ParsedContent; +use crate::parse::Code; +use crate::Cfg; lazy_static! { static ref END: AhoCorasick = AhoCorasickBuilder::new() @@ -20,11 +20,9 @@ pub fn parse_style_content(cfg: &Cfg, code: &mut Code) -> ParsedContent { }; ParsedContent { closing_tag_omitted, - children: vec![ - NodeData::ScriptOrStyleContent { - code: code.copy_and_shift(len), - lang: ScriptOrStyleLang::CSS, - }, - ], + children: vec![NodeData::ScriptOrStyleContent { + code: code.copy_and_shift(len), + lang: ScriptOrStyleLang::CSS, + }], } } diff --git a/src/parse/textarea.rs b/src/parse/textarea.rs index dfe67e3..fb5273e 100644 --- a/src/parse/textarea.rs +++ b/src/parse/textarea.rs @@ -3,10 +3,10 @@ use aho_corasick::AhoCorasickBuilder; use lazy_static::lazy_static; use crate::ast::NodeData; -use crate::Cfg; -use crate::parse::Code; use crate::parse::content::ParsedContent; +use crate::parse::Code; use crate::spec::entity::decode::decode_entities; +use crate::Cfg; lazy_static! { static ref END: AhoCorasick = AhoCorasickBuilder::new() @@ -21,6 +21,8 @@ pub fn parse_textarea_content(cfg: &Cfg, code: &mut Code) -> ParsedContent { }; ParsedContent { closing_tag_omitted, - children: vec![NodeData::Text { value: decode_entities(code.slice_and_shift(len), false) }], + children: vec![NodeData::Text { + value: decode_entities(code.slice_and_shift(len), false), + }], } } diff --git a/src/pattern.rs b/src/pattern.rs index 5f20304..f7d89a5 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -46,7 +46,7 @@ impl TrieNode { if node.value.is_some() { break; }; - }; + } (node, pos) } @@ -65,7 +65,7 @@ impl TrieNode { Some(v) => value = Some(TrieNodeMatch::Found { len: pos, value: v }), None => {} }; - }; + } value.unwrap_or(TrieNodeMatch::NotFound { reached: pos }) } } @@ -77,7 +77,10 @@ pub struct Replacer { impl Replacer { pub fn new(searcher: AhoCorasick, replacements: Vec>) -> Replacer { - Replacer { searcher, replacements } + Replacer { + searcher, + replacements, + } } pub fn replace_all(&self, src: &[u8]) -> Vec { diff --git a/src/spec/entity/decode.rs b/src/spec/entity/decode.rs index 845b2df..d55030a 100644 --- a/src/spec/entity/decode.rs +++ b/src/spec/entity/decode.rs @@ -17,8 +17,10 @@ use std::char::from_u32; use memchr::memchr; -use crate::gen::codepoints::{ALPHANUMERIC_OR_EQUALS, DIGIT, HEX_DIGIT, Lookup, LOWER_HEX_ALPHA, UPPER_HEX_ALPHA}; -use crate::gen::entities::{ENTITY, EntityType}; +use crate::gen::codepoints::{ + Lookup, ALPHANUMERIC_OR_EQUALS, DIGIT, HEX_DIGIT, LOWER_HEX_ALPHA, UPPER_HEX_ALPHA, +}; +use crate::gen::entities::{EntityType, ENTITY}; use crate::pattern::TrieNodeMatch; enum Decoded { @@ -44,7 +46,7 @@ fn parse_numeric_entity( // Skip initial zeros. while code.get(read_next).filter(|c| **c == b'0').is_some() { read_next += 1; - }; + } // Browser will still continue to consume digits past max_digits. loop { match code.get(read_next) { @@ -56,7 +58,7 @@ fn parse_numeric_entity( } _ => break, }; - }; + } // Semicolon is required by spec but seems to be optional in actual browser behaviour. if let Some(b';') = code.get(read_next) { read_next += 1; @@ -79,7 +81,10 @@ fn parse_entity(code: &[u8], in_attr_val: bool) -> ParsedEntity { read_len: reached, decoded: Decoded::Ignored, }, - TrieNodeMatch::Found { len: match_len, value } => match value { + TrieNodeMatch::Found { + len: match_len, + value, + } => match value { EntityType::Dec => parse_numeric_entity( // Skip past '&#'. Note that match_len is 3 as it matches '&#[0-9]'. &code[2..], @@ -91,16 +96,24 @@ fn parse_entity(code: &[u8], in_attr_val: bool) -> ParsedEntity { // Skip past '&#x'. Note that match_len is 4 as it matches '&#x[0-9a-fA-F]'. &code[3..], HEX_DIGIT, - |value, c| value.wrapping_mul(16).wrapping_add(match c { - c if DIGIT[c] => (c - b'0') as u32, - c if LOWER_HEX_ALPHA[c] => 10 + (c - b'a') as u32, - c if UPPER_HEX_ALPHA[c] => 10 + (c - b'A') as u32, - _ => unreachable!(), - }), + |value, c| { + value.wrapping_mul(16).wrapping_add(match c { + c if DIGIT[c] => (c - b'0') as u32, + c if LOWER_HEX_ALPHA[c] => 10 + (c - b'a') as u32, + c if UPPER_HEX_ALPHA[c] => 10 + (c - b'A') as u32, + _ => unreachable!(), + }) + }, 6, ), EntityType::Named(decoded) => { - if in_attr_val && code[match_len - 1] != b';' && code.get(match_len).filter(|&&c| ALPHANUMERIC_OR_EQUALS[c]).is_some() { + if in_attr_val + && code[match_len - 1] != b';' + && code + .get(match_len) + .filter(|&&c| ALPHANUMERIC_OR_EQUALS[c]) + .is_some() + { // Don't decode if named entity is inside an attribute value and doesn't end with semicolon but is followed by an alphanumeric or `=` character. // https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state. ParsedEntity { @@ -129,10 +142,7 @@ pub fn decode_entities(mut code: &[u8], in_attr_val: bool) -> Vec { res.extend_from_slice(&code[..before]); code = &code[before..]; if matched { - let ParsedEntity { - decoded, - read_len, - } = parse_entity(code, in_attr_val); + let ParsedEntity { decoded, read_len } = parse_entity(code, in_attr_val); match decoded { Decoded::Numeric(c) => { let mut encoded = [0u8; 4]; @@ -140,10 +150,10 @@ pub fn decode_entities(mut code: &[u8], in_attr_val: bool) -> Vec { res.extend_from_slice(&encoded); } Decoded::Ignored => res.extend_from_slice(&code[..read_len]), - Decoded::Named(s) => res.extend_from_slice(s) + Decoded::Named(s) => res.extend_from_slice(s), }; code = &code[read_len..]; }; - }; + } res } diff --git a/src/spec/entity/encode.rs b/src/spec/entity/encode.rs index e08f1ad..728c638 100644 --- a/src/spec/entity/encode.rs +++ b/src/spec/entity/encode.rs @@ -1,7 +1,7 @@ use memchr::memchr; use crate::gen::codepoints::ALPHANUMERIC_OR_EQUALS; -use crate::gen::entities::{ENTITY, EntityType}; +use crate::gen::entities::{EntityType, ENTITY}; use crate::pattern::TrieNodeMatch; pub fn encode_ampersands(mut code: &[u8], in_attr_val: bool) -> Vec { @@ -19,9 +19,14 @@ pub fn encode_ampersands(mut code: &[u8], in_attr_val: bool) -> Vec { TrieNodeMatch::NotFound { reached } => reached, TrieNodeMatch::Found { len, value } => { match value { - EntityType::Named(_) if in_attr_val - && code[len - 1] != b';' - && code.get(len).filter(|&&c| ALPHANUMERIC_OR_EQUALS[c]).is_some() => { + EntityType::Named(_) + if in_attr_val + && code[len - 1] != b';' + && code + .get(len) + .filter(|&&c| ALPHANUMERIC_OR_EQUALS[c]) + .is_some() => + { // A named entity inside an attribute value that doesn't end with semicolon but is followed by an alphanumeric or `=` character is not decoded, so we don't need to encode. // https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state. } @@ -36,6 +41,6 @@ pub fn encode_ampersands(mut code: &[u8], in_attr_val: bool) -> Vec { res.extend_from_slice(&code[..len]); code = &code[len..]; }; - }; + } res } diff --git a/src/spec/tag/mod.rs b/src/spec/tag/mod.rs index c4eb12f..7267788 100644 --- a/src/spec/tag/mod.rs +++ b/src/spec/tag/mod.rs @@ -3,4 +3,4 @@ pub mod omission; pub mod void; pub mod whitespace; -pub static EMPTY_TAG_NAME: &'static[u8] = &[]; +pub static EMPTY_TAG_NAME: &'static [u8] = &[]; diff --git a/src/spec/tag/omission.rs b/src/spec/tag/omission.rs index cfc6277..4a4d9ce 100644 --- a/src/spec/tag/omission.rs +++ b/src/spec/tag/omission.rs @@ -1,5 +1,5 @@ use lazy_static::lazy_static; -use std::collections::{HashSet, HashMap}; +use std::collections::{HashMap, HashSet}; // Rules sourced from https://html.spec.whatwg.org/multipage/syntax.html#syntax-tag-omission. // TODO Opening tags @@ -161,14 +161,15 @@ lazy_static! { } lazy_static! { - static ref OPTGROUP_CLOSING_TAG_OMISSION_RULE: ClosingTagOmissionRule = ClosingTagOmissionRule { - followed_by: { - let mut s = HashSet::<&'static [u8]>::new(); - s.insert(b"optgroup"); - s - }, - is_last: ClosingTagOmissionRuleIfLast::Always, - }; + static ref OPTGROUP_CLOSING_TAG_OMISSION_RULE: ClosingTagOmissionRule = + ClosingTagOmissionRule { + followed_by: { + let mut s = HashSet::<&'static [u8]>::new(); + s.insert(b"optgroup"); + s + }, + is_last: ClosingTagOmissionRuleIfLast::Always, + }; } lazy_static! { @@ -275,7 +276,8 @@ lazy_static! { // Use an empty slice for `parent` if no parent. pub fn can_omit_as_last_node(parent: &[u8], child: &[u8]) -> bool { - CLOSING_TAG_OMISSION_RULES.get(child) + CLOSING_TAG_OMISSION_RULES + .get(child) .filter(|r| match &r.is_last { ClosingTagOmissionRuleIfLast::Always => true, ClosingTagOmissionRuleIfLast::Never => false, @@ -286,7 +288,8 @@ pub fn can_omit_as_last_node(parent: &[u8], child: &[u8]) -> bool { // Use an empty slice for `before` if no previous sibling element. pub fn can_omit_as_before(before: &[u8], after: &[u8]) -> bool { - CLOSING_TAG_OMISSION_RULES.get(before) + CLOSING_TAG_OMISSION_RULES + .get(before) .filter(|r| r.followed_by.contains(after)) .is_some() } diff --git a/src/spec/tag/whitespace.rs b/src/spec/tag/whitespace.rs index 65fab05..b2f1a4a 100644 --- a/src/spec/tag/whitespace.rs +++ b/src/spec/tag/whitespace.rs @@ -166,7 +166,10 @@ lazy_static! { } #[inline(always)] -pub fn get_whitespace_minification_for_tag(tag_name: Option<&[u8]>, descendant_of_pre: bool) -> &'static WhitespaceMinification { +pub fn get_whitespace_minification_for_tag( + tag_name: Option<&[u8]>, + descendant_of_pre: bool, +) -> &'static WhitespaceMinification { if descendant_of_pre { WHITESPACE_SENSITIVE } else { diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 788c485..dc4b185 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -3,9 +3,16 @@ fn _eval(src: &'static [u8], expected: &'static [u8], cfg: &super::Cfg) -> () { let mut code = src.to_vec(); match super::with_friendly_error(&mut code, cfg) { Ok(len) => { - assert_eq!(std::str::from_utf8(&code[..len]).unwrap(), std::str::from_utf8(expected).unwrap()); + assert_eq!( + std::str::from_utf8(&code[..len]).unwrap(), + std::str::from_utf8(expected).unwrap() + ); } - Err(super::FriendlyError { code_context, message, .. }) => { + Err(super::FriendlyError { + code_context, + message, + .. + }) => { println!("{}", message); println!("{}", code_context); assert!(false); @@ -16,41 +23,60 @@ fn _eval(src: &'static [u8], expected: &'static [u8], cfg: &super::Cfg) -> () { #[cfg(test)] fn _eval_error(src: &'static [u8], expected: ErrorType, cfg: &super::Cfg) -> () { let mut code = src.to_vec(); - assert_eq!(super::in_place(&mut code, cfg).unwrap_err().error_type, expected); + assert_eq!( + super::in_place(&mut code, cfg).unwrap_err().error_type, + expected + ); } #[cfg(test)] fn eval(src: &'static [u8], expected: &'static [u8]) -> () { - _eval(src, expected, &super::Cfg { - minify_js: false, - minify_css: false, - }); + _eval( + src, + expected, + &super::Cfg { + minify_js: false, + minify_css: false, + }, + ); } #[cfg(test)] fn eval_error(src: &'static [u8], expected: ErrorType) -> () { - _eval_error(src, expected, &super::Cfg { - minify_js: false, - minify_css: false, - }); + _eval_error( + src, + expected, + &super::Cfg { + minify_js: false, + minify_css: false, + }, + ); } #[cfg(test)] #[cfg(feature = "js-esbuild")] fn eval_with_js_min(src: &'static [u8], expected: &'static [u8]) -> () { - _eval(src, expected, &super::Cfg { - minify_js: true, - minify_css: false, - }); + _eval( + src, + expected, + &super::Cfg { + minify_js: true, + minify_css: false, + }, + ); } #[cfg(test)] #[cfg(feature = "js-esbuild")] fn eval_with_css_min(src: &'static [u8], expected: &'static [u8]) -> () { - _eval(src, expected, &super::Cfg { - minify_js: false, - minify_css: true, - }); + _eval( + src, + expected, + &super::Cfg { + minify_js: false, + minify_css: true, + }, + ); } #[test] @@ -75,7 +101,10 @@ fn test_collapse_destroy_whole_and_trim_whitespace() { eval(b"

    \n
", b"
    "); eval(b"
      \n a
    ", b"
      a
    "); eval(b"
      \n a b
    ", b"
      a b
    "); - eval(b"
      \n a
         
      b   
    ", b"
      a
      b
    "); + eval( + b"
      \n a
         
      b   
    ", + b"
      a
      b
    ", + ); // Tag names should be case insensitive. eval(b"
      \n a b
    ", b"
      a b
    "); } @@ -83,25 +112,40 @@ fn test_collapse_destroy_whole_and_trim_whitespace() { #[test] fn test_no_whitespace_minification() { eval(b"
       \n  \t   
    ", b"
       \n  \t   
    "); - eval(b"", b""); + eval( + b"", + b"", + ); // Tag names should be case insensitive. eval(b"
       \n  \t   
    ", b"
       \n  \t   
    "); - eval(b"
        1    2     
    ", b"
        1    2     
    "); - eval(b"
        1 
    \n
    2
    ", b"
        1 
    \n
    2
    "); - eval(b"
        1 
    \n
    2
    ", b"
        1 
    \n
    2
    "); - eval(br#"
    fn main() {
    +    eval(
    +        b"
        1    2     
    ", + b"
        1    2     
    ", + ); + eval( + b"
        1 
    \n
    2
    ", + b"
        1 
    \n
    2
    ", + ); + eval( + b"
        1 
    \n
    2
    ", + b"
        1 
    \n
    2
    ", + ); + eval( + br#"
    fn main() {
       println!("Hello, world!");
       loop {
         println!("Hello, world!");
       }
     }
    -
    "#, br#"
    fn main() {
    +
    "#, + br#"
    fn main() {
       println!("Hello, world!");
       loop {
         println!("Hello, world!");
       }
     }
    -
    "#); +
    "#, + ); } #[test] @@ -109,7 +153,10 @@ fn test_parsing_omitted_closing_tag() { eval(b"", b""); eval(b" \n", b""); eval(b" \n", b""); - eval(b"

    Foo

    ", b"

    Foo

    "); + eval( + b"

    Foo

    ", + b"

    Foo

    ", + ); } #[test] @@ -138,19 +185,50 @@ fn test_parsing_with_omitted_tags() { fn test_unmatched_closing_tag() { eval_error(b"Hello

    Goodbye", ErrorType::UnexpectedClosingTag); eval_error(b"Hello

    Goodbye", ErrorType::UnexpectedClosingTag); - eval_error(b"
    Hello

    Goodbye", ErrorType::ClosingTagMismatch { expected: "div".to_string(), got: "p".to_string() }); - eval_error(b"
    • a

      ", ErrorType::ClosingTagMismatch { expected: "ul".to_string(), got: "p".to_string() }); - eval_error(b"
      • a

        ", ErrorType::ClosingTagMismatch { expected: "ul".to_string(), got: "p".to_string() }); - eval_error(b"
        • a

          ", ErrorType::ClosingTagMismatch { expected: "ul".to_string(), got: "p".to_string() }); + eval_error( + b"
          Hello

          Goodbye", + ErrorType::ClosingTagMismatch { + expected: "div".to_string(), + got: "p".to_string(), + }, + ); + eval_error( + b"
          • a

            ", + ErrorType::ClosingTagMismatch { + expected: "ul".to_string(), + got: "p".to_string(), + }, + ); + eval_error( + b"
            • a

              ", + ErrorType::ClosingTagMismatch { + expected: "ul".to_string(), + got: "p".to_string(), + }, + ); + eval_error( + b"
              • a

                ", + ErrorType::ClosingTagMismatch { + expected: "ul".to_string(), + got: "p".to_string(), + }, + ); } #[test] fn test_removal_of_optional_tags() { - eval(b"
                • 1
                • 2
                • 3
                ", b"
                • 1
                • 2
                • 3
                "); + eval( + b"
                • 1
                • 2
                • 3
                ", + b"
                • 1
                • 2
                • 3
                ", + ); eval(b"", b""); - eval(b"1
                ", b"1
                "); + eval( + b"1
                ", + b"1
                ", + ); eval(b"
                ", b"
                "); - eval(br#" + eval( + br#" @@ -158,7 +236,9 @@ fn test_removal_of_optional_tags() { - "#, b""); + "#, + b"", + ); // Tag names should be case insensitive. eval(b"", b""); } @@ -168,7 +248,10 @@ fn test_removal_of_optional_closing_p_tag() { eval(b"

                ", b"

                "); eval(b"

                ", b"

                "); eval(b"

                ", b"

                "); - eval(b"

                ", b"

                "); + eval( + b"

                ", + b"

                ", + ); } #[test] @@ -186,7 +269,10 @@ fn test_attr_single_quoted_value_minification() { eval(b"", b""); eval(b"", b""); eval(b"", b"a\">"); - eval(b"", b""); + eval( + b"", + b"", + ); } #[test] @@ -203,7 +289,10 @@ fn test_attr_unquoted_value_minification() { #[test] fn test_class_attr_value_minification() { eval(b"", b""); - eval(b"", b""); + eval( + b"", + b"", + ); eval(b"", b""); eval(b"", b""); eval(b"", b""); @@ -218,13 +307,34 @@ fn test_class_attr_value_minification() { #[test] fn test_d_attr_value_minification() { eval(b"", b""); - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); eval(b"", b""); // Attribute names should be case insensitive. eval(b"", b""); @@ -263,12 +373,27 @@ fn test_default_attr_value_removal() { #[test] fn test_script_type_attr_value_removal() { - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); - eval(b"", b""); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); + eval( + b"", + b"", + ); // Tag and attribute names should be case insensitive. - eval(b"", b""); + eval( + b"", + b"", + ); } #[test] @@ -282,9 +407,15 @@ fn test_empty_attr_value_removal() { #[test] fn test_space_between_attrs_minification() { - eval(b"
                ", b"
                "); + eval( + b"
                ", + b"
                ", + ); eval(b"
                ", b"
                "); - eval(b"
                ", b"
                "); + eval( + b"
                ", + b"
                ", + ); eval(b"
                ", b"
                "); eval(b"
                ", b"
                "); eval(b"
                ", b"
                "); @@ -304,7 +435,10 @@ fn test_hexadecimal_entity_decoding() { eval(b"0", b"0"); eval(b"ᅑ", b"\xe1\x85\x91"); eval(b"�", b"\xef\xbf\xbd"); - eval(b"�", b"\xef\xbf\xbd"); + eval( + b"�", + b"\xef\xbf\xbd", + ); } #[test] @@ -317,7 +451,10 @@ fn test_decimal_entity_decoding() { eval(b"0", b"0"); eval(b"ᅑ", b"\xe1\x85\x91"); eval(b"�", b"\xef\xbf\xbd"); - eval(b"�", b"\xef\xbf\xbd"); + eval( + b"�", + b"\xef\xbf\xbd", + ); } #[test] @@ -337,9 +474,18 @@ fn test_named_entity_decoding() { // Named entities not ending with ';' in attr values are not decoded if immediately // followed by an alphanumeric or `=` character. (See parser for more details.) - eval(br#""#, br#""#); - eval(br#""#, br#""#); - eval(br#""#, br#""#); + eval( + br#""#, + br#""#, + ); + eval( + br#""#, + br#""#, + ); + eval( + br#""#, + br#""#, + ); } #[test] @@ -419,9 +565,15 @@ fn test_left_chevron_in_content() { #[test] fn test_comments_removal() { - eval(b"
                a   b
                ", b"
                a   b
                "); + eval( + b"
                a   b
                ", + b"
                a   b
                ", + ); eval(b"&amp", b"&"); - eval(b"", b""); + eval( + b"", + b"", + ); } #[test] @@ -434,30 +586,54 @@ fn test_processing_instructions() { #[test] fn test_js_minification() { eval_with_js_min(b"", b""); - eval_with_js_min(br#" + eval_with_js_min( + br#" - "#, b""); - eval_with_js_min(b"", b""); - eval_with_js_min(br#" + "#, + b"", + ); + eval_with_js_min( + b"", + b"", + ); + eval_with_js_min( + br#" - "#, b""); + "#, + b"", + ); } #[cfg(feature = "js-esbuild")] #[test] fn test_js_minification_unintentional_closing_tag() { - eval_with_js_min(br#""#, br#""#); - eval_with_js_min(br#""#, br#""#); - eval_with_js_min(br#""#, br#""#); - eval_with_js_min(br#""#, br#""#); + eval_with_js_min( + br#""#, + br#""#, + ); + eval_with_js_min( + br#""#, + br#""#, + ); + eval_with_js_min( + br#""#, + br#""#, + ); + eval_with_js_min( + br#""#, + br#""#, + ); } #[cfg(feature = "js-esbuild")] #[test] fn test_css_minification() { - eval_with_css_min(b"", b""); + eval_with_css_min( + b"", + b"", + ); }