fix: improve compiled output of multiple call expression in single text node (#11097)

* fix: improve compiled output of multiple call expression in single text node

* fix
pull/11093/head
Dominic Gannaway 1 year ago committed by GitHub
parent 22494be9ec
commit 3462c54fd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve compiled output of multiple call expression in single text node

@ -1396,7 +1396,7 @@ function process_children(nodes, expression, is_element, { visit, state }) {
state.template.push(' ');
const [contains_call_expression, value] = serialize_template_literal(sequence, visit);
const [contains_call_expression, value] = serialize_template_literal(sequence, visit, state);
const update = b.stmt(b.call('$.set_text', text_id, value));
@ -1511,25 +1511,39 @@ function serialize_attribute_value(attribute_value, context) {
}
}
return serialize_template_literal(attribute_value, context.visit);
return serialize_template_literal(attribute_value, context.visit, context.state);
}
/**
* @param {Array<import('#compiler').Text | import('#compiler').ExpressionTag>} values
* @param {(node: import('#compiler').SvelteNode) => any} visit
* @param {import("../types.js").ComponentClientTransformState} state
* @returns {[boolean, import('estree').TemplateLiteral]}
*/
function serialize_template_literal(values, visit) {
function serialize_template_literal(values, visit, state) {
/** @type {import('estree').TemplateElement[]} */
const quasis = [];
/** @type {import('estree').Expression[]} */
const expressions = [];
let contains_call_expression = false;
let contains_multiple_call_expression = false;
quasis.push(b.quasi(''));
for (let i = 0; i < values.length; i++) {
const node = values[i];
if (node.type === 'ExpressionTag' && node.metadata.contains_call_expression) {
if (contains_call_expression) {
contains_multiple_call_expression = true;
}
contains_call_expression = true;
}
}
for (let i = 0; i < values.length; i++) {
const node = values[i];
if (node.type === 'Text') {
const last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
last.value.raw += sanitize_template_string(node.data);
@ -1539,11 +1553,23 @@ function serialize_template_literal(values, visit) {
last.value.raw += sanitize_template_string(node.expression.value + '');
}
} else {
if (node.type === 'ExpressionTag' && node.metadata.contains_call_expression) {
contains_call_expression = true;
}
if (contains_multiple_call_expression) {
const id = b.id(state.scope.generate('stringified_text'));
state.init.push(
b.const(
id,
b.call(
// In runes mode, we want things to be fine-grained - but not in legacy mode
state.analysis.runes ? '$.derived' : '$.derived_safe_equal',
b.thunk(/** @type {import('estree').Expression} */ (visit(node.expression)))
)
)
);
expressions.push(b.call('$.get', id));
} else {
expressions.push(b.call('$.stringify', visit(node.expression)));
}
quasis.push(b.quasi('', i + 1 === values.length));
}
}
@ -1586,7 +1612,7 @@ export const template_visitors = {
declaration.id,
b.call(
// In runes mode, we want things to be fine-grained - but not in legacy mode
state.options.runes ? '$.derived' : '$.derived_safe_equal',
state.analysis.runes ? '$.derived' : '$.derived_safe_equal',
b.thunk(/** @type {import('estree').Expression} */ (visit(declaration.init)))
)
)
@ -1623,7 +1649,7 @@ export const template_visitors = {
state.init.push(
// In runes mode, we want things to be fine-grained - but not in legacy mode
b.const(tmp, b.call(state.options.runes ? '$.derived' : '$.derived_safe_equal', fn))
b.const(tmp, b.call(state.analysis.runes ? '$.derived' : '$.derived_safe_equal', fn))
);
// we need to eagerly evaluate the expression in order to hit any
@ -2972,7 +2998,7 @@ export const template_visitors = {
b.assignment(
'=',
b.member(b.id('$.document'), b.id('title')),
serialize_template_literal(/** @type {any} */ (node.fragment.nodes), visit)[1]
serialize_template_literal(/** @type {any} */ (node.fragment.nodes), visit, state)[1]
)
)
);

@ -1,7 +1,7 @@
<script>
let foo = () => 1;
function bar() {
var bar = function() {
return 2;
}

@ -0,0 +1,23 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { log } from './log.js';
export default test({
before_test() {
log.length = 0;
},
async test({ assert, target }) {
const [b1, b2] = target.querySelectorAll('button');
flushSync(() => {
b1.click();
});
flushSync(() => {
b2.click();
});
assert.deepEqual(log, ['x', 'y', 'x', 'y']);
}
});

@ -0,0 +1,21 @@
<script>
import { log } from './log.js';
let x = $state(0);
let y = $state(0);
function getX() {
log.push('x')
return x;
}
function getY() {
log.push('y')
return y;
}
</script>
<button on:click={() => x++}>{x}</button>
<button on:click={() => y++}>{y}</button>
{getX()}|{getY()}
Loading…
Cancel
Save