From 97c86d66f1b870898414e32e8fc777e7253d9104 Mon Sep 17 00:00:00 2001 From: Ajai <1452845+ajainarayanan@users.noreply.github.com> Date: Wed, 7 Nov 2018 12:26:19 -0800 Subject: [PATCH] [Feature][#67] Adds tslint autofix as a flag to ForkTsCheckerWebpackPlugin plugin (#174) * Adds tslintAutoFix flag to ForkTsCheckerWebpackPlugin * Updates Vue integration test based on IncrementalChecker class update * Adds integration testing for tslintAutoFix flag * Updates README file to add description about tslintAutoFix flag * Removes unnecessary tslint checks * Adds a check to verify formatted file contents * Adds seperate tslint autofix json to avoid formatting files other than autofix files in integration test * Bumps package.json and updates CHANGELOG file for tslintAutoFix option * Updates README for tslintAutoFix with default value as false --- .prettierignore | 1 + CHANGELOG.md | 4 + README.md | 3 + fork-ts-checker-webpack-plugin-v0.4.11.tgz | Bin 0 -> 24199 bytes package.json | 2 +- src/IncrementalChecker.ts | 9 +- src/index.ts | 4 + src/service.ts | 1 + test/integration/index.spec.js | 113 ++++++++++++++++++- test/integration/project/tslint.autofix.json | 14 +++ test/integration/vue.spec.js | 1 + 11 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 .prettierignore create mode 100644 fork-ts-checker-webpack-plugin-v0.4.11.tgz create mode 100644 test/integration/project/tslint.autofix.json diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..5c619fa1 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +./test/integration/project/lintingError.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 587aa9a5..6565fb34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.4.15 + +* [Add `tslintAutoFix` option to be passed on to tslint to auto format typescript files](/~https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/174) (#174) + ## v0.4.14 * [Add support for `reportFiles` option](/~https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/179) (#179) diff --git a/README.md b/README.md index 445b71bf..368edabd 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,9 @@ Allows overriding TypeScript options. Should be specified in the same format as * **tslint** `string | true`: Path to *tslint.json* file or `true`. If `true`, uses `path.resolve(compiler.options.context, './tslint.json')`. Default: `undefined`. +* **tslintAutoFix** `boolean `: +Passes on `--fix` flag while running `tslint` to auto fix linting errors. Default: false. + * **watch** `string | string[]`: Directories or files to watch by service. Not necessary but improves performance (reduces number of `fs.stat` calls). diff --git a/fork-ts-checker-webpack-plugin-v0.4.11.tgz b/fork-ts-checker-webpack-plugin-v0.4.11.tgz new file mode 100644 index 0000000000000000000000000000000000000000..fd990d7b72563fa0ead0fe33950197f041f65bd6 GIT binary patch literal 24199 zcmV(@K-Rw>iwFP!000006YahGcH2ghIJ|%JDLTrYkW@%ecW3B0jx5WGW^BnvlH<+M zcqE7fB}5>=1wdWa(Z0yRx%r5XJZlQOLcX1b=|spK2^lW{d;lJ>h|MDNptE(HU&z6_h)}OJZ<)!uY74{$NUlc0wjI-QN0hIf;V-D`$ zVgI4~0DNq$tyRwdvt=L-n*WXUjiu!^nE#cvwP*1Cp#gC{ zfARVM`fGN% zMWqga0P}^1fO2hvpoD))D8G~Q+Q@H4fTUg$MPUYjHoI&*>ic=XL|YF5!TK_XK%L%a zwHliSLhsya%h(F2@1(d6|TLHt?eix=XS!4=({117JSw9t=O|jqy$UH1gw% zb`-_{+~L97FwR*zhA9FT@XI(L7Vscoe#gO75w%t`K<4W@U|HH@ex9e{=@^JOi3w#{ zFAYaIJB^aw1-_HeWe)=05`nk8++tsUw@#?UIXi?oJK+8PYt>uwmT>+?L6E)@PJCd>y%XGAXvURYK*A)(&DPj? zl3Zl$bbMBpTEbEX;}P-qqNM!3%D*E)cQMULK@-gZD(5z%`II$AHrT6zMM%%{|*-3pfqih@&oZ zx4dN5E&%%*HbiVdAbCLO%W?DQMM=i_(h1Npg-uJCWtZa83Z`9?YB<#Fr;*$R~EYOGjwQOQT0?-frvpC6U zAt4$H`~`r@Ho?b#ozN~*{uWI3#KPBlF*ZT6yZ|&d#H~Gyc@y{wSkTG-_U7w%+aNuk zlufJ^*xV+D)#YM9^&(%8C>V`TVT(Ku`W`NoY^)4Z_ygNN4G>q*a!R9)dkR3s!o`9ooC>=vPjUST zoEbx)HJE3>-3Q^B_ge-fa8h_x{(I!-=gbE@6E;$K4;10YH;8)=tDg`>C_PX~U|fCV zx%JaAP-z{es;@4Qo)3)e3YaexF1Fj`^tYgwv&KmrTp@Z&G3_H^^*v2Zqj^Hy_LZN7 zJ%;d{rF{1DAOmu1_)!8&71nl`XH;@=@fEE83tGVEehe&daj{!tjK)q&RRA5t{wWgt z=?w$E;E$smi0mdAvvVKz7-Y5}W15InP+j*rh^|habQBcUPp~R)n}xZ@dp@CUX&a;- z6?JJaOfCU}HWWk&4A>3x$9aPE-Sea92EI_mjQP=(f0LOwZm~GH1Oma=G%@_OC+B>b zFQ?aGM&QWt53m$%;v5rU42*&nKhgutktj&i0A-L51$}I3X9ye!uv09%vZu9@tsqe) zoPG9b65=2tB9KMoz_|h;zf9z4#LC*lq;-b2tZb`p?mx`KVW95-h_Stc|5_*;p;h`3 zI!DfhNMu*=1EuCP1v-VfXbi&ZfaJ8KS=L)tcg7)%E4>loEiCFG5LMU~Oxs))euQw| zxbTGFAsUg0!%>M`3UX!gXEk9$0 zdQz*s57HrQ57GcOEZ78bYi_YY8j#io+#@}M{Q&qbY}Y6;;C7yz=6)C>7x96S zjc#gCGCzlAvSg57;XaQHAGmwc3sEcqF|Ris1|Xsm|KRMof#T=FfvB<2q)z$(U@hdD zm;6Lqd@@Gj-vyca~4EV4O#%Ti_ut1=vrLZLH#U6_RLX4^7YkuGSo*BX0^dM zjY$@y;es@fP>&?E2$_74pzVw#jRcrA$u-?t?GQfsr?^e_ikSt@jG{JyfDHapmRbNF#{f1B+bu=o3WzwEr; ze$5s(58(Ggi+$WV{CV%gA%hb8o4bd#VLZfAGv?T6PpyFam4P;Yk+$ae>b7#cm?W7wf+YG?ZZ8+*6CkEZRz%~v~bcMgAT z)!ytJ?qZv7_V(E(d%wAVxU==)?dCpv|6%|A-oZ9>{~DUz-PwJ!54~)^+ul9&pjUXu zwts;i?BM6kw{Nkl+U5swzR-2V$X`U~_idH-M8ShM{<@PAMH|6@E~lg7&q517z-*+*eY;A(H}=&PgM z(U5_1muW7baCqir=V1`_GcQa!@o3n&oMOWCvdgoVWVL!Ri2S^r{r4F5iDud6)zy^; z4gHppWmJ;pEGq&2R_Q1ja1YBEVKu*u^t&YMkx z{~m`R^spfaTf^~?EiOvS(2BRZxY&XhN{1`n^5Pu9gr%8O)DGD~5*ywLr z?b1(Owweo0wd{pNMWa3$#(ML4jT#fLw>W?=*ykEUX!GDY@3Q0LewfDo5M;MbheTV= zI0Bk{U$Mi&*6h=4fgOL{_>#`&I!Nf~^(6H2Hoqs~L z>zDu8X%!zhE}-oKFZJ@HFl%*{h8RNKm$ny`%Gxk)5Qkw_(d5r<1&A;~P)Z9x`EiB@ z!M!-T;Z`VCe7>!z|9*o1-XcJ}kz#BW_O%OXV5?!(+vh|!NapWA9=()A9*{6x*eWs* z-6NQ`EQ!X#EPLc%1z9o-+9icgBCo7H^5a2}CYPPcicOFGnvBsYQuEO!B;e)%b4zkR zh=Mcj!sI9wBDuA68A{{u1Lk1JZICCG{hqKZKO-iAY70xoDOqD$HJBm%;sXifECZPz zJ3RN}JFO++F=)N+r2*+$AoUX?ZT#=bQpPSb_P?uH)2kf>s8vLu1Oc%iog8rvQT8-P@xhf4cW!}h|`7WNV!{WMF;KH5 z4+K0XSmiS82M)7!t7Mfhl8kMFB7+_tM*fg%b_i;0hV`z3AZChRKckU=ZiMW$1~UwJ z$f+IboXy?(ql>+6oIjDJ`BJvJDno`@<11uv$2v%48KM z%K$JK!Dewep-U4v?I&_)7>%}6TH&0J$PU&5F!B?n{t5XrvS5gm-4k9p97G-IgZoI) zjG+)0U*l&9EF@{)5FLe?n59J@9iLfFewqaIZeRz1nvZf3@F^-#s9+FRQJ;bqB-XC{ zQ1||z=|Z?|q{-y!JnWq#^F{#1aArW5z~vY07iDnThk(sKUjp3IU)vd! z^inzr=HNqR*M&y}{VhO4dh0cCVEGp z%f8v~9JgJj!cd@qL%`iySPT~0K>XR_9BeL-%4q_ClwlQq7YQagt28M2A4i`M($^s} zpd=M$FHZin^3WSi^g~V|kL?1Rj00ruKJez#agO{MJye;>AXp;}`eP`?;_>hlrFGq|lF4l|0Fv#2KL!V9K7j z41%sm;9Nh2zsP#9#M3Ylz2dqblIinGY?e-FGbXkbWKB5q z6PUa-@?rVP_(wm2)l5?+bqLUb$S(*Io0zr`)?*sHF4rYaA)jm{soGn?Nfj-uT*QFn zJ|{5VjMgUd!K|cIPM}3|TxFwxDAZHzMtVsE^QsdRE-^m-mQ)Wo`tvph0#FT{M-dk% zBYD&X#TP5@f)~RsxJw;}%WD$LrVSD}Ty~y}VS-^Z6rOhy2SVK2Q3{2PBgoH_J~Ymq ztS$8Qr?_>WV9cbs!LRu}@~2h@o_0-9inN!TRs` zE8;d=H1sYLsA{qoKM20igh9QLy%1R{JebxI@oJB~D%UAzU*gwE8JJQi7a$2|2@kTl zL0Lb!ipx@rHoXp<-2 z39ma+loC_Z=#4=-i_ss=MW+J8C$M%A$Rq#K2abW8tzgpAEIp_GX%Mxsp*FSjwWtSL zKS7%T|K)p%PQzlG5M)Y19g3}|q^2eCZUS{UK~L=N+m^GBoZsNBKGGx|7s8$%k1ALXoQuj(pm^FekzWzX# zO;i7dyd4L(#J7bn$5=f_h0!$ziWVti zUI}$;sCZ{`V?q)Fg`BO(K{Y`^<2DdPA&k0Ri&25cnMT0LC?G>_r0GB+q|L#_7#y+^ zp8G{~&KQ|Cr#U%h*f%sy9;%^ATF5k+EJUTNg)kZjP zZ+H6`kRj>eavW5$TU?`x{8+>b(tsq%{xS~!4wwZvB4Fz9y^ZCP7^$M+VKg%uq9Cy%yowtmh*=5&mUOGH+5413KSq-i z@i7n)=&4a?-3(|2au5M@V+yVckn*P1-hBHOYabZZ(HKvJ+t6r8SvSpD0Xu%PzrBsk z!!%>`eN5XrLC3cMZWl!JC2Z(7?Cu>Ne%zz66g@637OF(hC$7L@$gdJUI$G%sgru^Bg4etEs{$+?Wh(;b#)+pvp+7a?`N^>vmTA5Nv5mNX^5Ua@B!`0j| z*FZW{q4PEU)8q<+NsSm!F$gWPJmJ{OG1eQIAaGa#aylqW`MLqh;7%|5d^rH>KKl8)5MT$0bQiv~M#O29?@i7GHMmio&3!(2Ex8Gh6A#MsvDu(Pf!;jO`*s@*3Y|J1RAW?^&i}Gos;P&xBGKL>V2&WTQza{5!e3J$+`!^P&ujruZabd6+ zXCEYA*c<&k0H$?Lnw0b$ZNA@OzJTAHj}vn~hM}}P;NC0k^Z$sE#C9;aoqfbbgmkf+ z#BGePCc7fqlCxTE6Qf~+45uJ3JXsrtyAs^w;bcCoXQpzDk1 za%^)5QmpWvD5rL4Z4_D&8H9ezNQ^9Osy;8tt;MKK!0O6`Vn` zLg@$*a#+_#bMBj;;&Yqj6m_9d-OP>dismD zVwe*UFEeZhT0hLtVCAmwJRI~p+eCzD5fWk|N!ub@OAz@tWMiKgoe#Z&7%{15*`+v$ zThJA~=eUq|ZM0US?TMS%vobU^V2sH~DAbNB+<+JsgqHzSeJ>diy~x}qF23a}Fe;@G1yl&f`842h*wPo0~gg}Zs478TQaZ`7%(wIfQ1YQQGH!9ZUj2z zFX;DelLuj}kT)IeAD8HfS5BEqSWY}TXGuC7*V5yF%M-$`M5SbalYa&xNd%k47&YJW z2!}wsa_|js_;YQQ<6lhWBsjHILfDmT=5#9-ZLg zSOS{jgsS;ldH8#9Q!su2KMFbF7U#9Kumj;hCJPZ3zTv^{IkW`Q8vFZ!=uh~h+kC2! zzf%FH_;DHmWe3C4G`Q)wt2ON@rSLM2^994xywGI}#6lN1#usQ|^s|LBx@^JS&w>ct zx+Mgzdu&@-y=Gj7pp%T@R51~OA?OXmy=b z1%FJ30#sW}4Z=1DCnH2YE0hB|OanU#Ic#H)>VG-d0`y}fsf?#M3-Xcy1O5LJfH+=~ z`_Ko`C?7?jKX{j6HU|EekNaUl3m^o}oV~>V?t<+5BI)I6Fz_z11@1yP5}6)gP2R0Z zkjFuDJNJh}P}&6TlUY!N%0xlVw~{`rp$HFZ(s&23KX6H39*%mqbNGMp2!wRKftviq z`j|ie*YfJh(o_Dg$9UxYi+_pfJ#-&a&VO#Kt*#p9KUSAlp3Z+h%0v4b8Xgv=C#Rqd zSsVnx;yiB{f88&Q7Wip@($NN~Lh@4%R-7+yaOj8B5-=taJpUUP6&9#j`H6mr0(~h> zERal6N*hqHlqfhv<%YaKdL*{T;}OLG**D)X{z4dr**_O3#`K>Ha$_fn74tn{cqjv-skyNjipm!SVAe~u ze-$p$UTuilZEl>a8cq*mq=0Q;O#!ETgYIjRnhH5a03#IBJ?ka1`2t!T+MPd(UQy-`_`O+TM4Up$ae}Pes=Dm zPK#a>Dz}C?k=*6NOoq)-Nlc7ZS(1nMi54r%kzsan-*og&vQz5Q9Hu1Ge|-lZS2m2V z!q&n!SlD8X&vG&I?$^A(l}ptRMVIT|Qt>t`)*pU@{=V~`73P6V^3H#)1GbAw=i}_+ zMohx8w^A%j!OlfXYvuHiS_NOv0@_Ib^$aty$&bX=1!QX_GT`+^dyt8N=;bfk;`knY zT|qPz+$+V9{Xo*l@>)3odt~ zwWt8?8xqFl4drdS7x^$ui%Cc5folWR*r5q-H1hsdBdA-`wWZ~#Zr=aBxl~0-} z1Ixv%;AD*w4F3K*1MDnSj(G*M15v3}wUpXBPKQ#2{-VZJ=HddTilwY5gpV0TMK21~ zX)I<%U0+qaW!Wg;U@G5PMGS6Yw&7qS<+`x=M**V38i3wZa`Q(RXDdEv2$XACV2)gn zsxfNBgPMk1id7eKXmx_Q0hX9 zeP)+_B;AJWw)vdS(f87uQJyFV@E7=-1@V25so!A#7w;48eNw!q)PKqs{4KxbS{-Ho z5#KF>hT@&YMfM|Yv~01%8j_c@MpJOA;*C|ip@v6bWX~>T1PC)xGUzwe)BERP<|*Hx z@2|d6em~bsy4q$hiZb{(i@=`A5$vUY+)swDZa^1pY^*iCJUO6Us8K%;t})Mn)*oOX zS4T)5L7$n=~2z{a|kw%9lt)^;kth8c?VuI;L%OVqxdFTZ}%b zh!qe$uK)>j^*liWfKgjOIRN@R6|vpwX=!Pd6)3ybq!%S`XCA;=pv?<*`kt?Wi6f%Z zk-sHj+(Jv-RPf3{fBPCex$vT4jd6w{h`=^2>a7ZLz&FW;h}9WT z-ePr&pXw7>67~#`_V8@Qcr+8FuEm9x$hj!SoCc^ojzP4(n2+45h!@p>iU|{RX<_4e z?UtGrqK4<%xgC}MXzA(S|54?C3Rd0^&O$tu{XnumK2zlX)s3|kL;hb|Uw+E}_9)MT z%l{e?%_VPZH5+|D_uu%KeBs8Ds(BuU7wq$`!Gx7c@LBn#3bZ= zv{8bh%TiVCV}PsL{6O$j_wbJ7=T9OTS@}>J@ot$zT$e|2)Ljc5jiPk3LME*Oo2N*h z3VE?Ho%>l?z}#stTUH)8hgq>>RDp#7?9*UUr63;B2etOD;)1e^N;6>sBb{bJ!&lSs zPzpYD?7UH@dsr6g>{}-5z@PO6IEYB6;Q+ z26Th)@6R>MP^TO{HAGRP;hGHsY-XB!Cp4kEVqsXS z98)^WCUw^0d}j_66fD6UJ~hO?dhx<;vS`*_N7T?|P|(uo^ipxAg`Y?2D|xIi?_7ZA z4H5IxJL_{wu$bty$+T!&%!-C^Q`R+iOr!9Z-Ty85kIu0@sQ5S4{=2be#{aFYKIQ*? zoaf=~zrw+$S%9U}Z3dezca2d#Jf(!~H&ew;L9_Eqo1$W)Jk8bO#}T)SfM$!|m1Uv7 z^2c*Wsj?MWw0z?#kNF~Au%l1LH_W~l#QdWac@Qwg*15A%X z>-Gi>vM&bLImQaAn?7>!_OiXb*ii9MvMK=^C-a!jcyhk$*ha!k9;ybOY-Tb|Dn2_G=G zb+OXymXf$p=eu6L<=ngR6jWvcD6xAi(5q2RwPYtBQLiA+BMHJM^hz9kYI=ht-S%OK zB}BZ$TT!K|WqkCK)=-{1E8aTZ-`4aJZtQUbm=k+n9BrcS325UbWMX6uLI6r5pKQtRIzsR!o zx}Hl@va2`vsmdWgc8y4Ci32_Mo6T{aya}(BjTCh(Ko(Dy!T)|8Uebl|E#}I}*J0Up7OC z9JqsO&eu@g@Y7Ngcxw0sWuUMNbUN$4WH3i#cKe{{uO;V<4%EH)pUftmK9#OUo zon7d*IDJtRf~plFLe@g)eiUe5__3x+KMf75uSLzOpYT$HPpafyO5gNf$7YR@;qTQI zph;D|g2Y{dD6A(x&4RyYNnEalEzGGN=M5Ft`;?t3!rYGH!atcqUnDEhk4lNFKbU^s zw7d<0UjZ*$7rPIzr0^_m07$5;m(VC9z?`jKcEd~1kUajeWr%@Bw_T&h+oo)(#RI6s zH9sn{bP=`!?Qaz>G6UB6PDa7Z%1uT5jcSr8W`|N&Y^fOws9Ws~2INtUhSKLW*m)?Q zAQ}yDjg_`!f)}Byv``clwajsyCmD_k(8?R%5+@OUhWC1_GIzfb*#)(tpMv~=mXF}l z*eJR+%9mvw`&)(oLMER1g`e=mB$C7p9Z_F{FwJtor$FZr!=}q;q-sYl2TEa!cBZy0 zOgCSkk3y$IRKY|mhJrlVV34Ob70SLamXbgut`MN`ohceW_k&7Lk7-unZWfOOyS;%G z?L)+5z3Gv((y;tE3OriS9uT4a2m8Jmu}RTwTf=1vOgsT zkKp2L+{Fj)!M%BSBXMxve&aLX@Ve^~FmH>YPlcUZ!nUu)9laGS&yby5hBv91Db?z9 zmcEX}ZObf5bEZ{o$T^%MEr~ZC{j02F%a%5AcH-bV-^qh?a%|*e7s6MnvCUjnbOWH} zvXLUOwN75*g;RK$AH#pH>0eBr^T{gNHA;Tc7nll@Dv}oZsAe5%7;1*?tg;;AAPdBJ zh+XzU$wr+FP6g#2{)A&C+UAbCjLC&8$mX=ws~}C@P$u@wy){mUk!oR81VKz8;Zi#* zjFp-QIfJ0ta5t_GL9v*Y<-`wp!G~cwcY>r>@kCxO7rKG!FjG3uN>N%fMs#rqzvrCm zhJK%4RgTxCT?Xkn$np*yP-%8I$w8l@yTUGIeq1sZg_-2T{9<*oTwxBq()*Y3OC{(! zGm-=-EmzCc4P8Z#Y5FjApSWFNl%OVr_nqTCd087z*-{2(aie3Vr0pe;L|PNPGGY>P zHMMp|q#OQ6fmns>m}1LSZdM9 zaq&R$&EeWr2R&hR$d1+Bx}ic=Wrm-)yXdf2ZZEdg$vB_oC}8ZL_^6gUul!+a?+v>> zV||P1u4+-2wd~dmowuU9mSQz&X&kY|9H^fa;W|-#X{66$EtwhL)AVR3svjJQpoKWZ z)hZ{WSU>2sD(q3S_l3f~k^@*XaG0kuW|PS12$$BRVbjZk2;~;8krg(>1~>J|D}eY* zEzD1*hxG-Y&sew9)Vig&hY5{RG8BP+-Hec_tO{i*KkAKfgJRkE6oUzq0neI`w>2hO zA6MKPAVj*tW#Eaw8Y&Eu9u%9nW&Je(A<)mlOL5N(CC`=LMc0lXf~**s$zqWYPn<~k zScN8@6l+XWCk+xfOq3W%A{wiAr-j=koZE6Zub#v`KNs;A>XZw5QfOR3R?8lB(+(n; z+<^r7K0S2V0|2g1h{rtT8cnz$YfCt zZ<%LbZ>Kb-f=J@fY%P>0mrIPzqlW^@=^Dm|;DA~fy%1$)4r@cR7SF=oF4F2@_;Z{H z9lav5&B0i)yo*1+<@Swo-_ii%M__a!wZkZ?v@$X6U#XgzZBXJK5|?)J)l_?kqH-Q9 z8=ztdsifeCXY+{4`MEq9nC52k(uiiF{C=F#^X&lmmUGa0@)2_okzc zkAd^(3MS#=%a4G72_ribBO}ykd^QrB?mU|jziC?;bQs4$O51mfP1%^rqPj>oX{XY5 zlorPE&L|h@!@aXa#0lyyvJei`kb){TT{C#m8C&G4_D2W0Jw47xjsGmKk$%`drkwv; zT3%i^;y+hcmp7i`KOf_H(D=_kdN5DV+>g5cT^GtfL?4sa|MJ?#in;#RSJ$7`|D!w) z9{*j2Wb1*+cBr;RZgWK?TeU5Tlq5D%^>``}`r8bd#e2NPXZ+jvoQaE-WD)t>YK7t? z%ZBLZb6X^rB?itw^ZN>Kbso&$qQQnDsp$3J5oGFz@!Z*E~%?zfQv`XumY0J_f z7qYqW#sCc;%CuHAO5?YZPzn6#rHY^+U5lV&0+?N&$Ag%axScN8jQd*>mc7AyQC(;rM=*D-mAzrNo-e!a8#)9&8E z;m(%s!A2VHs_4KMdJ##(U2Um)B_(VDZJZ_P&5_!Sc=yT6lefuLkZ$=IsLy8Su{gM@ zHav*X(HxiUi-8;l*SR_s!}4{D)&CjSjn;8uyYycxSQ_5re_QSe>Xv_6nx{~ArfEmo z;xG*j1}#b>!vT_3L32$PO*U-b;=L*3?auC@izXyk`(tVQs3Hrsq`XE|WV?0#kchsPMGDlHtfVvg!y@-)u>4{mMG7S(H%?k5=oJ zu}^^8b}}EW;a7KRcoI{y?GAGAcsaU)-q8)7oDKf}~eu6zo(mAs8tuHvPc{LcC)O0M`#r7^aOOBXM8CJ$K{^INm8{F|5e zCjq>t&>AYedl(XvhhwZR#A~aUC6I2}_J5E4=r954b{gXduw*s|-%!In1pLk#=!;mI z(z$A%bU@&WBbJ}M43vdxUeL6?gra7PQLd2+&eNce9C(VkufkZ_oP_9zS8cQ9PfdsQ zc^c~`?xkS?sT@#>|Gcs!fiz4w*T9$-wd5xwZVz8p4ED$}t54YNk*t=0pzK)2slp>x zU52V!%}+(n7lP1ju9sP-i_sn}eF6+Czn4GFhTf9RYB-ki2w+eCIR)3Q8V`)~gY93o z_je9|J^r}4zq_;h(>$mz>Td7v@9qB?FmG@-9sTqUQAvMT0*d%f>(Nm}0d%QK6j7Tf zyv4Y*)erGFislw_1VB|Szna$aBq>J#S7z65dQsBzBRc1XELZfQ6qu3Eh)r9Y2EMPt zH1I!M{9Y6R5)fsk^me~g`CRuXOe-!;qcE&g>Yb`-rAmcV>?$smqA;nrG>O8XQmH}c zHkER=XU3h7S7(a7EbUG+G#qB7raVgz(|J4+yG#qoW$ZbCLGAY*V9@?_4*-PBHWQjl z``v5}zroLW9`tAK!JHc?_>$ER4=`=393U4lW%zsXVjjQ_N~_~^m~@lmOmj*hD06k9 zsW&vA)AqMH!1?H>G4RPR2awpT=Oa34(Vd0v6m##4q-P#do|LtCo`&CY+vQC0;Bz&+ zrIKRjgiG1nU!Pan8c(bm)?oq~I7qM3c0)(UAuY0hp5iX>Aog8u?$BR-f+wdX(qU@;}`tsgrg% zYjzi*b{>s?YbO3T3MMtjIWelEy^X8;pji5tQ!q?`f&(oFsRTJPCG&(gC4n7=j zGBJbaqgi)1i4QaV{Ja+ZSzJ_xRW-o?mNYN5$PNNO?VXcNxX(`rva2xa_WouB(T&4`!{CiBq9!?bk%*OUDoYDbCbglwOm`~`s~5MlUu9v~0% zF|7li?quLpNAqrWa0-j;LmIJ0INKPraR zmn-K}Crf+vqKn2Mnbb4pGrXI<#j7E4Kq-+3Cq;h0p=w$#Ubn~$;D@ou zkkev_%04m$nK8)V#uC*pWPt+tFReFS*_zG?`eBBI74#2ohNnryIl4!A8|c3sleJ4y zG|w)g0V+{x%;bRT9Wr`BN2E5Ca&b_(qjF#Y0w{O1WF(i6(3nHha(eT3P4+!osydTU zjI^p^)scg;BE`8YwQN8qWF0R43V?MPT^U`}e{`RFLVShUet^eZ=rWtHh{=W7<|z>7 zI1d!^GtyD@k`!0iN6}IFvFzHOHu=qU(6a2wqjjA&mRf9uYq14?`<5+q7Mv$Ab#Pc& zr*g|P4%{0pxXw(7+yKgYA_BF5d8vOtGJ(TUEH1dRq8Nve)y_3$_d>#Q*S=v@0QVV1 zelKX$7wdF&p97vcGEW_rp~|PU)Cq!>v@}p#%%0d4_w9^C$2b)wNt&}z-MP6tD~z(K z!Z7KIpt6*<4=W5i%zhcqoV(k7Hvm8MM0s(ldYL)>T(JTCiSy8bZ1^!?aR3{r&wD2s z1YPGO^WebQ!JDm&H8Pm6NF2XH>wgjlcz~qL6!MhQ?kT68``1%Wy9do_M-(S}oHetZ zG7n0?i?9P{TsOhRjxAUS7rlM+jm2&!uNuyhgl6)>AzX8D{8g0nE<`6@4oumBl48IG zb95qE_Ez}eY_#($N{WIU6aN4)ah61a6A}j6yp(jYY!vh`2NU1Fc)wguK$TCTJTv&H z0I$?LvI@l`Gc^yFY$OLO6?t9y#|L3)(82!@zAmYoaz;V%%J1h`=zG0{xCjD2efw<{ zDQE(MR{iKWbSMIV(L><7dBV8G57bwbl1dcXX{zkea+0y|IZ=13Nag6}0IEG~`k8k1 zp_AdFoL8hYB=Lh%8BVH;j|?*+iYdV;+svX6L`ay;_NpD*<$9`Ga&18Ju{R?5ICP(i zAyoD|Z@0I0SPSn)8Y1VLA*4XENeo93KOHK~8Mtl6K@Z&@>5a$!KF)GlM0kvzUxvg^ z1I#3zq&AhxXBq(@$Nj2$PUgU^L_h^?Ji_c+5X?Wfj(yV87rWb-pqHsan_aSK{LSP! zsvL(kcT?J*IHgnSlJqeddUeX($af>&*gm+~!a(XQ0_p^cfra)4V{((YP5Jc;J9?$e z?F%c2$dfSDa5tN=Zkm#%K1eW@JftYIvrnc#>9ob9PiI#{ft&9Yn3o9cQcl-;^~#%z zFs878I}8%&V267sN)3gyla^#ApqldQ9Asd(Obl`rFh9%2uoB=GPb~zqc^UReAX}jH zzze)tWYl5atY*wA^d-K{)vV&*on1?PUb1>M-sSTLPwFHsPT=2|RHrEXr^ubHEKRgZ z6k`6Xo43Ak%^B(lX0&KTh0q*CT>i5Q7cjuGUGMNDES}N*$x3aA6X~A$t7r9+-9x z3<5of?Vhlo0l@zgMmI$cp^!{mJgbm&i1p#E+BC2a?x#ZUEbRM1+|wFBH&ra`xuD)D zg^~d>mf4SrUO8h8fQWOo}9O zwKg4qiXwm(Q0M)o_`h+w0(o#H3V7;ZtdlWOsRB2rH&}F-1%Q2Jzb#zNiqpxqg5l*j zlqbI14>SKX3fh?Wyp5q+S~=d5ntR>}jN20;4O^*YBD8YNeME}ANyelxoUNv8Av0r;4?1Z?2_zqiZcndwVHjnd_ZJV`AB2=bteTt0{cEpKqW4 zGuHQ=+sSyto^@%>!J8YrtVe8F!_A>I7iMXX`8h}cr?6FO2oiPiW9C6IhgDgy3i6$o zd;pd&Uud|Q9$kOZ$3;U(@yNN^LE)ZmNFJN#^G{Iuw=>B%myoYoEIf-7 zq~jtx+?DjcBZws82o-gZjN`tmtxT{Tbj3xulVav6Ae_f({5!@D0!q-U+SdAeJ*!u_=yH z+LqW!r*lG5Z{PzbrGtzzrM+5{0&T=m<;ws!vN&m@MI-2q@lBfmYIA@N59pYAI#vwE zxJr`2Afx<}Vopo7Q>+}Gz`)B!QJBM`Nnidm?wmEH1<}}m`h5&`myykzc!gVo_t5ly zOTxGT(}D-@5y!lFy<4qMOG4F`<195K$wD_3uze}r2t1DLg@A}$P{O@Bt4<7$p646|-x@ENnWyDQ}z@4pZK38hvpA~Lj zrqZQ~Ok9>pKLi({|0*P29&gC_ZQ{CDh!XW07VYBTA?49G`YeK@ikcexa`znM&Q8gt z21VVscuRQ8o@PxOjs5YKF=;*~6<)xzOR^pK6E;{O?PT(f^$Pjjn2;mc$R}<*g;&$Z zk9MUQkzO%!wCa~fJhf>t;hGN4S;cfb^fa73;52AA$=_+zFbSJcbcb8D%&x^cz#}*} zRtTdkeJoR+)BEShDmMm^sri^{8fs<1X+iev7%N zN@++yQIC;6=SlN6l?A1R4!}TUD*opkZvl~AbFXSBrZisYG5}|UJeYeBNln) zwEKv~J2`o{<)(?>@A+9?rf5!ztu_$%*h%OeC(7gqCODAApt2zD7XVE10Xy7zc-p7q>gv zcivHSJJl*Ii4~XmyrWVreqGPLw3rs5+_ryMn**f@Z5~9n0i{v(bJO-F3yiDnMe5x_ zYD@g4Al+$+Rxsp_8g$5}MZ-s*tf;f01-2`b%+x!B>}K5k$orS>+=F>R5Hiz6Ya7=5FA=>wG$5|$FFyae{(pa+d@l7LHs|O=V4J#gI;_Ao)ZoPOFz}tW>Rq5JI3lm5CluETJLapAi8{^aDXn;Nc{$)a^d*gg>@Gclq2Dr+u zlX2co2JIo0bG5cT3|*iH!_W!w>m+u8+lSZn+U@fir3+ic2wnxXoVGXt;@ACgoT;bt z=^`+BRXXPG;%u(Y_Byg#~W zhOh}}FxjD|0H{rDft$YvTrFdV{H%E%ri(+Fc@_o^VrZLtd?dvB4K8UB0`n6^gkhSb@)h)ag+P+?wzjf7$lCv}NtI7)E1(d~j=ft|}E(@bTn|k>| z%ydd82rU2L9MP)i%3ok3+Lb_&V5);J!0wVXx*P@giI*z zg{QfgG-3G%lvJ-?Z*O<|colY4l*{buvS+rwkkif?p> z=|PjozzKgbGlpe-G^7h5&lAPbCW3F{0l!`@S`~O(CgN;Gq2e%{Pj4 z*Ra0Zhf81DjX1c+1gr|1sjO`GN&HYCpx&~(+fzAn6`vJ{vnMmEDTRo6yr;aAFYJX} z9Am3)fW!>4%vO~MB7c-kEYUM%jt2n z4@z*cKD*Z97Y+qmA(Inkd@#+(y!}GMs_wz1uoda+%ufwlF2hGaY4>48BY%i5;^Zpk z!N(*YQ{ZvIl{~h2>BHK=b7MYcgcVJZLKIZBi(V<$>1?O=8C78*9f>7plH6{yG0LX{y}3QEbPPtodAs`qye!uWz2}{xlDb*PN?&f z7CXWIPVfN#33hVA&_|y1y@e_Mqhi42jDWNvk?b0K{TwYLb<`(aOGBe4nd5J(G^tcO zw2E5X8bjssl50*VfqUVE&$#EgomGx(3Y;hk9L_Sw^613?&rB~=9XGZ4 zNX7A0p8LdO@1p>DJI|9TPvxR@VS=j9TOafM+a8;69`}6$N;q;~qPwg+sVu{zBov%+ z(&PN%q|6PDy4!9oA(#D$1>EYjkAeR;x~0*?VnIrKac zC&upx9bgnwb;hrIWexMJu`2i=u{@CEpvOlosl!35Q;3 zupppXMHBj|sF}v6Y>am}97h3#<5;VCEa7Z1SBN@3$5XXle0mP;(74%zM9KXJ0YJaT zV}||>!9|-QN6d+29&5I6P)sbf<^e*z+#hYCy{}>UoLY!*mxy7sB2hE3DOqS%nM4`K z3hS`d2~cptYSaPR`gE9OX#%Lt>r?`F7y3>{cO-9uVv7Pns~RXN3Zs#PS7`#(_7mg& zx?@V=?bHfPN_Fki6Z_WZ^fBnS#2C_ECD~Dl83-A%Rn-uF`+~H~sga`U>N7(vE0ZU0 z0*Euk$jvmxw|C(C4mGNhz6pj;Sa zNaT&9Po_0&28uKrMMDs8O~XdrviX+|+PS*5DSB22cvQySdX=l7y07}VpB>U|$@M#r zXXc@(7K(by{3g{)^Gj)Nw7#fbOY@`RT)ZRp{L@I0j}zA8G#17GAV=Nlfyme55a z<21zpvnsq+3{PyFj^J<4de@-t&q?)FY)b0_AUcuv5QI>sptkR+Qy&#gJV5Z9Zv;$kXR#Z8)p0E0ryw&tRa&OT zBMDpv2#YayS(U|IefUV&OYTYW@p|Jv?)Ao3QwED zqi+h67p?Pz5_{Sd;^Qnxh;(?jslfJl%7<%mlXSgf zSFrH067s7>3cJVgykZyy@2uWEgNiuhDnRYsR##>p!&QbbPjt{?fiEbZ@WW~DUgjtB z*QQ_d57x>jc@C#JUnO9c16J9uD%TM{uJxi%q1w$1RE`fX)~^ViukK>PwQEZ66GAU_ z0A}zas2a5h&nXVp%(Z3SYb(^YK@4KmAey+ny=3*n;xr}ByF5;be*>A)RbnWYdEVqp z+PY>#M&;RerkT|ShgI$iG7;hEo~%net)&V8W)y9Tv(xNpP5o)t)I3|Js=3@@)6`U` z7i{)aiBwTP!TAGQ=0}Um+^BU#@#Lh6_>_qi-OXCqeF=?NFDIsDq=psu>?hqlH&aSR ztH;BGt-akhJ3n>pV0b(8+2O(4o!!HtsCqP{Uau;?`QdQy&CY*mwZu7UyUNGS!>ymY z)>*)p<_Q{cf6?!C(yttSYdJZ)JZUrFwXy7)cSn*p^~7w~LcLvn>*wvQe;gnD3gg{6 z+}S$b-rwKbKj>B;LAIOt<->NjI74TwFTM0#QfKmZ9zoWuv{Q0H$R;zBoLc5&yQZvV z&B+(o*XPi&>n+Cu`jR74E+#29t_k~=wN=$=PH=JM>i*%fb*Lx3kUgrK6|u*<>)yAz zG@v-PAsdKT{YI60$Xf27%Uz!wOK4a0PeELkmue=oecY1fJD5h7#qLsaAt7T zBm2@^XM&R7V{)0Fw=hjPr8tCr8KHSeK={l^60=bSO4TJpF+7G3RKCE|uy= zn%)sVFrZ%+BajCo%#A34IeP`i$NTDLICZBPE$2x7ijQ$~4c@{i*qF%Jqsi`H+QncVv}rj^vH-Y)l*X8*T7uB@pv@N zuVKrs+8mgfFC*>bC&bH#JR5|p-v1rgS}rTULu?7ltoN^;B7zAGBl> z51I8||fS}Gc2wBeA~@f8{R%hvFs zH_WHdXi{?iCW#B}{bQr1=tfn{qh36 z2-;I*d1Xpl%D5k0952$_S(G*vEaO;5VeD{DvF=AIO?FaA)$M3fzO3@e+>?EyOkf`Q zbITTVzc;-lI>J2Go3Hi{>kiVu%c%X+=!PZZ94|5!LTR_-7Dp#p_~s!>2Suzo3(Tr@ zDj}krUhiwwoJgx~=w?$P^^}Tp?Ed)7sR(gl^U4Z8`&t8|#x zX@1y=q79vhcxt4Mna{aTRRQKY*KB!Y=kqcPHeS@wSGwb}1GgL{zm_5f*{o8$gubB) zA4f}{*dkjF{w7U=^8NBBhr&3|;+weerY<_f;Ph>wB?masFI}+)r>?(w)}HYA-XB;? zuo3q_D4UKWvwwy1X$(`|9mA6}StTiJvdG`mFY@V{PwHO@39q~-1jLF1yty^ZZyHT6 zPdQ#eMM&hqYEI*%bm+k=9CLTKbEM zq=OahL`jcUdv}882WC~rB?xXo6=3-E&i&Ny0W?~zE%~-#XDP(z*4-c`Indg9L%DeD zO~c+tkR`~9D9EHSaP*Q8s2~zGQs3dNtDyZ+id#l<7Pf;>&2WGs|gscVg?+<2v zze)xl;rxJPh#nmPU(-?pt;RbS)~nv|IC*kFw+P#Klc*D^{;Pnr}mv zkG9>Gma~~R9JenXp9wsy6k*TrEH+Vc zRT!RuAa2xm6Yjd=y9G=Puo_Dx$gqP<(l6+0D0avFrin-31(g*n|Wv{)9dJ zW%;*ctKAuz6(AhH+27ul`?(0Am<1TT33_TDhadN-^xZpI5uFG*rn-{6i+M;F+Ir%a zTj+CAl|TBvo`-(a`=82?riblg%Kgu)ODn6^{a??X?tgxi=fUrPo_|_RZ`rXOaD~b zgzj)5_MA6e*KX&%C>$w&rlX~XZ@y@!dG8x)|L860>3PIQmH%if{sMi>fB);s+Q!<` z{jZPlIPd>;Tn2d`rC_T3zr141|FiYAr~6+Y<#}-Vzv^yQB&jzkzZtaneCnSDQ5!$C ziQMjUF|4>1a;r@BfbBABSGm(h+}Zde-t;&uu0)g*#%PkBnPee}w4z^8xE~Jna#=D?DVo=E zkFsyR(K^&Gv$2Z1%44Ed{OYdJV)b!8Xn$8XFg6g&pkCKi2M($!gUZsy0utp~YE-B4 ztMDwhs;~0o7tP@kJ`c~%Blv%cDb%OgHqlB&5@YV|k9sIS5RnqoSZ8DyhL;$vXxF7! z{v`9Z_ue`MbkR&hCAP*)p$m-MfY`ZXMs;H^@85W-(OJXt@M8yEqjklLZ+2nFOSs}0 zj3NzA0xt^y1x=`y@>`JIYl2Z%-WY~dRPpIa?Eh;%Zu!r=>F$0e;VJSTNPDLJ_u0z& z#*_T_7|(;tf73)amwc#+ZW)Os#kG)@;8qA#CXqTtD*I~23Q5Xr?XMz7VeHsu+~?;U z4PlCE^ltq4xiRj3V3fqOdC$$=`pC7>&9ikc;MTq1^2ypz+u|2C&{)v7=3>)cXf0H3 z+W5KY>{c5C?E6N5Ux6467&G#bA{?7W?{e!e+WX{?i5#1}N#Dg5Z+@uQ;4S-)?IH2{ zUVbmL&@}$Pvii*6{~OO%pY;DndB{aE@Igbe=KZyw`-0;Y=6qyfr%8e*^n`mwsfEi9 zQ%H4bLy6ByY6b4vi|}p>_-~fkUEQ-AECCH`=`P7b$0I~y;u4}Eg)L8NwB-awtV2wT z75126f&VSTkQ^r(n~wLw1C>zSrW#y4eXx^}B?3{9tr#uQCACextx8vo(JDEBb_SJ& zFO#q@BQG4uN7Vw(6P~g_K{KCkpOlg>{@DB<=_K11cOc!H_v15-|F5sCnf!lw=}G>7 zlqVe0T3cj(hJhIaU}j9cM*exN+#!&Y9i00k8I{cKP+jyeAJCsjI)WQxEt4+^r>q~} zpmV-rZ_vn3bcE7grgF$5d99;lWuMH$8N=LS{qpI5aN1>!WBmD& zfN!!FKbY0kZDq!aVlTM}ZnBak%cupv-*1>>G(Oky(LA zClUqbf;bzeQ((iW3aIQVWHdS)=P1s)3b**jBn3Ph01>XSJG0k!bUfeDtvbT2s$5IQ z$G`ukRl)!1MDqi&|Ec_cY1QQa>(7>-;{P7yQTc!GJh=$_mb1pqf()LJ=+p`??p6`@u_dd%dkxx9rtk zMuwiH{*VLsh7Oo(<~9P*{>pw=FL2?dL~>Wx-sqMUlJtUG_I0To-@gtoLw@#6v+6nW zsT$o09a1Ac709k2XnS~FdpgxZ+lX@^E)>+@?YxtJ%25e~lDhn!|NY#?H2;jj_x-J8 zIP~K_x-2vysjDp%5&4dOINf5Z2s@Q?*_t|!t%^BpIp?qCn7fv9-ddCAtfh@eH@ilO z-+!-;sL`{)Z%)Fa(#~6D`0i#Z=3X-a3uqcM%w)?+h%NWrwpbF$p{jJ#w26oVB2FAQ zNUcd02n}{F%x-g*Vau|und#dUOpT)!stAfW|7Bbt%rOuwA$(U8N-3u+Y=g$c;~EZ2 zJTzhL7jo5BpUs$~p+B*8z?T1H?!O07{ppz^|1GUp`v2Oqm8B>7?=hY`OH+cPOPNPj z1eZ{lfl#(Em0p|Nq9*`hS$CSpVgwS*mnSHE@3% z1#kQ?8mED+{7L14@^Fw$M`;6JsCUcPLAI>B%F9R~EY5GJ!;&Jsl%`)yw`5ge<48Uimj~FA}mG73^6EEd&$=o%9qV^KdS=T;jizvk6-U> z{@8NJ4IN1JWdw=KfSAHJX9H&|6i>Ojpqs3W}7Yx2rCaIT}#HNZf;%+Eg+e0eQ*rvrR|&;-J7Q$4Ao* z##;^kdkm`JeHzsybkQp49OF?G_F(L?X}2gaNj%rbjf9yskWx1lQf(3KzEa+}hbbBn zM6h(p91AAabyjvCPA)To1B{;iW*@cYZ3;Rafu{J3_L$U>PcEa+NS6kktZ~ z8^wsCb-^iuFm+Z`1e98@c{FL)1XBqmb!-8DE*;R8|4Q}zp;W*r^54p;?f+d{d5Zse zlxGh6|Ch4o7gF6mzmlzgz%!Z&S%`l8BaHhz(5U!XAx>0?S|wHMGSMSz~Y4Z%S6)(q?j-=h^a}507?$v zu$LxTGRQl)PjNcxgjqHQp0~cV`Zp1Jzt~a9L!fgvi4VoW7YsFM42wU@Z5%1l4`boj zFW)07VW8y;G4n)J2HuS=rZCh3^-hfxxVuH#g7C|js7GmdiAS>qptzqGi}}^fTi+P9 zKs_(>DoW^LY;CbaA3DqU)9$i=-pAhmKPKq~pcT(BJN{#lCo=e}c+sWhC*QqJhQJq#xL;Fgw~9zrokv+^RDiSELbuTwUyxg6TF5>K z5{$bwgJP$(c;;wPb)Z2Tn|OPO>2ifXQ}ZZ9f7}Zi{2vTc9WHlSsWh(?KPX)$&6yY_7L+0*)ejAy$1U%B{!NR*W?m+*ez_fekR zOjG~nd+lhz51`TCH_`*Y9EAT9*l%BfpyDXJjfz8+!SD`%&mQ6+_?S#AE^i+ICQx>} zlLtdu+qmZY!F5sB3Sa+1?l61(%bTtrZ~ZSVo9lmlY58gYf0XA*T>fi6_WCa}E<9Kt zOLOP{TU*Iiy2i-V{ijEuE0nD5{FDH>_M7nu0r`4?VL`jWWYnsF@;Cq26s>kKq5 zNZF;+SCYTYEcNwGdx^D@jrA(gu6jsR{MzrU&!5OU)AW$}loA>o=>Zp_hPY3t>hmnI z<7J!zKkn(mJ>D{BAxXQS+W30^C|nwyasgo%bH@wYgy=)LAJG14T{NX2Rl5*MMK-^O zrmIOD-j?#i#Uf4HPEs76G8d{d7Ocqo#sl3dHVVai$M@I!hyk?D@LIk`NpV6DDjb7) z-W+&2#_XNI#IK2@U0y-8`4O?#1EgNvFfBhMBhz5b-F;gi7bnA?@uovpMFF1c6JA&8 zdXMC(zt2YgRV=RN*1ueYQRMuf-E}VTTuwo0Ew8A7x1;kL(XAjOc}2Q2TZMfkw0aG+ zFyQqZivTGEFCyzs*!+wYFvyCVJ&!ap~_TRtuGr|7rx&`D;OkvvkUtc%!KddY-uRrDgd6Z`s ztC`zu_V0M#hT+Se`TC8AkoN!RnRY*u*1wen{*EHSwDrHbVZ?v0P)Nwr`hSGyf!6;$ ileSM@mv#>K|BEZ}>3Mpdo~P$=pZ_0mG1UzK`~d(_gn4ZM literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 992faf3b..83479b49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fork-ts-checker-webpack-plugin", - "version": "0.4.14", + "version": "0.4.15", "description": "Runs typescript type checker and linter on separate process.", "main": "lib/index.js", "types": "lib/types/index.d.ts", diff --git a/src/IncrementalChecker.ts b/src/IncrementalChecker.ts index cc549547..d3c0a88b 100644 --- a/src/IncrementalChecker.ts +++ b/src/IncrementalChecker.ts @@ -24,6 +24,7 @@ export class IncrementalChecker { programConfigFile: string; compilerOptions: object; linterConfigFile: string | false; + linterAutoFix: boolean; watchPaths: string[]; workNumber: number; workDivision: number; @@ -44,6 +45,7 @@ export class IncrementalChecker { programConfigFile: string, compilerOptions: object, linterConfigFile: string | false, + linterAutoFix: boolean, watchPaths: string[], workNumber: number, workDivision: number, @@ -53,6 +55,7 @@ export class IncrementalChecker { this.programConfigFile = programConfigFile; this.compilerOptions = compilerOptions; this.linterConfigFile = linterConfigFile; + this.linterAutoFix = linterAutoFix; this.watchPaths = watchPaths; this.workNumber = workNumber || 0; this.workDivision = workDivision || 1; @@ -137,10 +140,10 @@ export class IncrementalChecker { ); } - static createLinter(program: ts.Program) { + createLinter(program: ts.Program) { const tslint = require('tslint'); - return new tslint.Linter({ fix: false }, program); + return new tslint.Linter({ fix: this.linterAutoFix }, program); } static isFileExcluded( @@ -192,7 +195,7 @@ export class IncrementalChecker { this.program = this.vue ? this.loadVueProgram() : this.loadDefaultProgram(); if (this.linterConfig) { - this.linter = IncrementalChecker.createLinter(this.program); + this.linter = this.createLinter(this.program); } } diff --git a/src/index.ts b/src/index.ts index aac5abd2..3561c5f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ interface Options { tsconfig: string; compilerOptions: object; tslint: string | true; + tslintAutoFix: boolean; watch: string | string[]; async: boolean; ignoreDiagnostics: number[]; @@ -76,6 +77,7 @@ class ForkTsCheckerWebpackPlugin { tsconfig: string; compilerOptions: object; tslint: string | true; + tslintAutoFix: boolean; watch: string[]; ignoreDiagnostics: number[]; ignoreLints: string[]; @@ -128,6 +130,7 @@ class ForkTsCheckerWebpackPlugin { ? './tslint.json' : options.tslint : undefined; + this.tslintAutoFix = options.tslintAutoFix || false; this.watch = isString(options.watch) ? [options.watch] : options.watch || []; @@ -566,6 +569,7 @@ class ForkTsCheckerWebpackPlugin { TSCONFIG: this.tsconfigPath, COMPILER_OPTIONS: JSON.stringify(this.compilerOptions), TSLINT: this.tslintPath || '', + TSLINTAUTOFIX: this.tslintAutoFix, WATCH: this.isWatching ? this.watchPaths.join('|') : '', WORK_DIVISION: Math.max(1, this.workersNumber), MEMORY_LIMIT: this.memoryLimit, diff --git a/src/service.ts b/src/service.ts index 01307205..226a7fa8 100644 --- a/src/service.ts +++ b/src/service.ts @@ -8,6 +8,7 @@ const checker = new IncrementalChecker( process.env.TSCONFIG, JSON.parse(process.env.COMPILER_OPTIONS), process.env.TSLINT === '' ? false : process.env.TSLINT, + process.env.TSLINTAUTOFIX === 'true', process.env.WATCH === '' ? [] : process.env.WATCH.split('|'), parseInt(process.env.WORK_NUMBER, 10), parseInt(process.env.WORK_DIVISION, 10), diff --git a/test/integration/index.spec.js b/test/integration/index.spec.js index 3592e6d9..a872abb8 100644 --- a/test/integration/index.spec.js +++ b/test/integration/index.spec.js @@ -1,3 +1,4 @@ +var fs = require('fs'); var describe = require('mocha').describe; var it = require('mocha').it; var chai = require('chai'); @@ -9,12 +10,31 @@ chai.config.truncateThreshold = 0; var expect = chai.expect; var webpackMajorVersion = require('./webpackVersion')(); +const writeContentsToLintingErrorFile = (fileName, data) => { + const promise = new Promise((resolve, reject) => { + try { + fs.writeFileSync( + path.resolve(__dirname, `./project/src/${fileName}.ts`), + data, + { flag: 'w' } + ); + } catch (e) { + return reject(e); + } + return resolve(); + }); + return promise; +}; describe('[INTEGRATION] index', function() { this.timeout(60000); var plugin; - function createCompiler(options, happyPackMode) { + function createCompiler( + options, + happyPackMode, + entryPoint = './src/index.ts' + ) { plugin = new ForkTsCheckerWebpackPlugin( Object.assign({}, options, { silent: true }) ); @@ -26,7 +46,7 @@ describe('[INTEGRATION] index', function() { return webpack({ ...(webpackMajorVersion >= 4 ? { mode: 'development' } : {}), context: path.resolve(__dirname, './project'), - entry: './src/index.ts', + entry: entryPoint, output: { path: path.resolve(__dirname, '../../tmp') }, @@ -92,6 +112,95 @@ describe('[INTEGRATION] index', function() { }); }); + it('should fix linting errors with tslintAutofix flag set to true', function(callback) { + const lintErrorFileContents = `function someFunctionName(param1,param2){return param1+param2}; +`; + const formattedFileContents = `function someFunctionName(param1, param2) {return param1 + param2; } +`; + const fileName = 'lintingError1'; + writeContentsToLintingErrorFile(fileName, lintErrorFileContents).then( + () => { + var compiler = createCompiler( + { + tslintAutoFix: true, + tslint: path.resolve(__dirname, './project/tslint.autofix.json'), + tsconfig: false + }, + false, + `./src/${fileName}.ts` + ); + const deleteFile = () => + fs.unlinkSync( + path.resolve(__dirname, `./project/src/${fileName}.ts`) + ); + compiler.run(function(err, stats) { + expect(stats.compilation.warnings.length).to.be.eq(0); + let fileContents; + try { + fileContents = fs.readFileSync( + path.resolve(__dirname, `./project/src/${fileName}.ts`), + { + encoding: 'utf-8' + } + ); + } catch (e) { + throw e; + } + /* + Helpful to wrap this in a try catch. + If the assertion fails we still need to cleanup + the temporary file created as part of the test + */ + try { + expect(fileContents).to.be.eq(formattedFileContents); + } catch (e) { + deleteFile(); + throw e; + } + deleteFile(); + callback(); + }); + }, + err => { + throw err; + } + ); + }); + it('should not fix linting by default', function(callback) { + const lintErrorFileContents = `function someFunctionName(param1,param2){return param1+param2}; +`; + const fileName = 'lintingError2'; + const deleteFile = () => + fs.unlinkSync(path.resolve(__dirname, `./project/src/${fileName}.ts`)); + writeContentsToLintingErrorFile(fileName, lintErrorFileContents).then( + () => { + var compiler = createCompiler( + { tslint: true }, + false, + `./src/${fileName}.ts` + ); + compiler.run(function(err, stats) { + /* + Helpful to wrap this in a try catch. + If the assertion fails we still need to cleanup + the temporary file created as part of the test + */ + try { + expect(stats.compilation.warnings.length).to.be.eq(7); + } catch (e) { + deleteFile(); + throw e; + } + deleteFile(); + callback(); + }); + }, + err => { + throw err; + } + ); + }); + it('should block emit on build mode', function(callback) { var compiler = createCompiler(); diff --git a/test/integration/project/tslint.autofix.json b/test/integration/project/tslint.autofix.json new file mode 100644 index 00000000..8ff4101b --- /dev/null +++ b/test/integration/project/tslint.autofix.json @@ -0,0 +1,14 @@ +{ + "defaultSeverity": "warning", + "extends": [ + "tslint:recommended" + ], + "linterOptions": { + "exclude": [ + "src/index.ts" + ] + }, + "jsRules": {}, + "rules": {}, + "rulesDirectory": [] +} diff --git a/test/integration/vue.spec.js b/test/integration/vue.spec.js index bc622c51..d2ed0091 100644 --- a/test/integration/vue.spec.js +++ b/test/integration/vue.spec.js @@ -78,6 +78,7 @@ describe('[INTEGRATION] vue', function() { plugin.tsconfigPath, {}, plugin.tslintPath || false, + plugin.tslintAutoFix || false, [compiler.context], ForkTsCheckerWebpackPlugin.ONE_CPU, 1,