From 8227c0a69e684c263a7733e2b98da319e4b4f22b Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Wed, 13 Dec 2023 16:13:26 +0800 Subject: [PATCH] Fix formatting of prettier-ignored unclosed elements (#15748) --- changelog_unreleased/html/15748.md | 18 ++++ src/language-html/print/children.js | 39 ++++++-- .../__snapshots__/jsfmt.spec.js.snap | 95 +++++++++++++++++++ .../html/prettier_ignore/issue-15738.html | 19 ++++ .../format/html/prettier_ignore/unclosed.html | 4 + .../html/prettier_ignore/unclosed2.html | 4 + 6 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 changelog_unreleased/html/15748.md create mode 100644 tests/format/html/prettier_ignore/issue-15738.html create mode 100644 tests/format/html/prettier_ignore/unclosed.html create mode 100644 tests/format/html/prettier_ignore/unclosed2.html diff --git a/changelog_unreleased/html/15748.md b/changelog_unreleased/html/15748.md new file mode 100644 index 000000000..46142fe3c --- /dev/null +++ b/changelog_unreleased/html/15748.md @@ -0,0 +1,18 @@ +#### Fix formatting of prettier-ignored unclosed elements (#15748 by @fisker) + + +```html + + +

+Hello world! + + + +

+ + + +

+Hello world! +``` diff --git a/src/language-html/print/children.js b/src/language-html/print/children.js index 1b44b8371..bdfb95feb 100644 --- a/src/language-html/print/children.js +++ b/src/language-html/print/children.js @@ -7,6 +7,8 @@ import { hardline, } from "../../document/builders.js"; import { replaceEndOfLine } from "../../document/utils.js"; +import isNonEmptyArray from "../../utils/is-non-empty-array.js"; +import htmlWhitespaceUtils from "../../utils/html-whitespace-utils.js"; import { locStart, locEnd } from "../loc.js"; import { forceBreakChildren, @@ -25,22 +27,41 @@ import { needsToBorrowParentClosingTagStartMarker, } from "./tag.js"; +function getEndLocation(node) { + const endLocation = locEnd(node); + + // Element can be unclosed + if ( + node.type === "element" && + !node.endSourceSpan && + isNonEmptyArray(node.children) + ) { + return Math.max(endLocation, getEndLocation(node.children.at(-1))); + } + + return endLocation; +} + function printChild(childPath, options, print) { const child = childPath.node; if (hasPrettierIgnore(child)) { + const endLocation = getEndLocation(child); + return [ printOpeningTagPrefix(child, options), replaceEndOfLine( - options.originalText.slice( - locStart(child) + - (child.prev && needsToBorrowNextOpeningTagStartMarker(child.prev) - ? printOpeningTagStartMarker(child).length - : 0), - locEnd(child) - - (child.next && needsToBorrowPrevClosingTagEndMarker(child.next) - ? printClosingTagEndMarker(child, options).length - : 0), + htmlWhitespaceUtils.trimEnd( + options.originalText.slice( + locStart(child) + + (child.prev && needsToBorrowNextOpeningTagStartMarker(child.prev) + ? printOpeningTagStartMarker(child).length + : 0), + endLocation - + (child.next && needsToBorrowPrevClosingTagEndMarker(child.next) + ? printClosingTagEndMarker(child, options).length + : 0), + ), ), ), printClosingTagSuffix(child, options), diff --git a/tests/format/html/prettier_ignore/__snapshots__/jsfmt.spec.js.snap b/tests/format/html/prettier_ignore/__snapshots__/jsfmt.spec.js.snap index 8daa5d9ea..77bc894ad 100644 --- a/tests/format/html/prettier_ignore/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/html/prettier_ignore/__snapshots__/jsfmt.spec.js.snap @@ -117,6 +117,60 @@ printWidth: 80 ================================================================================ `; +exports[`issue-15738.html format 1`] = ` +====================================options===================================== +parsers: ["html"] +printWidth: 80 + | printWidth +=====================================input====================================== + + + + + + +# Hello world! + +\`\`\`html +<p>Look at these <span id="html">HTML tags</span></p> +<div class="box">They aren't being <code>interpreted</code> as actual HTML</div> +\`\`\` + +But this HTML is <mark>actually parsed</mark> just like **normal**. + +> <em>Markdown</em> lets you include <strong>arbitrary</strong> <abbr>HTML</abbr> in it. + +=====================================output===================================== +<head></head> +<link + rel="stylesheet" + href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css" +/> +<style> + marked-md:not(:defined) { + display: none; + } +</style> +<script type="module" src="../auto.js"></script> +<!-- prettier-ignore --> +<marked-md display="block"><plaintext> +# Hello world! + +\`\`\`html +<p>Look at these <span id="html">HTML tags</span></p> +<div class="box">They aren't being <code>interpreted</code> as actual HTML</div> +\`\`\` + +But this HTML is <mark>actually parsed</mark> just like **normal**. + +> <em>Markdown</em> lets you include <strong>arbitrary</strong> <abbr>HTML</abbr> in it. + +================================================================================ +`; + exports[`long_lines.html format 1`] = ` ====================================options===================================== parsers: ["html"] @@ -160,3 +214,44 @@ A super long string that has been marked as ignore because it was probably gener ================================================================================ `; + +exports[`unclosed.html format 1`] = ` +====================================options===================================== +parsers: ["html"] +printWidth: 80 + | printWidth +=====================================input====================================== +<!-- prettier-ignore --> +<div> +# Hello world! +<span> + +=====================================output===================================== +<!-- prettier-ignore --> +<div> +# Hello world! +<span> + +================================================================================ +`; + +exports[`unclosed2.html format 1`] = ` +====================================options===================================== +parsers: ["html"] +printWidth: 80 + | printWidth +=====================================input====================================== +<!-- prettier-ignore --> +<p> +# Hello world! +<div> + +=====================================output===================================== +<!-- prettier-ignore --> +<p> +# Hello world! + +<div></div> + +================================================================================ +`; diff --git a/tests/format/html/prettier_ignore/issue-15738.html b/tests/format/html/prettier_ignore/issue-15738.html new file mode 100644 index 000000000..c954272c4 --- /dev/null +++ b/tests/format/html/prettier_ignore/issue-15738.html @@ -0,0 +1,19 @@ +<head></head> +<link + rel="stylesheet" + href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css" +/> +<style>marked-md:not(:defined) { display: none }</style> +<script type="module" src="../auto.js"></script> +<!-- prettier-ignore --> +<marked-md display="block"><plaintext> +# Hello world! + +```html +<p>Look at these <span id="html">HTML tags</span></p> +<div class="box">They aren't being <code>interpreted</code> as actual HTML</div> +``` + +But this HTML is <mark>actually parsed</mark> just like **normal**. + +> <em>Markdown</em> lets you include <strong>arbitrary</strong> <abbr>HTML</abbr> in it. diff --git a/tests/format/html/prettier_ignore/unclosed.html b/tests/format/html/prettier_ignore/unclosed.html new file mode 100644 index 000000000..1f8ac0f36 --- /dev/null +++ b/tests/format/html/prettier_ignore/unclosed.html @@ -0,0 +1,4 @@ +<!-- prettier-ignore --> +<div> +# Hello world! +<span> diff --git a/tests/format/html/prettier_ignore/unclosed2.html b/tests/format/html/prettier_ignore/unclosed2.html new file mode 100644 index 000000000..be70dabfc --- /dev/null +++ b/tests/format/html/prettier_ignore/unclosed2.html @@ -0,0 +1,4 @@ +<!-- prettier-ignore --> +<p> +# Hello world! +<div>