diff --git a/apps/oxfmt/test/cli/embedded_languages/__snapshots__/embedded_languages.test.ts.snap b/apps/oxfmt/test/cli/embedded_languages/__snapshots__/embedded_languages.test.ts.snap index 3b74e81fb0a5b..2b9cdc6bf2095 100644 --- a/apps/oxfmt/test/cli/embedded_languages/__snapshots__/embedded_languages.test.ts.snap +++ b/apps/oxfmt/test/cli/embedded_languages/__snapshots__/embedded_languages.test.ts.snap @@ -16,6 +16,27 @@ const mixedTemplate = html\`

Title

\`; const mixedDocs = md\`#Documentation This is **important**.\`; +// Multi-line with blank lines - should preserve blank lines without trailing whitespace +const multilineCSS = css\` + .foo { + color: red; + } + + .bar { + color: blue; + } +\`; + +const multilineGQL = gql\` + type Foo { + name: String! + } + + type Bar { + value: Int! + } +\`; + // Empty - Regular template literals retain newlines and spaces, but embedded ones are condensed const empty = css\`\`; const empty2 = styled\` @@ -58,6 +79,27 @@ const mixedDocs = md\` This is **important**. \`; +// Multi-line with blank lines - should preserve blank lines without trailing whitespace +const multilineCSS = css\` + .foo { + color: red; + } + + .bar { + color: blue; + } +\`; + +const multilineGQL = gql\` + type Foo { + name: String! + } + + type Bar { + value: Int! + } +\`; + // Empty - Regular template literals retain newlines and spaces, but embedded ones are condensed const empty = css\`\`; const empty2 = styled\`\`; diff --git a/apps/oxfmt/test/cli/embedded_languages/fixtures/mixed.js b/apps/oxfmt/test/cli/embedded_languages/fixtures/mixed.js index 1c5ec4ef9df01..1af5931bc4d6a 100644 --- a/apps/oxfmt/test/cli/embedded_languages/fixtures/mixed.js +++ b/apps/oxfmt/test/cli/embedded_languages/fixtures/mixed.js @@ -10,6 +10,27 @@ const mixedTemplate = html`

Title

`; const mixedDocs = md`#Documentation This is **important**.`; +// Multi-line with blank lines - should preserve blank lines without trailing whitespace +const multilineCSS = css` + .foo { + color: red; + } + + .bar { + color: blue; + } +`; + +const multilineGQL = gql` + type Foo { + name: String! + } + + type Bar { + value: Int! + } +`; + // Empty - Regular template literals retain newlines and spaces, but embedded ones are condensed const empty = css``; const empty2 = styled` diff --git a/crates/oxc_formatter/src/print/template.rs b/crates/oxc_formatter/src/print/template.rs index fcc7d2ee4dad9..374c49a9709e5 100644 --- a/crates/oxc_formatter/src/print/template.rs +++ b/crates/oxc_formatter/src/print/template.rs @@ -822,7 +822,11 @@ fn format_embedded_template<'a>( let format_content = format_with(|f: &mut Formatter<'_, 'a>| { let content = f.context().allocator().alloc_str(&formatted); for line in content.split('\n') { - write!(f, [text(line), hard_line_break()]); + if line.is_empty() { + write!(f, [empty_line()]); + } else { + write!(f, [text(line), hard_line_break()]); + } } });