feat(html/codegen): Omit end tags (#4770)

This commit is contained in:
Alexander Akait 2022-05-24 15:54:12 +03:00 committed by GitHub
parent f4d828feaf
commit 07c197f51c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 7 deletions

View File

@ -136,8 +136,12 @@ where
formatting_newline!(self);
}
#[emitter]
fn emit_element(&mut self, n: &Element) -> Result {
fn basic_emit_element(
&mut self,
n: &Element,
_parent: Option<&Element>,
next: Option<&Child>,
) -> Result {
write_raw!(self, "<");
write_raw!(self, &n.tag_name);
@ -200,11 +204,69 @@ where
..self.ctx
};
self.with_ctx(ctx)
.emit_list(&n.children, ListFormat::NotDelimited)?;
if self.config.minify {
self.with_ctx(ctx)
.emit_list_for_tag_omission(n, &n.children)?;
} else {
self.with_ctx(ctx)
.emit_list(&n.children, ListFormat::NotDelimited)?;
}
}
if self.is_plaintext {
let can_omit_end_tag = self.is_plaintext
|| (self.config.minify
&& n.namespace == Namespace::HTML
&& match &*n.tag_name {
// Tag omission in text/html:
// An li element's end tag can be omitted if the li element is immediately
// followed by another li element or if there is no more content in the parent
// element.
"li" => match next {
Some(Child::Element(Element {
namespace,
tag_name,
..
})) if *namespace == Namespace::HTML && tag_name == "li" => true,
None => true,
_ => false,
},
// A dt element's end tag can be omitted if the dt element is immediately
// followed by another dt element or a dd element.
"dt" => match next {
Some(Child::Element(Element {
namespace,
tag_name,
..
})) if *namespace == Namespace::HTML
&& (tag_name == "dt" || tag_name == "dd") =>
{
true
}
_ => false,
},
// A dd element's end tag can be omitted if the dd element is immediately
// followed by another dd element or a dt element, or if there is no more
// content in the parent element.
"dd" => match next {
Some(Child::Element(Element {
namespace,
tag_name,
..
})) if *namespace == Namespace::HTML
&& (tag_name == "dd" || tag_name == "dt") =>
{
true
}
None => true,
_ => false,
},
_ => false,
});
if can_omit_end_tag {
return Ok(());
}
@ -212,6 +274,13 @@ where
write_raw!(self, "/");
write_raw!(self, &n.tag_name);
write_raw!(self, ">");
Ok(())
}
#[emitter]
fn emit_element(&mut self, n: &Element) -> Result {
self.basic_emit_element(n, None, None)?;
}
#[emitter]
@ -565,6 +634,23 @@ where
Ok(())
}
fn emit_list_for_tag_omission(&mut self, parent: &Element, nodes: &[Child]) -> Result {
for (idx, node) in nodes.iter().enumerate() {
match node {
Child::Element(element) => {
let next = nodes.get(idx + 1);
self.basic_emit_element(element, Some(parent), next)?;
}
_ => {
emit!(self, node)
}
}
}
Ok(())
}
fn write_delim(&mut self, f: ListFormat) -> Result {
match f & ListFormat::DelimitersMask {
ListFormat::None => {}

View File

@ -425,6 +425,7 @@ fn test_indent_type_option(input: PathBuf) {
);
}
// TODO minified verification
#[testing::fixture("../swc_html_parser/tests/fixture/**/*.html")]
fn parser_verify(input: PathBuf) {
verify_document(&input, None, None, None, false);

View File

@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head><title>Document</title></head><body>
<ul><li>test</li></ul>
<ul> <li>test</li> </ul>
<ul> <li>test</li> <li>test</li> </ul>
<ul> <li>test</li> <li>test</li></ul>
<ul><li>test</li><li>test</li><li>test</li></ul>
<ul><li>test</li><li>test</li> <li>test</li> </ul>
<article>
<h1>FAQ</h1>
<dl><dt>What do we want?</dt><dd>Our data.</dd><dt>When do we want it?</dt><dd>Now.</dd><dt>Where is it?</dt><dd>We are not sure.</dd></dl>
</article>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head><title>Document</title></head><body>
<ul><li>test</li></ul>
<ul> <li>test</li> </ul>
<ul> <li>test</li> <li>test</li> </ul>
<ul> <li>test</li> <li>test</li></ul>
<ul><li>test</li><li>test</li><li>test</li></ul>
<ul><li>test</li><li>test</li> <li>test</li> </ul>
<article>
<h1>FAQ</h1>
<dl><dt>What do we want?</dt><dd>Our data.</dd><dt>When do we want it?</dt><dd>Now.</dd><dt>Where is it?</dt><dd>We are not sure.</dd></dl>
</article>
</body></html>

View File

@ -0,0 +1,16 @@
<!doctype html><html lang=en><head><title>Document</title></head><body>
<ul><li>test</ul>
<ul> <li>test</li> </ul>
<ul> <li>test</li> <li>test</li> </ul>
<ul> <li>test</li> <li>test</ul>
<ul><li>test<li>test<li>test</ul>
<ul><li>test<li>test</li> <li>test</li> </ul>
<article>
<h1>FAQ</h1>
<dl><dt>What do we want?<dd>Our data.<dt>When do we want it?<dd>Now.<dt>Where is it?<dd>We are not sure.</dl>
</article>
</body></html>

View File

@ -2,7 +2,7 @@
<body>
<p>For more information, read <a href=https://stackoverflow.com/questions/17408815/fieldset-resizes-wrong-appears-to-have-unremovable-min-width-min-content/17863685#17863685>this Stack Overflow answer</a>.</p>
<p>a</p><div>b</div>
<p>a</p><ul><li>item</li></ul>
<p>a</p><ol><li>item</li></ol>
<p>a</p><ul><li>item</ul>
<p>a</p><ol><li>item</ol>
</body></html>