Skip to content

Commit

Permalink
fix: remove leading newline from <pre> contents (#14922)
Browse files Browse the repository at this point in the history
... if it's not followed by another newline, according to the spec

Fixes #14767

---------

Co-authored-by: Simon Holthausen <[email protected]>
  • Loading branch information
Rich-Harris and dummdidumm authored Jan 7, 2025
1 parent 08a9d12 commit 7737868
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/tricky-radios-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: remove leading newline from `<pre>` contents
17 changes: 17 additions & 0 deletions packages/svelte/src/compiler/phases/3-transform/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import {
regex_ends_with_whitespaces,
regex_not_whitespace,
regex_starts_with_newline,
regex_starts_with_whitespaces
} from '../patterns.js';
import * as b from '../../utils/builders.js';
Expand Down Expand Up @@ -270,6 +271,22 @@ export function clean_nodes(

var first = trimmed[0];

// initial newline inside a `<pre>` is disregarded, if not followed by another newline
if (parent.type === 'RegularElement' && parent.name === 'pre' && first.type === 'Text') {
const text = first.data.replace(regex_starts_with_newline, '');
if (text !== first.data) {
const tmp = text.replace(regex_starts_with_newline, '');
if (text === tmp) {
first.data = text;
first.raw = first.raw.replace(regex_starts_with_newline, '');
if (first.data === '') {
trimmed.shift();
first = trimmed[0];
}
}
}
}

// Special case: Add a comment if this is a lone script tag. This ensures that our run_scripts logic in template.js
// will always be able to call node.replaceWith() on the script tag in order to make it run. If we don't add this
// and would still call node.replaceWith() on the script tag, it would be a no-op because the script tag has no parent.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from '../../test';

// A note about _expected.html: It is different from body.html because we're
// testing against target.innerHTML which already removed the redundant first newline
export default test({});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!--[--><pre>static content no line</pre> <pre> static content ignored line
</pre> <pre>
static content relevant line
</pre> <pre><div><span></span></div>
</pre> <pre>
<div><span></span></div>
</pre><!--]-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script>
let name = $state('');
</script>

<pre>static content no line</pre>

<pre>
static content ignored line
</pre>

<pre>

static content relevant line
</pre>

<pre>
<div><span>{name}</span></div>
</pre>

<pre>

<div><span>{name}</span></div>
</pre>
18 changes: 5 additions & 13 deletions packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,9 @@ import { test } from '../../test';

export default test({
mode: ['client', 'server'], // output is correct, but test suite chokes on the extra ssr comment which is harmless
withoutNormalizeHtml: true,
html: get_html(false),
ssrHtml: get_html(true)
});

/** @param {boolean} ssr */
function get_html(ssr) {
// ssr rendered HTML has an extra newline prefixed within `<pre>` tag,
// if the <pre> tag starts with `\n`
// because when browser parses the SSR rendered HTML, it will ignore the 1st '\n' character
return `${ssr ? '<!--[-->' : ''}<pre id="pre"> A
withoutNormalizeHtml: 'only-strip-comments', // because whitespace inside pre tags is significant
// Note how we're testing against target.innerHTML which already removed the redundant first newline
html: `<pre id="pre"> A
B
<span>
C
Expand All @@ -35,5 +27,5 @@ function get_html(ssr) {
leading newlines</pre></div> <div id="pre-without-leading-newline"><pre>without spaces</pre> <pre> with spaces </pre> <pre>${' '}
newline after leading space</pre></div> <pre id="pre-with-multiple-leading-newlines">
multiple leading newlines</pre>${ssr ? '<!--]-->' : ''}`;
}
multiple leading newlines</pre>`
});

0 comments on commit 7737868

Please sign in to comment.