Skip to content
Merged
5 changes: 5 additions & 0 deletions .changeset/selfish-onions-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': minor
---

feat: partially evaluate certain expressions
Original file line number Diff line number Diff line change
Expand Up @@ -685,14 +685,13 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
: value
);

const evaluated = context.state.scope.evaluate(value);
const assignment = b.assignment('=', b.member(node_id, '__value'), value);

const inner_assignment = b.assignment(
'=',
b.member(node_id, 'value'),
b.conditional(
b.binary('==', b.null, b.assignment('=', b.member(node_id, '__value'), value)),
b.literal(''), // render null/undefined values as empty string to support placeholder options
value
)
evaluated.is_defined ? assignment : b.logical('??', assignment, b.literal(''))
);

const update = b.stmt(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,21 @@ export function build_template_chunk(
}
}

const is_defined =
value.type === 'BinaryExpression' ||
(value.type === 'UnaryExpression' && value.operator !== 'void') ||
(value.type === 'LogicalExpression' && value.right.type === 'Literal') ||
(value.type === 'Identifier' && value.name === state.analysis.props_id?.name);

if (!is_defined) {
// add `?? ''` where necessary (TODO optimise more cases)
value = b.logical('??', value, b.literal(''));
}
const evaluated = state.scope.evaluate(value);

if (evaluated.is_known) {
quasi.value.cooked += evaluated.value + '';
} else {
if (!evaluated.is_defined) {
// add `?? ''` where necessary
value = b.logical('??', value, b.literal(''));
}

expressions.push(value);
expressions.push(value);

quasi = b.quasi('', i + 1 === values.length);
quasis.push(quasi);
quasi = b.quasi('', i + 1 === values.length);
quasis.push(quasi);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,17 @@ export function process_children(nodes, { visit, state }) {
if (node.type === 'Text' || node.type === 'Comment') {
quasi.value.cooked +=
node.type === 'Comment' ? `<!--${node.data}-->` : escape_html(node.data);
} else if (node.type === 'ExpressionTag' && node.expression.type === 'Literal') {
if (node.expression.value != null) {
quasi.value.cooked += escape_html(node.expression.value + '');
}
} else {
expressions.push(b.call('$.escape', /** @type {Expression} */ (visit(node.expression))));
const evaluated = state.scope.evaluate(node.expression);

if (evaluated.is_known) {
quasi.value.cooked += escape_html((evaluated.value ?? '') + '');
} else {
expressions.push(b.call('$.escape', /** @type {Expression} */ (visit(node.expression))));

quasi = b.quasi('', i + 1 === sequence.length);
quasis.push(quasi);
quasi = b.quasi('', i + 1 === sequence.length);
quasis.push(quasi);
}
}
}

Expand Down
Loading