Skip to content

Commit 74fd8a7

Browse files
authored
Merge pull request #199 from developit/fix-fragments
Ensure that template literals generated by JSX-to-HTM transform has a balanced amount of quasis and expressions
2 parents 864036b + aa924ce commit 74fd8a7

File tree

2 files changed

+14
-21
lines changed

2 files changed

+14
-21
lines changed

packages/babel-plugin-transform-jsx-to-htm/index.mjs

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,16 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
4848

4949
let quasis = [];
5050
let expressions = [];
51-
let buffer = '';
5251

5352
function expr(value) {
54-
commit(true);
5553
expressions.push(value);
54+
quasis.push(t.templateElement({ raw: '', cooked: '' }));
5655
}
5756

5857
function raw(str) {
59-
buffer += str;
58+
const last = quasis[quasis.length - 1];
59+
last.value.raw += str;
60+
last.value.cooked += str;
6061
}
6162

6263
function escapeText(text) {
@@ -81,15 +82,6 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
8182
return expr(t.stringLiteral(node.value));
8283
}
8384

84-
function commit(force) {
85-
if (!buffer && !force) return;
86-
quasis.push(t.templateElement({
87-
raw: buffer,
88-
cooked: buffer
89-
}));
90-
buffer = '';
91-
}
92-
9385
const FRAGMENT_EXPR = dottedIdentifier('React.Fragment');
9486

9587
function isFragmentName(node) {
@@ -197,25 +189,21 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
197189
processChildren(node, name, isFragment);
198190

199191
if (isRoot) {
200-
commit(true);
201192
const template = t.templateLiteral(quasis, expressions);
202193
const replacement = t.taggedTemplateExpression(tag, template);
203194
path.replaceWith(replacement);
204195
}
205196
}
206197

207198
function jsxVisitorHandler(path, state, isFragment) {
208-
let quasisBefore = quasis.slice();
209-
let expressionsBefore = expressions.slice();
210-
let bufferBefore = buffer;
199+
let quasisBefore = quasis;
200+
let expressionsBefore = expressions;
211201

212-
buffer = '';
213-
quasis.length = 0;
214-
expressions.length = 0;
202+
quasis = [t.templateElement({ raw: '', cooked: '' })];
203+
expressions = [];
215204

216205
if (isFragment) {
217206
processChildren(path.node, null, true);
218-
commit();
219207
const template = t.templateLiteral(quasis, expressions);
220208
const replacement = t.taggedTemplateExpression(tag, template);
221209
path.replaceWith(replacement);
@@ -226,7 +214,6 @@ export default function jsxToHtmBabelPlugin({ types: t }, options = {}) {
226214

227215
quasis = quasisBefore;
228216
expressions = expressionsBefore;
229-
buffer = bufferBefore;
230217

231218
state.set('jsxElement', true);
232219
}

test/babel-transform-jsx.test.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ describe('babel-plugin-transform-jsx-to-htm', () => {
177177
compile(`<React.Fragment>{Foo}{Bar}</React.Fragment>`)
178178
).toBe('html`${Foo}${Bar}`;');
179179
});
180+
181+
test('short syntax fragments should not crash due to TemplateLiteral quasi/expression unbalance', () => {
182+
expect(
183+
compile(`<><Foo />{Bar}</>`)
184+
).toBe('html`<${Foo}/>${Bar}`;');
185+
});
180186
});
181187

182188
describe('props', () => {

0 commit comments

Comments
 (0)