Skip to content

Commit 72244cd

Browse files
committed
fix: special case literals with " in it and fix standalone case
1 parent dec07f0 commit 72244cd

File tree

6 files changed

+36
-19
lines changed

6 files changed

+36
-19
lines changed

packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
/** @import { Context } from '../types' */
33
import { is_tag_valid_with_parent } from '../../../../html-tree-validation.js';
44
import * as e from '../../../errors.js';
5-
import { is_inlinable_expression } from '../../utils.js';
6-
import { mark_subtree_dynamic } from './shared/fragment.js';
75

86
/**
97
* @param {AST.ExpressionTag} node

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../../../cons
66
import { dev } from '../../../../state.js';
77
import * as b from '../../../../utils/builders.js';
88
import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
9+
import { is_inlinable_expression } from '../../../utils.js';
910
import { clean_nodes, infer_namespace } from '../../utils.js';
1011
import { process_children } from './shared/fragment.js';
1112
import { build_render_statement } from './shared/utils.js';
@@ -142,7 +143,8 @@ export function Fragment(node, context) {
142143

143144
const use_space_template =
144145
trimmed.some((node) => node.type === 'ExpressionTag') &&
145-
trimmed.every((node) => node.type === 'Text' || node.type === 'ExpressionTag');
146+
trimmed.every((node) => node.type === 'Text' || node.type === 'ExpressionTag') &&
147+
!is_inlinable_expression(trimmed, context.state.scope);
146148

147149
if (use_space_template) {
148150
// special case — we can use `$.text` instead of creating a unique template

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,7 @@ export function RegularElement(node, context) {
364364
let { value } = build_template_literal(trimmed, context.visit, child_state);
365365
// if the expression is inlinable we just push it to the template
366366
if (is_inlinable_expression(trimmed, context.state.scope)) {
367-
// escaping every quasi if it's a template literal
368-
if (value.type === 'TemplateLiteral') {
369-
escape_template_quasis(value);
370-
}
367+
escape_template_quasis(value);
371368
state.template.push(value);
372369
} else {
373370
// else we programmatically set the value
@@ -601,6 +598,7 @@ function build_element_attribute_update_assignment(element, node_id, attribute,
601598
return true;
602599
} else {
603600
if (inlinable_expression) {
601+
escape_template_quasis(value, true);
604602
context.state.template.push(` ${name}="`, value, '"');
605603
} else {
606604
state.init.push(update);

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,8 @@ export function process_children(nodes, initial, is_element, { visit, state }) {
8484
state.update.push(update);
8585
} else {
8686
// if the expression is inlinable we just push it to the template
87-
if (is_inlinable_expression(sequence, state.scope)) {
88-
// escaping every quasi if it's a template literal
89-
if (value.type === 'TemplateLiteral') {
90-
escape_template_quasis(value);
91-
}
87+
if (is_inlinable_expression(sequence, state.scope) && !is_text) {
88+
escape_template_quasis(value);
9289
state.template.push(value);
9390
} else {
9491
// else we programmatically set the value

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, Statement, Super, TemplateLiteral } from 'estree' */
1+
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, Statement, Super, TemplateLiteral, Literal } from 'estree' */
22
/** @import { AST, SvelteNode } from '#compiler' */
33
/** @import { ComponentClientTransformState } from '../../types' */
44
import { walk } from 'zimmerframe';
@@ -34,12 +34,30 @@ export function get_states_and_calls(values) {
3434
}
3535
/**
3636
* Escape the html in every quesi in the template literal
37-
* @param {TemplateLiteral} template
37+
* @param {SvelteNode} template
38+
* @param {boolean} [is_attr]
3839
*/
39-
export function escape_template_quasis(template) {
40-
for (let quasi of template.quasis) {
41-
quasi.value.raw = escape_html(quasi.value.raw);
42-
}
40+
export function escape_template_quasis(template, is_attr) {
41+
walk(
42+
template,
43+
{},
44+
{
45+
TemplateLiteral(node, { next }) {
46+
for (let quasi of node.quasis) {
47+
quasi.value.raw = escape_html(quasi.value.raw, is_attr);
48+
}
49+
next();
50+
},
51+
Literal(node, { next }) {
52+
if (node.raw != null) {
53+
node.raw = escape_html(node.raw, is_attr);
54+
} else {
55+
node.value = escape_html(node.value, is_attr);
56+
}
57+
next();
58+
}
59+
}
60+
);
4361
}
4462

4563
/**

packages/svelte/src/compiler/phases/utils.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ export function is_inlinable_expression(value, scope) {
6666
// we need to special case null and boolean values because
6767
// we want to set them programmatically
6868
value.expression.type === 'Literal' &&
69-
(value.expression.value === null || typeof value.expression.value === 'boolean')
69+
(value.expression.value === null ||
70+
typeof value.expression.value === 'boolean' ||
71+
// we also want to special case the case of a literal with quotes
72+
// because it could mess with the template
73+
(typeof value.expression.value === 'string' && value.expression.value.includes('"')))
7074
) {
7175
return false;
7276
}

0 commit comments

Comments
 (0)