Skip to content

Commit 90563e9

Browse files
feat: add partial evaluation (#15494)
* feat: add partial evaluation * fix * tweak * more * more * evaluate stuff in template * update test * SSR * unused * changeset * remove TODO * Apply suggestions from code review Co-authored-by: Simon H <[email protected]> * allow unknown operators * use blocks and block-scoping in switch statement --------- Co-authored-by: Simon H <[email protected]>
1 parent a051f96 commit 90563e9

File tree

9 files changed

+357
-33
lines changed

9 files changed

+357
-33
lines changed

.changeset/selfish-onions-begin.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': minor
3+
---
4+
5+
feat: partially evaluate certain expressions

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -685,14 +685,13 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
685685
: value
686686
);
687687

688+
const evaluated = context.state.scope.evaluate(value);
689+
const assignment = b.assignment('=', b.member(node_id, '__value'), value);
690+
688691
const inner_assignment = b.assignment(
689692
'=',
690693
b.member(node_id, 'value'),
691-
b.conditional(
692-
b.binary('==', b.null, b.assignment('=', b.member(node_id, '__value'), value)),
693-
b.literal(''), // render null/undefined values as empty string to support placeholder options
694-
value
695-
)
694+
evaluated.is_defined ? assignment : b.logical('??', assignment, b.literal(''))
696695
);
697696

698697
const update = b.stmt(

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,21 @@ export function build_template_chunk(
8989
}
9090
}
9191

92-
const is_defined =
93-
value.type === 'BinaryExpression' ||
94-
(value.type === 'UnaryExpression' && value.operator !== 'void') ||
95-
(value.type === 'LogicalExpression' && value.right.type === 'Literal') ||
96-
(value.type === 'Identifier' && value.name === state.analysis.props_id?.name);
97-
98-
if (!is_defined) {
99-
// add `?? ''` where necessary (TODO optimise more cases)
100-
value = b.logical('??', value, b.literal(''));
101-
}
92+
const evaluated = state.scope.evaluate(value);
10293

103-
expressions.push(value);
94+
if (evaluated.is_known) {
95+
quasi.value.cooked += evaluated.value + '';
96+
} else {
97+
if (!evaluated.is_defined) {
98+
// add `?? ''` where necessary
99+
value = b.logical('??', value, b.literal(''));
100+
}
104101

105-
quasi = b.quasi('', i + 1 === values.length);
106-
quasis.push(quasi);
102+
expressions.push(value);
103+
104+
quasi = b.quasi('', i + 1 === values.length);
105+
quasis.push(quasi);
106+
}
107107
}
108108
}
109109

packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/utils.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,17 @@ export function process_children(nodes, { visit, state }) {
4444
if (node.type === 'Text' || node.type === 'Comment') {
4545
quasi.value.cooked +=
4646
node.type === 'Comment' ? `<!--${node.data}-->` : escape_html(node.data);
47-
} else if (node.type === 'ExpressionTag' && node.expression.type === 'Literal') {
48-
if (node.expression.value != null) {
49-
quasi.value.cooked += escape_html(node.expression.value + '');
50-
}
5147
} else {
52-
expressions.push(b.call('$.escape', /** @type {Expression} */ (visit(node.expression))));
48+
const evaluated = state.scope.evaluate(node.expression);
49+
50+
if (evaluated.is_known) {
51+
quasi.value.cooked += escape_html((evaluated.value ?? '') + '');
52+
} else {
53+
expressions.push(b.call('$.escape', /** @type {Expression} */ (visit(node.expression))));
5354

54-
quasi = b.quasi('', i + 1 === sequence.length);
55-
quasis.push(quasi);
55+
quasi = b.quasi('', i + 1 === sequence.length);
56+
quasis.push(quasi);
57+
}
5658
}
5759
}
5860

0 commit comments

Comments
 (0)