From 80012faa116342a5e855ff44ab23b2e83d06e457 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Mon, 5 Oct 2026 20:51:10 +0900 Subject: [PATCH] fix(parser): report nesting and template errors consistently Unexpected closing braces and unterminated nesting return success in the Wasm parser because errors are discarded or never recorded. Unterminated templates in the JavaScript parser call an undefined helper and produce a ReferenceError. Signed-off-by: Ruben Bridgewater --- lexer.js | 2 +- lib/lexer.wasm | Bin 22369 -> 22419 bytes src/lexer.c | 7 +++++-- test/_unit.js | 24 ++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lexer.js b/lexer.js index 8f8ff12..3e30b6d 100755 --- a/lexer.js +++ b/lexer.js @@ -1413,7 +1413,7 @@ function templateString () { if (ch === 92/*\*/) pos++; } - syntaxError(); + throw new Error('Unterminated template.'); } function blockComment () { diff --git a/lib/lexer.wasm b/lib/lexer.wasm index 08fbd540e65e1f1e87e704db63f3121c91814525..dc291380c4735361e2b391d5795f8db0ea8131fd 100755 GIT binary patch delta 1770 zcmYLKZ)hAv6rY)$-P^m_xokFj*)(Z$bK6UsrguFJwuM$|M!4IASPNC~5B;EEsrD$+ zP-zh)Vo~}@Di1{PgDoh6A8P6%DD*@8V8Ie;RS*lJRvRp0wY4n@O5>Zo3m3?~H#6_| zoA=(l_wLFW3LnywM=Z;--#Gd%{Q}m~z0`u|=_r0*r?r47sy8P1iIc;UDC!qri8d&M z|LBmgwlN|!=@W{jW%ekgh4hG3K>=^_+q4FgxiQBaYYKPlSEz(z&ZqFPt>NC>8Ao_b z_+Gl48!Z&MeycprNNmsG9US_Df%~|!TYO4WBqy4;8FJg84QD%S(LU7#(LEncK_UJ+l#)DJ3z&0|#GlLRjziZmr17W&*Nif(A8xuWo8 z@H2fI76!D( zV}w@2uumQ6msDB$(ykU#y>wV#-qnI{)HB9ldu1yes@yedJASN!c0`~3iL|vngW74M zn3sMDccZ9CM7H-YX%{UK1;o^Q+>#!O`&%+X zagns7gYqwu$U#kf-jsvN@@*7e35pYI+)`&*g2setvyUb=3h7ay9bXEslwO^vQ(A(c zR@~x~HB(elA)T&X*tOxZKbR$!T zGLK5IP#dKoT&!)L53^3d20Dn7K{KBZdtoO$6LP_JLh~oOA>&&W9WM;65XVR_3Ar%8 znuL5O31K%0Sf%uPD;FD z=cFa`a6-4J2jA)44`SC6y|QApFnAP)71=WB-K-4!d5mgdN2!>MGfnG^a(Hk64bt44Tj zVjML9l9-0WZ_Gw27<+{))|B{SO=)?^%aDn|mE<^HwSRhFH7iInD2e&i@VL-k#f&pw zcJ8TA&rZLZo@20kc4U^L5zaCr^tCeft7l3IC8Av%aC95vC^D|t%yp{F=#H6o4=O~C NWQ&X>Jv+M~{s&StR|Wt8 delta 1724 zcmZWqU2GIp6u#%q?Ck8^JKO2*c3QTjd%G?4hovuhNWz{B;<2Y7S(up=cGf#3Wk-Rn(S`ao%jv$9>I3al}pG9uEL(YVnp zWmhQ|P$5j)b+QN9zLZcY@eo+Ee4MNf-Uz#KXRf>{rJReS1N{c-Jvx)_(%z|7W zaMJa+EHXtZnDn72^sz%gg=nsA#qd<_2RMN5#SKBuC2Rurb@I1}H--&`AOv zp&T)}6zJiHVR4&sf;MwfTDh$NnFM5n%7|O3VLqN5!4=y~-Z8?9SS#L&<4K%F?;THc z?t*z7?K*}Ry2h}$?3zcgUCz~YP-`@c#gF-N+W%dwYo|uaX;Q3OgS77#wdReUdBFMJ zjaVsd!M&w5c(^o$|CY8u1MgNvd_?UEl%>DeXlS%|Mt{Ar+Q74F2Uh#m;-0<*e7bx; zxt=a7yi(qd_w;Y0-8=n7Jkj64^#dF5iGimKD~^1{>v~nKfqxEM#Pci4m|pq0OXOb7 zh*$W{%2I~jM?EG@lMfDobF>PnS&pMapWz=vkK)eZ6_CRH!v#Dz?BJWjrP=l{biz~^ zhCqLtiI`@C^=zgsmmy0S28r!Dt7k14`pnc(uKHOLcU1k5#3@$w9g@GZ$nVfBAlh^& zD@c)$1wpsYp4JzczQpvrane_rAxy!zSR}DJ@+{q%Pe%rYCqZZ@@PsThuaB$-DBy6V zl8IgYye!~@m7ZKa&TWq?y1`73MwH>D%0Oqq>_dHyiip*&xSj%jQt5>}p0BK$&Bt6O z;!o3!*F3O`GT&-grqX%yqYh&b&QilpHlMfhG#+A041t>$OAr_&2!eb9fkpBnot{ft zre=R)`Wn+0nEshs_9p%IMOfPL_0^Bv)}HwN^*?BcD+ay5bd=Rsm?13-TuBk!5Ae>> zo2Ce&fQW0{+Kih`r$mdY6JrotT?$UDUQ3lhhNATQhd{&ajL9}UHoDBsE@sQ(nbDIp z0^c6{h|>t%e@me`x8}F(+AN)|=Yq)3Xc>4iC$vkVUFheI)BMs<-vCU?B_|d;wc$Qp z^*ljXdz#5CeyOJ>=wdUyuwYe*7$jyC+tTn|ZBaG~XMvDu1Gnjk#_b4AF7h9Xd z&@`29bH~JYHZkU|XeF)F(els{`uXGLp6eS6R^-!Uqih*`BU-WCjw_@`#l)qkFPS;q z2htIErrLu8n;xb#FK*gSF+@Kz@0j@{NZu5+29J$#h`_y@yK5FbGlS1?=+_e6YH8?1 ll7d{Chp>*@B;pi`X09^BwhY>xHoI=KG0zlh{ { assert.deepStrictEqual(first, { exports: ['first'], reexports: [] }); }); + test('rejects unterminated and unexpected nesting', () => { + for (const source of ['(', '{', ')', '}', '({', '{(', 'exports.value = 1; }']) { + assert.throws(() => parse(source, 'nesting.js'), { name: 'Error' }); + assert.deepStrictEqual(parse('exports.recovery = 1;'), { + exports: ['recovery'], + reexports: [] + }); + } + assert.deepStrictEqual(parse('({}); exports.value = 1;'), { + exports: ['value'], + reexports: [] + }); + }); + + test('rejects unterminated templates with a parser error', () => { + for (const source of ['`open', '`open ${value', 'const value = `open']) { + assert.throws(() => parse(source, 'template.js'), { name: 'Error' }); + assert.deepStrictEqual(parse('exports.recovery = 1;'), { + exports: ['recovery'], + reexports: [] + }); + } + }); + test('automatic Wasm initialization', async () => { const lexer = await import('../dist/lexer.mjs?automatic-initialization');