fix: preserve line feed character references in attribute values (#18691)

Fixes #15555

Pass on whether we're in an attribute to not replace the charcode with the whitespace charcode in that case
pull/18712/head
Bao Nguyen 4 days ago committed by GitHub
parent 34489c10df
commit b433f3cd87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: preserve line feed character references in attribute values

@ -60,7 +60,7 @@ export function decode_character_references(html, is_attribute_value) {
return match;
}
return String.fromCodePoint(validate_code(code));
return String.fromCodePoint(validate_code(code, is_attribute_value));
}
);
}
@ -75,10 +75,15 @@ const NUL = 0;
// Also see: https://en.wikipedia.org/wiki/Plane_(Unicode)
// Also see: https://html.spec.whatwg.org/multipage/parsing.html#preprocessing-the-input-stream
/** @param {number} code */
function validate_code(code) {
// line feed becomes generic whitespace
if (code === 10) {
/**
* @param {number} code
* @param {boolean} is_attribute_value
*/
function validate_code(code, is_attribute_value) {
// line feed becomes generic whitespace, since it is collapsed along with the
// surrounding whitespace anyway. In an attribute value it is significant, so it
// is left alone there
if (code === 10 && !is_attribute_value) {
return 32;
}

@ -0,0 +1,53 @@
{
"html": {
"type": "Fragment",
"start": 0,
"end": 32,
"children": [
{
"type": "Element",
"start": 0,
"end": 32,
"name": "p",
"attributes": [
{
"type": "Attribute",
"start": 3,
"end": 19,
"name": "title",
"name_loc": {
"start": {
"line": 1,
"column": 3,
"character": 3
},
"end": {
"line": 1,
"column": 8,
"character": 8
}
},
"value": [
{
"start": 10,
"end": 18,
"type": "Text",
"raw": "A
B",
"data": "A\nB"
}
]
}
],
"children": [
{
"type": "Text",
"start": 20,
"end": 28,
"raw": "A
B",
"data": "A B"
}
]
}
]
}
}

@ -0,0 +1,5 @@
<script>
const { text } = $props();
</script>
<span id="prop">{text}</span>

@ -0,0 +1,15 @@
import { test } from '../../test';
export default test({
async test({ assert, target }) {
// a line feed entity in an attribute value stays a line feed...
assert.equal(target.querySelector('#attr')?.getAttribute('title'), 'A\nB');
assert.equal(target.querySelector('#attr-decimal')?.getAttribute('title'), 'A\nB');
// ...including when the attribute is a prop passed to a component
assert.equal(target.querySelector('#prop')?.textContent, 'A\nB');
// other entities in attribute values still decode
assert.equal(target.querySelector('#attr-other-entity')?.getAttribute('title'), '©');
}
});

@ -0,0 +1,9 @@
<script>
import Component from './Component.svelte';
</script>
<span id="attr" title="A&#x0A;B"></span>
<span id="attr-decimal" title="A&#10;B"></span>
<span id="attr-other-entity" title="&copy;"></span>
<Component text="A&#x0A;B" />
Loading…
Cancel
Save