Skip to content

Commit 6f6c3a0

Browse files
authored
fix: only escape attribute values for elements, not components (#9456)
* only escape attribute values for elements, not components - closes #9454 * changeset --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 9abfb52 commit 6f6c3a0

File tree

5 files changed

+31
-4
lines changed

5 files changed

+31
-4
lines changed

.changeset/sour-rules-march.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: only escape attribute values for elements, not components

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,9 +611,15 @@ const javascript_visitors_runes = {
611611
* @param {true | Array<import('#compiler').Text | import('#compiler').ExpressionTag>} attribute_value
612612
* @param {import('./types').ComponentContext} context
613613
* @param {boolean} trim_whitespace
614+
* @param {boolean} is_component
614615
* @returns {import('estree').Expression}
615616
*/
616-
function serialize_attribute_value(attribute_value, context, trim_whitespace = false) {
617+
function serialize_attribute_value(
618+
attribute_value,
619+
context,
620+
trim_whitespace = false,
621+
is_component = false
622+
) {
617623
if (attribute_value === true) {
618624
return b.true;
619625
}
@@ -629,7 +635,8 @@ function serialize_attribute_value(attribute_value, context, trim_whitespace = f
629635
if (trim_whitespace) {
630636
data = data.replace(regex_whitespaces_strict, ' ').trim();
631637
}
632-
return b.literal(escape_html(data, true));
638+
639+
return b.literal(is_component ? data : escape_html(data, true));
633640
} else {
634641
return /** @type {import('estree').Expression} */ (context.visit(value.expression));
635642
}
@@ -777,12 +784,12 @@ function serialize_inline_component(node, component_name, context) {
777784
} else if (attribute.type === 'Attribute') {
778785
if (attribute.name === 'slot') continue;
779786
if (attribute.name.startsWith('--')) {
780-
const value = serialize_attribute_value(attribute.value, context);
787+
const value = serialize_attribute_value(attribute.value, context, false, true);
781788
custom_css_props.push(b.init(attribute.name, value));
782789
continue;
783790
}
784791

785-
const value = serialize_attribute_value(attribute.value, context);
792+
const value = serialize_attribute_value(attribute.value, context, false, true);
786793
push_prop(b.prop('init', b.key(attribute.name), value));
787794
} else if (attribute.type === 'BindDirective') {
788795
// TODO this needs to turn the whole thing into a while loop because the binding could be mutated eagerly in the child
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
const { prop } = $props();
3+
</script>
4+
5+
{prop}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: `&quot;`
5+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
</script>
4+
5+
<Child prop='"'/>

0 commit comments

Comments
 (0)