fix: handle spreads within static strings (#9554)

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
pull/9555/head
Simon H 2 years ago committed by GitHub
parent 1fd0b18459
commit 9b3341378a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: handle spreads within static strings

@ -1312,9 +1312,19 @@ function to_html(wrappers, block, literal, state, can_use_raw_text) {
// The value attribute of <textarea> renders as content. // The value attribute of <textarea> renders as content.
return; return;
} }
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)}="`; state.quasi.value.raw += ` ${fix_attribute_casing(attr.node.name)}="`;
to_html_for_attr_value(attr, block, literal, state); to_html_for_attr_value(attr, block, literal, state);
state.quasi.value.raw += '"'; state.quasi.value.raw += '"';
}
}); });
if (!wrapper.void) { if (!wrapper.void) {
state.quasi.value.raw += '>'; state.quasi.value.raw += '>';

@ -1180,6 +1180,36 @@ export function attribute_to_object(attributes) {
return result; 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 * @param {HTMLElement} element
* @returns {{}} * @returns {{}}

@ -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>
`
};

@ -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>

@ -0,0 +1,6 @@
export function spread() {
return {
class: 'tooltip',
id: null
};
}
Loading…
Cancel
Save