fix(html/minifier): Fix smart mode (#5058)

This commit is contained in:
Alexander Akait 2022-06-29 15:30:28 +03:00 committed by GitHub
parent 93cd38d113
commit e9bad20898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 610 additions and 210 deletions

View File

@ -1,5 +1,7 @@
#![deny(clippy::all)]
use std::mem::take;
use once_cell::sync::Lazy;
use serde_json::Value;
use swc_atoms::{js_word, JsWord};
@ -684,45 +686,51 @@ impl Minifier {
}
}
fn remove_whitespace_from_first_text_element(&self, node: &mut Child) {
match node {
Child::Text(text) => {
text.data = text.data.trim_start_matches(is_whitespace).into();
}
Child::Element(Element {
namespace,
tag_name,
children,
..
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
if let Some(last) = children.first_mut() {
self.remove_whitespace_from_first_text_element(last)
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();
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);
}
_ => {}
}
}
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();
}
}
Child::Element(Element {
namespace,
tag_name,
children,
..
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
self.remove_leading_and_trailing_whitespaces(children);
}
_ => {}
}
_ => {}
}
}
fn remove_whitespace_from_last_text_element(&self, node: &mut Child) {
match node {
Child::Text(text) => {
text.data = text.data.trim_end_matches(is_whitespace).into();
}
Child::Element(Element {
namespace,
tag_name,
children,
..
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
if let Some(last) = children.last_mut() {
self.remove_whitespace_from_last_text_element(last)
}
}
_ => {}
}
}
fn get_deep_last_text_element<'a>(&self, node: &'a mut Child) -> Option<&'a mut Text> {
fn get_deep_last_text_element<'a>(&self, node: &'a Child) -> Option<&'a Text> {
match node {
Child::Text(text) => Some(text),
Child::Element(Element {
@ -731,7 +739,7 @@ impl Minifier {
children,
..
}) if get_white_space(*namespace, tag_name) == WhiteSpace::Normal => {
if let Some(last) = children.last_mut() {
if let Some(last) = children.last() {
self.get_deep_last_text_element(last)
} else {
None
@ -741,6 +749,47 @@ impl Minifier {
}
}
fn get_prev_non_comment_node<'a>(
&self,
children: &'a Vec<Child>,
index: usize,
) -> Option<&'a Child> {
let prev = children.get(index);
match prev {
Some(Child::Comment(_)) if index >= 1 => {
self.get_prev_non_comment_node(children, index - 1)
}
Some(_) => prev,
_ => None,
}
}
fn get_next_non_comment_node<'a>(
&self,
children: &'a Vec<Child>,
index: usize,
) -> Option<&'a Child> {
let next = children.get(index);
match next {
Some(Child::Comment(_)) => self.get_next_non_comment_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,
mode: &CollapseWhitespaces,
@ -818,199 +867,232 @@ impl Minifier {
}
fn minify_children(&mut self, children: &mut Vec<Child>) {
let namespace = self.current_element.as_ref().unwrap().namespace;
let tag_name = &self.current_element.as_ref().unwrap().tag_name;
let (namespace, tag_name) = match &self.current_element {
Some(element) => (element.namespace, &element.tag_name),
_ => return,
};
let mode = self
.collapse_whitespaces
.as_ref()
.map(|mode| self.get_whitespace_minification_for_tag(mode, namespace, tag_name));
let mut index = 0;
let child_will_be_retained =
|child: &mut Child, prev: Option<&Child>, next: Option<&Child>| {
match child {
Child::Comment(comment) if self.remove_comments => {
self.is_preserved_comment(&comment.data)
}
// Always remove whitespaces from html and head elements (except nested
// elements), it should be safe
Child::Text(text)
if namespace == Namespace::HTML
&& matches!(&**tag_name, "html" | "head")
&& text.data.chars().all(is_whitespace) =>
{
false
}
Child::Text(text) if text.data.is_empty() => false,
Child::Text(text)
if !self.descendant_of_pre
&& get_white_space(namespace, tag_name) == WhiteSpace::Normal
&& mode.is_some() =>
{
let mode = mode.unwrap();
let mut is_smart_left_trim = false;
let mut is_smart_right_trim = false;
let mut cloned_children = None;
if self.collapse_whitespaces == Some(CollapseWhitespaces::Smart) {
let prev_display = if let Some(Child::Element(Element {
namespace,
tag_name,
..
})) = &prev
{
Some(self.get_display(*namespace, tag_name))
} else {
None
};
if mode.is_some() {
cloned_children = Some(children.clone());
}
is_smart_left_trim = match prev_display {
// Block-level containers:
//
// `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)
Some(
Display::Block
| Display::ListItem
| Display::Table
| Display::TableColumnGroup
| Display::TableCaption
| Display::TableColumn
| Display::TableRow
| Display::TableCell
| Display::TableHeaderGroup
| Display::TableRowGroup
| Display::TableFooterGroup,
) => true,
// Inline box
Some(Display::Inline) => {
if let Some(prev) = &prev {
let deep = self.get_deep_last_text_element(prev);
let mut prev = None;
let mut next = None;
if namespace == Namespace::HTML && &**tag_name == "body" {
if let Some(first) = children.first_mut() {
self.remove_whitespace_from_first_text_element(first);
}
if let Some(last) = children.last_mut() {
self.remove_whitespace_from_last_text_element(last)
}
}
children.retain_mut(|child| {
index += 1;
if mode.is_some() {
if let Some(cloned_children) = &cloned_children {
next = cloned_children.get(index);
}
}
let result = match child {
Child::Comment(comment) if self.remove_comments => {
self.is_preserved_comment(&comment.data)
}
// Always remove whitespaces from html and head elements (except nested elements),
// it should be safe
Child::Text(text)
if namespace == Namespace::HTML
&& matches!(&**tag_name, "html" | "head")
&& text.data.chars().all(is_whitespace) =>
{
false
}
Child::Text(text)
if !self.descendant_of_pre
&& get_white_space(namespace, &**tag_name) == WhiteSpace::Normal =>
{
let mut is_smart_left_trim = false;
let mut is_smart_right_trim = false;
if self.collapse_whitespaces == Some(CollapseWhitespaces::Smart) {
let prev_display = if let Some(Child::Element(Element {
namespace,
tag_name,
..
})) = &prev
{
Some(self.get_display(*namespace, &**tag_name))
} else {
None
};
is_smart_left_trim = match prev_display {
// Block-level containers:
//
// `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)
Some(
Display::Block
| Display::ListItem
| Display::Table
| Display::TableColumnGroup
| Display::TableCaption
| Display::TableColumn
| Display::TableRow
| Display::TableCell
| Display::TableHeaderGroup
| Display::TableRowGroup
| Display::TableFooterGroup,
) => true,
// Inline box
Some(Display::Inline) => {
let deep = self.get_deep_last_text_element(prev.as_mut().unwrap());
if let Some(deep) = deep {
deep.data.ends_with(is_whitespace)
} else {
false
}
}
// Inline level containers and etc
Some(_) => false,
None => {
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)
if let Some(deep) = deep {
deep.data.ends_with(is_whitespace)
} else {
false
}
} else {
false
}
_ => true,
}
}
};
// Inline level containers and etc
Some(_) => false,
None => {
let parent_display = self.get_display(namespace, tag_name);
let next_display = if let Some(Child::Element(Element {
namespace,
tag_name,
..
})) = &next
{
Some(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,
}
}
};
let next_display = if let Some(Child::Element(Element {
namespace,
tag_name,
..
})) = &next
{
Some(self.get_display(*namespace, tag_name))
} else {
None
};
is_smart_right_trim = match next_display {
// Block-level containers:
//
// `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)
Some(
Display::Block
| Display::ListItem
| Display::Table
| Display::TableColumnGroup
| Display::TableCaption
| Display::TableColumn
| Display::TableRow
| Display::TableCell
| Display::TableHeaderGroup
| Display::TableRowGroup
| Display::TableFooterGroup,
) => true,
Some(_) => false,
None => {
let parent_display = self.get_display(namespace, tag_name);
!matches!(parent_display, Display::Inline)
}
};
}
let mut value = if (mode.trim) || is_smart_left_trim {
text.data.trim_start_matches(is_whitespace)
} else {
None
&*text.data
};
is_smart_right_trim = match next_display {
// Block-level containers:
//
// `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)
Some(
Display::Block
| Display::ListItem
| Display::Table
| Display::TableColumnGroup
| Display::TableCaption
| Display::TableColumn
| Display::TableRow
| Display::TableCell
| Display::TableHeaderGroup
| Display::TableRowGroup
| Display::TableFooterGroup,
) => true,
Some(_) => false,
None => {
let parent_display = self.get_display(namespace, &**tag_name);
!matches!(parent_display, Display::Inline)
}
value = if (mode.trim) || is_smart_right_trim {
value.trim_end_matches(is_whitespace)
} else {
value
};
if value.is_empty() {
false
} else if mode.collapse {
text.data = self.collapse_whitespace(value).into();
true
} else {
text.data = value.into();
true
}
}
let mut value = if (mode.is_some() && mode.unwrap().trim) || is_smart_left_trim
{
text.data.trim_start_matches(is_whitespace)
} else {
&*text.data
};
value = if (mode.is_some() && mode.unwrap().trim) || is_smart_right_trim {
value.trim_end_matches(is_whitespace)
} else {
value
};
if value.is_empty() {
false
} else if mode.is_some() && mode.unwrap().collapse {
text.data = self.collapse_whitespace(value).into();
true
} else {
text.data = value.into();
true
}
_ => true,
}
_ => true,
};
if result && mode.is_some() {
prev = Some(child.clone());
let cloned_children = children.clone();
let mut index = 0;
let mut pending_text = vec![];
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());
index += 1;
return false;
}
Child::Text(text) if !pending_text.is_empty() => {
let mut new_value = String::new();
for text in take(&mut pending_text) {
new_value.push_str(&text);
}
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
};
let next = self.get_next_non_comment_node(&cloned_children, index + 1);
let result = child_will_be_retained(child, prev, next);
index += 1;
result
});
// Remove all leading and trailing whitespaces for the `body` element
if namespace == Namespace::HTML && tag_name == "body" {
self.remove_leading_and_trailing_whitespaces(children);
}
}
fn get_attribute_value(&self, attributes: &Vec<Attribute>, name: &str) -> Option<JsWord> {

View File

@ -79,5 +79,19 @@
According to the conditional comment this is not IE 5-9<br />
<!-- <![endif]-->
</p>
<div>a <!-- test --> b <!-- test --> c</div>
<div>
a
<!-- test -->
b
<!-- test -->
c
</div>
</body>
</html>

View File

@ -52,4 +52,18 @@
<!--[if !IE]> -->
According to the conditional comment this is not IE 5-9<br>
<!-- <![endif]-->
</p>
<div>a b c</div>
<div>
a
b
c
</div>

View File

@ -1,4 +1 @@
<!doctype html><html lang=en><title>Document</title><body>
<div>test</div>
<!doctype html><html lang=en><title>Document</title><div>test</div>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,8 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
<!-- a --> <!-- b --> <!-- c --><link>
</head>
<body><div>foo<div> baz </div> bar</div></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><link><div>foo<div>baz</div>bar</div>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<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 type="submit" [disabled]="!theForm.form.valid">Submit</button>
</form>
</body>
</html>

View File

@ -0,0 +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>

View File

@ -255,5 +255,36 @@
<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>
<!--test-->
</div></div>
<pre>
foo
<!-- bar -->
baz
</pre>
<div> a <input> c </div>
<div>Empty <!-- NOT --> </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 <!-- text --><!-- text --> b</div>
<div>a <!-- text --> b <!-- text --> c <!-- text --> d</div>
<div> <!-- test --> text <!-- test --></div>
<span> <!-- test --> text </span>
<span> text <!-- test --> </span>
</body>
</html>

View File

@ -25,4 +25,8 @@
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>foo</div><p><p>ab<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>
</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>foo</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>

View File

@ -255,5 +255,40 @@
<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><b> foo
</b></div>
<div><div>
<!--test-->
</div></div>
<pre>
foo
<!-- bar -->
baz
</pre>
<div> a <input> c </div>
<div>Empty <!-- NOT --> </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 <!-- text --><!-- text --> b</div>
<div>a <!-- text --> b <!-- text --> c <!-- text --> d</div>
<div> <!-- test --> text <!-- test --></div>
<span> <!-- test --> text </span>
<span> text <!-- test --> </span>
</body>
</html>

View File

@ -25,4 +25,8 @@
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</p> </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> <p>test</p> <p>test</p> </div> <div> <p>test</p> <p>test</p> <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</p> </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> <p>foo<img>bar</p> <p>foo <img>bar</p> <p>foo<img> bar</p> <p>foo <wbr> bar</p> <p>foo <br> bar</p> <p>foo <nobr>a</nobr> bar</p> <div> fo o </div> <div>foo</div> <p></p> <p>a b</p> <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> <p>foo<span></span></p> <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>
</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</p> </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> <p>test</p> <p>test</p> </div> <div> <p>test</p> <p>test</p> <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</p> </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> <p>foo<img>bar</p> <p>foo <img>bar</p> <p>foo<img> bar</p> <p>foo <wbr> bar</p> <p>foo <br> bar</p> <p>foo <nobr>a</nobr> bar</p> <div> fo o </div> <div>foo</div> <p></p> <p>a b</p> <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> <p>foo<span></span></p> <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><b> foo </b></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>

View File

@ -255,5 +255,36 @@
<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>
<!--test-->
</div></div>
<pre>
foo
<!-- bar -->
baz
</pre>
<div> a <input> c </div>
<div>Empty <!-- NOT --> </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 <!-- text --><!-- text --> b</div>
<div>a <!-- text --> b <!-- text --> c <!-- text --> d</div>
<div> <!-- test --> text <!-- test --></div>
<span> <!-- test --> text </span>
<span> text <!-- test --> </span>
</body>
</html>

View File

@ -25,4 +25,8 @@
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>foo</div><p><p>ab<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>
</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>foo</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>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,2 @@
<!doctype html>
<body></body>

View File

@ -0,0 +1 @@
<!doctype html>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,2 @@
<!doctype html>
<html><head></head><body></body></html>

View File

@ -0,0 +1 @@
<!doctype html>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1 @@
<!doctype html> <html></html>

View File

@ -0,0 +1 @@
<!doctype html>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1 @@
<!doctype html><html> </html>

View File

@ -0,0 +1 @@
<!doctype html>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1 @@
<!doctype html> <html> <body> </body> </html>

View File

@ -0,0 +1 @@
<!doctype html>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,2 @@
<!doctype html>
<html><body></body></html>

View File

@ -0,0 +1 @@
<!doctype html>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body><span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><span class=input-group-btn><button class="btn btn-default" type=button><span class="glyphicon glyphicon-search"></span></button></span>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>a<span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>a</body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title>a<span class=input-group-btn> <button class="btn btn-default" type=button><span class="glyphicon glyphicon-search"></span></button> </span>a

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body><button>a</button> <button>b</button></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><button>a</button> <button>b</button>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body><button>a</button><button>b</button></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><button>a</button><button>b</button>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body><p>where <math> <mi>R</mi> </math> is the Rici tensor.</p></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><p>where <math><mi>R</mi> </math>is the Rici tensor.

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<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>
</head>
<body>
<div>
<span>test</span><noscript><a href="#" onclick="javascript:">External Link</a></noscript>
</div>
<div>
<span>test</span><noscript> <a href="#" onclick="javascript:">External Link</a></noscript>
</div>
</body>
</html>

View File

@ -0,0 +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>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "conservative"
}

View File

@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body><span>test</span><select>
<option>foo</option>
<option>bar</option>
</select></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><span>test</span><select> <option>foo</option> <option>bar</option> </select>

View File

@ -0,0 +1,3 @@
{
"collapseWhitespaces": "smart"
}

View File

@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body><select>
<option>foo</option>
<option>bar</option>
</select></body>
</html>

View File

@ -0,0 +1 @@
<!doctype html><html lang=en><title>Document</title><select><option>foo<option>bar</select>