fix: Backtick now displays with templates (#9973)

* Add a test for backtick in template

* Put sanitize_template_string and use it everywhere

* Prettier

* Add changeset
pull/10008/head
Nguyen Tran 9 months ago committed by GitHub
parent 5dffe715d3
commit b31946eb08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
Fix interopability between backticks and templates

@ -33,6 +33,7 @@ import {
} from '../../../../../constants.js';
import { regex_is_valid_identifier } from '../../../patterns.js';
import { javascript_visitors_runes } from './javascript-runes.js';
import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
/**
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element
@ -1637,7 +1638,7 @@ function serialize_template_literal(values, visit, state) {
const node = values[i];
if (node.type === 'Text') {
const last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
last.value.raw += node.data;
last.value.raw += sanitize_template_string(node.data);
} else {
if (node.type === 'ExpressionTag' && node.metadata.contains_call_expression) {
contains_call_expression = true;

@ -26,6 +26,7 @@ import { binding_properties } from '../../bindings.js';
import { regex_starts_with_newline, regex_whitespaces_strict } from '../../patterns.js';
import { remove_types } from '../typescript.js';
import { DOMBooleanAttributes } from '../../../../constants.js';
import { sanitize_template_string } from '../../../utils/sanitize_template_string.js';
/**
* @param {string} value
@ -117,14 +118,6 @@ function serialize_template(template, out = b.id('out')) {
return statements;
}
/**
* @param {string} str
* @returns {string}
*/
function sanitize_template_string(str) {
return str.replace(/(`|\${|\\)/g, '\\$1');
}
/**
* Processes an array of template nodes, joining sibling text/expression nodes and
* recursing into child nodes.
@ -194,7 +187,10 @@ function process_children(nodes, parent, { visit, state }) {
const node = sequence[i];
if (node.type === 'Text' || node.type === 'Comment') {
let last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
last.value.raw += node.type === 'Comment' ? `<!--${node.data}-->` : escape_html(node.data);
last.value.raw +=
node.type === 'Comment'
? `<!--${node.data}-->`
: sanitize_template_string(escape_html(node.data));
} else if (node.type === 'Anchor') {
expressions.push(node.id);
quasis.push(b.quasi('', i + 1 === sequence.length));

@ -1,4 +1,5 @@
import { regex_is_valid_identifier } from '../phases/patterns.js';
import { sanitize_template_string } from './sanitize_template_string.js';
/**
* @param {Array<import('estree').Expression | import('estree').SpreadElement | null>} elements
@ -314,7 +315,7 @@ export function prop_def(key, value, computed = false, is_static = false) {
* @returns {import('estree').TemplateElement}
*/
export function quasi(cooked, tail = false) {
const raw = cooked.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
const raw = sanitize_template_string(cooked);
return { type: 'TemplateElement', value: { raw, cooked }, tail };
}

@ -0,0 +1,7 @@
/**
* @param {string} str
* @returns {string}
*/
export function sanitize_template_string(str) {
return str.replace(/(`|\${|\\)/g, '\\$1');
}

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
html: '<div>/ $clicks: 0 `tim$es` \\</div><div>$dollars `backticks` pyramid /\\</div>'
});

@ -0,0 +1,6 @@
<div>
/ $clicks: {0} `tim${"e"}s` \
</div>
<div>
$dollars `backticks` pyramid /\
</div>
Loading…
Cancel
Save