Skip to content

Commit

Permalink
fix: handle spreads within static strings (#9554)
Browse files Browse the repository at this point in the history
Previously, if a part of the template was determined be be optimizable using innerHTML, it would error if there's a spread on an attribute
  • Loading branch information
dummdidumm authored Nov 20, 2023
1 parent 1fd0b18 commit 9b33413
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/gentle-spies-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: handle spreads within static strings
Original file line number Diff line number Diff line change
Expand Up @@ -1312,9 +1312,19 @@ function to_html(wrappers, block, literal, state, can_use_raw_text) {
// The value attribute of <textarea> renders as content.
return;
}
state.quasi.value.raw += ` ${fix_attribute_casing(attr.node.name)}="`;
to_html_for_attr_value(attr, block, literal, state);
state.quasi.value.raw += '"';

if (attr instanceof SpreadAttributeWrapper) {
literal.quasis.push(state.quasi);
literal.expressions.push(x`@stringify_spread(${attr.node.expression.manipulate(block)})`);
state.quasi = {
type: 'TemplateElement',
value: { raw: '' }
};
} else {
state.quasi.value.raw += ` ${fix_attribute_casing(attr.node.name)}="`;
to_html_for_attr_value(attr, block, literal, state);
state.quasi.value.raw += '"';
}
});
if (!wrapper.void) {
state.quasi.value.raw += '>';
Expand Down
30 changes: 30 additions & 0 deletions packages/svelte/src/runtime/internal/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,36 @@ export function attribute_to_object(attributes) {
return result;
}

const escaped = {
'"': '&quot;',
'&': '&amp;',
'<': '&lt;'
};

const regex_attribute_characters_to_escape = /["&<]/g;

/**
* Note that the attribute itself should be surrounded in double quotes
* @param {any} attribute
*/
function escape_attribute(attribute) {
return String(attribute).replace(regex_attribute_characters_to_escape, (match) => escaped[match]);
}

/**
* @param {Record<string, string>} attributes
*/
export function stringify_spread(attributes) {
let str = ' ';
for (const key in attributes) {
if (attributes[key] != null) {
str += `${key}="${escape_attribute(attributes[key])}" `;
}
}

return str;
}

/**
* @param {HTMLElement} element
* @returns {{}}
Expand Down
11 changes: 11 additions & 0 deletions packages/svelte/test/runtime/samples/spread-from-import/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
html: `
<div>
<p class="tooltip">static stuff</p>
</div>
<div>
<p class="tooltip">dynamic stuff</p>
</div>
<button>unused</button>
`
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script>
import { spread } from './spread.js';
let dynamic = 'dynamic';
</script>

<div>
<p {...spread()}>static stuff</p>
</div>

<div>
<p {...spread()}>{dynamic} stuff</p>
</div>

<button on:click={() => dynamic = ''}>unused</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function spread() {
return {
class: 'tooltip',
id: null
};
}

0 comments on commit 9b33413

Please sign in to comment.