diff --git a/changelog_unreleased/angular/20001.md b/changelog_unreleased/angular/20001.md
new file mode 100644
index 000000000..831fdfa59
--- /dev/null
+++ b/changelog_unreleased/angular/20001.md
@@ -0,0 +1,23 @@
+#### Avoid adding blank lines to interpolations (#20001 by @vzer200)
+
+
+```html
+
+
+ ({{ a
+ }})
+
+
+
+
+ ({{ a
+
+ }})
+
+
+
+
+ ({{ a
+ }})
+
+```
diff --git a/changelog_unreleased/vue/20001-2.md b/changelog_unreleased/vue/20001-2.md
new file mode 100644
index 000000000..a1ca1db4a
--- /dev/null
+++ b/changelog_unreleased/vue/20001-2.md
@@ -0,0 +1,29 @@
+#### Avoid adding blank lines to interpolations (#20001 by @vzer200)
+
+
+```html
+
+
+
+ ({{ a
+ }})
+
+
+
+
+
+
+ ({{ a
+
+ }})
+
+
+
+
+
+
+ ({{ a
+ }})
+
+
+```
diff --git a/src/language-html/printer-html.js b/src/language-html/printer-html.js
index 8c568cca7..dc43ec65b 100644
--- a/src/language-html/printer-html.js
+++ b/src/language-html/printer-html.js
@@ -3,6 +3,7 @@
*/
import {
+ breakParent,
fill,
group,
hardline,
@@ -30,6 +31,7 @@ import { printChildren } from "./print/children.js";
import { printElement } from "./print/element.js";
import { printStartTagComment } from "./print/start-tag-comment.js";
import {
+ needsToBorrowPrevClosingTagEndMarker,
printClosingTagEnd,
printClosingTagSuffix,
printOpeningTagPrefix,
@@ -90,13 +92,30 @@ function genericPrint(path, options, print) {
];
case "text": {
if (node.parent.kind === "interpolation") {
+ let { value } = node;
// replace the trailing literalline with hardline for better readability
const trailingNewlineRegex = /\n[^\S\n]*$/;
- const hasTrailingNewline = trailingNewlineRegex.test(node.value);
- const value = hasTrailingNewline
- ? node.value.replace(trailingNewlineRegex, "")
- : node.value;
- return [replaceEndOfLine(value), hasTrailingNewline ? hardline : ""];
+ const hasTrailingNewline = trailingNewlineRegex.test(value);
+
+ if (hasTrailingNewline) {
+ value = value.replace(trailingNewlineRegex, "");
+ }
+
+ const parts = [replaceEndOfLine(value)];
+
+ if (hasTrailingNewline) {
+ // The interpolation's trailing softline already prints this newline.
+ if (
+ node.parent.next &&
+ needsToBorrowPrevClosingTagEndMarker(node.parent.next)
+ ) {
+ parts.push(breakParent);
+ } else {
+ parts.push(hardline);
+ }
+ }
+
+ return parts;
}
const prefix = printOpeningTagPrefix(node, options);
diff --git a/tests/format/angular/interpolation/embedded-language-formatting-off/__snapshots__/format.test.js.snap b/tests/format/angular/interpolation/embedded-language-formatting-off/__snapshots__/format.test.js.snap
new file mode 100644
index 000000000..8f7b9ff16
--- /dev/null
+++ b/tests/format/angular/interpolation/embedded-language-formatting-off/__snapshots__/format.test.js.snap
@@ -0,0 +1,87 @@
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
+
+exports[`siblings.html - {"embeddedLanguageFormatting":"off"} format 1`] = `
+====================================options=====================================
+embeddedLanguageFormatting: "off"
+parsers: ["angular"]
+ printWidth: 80 (default) |
+=====================================input======================================
+{{ a
+}}
+{{ a
+}} text
+{{ a
+}}text
+{{ a
+}}
+{{ a
+}}{{ b }}
+({{ a
+
+}})
+
+=====================================output=====================================
+
+ {{ a
+ }}
+
+
+ {{ a
+ }}
+ text
+
+
+ {{ a
+ }}text
+
+
+ {{ a
+ }}
+
+
+ {{ a
+ }}{{ b }}
+
+
+ ({{ a
+
+ }})
+
+
+================================================================================
+`;
+
+exports[`trailing-newline.html - {"embeddedLanguageFormatting":"off"} format 1`] = `
+====================================options=====================================
+embeddedLanguageFormatting: "off"
+parsers: ["angular"]
+ printWidth: 80 (default) |
+=====================================input======================================
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ({{ a }})
+
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ({{ a
+ }})
+
+
+ ({{ a
+ }})
+
+
+=====================================output=====================================
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ({{ a
+ }})
+
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ({{ a
+ }})
+
+
+ ({{ a
+ }})
+
+
+================================================================================
+`;
diff --git a/tests/format/angular/interpolation/embedded-language-formatting-off/format.test.js b/tests/format/angular/interpolation/embedded-language-formatting-off/format.test.js
new file mode 100644
index 000000000..4b1453b04
--- /dev/null
+++ b/tests/format/angular/interpolation/embedded-language-formatting-off/format.test.js
@@ -0,0 +1 @@
+runFormatTest(import.meta, ["angular"], { embeddedLanguageFormatting: "off" });
diff --git a/tests/format/angular/interpolation/embedded-language-formatting-off/siblings.html b/tests/format/angular/interpolation/embedded-language-formatting-off/siblings.html
new file mode 100644
index 000000000..3142ca5ef
--- /dev/null
+++ b/tests/format/angular/interpolation/embedded-language-formatting-off/siblings.html
@@ -0,0 +1,13 @@
+{{ a
+}}
+{{ a
+}} text
+{{ a
+}}text
+{{ a
+}}
+{{ a
+}}{{ b }}
+({{ a
+
+}})
diff --git a/tests/format/angular/interpolation/embedded-language-formatting-off/trailing-newline.html b/tests/format/angular/interpolation/embedded-language-formatting-off/trailing-newline.html
new file mode 100644
index 000000000..0d974fbba
--- /dev/null
+++ b/tests/format/angular/interpolation/embedded-language-formatting-off/trailing-newline.html
@@ -0,0 +1,11 @@
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ({{ a }})
+
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ({{ a
+ }})
+
+
+ ({{ a
+ }})
+
diff --git a/tests/format/vue/interpolation/embedded-language-formatting-off/__snapshots__/format.test.js.snap b/tests/format/vue/interpolation/embedded-language-formatting-off/__snapshots__/format.test.js.snap
new file mode 100644
index 000000000..274be07f6
--- /dev/null
+++ b/tests/format/vue/interpolation/embedded-language-formatting-off/__snapshots__/format.test.js.snap
@@ -0,0 +1,45 @@
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
+
+exports[`trailing-newline.vue - {"embeddedLanguageFormatting":"off"} format 1`] = `
+====================================options=====================================
+embeddedLanguageFormatting: "off"
+parsers: ["vue"]
+ printWidth: 80 (default) |
+=====================================input======================================
+
+
+ {{
+ (
+ something.something.very.long.code ??
+ fail("this is even longer to enforce multiple lines")
+ ).toUpperCase()
+ }}.
+
+ ({{ a
+ }})
+ {{ a
+ }}
+
+
+=====================================output=====================================
+
+
+ {{
+ (
+ something.something.very.long.code ??
+ fail("this is even longer to enforce multiple lines")
+ ).toUpperCase()
+ }}.
+
+
+ ({{ a
+ }})
+
+
+ {{ a
+ }}
+
+
+
+================================================================================
+`;
diff --git a/tests/format/vue/interpolation/embedded-language-formatting-off/format.test.js b/tests/format/vue/interpolation/embedded-language-formatting-off/format.test.js
new file mode 100644
index 000000000..779b3be80
--- /dev/null
+++ b/tests/format/vue/interpolation/embedded-language-formatting-off/format.test.js
@@ -0,0 +1 @@
+runFormatTest(import.meta, ["vue"], { embeddedLanguageFormatting: "off" });
diff --git a/tests/format/vue/interpolation/embedded-language-formatting-off/trailing-newline.vue b/tests/format/vue/interpolation/embedded-language-formatting-off/trailing-newline.vue
new file mode 100644
index 000000000..19c9ca06e
--- /dev/null
+++ b/tests/format/vue/interpolation/embedded-language-formatting-off/trailing-newline.vue
@@ -0,0 +1,14 @@
+
+
+ {{
+ (
+ something.something.very.long.code ??
+ fail("this is even longer to enforce multiple lines")
+ ).toUpperCase()
+ }}.
+
+ ({{ a
+ }})
+ {{ a
+ }}
+