mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 06:36:08 +03:00
fix(html/minifier): Fix bugs of the smart mode (#5093)
This commit is contained in:
parent
09d7f7aa27
commit
5932a0a2ef
@ -1,7 +1,5 @@
|
||||
#![deny(clippy::all)]
|
||||
|
||||
use std::mem::take;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use serde_json::Value;
|
||||
use swc_atoms::{js_word, JsWord};
|
||||
@ -656,6 +654,15 @@ impl Minifier {
|
||||
!matches!(self.collapse_whitespaces, CollapseWhitespaces::None)
|
||||
}
|
||||
|
||||
fn is_custom_element(&self, tag_name: &str) -> bool {
|
||||
// https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
|
||||
match tag_name {
|
||||
"annotation-xml" | "color-profile" | "font-face" | "font-face-src"
|
||||
| "font-face-uri" | "font-face-format" | "font-face-name" | "missing-glyph" => false,
|
||||
_ => matches!(tag_name.chars().next(), Some('a'..='z')) && tag_name.contains('-'),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_display(&self, namespace: Namespace, tag_name: &str) -> Display {
|
||||
match namespace {
|
||||
Namespace::HTML => {
|
||||
@ -715,90 +722,87 @@ impl Minifier {
|
||||
_ => Display::Inline,
|
||||
}
|
||||
}
|
||||
Namespace::SVG => match tag_name {
|
||||
"text" | "foreignObject" => Display::Block,
|
||||
|
||||
_ => Display::Inline,
|
||||
},
|
||||
_ => Display::Inline,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_element_displayed(&self, namespace: Namespace, tag_name: &str) -> bool {
|
||||
match namespace {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#metadata_content
|
||||
//
|
||||
// Excluded:
|
||||
// `noscript` - can be displayed if JavaScript disabled
|
||||
// `script` - can insert markup using `document.write`
|
||||
Namespace::HTML => !matches!(
|
||||
tag_name,
|
||||
"base" | "command" | "link" | "meta" | "style" | "title"
|
||||
),
|
||||
Namespace::HTML => {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#metadata_content
|
||||
//
|
||||
// Excluded:
|
||||
// `noscript` - can be displayed if JavaScript disabled
|
||||
// `script` - can insert markup using `document.write`
|
||||
!matches!(
|
||||
tag_name,
|
||||
"base" | "command" | "link" | "meta" | "style" | "title" | "template"
|
||||
)
|
||||
}
|
||||
Namespace::SVG => !matches!(tag_name, "style"),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_leading_and_trailing_whitespaces(&self, children: &mut Vec<Child>) {
|
||||
if let Some(last) = children.first_mut() {
|
||||
match last {
|
||||
Child::Text(text) => {
|
||||
text.data = text.data.trim_start_matches(is_whitespace).into();
|
||||
fn remove_leading_and_trailing_whitespaces(
|
||||
&self,
|
||||
children: &mut Vec<Child>,
|
||||
only_first: bool,
|
||||
only_last: bool,
|
||||
) {
|
||||
if only_first {
|
||||
if let Some(last) = children.first_mut() {
|
||||
match last {
|
||||
Child::Text(text) => {
|
||||
text.data = text.data.trim_start_matches(is_whitespace).into();
|
||||
|
||||
if text.data.is_empty() {
|
||||
children.remove(0);
|
||||
if text.data.is_empty() {
|
||||
children.remove(0);
|
||||
}
|
||||
}
|
||||
Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
children,
|
||||
..
|
||||
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
|
||||
self.remove_leading_and_trailing_whitespaces(children, true, false);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
children,
|
||||
..
|
||||
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
|
||||
self.remove_leading_and_trailing_whitespaces(children);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(last) = children.last_mut() {
|
||||
match last {
|
||||
Child::Text(text) => {
|
||||
text.data = text.data.trim_end_matches(is_whitespace).into();
|
||||
if only_last {
|
||||
if let Some(last) = children.last_mut() {
|
||||
match last {
|
||||
Child::Text(text) => {
|
||||
text.data = text.data.trim_end_matches(is_whitespace).into();
|
||||
|
||||
if text.data.is_empty() {
|
||||
children.pop();
|
||||
if text.data.is_empty() {
|
||||
children.pop();
|
||||
}
|
||||
}
|
||||
Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
children,
|
||||
..
|
||||
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
|
||||
self.remove_leading_and_trailing_whitespaces(children, false, true);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
children,
|
||||
..
|
||||
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
|
||||
self.remove_leading_and_trailing_whitespaces(children);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_deep_last_text_element<'a>(&self, node: &'a Child) -> Option<&'a Text> {
|
||||
match node {
|
||||
Child::Text(text) => Some(text),
|
||||
Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
children,
|
||||
..
|
||||
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
|
||||
if let Some(last) = children.last() {
|
||||
self.get_deep_last_text_element(last)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_prev_non_comment_node<'a>(
|
||||
fn get_prev_displayed_node<'a>(
|
||||
&self,
|
||||
children: &'a Vec<Child>,
|
||||
index: usize,
|
||||
@ -806,15 +810,96 @@ impl Minifier {
|
||||
let prev = children.get(index);
|
||||
|
||||
match prev {
|
||||
Some(Child::Comment(_)) if index >= 1 => {
|
||||
self.get_prev_non_comment_node(children, index - 1)
|
||||
Some(Child::Comment(_)) => {
|
||||
if index >= 1 {
|
||||
self.get_prev_displayed_node(children, index - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Child::Element(element)) => {
|
||||
if !self.is_element_displayed(element.namespace, &element.tag_name) && index >= 1 {
|
||||
self.get_prev_displayed_node(children, index - 1)
|
||||
} else if !element.children.is_empty() {
|
||||
self.get_prev_displayed_node(&element.children, element.children.len() - 1)
|
||||
} else {
|
||||
prev
|
||||
}
|
||||
}
|
||||
Some(_) => prev,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_non_comment_node<'a>(
|
||||
fn get_last_displayed_text_node<'a>(
|
||||
&self,
|
||||
children: &'a Vec<Child>,
|
||||
index: usize,
|
||||
) -> Option<&'a Text> {
|
||||
let prev = children.get(index);
|
||||
|
||||
match prev {
|
||||
Some(Child::Comment(_)) => {
|
||||
if index >= 1 {
|
||||
self.get_last_displayed_text_node(children, index - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Child::Element(element)) => {
|
||||
if !self.is_element_displayed(element.namespace, &element.tag_name) && index >= 1 {
|
||||
self.get_last_displayed_text_node(children, index - 1)
|
||||
} else if !element.children.is_empty() {
|
||||
for index in (0..=element.children.len() - 1).rev() {
|
||||
if let Some(text) =
|
||||
self.get_last_displayed_text_node(&element.children, index)
|
||||
{
|
||||
return Some(text);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Child::Text(text)) => Some(text),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_first_displayed_text_node<'a>(
|
||||
&self,
|
||||
children: &'a Vec<Child>,
|
||||
index: usize,
|
||||
) -> Option<&'a Text> {
|
||||
let next = children.get(index);
|
||||
|
||||
match next {
|
||||
Some(Child::Comment(_)) => self.get_first_displayed_text_node(children, index + 1),
|
||||
Some(Child::Element(element)) => {
|
||||
if !self.is_element_displayed(element.namespace, &element.tag_name) && index >= 1 {
|
||||
self.get_first_displayed_text_node(children, index - 1)
|
||||
} else if !element.children.is_empty() {
|
||||
for index in 0..=element.children.len() - 1 {
|
||||
if let Some(text) =
|
||||
self.get_first_displayed_text_node(&element.children, index)
|
||||
{
|
||||
return Some(text);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Child::Text(text)) => Some(text),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_displayed_node<'a>(
|
||||
&self,
|
||||
children: &'a Vec<Child>,
|
||||
index: usize,
|
||||
@ -822,23 +907,17 @@ impl Minifier {
|
||||
let next = children.get(index);
|
||||
|
||||
match next {
|
||||
Some(Child::Comment(_)) => self.get_next_non_comment_node(children, index + 1),
|
||||
Some(Child::Comment(_)) => self.get_next_displayed_node(children, index + 1),
|
||||
Some(Child::Element(element))
|
||||
if !self.is_element_displayed(element.namespace, &element.tag_name) =>
|
||||
{
|
||||
self.get_next_displayed_node(children, index + 1)
|
||||
}
|
||||
Some(_) => next,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_text_node<'a>(&self, children: &'a Vec<Child>, index: usize) -> Option<&'a Child> {
|
||||
let next = children.get(index);
|
||||
|
||||
match next {
|
||||
Some(Child::Text(_)) => next,
|
||||
Some(Child::Element(_)) => None,
|
||||
Some(_) => self.get_next_text_node(children, index + 1),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_whitespace_minification_for_tag(
|
||||
&self,
|
||||
namespace: Namespace,
|
||||
@ -966,17 +1045,17 @@ impl Minifier {
|
||||
true
|
||||
}
|
||||
|
||||
fn minify_children(&mut self, children: &mut Vec<Child>) {
|
||||
fn minify_children(&mut self, children: &Vec<Child>) -> Vec<Child> {
|
||||
let (namespace, tag_name) = match &self.current_element {
|
||||
Some(element) => (element.namespace, &element.tag_name),
|
||||
_ => return,
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
|
||||
let mode = self.get_whitespace_minification_for_tag(namespace, tag_name);
|
||||
|
||||
let child_will_be_retained = |child: &mut Child,
|
||||
prev: Option<&Child>,
|
||||
next: Option<&Child>| {
|
||||
let child_will_be_retained = |child: &mut Child, children: &Vec<Child>, index: usize| {
|
||||
match child {
|
||||
Child::Comment(comment) if self.remove_comments => {
|
||||
self.is_preserved_comment(&comment.data)
|
||||
@ -989,7 +1068,8 @@ impl Minifier {
|
||||
|| (element.namespace == Namespace::HTML
|
||||
&& &*element.tag_name == "noscript"))
|
||||
&& element.attributes.is_empty()
|
||||
&& self.empty_children(&element.children) =>
|
||||
&& self.empty_children(&element.children)
|
||||
&& element.content.is_none() =>
|
||||
{
|
||||
false
|
||||
}
|
||||
@ -1016,16 +1096,20 @@ impl Minifier {
|
||||
let mut is_smart_right_trim = false;
|
||||
|
||||
if self.collapse_whitespaces == CollapseWhitespaces::Smart {
|
||||
let prev_display = if let Some(Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
..
|
||||
})) = &prev
|
||||
{
|
||||
Some(self.get_display(*namespace, tag_name))
|
||||
let prev = if index >= 1 {
|
||||
children.get(index - 1)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let prev_display = match prev {
|
||||
Some(Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
..
|
||||
})) => Some(self.get_display(*namespace, tag_name)),
|
||||
Some(Child::Comment(_)) => Some(Display::None),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
is_smart_left_trim = match prev_display {
|
||||
// Block-level containers:
|
||||
@ -1033,8 +1117,8 @@ impl Minifier {
|
||||
// `Display::Block` - `display: block flow`
|
||||
// `Display::ListItem` - `display: block flow list-item`
|
||||
// `Display::Table` - `display: block table`
|
||||
// + internal table display (only whitespace characters allowed
|
||||
// there)
|
||||
//
|
||||
// + internal table display (only whitespace characters allowed there)
|
||||
Some(
|
||||
Display::Block
|
||||
| Display::ListItem
|
||||
@ -1048,62 +1132,106 @@ impl Minifier {
|
||||
| Display::TableRowGroup
|
||||
| Display::TableFooterGroup,
|
||||
) => true,
|
||||
// These elements are not displayed
|
||||
Some(Display::None) if prev.is_some() => {
|
||||
if let Some(Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
..
|
||||
})) = &prev
|
||||
{
|
||||
!self.is_element_displayed(*namespace, tag_name)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
// Elements are not displayed
|
||||
// And
|
||||
// Inline box
|
||||
Some(Display::Inline) => {
|
||||
if let Some(prev) = &prev {
|
||||
let deep = self.get_deep_last_text_element(prev);
|
||||
|
||||
if let Some(deep) = deep {
|
||||
deep.data.ends_with(is_whitespace)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
Some(Display::None) | Some(Display::Inline) => {
|
||||
// A custom element can contain any elements, we cannot predict the
|
||||
// behavior of spaces
|
||||
let is_custom_element = if let Some(Child::Element(element)) = &prev
|
||||
{
|
||||
self.is_custom_element(&*element.tag_name)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if is_custom_element {
|
||||
false
|
||||
} else {
|
||||
match &self.get_prev_displayed_node(children, index - 1) {
|
||||
Some(Child::Text(text)) => {
|
||||
text.data.ends_with(is_whitespace)
|
||||
}
|
||||
Some(Child::Element(element)) => {
|
||||
let deep = if !element.children.is_empty() {
|
||||
self.get_last_displayed_text_node(
|
||||
&element.children,
|
||||
element.children.len() - 1,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(deep) = deep {
|
||||
deep.data.ends_with(is_whitespace)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let parent_display =
|
||||
self.get_display(namespace, tag_name);
|
||||
|
||||
match parent_display {
|
||||
Display::Inline => {
|
||||
if let Some(Child::Text(Text {
|
||||
data, ..
|
||||
})) = &self.latest_element
|
||||
{
|
||||
data.ends_with(is_whitespace)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inline level containers and etc
|
||||
Some(_) => false,
|
||||
None => {
|
||||
let parent_display = self.get_display(namespace, tag_name);
|
||||
// Template can be used in any place, so let's keep whitespaces
|
||||
//
|
||||
// For custom elements - an unnamed `<slot>` will be filled with all
|
||||
// of the custom element's top-level
|
||||
// child nodes that do not have the slot
|
||||
// attribute. This includes text nodes.
|
||||
// Also they can be used for custom logic
|
||||
|
||||
match parent_display {
|
||||
Display::Inline => {
|
||||
if let Some(Child::Text(Text { data, .. })) =
|
||||
&self.latest_element
|
||||
{
|
||||
data.ends_with(is_whitespace)
|
||||
} else {
|
||||
false
|
||||
if (namespace == Namespace::HTML && tag_name == "template")
|
||||
|| self.is_custom_element(tag_name)
|
||||
{
|
||||
false
|
||||
} else {
|
||||
let parent_display = self.get_display(namespace, tag_name);
|
||||
|
||||
match parent_display {
|
||||
Display::Inline => {
|
||||
if let Some(Child::Text(Text { data, .. })) =
|
||||
&self.latest_element
|
||||
{
|
||||
data.ends_with(is_whitespace)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let next_display = if let Some(Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
..
|
||||
})) = &next
|
||||
{
|
||||
Some(self.get_display(*namespace, tag_name))
|
||||
} else {
|
||||
None
|
||||
let next = children.get(index + 1);
|
||||
let next_display = match next {
|
||||
Some(Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
..
|
||||
})) => Some(self.get_display(*namespace, tag_name)),
|
||||
Some(Child::Comment(_)) => Some(Display::None),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
is_smart_right_trim = match next_display {
|
||||
@ -1112,8 +1240,8 @@ impl Minifier {
|
||||
// `Display::Block` - `display: block flow`
|
||||
// `Display::ListItem` - `display: block flow list-item`
|
||||
// `Display::Table` - `display: block table`
|
||||
// + internal table display (only whitespace characters allowed
|
||||
// there)
|
||||
//
|
||||
// + internal table display (only whitespace characters allowed there)
|
||||
Some(
|
||||
Display::Block
|
||||
| Display::ListItem
|
||||
@ -1128,23 +1256,39 @@ impl Minifier {
|
||||
| Display::TableFooterGroup,
|
||||
) => true,
|
||||
// These elements are not displayed
|
||||
Some(Display::None) if prev.is_some() => {
|
||||
if let Some(Child::Element(Element {
|
||||
namespace,
|
||||
tag_name,
|
||||
..
|
||||
})) = &next
|
||||
{
|
||||
!self.is_element_displayed(*namespace, tag_name)
|
||||
} else {
|
||||
true
|
||||
Some(Display::None) => {
|
||||
match &self.get_next_displayed_node(children, index + 1) {
|
||||
Some(Child::Text(text)) => text.data.starts_with(is_whitespace),
|
||||
Some(Child::Element(element)) => {
|
||||
let deep = self
|
||||
.get_first_displayed_text_node(&element.children, 0);
|
||||
|
||||
if let Some(deep) = deep {
|
||||
!deep.data.starts_with(is_whitespace)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let parent_display = self.get_display(namespace, tag_name);
|
||||
|
||||
!matches!(parent_display, Display::Inline)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(_) => false,
|
||||
None => {
|
||||
let parent_display = self.get_display(namespace, tag_name);
|
||||
// Template can be used in any place, so let's keep whitespaces
|
||||
let is_template =
|
||||
namespace == Namespace::HTML && tag_name == "template";
|
||||
|
||||
!matches!(parent_display, Display::Inline)
|
||||
if is_template {
|
||||
false
|
||||
} else {
|
||||
let parent_display = self.get_display(namespace, tag_name);
|
||||
|
||||
!matches!(parent_display, Display::Inline)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1177,56 +1321,59 @@ impl Minifier {
|
||||
}
|
||||
};
|
||||
|
||||
let cloned_children = children.clone();
|
||||
let mut new_children = Vec::with_capacity(children.len());
|
||||
|
||||
let mut index = 0;
|
||||
let mut pending_text = vec![];
|
||||
for (index, child) in children.iter().enumerate() {
|
||||
let mut child = child.clone();
|
||||
|
||||
children.retain_mut(|child| {
|
||||
match child {
|
||||
Child::Text(text)
|
||||
if self
|
||||
.get_next_text_node(&cloned_children, index + 1)
|
||||
.is_some()
|
||||
&& !child_will_be_retained(
|
||||
&mut cloned_children.get(index + 1).cloned().unwrap(),
|
||||
self.get_prev_non_comment_node(&cloned_children, index),
|
||||
self.get_next_non_comment_node(&cloned_children, index + 2),
|
||||
) =>
|
||||
{
|
||||
pending_text.push(text.data.clone());
|
||||
// Merge adjacent text nodes
|
||||
let merged = match &mut child {
|
||||
Child::Text(text) => {
|
||||
if let Some(Child::Text(prev_text)) = new_children.last_mut() {
|
||||
let mut new_data =
|
||||
String::with_capacity(prev_text.data.len() + text.data.len());
|
||||
|
||||
index += 1;
|
||||
new_data.push_str(&prev_text.data);
|
||||
new_data.push_str(&text.data);
|
||||
|
||||
return false;
|
||||
}
|
||||
Child::Text(text) if !pending_text.is_empty() => {
|
||||
let mut new_value = String::new();
|
||||
text.data = new_data.into();
|
||||
|
||||
for text in take(&mut pending_text) {
|
||||
new_value.push_str(&text);
|
||||
new_children.pop();
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
new_value.push_str(&text.data);
|
||||
|
||||
text.data = new_value.into();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let prev = if index >= 1 {
|
||||
self.get_prev_non_comment_node(&cloned_children, index - 1)
|
||||
} else {
|
||||
None
|
||||
_ => false,
|
||||
};
|
||||
let next = self.get_next_non_comment_node(&cloned_children, index + 1);
|
||||
|
||||
let result = child_will_be_retained(child, prev, next);
|
||||
let mut merged_children = new_children.clone();
|
||||
|
||||
index += 1;
|
||||
let (merged_children, offset) = if merged {
|
||||
merged_children.push(child.clone());
|
||||
|
||||
result
|
||||
});
|
||||
let offset = merged_children.len() - 1;
|
||||
|
||||
merged_children.extend_from_slice(&children[index + 1..]);
|
||||
|
||||
(merged_children, offset)
|
||||
} else {
|
||||
let offset = merged_children.len();
|
||||
|
||||
merged_children.extend_from_slice(&children[index..]);
|
||||
|
||||
(merged_children, offset)
|
||||
};
|
||||
|
||||
let result = child_will_be_retained(&mut child, &merged_children, offset);
|
||||
|
||||
if result {
|
||||
new_children.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
new_children
|
||||
}
|
||||
|
||||
fn get_attribute_value(&self, attributes: &Vec<Attribute>, name: &str) -> Option<JsWord> {
|
||||
@ -1548,7 +1695,7 @@ impl Minifier {
|
||||
let mut document_or_document_fragment = match mode {
|
||||
HtmlMinificationMode::ConditionalComments => {
|
||||
// Emulate content inside conditional comments like content inside the
|
||||
// `template` element
|
||||
// `template` element, because it can be used in any place in source code
|
||||
context_element = Some(Element {
|
||||
span: Default::default(),
|
||||
tag_name: "template".into(),
|
||||
@ -1660,7 +1807,7 @@ impl VisitMut for Minifier {
|
||||
}
|
||||
|
||||
fn visit_mut_document_fragment(&mut self, n: &mut DocumentFragment) {
|
||||
self.minify_children(&mut n.children);
|
||||
n.children = self.minify_children(&n.children);
|
||||
|
||||
n.visit_mut_children_with(self);
|
||||
}
|
||||
@ -1682,8 +1829,13 @@ impl VisitMut for Minifier {
|
||||
|
||||
self.current_element = None;
|
||||
|
||||
if self.need_collapse_whitespace() {
|
||||
self.latest_element = Some(n.clone());
|
||||
if self.collapse_whitespaces == CollapseWhitespaces::Smart {
|
||||
match n {
|
||||
Child::Text(_) | Child::Element(_) => {
|
||||
self.latest_element = Some(n.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1705,7 +1857,7 @@ impl VisitMut for Minifier {
|
||||
self.descendant_of_pre = get_white_space(n.namespace, &n.tag_name) == WhiteSpace::Pre;
|
||||
}
|
||||
|
||||
self.minify_children(&mut n.children);
|
||||
n.children = self.minify_children(&n.children);
|
||||
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
@ -1714,7 +1866,7 @@ impl VisitMut for Minifier {
|
||||
&& &*n.tag_name == "body"
|
||||
&& self.need_collapse_whitespace()
|
||||
{
|
||||
self.remove_leading_and_trailing_whitespaces(&mut n.children);
|
||||
self.remove_leading_and_trailing_whitespaces(&mut n.children, true, true);
|
||||
}
|
||||
|
||||
if self.need_collapse_whitespace() {
|
||||
|
@ -1,9 +1,4 @@
|
||||
<!doctype html><html lang=en><body>
|
||||
|
||||
|
||||
|
||||
|
||||
<svg>
|
||||
<!doctype html><html lang=en><svg>
|
||||
|
||||
|
||||
</svg>
|
||||
</svg>
|
@ -1 +1 @@
|
||||
<!doctype html><html lang=en><meta charset=UTF-8><title>Document</title><body><template ngfor #hero [ngforof]=heroes><hero-detail *ngif=hero [hero]=hero></hero-detail></template><form (ngsubmit)=onSubmit(theForm) #theform=ngForm><div class=form-group><label for=name>Name</label> <input class=form-control required ngcontrol=firstName [(ngmodel)]=currentHero.firstName></div><button [disabled]=!theForm.form.valid>Submit</button></form>
|
||||
<!doctype html><html lang=en><meta charset=UTF-8><title>Document</title><body><template ngfor #hero [ngforof]=heroes> <hero-detail *ngif=hero [hero]=hero></hero-detail> </template><form (ngsubmit)=onSubmit(theForm) #theform=ngForm><div class=form-group><label for=name>Name</label> <input class=form-control required ngcontrol=firstName [(ngmodel)]=currentHero.firstName></div><button [disabled]=!theForm.form.valid>Submit</button></form>
|
@ -432,5 +432,14 @@
|
||||
</style>
|
||||
</svg>
|
||||
|
||||
<div>
|
||||
<span>test</span> a <!-- test -->b <span>test</span>
|
||||
<span>test</span> a<!-- test --> b <span>test</span>
|
||||
<span>test</span> a <!-- test --> b <span>test</span>
|
||||
</div>
|
||||
|
||||
<div><foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar></div>
|
||||
<div><svg> <linearGradient id=gradient /> </svg> <span>a</span></div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -21,12 +21,12 @@
|
||||
Foo
|
||||
|
||||
|
||||
</textarea><div><div>Text</div></div><unknown><div>Text</div></unknown><div></div><svg version=1.1 viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect x=0 y=0 width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg viewBox="0 0 100 100"> <a href=/docs/Web/SVG/Element/circle><circle cx=50 cy=40 r=35 /> </a> <a href=/docs/Web/SVG/Element/text><text x=50 y=90 text-anchor=middle><circle> </text></a></svg><script data-test=test></script> <script>console.log("test")</script><xmp>
|
||||
</textarea><div><div>Text</div></div><unknown><div>Text</div></unknown><div></div><svg version=1.1 viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect x=0 y=0 width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg viewBox="0 0 100 100"> <a href=/docs/Web/SVG/Element/circle><circle cx=50 cy=40 r=35 /> </a><a href=/docs/Web/SVG/Element/text><text x=50 y=90 text-anchor=middle><circle></text></a></svg><script data-test=test></script><script>console.log("test")</script><xmp>
|
||||
|
||||
test
|
||||
|
||||
</xmp><div>foo <a>baz </a>bar foo <a>baz </a>bar foo <a>baz </a>bar</div><div>foo <a>baz </a>bar foo <a>baz </a>bar foo <a>baz </a>bar</div><div>foo <img src=https://prettier.io/icon.png></div><div>text <img src=https://colourlex.com/wp-content/uploads/2021/02/vine-black-painted-swatch.jpg alt=test> test</div><span>test<script>console.log("test")</script>test</span> <span>test <script>console.log("test")</script> test</span><div><p>blah</div><div>test <br> test</div><div>test <wbr> test</div><div>a <input> c</div><div><div>a</div><div>b</div></div><div><span> a </span><span>b</span></div><div><div>test</div><span>test</span></div><div><div>test</div><span>test</span></div><div><span>test</span><div>test</div></div><div><span>test</span> <span>test</span></div><div><div>test</div><div>test</div></div><div><span>test</span><p>test<p>test<p>test</div><div><p>test<p>test<p>test</p><span>test</span></div><div><a href=test> test </a><a href=test>test</a></div><div><a href=test>test</a><a href=test>test</a></div><div><p>blah</div><div>test <button>test</button></div><div><button>test</button> <button>test</button></div><div>foo <button>test</button> foo</div><div>foo<button>test</button>foo</div><div>foo <button>test</button>foo</div><div>foo<button>test</button> foo</div><div>foo<button>test</button>foo</div><div>foo <button>test</button>foo</div><div>foo<button>test</button> foo</div><div><span> foo </span></div><p>foo <img> bar<p>foo<img>bar<p>foo <img>bar<p>foo<img> bar<p>foo <wbr> bar<p>foo <br> bar<p>foo <nobr>a</nobr> bar<div> fo o </div><div> fo o </div><p><p>a b<div class=leaveAlone></div><div>foo bar</div><div class=leaveAlone><div></div><span> </span>foo bar</div><div class=leaveAlone><span> </span>foo bar</div><p>foo <span></span><p>foo<span></span><div>foo <button>test</button> foo</div><div>foo <button>test</button> foo <button>test</button> foo</div><div>foo <span>foo</span> foo</div><div>foo<span> foo</span>foo</div><div><span>a </span>b<span> c</span></div><div><span>a </span>b <span>c</span></div><div><span>a </span>b <span>c</span></div><div>foo <span>baz</span></div><div>foo <span>baz</span></div><div>foo<span> baz</span></div><div>foo<span>baz</span></div><span>test </span><span><span><span><span>foo <span>baz</span></span></span></span></span> <span><span><span><span>foo <span>baz</span></span></span></span></span><span>test </span><div>test</div><span><span><span><span>foo <span>baz</span></span></span></span></span> <span><span><span><span>foo <span>baz</span></span></span></span></span><div>test</div><div><div></div></div><pre>
|
||||
</xmp><div>foo <a>baz </a>bar foo <a>baz </a>bar foo <a>baz </a>bar</div><div>foo <a>baz </a>bar foo <a>baz </a>bar foo <a>baz </a>bar</div><div>foo <img src=https://prettier.io/icon.png></div><div>text <img src=https://colourlex.com/wp-content/uploads/2021/02/vine-black-painted-swatch.jpg alt=test> test</div><span>test<script>console.log("test")</script>test</span> <span>test<script>console.log("test")</script> test</span><div><p>blah</div><div>test <br> test</div><div>test <wbr> test</div><div>a <input> c</div><div><div>a</div><div>b</div></div><div><span> a </span><span>b</span></div><div><div>test</div><span>test</span></div><div><div>test</div><span>test</span></div><div><span>test</span><div>test</div></div><div><span>test</span> <span>test</span></div><div><div>test</div><div>test</div></div><div><span>test</span><p>test<p>test<p>test</div><div><p>test<p>test<p>test</p><span>test</span></div><div><a href=test> test </a><a href=test>test</a></div><div><a href=test>test</a><a href=test>test</a></div><div><p>blah</div><div>test <button>test</button></div><div><button>test</button> <button>test</button></div><div>foo <button>test</button> foo</div><div>foo<button>test</button>foo</div><div>foo <button>test</button>foo</div><div>foo<button>test</button> foo</div><div>foo<button>test</button>foo</div><div>foo <button>test</button>foo</div><div>foo<button>test</button> foo</div><div><span> foo </span></div><p>foo <img> bar<p>foo<img>bar<p>foo <img>bar<p>foo<img> bar<p>foo <wbr> bar<p>foo <br> bar<p>foo <nobr>a</nobr> bar<div> fo o </div><div> fo o </div><p><p>a b<div class=leaveAlone></div><div>foo bar</div><div class=leaveAlone><div></div><span> </span>foo bar</div><div class=leaveAlone><span> </span>foo bar</div><p>foo <span></span><p>foo<span></span><div>foo <button>test</button> foo</div><div>foo <button>test</button> foo <button>test</button> foo</div><div>foo <span>foo</span> foo</div><div>foo<span> foo</span>foo</div><div><span>a </span>b<span> c</span></div><div><span>a </span>b <span>c</span></div><div><span>a </span>b <span>c</span></div><div>foo <span>baz</span></div><div>foo <span>baz</span></div><div>foo<span> baz</span></div><div>foo<span>baz</span></div><span>test </span><span><span><span><span>foo <span>baz</span></span></span></span></span> <span><span><span><span>foo <span>baz</span></span></span></span></span><span>test </span><div>test</div><span><span><span><span>foo <span>baz</span></span></span></span></span> <span><span><span><span>foo <span>baz</span></span></span></span></span><div>test</div><div><div></div></div><pre>
|
||||
foo
|
||||
|
||||
baz
|
||||
</pre><div>a <input> c</div><div>Empty</div><!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span><![endif]--><div><a href=#> <span><b>foo </b><i> bar </i></span></a></div><div>a b</div><div>a b c d</div><div>text</div><span> text </span><span> text </span><div><span>test</span><span>test</span></div><div><span>test</span> <command>test</command> <span>test</span></div><div><span>test</span><link rel=stylesheet href=""><span>test</span></div><div><span>test</span><meta name=content><span>test</span></div><div><span>test</span> <script>console.log("test")</script> <span>test</span></div><div><span>test</span><style>a{color:red}</style><span>test</span></div><div><span>test</span><title>test</title><span>test</span></div><div><meta name=test><meta name=test></div><div><link rel=stylesheet href=""><link rel=stylesheet href=""></div><div><script>console.log("test")</script> <script>console.log("test")</script></div><div><script>console.log("test")</script> <span>test</span> <script>console.log("test")</script></div><div><style>a{color:red}</style><style>a{color:red}</style></div><div><script>console.log("test")</script><style>a{color:red}</style></div><div><span itemscope><meta itemprop=name content="The Castle">test</span> <span>test</span></div><div><meta name=test></div><div><style>a{color:red}</style></div><div><meta name=test><div>test</div><meta name=test></div><div><meta name=test><span>test</span><meta name=test></div><svg> <title>test</title> <metadata>test</metadata> <desc>test</desc> </svg><svg> <a>test</a> <a>test</a> </svg><svg> <text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan> </text></svg><svg> <tspan>test</tspan> <foreignObject>test</foreignObject> </svg><svg> <text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan> </text></svg><svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect x=0 y=0 width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg> <script>console.log("test")</script></svg><svg><style>a{color:red}</style></svg>
|
||||
</pre><div>a <input> c</div><div>Empty</div><!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--><div><a href=#> <span><b>foo </b><i> bar </i></span></a></div><div>a b</div><div>a b c d</div><div>text</div><span> text </span><span> text </span><div><span>test</span> <span>test</span></div><div><span>test</span> <command>test</command><span>test</span></div><div><span>test</span><link rel=stylesheet href=""> <span>test</span></div><div><span>test</span><meta name=content> <span>test</span></div><div><span>test</span><script>console.log("test")</script> <span>test</span></div><div><span>test</span><style>a{color:red}</style> <span>test</span></div><div><span>test</span><title>test</title> <span>test</span></div><div><meta name=test><meta name=test></div><div><link rel=stylesheet href=""><link rel=stylesheet href=""></div><div><script>console.log("test")</script><script>console.log("test")</script></div><div><script>console.log("test")</script> <span>test</span><script>console.log("test")</script></div><div><style>a{color:red}</style><style>a{color:red}</style></div><div><script>console.log("test")</script><style>a{color:red}</style></div><div><span itemscope><meta itemprop=name content="The Castle">test</span> <span>test</span></div><div><meta name=test></div><div><style>a{color:red}</style></div><div><meta name=test><div>test</div><meta name=test></div><div><meta name=test> <span>test</span><meta name=test></div><svg> <title>test</title> <metadata>test</metadata> <desc>test</desc> </svg><svg> <a>test</a> <a>test</a> </svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg> <tspan>test</tspan><foreignObject>test</foreignObject></svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect x=0 y=0 width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg> <script>console.log("test")</script></svg><svg> <style>a{color:red}</style></svg><div><span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span></div><div><foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar></div><div><svg> <linearGradient id=gradient /> </svg><span>a</span></div>
|
@ -1 +1 @@
|
||||
<!doctype html><html lang=en><div><a href=#><span><b>foo</b>z <i>bar</i></span></a></div>
|
||||
<!doctype html><html lang=en><div><a href=#><span><b>foo </b>z <i>bar</i></span></a></div>
|
@ -1,3 +1,6 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<span> <!-- test --> text <!-- test --></span> <span> <!-- test --> text <!-- test --></span>
|
||||
<span> <!-- test --> text <!-- test --></span> <span><!-- test --> text <!-- test --></span>
|
||||
<span> <!-- test --> text <!-- test --> </span> <span><!-- test --> text <!-- test --></span>
|
||||
<span> <!-- test --> text <!-- test --></span> <span> <!-- test --> text <!-- test --></span>
|
||||
<span> <!-- test --> text <!-- test --> </span> <span> <!-- test --> text <!-- test --></span>
|
@ -1 +1 @@
|
||||
<!doctype html><html lang=en><span>text</span> <span>text</span>
|
||||
<!doctype html><html lang=en><span>text </span><span> text </span><span> text </span><span> text </span><span> text </span><span> text </span><span> text </span><span> text</span>
|
@ -1 +1 @@
|
||||
<!doctype html><svg><linearGradient id=gradient /></svg><span>a</span>
|
||||
<!doctype html><svg><linearGradient id=gradient /> </svg><span>a</span>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<span> <span><!-- test --> text <!-- test --> </span></span> <span><span> <!-- test --> text <!-- test --></span> </span>
|
@ -0,0 +1 @@
|
||||
<!doctype html><html lang=en><span><span>text </span></span><span><span> text</span></span>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<span> <div><!-- test --> text <!-- test --> </div></span> <span><div> <!-- test --> text <!-- test --></div> </span>
|
@ -0,0 +1 @@
|
||||
<!doctype html><html lang=en><span><div>text</div></span><span><div>text</div></span>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<span> <span><!-- test --> text <!-- test --> </span><meta name="test"><!-- test --></span> <span><!-- test --><meta name="test"><span> <!-- test --> text <!-- test --></span> </span>
|
@ -0,0 +1 @@
|
||||
<!doctype html><html lang=en><span><span>text </span><meta name=test></span><span><meta name=test><span> text</span></span>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<foo-bar><span>test</span> a </foo-bar> b <foo-bar> c <span> test</span></foo-bar>
|
@ -0,0 +1 @@
|
||||
<!doctype html><html lang=en><foo-bar><span>test</span> a </foo-bar> b <foo-bar> c <span>test</span></foo-bar>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar>
|
@ -0,0 +1 @@
|
||||
<!doctype html><html lang=en><foo-bar><span>test</span> </foo-bar> <foo-bar> <span>test</span></foo-bar>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<div><span>test</span> <meta name="test"> <span>test</span></div>
|
||||
<div><span>test</span> a <meta name="test"> <span>test</span></div>
|
||||
<div><span>test</span> <meta name="test"> b <span>test</span></div>
|
||||
<div><span>test</span> a <meta name="test"> b <span>test</span></div>
|
||||
<div> <meta name="test"> <span>test</span> <meta name="test"> <span>test</span> <meta name="test"> </div>
|
||||
<div> <span>test</span> <meta name="test"><meta name="test"><meta name="test"> <span>test</span> </div>
|
||||
<div> <span>test</span> <meta name="test"> <meta name="test"> <meta name="test"> <span>test</span> </div>
|
||||
<div><span>test</span> <template></template> <span>test</span></div>
|
||||
<div><div>test</div> <meta name="test"> <div>test</div></div>
|
||||
<div><img src="" alt=""> <meta name="test"> <img src="" alt=""></div>
|
||||
<div><meta name="test"> <span>test</span> <meta name="test"></div>
|
||||
<div><span>test</span> a<meta name="test"> b <span>test</span></div>
|
||||
<div><span>test</span> a <meta name="test">b <span>test</span></div>
|
||||
<div><span>test</span> a <meta name="test"> b <span>test</span></div>
|
||||
<div><span>test</span> a<meta name="test">b <span>test</span></div>
|
||||
<div> <meta name="test"> <span>test</span> <meta name="test"> <span>test</span> <meta name="test"> </div>
|
||||
<div><span>test </span> a <meta name="test"> b <span>test</span></div>
|
@ -0,0 +1 @@
|
||||
<!doctype html><div><span>test</span><meta name=test> <span>test</span></div><div><span>test</span> a<meta name=test> <span>test</span></div><div><span>test</span><meta name=test> b <span>test</span></div><div><span>test</span> a<meta name=test> b <span>test</span></div><div><meta name=test> <span>test</span><meta name=test> <span>test</span><meta name=test></div><div><span>test</span><meta name=test><meta name=test><meta name=test> <span>test</span></div><div><span>test</span><meta name=test><meta name=test><meta name=test> <span>test</span></div><div><span>test</span><template></template> <span>test</span></div><div><div>test</div><meta name=test><div>test</div></div><div><img src="" alt=""><meta name=test> <img src="" alt=""></div><div><meta name=test> <span>test</span><meta name=test></div><div><span>test</span> a<meta name=test> b <span>test</span></div><div><span>test</span> a <meta name=test>b <span>test</span></div><div><span>test</span> a<meta name=test> b <span>test</span></div><div><span>test</span> a<meta name=test>b <span>test</span></div><div><meta name=test> <span>test</span><meta name=test> <span>test</span><meta name=test></div><div><span>test </span>a<meta name=test> b <span>test</span></div>
|
@ -1 +1 @@
|
||||
<!doctype html><html lang=en><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><meta http-equiv=X-UA-Compatible content="ie=edge"><title>Document</title><div><span>test</span><noscript><a href=#>External Link</a></noscript></div><div><span>test</span><noscript><a href=#>External Link</a></noscript></div>
|
||||
<!doctype html><html lang=en><meta charset=UTF-8><meta name=viewport content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><meta http-equiv=X-UA-Compatible content="ie=edge"><title>Document</title><div><span>test</span><noscript><a href=#>External Link</a></noscript></div><div><span>test</span><noscript> <a href=#>External Link</a></noscript></div>
|
@ -1 +1 @@
|
||||
<!doctype html><html lang=en><title>Document</title><body><template><span>test</span> <slot name=test>Test</slot></template> <template><span>test</span><slot name=test>Test</slot></template> <template><div>test</div><slot name=test>Test</slot></template> <template><div>test</div><slot name=test>Test</slot></template> <template><slot>A</slot> B <slot>C</slot></template>
|
||||
<!doctype html><html lang=en><title>Document</title><body><template> <span>test</span> <slot name=test>Test</slot> </template><template> <span>test</span><slot name=test>Test</slot> </template><template><div>test</div><slot name=test>Test</slot> </template><template><div>test</div><slot name=test>Test</slot> </template><template> <slot>A</slot> B <slot>C</slot> </template>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<!doctype html>
|
||||
<template id="template">
|
||||
<slot name="a"><p>a</p></slot>
|
||||
<slot name="b"><span>test</span> <span>test</span></slot>
|
||||
<slot name="C"><div>test</div> <div>test</div></slot>
|
||||
</template>
|
@ -0,0 +1 @@
|
||||
<!doctype html><template id=template> <slot name=a><p>a</p></slot> <slot name=b><span>test</span> <span>test</span></slot> <slot name=C><div>test</div><div>test</div></slot> </template>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>element-details - web component using <template> and <slot></title>
|
||||
<style>
|
||||
dl { margin-left: 6px; }
|
||||
dt { font-weight: bold; color: #217ac0; font-size: 110% }
|
||||
dt { font-family: Consolas, "Liberation Mono", Courier }
|
||||
dd { margin-left: 16px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>element-details - web component using <code><template></code> and <code><slot></code></h1>
|
||||
|
||||
<template id="element-details-template-1">
|
||||
VALUE: !<slot>?</slot>!
|
||||
</template>
|
||||
|
||||
<element-details>
|
||||
<span>test</span> <span>foo</span>
|
||||
</element-details>
|
||||
|
||||
|
||||
<script>
|
||||
customElements.define('element-details',
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const template = document
|
||||
.getElementById('element-details-template-1')
|
||||
.content;
|
||||
const shadowRoot = this.attachShadow({mode: 'open'})
|
||||
.appendChild(template.cloneNode(true));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
<!doctype html><meta charset=utf-8><title>element-details - web component using <template> and <slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%}dt{font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code><template></code> and <code><slot></code></h1><template id=element-details-template-1> VALUE: !<slot>?</slot>! </template> <element-details> <span>test</span> <span>foo</span> </element-details> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let a=document.getElementById("element-details-template-1").content,b=this.attachShadow({mode:"open"}).appendChild(a.cloneNode(true))}})</script>
|
@ -1 +1 @@
|
||||
<!doctype html><meta charset=utf-8><title>element-details - web component using <template> and <slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%}dt{font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code><template></code> and <code><slot></code></h1><template id=element-details-template-1>VALUE: <slot name=q>?</slot></template> <template id=element-details-template-2>VALUE:<slot name=q>?</slot></template> <template id=element-details-template-3><div>VALUE:</div><slot name=q>?</slot></template> <element-details><span slot=q>1</span> </element-details><element-details> <span slot=q>2</span> </element-details><element-details-more> <span slot=q>3</span> </element-details-more><element-details-more> <span slot=q>4</span> </element-details-more><script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let a=document.getElementById("element-details-template-1").content,b=this.attachShadow({mode:"open"}).appendChild(a.cloneNode(true))}});customElements.define("element-details-more",class extends HTMLElement{constructor(){super();let a=document.getElementById("element-details-template-2").content,b=this.attachShadow({mode:"open"}).appendChild(a.cloneNode(true))}})</script>
|
||||
<!doctype html><meta charset=utf-8><title>element-details - web component using <template> and <slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%}dt{font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code><template></code> and <code><slot></code></h1><template id=element-details-template-1> VALUE: <slot name=q>?</slot> </template><template id=element-details-template-2> VALUE:<slot name=q>?</slot> </template><template id=element-details-template-3><div>VALUE:</div><slot name=q>?</slot> </template> <element-details> <span slot=q>1</span> </element-details> <element-details> <span slot=q>2</span> </element-details> <element-details-more> <span slot=q>3</span> </element-details-more> <element-details-more> <span slot=q>4</span> </element-details-more> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let a=document.getElementById("element-details-template-1").content,b=this.attachShadow({mode:"open"}).appendChild(a.cloneNode(true))}});customElements.define("element-details-more",class extends HTMLElement{constructor(){super();let a=document.getElementById("element-details-template-2").content,b=this.attachShadow({mode:"open"}).appendChild(a.cloneNode(true))}})</script>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<!doctype html>
|
||||
<span>test</span> <svg><text x="0" y="150" class="small">Мой</text> </svg> <span>a</span>
|
@ -0,0 +1 @@
|
||||
<!doctype html><span>test</span> <svg><text x=0 y=150 class=small>Мой</text></svg><span>a</span>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<!doctype html>
|
||||
<span>test</span><svg> a <text x="0" y="150" class="small">Мой</text></svg><span>a</span>
|
@ -0,0 +1 @@
|
||||
<!doctype html><span>test</span><svg> a<text x=0 y=150 class=small>Мой</text></svg><span>a</span>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
13
crates/swc_html_minifier/tests/fixture/text/svg-3/input.html
Normal file
13
crates/swc_html_minifier/tests/fixture/text/svg-3/input.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<svg width="350" height="60" xmlns="http://www.w3.org/2000/svg">
|
||||
<text>
|
||||
This is <tspan font-weight="bold" fill="red">bold and red</tspan> <tspan font-weight="bold" fill="red">bold and red</tspan>
|
||||
</text>
|
||||
|
||||
<style><![CDATA[
|
||||
text{
|
||||
dominant-baseline: hanging;
|
||||
font: 28px Verdana, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
]]></style>
|
||||
</svg>
|
@ -0,0 +1 @@
|
||||
<!doctype html><svg width=350 height=60><text>This is <tspan font-weight=bold fill=red>bold and red</tspan> <tspan font-weight=bold fill=red>bold and red</tspan></text><style>text{dominant-baseline:hanging;font:28px Verdana,Helvetica,Arial,sans-serif}</style></svg>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
96
crates/swc_html_minifier/tests/fixture/text/svg-4/input.html
Normal file
96
crates/swc_html_minifier/tests/fixture/text/svg-4/input.html
Normal file
@ -0,0 +1,96 @@
|
||||
<!doctype html>
|
||||
<svg>
|
||||
<a href=""> </a>
|
||||
<altGlyph> </altGlyph>
|
||||
<altGlyphDef> </altGlyphDef>
|
||||
<altGlyphItem> </altGlyphItem>
|
||||
<animate> </animate>
|
||||
<animateColor> </animateColor>
|
||||
<animateMotion> </animateMotion>
|
||||
<animateTransform> </animateTransform>
|
||||
<animation> </animation>
|
||||
<audio src=""></audio>
|
||||
<canvas> </canvas>
|
||||
<circle> </circle>
|
||||
<clipPath> </clipPath>
|
||||
<color-profile> </color-profile>
|
||||
<cursor> </cursor>
|
||||
<defs> </defs>
|
||||
<desc> </desc>
|
||||
<discard> </discard>
|
||||
<ellipse> </ellipse>
|
||||
<feBlend> </feBlend>
|
||||
<feColorMatrix> </feColorMatrix>
|
||||
<feComponentTransfer> </feComponentTransfer>
|
||||
<feComposite> </feComposite>
|
||||
<feConvolveMatrix> </feConvolveMatrix>
|
||||
<feDiffuseLighting> </feDiffuseLighting>
|
||||
<feDisplacementMap> </feDisplacementMap>
|
||||
<feDistantLight> </feDistantLight>
|
||||
<feDropShadow> </feDropShadow>
|
||||
<feFlood> </feFlood>
|
||||
<feFuncA> </feFuncA>
|
||||
<feFuncB> </feFuncB>
|
||||
<feFuncG> </feFuncG>
|
||||
<feFuncR> </feFuncR>
|
||||
<feGaussianBlur> </feGaussianBlur>
|
||||
<feImage> </feImage>
|
||||
<feMerge> </feMerge>
|
||||
<feMergeNode> </feMergeNode>
|
||||
<feMorphology> </feMorphology>
|
||||
<feOffset> </feOffset>
|
||||
<fePointLight> </fePointLight>
|
||||
<feSpecularLighting> </feSpecularLighting>
|
||||
<feSpotLight> </feSpotLight>
|
||||
<feTile> </feTile>
|
||||
<feTurbulence> </feTurbulence>
|
||||
<filter> </filter>
|
||||
<font> </font>
|
||||
<font-face> </font-face>
|
||||
<font-face-format> </font-face-format>
|
||||
<font-face-name> </font-face-name>
|
||||
<font-face-src> </font-face-src>
|
||||
<font-face-uri> </font-face-uri>
|
||||
<foreignObject> </foreignObject>
|
||||
<g> </g>
|
||||
<glyph> </glyph>
|
||||
<glyphRef> </glyphRef>
|
||||
<handler> </handler>
|
||||
<hkern> </hkern>
|
||||
<iframe src="" frameborder="0"></iframe>
|
||||
<image> </image>
|
||||
<line> </line>
|
||||
<linearGradient> </linearGradient>
|
||||
<listener> </listener>
|
||||
<marker> </marker>
|
||||
<mask> </mask>
|
||||
<metadata> </metadata>
|
||||
<missing-glyph> </missing-glyph>
|
||||
<mpath> </mpath>
|
||||
<path> </path>
|
||||
<pattern> </pattern>
|
||||
<polygon> </polygon>
|
||||
<polyline> </polyline>
|
||||
<prefetch> </prefetch>
|
||||
<radialGradient> </radialGradient>
|
||||
<rect> </rect>
|
||||
<script> </script>
|
||||
<set> </set>
|
||||
<solidColor> </solidColor>
|
||||
<stop> </stop>
|
||||
<style> </style>
|
||||
<svg> </svg>
|
||||
<switch> </switch>
|
||||
<symbol> </symbol>
|
||||
<tbreak> </tbreak>
|
||||
<text> </text>
|
||||
<textArea> </textArea>
|
||||
<textPath> </textPath>
|
||||
<title> </title>
|
||||
<tref> </tref>
|
||||
<tspan> </tspan>
|
||||
<unknown> </unknown>
|
||||
<use> </use>
|
||||
<video src=""></video>
|
||||
<view> </view>
|
||||
</svg>
|
@ -0,0 +1 @@
|
||||
<!doctype html><svg><a href="" /><altGlyph/><altGlyphDef/><altGlyphItem/><animate/><animateColor/><animateMotion/><animateTransform/><animation/><audio src="" /> <canvas/><circle> </circle><clipPath/><color-profile/><cursor/><defs/><desc/><discard/><ellipse> </ellipse><feBlend/><feColorMatrix/><feComponentTransfer/><feComposite/><feConvolveMatrix/><feDiffuseLighting/><feDisplacementMap/><feDistantLight/><feDropShadow/><feFlood/><feFuncA/><feFuncB/><feFuncG/><feFuncR/><feGaussianBlur/><feImage/><feMerge/><feMergeNode/><feMorphology/><feOffset/><fePointLight/><feSpecularLighting/><feSpotLight/><feTile/><feTurbulence/><filter/><font/><font-face/><font-face-format/><font-face-name/><font-face-src/><font-face-uri/><foreignObject/><g> </g><glyph/><glyphRef/><handler/><hkern/><iframe src="" frameborder=0 /> <image/><line> </line><linearGradient/><listener/><marker/><mask/><metadata/><missing-glyph/><mpath/><path> </path><pattern/><polygon> </polygon><polyline> </polyline><prefetch/><radialGradient/><rect> </rect><set/><solidcolor/><stop/><svg> </svg><switch> </switch><symbol> </symbol><tbreak/><text/><textarea/><textPath/><title/><tref/><tspan> </tspan><unknown/><use> </use><video src="" /> <view/></svg>
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"collapseWhitespaces": "smart"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<!doctype html>
|
||||
<span>test</span> <svg> <text x="0" y="150" class="small">Мой</text> </svg> <span>a</span>
|
@ -0,0 +1 @@
|
||||
<!doctype html><span>test</span> <svg><text x=0 y=150 class=small>Мой</text></svg><span>a</span>
|
@ -1 +1 @@
|
||||
<!doctype html><html lang=en><title>Document</title><div><span>test</span> <template><div>test</div></template> <template><div>test</div></template> <span>test</span></div><div><span>test</span><template><div>test</div></template> <template><div>test</div></template><span>test</span></div><div><span>test</span> <template><div>test</div></template><template><div>test</div></template><span>test</span></div><div><span>test</span><template><div>test</div></template><template><div>test</div></template> <span>test</span></div>
|
||||
<!doctype html><html lang=en><title>Document</title><div><span>test</span><template><div>test</div></template><template><div>test</div></template> <span>test</span></div><div><span>test</span><template><div>test</div></template><template><div>test</div></template><span>test</span></div><div><span>test</span><template><div>test</div></template><template><div>test</div></template><span>test</span></div><div><span>test</span><template><div>test</div></template><template><div>test</div></template> <span>test</span></div>
|
Loading…
Reference in New Issue
Block a user