From 98972fe63fd3b072f5956b2b88ac0c6b13cff2ab Mon Sep 17 00:00:00 2001 From: Matt Hamlin Date: Tue, 14 May 2024 18:02:38 -0400 Subject: [PATCH] WIP - setup tests, pull in jsonc-parser --- bun.lockb | Bin 264672 -> 264552 bytes package.json | 4 +- .../__tests__/jsonc-parser.test.mjs | 15 + .../__tests__/one-version.test.mjs | 13 +- packages/one-version/bin/index.mjs | 2 +- packages/one-version/biome.jsonc | 6 +- packages/one-version/one-version.mjs | 39 +- packages/one-version/utils/jsonc-parser.mjs | 736 ++++++++++++++++++ packages/template-library/biome.jsonc | 6 +- 9 files changed, 812 insertions(+), 9 deletions(-) create mode 100644 packages/one-version/__tests__/jsonc-parser.test.mjs mode change 100644 => 100755 packages/one-version/bin/index.mjs create mode 100644 packages/one-version/utils/jsonc-parser.mjs diff --git a/bun.lockb b/bun.lockb index 54bc05d3ee40f04ef6a456fc703bfc108ca8a850..a60eca64cb25158df753b9de81c960e0df6f69ad 100755 GIT binary patch delta 51921 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

    TR3_LdEDB zS9Mi6Y`x9X+dXBl280t11A6;V3)BQPKy^?J==`q&DuYTuvs`JKfu=zDYCA7z#E&Kz zCqYBPa=HqrG7Z2Cbgl1tgf$#>VV&)DfYy0^Sen9D!%cwB{S+_^3 z?D0avBM9FNZUG~~C@>z3E8s^O7z0LwJ~*esW5Gm_0n&kXy9sa>$OILDp3dqmq@EwY zgRR@jD_||q{K1dzJAnCkW8mr}cN27fPC?auD#zoc@DiXVEr#y{ z_ku-WA-D(319QP_Fw4Y06}YNE4VwvOfI={wvX zRGkOFN>Bt=1Lb!F)?AhUTkxAe6Z;L#D^1qJ2(N+L3D<>R2g*dfbP((Z`@mkX2fPF{ z$FwOv1n&Yn!4u$duns%|9tP{d2Jk3&%(HjEPlFK6tBnMn1Wy5lH-Trs^FTZ1b8sxY z8GaTFAROFDw`0psK3l*xu+_7d;r9aJ-QX$0FTzj53cpNvG`vUMuU1~!ZR&|vJzZmc zzzeI@hk#nGG^2oePrs|s8xvhv^#)Ft*&Lwv0->NRD8^57uMFW3@CV`FLBYTI@f({m9U=(51UK`tw*gt@C;9KwwI164T?rZoA_!Kaf&ff+682*^JldvkMBVjN&f&BqE z4q9P<1iz>8SJ%FaQ35^$$G}k_=l6kh+2T*Y=ioE&1^5!2248`HflfeY&tC8t_zqi@ zR``2Zx)7}V1wTjQc_MxWzkrKCtyT@y6AG)vr@+UA{dApLqj=rzOMw6=4OEc2Shxv$ zyxFrUP`yBpMOCIAlPZ}Wnd;H$AfQL7{lImgFR*};>s?|vhy;2pS_kMcX$_!9rFt3~ z25NzFK>qTRj~=Nitjj^A03ECZZ)510YA`~Mde&O=Pnrq{K7W;u5KO1Ipnq-8FIZ9K ztI8-|=_7!&w<+JLp^QF2Z>SprCF})yf*v4Ph+29r=mxq1RUi>0fMDfl)ul$MC*nZ^ z&;`VSj-WGW3Zj&up4+HfR4YA@Q`dC@9Zc3{w!oGIuLgBNux|AUt2{k(RtGBoMnLtx z21siRT7c%D8BlpmfZ~)+kiS@I6b|OAHbepPEcnZUgARX{NSZoS87Qo&qIUjOSW_q% zr!?vu`2{OiA;1W!#?fAcGLx;&lA{nTNTZ>6Y06Bt!qQZbriFT{J5W!k5c!BT1%v4{ zQkTL7R~m#hO|Hx|SdfNU!>TxikC0*THk^d5O};-o00h&k<-y7Yd*RP^fdoZr(cTC& zMFxUkCTiIb5NyGf8K`v{_bYu>Va;K!K*ekBYEcB|t>)}7peaaR1&))tJQ-*e{W-H> zCc}x-qEL5^2I}Tia0}45#sUqaCgupB2|Wso1S#NVpuClz@=&;*#{Xq+Y=SLQ3)JE( zEAqdyl}5cNKRwTz4Ai6JKsJ~JGQmWkBXTIL9=$>1p8>Ai9JL8fK+Ez_3R{`o4m3o{ zG#`usw}I(EnQ2bk1(cUI*=b-P(B_&8l<%$ZRL}sQJh(uCD_g3Jx1ouZ;TwO7zp|w| zAk+X=Kv$X>UK&+Gh2>z+1iH@^!t=mgU^bWqNMGPMO4JD=_9C3mCn%%2Xu8(Tfpw6V z!S7S}6i}fbgFC@V5KOPD(0%x?g71YFfrUVq2wfhe+t^D3+{zXcSORqCQljO+fcrrO zG}+6*0-#pC4V1~1H(1|xB6)4=XujGO=-M%Ya0MED-MhUSX69GAyM7tnb*rKz!d2h{ zp>NmR_vG5*`eoF(aFl^2e|w;Pgr04b$6Vj{%(Elw6@-VDNk*xGVxHU{cz(hslvD}p zp;ejdr|fO=R5O3uR-Ib4$LBj@$`P}sabe4A=A?~o=I_|5L#vL&%q_**BIe0swL0$k zdBBm2cZPj1uYXGaE#M#7wiO*qzY(L{m#zKo&0hDFok$EdSKZr|Gj(^m*9B55&K95)AdE-M^rS! zUqp|oWY&vmz@QeTYMS!91CfDiE14F%agMEQM((B??yKxhnW2NZZ+WBT+=)!&!1|V)8g9I zO&uz)99q6g!2@0nL@1jle?Tm*VP?OK)4?#aO&o0L`^|9w--Max-wRx04(|<=4g3;jTK;;ek?rb~Vge|eA@6*B^=;WzlF6nM-9fvk zRl+NH{%4A?z}#@N5WUV4Qfl@-nceoe%x}i5zFYx1@TFJ&cZ1@rk>H?oxyoH5Qyx9; zyR~U}I(bnC4O`QyX7RpD^>qd%!hEzZ5K-s9r}@wR>>ub-$K3WRUALr;d5Zq+w5E=? z1GRsDz?yXzqA88C)aE119Zik~AGRLZbYz1s1OAyE-RYANY5uJ|+|h0qSXS4JeT~(1 zxUSoOC1WZ*dDk1GpCg6xYR7$`o;wvURBX7VX4eP53;2^fWk`MVI%xwZ>)*eh>Ri*n z-9pY3w6JdsU+FH;4r+WCVl;)0-rw!2pQkUl&Z{Ufzc(-g_LGIx(5xblAlLbw6ly@s zbqBv`_dvw-(*BVh=*UhSJB`d+c-E=a$lbqpw|wAO+>kIg&vu%ZO&Xcf2gtK+BNHQ@ z*2rWYAjLPNP%YwrcxltYDjhXA(QbEjxY|63M_}&NW`|NtX>7ic{c~dzdN9zxP8qMP z1!I?O+Ij52$$+1w=xpd)o0!Q5X?v-r+(pSdu3n#!w=KP{pVLBCEYDntQA-BR%-s3W zrp-@!rBcs#o0=Du_5>ak@mP2N>aRoU-_i{a7Nq*^U&LrqzdxYYWB$sv~YPc_|AUc5eIZ{YWL7UQYifKnjFN?ovVXC|ipKEDG zzE0_tqTGJ$`APh~ovS|GK}rpLG#587X6AjHU$0jwqT%J3R#E0j(gqTu%&V`{Ujw4d zui{}*rqy9;Gmez%>5P68YqnlGztBm^uEBjQ%G`lRV0M&w<}jr%!c#3=HmY{w=#MJ) ztl>|HZ_7;W*yes>)Ne~#4`0+|OMGkW-<7r&_bcs@R(6+HzZ$&q1$UBn z;zXEBNjebn&uuySVdBo20S>eFtzt=gwyo*^26Le_Bg0xPyihf5;_n>}7dbU#hPCni z+RhZdK^scbcUACcSNq8(x3#_FZalo%Qlq_jgFHHosOZ-HyH{pRUiHE2?>HW9$;8)~ zw3-bs-qR<4>>Z9vP>Z=yOVS-U7teAP8{@9^@cce%R8hT8E2k)hcQaWQ;lkV*E{}cZ_llYC;N@c$cr=o#s(SNYAo-(N26vujP25>1KT~Q_5 zQ-1l06uLi9zv^C0RL$+}Uj6##WtU^>_b^W?uNFPbtK`+GGoIQ{o;md7u@)zJb9ZTn z>_LoniO-hyD1Pky0m@xlGr14!VOkxd{9#@xzux-I;@*$UXn8qpnwRT{zB5Lj?Z0I6 z<(TXq<_^-hw-ucfmbY?X_nH zycSoQvf8(5uN8NanCf&yg~#7|t8?j9-pxm+KbPN~Ouzr(^7~1^d`BsDW_yRhoSXOG za%cZ?Uxjkh?4XAD0{u+F3F@J(zax9mJtyeY#Y_p!{I-dYG`{1ms?2=q;<(T1XI?tN z*#G$q;e=?%{it25n0@`+v=1Lzk-uib+Zn{fu*b0f2b=oePnRkE-A?HB_#YeUZ0cT_ zPS7Qfdd}!?Zazs<@5X~$bK!>A<&&=u|K544<~HPk{$?>Aoi^j4OJ~Vf^Gu_q>ksP< znd@US!0YGf%uw zzwYIjwn?Vt$JDGh9=seByi>p)m7sv4 zfEbei0wRitB`TsK#umFlU0XDwqJB*f{hC13*ppa@yjV%jlYatIX{vW z08@V*$|wDwwh2tPckC7lJ+#6CVDG)ZGB6VabsR46`i|LMhPyd{B!jl~)w^3=ce%Yf zCMmKd?F!CHN)t9;hQn{-vG58wUyfw1S6~JYB3Z;0bR)A{hJMYHo;>qRn)y>q>R-!g z3&>som`8!3AB7B#WQ~r$`{w!Fgr_nFJni#d9CGz#%%A$xL1FO0v^BAsZK7EHGK}pO z#bb!a>FK*yt{yuIW3g0(u_l_2eKvfjd*+cJP^(H=Dl||K&C)Pd*cr{Hl)HEt734F4T86mXglm z7?uGH;b;sSdjptdz$71(v-A@C+w%hD-4tn|#>X*i2Qc-fz4_*>J#_ZRu4OYTfkDL) z+ZHx``Zt~w%P22+ng)@36chUA{wXT7B2eio^5>8(}Za(&MB*x0R4e!m`14A%i z#>H}NM3zNncTyHVm*kLQ)__8<)lkb1O-@5=K9!3r@_|N0BQ zttWRM_IR}U!TQojiG^bvr&-wCI&)0g=qhS-i({{eYeTqCavHN&ZjOF6?g#}rT1JRB zJDvsH6g(TPkLT+96;BF!Hj!7^lVuwbri)~VO#+*66I13-7hzrkJA4z$L*;mr`bYL- znp@y?xF26CyIlXr$MP@JQpu{YOJqH6!C>F7AgO>v{$Y}o#Fhg?7?Q+}-@+yol9}6W z@Q6%iLATL=CYhzxbfOlw4s4`H8T$b+IW&1Tx}VB-WA}kv^n!Jdr}kX3>42axK(fM_ z(|rh-3=G;?+HVra?EdyUBn7ePA)7{$mIMs^4wu~*wAoqcc0%{^*r3zG-bA={1F3m{ zkj>=ypBmxdl^bh>tN}y?$j0pKoA$~Fi;R#RfKUkdWQs{w@3pbHMo1|j&VZbm=(I_B z!rN4aWTWc=KophcK3rGQWn_tmagfCzPA=^1`pl4?LKWfM0U;4mW_@{L=DYzDjAMcT zA!=t|RQzUjuWYgr(i0GSK>8M1#wMpuN<;MVx8N=!i5+<$XcKaQL7qIzCHQ&j)TsWp ziV^6c8fjQ^LgEM*=-eBn7gTfi%{M}3rtvX7%kl@!@3%2VP^6#-pI=lnCWR$F6x{Jc z>&XuVtu7;jt7QGQ_}i-{_8&5Fzn5o(EMxN?3o7+CAW)d@ zZmO;~*m_R_g<2`Dn3OX2N3f=H7L145eke+9;Qh2aZ?oS1niTLko*x@R2w^~I2!!~k zo-TKzwnZ2TrL%K?gV1dD3*qGfkIW?NZoh}MzFJ>JqGI-l7#?QUKv!P@9vQ%c*z*f) zy8h^Fl>8-Y2LzqNFdj}X?RI=UsdT_qBSK?9Xwn(^ZHp&n-9chwP)87(MWXnywSNm* z{9Kp>`+(%~)M}nPSB`?K>I1su$~K%bY6fNUJ+;+r z-8qYIRQTN-;K@({R@H`5`d;wcVpiBUhr3UKLI#8bglw{;w!tKX0# zi|09y(~*dDjOJ&u9}p{OLA^fvV!@3cO=NP=({c7K$f&Q$L;Gy-xLtel$nAnc&KOJ{ zvtvLItj4puPvQ3CVwrgboaxx{e5WjREV}JFdHWzxgl&*sakigc0dJPeR#ph%iq-5v z1>_vWhE{^lNO%`=c|E^AT~I%^tCcJWl>QZKQz>{UOMpOLlH=n7uNfGo@yy{ndY5Zs z^KEfRTq!Hj8Z%7KMp|Hym51YLjpt;Gl@_t29MnM#D~jVjSuNnos#e?%^w+XARgBJAaL!IFBB3oH#Ik`5b{w^%d89 zQlGthme={tOi-Ajhc=F=!mrkW5sWrX+u!QZ9nUTfD5O3@54rN1j;qlhPqeF*OA2c; zcRK1XAj}byxDRr3k2e@DO~=` zum31$+M@O%NsCfGQ1eOJ6n{1zV>S1%n53Qf&_wHoUq_QB<*d&%fNg#u1gL8`$cC;Z zV{>LsF9rQS?>lL?q~HROTQ3DI8EE}if(vfxY57XXN!>Gp$DEkOS0~ibEMJG$7_=2y z;9DO+NIrW-=wIbUDXXNpNj_dNlSi=rXWMO#Zr%#7J{|$r7Pzi}sPRmmSvUBbL;vk3 z=~heU(>mt<8dem;g7Huf1RnY1io*FJV&9Rp26`VP{^(*ufS}nfvxpgSKeNvp$Gw6g z7d_1YN3Fa1wczP-3T->Io6h2KV)*vx4Fy7-M<7LI2o|XedqgbbnDra590EMr+D>MD z>P6K13W*0QTP!DD|FU*K(9M?#1^IW2a?QC&C(;y|AX5!z>aFm}8JqP+2p0|@8Gj>$ z>8i<9$s2*k0T8bR?n@Up+7X_+wj9J;a`$?QJunrW77Q07)i;4eHHK>cJmvYxg>)E6 z7J;Z*vEZVpMY%`r4{vxBqN`vrn|-1X18`|YmI5$-U=@JtcgoPzw4crSr9TU-3?JB2 zEonth+myeFb5VpbTu`Xe^aUcR#cgEQ!eI_wcLCAQCy;pZ*E}xjWEms+>}4-$6ED2C&zum+|`NZaD}VljnIYV%AXz`zCEIWC&te&5OBSQiY_aaSy@fmfp!Kp@{3 zy^td&>~a4!WRZ&I(t=m;@}ciLhrf!OY=#*EUw6hwPil8k-Sz1H5P5zOKb7q?gH+R5 zZF8&?7NDcKxCEEkotK+q3l;z9tNe=MFvCC-UewP>YSj7f=;jxwZTHaczD?8EI6#9&3kE|i$ zKN65d7`BohR6H!2Hg~b*H9GX5%>}wA*oNBwnvfRPs=a9lbeTP;&gbc1E;*Wa1Y>h+ zi>|mdt_lmR%SB?y36aKn)T^>AvgRbssxUIk#(?WY(;mWx+P{^SU9kc6>FgEZ$OE&P ze;u?K>qd{w?0jA0vgr1&;U;%*-PAgzW+CS#El3W!6c9=yj_U6!A`Ut7<7NqRkNrWE zs!od=i(1I%C6!J4g}2pNy<$O)+!5^2fpxdVx_bbD;@=k$mwMfbY)bDR$)e$}WW5Ek zZ-J-i!B#Ya7d&c<*~t2p)?FnVA}zWrtedP+@hKZ@2imEiP1%?A+42RkKUoiz7Zkf? z1X~FN+$g!t4yHVpJs|XapwpIjI63p<9r=gu$ukG~Mt0E^=)bTwQ0xaxRo49PYzE=g zyeCew91nPcYhXx`C~H;st_cMtbZkvd2+Ao3gjBum@6l6Z7rPh9k_SS-walh29GLrB z?gw3(+;G1zcL~)CG#1e^n03H<;^MKsc&L+rNBYfKz1RLv(^;)$JZzgRHir;q0fB^g zSj&0ffaA}@jR?!wqsFwabO^vzO@!Gxh%FSAY?CA3*L>IMtJSt-?#}DEtlLK4jx6o+ zs-4UNrpkSRV||Eo0!Xx2CV}N6^Fn518Rd{Y%?0*LW60b2KYW#LClr{q8IgZV#=|a+ zV7`u`N*4zNTM!bXM@_%JP(!D!q#5K|H7u}>wv4|9lY!XyTR zpNVl8`6HPJo2f#gB(J1VKL(z%gEwr`rmh^>_M<8eOCW6GgO}~Wu=a)- zaEoUPG$P*Qa+hpi#{G%R?5zmK-YV+C1-X*%;ZE2f_1h(obnUpXzG%v6JD5umh)0XBvz%ldN%Q7_fBn+g1y>|KsE=8X#5MoOWl#Lb_tnjH)9ai*ZJr@0_M(S2lDr6S zMU<`Jy(GbC9n~ihHNbf{F62W3^#g?6DlV; zUd|c0pY_T#ymZ7+E-Kcx+SNYF;@puM{_lL=W;wDX+;TKEcngGs8VLBwsfw=VpjUGe z!HgVo=Q}&nYU@fJ0j|4f|xz5V}GZeM~ddOjgZBFh1L+#;byt#RNux>I}FXL_`CV; zxP0WfhPOJ>4piZ`*I>AMT(utE7~z?RU6$7v0bULQA8qBPc_M#hR1Ymf5hM9{OjUBD z;mFS0HG!pk4LmA#UVlEP_nqTi&d8h~q`Zdj?Cp0P440Lyrf*Jw{EokRf0H7@&@b9y zUxq!2J@7$0e9P=Z#%e(Nhm@Q%Cbt;HUNuFK?6-r@`;#^41*HwlEiiAn#*ph2xj;!{ z$<0Kqehknl`PNiUu->xs`y8OtD^sX*8X$E6xn+L%j&t3y$7Mw$&5)0Acva)fUN;jp zxcgS^39T>1pxPKT!|RyqYF&4#ohSk$d-=C@3|r}{ihZ8AIM1rM<+m|1y?c-1R?PwS%K#g$?a z8%iaVR7q)ZJi60c^ipmCQ%_9RgFW^}`3WD=yhb0xb~P7!5OsSWP_My_yjyMYrDf-R z#CnPn_QD71oeYk&Ce~ZJ*HbS}`x4U(z_AVz9DJ7J=PSBs{@TaSB^+%+KTRBPCI}e# z1e{D1ypw#zF!+*9zL-i=b_fspF6X+h7@!OJjn{$c^&js%RoWk-47rw>U=HklNw z?{ByN!WUNFJeyzeQ@ui`sfCRl<#y)JKQ)akd06U(Ht8;+WADSm_5{xHmEo>UQX)J`jpFd8o98bDhTT9`tcuZ*)-jVN-Xl*}uvEa4OnPX#eN<{pCNz zdG5+a+Y#-OTNn3arQ{x*k2WbPs(;jHR+F~u`PQ2Sv=rOEH<9Gw841INC!3UXY`gVE zNZ(x*$STO7_fOyaa&M2wd<(>XiYR3xCZ^gZg`TrRn>OQ`L49ZR59y%!REB5%vGL`^ z(KmESXiKqf@aayMQUa{+gC5CIe82Jj+((w#sb2zt7}SZ2bZ)w+%kkl(5+!Y?Oc=II zzu}rqyGS{NP0_CYVVlD=z(*58-_p1R6VGkA7YaDlO+R`+>(woOMAN44WRD%yFEw4dVb*KYpXZvKQ7q^a#Vf|VGe6pHI-wb# zfi^LickbsUnq^-*WT8znzPG{Be(2z9FJ_}n-u_072+h3jb16LiM$KX5pVR z62*{u4kI!%k}=@R^eU9t(0*dQqVOE?%lbuKSBYm5Rnl_dKcl)2>o&Yc!pD{7rc##+ z3$ZZ$h-Fxqx+&u=c%K_vY+?FF*@G_k!e0hkX=xf_T`V_CElpXl9$&iFR+@S_!b~L7 R>4T>OCf)>36sXl|yG1OrDvOF(c38SyayBsps(&X2KEhNVpE12-k&M!L{HBxCR^sSBGbK zJf4bh*Yb{C8?KBUQo-SzNjUH<#;%E;l`$hDD=~2Nl<vNW@LgHZC){ysjgQ>puvLq8E>B8N&74j#iR7tl(o=Jzr(~v1 zZH29FXbQ`J6m=p=;X| z_*Vr@%Z<)Y&C2wo=1iTLnvsf%M)i$nWB-(NJ~o#bnfKI zVg4xJ%r^!_5^Ri|t!vfEH^&Q6&Se-Pnfm3G+&Y7H+=lRI3 z;M=g;GOnTH{{T}(8J)(K-n)^Lz7woDIVCqbZEjvpYK_KD{IuNc8B;Pc(<)%A4~j_d zr~JaMO`L>rbti4)|_BE z%JhtK<5MSP=O}4kZ1qgQ<*TARqimtBEBw;Z<6-y;H%2@APqQ{257VKrGOYPqks7N) zscoGx&dr`QossgK$5zjL1FI(r+gVqaZ(I=Jn%BarS1-6K9Lwm*oz<6>nmgUI2wT~v z<+2ZErFz0UIvso(R(5H*v-2`Cb3G?rJH(CeNPe1X&0w`_YFb|O?3@gbJM{`uw{&*) z$qld{hx!!6U>8otknN>CVirbr=A1Oo&jBa?EUbb*f>m)gp6nZDcs%W6oe|8MJ~<QtDf8iYzBRumVE`Q0d4v@ z99%-nqa6E4vd6#c&I8!urMt)Xm-lX*4l%AQ9J1JvEs%O$rr(RFN8o7sD4(<^b z2eBWa55C6f*wh?*Yw=9Y&Z8$ho*maZ{d6x(`hvnoTww*Qk$7{s<8TP}V`rh)gg1_G z3cMa$YiQC)$De&}jxzoPTO&6FRy%{6+|1d|!SUrN$GjkSrmtN--5IpP`V5>q?VGTqaeriygv5tNNTus|~ zZeC7a_VkXPUl7y-KVR<@$Y~TkBQ-1SBj%6_3XFF$mqsU@oK?LojN?hbLAYm;!nH$-{(v4TnTpd zf1fA+eU1covHa9b)!S2)<{4}k5XmCYm|Wyk&|LlmZU7&FH55<5b>Mqo&G}nlb!ny> zKhlklwa!(lTX5@ir`q!~9d3oKTx!5deSVs=q&|kFABL6N2jkpQ(D7{pOHEvJ7Y52IR46K;_Tds+2pa{Cdd9P+2JJO z{hHG6WH=e-&YqORe(hPaz-htEjGWXw?n+q{s3#9+RU|JxZH6Y_^{zb?)>OTfbk$+| zzJ!0mLdRd92WF<`<_2d}19Z*Q9yc?ks}bl-Kp6xtwn6^y8@&2WEec+A({6Qos41Jh zDprY%m7jY9FS`n5Q8CS#;Kd{UHfIQaolpO3tUjCXIMAJGxsyDe_psIV!7e_4t;K3z z$7z|tRtt8+>hf+&od!JWrh5Zh`u*6d*tCqi4E12}QaL$uj!e(;`E;EegLkSIaI1lx z#>uXaY$NY<;s?4My25E;X4;$?%HUU5Kj!i$a0KZmr=`t|&dBw|W79c>?P2v?Ww-_G zg;lZh6P7zI(U_%j2@2l7r)12S96fucXY(q@ah=OEqcgK7F)Ls`)#Q2BSx)?E@=@2f zUF}qu4^nw~X_Gyr)~Tv>uQ*7o`tQ0mPHE3zt2%w|cI;MFt@_ojEEr>)iI)Ux32wkm z3$U3VK^u8Fhozeb?XbWLOtl8GlbY@uc-mKF45fTEk!s>(uO- zEKHB*MQqKxX{6JN8Mi?;d%BM=oHi!T?IFVHJ+7WRbctUj^7zr`jqUP z=(N;H>0=&p;x}w`@(bJS^ymWD?{#c#LK7ZwDs1q#_ky7a>dHh|73ktRyhs8Sm`Mg| z$^9fykBq?95GAmbRTrQuR`S|DD*2|%*JztYh z?fw8(hfdC(l*enIw3jGI1MnzZA6^a1?=Gj(ESn&(Jb=dU^gLn}R%toYgkwtrlEQ-!emS`@Z!wJ2@k z_9czlm9y5??zeqc)1m%qo088wIj%`T#6z#&`)kV0Kg}`2hI^B&YSCfaM_;|mtAOuq zpLM)VLTE`jk7t;5qD@@rH-xUWL)}9>om}#} z-{3IoIJ7Lxs^2le_j#B#relJ?o!{f>q`t9IXT^kJbj2udrN#$BAI74<_&DDQzcr>) zg0Ff-tGH8w|9WN@A9@PCR%C~O@4<>z{mu#gcMz42*Glaa;BcTVsPt7IJ~>WNAo zPdB1G^7ns@)ys7Z_}W#rin}EE(kolXyCj6&&uAnNr><;g_u$FO)|fzoe<;J(#ZIIw zZo`VPt@T|3{^zhdlv&?lsj%{PVO>}dvO?{u=2Wqc$50sVuw5`2%=v5KJ+b*$q_ z3I4h)(l)q+TBni%{uC^AmR*%FgEbV(%sT09U^TtEwno+eC8}D94;>Iu&*NzwOyM7n z)d#DbwLU2jx&w=;zPwwQ0?1x#J%g4IVb$-M;J+~GVx!T$iF>g=;K`>~;Q9B~NSh~}QxIz`Xj(a0LpH^KiJVk}}s z4OD33#$;wS>JaB2M<@opyma5)jjb{L5<=fa>}oaY80YWR#K|kfitHNjFU3-gC~i+o z7={)e)!P*l#=faCE7-Gt0G9g9p8fu{SW3l8XI$UHa@MN`tvnmL2F;$4zFv{m@%{;+ zw<0owr*;b=kZA8DHLkFV2PF7=UlHtgEx;SGdXv~^o$3?tzlxQF#qK~c4VpPU!>}>Y zQn3V@Cw`}g=)2rPm(#^qAE;N`0zXMCXLmTJBgt<|)o`G%C!tNuw zFr82jI|HqON3hfr&OY!3mfBarI@LemA9STtu+NIz5ffHss9UySxg&`ca+Q;%GxUA1 z;>e_;U8jXuW3cG5;+QZDRnY0_11&wCfbEzX7x3+ivc?Qc@ckBL6+_*xwvG==@ZWs3 zGv~>fwm*iYRZ`A6H8sY2wN-pgg1>7k{#yWAh~|`k8dfhXrmOt1wBkanQ}pA9SZZpR zr70QN+B$x1f`2$GN-d`28KPBX7VY=F(b_5=p5Ut*E%FbJ=0!1{9xF8|;Cn9G8Z#on zm(a#49+42bl2ZCxC7t8^9}rT0^e0O;r!Bf&r22CYmIjg$VJ?MGYj^1A!d_UaoZp_g zx4Ra#S`ib5!9UHE2V>apkB>_5w`}k9i@gH73}V9!97YRB1?<%vapoAygk{T!_tbcWUq&xu?E_4^6ZJ5N@v=14fy7F zv5sG#;CsJ|Rex-PuSUQc18oXe#bXn~>M*;e;8}Le_-{f{wdlQW0pG3|Ys|O=|3yTt zYG(F=m@taff}pe6&2Epi>W@$GKZmGfOsm*{@0VDsczl8{uB&w%%I#{^pOE0&(A63P zeb&_~h7#he;}a6X@|pRX;bj#F-G8Izh@COkak!5ucFr-e^qo6mWF}V!6e>D(3x;pp&wx-*atwPo=zI4 z*HT=|NwWsatyD=&7>2U5iwbQ*lX_Suy2kla38}UAt;~NPmO9$W;C*>H7CjNs+u4OV zYhnYTQ?O`zuQ=a>y{+PD3I6J=sv$VDA4~}NCiJoDPv_EssA~H)-+dqSv5KcBczc^S z!$Jb~JuSAcHKuh!*v);N(f-fleg~@Nhcgj>>}wTgCinvVtmDx1epdag1ph|b=eRH} z{of@!TN1k+R$msHHYmqhho$N{)>*6(Wmb;?9?#e^>prYYaX(^RTNc-sML4X?T8mW{ z7y1>}0IOt1H}4>;{>%h_)*xr!_h`5E9Uf#ABi0yPHj~*@rnnYI;P`-l-G9WrheiLp z>!Ch%mt{|Ne>Rr35iAB~Hf?VBOLby@V(py8(xm1RN9|iN3ur%aT89`~WNa*S-A*hebC%DKSWXpFhp{1zcG|&3 zj0(>yvr;FU0RXHu+%WBL0ej0?=+gVi!}v{UT|Bs2aDad zu(}mFGvJS9va5TXYsX?Nwn!H4deXg!)dkDB?o}A)l;@O?jKx3YnGzF5NVCp~`WDOC zYt-XO8N%F zCpy)sv^^{QbFtJBj^{zFBrNBiTYh4&1GSI#$I^f^Gp5FbVQ9SVg%i31tAkb2J1*=O zH%Zws71n8zlS!H4pMj!6=-*C((8sW1?D6`-^<&5c+(d)R9^ z)ZWKZ^RVIrVU5z923;y|Jc>IHxF0`&rE#I=bm=iSj^)F8ZZO3vZk-TXf2zlmVwJRx z3(X}o!VVoGG{g?oO}DovVkZ(BW^3CC4YEU?jG*5TLTqELJ6hFRhlRHE@NUBl`^bwK z9o8~*nlq28AeRHd=Qk4hsok{YYn~YydaA_Q*DWGsy2o>klGgMtx7y!!Rp{>sV=fnN z%luEF<;Mujzrz13`&H5PTE=I2JWQ;=<$Eu_Op(9kdlBEiTZb_-JRa8I-^%xCeE)78 z>SX`@w#~+ujqz{Q;RwF$L4U{B+suksni!gx!^P8Tv@|aC4nl+NP${843i;dQI@6nJ z$gPC`$lw`n>-z|?Dzv+^RGQ^^Jfm&>MnX(TSN{ad&fDK+w$qP}|5B`>wtp!hjj^N0 z%n9mC2wl>@#B%cKc*AA+`0vEhNU|{d#Drm}`<<)?&Q)W^F6|aV;2OKEuL)_Xau&1Q zU!CtPRkrF*0dKlhdS{}42U;&Y*sBTx{?K`jKd+}a!Fpn8m*HgwAFXy?isLi=xRc)M6ds}jANt7z3rNS_ZlnW?nM9Un;nhUNqjhny~VMdQz_TAxT>(@ZpBhhlJmVW zVXonPes6KB({XISY?`@PYLMR^zin8(uoyq8@RJ+I>B4AsT;!Z)G?p6!hLYKDrb2gP z@#!NF=lfxiHKr(m>J}9x`q$qU+{~5!ODy-sL5Bydl;TAH+QrV0I;YvISSsB<&AipD zh{I9tLcPhbiuxq% zxa(CmyZm)-56*#9sx;n8DM|F-}z{qgU6g-Gn&Gul~~-EuvFU7T~{Sl@hZxoV9wQJAJ<0^Z41>BdC= zlW3X(+}P-w@^?GUW;GN9LWf}SfjT}ebSa^sb|Xp&>2hXIHg9z+<>5sC4CCa>y^_v) z0E_!ea-9D-p`rLXV{-Lceoq05waD7K4QmLNy=VE~#TwyQ9Rj>>irAd!H$~2U*WNaL zr;DuP>k|Bpik%Ab34y`Oz#2?4I$}Ufm>Xs9MWNO1!BI619ZHB#q@B9yKkd?-_Ho{K zt&~R-{f+NshbA=>o=I{C))?F3a_ntlMQou8>zrMmSui{hy7)e2d7?|4|6M{_5=^LZ zfzbN*tALW#asD(y8awC0z5%OinRTMfTF;=>T_23&Wr=?dmfGPgi|?>TJJ#JX6&`Tj z&st5Mq7(Oif_U&P`_ONjH=+7SHcrqz^#rM_q6Ic8q4BA!U}*Lg5F^R*79V>y-8 z{eLr74=2}dfv~TzG>ghg^|rTCwk3MkSw-6t{pTMJZb^Env&oqd4D$GZcaD|vWTO8m zwBco$U9s62__ECW3s96j?WL-pVQCy3E8~%1&*-DfhB8b2bOKAOfJuYZ;?ZDpA{WJk zVK|+wWSg#o4&iK$hSS$es_;SL||*N_LFQ zfOm>j`h24QWi;i=y6GGUjoPgqWXXrFAjBM^n_4~-Y`7-xtymg1=W@5N%u?KMSZci! z*Y4TNt;tx|I_2N#-e3;2 z(_3Vf9-ybuhU3A3lPfLd#YEo^&soJUCin+FAM6Ot=whs1IMQWw(n+jK)vmG6DV{yB zcObMsRxj&BOq~BtLfuHi4Txbmg2hX_X>r~#tLR{&uAB!G{ZTJCgX`Q(CSi53D@-H3 zYpkM|6aBBFsbpuzta-qx6(58-#8a{4PwFQFp%&ISYwU=)&~t<)S|<*~`LBJ^)=^k>Uv}1q6E_x1 zGuyFV#!A9sdN4E<4ms`f+c*2}Se=QhWFK&Iur#E0I`6Ai%BzX~dWW4suVSBGH)3_i z!}-rQ7qFb1bv24T;?#jxCrrZvEc>G2-%Utq*fXvVcoVFM*AheTeMP$s|4qdEj#czp zqPMP9`dXqt<5g!F)Ua#%C{|a})v%BGe`BdHc=g;h;B9S{zMdHB_wc(2?&tA0ZY`)F z6X^N>!<9(a1XKpCfDc3iFK7co0E25kf5QFCB9xHXXg^|QKrh=&8|+6cJpjrBwio*m zd#(5{>J}&$`ptg+j1}M0jTeW30YJG9ba@c0M=YI<#C|Sk=|ey{a1D^nGVcM|fihOa za3CIGtAEalXBv5Y*4Z!WwwGgyEN~rAEPH_ch-Hs;nMv#MSYzL+TTqq244_KQaybvy z^JlDFX4|p<$(kYyfJ!d}dJ2K;n}PCQ%XJ!1UtBYlS=GtOq{54R9-vB*g6?9Gpk2nPUB!lOFu-dPT z{|%JUd6$2ImGF0<483ytKe!U{mGP5*RoDM=mQ;-&;_7aEfdUHGaD~e`9KDGf-_(s4 zYkIeE?LTAnOtc$+IZJBe>Mj@9f?D3rjSwq?7+6v)KNKG)U7q6VQ(Zd)R{0(~ z;Ig!7uH$rA$I>i`E~|iCH$D%RJ;$|gaCt7Qp<4v&`QO-HfB&1qe`laPZ*wyiYtpTR zHDpDuE>^JEwZ#hF)eR@UB^FT6|{+Xxomd*#Hz?suKu*EU(PCU zr>kFL+AnRF8zHWM{k&_772N0Am$Rh({7}XRVA(Ia{E`fw%URMverQ=Aas6H?a2;Q9 zg;!nsa@Kl&-Hm_4jsG*2-`m8iLhrhMV%hJzwphVquHN~$D}3Pchl=G9D|o`S#R{I} zM>*^0@h0}n`5a5xf9b}amJ5$q{rIhGU(S-gbM-%CHRA{3DRtl`D$QjDBV9YvXSe@y!S=h%;qTijDBxy%Ijb!(=;BzHySjc| zE4xCR1gp`xzFv>D{KL9d-nnY_wY4X@qI$c2ePr;673}BQVs-fd*Z$vF6&dLIiDeIR zZE-#9G@oapJ@%Py#O17lvfYF;U7qFo{Tb_|nM1r>=DL11TU$@mP1fdEh^ky~arrh_ z)mrR&ixq#nYyTPhtnia{^`{6tEAW!zO4r+FEB<6%>-v*n_FZW$Fa)SsFK6iwy8557wzS8IzY>1eKC7I7eJXt5CKM}pf*;E8q^tkGu=4rH%}1=@ zso;!1g(ZhiT>jMM&*a4;R{ZC%`t-D`U(Sj@im0lj6oEIZkaAL#001&8oM84iWp zzzbj%c#Esw>hdC3k68Y<*)}_#0xIBkSP56S4tKe{(&bgKdSDTM_VHSdUotepoes!Q}&Pyjc2+u+krN?U!Nx zd5-Wy>0fj0H(~j|1>5WYT{q&G%OALW64n9q1+0uu!+OLDe&w>hIiW|ajK6hlv4Y>b z{1dE-TyX8*%5hhcpdaE8ekg-bSY28Pt^!BE>dMBjj^GxsCS!Y;f1b|#Pz3`r{(_Zn z4DsSvm%D~oV?M1|psbUSl)9J8{a{sLFs#pm<6$M80PDG&rKh_3pRwX6y6Gpuy3)^v zl_WpJy)P253z#RBN3719@9GO&E^zgmVO4Mmtd+jfjb8=p5vxyDyS7;V#jbv@tKX|R zs8N0pK{egz@0W3V2v{2qrj7&~13&sb5<@IwvR>-zl z;U>z5T*WLDRW+reYNmZTsJdAys$ouvYMR&(sFqnNs%_4Q>X`1KP+e0bs%OrLB2035 zsJ>Y*YG5uvW=T298e4%P8=1`&5Mn|Q!ov`nn3OPt(-QVdh%|mb!rD-TEI&dsvs*&H z@(7J8BD63W6%o!$I4a>P6Hy6aQw4zv>8$Y9sVE8MP74OE@Z_uZgIGu&D;Z{5lB9=CFj(H4&ogA`CG3brHg9 zA)Jsf$VAmc*d<|kJ%k~qR6=@fg!l-AVP8qJ$Ka+z{cIgslw`t}_=TEQvrE+X!K-+1v;rranS=V}$W0r7^;3 z340}^8h;anwG9xmnjlOvyCw8%h|s7hLYm2Fif~@SQ3+E`L?ptdMhNpG5i-nS38Nb$ zL|=h0-Q-_^5Y`0YgoG>;)eK>mgyqc;vQ4Rk^ri^$%@JmqrOgrQMIxM)kZWRFARLlV z(gI<&IU`~26$pc_M7Y5eU5U`L8Nx*g`6l@)gkuu6UWIU@xgcRlbA+)i5$2oCEfHc` zAcRLD6quAKgwqoCN?2(8S0k*w5+Unqgj>vR3H`1@Xw(W}k;!OSZWSS7#)QW9gT2@$&W?|yBgtygyklx4ZWDBufUwydmN2>#LUatmqb5HFA*?gP2?<+GR4l?S3Cm*<9yg^D(z_tU zcSYD{mUcy`7eF{GVY`WqLpUU%Bo5(eb4J447=%IH5O$iPZU`-75iUyDZIa^=j!D=W zkMOLyAYn;Ygs}+-d(GwqgqS#l@I-{?O-drdX$gBJ>^J@-gtgrevXT%EnB5Zk#UnK8 zj_{Jn=#Fq+!chq?n}{9=n-UP__dqyo4oeuFh!EWq;T4nL6Co@K;e>>vCaM?0E(yzf zA-rx%C8T#pi0_T?rdiq>p5p()!d?ldj9)v`+P(-` z?1bJ=&29<(`XMwLi14||7>ICQ!chrdnutLNo01Xc4?;L&4oeu_A0c`$!dE7LFhZEl z)DsfUny4WNyCf_hg7B>=m5@FVA$};rIkR*qLcKusItiyg_}1;RZP?vsH#~gs%A<>)lK{Bpc-bWsHQn3 zs%2uYhiaRZqB`b`sIKWgmddppLw*~_Qn?6o4uN|{@;Io0Subj6E{GbLVdHU*xgO`I z$K%|@cqbs7mXJ09A<}GOk_4fSSG@vY=lAPO$oasbe@SY#4MbNke-F` zxrAY+{VarfGZ5CyLb%qPl5j{u?;L~?W@Qe-+-!uOB#biMbNSJ7Cc?&CgcNg5!Z8UW z@(`{w>+=wn%t8pAjWE^>n~e~YgYdM3@y0s`;k1ObIS8p{n}oHw2(@oOm}F9KKU)Q;Oi7XWHKc-DsAIZZfAt^G)o0Xn|QNDllh6g{J!gXrU<* z-E7W@ZZXLP(5+^@Xpy-fy3GtLgch64q9w+=5L#+dM7Nu5qC1TLW@wp76)iWrMR%I& zw?HdQhUhM{U$oLh+)Bmk-Acvh-%7B^;6veHX&hCjTykxpyI) zkg(H4twd87PbRWVgQ*N!623D24G3Wy5VAHPoHe^8?2^#vL4u7ftMDgqY0;C7X3c@S1;Z))hg@phs}=nxaQ=S^EgWMG56h@}mg-9!1#tC_<>Y zAmO}(v0D%-n9W-dHf=!&--_TjDO(XnZ$;QEp_1`Gh7k4`Le^sl;bymlT@o5Sj!@NP zJdTk5IKoj0)lI|`2=$&onEwPqO>A)Js<*F-&u(DF%yC4{3AhM96k&8J!d?k?82@pEu;U0>#}SsB-4b?5X!HTX3X|~x zLiz^?M3uEF`?+l}@U7xSGD%e4{D+(Hl}*@5J?sw82L&fh(K+|MI>bTCX*~ zSL)>R#8=)Bubsf``xhUpn*PD(we+)u-uRdIDMR#7l~OVIf9fg;n04QH=Y$r7JE?y2^1kB9DrrXe#EfkIPl5bq?G(4tJ5?e74F0!4YTCCu+yCm#F6Z69bN%n$ zM6dVo&QpJQU-5Er-0Jmx;2VCsor^#CzYTeRr?;Gszs1>%->c-BIJV0TXTXZqynDmdrn{`K_&scx&NbsV%ZDcmR)zJ=?MGZq zU#n5$s)0vcEywlKFKZ7r!<5A}ZqyB~yS~SuM(NQvZj^=k;SL3O@?A~KV!TKyz46@XJ9>310;?GWvp${31b1vr<`TB4~j0T_F|J44fyd zUq!jY)s$r+&}c1lwHAaInp4W+?hwK}cM`=vyR_R~?Jn27CHf3B{noy|Xr!W|z;&km z8nUQPEi`DB8`X-irj(x5uExGo_KmYOt`?1Uzgeg(W-Ch`<3_b5e66i`Jo+M&qT7K& zpf8~nxmtU|3(cF#Vh%wK+C4<^&(jgy2=tV=?wttF0QG@><3ibX29r(X-DHu5t%1DX zjnbc6XyMjuy{pBbMWJbMgI}3qNA%P*vy?>xqO^oIy6$m=zXW<7arMDkld3GXxKTUYDAnLGSKH}o{m=@58WY?Ik_j&~+myuuf*OTq zaOa=>_a-U~&+j|cjunY3dttI#t6=&P!#yuNQIzf^F}tR#!tg-A*k{0iPA!VAsrBHwkr4>BiS z28Y05a0I*pUIjQMKPBs6JO8t4|*U8%^pxz9!YR4c!g2=jgZ52Ah@l_-ZDPAUG0?0;53+ zxE_oJp7s2m9 zUs1mu=-65YmV-M%K9~n?1UG^CU;)tgu?xXMa5K0C===6sA)5ULti{b9?^KM5K;u0b zqya8f_5qg;XMkxS6J*IIBmHW)PPB3$1n49y55j;SR0MD1`!0A7ybq3nQg9qR2cFm0 zp!N~i4_*KVz>DA@co`f5hrtn`V?)Qp9uNtdgO*??!@djb2EWsj-g5jE3ix5-Hi7R6 z{{VgjJF$0x-QW{&Rtw}C@GtNg_y~LqPJ)MU7zeaaJ_PRpEw1B0dyu{pr7u{m0XilP zCu&|-~5^k(!dlj9b|)2yJ%a6fe2)G7ZYa-YAY8Ipr90RTgei~E>R0g#` z9iT7y>aP{70;_=mYr#F#YaLh*?xUXi{XrduI+j;~aD1u&oxi%L>0UMs=q{#T!5jek z_*j~e1g-$hK?}2gov&{}6N2}Xc0G6iYyb~}jo=~hFem{!thI|?1GLdB1IxjkU^bWw z^1(cCBbX0zfc{*>RFDoPgE-I)#DfGc=XxT6B+wo706jr3Gygtcvx1HUJA)SBN^liu z3L-%>&>Vb58DD~bffL{jprffHcnmxao&ejxlVCe|3Oo%gpzpN#==XBqQS8m&C;H@B zEu&{JKF9b1oB~PMv)~+%2WEo}WMBb(YtR0+BU}N50Y9h+7J%(ImiSv zKo1ZAUl6Z9kMJ=#21>yj;7#xr(BE`83UoctU#xfpJnHqB2KV_Q3ZBH+4mN>x;6Biq zLhk}Az|G(ma4Q%9Vu)`8qCr45hy%I>{Q`akUxTyYB=`ut3EF_RU^G|_)_@Rww{#1E z=gI67TB1WcALt9poq)biJOJo>!^6NeU^o~7MuO|W^2x}YAg$fpGVDWvZN zuLOla`P>0?&7Vd2_B}ogXI;jx05w4au!^{zpfAuBS%nL_U0nz6qtNw0U%?H=iSMMq z?%;Fs&>yN9ep#AA!VAFyS1Xu;Lle*zbVV!#a*%crZVw89G~EKnfWbh%`d~H(=ueNF z0sjKJVd^iZ90D(a-5^-uLeeY*mo=iGEHdb%VUWW-GS(gPCNLi?06GJ8DLe3*5|u^#Z%Eb5 zwvBArRS8xB;h-`gk$v6s!`hbb1k*u3ppD=Kun}m)YXEH~)j`mAA>nMGG*f}n^#NCd z#-IUEx(HBHx93{M`;f10L4E9opb=;SqJZudnyJk|Bxnk*0L{UbpaqaFEeUAD(%8iU zjcq&72DAdLK{RL!R98(pZHOHKGq|8^*XxF$F^UI?K(n+v=mC0x-axZ94QTeM(8*vN z7z@<*DtH*scxyuS2dc;*kPMV(P}AlyfbwmJAs8b-Fymlru0^{B1Y4tcX~D{A_Nu2w zx~%PZ6i}~fIgJ5o?Ie&2#)Ao9BA5b(Q@$r1OamEU2FL=LE@T&idEf@11wIqxfLS0H z8z0FQ%*KrsGc z!kfV+@F;i$Yz0cY4+Q=85DwT;0QPj4uFH;CGaA685{z2G%o+wjMi*E3i^XKU=Vl> z)B$e+Rs2ox1}Fu`zxcopU* zw0(lQ3R3vrKs}|_T>$67ui#2B+3Q>@%fWwO{|+u{{57uXDi0Ap;04NHHK%h_!t`9c^I?t~KgTWxs7jy^u)DQ`D+%^UJB%y0k7oblGoxs(gB`9dY zkKjiHT@)0)3S0?vdFTMz0$oyD1I4!j^3|oa9cT|CshH4_uzF7y+khKZq0)3uO9F|& z{a91r>4VV=^Z-4<7#zjD!AQab;C>((^ale$ee|KQx^#%k3keS+d<_^0hJz7cEVv$A z2U5Uj5RdODc#N0vPbDxOj04*3Ccu-xM34!lgJ~cGq=Tto3P=M!u-ZrK!0q5I>^H#y za6h<6ely_vfIbe~3+@40bq3~Fcenbkip?Py+$6;_v9rM}msi4f0kwApd?#2AmYK1S z`5F}5PH+jh4crQD28Cb&m=A6O1z-rt7s9uIMPM;l3hn^QfU@j`&nmb#Y{9F+-9XhT z21Q^kC;`gv4gCqX>KID!I{X^Yv_A@KCcg?F1TzV12EPK7iMr@8cp1D1UI6>R^FR|& zTjqLr4|o*z%LlQ(!09;o3{_dxr3HU<2jbA5R{HH-Pkt z8&<22C`>w~(acrvEoD+I0lIDKqnvK9`d~d3Q~>2c!73az^FlE~!0&`Ff?vTeU>@-o z;2*(oWeT+G{eb;F_zrvn&VsMOPU60TPlHc@hVo3ueHTcVEj|T41D}G=!5835a0dJfv<5nub^%>DzQtCh@6{fD zj({SBVC~PN{S1Br{|3JSwOSQaPbjPwt7U2xcVhd-toT3BeAr%44yYjYu%K6<`uvp! zCWA@(1Thily{Ia14XjLt!9&3iFc|a)$)Fzy1IkSALhFHsKpz?#0KF%z2`Yp7pf0El z^d43I@{>8oY_9m9f0Ijn@u2ZmEg0&0w!k^iS)1ti==mpd3rTY6D#Ojpl(o&HEn}yOVd^BKx3+|)ifOiIs;{ z1NCMqP%lpaY!1c%O{{TXEVv$A2b6hmNEB9P+7AD_P__7S?fLGg4cjy7U@YFWN8P4z=xNpk=x^kDv0I2Q);=b1s+&^1%&2 zc^#yD``A%t+E?cQjivU}9H5M6!+D?%KDjPm-cn_}Rr$c0WCy_I@lH#fhU$P=fS)R$ z8%@DYZlbvuDr^?^e4yK$Cg);sGq?pT1j;~u(sY7|gZgcRmCqtr*ScF_o#VfPW8giY zLNEL9R#29K?m~BxKv&7-@G@`*&@Do@2kEP@SArGbE}%P?(yRt|gEe3>S~XA({6S&P zXQIEl);4r9zaQt|y|&tJa^Y#$#T?(|OVa;iUT?ArHzl8Wa$J*wh^FQJD78>x;mUCT zclunBnO|jb)AB7*s-uj9tHFoE-m3l5mh~k~%j+r`filAk+3o9S?%nO%(Iu>$p4#A|7?|$a;Ci=%t|r zLoa!ZENAw~BNGpmSglfzAAF5VdtLHaRL=bPtgnOb+fdVTk8hywe5m>El&^Lu1@oPq zyY~3%`6`w-kLh^Rqa~d)Y$7})<;}a-pms} zP~JSY*H>JY!#Q%ONp+q`Z}`WaQE&16;f`%Ow&_5(gj6sKo+HIg70i>*QJuvV?tb3a zq2ci`r{5z#XgltzagkrTMYd;%{bum-8=Y(Fh%TGdp3ft*@VuqMcz z>z^EPasKNg?6TXn>CARm)g-+@?M79zUy~M2oYg!&sZ!M#+ap$GJygxyNglo})%itN z^8CHJ`A|&W)u^S99GbrDt7m!~@YVN?;&=CcKqS%J130~1%WM$`oAeR2V73<4S)Ecj zcX8gU6w}cew$rsttrzJ#w<%`ci)8n6E%V5GzE=J~o6f4Nr?wgTOIb7PnQHI*>UXJJ z+sSgo+g~@Imt8G|EW3~;!_t&iYoQEo`@#beM-J2?rjt|He`VxbQQH*0L_ZaimnQL+ z?DkJ(eluy^rRq67TiYCd$v3R5HGeul_Ie2pQ180tYX+)eJBCtK@y!e0ar+h3X4_S1 zukLj+?qJ?HNPAuP|LWU;zTWlBjF%au;(8p8Wb^D>UrgMT`_y8x(Hx?!o9dZ8jKZHx z(gmHJIg=A%z9SD`tE#5?A-JTz87+RVzFBsNloQz@wRv0!zvAiIN%w!}^Nw_taShEr zJR6>7bCO4({v(T{xBUBMw{!-kQzKL5FnRQ5Z>osLvAerB`1jm9`r97%s;toX?owZE zGwLuaqDEtL7v4ecQh|>g>YSMVN51KBPyM+e8mIPcy0BiFINR18lUHxsbNui}7)!evm(B!(}y9W zI}ATs{*jl6(au31u4rl=BaepjBAv7qOHLiXwZf+z?NaSt{v*=-cEmTZ%m1vGs-+pa z?+T}n7FUQ`H)z9?50h3S#Lir~nOX1(HGZqv>TNuuIX%5##r9X5RH=W3 zUGH|sE`>CRQVD2UW|{`D#=7b!xsb+BpgG&pmzYgTy@xd>mRG)#0AXZA_9pn(+~t zsa$xWdfN2gI~^^uYsd_1=ZR=*`n^dFo3(XX-=Xf7E9bSpN$bj;EgjpMC*I^JV!YVp zKU8+TaAs#IeD3ys`Qvt6U+I$bwQWtcH}FWsqdFcRHkcFt+rpU}@u0IcZ7HzV8w|)d zc&O8=RrzN9wvy_@@L;pm3_9P|Y;+vC87gxBhH)&ZK9ouyBgm*Lp-=bb8 zJDS3`sMqO^<~7+)y{%Jh zU{Js`eTVLw#PF(vM;z;NCiCE?v83+80YC$C0%rI-q@Euz54=M;i}6%bqi%WId&66| zRmW31Jmpvc^PN0D3Ydg<>Atf8^Ks*H^?W}EOwPMhyM3&AtWvpp=DBy-cAZnIt?nCt z_n_(@(mpnL>N=-X2j734DmtD9`Z?fw3{>K$FzO7>X~vW zw^Q|ivz52%Wy%!eP+#PB53_&B3dKglU=@Su#4J3|(Y z!jq#;v7AG#9;%T@x6P=W4#;mWR)tuxcsN)6Qli{)8f%2^Bie?>yylw52-0! zS-lW!L6DvJfj;~<$uHPjZhBMY1T!$0iIb>y6K3#VluV0VC-d+L4pUMdJmKrm<*yt0 z7a7rn(Y;NZlT^u>E%kig_ck}3q{Dva!$D0ttnwpoywNq}ULBt70<0`gk4okVJbb|` zYh+*Z89DrqEk4ZKzD*~sLr>ejro%^+@ko^U`YhMP1s`!|E8_00F>9arV2hh>sm_!R z-o3x->%`pn_0*$FYJ9~xr0$L(BP#jYM^vs&KgVOkD{J%boAy?Q&$}Ro-GSXa*o@%G za2!wV4t*Z^V{^l8J*qm*P_4e`XNG>vxPOO-?!}v9*UY>o;`{qT%Bmfb%&P@r&Ls~X z`$*-)TQ0>kOg8J3wxjE@ZtKa+UnY#$c*$b`G5Vl0qVkzVX({viUW%EVY`!LK!-cL# zqx$!qdGy()jW2l=C!40H$o&aC_%ASpS%bS&zBzZ$l1m;(+?c2CdH($mzt~WGDdw|e zGec?rqTOum7YA{NCfAeK`cf7*`usI|LPkN{h@41!_(xW z)%4ld&(z=7^x~U#uLjzn9`9#zK4GYrN12B{;gD;~9ZaYCy4#-Zx#?n+hZrfwN&Vk{ zu&MGXo}&kw9-p#Hb8EZnQ))hLh;wjGUbbUo#)s>^A#Zn;j~?vY+HNX8_MZ4<8)p#X z?oXsWskD=ZI`iVQ-$ow)|2n(wxT=oj&pn4~rMG(#u@IyR2x2cW5(@~}uwnzEf=oRLFauAO9@7GdsIGJ8fqV zOJIJ}&WIw}>R_}?Ksai)zx&p^(|2Qzmi65hMxM8^>KYNE@2k=KU6M}!Xb%jIK%r}P z5i|f8l3N5#xQ!V%i=fS1Zx=y%Tn~+)*Id4ipoWE*MYXPi!!;cqc?T@+$>%8cNZ_9f zAS_YEoBo(OB_L=9AnG}#Nmoj^i@u$KVGfM6W!LGM`_)olu-61<`vSrNMTT|tQ8lLj zYdatupI~kAUFjso)qMvHwy2#wU4Q!C)x}TJq@sl_`tq)e{si$2sIoE)%)fEYc;XF? zI8@edS0VmI_xomRvP{Y#YS+AOf;-{2!c*Fr?JQB|rP#o;fG|<(5!L+sR~JVE!aN7x z)^(@l7*^K?*Ne=1U5|?y>n?iOs2G^}mAZ5W7*dxWbpKCqP#tVAI`Bds8yal-&*Pq( z(LrTX<@3DRgW~Rh#GRhB>JG#SgFn6l(yBqwW%LpO;5T7rb;f6mLqwzxFL(8#=3u=Z zQ&P7=U)L?^Ew-egoSry04u6*Lo@=pvXdiFdapxsvO4=tlB+{TGW?Z?@8|UEc*#2d81^7sS$pgUM$as6Rxd7#`UAbd$983P-hY8 zc4uYxfm^d4f+k11V0Z~2Jlb!aQlA@KEo3Lh!UG5nkAI-Abge&`-^Z3TjuP8xG2i#^ zvza$|JJn5_5Jm0o!EJUYtc1a@185#Fq)P+n=zXa8@PT4fx06;o-<&*+x7hTf z?jA_q4}jTv5Dh}9JBPCjuPtnH+@3$S{Ip5M1W^b=&I53=g3}J$eyqT(o)ELKJ^h^0 zCx#wJUzL-02hm&f)xCvwF!g;ALk~%B&(8sdY99U?M1Bu3{tz><>ZgY%B`m*q@;oqD zF)=<4OQ{bbH8?DtdWc0o}Bd|w|lHyF=blEoG;LFgnY-j^n8x7(BVO2gG_*2{c zr=ImMgG`N~J-acVWx!w;uy@m!t#mzu6vra^Zi}I(zz969(rD$i-gMaIT2IPo+ysP= zE4!CQ+XpWgcBl;UCWcxflg84igD=%ArPGaM2Tdk*c_cY#w$so@lD{UGR&a5F&Z1Fu zyYBU_4HbgZdYE9t=B&S`M=afPOw#Bf@E%PcgHb(z!8+|fZ}5bJD^?-m>3|j%Ej4Ce z@mO-w45D8iOa3Ww0NDbR5!p0fIy4xLOiykKAnaPxe1A){_Lv`823Z6M^Cmkb<*udK zlf`9_Y(UuQefckgj-Ee6&M$);1H=xHi&Jd3n4R}DR3Ry7x(*O;#+;{FC)c{Oq}3rIz*a0EDUiURrdt%A;G;${?QuVhKo}9Mj0? zp;P0mp*AK$KD*Q3Pb7c4slb4gr6$`qD;YYyTa39T8ZFK=@~LE_Rel9v}JVe677ZMcyT=KvpGLxQT>pW@XYpfxVW^pl@&Oeu8ITPCa1#~r?y1$V8 zD~qpu{S1)FTKhukjMrlRdI7~nLaW+K$zEG|;IoQay~H?TR2ubCa>V;B>1fjKnj}`F zU7vDo^PQg!R9lC&9-@QXC!Y#X=xzg#wd(NZacwO%?UI3~_*!3s(n(}q1WS|Gjogc1 z=i?^}%w;w^?mJG~!|8Tr0o*tO$9YAPAD-MfQY3|F7Xp#h{(ku2Mmj~OsU%qL^R zya%>6=cWNu&DFG}lvk2NAP3AmpEq%uoP;{?ULM)KE|Lh6~F z>t?R1>mItMB`EMTv4Atw=Z%zx7mTjFft@=sOKhg4ro$i4cf@|LjHKA!XMnH=i}}6P z*6vu6f9|wE}UeJzM!!FZJoM&0f}ZjL)Gr#FhCLOi^zohp;|CU^`os zvmjXRGnPZSKyRdgaODYz6(BdCx?XW_{B;2!IA5{0{RjvT+#~UEQm=P5ha}BZv@}2q zj@Nl_C3mxKAuU1^lANaHHb+ZEjEVWKo8mrT+JoA$b@cERT+dzza>{$_6s!nPAqQxt{07sns(qM zDuYa6?%zPfA>MBi^^*JG+oHc6%WKb1pTzfU0>nGUnplwZ}ngn1*3x+Y4@gE zMsf%q`0zExE+82YV=OPlGcpiC|W9P*hZJgH6_#D)dLw;QjBZ3 zOo+k5;z3uUtW5bzLshSoP{Ma77K4f3N*?W}vD4B>O6mN>% zze1~l&fM68b?Er3`|7~&RxrWMLl+byX`X_DIaNp}Z*EhT%R@S+xGD4J3> z*Me!Jne2gwd{&srE}H(dAGIpuK(aOnJj+<*2u_t|P(ugV9%3BshMVF6wPizoC$b8< z*QT@HD12y(tL#AER*@ZHxo%VygzKW{MpuBR9kx=adQR2L@#Cj$=MxR@6)a3LSpZ!U zLkY4@w9Qqv)%=H&EkQwyq)&ot`>qmV;-q_%GIzrr7y)IwAkxaf{#Z&{^-sE~GsL?< zld1uDm`+!UBUW*VYFYqMB_`GKQDSS{bvj#KW|*24rT6yy;Yx7c!ErS;+p{G>pnV%6?kjl6{fuZ>fR- zeiM1IAgv+`dlZ{#AlHO+X)9;oPSUu*$OqutA0fj>Fn|RH81LorV4}O@U6t3EVm`eA z$$&y2AOcCvdNzJ~pffNOP=E)JCA|eWO*iUe=7Af8!rmXa*{DTgCf`@^%ppsy0O5&Mz1i%3 zr}=ZMs}lpkFp9Uq%n5AcL#p+K*`M#rJn=~FiY*yHtAQX!Qf8~n+d)j9t%;bB+IpB; z*uIx>u})RYgiHifzO>4i*Qg@qeLz$-X%!6jfw9xerP}!3*b2+~zqJa(Y{bs8d^a0I z2!Uz`avWqw5G&6X{WMf<6#Gq`9Th|vej6h&T5p;JR9CsWsI>J&1!LcjsElFjj7=|v zZ{bb<@^A~=&{3h{!cDQLiVLt|g;VA%ynvnp^Ciqh?}Qxw!MZ8}>!4{(&2*3uMNrC1 zh`L%K=d?>FJBcZmW0q=I^h*&O{GjnuWYwyww90c%*&I9BU#!a7STTfx9~?mnyQZte zdO;7%*dkCrz9tSRLI{EIHud#^#;;C9hYu;!OYfgW03%%-i5F=7JQN5*82q^ac{$7e zy2C(V1-qN|@0$7f#yC-JLyI|DK63r4Sm~vqd?Zj_;wp|6D#j44ni2Td0Z{dRJA}6! z_Em84xa-Y!D^peS7K$BK;}u)>mU>D1P$KZC>Toy2Aj@6!^7~Jd(Yqkw8q}SBuY2Y6 zNo>B}wdtb}eRsumss7kOQ{Htckrn%`pJ^5fUFFV0&r?+-pdzZ}wW8|v(6f@z33wmv z(fe8ZmRBI*ULEjg;1y8QTEnEWAL$=@z3aVjw>Ao&eK|Lw+R6g*fYsKv-YTM1UHi1L zcP~lKs!##%Aw>ZJdAp?g@Y=$g($V?|Glap%KPV|>gmkiT#bF^~w>aLcIv#8OXt!Y$ z2&s|Z1e%1PQLkm?_3~o_PWGSaH}wOfR8Fh2H6kpiJd>eB z|8`WzUDn}^iB<^gb+bW+PXMz#&N{9Q=z{w+g$&}33QquZz+JX9)5rJ)RNyX$1XO;F zUiq4OQ9nMgRHC{tUCN?EkQPIt!9g>YUU}gBg|A$^J^8Gxe0XZF9!s<{4+?>6?waLm z-geGvbrBGA<)q?|T;nZI*~4rd@Z7OjYqImg8Lu`)dx2<$s-T=y=ua;>RBtmW)LSn| z6Mv>&k_}s{#!i#9dc>PN8=*q*- z@R2)fgOTyzbdGW1Gpp{h_1Lm+#~kPhBdXUH&JATJO%Szc2)0F1bzc+-G?HrzXjVh{ z3$ve&3Nx(&mE$z$3DmlR2q%QkDD4-?_55{DrlbJZ8; zJpBg~`wCYcFwhu z`BObk6+ku~0m3RY7M?Rv88 zvbB)X8p-}qF2QOBZ+TqS$V0B1-QM4;wH`fgun(TIT-33ld;7jUechB#`S4|j!N;Ev zav%NoCBhaSH*T=EQ^U09Zq(+Q7@p!^LB-{?Rjcc zZjNcpKymu`(Id=Z>6{zz@bc^ZMx60IQxtVTM5-7Knwl$!p zjpbS?wuq289Lf9l*4Kx^!ZTe_uY&rm#3@6~hjb`th&t=!y5W6h#RRv}C8_YFU$b9N z8Gk3>8`LcTPma%TcRkjxYIW3kyq%Bh=gt4ibm#)qnSRZva67lf?aw8S9;|ThK&kb* zQ48jfU7+kzXIldyB~ya}PHM*2c#EA^kYZCuEf3sSSR*ThE@QIN)(|Q|X}LE<;D0-@ zxax=tUtPkN8}31JEx+6_;d|Fy{MmfVdEMmSQRm&5Td-@XZuv~>+o)Ti{%E7A<;eKL z(xNb$fPOAtAPLNirnmlW<8nG#UVzkczmCPn;*6er-|Y+96(l=1tvOjV7j#cv+jC=W z2S?Od!_w@!*LY{$=&CE~yw)R4qPn&k+w@{i6Co+yCS=(}_My2=WM^vAL=M{lNFRwZ zn#$T8POarVuH@ES4%uNID|!^2gxt__;5ksQK zd&kr2c-d)3+*El?tsN7Z%QNI1H`d4(2fKRv3>i8)5&cIfFTpCDG#J-qRHxBl13ynN zF;p7n&{<={&*-JGVI8weYTIIRF)@5+mdEcy;pZ+jFf|OW(vY8u!cUkPO)xcVZvlZ) Qb{xB`nA$Jstf?XWA6ol9h5!Hn diff --git a/package.json b/package.json index f420bcf..845a701 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "devDependencies": { "@turbo/gen": "1.13.3", "dprint": "0.45.0", - "turbo": "1.13.3" + "turbo": "1.13.3", + "one-version": "workspace:*" }, "scripts": { "dev": "turbo run dev", @@ -19,6 +20,7 @@ "format": "dprint fmt", "format:check": "dprint check", "test": "turbo run test", + "one-version:check": "one-version check", "generator": "bun ./scripts/generator.ts" } } diff --git a/packages/one-version/__tests__/jsonc-parser.test.mjs b/packages/one-version/__tests__/jsonc-parser.test.mjs new file mode 100644 index 0000000..e589cb7 --- /dev/null +++ b/packages/one-version/__tests__/jsonc-parser.test.mjs @@ -0,0 +1,15 @@ +import assert from "node:assert"; +import { after, before, test } from "node:test"; +import { parse } from "../utils/jsonc-parser.mjs"; + +test("parses plain old JSON fine", () => { + let sample = { + foo: { + bar: ["baz", 1, 2, false, true, null], + }, + }; + + let result = parse(JSON.stringify(sample)); + + assert.deepEqual(result, sample); +}); diff --git a/packages/one-version/__tests__/one-version.test.mjs b/packages/one-version/__tests__/one-version.test.mjs index 28afce7..0c15c4a 100644 --- a/packages/one-version/__tests__/one-version.test.mjs +++ b/packages/one-version/__tests__/one-version.test.mjs @@ -1,6 +1,15 @@ import assert from "node:assert"; import { after, before, test } from "node:test"; +import { start } from "../one-version.mjs"; -test("stub", () => { - assert.ok(true); +test("supports help command", async () => { + let logs = []; + const logger = { + log: (...args) => { + logs.push(args.join(" ")); + }, + }; + await start({ rootDirectory: process.cwd(), logger, args: ["help"] }); + + assert.match(logs[0], /one-version/); }); diff --git a/packages/one-version/bin/index.mjs b/packages/one-version/bin/index.mjs old mode 100644 new mode 100755 index 37f2c97..5d2ca53 --- a/packages/one-version/bin/index.mjs +++ b/packages/one-version/bin/index.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node import { start } from "../one-version.mjs"; -start({ rootDirectory: process.cwd(), logger: console }).catch((e) => { +start({ rootDirectory: process.cwd(), logger: console, args: process.argv.slice(2) }).catch((e) => { console.error("Error running one-version:"); console.error(e); process.exit(1); diff --git a/packages/one-version/biome.jsonc b/packages/one-version/biome.jsonc index fffa367..dc20e31 100644 --- a/packages/one-version/biome.jsonc +++ b/packages/one-version/biome.jsonc @@ -6,7 +6,11 @@ "linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "style": { + "useConst": "off", + "noUnusedTemplateLiteral": "off" + } } } } diff --git a/packages/one-version/one-version.mjs b/packages/one-version/one-version.mjs index 70db470..76bede0 100644 --- a/packages/one-version/one-version.mjs +++ b/packages/one-version/one-version.mjs @@ -1,4 +1,37 @@ -export async function start({ rootDirectory, logger }) { - logger.log(`Running one-version in ${rootDirectory}`); - return Promise.resolve(); +import { parse } from "./utils/jsonc-parser.mjs"; + +async function _loadConfig({ rootDirectory }) { +} + +export async function start({ rootDirectory, logger, args, loadConfig = _loadConfig }) { + let [firstArg] = args; + + let usageLogs = [ + "", + `Usage:`, + ` one-version check - Check the repo to ensure all dependencies are match the expected versions`, + ` one-version help - Display this help message!`, + "", + ]; + + switch (firstArg) { + case "check": { + // @TODO + return; + } + case "help": { + logger.log(`one-version - a strict dependency conformance tool for (mono)repos!`); + for (let log of usageLogs) { + logger.log(log); + } + return; + } + default: { + logger.log(`Unknown command: ${firstArg}`); + for (let log of usageLogs) { + logger.log(log); + } + return; + } + } } diff --git a/packages/one-version/utils/jsonc-parser.mjs b/packages/one-version/utils/jsonc-parser.mjs new file mode 100644 index 0000000..2fc645a --- /dev/null +++ b/packages/one-version/utils/jsonc-parser.mjs @@ -0,0 +1,736 @@ +// Mostly all of this is lifted from `jsonc-parser` package +// See: https://github.com/microsoft/node-jsonc-parser/tree/b6b34ba39da3f5bee17d41004c03a86686dade4c + +/** + * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result. + * Therefore always check the errors list to find out if the input was valid. + */ +export function parse(text, errors = [], options = { + allowTrailingComma: false, +}) { + let currentProperty = null; + let currentParent = []; + const previousParents = []; + + function onValue(value) { + if (Array.isArray(currentParent)) { + currentParent.push(value); + } else if (currentProperty !== null) { + currentParent[currentProperty] = value; + } + } + + const visitor = { + onObjectBegin: () => { + const object = {}; + onValue(object); + previousParents.push(currentParent); + currentParent = object; + currentProperty = null; + }, + onObjectProperty: (name) => { + currentProperty = name; + }, + onObjectEnd: () => { + currentParent = previousParents.pop(); + }, + onArrayBegin: () => { + const array = []; + onValue(array); + previousParents.push(currentParent); + currentParent = array; + currentProperty = null; + }, + onArrayEnd: () => { + currentParent = previousParents.pop(); + }, + onLiteralValue: onValue, + onError: (error, offset, length) => { + errors.push({ error, offset, length }); + }, + }; + visit(text, visitor, options); + return currentParent[0]; +} + +/** + * Parses the given text and invokes the visitor functions for each object, array and literal reached. + */ +export function visit(text, visitor, options = { allowTrailingComma: false }) { + const _scanner = createScanner(text, false); + // Important: Only pass copies of this to visitor functions to prevent accidental modification, and + // to not affect visitor functions which stored a reference to a previous JSONPath + const _jsonPath = []; + + function toNoArgVisit(visitFunction) { + return visitFunction + ? () => + visitFunction( + _scanner.getTokenOffset(), + _scanner.getTokenLength(), + _scanner.getTokenStartLine(), + _scanner.getTokenStartCharacter(), + ) + : () => true; + } + function toNoArgVisitWithPath(visitFunction) { + return visitFunction + ? () => + visitFunction( + _scanner.getTokenOffset(), + _scanner.getTokenLength(), + _scanner.getTokenStartLine(), + _scanner.getTokenStartCharacter(), + () => _jsonPath.slice(), + ) + : () => true; + } + function toOneArgVisit(visitFunction) { + return visitFunction + ? (arg) => + visitFunction( + arg, + _scanner.getTokenOffset(), + _scanner.getTokenLength(), + _scanner.getTokenStartLine(), + _scanner.getTokenStartCharacter(), + ) + : () => true; + } + function toOneArgVisitWithPath(visitFunction) { + return visitFunction + ? (arg) => + visitFunction( + arg, + _scanner.getTokenOffset(), + _scanner.getTokenLength(), + _scanner.getTokenStartLine(), + _scanner.getTokenStartCharacter(), + () => _jsonPath.slice(), + ) + : () => true; + } + + const onObjectBegin = toNoArgVisitWithPath(visitor.onObjectBegin); + const onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty); + const onObjectEnd = toNoArgVisit(visitor.onObjectEnd); + const onArrayBegin = toNoArgVisitWithPath(visitor.onArrayBegin); + const onArrayEnd = toNoArgVisit(visitor.onArrayEnd); + const onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue); + const onSeparator = toOneArgVisit(visitor.onSeparator); + const onComment = toNoArgVisit(visitor.onComment); + const onError = toOneArgVisit(visitor.onError); + + const disallowComments = options?.disallowComments; + const allowTrailingComma = options?.allowTrailingComma; + function scanNext() { + while (true) { + const token = _scanner.scan(); + switch (_scanner.getTokenError()) { + case ScanError.InvalidUnicode: + handleError(ParseErrorCode.InvalidUnicode); + break; + case ScanError.InvalidEscapeCharacter: + handleError(ParseErrorCode.InvalidEscapeCharacter); + break; + case ScanError.UnexpectedEndOfNumber: + handleError(ParseErrorCode.UnexpectedEndOfNumber); + break; + case ScanError.UnexpectedEndOfComment: + if (!disallowComments) { + handleError(ParseErrorCode.UnexpectedEndOfComment); + } + break; + case ScanError.UnexpectedEndOfString: + handleError(ParseErrorCode.UnexpectedEndOfString); + break; + case ScanError.InvalidCharacter: + handleError(ParseErrorCode.InvalidCharacter); + break; + } + switch (token) { + case SyntaxKind.LineCommentTrivia: + case SyntaxKind.BlockCommentTrivia: + if (disallowComments) { + handleError(ParseErrorCode.InvalidCommentToken); + } else { + onComment(); + } + break; + case SyntaxKind.Unknown: + handleError(ParseErrorCode.InvalidSymbol); + break; + case SyntaxKind.Trivia: + case SyntaxKind.LineBreakTrivia: + break; + default: + return token; + } + } + } + + function handleError(error, skipUntilAfter = [], skipUntil = []) { + onError(error); + if (skipUntilAfter.length + skipUntil.length > 0) { + let token = _scanner.getToken(); + while (token !== SyntaxKind.EOF) { + if (skipUntilAfter.indexOf(token) !== -1) { + scanNext(); + break; + // biome-ignore lint/style/noUselessElse: don't feel confident that the recommended change is safe + } else if (skipUntil.indexOf(token) !== -1) { + break; + } + token = scanNext(); + } + } + } + + function parseString(isValue) { + const value = _scanner.getTokenValue(); + if (isValue) { + onLiteralValue(value); + } else { + onObjectProperty(value); + // add property name afterwards + _jsonPath.push(value); + } + scanNext(); + return true; + } + + function parseLiteral() { + switch (_scanner.getToken()) { + case SyntaxKind.NumericLiteral: { + const tokenValue = _scanner.getTokenValue(); + let value = Number(tokenValue); + + if (Number.isNaN(value)) { + handleError(ParseErrorCode.InvalidNumberFormat); + value = 0; + } + + onLiteralValue(value); + break; + } + case SyntaxKind.NullKeyword: + onLiteralValue(null); + break; + case SyntaxKind.TrueKeyword: + onLiteralValue(true); + break; + case SyntaxKind.FalseKeyword: + onLiteralValue(false); + break; + default: + return false; + } + scanNext(); + return true; + } + + function parseProperty() { + if (_scanner.getToken() !== SyntaxKind.StringLiteral) { + handleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]); + return false; + } + parseString(false); + if (_scanner.getToken() === SyntaxKind.ColonToken) { + onSeparator(":"); + scanNext(); // consume colon + + if (!parseValue()) { + handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]); + } + } else { + handleError(ParseErrorCode.ColonExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]); + } + _jsonPath.pop(); // remove processed property name + return true; + } + + function parseObject() { + onObjectBegin(); + scanNext(); // consume open brace + + let needsComma = false; + while (_scanner.getToken() !== SyntaxKind.CloseBraceToken && _scanner.getToken() !== SyntaxKind.EOF) { + if (_scanner.getToken() === SyntaxKind.CommaToken) { + if (!needsComma) { + handleError(ParseErrorCode.ValueExpected, [], []); + } + onSeparator(","); + scanNext(); // consume comma + if (_scanner.getToken() === SyntaxKind.CloseBraceToken && allowTrailingComma) { + break; + } + } else if (needsComma) { + handleError(ParseErrorCode.CommaExpected, [], []); + } + if (!parseProperty()) { + handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]); + } + needsComma = true; + } + onObjectEnd(); + if (_scanner.getToken() !== SyntaxKind.CloseBraceToken) { + handleError(ParseErrorCode.CloseBraceExpected, [SyntaxKind.CloseBraceToken], []); + } else { + scanNext(); // consume close brace + } + return true; + } + + function parseArray() { + onArrayBegin(); + scanNext(); // consume open bracket + let isFirstElement = true; + + let needsComma = false; + while (_scanner.getToken() !== SyntaxKind.CloseBracketToken && _scanner.getToken() !== SyntaxKind.EOF) { + if (_scanner.getToken() === SyntaxKind.CommaToken) { + if (!needsComma) { + handleError(ParseErrorCode.ValueExpected, [], []); + } + onSeparator(","); + scanNext(); // consume comma + if (_scanner.getToken() === SyntaxKind.CloseBracketToken && allowTrailingComma) { + break; + } + } else if (needsComma) { + handleError(ParseErrorCode.CommaExpected, [], []); + } + if (isFirstElement) { + _jsonPath.push(0); + isFirstElement = false; + } else { + _jsonPath[_jsonPath.length - 1]++; + } + if (!parseValue()) { + handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken]); + } + needsComma = true; + } + onArrayEnd(); + if (!isFirstElement) { + _jsonPath.pop(); // remove array index + } + if (_scanner.getToken() !== SyntaxKind.CloseBracketToken) { + handleError(ParseErrorCode.CloseBracketExpected, [SyntaxKind.CloseBracketToken], []); + } else { + scanNext(); // consume close bracket + } + return true; + } + + function parseValue() { + switch (_scanner.getToken()) { + case SyntaxKind.OpenBracketToken: + return parseArray(); + case SyntaxKind.OpenBraceToken: + return parseObject(); + case SyntaxKind.StringLiteral: + return parseString(true); + default: + return parseLiteral(); + } + } + + scanNext(); + if (_scanner.getToken() === SyntaxKind.EOF) { + if (options.allowEmptyContent) { + return true; + } + handleError(ParseErrorCode.ValueExpected, [], []); + return false; + } + if (!parseValue()) { + handleError(ParseErrorCode.ValueExpected, [], []); + return false; + } + if (_scanner.getToken() !== SyntaxKind.EOF) { + handleError(ParseErrorCode.EndOfFileExpected, [], []); + } + return true; +} + +/** + * Creates a JSON scanner on the given text. + * If ignoreTrivia is set, whitespaces or comments are ignored. + */ +export function createScanner(text, ignoreTrivia = false) { + const len = text.length; + let pos = 0; + let value = ""; + let tokenOffset = 0; + let token = SyntaxKind.Unknown; + let lineNumber = 0; + let lineStartOffset = 0; + let tokenLineStartOffset = 0; + let prevTokenLineStartOffset = 0; + let scanError = ScanError.None; + + function scanHexDigits(count, exact) { + let digits = 0; + let value = 0; + while (digits < count || !exact) { + let ch = text.charCodeAt(pos); + if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) { + value = value * 16 + ch - CharacterCodes._0; + } else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) { + value = value * 16 + ch - CharacterCodes.A + 10; + } else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) { + value = value * 16 + ch - CharacterCodes.a + 10; + } else { + break; + } + pos++; + digits++; + } + if (digits < count) { + value = -1; + } + return value; + } + + function setPosition(newPosition) { + pos = newPosition; + value = ""; + tokenOffset = 0; + token = SyntaxKind.Unknown; + scanError = ScanError.None; + } + + function scanNumber() { + let start = pos; + if (text.charCodeAt(pos) === CharacterCodes._0) { + pos++; + } else { + pos++; + while (pos < text.length && isDigit(text.charCodeAt(pos))) { + pos++; + } + } + if (pos < text.length && text.charCodeAt(pos) === CharacterCodes.dot) { + pos++; + if (pos < text.length && isDigit(text.charCodeAt(pos))) { + pos++; + while (pos < text.length && isDigit(text.charCodeAt(pos))) { + pos++; + } + } else { + scanError = ScanError.UnexpectedEndOfNumber; + return text.substring(start, pos); + } + } + let end = pos; + if (pos < text.length && (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e)) { + pos++; + if ( + pos < text.length && text.charCodeAt(pos) === CharacterCodes.plus + || text.charCodeAt(pos) === CharacterCodes.minus + ) { + pos++; + } + if (pos < text.length && isDigit(text.charCodeAt(pos))) { + pos++; + while (pos < text.length && isDigit(text.charCodeAt(pos))) { + pos++; + } + end = pos; + } else { + scanError = ScanError.UnexpectedEndOfNumber; + } + } + return text.substring(start, end); + } + + function scanString() { + let result = ""; + let start = pos; + + while (true) { + if (pos >= len) { + result += text.substring(start, pos); + scanError = ScanError.UnexpectedEndOfString; + break; + } + const ch = text.charCodeAt(pos); + if (ch === CharacterCodes.doubleQuote) { + result += text.substring(start, pos); + pos++; + break; + } + if (ch === CharacterCodes.backslash) { + result += text.substring(start, pos); + pos++; + if (pos >= len) { + scanError = ScanError.UnexpectedEndOfString; + break; + } + const ch2 = text.charCodeAt(pos++); + switch (ch2) { + case CharacterCodes.doubleQuote: + result += "\""; + break; + case CharacterCodes.backslash: + result += "\\"; + break; + case CharacterCodes.slash: + result += "/"; + break; + case CharacterCodes.b: + result += "\b"; + break; + case CharacterCodes.f: + result += "\f"; + break; + case CharacterCodes.n: + result += "\n"; + break; + case CharacterCodes.r: + result += "\r"; + break; + case CharacterCodes.t: + result += "\t"; + break; + case CharacterCodes.u: + const ch3 = scanHexDigits(4, true); + if (ch3 >= 0) { + result += String.fromCharCode(ch3); + } else { + scanError = ScanError.InvalidUnicode; + } + break; + default: + scanError = ScanError.InvalidEscapeCharacter; + } + start = pos; + continue; + } + if (ch >= 0 && ch <= 0x1f) { + if (isLineBreak(ch)) { + result += text.substring(start, pos); + scanError = ScanError.UnexpectedEndOfString; + break; + } else { + scanError = ScanError.InvalidCharacter; + // mark as error but continue with string + } + } + pos++; + } + return result; + } + + function scanNext() { + value = ""; + scanError = ScanError.None; + + tokenOffset = pos; + lineStartOffset = lineNumber; + prevTokenLineStartOffset = tokenLineStartOffset; + + if (pos >= len) { + // at the end + tokenOffset = len; + return token = SyntaxKind.EOF; + } + + let code = text.charCodeAt(pos); + // trivia: whitespace + if (isWhiteSpace(code)) { + do { + pos++; + value += String.fromCharCode(code); + code = text.charCodeAt(pos); + } while (isWhiteSpace(code)); + + return token = SyntaxKind.Trivia; + } + + // trivia: newlines + if (isLineBreak(code)) { + pos++; + value += String.fromCharCode(code); + if (code === CharacterCodes.carriageReturn && text.charCodeAt(pos) === CharacterCodes.lineFeed) { + pos++; + value += "\n"; + } + lineNumber++; + tokenLineStartOffset = pos; + return token = SyntaxKind.LineBreakTrivia; + } + + switch (code) { + // tokens: []{}:, + case CharacterCodes.openBrace: + pos++; + return token = SyntaxKind.OpenBraceToken; + case CharacterCodes.closeBrace: + pos++; + return token = SyntaxKind.CloseBraceToken; + case CharacterCodes.openBracket: + pos++; + return token = SyntaxKind.OpenBracketToken; + case CharacterCodes.closeBracket: + pos++; + return token = SyntaxKind.CloseBracketToken; + case CharacterCodes.colon: + pos++; + return token = SyntaxKind.ColonToken; + case CharacterCodes.comma: + pos++; + return token = SyntaxKind.CommaToken; + + // strings + case CharacterCodes.doubleQuote: + pos++; + value = scanString(); + return token = SyntaxKind.StringLiteral; + + // comments + case CharacterCodes.slash: + const start = pos - 1; + // Single-line comment + if (text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + + while (pos < len) { + if (isLineBreak(text.charCodeAt(pos))) { + break; + } + pos++; + } + value = text.substring(start, pos); + return token = SyntaxKind.LineCommentTrivia; + } + + // Multi-line comment + if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { + pos += 2; + + const safeLength = len - 1; // For lookahead. + let commentClosed = false; + while (pos < safeLength) { + const ch = text.charCodeAt(pos); + + if (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + pos += 2; + commentClosed = true; + break; + } + + pos++; + + if (isLineBreak(ch)) { + if (ch === CharacterCodes.carriageReturn && text.charCodeAt(pos) === CharacterCodes.lineFeed) { + pos++; + } + + lineNumber++; + tokenLineStartOffset = pos; + } + } + + if (!commentClosed) { + pos++; + scanError = ScanError.UnexpectedEndOfComment; + } + + value = text.substring(start, pos); + return token = SyntaxKind.BlockCommentTrivia; + } + // just a single slash + value += String.fromCharCode(code); + pos++; + return token = SyntaxKind.Unknown; + + // numbers + case CharacterCodes.minus: + value += String.fromCharCode(code); + pos++; + if (pos === len || !isDigit(text.charCodeAt(pos))) { + return token = SyntaxKind.Unknown; + } + // found a minus, followed by a number so + // we fall through to proceed with scanning + // numbers + case CharacterCodes._0: + case CharacterCodes._1: + case CharacterCodes._2: + case CharacterCodes._3: + case CharacterCodes._4: + case CharacterCodes._5: + case CharacterCodes._6: + case CharacterCodes._7: + case CharacterCodes._8: + case CharacterCodes._9: + value += scanNumber(); + return token = SyntaxKind.NumericLiteral; + // literals and unknown symbols + default: + // is a literal? Read the full word. + while (pos < len && isUnknownContentCharacter(code)) { + pos++; + code = text.charCodeAt(pos); + } + if (tokenOffset !== pos) { + value = text.substring(tokenOffset, pos); + // keywords: true, false, null + switch (value) { + case "true": + return token = SyntaxKind.TrueKeyword; + case "false": + return token = SyntaxKind.FalseKeyword; + case "null": + return token = SyntaxKind.NullKeyword; + } + return token = SyntaxKind.Unknown; + } + // some + value += String.fromCharCode(code); + pos++; + return token = SyntaxKind.Unknown; + } + } + + function isUnknownContentCharacter(code) { + if (isWhiteSpace(code) || isLineBreak(code)) { + return false; + } + switch (code) { + case CharacterCodes.closeBrace: + case CharacterCodes.closeBracket: + case CharacterCodes.openBrace: + case CharacterCodes.openBracket: + case CharacterCodes.doubleQuote: + case CharacterCodes.colon: + case CharacterCodes.comma: + case CharacterCodes.slash: + return false; + } + return true; + } + + function scanNextNonTrivia() { + let result; + do { + result = scanNext(); + } while (result >= SyntaxKind.LineCommentTrivia && result <= SyntaxKind.Trivia); + return result; + } + + return { + setPosition: setPosition, + getPosition: () => pos, + scan: ignoreTrivia ? scanNextNonTrivia : scanNext, + getToken: () => token, + getTokenValue: () => value, + getTokenOffset: () => tokenOffset, + getTokenLength: () => pos - tokenOffset, + getTokenStartLine: () => lineStartOffset, + getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset, + getTokenError: () => scanError, + }; +} diff --git a/packages/template-library/biome.jsonc b/packages/template-library/biome.jsonc index fffa367..dc20e31 100644 --- a/packages/template-library/biome.jsonc +++ b/packages/template-library/biome.jsonc @@ -6,7 +6,11 @@ "linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "style": { + "useConst": "off", + "noUnusedTemplateLiteral": "off" + } } } }