Skip to content

Commit

Permalink
fix(mrml-core): only void element should self close
Browse files Browse the repository at this point in the history
div is not a void element according to mdn so it should not self close.
With this fix, we only self close elements that are void elements.

Signed-off-by: Jérémie Drouet <[email protected]>
  • Loading branch information
jdrouet committed Apr 13, 2024
1 parent 5311e58 commit 1414252
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/mrml-core/lib/html-compare/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ fn compare_elements<'a>(
let ending = compare_attributes(cursor, expected.clone(), generated.clone())?;

if matches!(ending.end, HtmlElementEnd::Open)
&& !["br", "meta"].contains(&expected.local.as_str())
&& !matches!(expected.local.as_str(), "br" | "meta")
{
compare_all(cursor, &expected.local, expected.span, generated.span)?;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/mrml-core/resources/compare/success/mj-raw.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@
<span>Hello</span>
</div>
Something
<canvas />
<canvas></canvas>
<!-- some comment -->
<img src="some_url" />
</div>
</body>

</html>
</html>
8 changes: 4 additions & 4 deletions packages/mrml-core/src/mj_body/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ use crate::mj_table::NAME as MJ_TABLE;
use crate::mj_text::NAME as MJ_TEXT;
use crate::mj_wrapper::NAME as MJ_WRAPPER;
use crate::node::Node;
use crate::prelude::is_void_element;
use crate::prelude::parser::{
parse_attributes_map, should_ignore_children, Error, MrmlCursor, MrmlParser, MrmlToken,
ParseChildren, ParseElement,
parse_attributes_map, Error, MrmlCursor, MrmlParser, MrmlToken, ParseChildren, ParseElement,
};
#[cfg(feature = "async")]
use crate::prelude::parser::{AsyncMrmlParser, AsyncParseChildren, AsyncParseElement};
Expand All @@ -37,7 +37,7 @@ impl<'opts> ParseElement<Node<MjBodyChild>> for MrmlParser<'opts> {
let tag = tag.to_string();
let attributes = parse_attributes_map(cursor)?;
let ending = cursor.assert_element_end()?;
if ending.empty || should_ignore_children(tag.as_str()) {
if ending.empty || is_void_element(tag.as_str()) {
return Ok(Node {
tag,
attributes,
Expand Down Expand Up @@ -68,7 +68,7 @@ impl AsyncParseElement<Node<MjBodyChild>> for AsyncMrmlParser {
let tag = tag.to_string();
let attributes = parse_attributes_map(cursor)?;
let ending = cursor.assert_element_end()?;
if ending.empty || should_ignore_children(tag.as_str()) {
if ending.empty || is_void_element(tag.as_str()) {
return Ok(Node {
tag,
attributes,
Expand Down
12 changes: 6 additions & 6 deletions packages/mrml-core/src/mj_raw/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ use xmlparser::StrSpan;
use super::{MjRaw, MjRawChild};
use crate::comment::Comment;
use crate::node::Node;
use crate::prelude::parser::{
should_ignore_children, Error, MrmlCursor, MrmlParser, MrmlToken, ParseAttributes,
ParseChildren, ParseElement,
};
use crate::prelude::is_void_element;
#[cfg(feature = "async")]
use crate::prelude::parser::{AsyncMrmlParser, AsyncParseChildren, AsyncParseElement};
use crate::prelude::parser::{
Error, MrmlCursor, MrmlParser, MrmlToken, ParseAttributes, ParseChildren, ParseElement,
};
use crate::text::Text;

impl<'opts> ParseElement<Node<MjRawChild>> for MrmlParser<'opts> {
Expand All @@ -19,7 +19,7 @@ impl<'opts> ParseElement<Node<MjRawChild>> for MrmlParser<'opts> {
) -> Result<Node<MjRawChild>, Error> {
let attributes = self.parse_attributes(cursor)?;
let ending = cursor.assert_element_end()?;
if ending.empty || should_ignore_children(tag.as_str()) {
if ending.empty || is_void_element(tag.as_str()) {
return Ok(Node {
tag: tag.to_string(),
attributes,
Expand Down Expand Up @@ -49,7 +49,7 @@ impl AsyncParseElement<Node<MjRawChild>> for AsyncMrmlParser {
) -> Result<Node<MjRawChild>, Error> {
let attributes = self.parse_attributes(cursor)?;
let ending = cursor.assert_element_end()?;
if ending.empty || should_ignore_children(tag.as_str()) {
if ending.empty || is_void_element(tag.as_str()) {
return Ok(Node {
tag: tag.to_string(),
attributes,
Expand Down
15 changes: 9 additions & 6 deletions packages/mrml-core/src/node/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ use std::cell::{Ref, RefCell};
use std::rc::Rc;

use super::Node;
use crate::prelude::is_void_element;
use crate::prelude::render::{Error, Header, Render, RenderOptions, Renderable};

const SHOULD_SELF_CLOSE: [&str; 1] = ["script"];

struct NodeRender<'e, 'h, T> {
header: Rc<RefCell<Header<'h>>>,
element: &'e Node<T>,
Expand Down Expand Up @@ -33,10 +32,14 @@ where
buf.push_str(value);
buf.push('"');
}
if self.element.children.is_empty()
&& !SHOULD_SELF_CLOSE.contains(&self.element.tag.as_str())
{
buf.push_str(" />");
if self.element.children.is_empty() {
if is_void_element(self.element.tag.as_str()) {
buf.push_str(" />");
} else {
buf.push_str("></");
buf.push_str(&self.element.tag);
buf.push('>');
}
} else {
buf.push('>');
for (index, child) in self.element.children.iter().enumerate() {
Expand Down
22 changes: 22 additions & 0 deletions packages/mrml-core/src/prelude/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,25 @@ pub mod print;
pub mod render;

pub mod hash;

// see https://developer.mozilla.org/en-US/docs/Glossary/Void_element
#[cfg(any(feature = "parser", feature = "render"))]
pub(crate) fn is_void_element(tag: &str) -> bool {
matches!(
tag,
"area"
| "base"
| "br"
| "col"
| "embed"
| "hr"
| "img"
| "input"
| "link"
| "meta"
| "param"
| "source"
| "track"
| "wbr"
)
}
20 changes: 0 additions & 20 deletions packages/mrml-core/src/prelude/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,6 @@ pub mod memory_loader;
pub mod multi_loader;
pub mod noop_loader;

pub(crate) fn should_ignore_children(tag: &str) -> bool {
matches!(
tag,
"area"
| "base"
| "br"
| "col"
| "embed"
| "hr"
| "img"
| "input"
| "link"
| "meta"
| "param"
| "source"
| "track"
| "wbr"
)
}

#[derive(Clone, Debug, Default)]
pub struct Span {
pub start: usize,
Expand Down

0 comments on commit 1414252

Please sign in to comment.