From 59c635b93971679a67e86b2d7c5259d64af47e75 Mon Sep 17 00:00:00 2001
From: fisker Cheung
Date: Tue, 6 May 2025 10:31:59 +0800
Subject: [PATCH] Correctly parse `` and `` (#17400)
---
changelog_unreleased/mjml/17400.md | 17 +++++++
src/language-html/parser-html.js | 8 ++-
tests/config/utils/check-parsers.js | 5 +-
.../mjml/__snapshots__/format.test.js.snap | 50 +++++++++++++++++++
tests/format/mjml/mjml/example.mjml | 19 +++++++
.../mj-raw/__snapshots__/format.test.js.snap | 38 ++++++++++++++
tests/format/mjml/parse/mj-raw/format.test.js | 3 ++
.../mjml/parse/mj-raw/invalid-in-html.mjml | 7 +++
.../__snapshots__/format.test.js.snap | 39 +++++++++++++++
.../format/mjml/parse/mj-style/format.test.js | 3 ++
.../mjml/parse/mj-style/invalid-in-html.mjml | 9 ++++
.../experimental-cli/test-0/should-format.js | 6 +++
.../test-0/should-not-format.js | 1 +
.../experimental-cli/test-1/should-format.js | 6 +++
.../test-1/should-not-format.js | 1 +
.../experimental-cli/test-2/should-format.js | 1 +
.../test-2/should-not-format.js | 1 +
.../experimental-cli/test-3/should-format.js | 1 +
.../test-3/should-not-format.js | 1 +
19 files changed, 214 insertions(+), 2 deletions(-)
create mode 100644 changelog_unreleased/mjml/17400.md
create mode 100644 tests/format/mjml/mjml/example.mjml
create mode 100644 tests/format/mjml/parse/mj-raw/__snapshots__/format.test.js.snap
create mode 100644 tests/format/mjml/parse/mj-raw/format.test.js
create mode 100644 tests/format/mjml/parse/mj-raw/invalid-in-html.mjml
create mode 100644 tests/format/mjml/parse/mj-style/__snapshots__/format.test.js.snap
create mode 100644 tests/format/mjml/parse/mj-style/format.test.js
create mode 100644 tests/format/mjml/parse/mj-style/invalid-in-html.mjml
create mode 100644 tests/integration/cli/experimental-cli/test-0/should-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-0/should-not-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-1/should-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-1/should-not-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-2/should-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-2/should-not-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-3/should-format.js
create mode 100644 tests/integration/cli/experimental-cli/test-3/should-not-format.js
diff --git a/changelog_unreleased/mjml/17400.md b/changelog_unreleased/mjml/17400.md
new file mode 100644
index 000000000..59f025afb
--- /dev/null
+++ b/changelog_unreleased/mjml/17400.md
@@ -0,0 +1,17 @@
+#### Correctly parse `` and `` (#17400 by @fisker)
+
+
+```html
+
+
+ a::before {
+ content: "
";
+ }
+
+
+
+SyntaxError: Unexpected closing tag "p".
+
+
+Correctly parsed as CSS.
+```
diff --git a/src/language-html/parser-html.js b/src/language-html/parser-html.js
index 9aab2030a..28be3609b 100644
--- a/src/language-html/parser-html.js
+++ b/src/language-html/parser-html.js
@@ -445,8 +445,14 @@ const HTML_PARSE_OPTIONS = {
// HTML
export const html = createParser(HTML_PARSE_OPTIONS);
+
+const MJML_RAW_TAGS = new Set(["mj-style", "mj-raw"]);
// MJML https://mjml.io/
-export const mjml = createParser({ ...HTML_PARSE_OPTIONS, name: "mjml" });
+export const mjml = createParser({
+ ...HTML_PARSE_OPTIONS,
+ name: "mjml",
+ shouldParseAsRawText: (tagName) => MJML_RAW_TAGS.has(tagName),
+});
// Angular
export const angular = createParser({ name: "angular" });
// Vue
diff --git a/tests/config/utils/check-parsers.js b/tests/config/utils/check-parsers.js
index 02f3717fd..ede5d8c98 100644
--- a/tests/config/utils/check-parsers.js
+++ b/tests/config/utils/check-parsers.js
@@ -50,7 +50,10 @@ const categoryParsers = new Map([
"html",
{ parsers: ["html"], verifyParsers: [], extensions: [".html", ".svg"] },
],
- ["mjml", { parsers: ["mjml"], verifyParsers: [], extensions: [".mjml"] }],
+ [
+ "mjml",
+ { parsers: ["mjml"], verifyParsers: ["html"], extensions: [".mjml"] },
+ ],
[
"js",
{
diff --git a/tests/format/mjml/mjml/__snapshots__/format.test.js.snap b/tests/format/mjml/mjml/__snapshots__/format.test.js.snap
index eb7bd3760..03b6b1e5f 100644
--- a/tests/format/mjml/mjml/__snapshots__/format.test.js.snap
+++ b/tests/format/mjml/mjml/__snapshots__/format.test.js.snap
@@ -13,6 +13,56 @@ printWidth: 80
================================================================================
`;
+exports[`example.mjml format 1`] = `
+====================================options=====================================
+parsers: ["mjml"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+
+=====================================output=====================================
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+================================================================================
+`;
+
exports[`head.mjml format 1`] = `
====================================options=====================================
parsers: ["mjml"]
diff --git a/tests/format/mjml/mjml/example.mjml b/tests/format/mjml/mjml/example.mjml
new file mode 100644
index 000000000..2c0dc58bd
--- /dev/null
+++ b/tests/format/mjml/mjml/example.mjml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
diff --git a/tests/format/mjml/parse/mj-raw/__snapshots__/format.test.js.snap b/tests/format/mjml/parse/mj-raw/__snapshots__/format.test.js.snap
new file mode 100644
index 000000000..1856c08a6
--- /dev/null
+++ b/tests/format/mjml/parse/mj-raw/__snapshots__/format.test.js.snap
@@ -0,0 +1,38 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`invalid-in-html.mjml [html] format 1`] = `
+"Unexpected closing tag "p". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags (3:9)
+ 1 |
+ 2 | Wrapped
+> 3 |
+ | ^^^^
+ 4 |
+ 5 |
+ 6 | WRAPPED"
+`;
+
+exports[`invalid-in-html.mjml format 1`] = `
+====================================options=====================================
+parsers: ["mjml", "html"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+
+Wrapped
+
+
+
+WRAPPED
+
+
+=====================================output=====================================
+
+Wrapped
+
+
+
+WRAPPED
+
+
+================================================================================
+`;
diff --git a/tests/format/mjml/parse/mj-raw/format.test.js b/tests/format/mjml/parse/mj-raw/format.test.js
new file mode 100644
index 000000000..e10c3bafd
--- /dev/null
+++ b/tests/format/mjml/parse/mj-raw/format.test.js
@@ -0,0 +1,3 @@
+runFormatTest(import.meta, ["mjml", "html"], {
+ errors: { html: ["invalid-in-html.mjml"] },
+});
diff --git a/tests/format/mjml/parse/mj-raw/invalid-in-html.mjml b/tests/format/mjml/parse/mj-raw/invalid-in-html.mjml
new file mode 100644
index 000000000..e5a22ece3
--- /dev/null
+++ b/tests/format/mjml/parse/mj-raw/invalid-in-html.mjml
@@ -0,0 +1,7 @@
+
+Wrapped
+
+
+
+WRAPPED
+
diff --git a/tests/format/mjml/parse/mj-style/__snapshots__/format.test.js.snap b/tests/format/mjml/parse/mj-style/__snapshots__/format.test.js.snap
new file mode 100644
index 000000000..b13d71ac8
--- /dev/null
+++ b/tests/format/mjml/parse/mj-style/__snapshots__/format.test.js.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`invalid-in-html.mjml [html] format 1`] = `
+"Unexpected closing tag "p". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags (2:25)
+ 1 |
+> 2 | a::before { content: "";
+ | ^^^^
+ 3 | }
+ 4 |
+ 5 |"
+`;
+
+exports[`invalid-in-html.mjml format 1`] = `
+====================================options=====================================
+parsers: ["mjml", "html"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+
+ a::before { content: "";
+ }
+
+
+
+ a::before { content: "";
+ }
+
+
+=====================================output=====================================
+
+ a::before {
+ content: "";
+ }
+
+
+ a::before { content: ""; }
+
+================================================================================
+`;
diff --git a/tests/format/mjml/parse/mj-style/format.test.js b/tests/format/mjml/parse/mj-style/format.test.js
new file mode 100644
index 000000000..e10c3bafd
--- /dev/null
+++ b/tests/format/mjml/parse/mj-style/format.test.js
@@ -0,0 +1,3 @@
+runFormatTest(import.meta, ["mjml", "html"], {
+ errors: { html: ["invalid-in-html.mjml"] },
+});
diff --git a/tests/format/mjml/parse/mj-style/invalid-in-html.mjml b/tests/format/mjml/parse/mj-style/invalid-in-html.mjml
new file mode 100644
index 000000000..d83271a3c
--- /dev/null
+++ b/tests/format/mjml/parse/mj-style/invalid-in-html.mjml
@@ -0,0 +1,9 @@
+
+ a::before { content: "";
+ }
+
+
+
+ a::before { content: "";
+ }
+
diff --git a/tests/integration/cli/experimental-cli/test-0/should-format.js b/tests/integration/cli/experimental-cli/test-0/should-format.js
new file mode 100644
index 000000000..994d8a206
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-0/should-format.js
@@ -0,0 +1,6 @@
+
+ console.log(
+"Hello, world!"
+
+
+ )
diff --git a/tests/integration/cli/experimental-cli/test-0/should-not-format.js b/tests/integration/cli/experimental-cli/test-0/should-not-format.js
new file mode 100644
index 000000000..a8141d3b1
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-0/should-not-format.js
@@ -0,0 +1 @@
+console.log("Hello, world!");
diff --git a/tests/integration/cli/experimental-cli/test-1/should-format.js b/tests/integration/cli/experimental-cli/test-1/should-format.js
new file mode 100644
index 000000000..994d8a206
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-1/should-format.js
@@ -0,0 +1,6 @@
+
+ console.log(
+"Hello, world!"
+
+
+ )
diff --git a/tests/integration/cli/experimental-cli/test-1/should-not-format.js b/tests/integration/cli/experimental-cli/test-1/should-not-format.js
new file mode 100644
index 000000000..a8141d3b1
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-1/should-not-format.js
@@ -0,0 +1 @@
+console.log("Hello, world!");
diff --git a/tests/integration/cli/experimental-cli/test-2/should-format.js b/tests/integration/cli/experimental-cli/test-2/should-format.js
new file mode 100644
index 000000000..a8141d3b1
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-2/should-format.js
@@ -0,0 +1 @@
+console.log("Hello, world!");
diff --git a/tests/integration/cli/experimental-cli/test-2/should-not-format.js b/tests/integration/cli/experimental-cli/test-2/should-not-format.js
new file mode 100644
index 000000000..a8141d3b1
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-2/should-not-format.js
@@ -0,0 +1 @@
+console.log("Hello, world!");
diff --git a/tests/integration/cli/experimental-cli/test-3/should-format.js b/tests/integration/cli/experimental-cli/test-3/should-format.js
new file mode 100644
index 000000000..a8141d3b1
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-3/should-format.js
@@ -0,0 +1 @@
+console.log("Hello, world!");
diff --git a/tests/integration/cli/experimental-cli/test-3/should-not-format.js b/tests/integration/cli/experimental-cli/test-3/should-not-format.js
new file mode 100644
index 000000000..a8141d3b1
--- /dev/null
+++ b/tests/integration/cli/experimental-cli/test-3/should-not-format.js
@@ -0,0 +1 @@
+console.log("Hello, world!");