From c45fef106ec4d1efdcd61a64c3dd3298272b3d99 Mon Sep 17 00:00:00 2001 From: Konv Suu <2583695112@qq.com> Date: Mon, 1 Dec 2025 11:25:11 +0800 Subject: [PATCH] Fix LWC attribute with `--embedded-language-formatting off` (#18383) Co-authored-by: fisker Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- changelog_unreleased/lwc/18383.md | 13 ++++++ src/language-html/embed/attribute.js | 15 +------ src/language-html/printer-html.js | 12 +++++- src/language-html/utilities/index.js | 21 ++++++++++ .../quotes/__snapshots__/format.test.js.snap | 42 +++++++++++++++++-- tests/format/lwc/attribute/quotes/quotes.html | 9 ++++ 6 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 changelog_unreleased/lwc/18383.md diff --git a/changelog_unreleased/lwc/18383.md b/changelog_unreleased/lwc/18383.md new file mode 100644 index 000000000..7ef64be48 --- /dev/null +++ b/changelog_unreleased/lwc/18383.md @@ -0,0 +1,13 @@ +#### Avoid quote around interpolations (#18383 by @kovsu) + + +```html + +
+ + +
+ + +
+``` diff --git a/src/language-html/embed/attribute.js b/src/language-html/embed/attribute.js index 2d89b625a..a7b56f81e 100644 --- a/src/language-html/embed/attribute.js +++ b/src/language-html/embed/attribute.js @@ -1,4 +1,5 @@ import { group, mapDoc } from "../../document/index.js"; +import { shouldUnquoteAttributeValue } from "../utilities/index.js"; import angularAttributePrinters from "./angular-attributes.js"; import { isClassNames, printClassNames } from "./class-names.js"; import { isEventHandler, printEventHandler } from "./event-handler.js"; @@ -43,19 +44,7 @@ function printAttribute(path, options) { return; } - const { valueSpan } = node; - const isQuoted = - valueSpan.end.offset - valueSpan.start.offset === value.length + 2; - - if ( - !isQuoted && - // lit-html: html`` - (/^PRETTIER_HTML_PLACEHOLDER_\d+_\d+_IN_JS$/u.test(value) || - // lwc: html`` - (options.parser === "lwc" && - value.startsWith("{") && - value.endsWith("}"))) - ) { + if (shouldUnquoteAttributeValue(node, options)) { return [node.rawName, "=", value]; } diff --git a/src/language-html/printer-html.js b/src/language-html/printer-html.js index 289634f1e..c60e1fc13 100644 --- a/src/language-html/printer-html.js +++ b/src/language-html/printer-html.js @@ -35,7 +35,11 @@ import { printOpeningTagStart, } from "./print/tag.js"; import preprocess from "./print-preprocess.js"; -import { getTextValueParts, unescapeQuoteEntities } from "./utilities/index.js"; +import { + getTextValueParts, + shouldUnquoteAttributeValue, + unescapeQuoteEntities, +} from "./utilities/index.js"; function genericPrint(path, options, print) { const { node } = path; @@ -128,8 +132,12 @@ function genericPrint(path, options, print) { if (node.value === null) { return node.rawName; } + const value = unescapeQuoteEntities(node.value); - const quote = getPreferredQuote(value, '"'); + const quote = shouldUnquoteAttributeValue(node, options) + ? "" + : getPreferredQuote(value, '"'); + return [ node.rawName, "=", diff --git a/src/language-html/utilities/index.js b/src/language-html/utilities/index.js index ec00e6262..266f2647b 100644 --- a/src/language-html/utilities/index.js +++ b/src/language-html/utilities/index.js @@ -600,6 +600,26 @@ function isVueScriptTag(node, options) { return isVueSfcBlock(node, options) && node.name === "script"; } +function isAttributeValueQuoted(node) { + const { valueSpan, value } = node; + return valueSpan.end.offset - valueSpan.start.offset === value.length + 2; +} + +function shouldUnquoteAttributeValue(node, options) { + if (isAttributeValueQuoted(node)) { + return false; + } + + const { value } = node; + + return ( + // Embedded HTML in JS: `` /* HTML */ `` `` + /^PRETTIER_HTML_PLACEHOLDER_\d+_\d+_IN_JS$/u.test(value) || + // LWC `
` + (options.parser === "lwc" && value.startsWith("{") && value.endsWith("}")) + ); +} + export { canHaveInterpolation, forceBreakChildren, @@ -629,5 +649,6 @@ export { isWhitespaceSensitiveNode, preferHardlineAsLeadingSpaces, shouldPreserveContent, + shouldUnquoteAttributeValue, unescapeQuoteEntities, }; diff --git a/tests/format/lwc/attribute/quotes/__snapshots__/format.test.js.snap b/tests/format/lwc/attribute/quotes/__snapshots__/format.test.js.snap index 19cf51248..e1f8a47f2 100644 --- a/tests/format/lwc/attribute/quotes/__snapshots__/format.test.js.snap +++ b/tests/format/lwc/attribute/quotes/__snapshots__/format.test.js.snap @@ -13,10 +13,28 @@ unquoted={data}>
-=====================================output===================================== -
+
-
+=====================================output===================================== +
+ +
+ +
================================================================================ `; @@ -33,10 +51,28 @@ unquoted={data}>
+
+ =====================================output=====================================
+
+ ================================================================================ `; diff --git a/tests/format/lwc/attribute/quotes/quotes.html b/tests/format/lwc/attribute/quotes/quotes.html index ad41f3f05..a254cabdb 100644 --- a/tests/format/lwc/attribute/quotes/quotes.html +++ b/tests/format/lwc/attribute/quotes/quotes.html @@ -3,3 +3,12 @@ unquoted={data}>
+ +