diff --git a/.changeset/sour-rules-march.md b/.changeset/sour-rules-march.md new file mode 100644 index 0000000000..f948540af7 --- /dev/null +++ b/.changeset/sour-rules-march.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: only escape attribute values for elements, not components diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index c0eebce99a..f0800fedc6 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -611,9 +611,15 @@ const javascript_visitors_runes = { * @param {true | Array} attribute_value * @param {import('./types').ComponentContext} context * @param {boolean} trim_whitespace + * @param {boolean} is_component * @returns {import('estree').Expression} */ -function serialize_attribute_value(attribute_value, context, trim_whitespace = false) { +function serialize_attribute_value( + attribute_value, + context, + trim_whitespace = false, + is_component = false +) { if (attribute_value === true) { return b.true; } @@ -629,7 +635,8 @@ function serialize_attribute_value(attribute_value, context, trim_whitespace = f if (trim_whitespace) { data = data.replace(regex_whitespaces_strict, ' ').trim(); } - return b.literal(escape_html(data, true)); + + return b.literal(is_component ? data : escape_html(data, true)); } else { return /** @type {import('estree').Expression} */ (context.visit(value.expression)); } @@ -777,12 +784,12 @@ function serialize_inline_component(node, component_name, context) { } else if (attribute.type === 'Attribute') { if (attribute.name === 'slot') continue; if (attribute.name.startsWith('--')) { - const value = serialize_attribute_value(attribute.value, context); + const value = serialize_attribute_value(attribute.value, context, false, true); custom_css_props.push(b.init(attribute.name, value)); continue; } - const value = serialize_attribute_value(attribute.value, context); + const value = serialize_attribute_value(attribute.value, context, false, true); push_prop(b.prop('init', b.key(attribute.name), value)); } else if (attribute.type === 'BindDirective') { // TODO this needs to turn the whole thing into a while loop because the binding could be mutated eagerly in the child diff --git a/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/Child.svelte b/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/Child.svelte new file mode 100644 index 0000000000..5094054f7c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/Child.svelte @@ -0,0 +1,5 @@ + + +{prop} diff --git a/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/_config.js b/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/_config.js new file mode 100644 index 0000000000..c88b372075 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `"` +}); diff --git a/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/main.svelte b/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/main.svelte new file mode 100644 index 0000000000..3c87b1849a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/component-prop-unescaped/main.svelte @@ -0,0 +1,5 @@ + + +