Handlebars: Fix invalid output for <style> containing mustaches (#20030)

Co-authored-by: fisker <lionkay@gmail.com>
This commit is contained in:
Konv Suuandfisker authored and GitHub committed 2026-09-11 18:09:38 +08:00
1 parent 3014654149
commit c150b07c07
8 files changed
+105 -16

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
#### Fix invalid output for `<style>` containing mustaches (#20030 by @kovsu)
<!-- prettier-ignore -->
```hbs
{{! Input }}
<style>
a {
color: {{foo}}
}
</style>
{{! Prettier stable }}
<style>
a {
color:{{foo}}}
</style>
{{! Prettier main }}
<style>
a { color:
{{foo}}
}
</style>
```
+3 -6
View File
@@ -1,3 +1,5 @@
import { isPlainTextStyleElement } from "./utilities.js";
function embed(path /* , options*/) {
const { node } = path;
@@ -7,12 +9,7 @@ function embed(path /* , options*/) {
const { parent } = path;
if (!(
parent.type === "ElementNode" &&
parent.tag === "style" &&
parent.children.length === 1 &&
parent.children[0] === node
)) {
if (!(isPlainTextStyleElement(parent) && parent.children[0] === node)) {
return;
}
+2 -5
View File
@@ -1,4 +1,5 @@
import htmlWhitespace from "../../utilities/html-whitespace.js";
import { isPlainTextStyleElement } from "../utilities.js";
function massageAstNode(original, cloned, parent) {
// (Glimmer/HTML) ignore TextNode
@@ -9,11 +10,7 @@ function massageAstNode(original, cloned, parent) {
}
// CSS will be formatted
if (
parent.tag === "style" &&
parent.children.length === 1 &&
parent.children[0] === original
) {
if (isPlainTextStyleElement(parent) && parent.children[0] === original) {
cloned.chars = "";
} else {
cloned.chars = htmlWhitespace.split(trimmed).join(" ");
+5 -4
View File
@@ -20,6 +20,7 @@ import { locEnd, locStart } from "./loc.js";
import { massageAstNode } from "./massage-ast/index.js";
import {
hasPrettierIgnore,
isPlainTextStyleElement,
isVoidElement,
isWhitespaceNode,
} from "./utilities.js";
@@ -59,11 +60,11 @@ function print(path, options, print) {
}
const endingTag = ["</", node.tag, ">"];
const isStyle = node.tag === "style";
const isPlainStyle = isPlainTextStyleElement(node);
if (
node.children.length === 0 ||
((!isWhitespaceSensitive || isStyle) &&
((!isWhitespaceSensitive || isPlainStyle) &&
node.children.every((node) => isWhitespaceNode(node)))
) {
return [startingTag, endingTag];
@@ -71,7 +72,7 @@ function print(path, options, print) {
const parts = path.map(print, "children");
if (isStyle || !isWhitespaceSensitive) {
if (isPlainStyle || !isWhitespaceSensitive) {
return [startingTag, indent([softline, ...parts]), softline, endingTag];
}
@@ -172,7 +173,7 @@ function print(path, options, print) {
return replaceEndOfLine(text);
}
if (parent.tag === "style") {
if (isPlainTextStyleElement(parent)) {
text = text.replaceAll(/^\n+/g, "");
text = htmlWhitespace.trimEnd(text);
text = htmlWhitespace.dedentString(text);
+18 -1
View File
@@ -34,6 +34,18 @@ function isWhitespaceNode(node) {
return node.type === "TextNode" && !/\S/.test(node.chars);
}
function isPlainTextElement(node) {
return (
node.type === "ElementNode" &&
node.children.length === 1 &&
node.children[0].type === "TextNode"
);
}
function isPlainTextStyleElement(node) {
return isPlainTextElement(node) && node.tag === "style";
}
function isPrettierIgnoreNode(node) {
return (
node?.type === "MustacheCommentStatement" &&
@@ -53,4 +65,9 @@ function hasPrettierIgnore(path) {
);
}
export { hasPrettierIgnore, isVoidElement, isWhitespaceNode };
export {
hasPrettierIgnore,
isPlainTextStyleElement,
isVoidElement,
isWhitespaceNode,
};
@@ -13,10 +13,14 @@ parsers: ["glimmer"]
</style>
</div>
<style></style>
=====================================output=====================================
<div>
<style></style>
</div>
<style></style>
================================================================================
`;
@@ -195,3 +199,38 @@ parsers: ["glimmer"]
</style>
================================================================================
`;
exports[`with-mustache.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80 (default) |
=====================================input======================================
<style>
a {
color: {{foo}}
}
</style>
<style>
.a { color: {{color}}; }
{{#if debug}}.b { color: red; }{{/if}}
</style>
<style>{{foo}}</style>
=====================================output=====================================
<style>
a { color:
{{foo}}
}
</style>
<style>
.a { color:
{{color}}; }
{{#if debug}}.b { color: red; }{{/if}}
</style>
<style>{{foo}}</style>
================================================================================
`;
@@ -5,3 +5,5 @@
</style>
</div>
<style></style>
@@ -0,0 +1,12 @@
<style>
a {
color: {{foo}}
}
</style>
<style>
.a { color: {{color}}; }
{{#if debug}}.b { color: red; }{{/if}}
</style>
<style>{{foo}}</style>