From 16f90bd22b465aca9a1fbad09248d80aa93fd824 Mon Sep 17 00:00:00 2001 From: Jacob Weisenburger <31667350+JacobWeisenburger@users.noreply.github.com> Date: Mon, 29 May 2023 10:14:00 -0500 Subject: [PATCH 01/22] Update README.md added https://github.com/JacobWeisenburger/freerstore --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4057cf424..a0064e054 100644 --- a/README.md +++ b/README.md @@ -495,6 +495,7 @@ There are a growing number of tools that are built atop or support Zod natively! #### Powered by Zod +- [`freerstore`](https://github.com/JacobWeisenburger/freerstore): Firestore cost optimizer. - [`slonik`](https://github.com/gajus/slonik/tree/gajus/add-zod-validation-backwards-compatible#runtime-validation-and-static-type-inference): Node.js Postgres client with strong Zod integration. - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod. - [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas. From 2c802507d92d2d2e15be959695b1de78b896bfcb Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Tue, 30 May 2023 15:52:13 -0700 Subject: [PATCH 02/22] Update readme --- README.md | 29 +++++++++++++++++++++++++++-- deno/lib/README.md | 30 ++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a0064e054..415194d30 100644 --- a/README.md +++ b/README.md @@ -232,7 +232,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer proxy.com - + Trigger.dev logo @@ -256,6 +256,19 @@ Sponsorship at any level is appreciated and encouraged. For individual developer

Simple file processing for developers.

+ + +
+ Infisical logo + +
+ Infisical +
+ infisical.com +
+

Open-source platform for secret management: sync secrets across your team/infrastructure and prevent secret leaks.

+ + #### Silver @@ -392,7 +405,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer - + Learn with Jason logo @@ -423,6 +436,18 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
+ + + + Katt profile picture + +
+ Alex / KATT +
+ Creator of tRPC +
+ + ### Ecosystem diff --git a/deno/lib/README.md b/deno/lib/README.md index 4057cf424..415194d30 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -232,7 +232,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer proxy.com - + Trigger.dev logo @@ -256,6 +256,19 @@ Sponsorship at any level is appreciated and encouraged. For individual developer

Simple file processing for developers.

+ + +
+ Infisical logo + +
+ Infisical +
+ infisical.com +
+

Open-source platform for secret management: sync secrets across your team/infrastructure and prevent secret leaks.

+ + #### Silver @@ -392,7 +405,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer - + Learn with Jason logo @@ -423,6 +436,18 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
+ + + + Katt profile picture + +
+ Alex / KATT +
+ Creator of tRPC +
+ + ### Ecosystem @@ -495,6 +520,7 @@ There are a growing number of tools that are built atop or support Zod natively! #### Powered by Zod +- [`freerstore`](https://github.com/JacobWeisenburger/freerstore): Firestore cost optimizer. - [`slonik`](https://github.com/gajus/slonik/tree/gajus/add-zod-validation-backwards-compatible#runtime-validation-and-static-type-inference): Node.js Postgres client with strong Zod integration. - [`soly`](https://github.com/mdbetancourt/soly): Create CLI applications with zod. - [`zod-xlsx`](https://github.com/sidwebworks/zod-xlsx): A xlsx based resource validator using Zod schemas. From eaf64e09ba1a87dd6bf348fb97061894a01242d2 Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Tue, 30 May 2023 15:57:06 -0700 Subject: [PATCH 03/22] Update sponsors --- README.md | 14 +------------- deno/lib/README.md | 14 +------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 415194d30..a59d90d5e 100644 --- a/README.md +++ b/README.md @@ -266,7 +266,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
infisical.com
-

Open-source platform for secret management: sync secrets across your team/infrastructure and prevent secret leaks.

+

Open-source platform for secret
management: sync secrets across your
team/infrastructure and prevent secret leaks.

@@ -436,18 +436,6 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
- - - - Katt profile picture - -
- Alex / KATT -
- Creator of tRPC -
- - ### Ecosystem diff --git a/deno/lib/README.md b/deno/lib/README.md index 415194d30..a59d90d5e 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -266,7 +266,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
infisical.com
-

Open-source platform for secret management: sync secrets across your team/infrastructure and prevent secret leaks.

+

Open-source platform for secret
management: sync secrets across your
team/infrastructure and prevent secret leaks.

@@ -436,18 +436,6 @@ Sponsorship at any level is appreciated and encouraged. For individual developer
- - - - Katt profile picture - -
- Alex / KATT -
- Creator of tRPC -
- - ### Ecosystem From c5763112e2912390f3317d738e4261fa8747494e Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Tue, 30 May 2023 16:04:51 -0700 Subject: [PATCH 04/22] Update readme --- README.md | 2 +- deno/lib/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a59d90d5e..a32bb3da8 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer - Infisical logo + Infisical logo
Infisical diff --git a/deno/lib/README.md b/deno/lib/README.md index a59d90d5e..a32bb3da8 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -259,7 +259,7 @@ Sponsorship at any level is appreciated and encouraged. For individual developer - Infisical logo + Infisical logo
Infisical From 5e23b4fae4715c7391f9ceb4369421a034851b4c Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Sat, 3 Jun 2023 23:58:08 -0400 Subject: [PATCH 05/22] Add `*.md` pattern to prettier (#2476) --- package.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5ce700d75..13a3287b3 100644 --- a/package.json +++ b/package.json @@ -68,11 +68,14 @@ "src/*.ts": [ "eslint --cache --fix", "prettier --ignore-unknown --write" + ], + "*.md": [ + "prettier --ignore-unknown --write" ] }, "scripts": { - "prettier:check": "prettier --check src/**/*.ts deno/lib/**/*.ts --no-error-on-unmatched-pattern", - "prettier:fix": "prettier --write src/**/*.ts deno/lib/**/*.ts --ignore-unknown --no-error-on-unmatched-pattern", + "prettier:check": "prettier --check src/**/*.ts deno/lib/**/*.ts *.md --no-error-on-unmatched-pattern", + "prettier:fix": "prettier --write src/**/*.ts deno/lib/**/*.ts *.md --ignore-unknown --no-error-on-unmatched-pattern", "lint:check": "eslint --cache --ext .ts ./src", "lint:fix": "eslint --cache --fix --ext .ts ./src", "check": "yarn lint:check && yarn prettier:check", From 898dced470f1045b5469543abd2f427a713d93eb Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Thu, 22 Jun 2023 17:45:10 -0700 Subject: [PATCH 06/22] Revamp tests --- .gitignore | 1 + babel.config.js | 6 + bun.lockb | Bin 214405 -> 0 bytes deno/build.mjs => deno-build.mjs | 0 deno/lib/__tests__/coerce.test.ts | 57 ++--- ...s.test.ts => discriminated-unions.test.ts} | 0 deno/lib/__tests__/language-server.source.ts | 76 +++++++ deno/lib/__tests__/language-server.test.ts | 209 ++++++++++++++++++ jest.config.json | 4 +- package.json | 16 +- playground.ts | 132 +---------- src/__tests__/coerce.test.ts | 57 ++--- ...s.test.ts => discriminated-unions.test.ts} | 0 ...es.source.ts => language-server.source.ts} | 0 src/__tests__/language-server.test.ts | 208 +++++++++++++++++ src/__tests__/languageServerFeatures.test.ts | 207 ----------------- swc-jest.config.json | 10 + ts-jest.config.json | 10 + 18 files changed, 597 insertions(+), 396 deletions(-) create mode 100644 babel.config.js delete mode 100755 bun.lockb rename deno/build.mjs => deno-build.mjs (100%) rename deno/lib/__tests__/{discriminatedUnions.test.ts => discriminated-unions.test.ts} (100%) create mode 100644 deno/lib/__tests__/language-server.source.ts create mode 100644 deno/lib/__tests__/language-server.test.ts rename src/__tests__/{discriminatedUnions.test.ts => discriminated-unions.test.ts} (100%) rename src/__tests__/{languageServerFeatures.source.ts => language-server.source.ts} (100%) create mode 100644 src/__tests__/language-server.test.ts delete mode 100644 src/__tests__/languageServerFeatures.test.ts create mode 100644 swc-jest.config.json create mode 100644 ts-jest.config.json diff --git a/.gitignore b/.gitignore index 2693009b4..943316dea 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ deno/lib/playground.ts .eslintcache workspace.code-workspace .netlify +bun.lockb diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..dd242dc90 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + presets: [ + ["@babel/preset-env", { targets: { node: "current" } }], + "@babel/preset-typescript", + ], +}; diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 0a94b94a09bee98a4273fb2ce189b1700f460c67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214405 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[&!ZU;B)Xbs^Nmh?;?=Kyp9qye$#+7 z=5?H)@p}ZMVLeJULD2Xu0sNElpDbv6U!Tv>A2$~H;Jfyuu}qo@8sC#A4SrnJ95l+| zJMN^hoLUGP-%lsc8fYit@*Qx}3IP{DBbo16GcJy@sxFD=_>MGbd{6eWpz-}?(uxAN z1&!|}lU59n-;}`KFKGCuDh_asgMWN?mo&bB+?xda@%>oFEeYfn^7w8mX{CUCg2wk! z8Mid>h5`KX-A_JO26&4w?aM>Z$|C$pJjZt~`CK{R62i1OzAs63dEm03@ts7{Dgajm zjqm+2ZbjfanfT*7d!$tY!b!j%-?t;XG9WF$;>vg0_*@mBHNZcH$*)ElSYpgEmdjdg97p z17Hn6`_~B?jti;!iRWT)rMyN!e?f~Cw8o$%0&FL7ppo4Ks6j>Xmmp|O5v~bZNnCpi znkT|VKr4l7U(lFFGoYA=%k=S2)f{+@0NX^Oc&-J)mI%}S2MC%M!kYlvI_nSrR4oCP zC2f7MptVA{2buUAiYt?&&9@~1f2=?1(gyGb*d|5_8lPzaCfmd)(C|;y4)9_G{3VI! z7|#kcwiDJppKA{k70-u~+6exs zIs=;#puN%_NW-xJ)mA~HJ&@KF*v$a`rsK*qe1YEtZHAzA1MPP~n~5uf-GRe`He1mA zK;!ShuuaSrG=GHon=7QH2wDKb%rD!?0??RlAg~KyJ4qGKsS(}>@Nbcz1tGj&qNr3$ zMBHH9>wgDfsi1{`Rv2Nnr)46p2I1QP|5k|SdLaA&U>jR0o(n~|1eL@GozL)bkd`f6Nv3mW@H zXV5%xr9Ds{`^Czjv3>3lv|b2T5wyL6)*G~Z2(x|e6SO`EGhMdN{espPVf}Z*X$?04xv)`J0@rY5Dpcz<09@r&={9(_M~`j5W=nT9NX+E z@!Vj9F97^IEuI^KFypcvpAod7g2r}tR?vnC8r#@8K^us3J;gE0G8ww-IZ;-6|P(3S!G z-N2P`#{rbbc5+kD#tT{xTyF{51cW)Bqy68;75}99IOEd(?~3OpBAg`3{+^&s0&NUv zwEz1e?qq}+m$v>;JU2zqXzPyzZK|Nr)*lPnG=%BzY1dB#Z92j^5T-3X6|@-$=MuDM zf;JO0e(Rj}^<2P)+NC1`UIz68*2*e{_8 zNbQu*u@2se=TZ>vhA`{kJ+Antnh)^z>{(_X1#JPs`4DCvKjR9vDivUUna3}Jwh-Yf zz+B*~pe;g}>81eR1Z^?Glt&pLL zXerN`aLo*40kQ(wfb2jHASaLu$PMHH%mI$=EP=d0J|I6(04NAp0oFhvpfGR*!jA%n zfWyEX=sXvg2XG!WA6NjS0tXpfk_~@CCX7-2p$q9|!;f0W}Z=1Op*}2Iv8V0==QjSzONn=K;=zIQO{%Tm^0b zocGiN=+o)Ldja&(oWJA&EP=cL=Pvny0zg5)3a|zW0fm7#sC3%(2jCMxo1_iW&s+!S zzu0%uSI{@G-Ls!#yN(8018soXfIGlG*8`{vGyoa`jesTq`=TO1QJ@%b68Ss@`~j3j zI^_Uw7-D;X^AgTOXzR3XwuimYcR%nu5C>i}U>(AH5PvVQ57+_h1U3Pifi1u`U^}oD zSO=^JHUJv|&R6CF^MDi}6<7#xezF)?3d{t?BONt#2m&~!SOst#F&y*}K!2b&&<98W zVu3gy5YNZpss(g_8RCTF8UgeK=r3X+KMsfo5`bPn3{U~j-o-NyfPn~ep2D&25MU(0 zaVp29V}P;1c!1-|WPszwNdU)+92-spIL=!^{ejg$Kiu~Rh9Nv0;MhJD_X`1z%@zY3 zk1Yi_-s1SZI8Xv$f0q&0EI@YPI_~MG*zd5PVZU+*2n5tX5YPi)pWP1NnAr=c1(X6x z^B(n?A1DZLJWYSs9M`RozXKQtuph_>IgSXgKpCwBRsrniCIBIT1_%Z?ep>@1;#rQd z`vUO*e;0zk;oypRZopH}o&hg_KY^FPYv2v=7We>s1U>Q?$lrhA zcrX++j`uje3j@M|NFW+$2@$P;azJ^Y0#FgC1XKp90964Sz!tCr>;VVB5vT?@0nUI6 zP#tgu+<+QD8K4c)xq#~~=sFYEHK?1_Ko5kwipt{DA-<5Ksd_fGhG*9`HkY9Q))1Qb3;%EC8kf(}Bz2S3o{00+oRCxaW|8zbjP- zaVFsE4_X0)&4DGjUkWS(mIEH3SpX{$9*g)~`)dJQ04@Tz0CV6ip5a)CV;_!rF9RIs zMnHBwpgzELrA@%^kh34y1?&cv16u*E9ZdtcHZ%#Cia1;oN(RONOK`sw7>w``AOoPm zb0NSzgoh!$5x^=uvj#{6YJy$_C<$Z+7{?5Fh37c#arhep8K4FgMIIrIfIa`3Ozz*OTXeW$h>_VJ90GHGYgMT04 z2f$mP9B7=MRsyO49>6@%&2Z)XQJ?kz#7hM9_Z~>UE>IibywDloypQud>X^^yS$!NW zK*-b6$ALcH=(%i2<23LQ&wT-oBFs5m+UF=oFT)G` zmOvxmnUSpOxYs{Z6XB{x_mvUm9A&W4^ZIA?SEj-G<+ToUt`67%Re}71o*ma50OuXK z0nRnv0*u2sMk=sS-0S6D0*`z>&LAGcUjcnS^*nu?ZsHlzji2Fs!uVbvk99@e^8jCr zo>?q(xdJ&?folNc=+n{5V*V)OhT!x5Cc+2bK>+@&={WHBck_m}c#Qszey=Q^KZEFJ z0oGRqfWD_Zc>sM2{og!bEqir?625wvHw~s{#ZuL3;QSbP3)tp11>;qpccUX ziTxD&sG5Km&;)1*GyvQI4}jzBx_gt+8V}G9vR|Q& zsX$wxC%|z4Rb|~EsH%_uk5VJps{wzY4Zt{EaqR+h z208)sq3r;s+Y#^q+5_}2ngwt8G3bp}-JeBrpOP1`G#A0i%IgKt-g*dbtl6 z=V2=DnFl-YsoPV8ZE&59EA>mkmHJHrCII7ru|Rep8!#SVdGMKuKr+Cx)Y|}g(*TwS z)8ccJfhhp%aXLW#s1wU~rU>iHn0hb{%Y$XW=jH*FN4;5Q`tq8C@LYg-W&g*1uqQ`0gR)6mOS1s0~nY0Oe?J%-roUk1Gj*izzyI!a1FQ$Tmdcv zmw*cZ^Ku?wnKDmDfkVJSU>mRt(C2Rh!s~#wz#3pRupZb9BmtWMy`0?$?*w)L+X2dA z88QA=5#~MR^U8SoXL$cRuou_^><9J%2Y_k->Bf5P#{CiCFu=5^i!q<_h;zVM-~@0C zp#IGNao`Ma8u$Y^33LHY0en`k%SD9w{Qs{jb)3&p8(_P7LC*wa1Tp~Z9KP{_E1%;%!^|V=nsTxMtOw5JEdY*va{_z^CO41^ z$OGgBEP;Fg=l%r%>SkOYEGvB(l>(n-qy~y0To_`j85OPoJA+aFy%Xf&wS1SD1-5tHq#)V{;4LO`GBh%uKF@#9F}Db z(CD)mW*eeS^7(tXvd(y48~3%+&`77=`tql|x_HI|U|q6qXMxrZS3XBQ^m&|yF!ksK z)B~R~8sgd;*QWr>leWuxY5w+A?;U_6#lBgA7FwZzp6;M}Y^ zFcCCQT$=!FJB@K|3N#aFgKI0GHP9B|T$}kY&I9d*_0BxZ1egc559T8q!fZDkfKEVr zfcas4upLs@$pH2B29G*Z9{WK0+m4_yF6HXRw0elgMxQ@rQ2|zoU zh%28l=Fb9cDlik60Zap?19O1czSHj#QI_058`?N z*bnRl_5izqUBFIYE3gUJ2&@Oz0j&Sk0Q&@%@hXH@0Ly`ez%qdKwivtxxH7MOfcc~W zOMxZ8B7o1Q0;Kbv*OkCpU=2_X*Z?q{&A3_uTL8AVZMg0LwgYSvzu{UH*L}D$FAV>V zE9rzjPqgWyxIYXW0Zsrc3)(Hqhhdfj^Q+G*^T#|fAC#Q}u#B$(_kf!K}d>61WxzxVBpY_r(F~nE}`5KoNj` z;}Ncm{|tBvJOLhy>qlI(ApQ$ni{knTSJH|gTnMlR-s0X0*Mh(sgqarCYu@4d8qlv9 zd_Xua=v))w8pJo;zXZ4*I0)CQxN^;q>m^)9;Q9&IQ8ELWfX{g5Pe8B3dxV+ZD}ZuL z(V0H=D+y39y-w7HH1e3AjF8V~zW^B!HUm@ub^HpD$8-oj&nx3FOg)%B!}_vf{+S=W zd_CRx8HUMcc`&S(&1bnjqkooZQx@;_U_7SDEAz$mR`PhyvZM_CJ+J!oDVKTY+931A zH1#s{>2rOD_CwHSXeYY>V>#R_V7h5(#`l!V@+*gDXU$Jpi~dbUNgvXLnKFOMT(s9cAb*SZ>a5-&CJ1x+Q|Bq z1n1z<GgP@Cb)_U8x-ZgMI4$2Nr)YBueA2MzGC^Ue?0pR2X z=T_wm!ylbBUj>evt%Dn+>E9>b(k`+0DvQPM!Ev>9pxViZQxI|H_&<5#*XR^RNZ?Qb zY0PX1j_=%UYaG^Astk^UtqVDvjphd@%iWjxyffyH1qa!5wsn%`g(bn+nybKYhro^hTbPEl~&GkRpH>vpq`6i4Fd--)(*7ErV1vyBTy9OOs;HPMhU3p~%ZoM^{5 zZno8I9lpQs|8_#TgcB>?YzN1|5uEDZzoby8bG{ROH|1C((s6M9{_Tk?zV>a_R@ssy zaishdfXU>7ZeQZ!QzsvKbrc*VVp|R4F!8O6R$-T$n5WhqFU6^D4-KMq@)v`r{I=-y zo{qbz0d%uRByhqbwNWANcZZMNIjwaoa2%YZLI8&!dQc7aaS5_Kc+Hm_ds|cy;)H4Z zQ9_O8TwR)CwT<<|>^NW)D85dgt7-nJV;*JP2~IUzSC(igXq^LE&ncH!waO5+e>O8G zTW83SM=e(1%*fy9Q^1FUV=_>h6AV!rLy+UOb8Vg2{$DGBQ%$a)%aBG+o<&DfTTi*_ zFU4`Dz#yGERvi(o+dOWd)sSbyuVpgpN8NrXO^0U25-pIYX{UgY^EDvN2^v6a{g>-4 z%G9nOm-W@A3}*dMoYiezRM{|?rS(p>NUU3}>&k|RV-HJobdXMRu>B1Fwqf=s>jDwr zz;r2%d;cthJ5RP2-d*y`DJhOrr`&y}jULR}YD%LA;d?TfNy#|4sak+Ti*Mt8vP#in zmWvFW01?Of<41=!hh5YL4$lx2K%Ch{?6;nN7|_YU;fa@g;Mmuj-fdGB^9%+K_t%(C zZmR|lXRnMsVBqkC1a;e^de*r7!wen<&LMDE2AVCk7CU7Lzh~fF7I7{Q3Tosq`Or8aUzLFhBPvN57m`=j}EFr$0E< zdU&SgA>Ax%#2YvhgtX+EPs;R2nm*jXStz9ac6a>Zd{&L$8919ooP%!@OY~XboowJ7 z73pNNbg#16Y~oP^=em&Q(){Sgc@x(6GH^K3Hr+~;?Rr{nX;&n%Q0*KUT(TzQkStMZ zryIesKu#Ops=a^v%-dUq^;XA-RdD)^U3auZp2DRKoO6QX)BD}seEnB!7aUmpJ;BLZ zJNNaG3u@U54qBuBy{3!r#s+Skd*@GZT+!y>L*60|TS=+y`R}*9S7)xoaUjP}8!UN@ zT>DF(Z#|_oH9!ouEN;`_U*gLHm$JL~w6K%XkvM^xAa=W|2l26IlA4bwEXAQqROLYg zrlV;VTEK3?h(r+w9BXiBRlnzYb^BwHU46l!-vK8fLQ+6=elF%Ccf)zML!1-XQ4*lwM zY?_o)l$^aP8;qK@J#nD*wl9Zmyk-A}%&M%xK~jlU+h<<(oi;_oII?FYvk(sq@6 zyZptlI(iEMryZ(*oQ}JmWuAHMX+^}rn1*qdfP+F!?9lp5i>@yZ-4yA-4x-`qn4eLB z6W46Nbm+Q>1A7}RIJ>IOxKz{I+Ea>yo&hs`a99hohi4OZj& zdSTv~872gclj5*&RC5rAw(~fA-wdDot&f1iP7^ux*ZKvhb(p{BzmR3?-uorMq3uA* zUBqFzd3S&E?c+GVx8R6gvkM$ArPY45d(B}B=MZo>4na;+z+p}^`8c*amSyRFa74Mi z28Yrr+co+8zH|PUA`W!Z=xl<+BK=iygM;qbwv2HGhq^)9b(ja!$uaBZrNLQmR|AKm zL2v@CW&d_8SBo>9Hatg9ONKLyD#%Y4-4oZ?Tb`%wy^^{jju=;I)iFA}vZ*pJ+pt}o zNmaW@9H|V_*8(e!(#m0w$ewms)=INm%wM}misL}@?FkNRyJm?dzP%=RHj_9Uj;d-E zmUG%}%eF0pN@o2?i|42k^9*qCFL7|4Geta49&AjlWllE{r&k|$*OZSPGD4a(-m(Aw zZGakDf8W~H%i_p^^}-H95Qk;Ge_YP7b=p73lK~?XSz3Be;UGBrH-QT@z1u$bgtE6Y zm{k{?SV&_|YX_eU>@%!KS*FAG_v;ITzOXCt}Z?-U-0*WP`O*`te_%1E&h>JeN$+lX_S}xB;IzC=wM%%ocK&wLO za2TCdHv{Jb;xIpzx-K|avrG5l;0U{>1~&NY@JscvskSRB&M?F&38w>Ro;W)tZ|tfa znt~Q)nL(i^Qq~{{Z00Lq%A&6^r?Syk{jF{RA%0<@u!j@32iP|+*yRG^$U|6_I$je^ zOEF)1<9gFmYoozI70{~UkPd6X)${N(#~Fp=r8thXMCF_g6md3}&R?_NlHKhMx|y~& zmS_^z_PLwt>JStkJ+LF)VPN!~b63CI;X#zSrxDeIY$G4VNPki?Rz*a6%R6vXdajYv0_B%7zu@&N=KWE#J@NU3wN%zKA?G8%va(_p5iGuw1Y2UW~-x0H()P=u{zsNf`e-W z%eui!vzK>wM(+lPz6#Pzw*`t@ib)o0;Yna8@2jDD7Tx;jd3WDcdX3 zq9f7~v%^XyWUamI_M{X#yf;5M!rn}#BaK58w1x&+NTY@L_bgl6Bd575qzOCt4IJk5 zl+V(WO<&Ksi{2T9#$F~gOdX>|S$C*CaCFx#%?=|DO9!=3yQCZ^<#Den(Oq5*1BY%0 zwV>R#-y;tDl3|%ARJ>gC@@2$vL7hT3<(6euO4d4h?wpj_b7w&}wo~{QRTw8=(5+4J z^6{1#yDX7(lgc2Eh+{E(Nb=zUf8>_qu$A}<&aC*}K|X!^cp0RbC~I03%T4VU5N)H; zjV;jCZ_C!{We~?fHl7ltW$P_5E5i+^yzB3SgB}>2x{C>EVgy;JjO_gz?hObyR^gQv zajK)Nkxq!8&L$|#FF5&1$kyCGms!@Lww1LmSXN#?n7Xj?(|7lR9wQFx6w(~QpE?vlZ*GAR6Oia2a@Q=D7eIOv*tCgQ*!*xS1Ppnk?7PCmq0 z`Y=)FdfjfXL7KLl+-rWBRlR@Jwsutvob+1jHBh!4Wv!KMCqQGPi3p0sImDcwdpuc* zo)%>w*_*OgHaU8d{7%}w5zX7OY$bjUbKQa(VNoKCP{eY&GcC z8k_>)WV?{vYH8_vxeOfTb{d2@^!^Pd2W?*75E~8OTW}0Gw6|K7hju^IvhXN_v;jhc zlf}ITPbl&1q=EA@J)rU^dNk6Z=L>P}w$QHX(@97NYb$I&%05IF=BEomi9Vf`J%1&2 z(s9HQEo(BQu`RS*aVqZV`9d5KiykoT8W(46ToQo2e_x-oEKp*dd-OWmJZNH6}JTQNbh4gRmVw6?@&C&wWcJ-`q`AL6I_CK(AS40X12hK0? zUaMXiTX;{ydX=7I!g_^A8i6>p(Fco1nx8wDg}tWmZzjB@G}FUw1LEXIoH6s(dVlGA zf@L6j854fgS> zoocpZ{zJ@=^{rlcY}plY*cNhFxY*m}7<9!D=ilr3)Zv=wXtg$B@o#g_b!hL_3F%g%pmth@XB7CEc(*DUh zY%5zij@=^n-S>w0bLEHg1*D_g&nf5h0;I8Yj%0gS-qY*wQRYV;1(;|hV%%$@m5A1; zY`s5Yqf6{$-D(6a)g@Q(?E&4`Gr_x<@DxG=W$RTggAGV0H_9NnS@o4`U27MX(ve2% znNX@Z!0Bmy@?O%UODb^aL(n%WkCpc#4t>>cd27Du)_lSd#6b*t1Z97qTsrB;JNo)* zj&fj+5p%G#%j`!(xb{Tdkh-!oWeZU*QROzLT%yYToXMUEJ53JNl(lw7dD9;p4ZXf> zyUV1H$f>YVWv!Kcm2!{%GyQgB=*AX&b%A%T)WAv{_fj{sZ4>>E(E117AMxnlhP`dF zr+nQwqcKt(IJD7%&2v3pzq9u-rXzc#!QfbclkaS4+XZW8?36k5y~?feKh>8^6uOz; zo>acHeTS>iP1vZi_5RGLQ@Jluw%!HMjqUV(>W+8492>MWl<3clI#-DLS#kJ^^@H6l zjOL9$(@M4q-8PT!bG_c&xN*=;_&4R5ga;Zo?ci~b-b1t3aG8TR)orWOSG58Mi>Hb2 znvZ?%aHovCb}Mm0z`+DQG4$O=C-;~2I1?9fhJnM;M&bA2PnR?+J<`CL3=VsYg8A+> zuQ3fSg$S_iPp0W;?J!O2?j~&ci~t ztE(EGaxawH4ji!*d=Z?Ih%?c%!p`mEIsNv1VJZ zu@Uk(9yapB*@yUTL&Hk2RCACN2rxe{_VtaLdHyJ8{9Lbsv;=$-PlMm_eK}?Ixx#%) zaSdNsqH>A;Oz9~5UgdO_!4^1zJX8D43danu=v`2A^nA*-pq!4f^(ssI_tvR$I=8B0 zUjjKzuF&7l`|s0h zTCn3yfom%b99M8?y^U{$HLU#GCaw{SIE}zzUvFN&(Pi`6Pr2GEaa>hx!C|Yf*V4OX zi=<@s_2AfJ*VUxImNYQwuO*H@q|qZielUG{Tf4o@A#?#(`DgWSptBCrO&=oYHztOH<~sW!3YLSE*+d*z~CIknN$!DUTVzc+#Ig zkT?$2v9l`w3hU!Gp6-wDw4r~)@dwT*X*gW-Hk?cllXnv*6W|MMdEW4FUD=1+{CaF< zMW@_yA1uuql}|G$=m!6xT-HC+ww0}SZ#{Y4-}mARTd%o=x$Yu)7bn$qaA?<&{gNAA zTvVBJ4B?TKt=IHw9$VwTH$SE=gm$3BaZ*_{kp02$Me}`~_0Zhfke|}vVCyXL@iKMl z>_6sg)N|~=|88yM)D!0YhBu!A4%Qqvdp9vg;u#Fsj&?+n9$#0R z5YX$lS#z$ZA6Z&9a%eY!|-V52<2sal`ooNW&QRzc>!g zqdNU3bo=j|jUtd2aJ%uz5NvoS|iQM8)UX@a?Yn+QN{=vv(KS zQz*}6OpL|E*d_f5B5Ae@i&vhXDzAqquWcyLHI-M)qBL5+XdET$|Lk!>Ezg2nbKvX{ zeWUUUpe;&=Yh1a@?W)z_l$~0{f#(|m4%gD`%(MBI7{BfjI9%C=w26YVvyEnNhOeht zqV$%S6)D%x)t0jNkL(iev9?EC2PqwCV+I1Hbkgr)`$Z&#`$Y$YypQ=X*!%GWt~oFr z%#5Bx8g*N>H>GL23MDUqBkD)F7JjCzmG>8vYatFti_}`Y`_ZcMrINaAR?v;B9`OF@ zPntt(X^dpsO7`2K6^GZ%UGXtSLX6^oT8Ivh3PS;@M#s8^s&_BgCUdYrpz_x-73^MS z8Q5`7fwSx6(K-iD7OmwTW9`Ci-jS`co`eRl0(#{!;N(HM^~ut8M(xq55u!xFF}YhV z*^YAknDqYAIz@@L^4MijRDsKH^Yk?nWq@>QfRh&*oV?d{+54VbIVPu7A*ap3;g~Pu z!|E*-s2*~chvznsd;mD?=Vq;X|9VRI%RDC})95T-Jw@`sA_7a5kQ24Ur+#!a{IpqnYnda*3F_lB>t8RFnaZGT@gBLZS<#R^9XX z*2y!10}V70A!@BAT4y=^k(KrJGr_1+Rx$oeYAua-A|nFSeB$8hdef%H`{j_NNq%$< zG_ZgM`;R=@(63wbo(2u#w0==h33y*(=EdU``ow;MRZ#@~l*>Rl9c5{zJvk3yn4EoJ zv{C&B7V@~g?8#^3h}&`~X#WZ1hr7!tQROk;`;v0YGCHZm-DPAqND~oggCBa$b5E0} z@P^hpNE5T_1s&vaODvXb-S~NJS8!;fNJsyBe`79=GXF4tc?L-XX*YH~;?PE)y!XG_ zEnhY#aKx!29LdY!mn)?phyqi9< zRVBAyWY#3rY`b)hOB#=+c9gBEed{A$eirKw7}8lSIF0+{o9FL)bCE$B_Cg~A&@-Gb zQ!DF`gkeJ^j+7r0yQE^>CCVmR3jDEH3F zK3=(}&D2Hi=gyo>Sw6a^v?tEP_Gn(pJ#7-EUmVA$KZ&XT4eg2!sV9m&hqcsb(GE6?u{8xkc4_d80QQ55} zSEYpQ>;s2;1)q0U|8PXzI#6(6qu38-LspHb-K)s1F>|@j$2isSrfOF?KQpEsF5EMG zb54mP`H-~x^@g)6$~`*Vl|sL*T%yXOv<}_mcKSG1$wD~?mUDz|^vcMOa&0T`+?|Is zw#L}`$80S$PwGRO*hNszkMa(b@}7k9K2s3N+Y%b2-#b*+K)FPfbyJqMxVt<*oqzUV z#aCT{J!EA&P_`;%4;v6k z4}x!S>~M20n|f>kw04r;jSW->;$=y^?|L@sVZA)}`4$%XGPYBT0NL~HopJ8e&@C&L zf+NP{CBWf+R+qb99`_oZi|g^CHU7+wjq(X1<<_WNKPGxWvDB!%H&s#Or`(VOsk=&^ z;JUvUk1G3k<&z1@HK$xZ%6n7FIaSV&@_z8%KzX!2w5fZu`LBn6K~AwI#N}4yS@l`O zq30_-=jBIj4R?%P^tG*=A7vk}T%u{mmeOvLwD#nH@vs#%XkEd!%!cWm3mG&}-jOyb zP3nJ4uAE9c>1~{52{h8E28Yi06Kq?(&jm3vxs zygC4bJ5}F~9gB5;om>=UE#|?>J#Bl9+)i8d3)_BW&AR1?!@UCdQ9p1v|Ec)rwdXpk z7n{HlJ#8pBoSUUip8X_q$?kPor}7*<9-Qppobzh5=<(Q_oQaEZi1O*$0f-~b7dki= zOX}lw7;!it#VSE$ggROiu2yxZv8-E?rP&m4xX*-nqrxgEv`&Jwe9$1u`-IQ^4%+?( z4Z?9IIlv|;VpZ1$WpYlL$u(7>b(CLph)t+E;Sb%euV>rT;%<`gRVF!-S3Vpn`yG!0 z*QeIll}++H(3*3m5Dkr9bu@g;yZJ3&HWC^jKN=ls2%N=LJ6vj;_tANSZnMJV63y|j zL$Nw@NAp~#(7+~K?$JN{t3KBIW;GEUOe0u7%0BVm>-m)Djmkbzd9~%5V5gp6n5;MH+A{ zz`4A$+59_WLb^zCq_uTrKdL-VR9^E|_Abh2ww3)(0<`9;N1m5+Mt8Oe9tN%XA`NU* z*&`|0ful;{WHzLk*vk>`qvwl|TYdbf=pFf1Ytq@41XdbMyokJ|ix=z@A-50no5D4K7$7VZ*%D;-?ic9gn8AJ0{HY;jDElD&VD zZ^Pv^D%@QUjz}j;tB#J=sI~fU9m!w2V8NB?DYu2>ZJ8&1+u-+5)B@URHE`(TpWRvY ztXtEeF@l3yr~?kiiO28kh?+X)4cB3XSN79t`N0B}TU_4XtcEY4=c9$7L`|;8OS=dP zy&2Lm(VL0B(L`^?GC(^2#@-AXDD-CFDD-CN=ahT1sF?65)?A~tzhxdceS@E&MEmRH zzNCWLf=0bIxW5F4`H?g*xm$spn%rMNedEhxSmCtKl0V+V_Lpn-|};2TvegXqW@sYjpl{#d`A-Md$o z@*|Z&9Heo)qiR;?dcg(T_klwjMf-_}i~q`*95gWu5-pCg4c>80o*E(oc-5 zy2Z);LId;Fi=vZGj)c~tHKzYgNk94nXpnwiQ%VQrhIhUL;gq9FmzYwhSm`#SAg!9b zlBMkVOzwq32Ylxhx>=&E14nOcuemb&nJ8EH>_Hr9lu7#m~=7Gcd$^LEp zobJý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 I|I`2e4=z;+8~^|S diff --git a/deno/build.mjs b/deno-build.mjs similarity index 100% rename from deno/build.mjs rename to deno-build.mjs diff --git a/deno/lib/__tests__/coerce.test.ts b/deno/lib/__tests__/coerce.test.ts index 6acc5249b..fd3868225 100644 --- a/deno/lib/__tests__/coerce.test.ts +++ b/deno/lib/__tests__/coerce.test.ts @@ -35,21 +35,21 @@ test("number coercion", () => { expect(schema.parse("-12")).toEqual(-12); expect(schema.parse("3.14")).toEqual(3.14); expect(schema.parse("")).toEqual(0); - expect(() => schema.parse("NOT_A_NUMBER")).toThrow; // z.ZodError + expect(() => schema.parse("NOT_A_NUMBER")).toThrow(); // z.ZodError expect(schema.parse(12)).toEqual(12); expect(schema.parse(0)).toEqual(0); expect(schema.parse(-12)).toEqual(-12); expect(schema.parse(3.14)).toEqual(3.14); expect(schema.parse(BigInt(15))).toEqual(15); - expect(() => schema.parse(NaN)).toThrow; // z.ZodError + expect(() => schema.parse(NaN)).toThrow(); // z.ZodError expect(schema.parse(Infinity)).toEqual(Infinity); expect(schema.parse(-Infinity)).toEqual(-Infinity); expect(schema.parse(true)).toEqual(1); expect(schema.parse(false)).toEqual(0); expect(schema.parse(null)).toEqual(0); - expect(() => schema.parse(undefined)).toThrow; // z.ZodError - expect(() => schema.parse({ hello: "world!" })).toThrow; // z.ZodError - expect(() => schema.parse(["item", "another_item"])).toThrow; // z.ZodError + expect(() => schema.parse(undefined)).toThrow(); // z.ZodError + expect(() => schema.parse({ hello: "world!" })).toThrow(); // z.ZodError + expect(() => schema.parse(["item", "another_item"])).toThrow(); // z.ZodError expect(schema.parse([])).toEqual(0); expect(schema.parse(new Date(1670139203496))).toEqual(1670139203496); }); @@ -84,23 +84,23 @@ test("bigint coercion", () => { expect(schema.parse("5")).toEqual(BigInt(5)); expect(schema.parse("0")).toEqual(BigInt(0)); expect(schema.parse("-5")).toEqual(BigInt(-5)); - expect(() => schema.parse("3.14")).toThrow; // not a z.ZodError! + expect(() => schema.parse("3.14")).toThrow(); // not a z.ZodError! expect(schema.parse("")).toEqual(BigInt(0)); - expect(() => schema.parse("NOT_A_NUMBER")).toThrow; // not a z.ZodError! + expect(() => schema.parse("NOT_A_NUMBER")).toThrow(); // not a z.ZodError! expect(schema.parse(5)).toEqual(BigInt(5)); expect(schema.parse(0)).toEqual(BigInt(0)); expect(schema.parse(-5)).toEqual(BigInt(-5)); - expect(() => schema.parse(3.14)).toThrow; // not a z.ZodError! + expect(() => schema.parse(3.14)).toThrow(); // not a z.ZodError! expect(schema.parse(BigInt(5))).toEqual(BigInt(5)); - expect(() => schema.parse(NaN)).toThrow; // not a z.ZodError! - expect(() => schema.parse(Infinity)).toThrow; // not a z.ZodError! - expect(() => schema.parse(-Infinity)).toThrow; // not a z.ZodError! + expect(() => schema.parse(NaN)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(Infinity)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(-Infinity)).toThrow(); // not a z.ZodError! expect(schema.parse(true)).toEqual(BigInt(1)); expect(schema.parse(false)).toEqual(BigInt(0)); - expect(() => schema.parse(null)).toThrow; // not a z.ZodError! - expect(() => schema.parse(undefined)).toThrow; // not a z.ZodError! - expect(() => schema.parse({ hello: "world!" })).toThrow; // not a z.ZodError! - expect(() => schema.parse(["item", "another_item"])).toThrow; // not a z.ZodError! + expect(() => schema.parse(null)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(undefined)).toThrow(); // not a z.ZodError! + expect(() => schema.parse({ hello: "world!" })).toThrow(); // not a z.ZodError! + expect(() => schema.parse(["item", "another_item"])).toThrow(); // not a z.ZodError! expect(schema.parse([])).toEqual(BigInt(0)); expect(schema.parse(new Date(1670139203496))).toEqual(BigInt(1670139203496)); }); @@ -111,25 +111,26 @@ test("date coercion", () => { expect(schema.parse(new Date().toISOString())).toBeInstanceOf(Date); expect(schema.parse(new Date().toUTCString())).toBeInstanceOf(Date); expect(schema.parse("5")).toBeInstanceOf(Date); - expect(schema.parse("0")).toBeInstanceOf(Date); - expect(schema.parse("-5")).toBeInstanceOf(Date); - expect(schema.parse("3.14")).toBeInstanceOf(Date); - expect(() => schema.parse("")).toThrow; // z.ZodError - expect(() => schema.parse("NOT_A_DATE")).toThrow; // z.ZodError + expect(schema.parse("2000-01-01")).toBeInstanceOf(Date); + // expect(schema.parse("0")).toBeInstanceOf(Date); + // expect(schema.parse("-5")).toBeInstanceOf(Date); + // expect(schema.parse("3.14")).toBeInstanceOf(Date); + expect(() => schema.parse("")).toThrow(); // z.ZodError + expect(() => schema.parse("NOT_A_DATE")).toThrow(); // z.ZodError expect(schema.parse(5)).toBeInstanceOf(Date); expect(schema.parse(0)).toBeInstanceOf(Date); expect(schema.parse(-5)).toBeInstanceOf(Date); expect(schema.parse(3.14)).toBeInstanceOf(Date); - expect(() => schema.parse(BigInt(5))).toThrow; // not a z.ZodError! - expect(() => schema.parse(NaN)).toThrow; // z.ZodError - expect(() => schema.parse(Infinity)).toThrow; // z.ZodError - expect(() => schema.parse(-Infinity)).toThrow; // z.ZodError + expect(() => schema.parse(BigInt(5))).toThrow(); // not a z.ZodError! + expect(() => schema.parse(NaN)).toThrow(); // z.ZodError + expect(() => schema.parse(Infinity)).toThrow(); // z.ZodError + expect(() => schema.parse(-Infinity)).toThrow(); // z.ZodError expect(schema.parse(true)).toBeInstanceOf(Date); expect(schema.parse(false)).toBeInstanceOf(Date); expect(schema.parse(null)).toBeInstanceOf(Date); - expect(() => schema.parse(undefined)).toThrow; // z.ZodError - expect(() => schema.parse({ hello: "world!" })).toThrow; // z.ZodError - expect(() => schema.parse(["item", "another_item"])).toThrow; // z.ZodError - expect(() => schema.parse([])).toThrow; // z.ZodError + expect(() => schema.parse(undefined)).toThrow(); // z.ZodError + expect(() => schema.parse({ hello: "world!" })).toThrow(); // z.ZodError + expect(() => schema.parse(["item", "another_item"])).toThrow(); // z.ZodError + expect(() => schema.parse([])).toThrow(); // z.ZodError expect(schema.parse(new Date())).toBeInstanceOf(Date); }); diff --git a/deno/lib/__tests__/discriminatedUnions.test.ts b/deno/lib/__tests__/discriminated-unions.test.ts similarity index 100% rename from deno/lib/__tests__/discriminatedUnions.test.ts rename to deno/lib/__tests__/discriminated-unions.test.ts diff --git a/deno/lib/__tests__/language-server.source.ts b/deno/lib/__tests__/language-server.source.ts new file mode 100644 index 000000000..b0105556c --- /dev/null +++ b/deno/lib/__tests__/language-server.source.ts @@ -0,0 +1,76 @@ +import * as z from "../index.ts"; + +export const filePath = __filename; + +// z.object() + +export const Test = z.object({ + f1: z.number(), +}); + +export type Test = z.infer; + +export const instanceOfTest: Test = { + f1: 1, +}; + +// z.object().merge() + +export const TestMerge = z + .object({ + f2: z.string().optional(), + }) + .merge(Test); + +export type TestMerge = z.infer; + +export const instanceOfTestMerge: TestMerge = { + f1: 1, + f2: "string", +}; + +// z.union() + +export const TestUnion = z.union([ + z.object({ + f2: z.string().optional(), + }), + Test, +]); + +export type TestUnion = z.infer; + +export const instanceOfTestUnion: TestUnion = { + f1: 1, + f2: "string", +}; + +// z.object().partial() + +export const TestPartial = Test.partial(); + +export type TestPartial = z.infer; + +export const instanceOfTestPartial: TestPartial = { + f1: 1, +}; + +// z.object().pick() + +export const TestPick = TestMerge.pick({ f1: true }); + +export type TestPick = z.infer; + +export const instanceOfTestPick: TestPick = { + f1: 1, +}; + +// z.object().omit() + +export const TestOmit = TestMerge.omit({ f2: true }); + +export type TestOmit = z.infer; + +export const instanceOfTestOmit: TestOmit = { + f1: 1, +}; diff --git a/deno/lib/__tests__/language-server.test.ts b/deno/lib/__tests__/language-server.test.ts new file mode 100644 index 000000000..bc35d7370 --- /dev/null +++ b/deno/lib/__tests__/language-server.test.ts @@ -0,0 +1,209 @@ +// @ts-ignore TS6133 +import { expect } from "https://deno.land/x/expect@v0.2.6/mod.ts"; +const test = Deno.test; +// import path from "path"; +// import { Node, Project, SyntaxKind } from "ts-morph"; + +// import { filePath } from "./language-server.source"; + +// The following tool is helpful for understanding the TypeScript AST associated with these tests: +// https://ts-ast-viewer.com/ (just copy the contents of languageServerFeatures.source into the viewer) + +test("", () => {}); +// describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { +// // Compile file developmentEnvironment.source +// const project = new Project({ +// tsConfigFilePath: path.join(__dirname, "..", "..", "tsconfig.json"), +// skipAddingFilesFromTsConfig: true, +// }); +// const sourceFile = project.addSourceFileAtPath(filePath); + +// test("works for object properties inferred from z.object()", () => { +// // Find usage of Test.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTest"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of Test.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// // test("works for first object properties inferred from z.object().merge()", () => { +// // // Find usage of TestMerge.f1 property +// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// // "instanceOfTestMerge" +// // ); +// // const propertyBeingAssigned = getPropertyBeingAssigned( +// // instanceVariable, +// // "f1" +// // ); + +// // // Find definition of TestMerge.f1 property +// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// // SyntaxKind.VariableDeclaration +// // ); + +// // // Assert that find definition returned the Zod definition of Test +// // expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// // expect(parentOfProperty?.getName()).toEqual("Test"); +// // }); + +// // test("works for second object properties inferred from z.object().merge()", () => { +// // // Find usage of TestMerge.f2 property +// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// // "instanceOfTestMerge" +// // ); +// // const propertyBeingAssigned = getPropertyBeingAssigned( +// // instanceVariable, +// // "f2" +// // ); + +// // // Find definition of TestMerge.f2 property +// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// // SyntaxKind.VariableDeclaration +// // ); + +// // // Assert that find definition returned the Zod definition of TestMerge +// // expect(definitionOfProperty?.getText()).toEqual( +// // "f2: z.string().optional()" +// // ); +// // expect(parentOfProperty?.getName()).toEqual("TestMerge"); +// // }); + +// test("works for first object properties inferred from z.union()", () => { +// // Find usage of TestUnion.f1 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestUnion" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestUnion.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for second object properties inferred from z.union()", () => { +// // Find usage of TestUnion.f2 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestUnion" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f2" +// ); + +// // Find definition of TestUnion.f2 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of TestUnion +// expect(definitionOfProperty?.getText()).toEqual( +// "f2: z.string().optional()" +// ); +// expect(parentOfProperty?.getName()).toEqual("TestUnion"); +// }); + +// test("works for object properties inferred from z.object().partial()", () => { +// // Find usage of TestPartial.f1 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestPartial" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestPartial.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for object properties inferred from z.object().pick()", () => { +// // Find usage of TestPick.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTestPick"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestPick.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for object properties inferred from z.object().omit()", () => { +// // Find usage of TestOmit.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTestOmit"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestOmit.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); +// }); + +// const getPropertyBeingAssigned = (node: Node, name: string) => { +// const propertyAssignment = node.forEachDescendant((descendent) => +// Node.isPropertyAssignment(descendent) && descendent.getName() == name +// ? descendent +// : undefined +// ); + +// if (propertyAssignment == null) +// fail(`Could not find property assignment with name ${name}`); + +// const propertyLiteral = propertyAssignment.getFirstDescendantByKind( +// SyntaxKind.Identifier +// ); + +// if (propertyLiteral == null) +// fail(`Could not find property literal with name ${name}`); + +// return propertyLiteral; +// }; diff --git a/jest.config.json b/jest.config.json index 936e972f8..ad53fa77a 100644 --- a/jest.config.json +++ b/jest.config.json @@ -1,9 +1,7 @@ { "rootDir": ".", - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, "testRegex": "src/.*\\.test\\.ts$", + "modulePathIgnorePatterns": ["language-server"], "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], "coverageReporters": ["json-summary", "text", "lcov"] } diff --git a/package.json b/package.json index 13a3287b3..b84bba5d5 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,18 @@ "main": "./lib/index.js", "module": "./lib/index.mjs", "devDependencies": { + "@babel/core": "^7.22.5", + "@babel/preset-env": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", "@rollup/plugin-typescript": "^8.2.0", + "@swc/core": "^1.3.66", + "@swc/jest": "^0.2.26", "@types/benchmark": "^2.1.0", "@types/jest": "^29.2.2", "@types/node": "14", "@typescript-eslint/eslint-plugin": "^5.15.0", "@typescript-eslint/parser": "^5.15.0", + "babel-jest": "^29.5.0", "benchmark": "^2.1.4", "dependency-cruiser": "^9.19.0", "eslint": "^8.11.0", @@ -30,7 +36,7 @@ "prettier": "^2.6.0", "pretty-quick": "^3.1.3", "rollup": "^2.70.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.1.0", "ts-morph": "^14.0.0", "ts-node": "^10.9.1", "tslib": "^2.3.1", @@ -82,14 +88,18 @@ "fix": "yarn lint:fix && yarn prettier:fix", "clean": "rm -rf lib/* deno/lib/*", "build": "yarn run clean && npm run build:cjs && npm run build:esm && npm run build:deno", - "build:deno": "node ./deno/build.mjs && cp ./README.md ./deno/lib", + "build:deno": "node ./deno-build.mjs && cp ./README.md ./deno/lib", "build:esm": "rollup --config rollup.config.js", "build:cjs": "tsc -p tsconfig.cjs.json", "build:types": "tsc -p tsconfig.types.json", "build:test": "tsc -p tsconfig.test.json", "rollup": "rollup --config rollup.config.js", "test:watch": "jest --watch", - "test": "jest --coverage", + "test": "yarn test:tsc", + "test:babel": "jest --coverage", + "test:bun": "bun test", + "test:tsc": "jest --config ./ts-jest.config.json", + "test:swc": "jest --config ./swc-jest.config.json", "test:deno": "cd deno && deno test", "prepublishOnly": "npm run test && npm run build && npm run build:deno", "play": "nodemon -e ts -w . -x tsx playground.ts", diff --git a/playground.ts b/playground.ts index 2924dc9bf..b12a86fd6 100644 --- a/playground.ts +++ b/playground.ts @@ -1,130 +1,8 @@ import { z } from "./src"; z; -const validEmails = [ - `email@domain.com`, - `firstname.lastname@domain.com`, - `email@subdomain.domain.com`, - `firstname+lastname@domain.com`, - `1234567890@domain.com`, - `email@domain-one.com`, - `_______@domain.com`, - `email@domain.name`, - `email@domain.co.jp`, - `firstname-lastname@domain.com`, - `very.common@example.com`, - `disposable.style.email.with+symbol@example.com`, - `other.email-with-hyphen@example.com`, - `fully-qualified-domain@example.com`, - `user.name+tag+sorting@example.com`, - `x@example.com`, - `mojojojo@asdf.example.com`, - `example-indeed@strange-example.com`, - `example@s.example`, - `user-@example.org`, - `user@my-example.com`, - `a@b.cd`, - `work+user@mail.com`, - `tom@test.te-st.com`, - `something@subdomain.domain-with-hyphens.tld`, - `francois@etu.inp-n7.fr`, -]; -const invalidEmails = [ - // no "printable characters" - // `user%example.com@example.org`, - // `mailhost!username@example.org`, - // `test/test@test.com`, - - // double @ - `francois@@etu.inp-n7.fr`, - - // do not support quotes - `"email"@domain.com`, - `"e asdf sadf ?<>ail"@domain.com`, - `" "@example.org`, - `"john..doe"@example.org`, - `"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`, - - // do not support IPv4 - `email@123.123.123.123`, - `email@[123.123.123.123]`, - `postmaster@123.123.123.123`, - `user@[68.185.127.196]`, - `ipv4@[85.129.96.247]`, - `valid@[79.208.229.53]`, - `valid@[255.255.255.255]`, - `valid@[255.0.55.2]`, - `valid@[255.0.55.2]`, - - // do not support ipv6 - `hgrebert0@[IPv6:4dc8:ac7:ce79:8878:1290:6098:5c50:1f25]`, - `bshapiro4@[IPv6:3669:c709:e981:4884:59a3:75d1:166b:9ae]`, - `jsmith@[IPv6:2001:db8::1]`, - `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]`, - `postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:192.168.1.1]`, - - // microsoft test cases - `plainaddress`, - `#@%^%#$@#$@#.com`, - `@domain.com`, - `Joe Smith <email@domain.com>`, - `email.domain.com`, - `email@domain@domain.com`, - `.email@domain.com`, - `email.@domain.com`, - `email..email@domain.com`, - `あいうえお@domain.com`, - `email@domain.com (Joe Smith)`, - `email@domain`, - `email@-domain.com`, - `email@111.222.333.44444`, - `email@domain..com`, - `Abc.example.com`, - `A@b@c@example.com`, - `colin..hacks@domain.com`, - `a"b(c)d,e:f;gi[j\k]l@example.com`, - `just"not"right@example.com`, - `this is"not\allowed@example.com`, - `this\ still\"not\\allowed@example.com`, - - // random - `i_like_underscore@but_its_not_allowed_in_this_part.example.com`, - `QA[icon]CHOCOLATE[icon]@test.com`, - `invalid@-start.com`, - `invalid@end.com-`, - `a.b@c.d`, - `invalid@[1.1.1.-1]`, - `invalid@[68.185.127.196.55]`, - `temp@[192.168.1]`, - `temp@[9.18.122.]`, - `double..point@test.com`, - `asdad@test..com`, - `asdad@hghg...sd...au`, - `asdad@hghg........au`, - `invalid@[256.2.2.48]`, - `invalid@[256.2.2.48]`, - `invalid@[999.465.265.1]`, - `jkibbey4@[IPv6:82c4:19a8::70a9:2aac:557::ea69:d985:28d]`, - `mlivesay3@[9952:143f:b4df:2179:49a1:5e82:b92e:6b6]`, - `gbacher0@[IPv6:bc37:4d3f:5048:2e26:37cc:248e:df8e:2f7f:af]`, - `invalid@[IPv6:5348:4ed3:5d38:67fb:e9b:acd2:c13:192.168.256.1]`, -]; - -const emailSchema = z.string().email(); -console.log( - validEmails.every((email) => { - const val = emailSchema.safeParse(email).success; - if (!val) console.log(`fail`, email); - return val; - }) -); -// for (const email of validEmails) { -// console.log("good", email); -// emailSchema.parse(email); -// } -for (const email of invalidEmails) { - try { - emailSchema.parse(email); - console.log(`PASS`, email); - } catch (_) {} -} +const schema = z.coerce.date(); +// console.log(schema.parse("3.14")); +test("asdf", () => { + expect(schema.parse("3.14")).toBeInstanceOf(Date); +}); diff --git a/src/__tests__/coerce.test.ts b/src/__tests__/coerce.test.ts index 79d91d1fc..3a8b99c17 100644 --- a/src/__tests__/coerce.test.ts +++ b/src/__tests__/coerce.test.ts @@ -34,21 +34,21 @@ test("number coercion", () => { expect(schema.parse("-12")).toEqual(-12); expect(schema.parse("3.14")).toEqual(3.14); expect(schema.parse("")).toEqual(0); - expect(() => schema.parse("NOT_A_NUMBER")).toThrow; // z.ZodError + expect(() => schema.parse("NOT_A_NUMBER")).toThrow(); // z.ZodError expect(schema.parse(12)).toEqual(12); expect(schema.parse(0)).toEqual(0); expect(schema.parse(-12)).toEqual(-12); expect(schema.parse(3.14)).toEqual(3.14); expect(schema.parse(BigInt(15))).toEqual(15); - expect(() => schema.parse(NaN)).toThrow; // z.ZodError + expect(() => schema.parse(NaN)).toThrow(); // z.ZodError expect(schema.parse(Infinity)).toEqual(Infinity); expect(schema.parse(-Infinity)).toEqual(-Infinity); expect(schema.parse(true)).toEqual(1); expect(schema.parse(false)).toEqual(0); expect(schema.parse(null)).toEqual(0); - expect(() => schema.parse(undefined)).toThrow; // z.ZodError - expect(() => schema.parse({ hello: "world!" })).toThrow; // z.ZodError - expect(() => schema.parse(["item", "another_item"])).toThrow; // z.ZodError + expect(() => schema.parse(undefined)).toThrow(); // z.ZodError + expect(() => schema.parse({ hello: "world!" })).toThrow(); // z.ZodError + expect(() => schema.parse(["item", "another_item"])).toThrow(); // z.ZodError expect(schema.parse([])).toEqual(0); expect(schema.parse(new Date(1670139203496))).toEqual(1670139203496); }); @@ -83,23 +83,23 @@ test("bigint coercion", () => { expect(schema.parse("5")).toEqual(BigInt(5)); expect(schema.parse("0")).toEqual(BigInt(0)); expect(schema.parse("-5")).toEqual(BigInt(-5)); - expect(() => schema.parse("3.14")).toThrow; // not a z.ZodError! + expect(() => schema.parse("3.14")).toThrow(); // not a z.ZodError! expect(schema.parse("")).toEqual(BigInt(0)); - expect(() => schema.parse("NOT_A_NUMBER")).toThrow; // not a z.ZodError! + expect(() => schema.parse("NOT_A_NUMBER")).toThrow(); // not a z.ZodError! expect(schema.parse(5)).toEqual(BigInt(5)); expect(schema.parse(0)).toEqual(BigInt(0)); expect(schema.parse(-5)).toEqual(BigInt(-5)); - expect(() => schema.parse(3.14)).toThrow; // not a z.ZodError! + expect(() => schema.parse(3.14)).toThrow(); // not a z.ZodError! expect(schema.parse(BigInt(5))).toEqual(BigInt(5)); - expect(() => schema.parse(NaN)).toThrow; // not a z.ZodError! - expect(() => schema.parse(Infinity)).toThrow; // not a z.ZodError! - expect(() => schema.parse(-Infinity)).toThrow; // not a z.ZodError! + expect(() => schema.parse(NaN)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(Infinity)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(-Infinity)).toThrow(); // not a z.ZodError! expect(schema.parse(true)).toEqual(BigInt(1)); expect(schema.parse(false)).toEqual(BigInt(0)); - expect(() => schema.parse(null)).toThrow; // not a z.ZodError! - expect(() => schema.parse(undefined)).toThrow; // not a z.ZodError! - expect(() => schema.parse({ hello: "world!" })).toThrow; // not a z.ZodError! - expect(() => schema.parse(["item", "another_item"])).toThrow; // not a z.ZodError! + expect(() => schema.parse(null)).toThrow(); // not a z.ZodError! + expect(() => schema.parse(undefined)).toThrow(); // not a z.ZodError! + expect(() => schema.parse({ hello: "world!" })).toThrow(); // not a z.ZodError! + expect(() => schema.parse(["item", "another_item"])).toThrow(); // not a z.ZodError! expect(schema.parse([])).toEqual(BigInt(0)); expect(schema.parse(new Date(1670139203496))).toEqual(BigInt(1670139203496)); }); @@ -110,25 +110,26 @@ test("date coercion", () => { expect(schema.parse(new Date().toISOString())).toBeInstanceOf(Date); expect(schema.parse(new Date().toUTCString())).toBeInstanceOf(Date); expect(schema.parse("5")).toBeInstanceOf(Date); - expect(schema.parse("0")).toBeInstanceOf(Date); - expect(schema.parse("-5")).toBeInstanceOf(Date); - expect(schema.parse("3.14")).toBeInstanceOf(Date); - expect(() => schema.parse("")).toThrow; // z.ZodError - expect(() => schema.parse("NOT_A_DATE")).toThrow; // z.ZodError + expect(schema.parse("2000-01-01")).toBeInstanceOf(Date); + // expect(schema.parse("0")).toBeInstanceOf(Date); + // expect(schema.parse("-5")).toBeInstanceOf(Date); + // expect(schema.parse("3.14")).toBeInstanceOf(Date); + expect(() => schema.parse("")).toThrow(); // z.ZodError + expect(() => schema.parse("NOT_A_DATE")).toThrow(); // z.ZodError expect(schema.parse(5)).toBeInstanceOf(Date); expect(schema.parse(0)).toBeInstanceOf(Date); expect(schema.parse(-5)).toBeInstanceOf(Date); expect(schema.parse(3.14)).toBeInstanceOf(Date); - expect(() => schema.parse(BigInt(5))).toThrow; // not a z.ZodError! - expect(() => schema.parse(NaN)).toThrow; // z.ZodError - expect(() => schema.parse(Infinity)).toThrow; // z.ZodError - expect(() => schema.parse(-Infinity)).toThrow; // z.ZodError + expect(() => schema.parse(BigInt(5))).toThrow(); // not a z.ZodError! + expect(() => schema.parse(NaN)).toThrow(); // z.ZodError + expect(() => schema.parse(Infinity)).toThrow(); // z.ZodError + expect(() => schema.parse(-Infinity)).toThrow(); // z.ZodError expect(schema.parse(true)).toBeInstanceOf(Date); expect(schema.parse(false)).toBeInstanceOf(Date); expect(schema.parse(null)).toBeInstanceOf(Date); - expect(() => schema.parse(undefined)).toThrow; // z.ZodError - expect(() => schema.parse({ hello: "world!" })).toThrow; // z.ZodError - expect(() => schema.parse(["item", "another_item"])).toThrow; // z.ZodError - expect(() => schema.parse([])).toThrow; // z.ZodError + expect(() => schema.parse(undefined)).toThrow(); // z.ZodError + expect(() => schema.parse({ hello: "world!" })).toThrow(); // z.ZodError + expect(() => schema.parse(["item", "another_item"])).toThrow(); // z.ZodError + expect(() => schema.parse([])).toThrow(); // z.ZodError expect(schema.parse(new Date())).toBeInstanceOf(Date); }); diff --git a/src/__tests__/discriminatedUnions.test.ts b/src/__tests__/discriminated-unions.test.ts similarity index 100% rename from src/__tests__/discriminatedUnions.test.ts rename to src/__tests__/discriminated-unions.test.ts diff --git a/src/__tests__/languageServerFeatures.source.ts b/src/__tests__/language-server.source.ts similarity index 100% rename from src/__tests__/languageServerFeatures.source.ts rename to src/__tests__/language-server.source.ts diff --git a/src/__tests__/language-server.test.ts b/src/__tests__/language-server.test.ts new file mode 100644 index 000000000..05445e68a --- /dev/null +++ b/src/__tests__/language-server.test.ts @@ -0,0 +1,208 @@ +// @ts-ignore TS6133 +import { expect, test, describe } from "@jest/globals"; +// import path from "path"; +// import { Node, Project, SyntaxKind } from "ts-morph"; + +// import { filePath } from "./language-server.source"; + +// The following tool is helpful for understanding the TypeScript AST associated with these tests: +// https://ts-ast-viewer.com/ (just copy the contents of languageServerFeatures.source into the viewer) + +test("", () => {}); +// describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { +// // Compile file developmentEnvironment.source +// const project = new Project({ +// tsConfigFilePath: path.join(__dirname, "..", "..", "tsconfig.json"), +// skipAddingFilesFromTsConfig: true, +// }); +// const sourceFile = project.addSourceFileAtPath(filePath); + +// test("works for object properties inferred from z.object()", () => { +// // Find usage of Test.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTest"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of Test.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// // test("works for first object properties inferred from z.object().merge()", () => { +// // // Find usage of TestMerge.f1 property +// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// // "instanceOfTestMerge" +// // ); +// // const propertyBeingAssigned = getPropertyBeingAssigned( +// // instanceVariable, +// // "f1" +// // ); + +// // // Find definition of TestMerge.f1 property +// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// // SyntaxKind.VariableDeclaration +// // ); + +// // // Assert that find definition returned the Zod definition of Test +// // expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// // expect(parentOfProperty?.getName()).toEqual("Test"); +// // }); + +// // test("works for second object properties inferred from z.object().merge()", () => { +// // // Find usage of TestMerge.f2 property +// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// // "instanceOfTestMerge" +// // ); +// // const propertyBeingAssigned = getPropertyBeingAssigned( +// // instanceVariable, +// // "f2" +// // ); + +// // // Find definition of TestMerge.f2 property +// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// // SyntaxKind.VariableDeclaration +// // ); + +// // // Assert that find definition returned the Zod definition of TestMerge +// // expect(definitionOfProperty?.getText()).toEqual( +// // "f2: z.string().optional()" +// // ); +// // expect(parentOfProperty?.getName()).toEqual("TestMerge"); +// // }); + +// test("works for first object properties inferred from z.union()", () => { +// // Find usage of TestUnion.f1 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestUnion" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestUnion.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for second object properties inferred from z.union()", () => { +// // Find usage of TestUnion.f2 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestUnion" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f2" +// ); + +// // Find definition of TestUnion.f2 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of TestUnion +// expect(definitionOfProperty?.getText()).toEqual( +// "f2: z.string().optional()" +// ); +// expect(parentOfProperty?.getName()).toEqual("TestUnion"); +// }); + +// test("works for object properties inferred from z.object().partial()", () => { +// // Find usage of TestPartial.f1 property +// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( +// "instanceOfTestPartial" +// ); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestPartial.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for object properties inferred from z.object().pick()", () => { +// // Find usage of TestPick.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTestPick"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestPick.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); + +// test("works for object properties inferred from z.object().omit()", () => { +// // Find usage of TestOmit.f1 property +// const instanceVariable = +// sourceFile.getVariableDeclarationOrThrow("instanceOfTestOmit"); +// const propertyBeingAssigned = getPropertyBeingAssigned( +// instanceVariable, +// "f1" +// ); + +// // Find definition of TestOmit.f1 property +// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; +// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( +// SyntaxKind.VariableDeclaration +// ); + +// // Assert that find definition returned the Zod definition of Test +// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); +// expect(parentOfProperty?.getName()).toEqual("Test"); +// }); +// }); + +// const getPropertyBeingAssigned = (node: Node, name: string) => { +// const propertyAssignment = node.forEachDescendant((descendent) => +// Node.isPropertyAssignment(descendent) && descendent.getName() == name +// ? descendent +// : undefined +// ); + +// if (propertyAssignment == null) +// fail(`Could not find property assignment with name ${name}`); + +// const propertyLiteral = propertyAssignment.getFirstDescendantByKind( +// SyntaxKind.Identifier +// ); + +// if (propertyLiteral == null) +// fail(`Could not find property literal with name ${name}`); + +// return propertyLiteral; +// }; diff --git a/src/__tests__/languageServerFeatures.test.ts b/src/__tests__/languageServerFeatures.test.ts deleted file mode 100644 index 499d25d3f..000000000 --- a/src/__tests__/languageServerFeatures.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -// @ts-ignore TS6133 -import { expect, fit } from "@jest/globals"; -import path from "path"; -import { Node, Project, SyntaxKind } from "ts-morph"; - -import { filePath } from "./languageServerFeatures.source"; - -// The following tool is helpful for understanding the TypeScript AST associated with these tests: -// https://ts-ast-viewer.com/ (just copy the contents of languageServerFeatures.source into the viewer) - -describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { - // Compile file developmentEnvironment.source - const project = new Project({ - tsConfigFilePath: path.join(__dirname, "..", "..", "tsconfig.json"), - skipAddingFilesFromTsConfig: true, - }); - const sourceFile = project.addSourceFileAtPath(filePath); - - test("works for object properties inferred from z.object()", () => { - // Find usage of Test.f1 property - const instanceVariable = - sourceFile.getVariableDeclarationOrThrow("instanceOfTest"); - const propertyBeingAssigned = getPropertyBeingAssigned( - instanceVariable, - "f1" - ); - - // Find definition of Test.f1 property - const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - SyntaxKind.VariableDeclaration - ); - - // Assert that find definition returned the Zod definition of Test - expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); - expect(parentOfProperty?.getName()).toEqual("Test"); - }); - - // test("works for first object properties inferred from z.object().merge()", () => { - // // Find usage of TestMerge.f1 property - // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( - // "instanceOfTestMerge" - // ); - // const propertyBeingAssigned = getPropertyBeingAssigned( - // instanceVariable, - // "f1" - // ); - - // // Find definition of TestMerge.f1 property - // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - // SyntaxKind.VariableDeclaration - // ); - - // // Assert that find definition returned the Zod definition of Test - // expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); - // expect(parentOfProperty?.getName()).toEqual("Test"); - // }); - - // test("works for second object properties inferred from z.object().merge()", () => { - // // Find usage of TestMerge.f2 property - // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( - // "instanceOfTestMerge" - // ); - // const propertyBeingAssigned = getPropertyBeingAssigned( - // instanceVariable, - // "f2" - // ); - - // // Find definition of TestMerge.f2 property - // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - // SyntaxKind.VariableDeclaration - // ); - - // // Assert that find definition returned the Zod definition of TestMerge - // expect(definitionOfProperty?.getText()).toEqual( - // "f2: z.string().optional()" - // ); - // expect(parentOfProperty?.getName()).toEqual("TestMerge"); - // }); - - test("works for first object properties inferred from z.union()", () => { - // Find usage of TestUnion.f1 property - const instanceVariable = sourceFile.getVariableDeclarationOrThrow( - "instanceOfTestUnion" - ); - const propertyBeingAssigned = getPropertyBeingAssigned( - instanceVariable, - "f1" - ); - - // Find definition of TestUnion.f1 property - const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - SyntaxKind.VariableDeclaration - ); - - // Assert that find definition returned the Zod definition of Test - expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); - expect(parentOfProperty?.getName()).toEqual("Test"); - }); - - test("works for second object properties inferred from z.union()", () => { - // Find usage of TestUnion.f2 property - const instanceVariable = sourceFile.getVariableDeclarationOrThrow( - "instanceOfTestUnion" - ); - const propertyBeingAssigned = getPropertyBeingAssigned( - instanceVariable, - "f2" - ); - - // Find definition of TestUnion.f2 property - const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - SyntaxKind.VariableDeclaration - ); - - // Assert that find definition returned the Zod definition of TestUnion - expect(definitionOfProperty?.getText()).toEqual( - "f2: z.string().optional()" - ); - expect(parentOfProperty?.getName()).toEqual("TestUnion"); - }); - - test("works for object properties inferred from z.object().partial()", () => { - // Find usage of TestPartial.f1 property - const instanceVariable = sourceFile.getVariableDeclarationOrThrow( - "instanceOfTestPartial" - ); - const propertyBeingAssigned = getPropertyBeingAssigned( - instanceVariable, - "f1" - ); - - // Find definition of TestPartial.f1 property - const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - SyntaxKind.VariableDeclaration - ); - - // Assert that find definition returned the Zod definition of Test - expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); - expect(parentOfProperty?.getName()).toEqual("Test"); - }); - - test("works for object properties inferred from z.object().pick()", () => { - // Find usage of TestPick.f1 property - const instanceVariable = - sourceFile.getVariableDeclarationOrThrow("instanceOfTestPick"); - const propertyBeingAssigned = getPropertyBeingAssigned( - instanceVariable, - "f1" - ); - - // Find definition of TestPick.f1 property - const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - SyntaxKind.VariableDeclaration - ); - - // Assert that find definition returned the Zod definition of Test - expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); - expect(parentOfProperty?.getName()).toEqual("Test"); - }); - - test("works for object properties inferred from z.object().omit()", () => { - // Find usage of TestOmit.f1 property - const instanceVariable = - sourceFile.getVariableDeclarationOrThrow("instanceOfTestOmit"); - const propertyBeingAssigned = getPropertyBeingAssigned( - instanceVariable, - "f1" - ); - - // Find definition of TestOmit.f1 property - const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; - const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( - SyntaxKind.VariableDeclaration - ); - - // Assert that find definition returned the Zod definition of Test - expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); - expect(parentOfProperty?.getName()).toEqual("Test"); - }); -}); - -const getPropertyBeingAssigned = (node: Node, name: string) => { - const propertyAssignment = node.forEachDescendant((descendent) => - Node.isPropertyAssignment(descendent) && descendent.getName() == name - ? descendent - : undefined - ); - - if (propertyAssignment == null) - fail(`Could not find property assignment with name ${name}`); - - const propertyLiteral = propertyAssignment.getFirstDescendantByKind( - SyntaxKind.Identifier - ); - - if (propertyLiteral == null) - fail(`Could not find property literal with name ${name}`); - - return propertyLiteral; -}; diff --git a/swc-jest.config.json b/swc-jest.config.json new file mode 100644 index 000000000..7e2aeec21 --- /dev/null +++ b/swc-jest.config.json @@ -0,0 +1,10 @@ +{ + "rootDir": ".", + "transform": { + "^.+\\.(t|j)sx?$": "@swc/jest" + }, + "testRegex": "src/.*\\.test\\.ts$", + "modulePathIgnorePatterns": ["language-server"], + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], + "coverageReporters": ["json-summary", "text", "lcov"] +} diff --git a/ts-jest.config.json b/ts-jest.config.json new file mode 100644 index 000000000..0d8700cfe --- /dev/null +++ b/ts-jest.config.json @@ -0,0 +1,10 @@ +{ + "rootDir": ".", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testRegex": "src/.*\\.test\\.ts$", + "modulePathIgnorePatterns": ["language-server"], + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], + "coverageReporters": ["json-summary", "text", "lcov"] +} From 6309322a28545e316299f8b9a36f43132d347300 Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 23 Jun 2023 12:06:50 -0700 Subject: [PATCH 07/22] Update test runners --- jest.config.json | 2 +- package.json | 8 +++++--- swc-jest.config.json | 2 +- ts-jest.config.json | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/jest.config.json b/jest.config.json index ad53fa77a..3b0e10956 100644 --- a/jest.config.json +++ b/jest.config.json @@ -1,7 +1,7 @@ { "rootDir": ".", "testRegex": "src/.*\\.test\\.ts$", - "modulePathIgnorePatterns": ["language-server"], + "modulePathIgnorePatterns": ["language-server", "__vitest__"], "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], "coverageReporters": ["json-summary", "text", "lcov"] } diff --git a/package.json b/package.json index b84bba5d5..83a4e07a4 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "ts-node": "^10.9.1", "tslib": "^2.3.1", "tsx": "^3.8.0", - "typescript": "~4.5.0" + "typescript": "~4.5.0", + "vitest": "^0.32.2" }, "exports": { ".": { @@ -98,8 +99,9 @@ "test": "yarn test:tsc", "test:babel": "jest --coverage", "test:bun": "bun test", - "test:tsc": "jest --config ./ts-jest.config.json", - "test:swc": "jest --config ./swc-jest.config.json", + "test:vitest": "npx vitest --no-isolate", + "test:ts-jest": "npx jest --config ./ts-jest.config.json", + "test:swc": "npx jest --config ./swc-jest.config.json", "test:deno": "cd deno && deno test", "prepublishOnly": "npm run test && npm run build && npm run build:deno", "play": "nodemon -e ts -w . -x tsx playground.ts", diff --git a/swc-jest.config.json b/swc-jest.config.json index 7e2aeec21..516809441 100644 --- a/swc-jest.config.json +++ b/swc-jest.config.json @@ -4,7 +4,7 @@ "^.+\\.(t|j)sx?$": "@swc/jest" }, "testRegex": "src/.*\\.test\\.ts$", - "modulePathIgnorePatterns": ["language-server"], + "modulePathIgnorePatterns": ["language-server", "__vitest__"], "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], "coverageReporters": ["json-summary", "text", "lcov"] } diff --git a/ts-jest.config.json b/ts-jest.config.json index 0d8700cfe..8051d1085 100644 --- a/ts-jest.config.json +++ b/ts-jest.config.json @@ -4,7 +4,7 @@ "^.+\\.tsx?$": "ts-jest" }, "testRegex": "src/.*\\.test\\.ts$", - "modulePathIgnorePatterns": ["language-server"], + "modulePathIgnorePatterns": ["language-server", "__vitest__"], "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], "coverageReporters": ["json-summary", "text", "lcov"] } From c0aece1672d1442d69ce1991142af8f16ed20ecb Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 23 Jun 2023 12:06:59 -0700 Subject: [PATCH 08/22] Add vitest config --- vitest.config.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 vitest.config.ts diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 000000000..581e75fb1 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + alias: { + "@jest/globals": "vitest", + }, + include: ["**/*.test.ts"], + isolate: false, + watch: false, + }, +}); From 73a5610186c413872153e8dcac76c4c4f23dfe4e Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 23 Jun 2023 12:07:49 -0700 Subject: [PATCH 09/22] Update script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 83a4e07a4..7bf7f60d5 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "build:test": "tsc -p tsconfig.test.json", "rollup": "rollup --config rollup.config.js", "test:watch": "jest --watch", - "test": "yarn test:tsc", + "test": "yarn test:ts-jest", "test:babel": "jest --coverage", "test:bun": "bun test", "test:vitest": "npx vitest --no-isolate", From 8d8e1a2d306cecaf3d8cb88f32fe3e130a834f9f Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 23 Jun 2023 12:24:13 -0700 Subject: [PATCH 10/22] Fix deno test bug --- deno-build.mjs | 4 ++-- src/__tests__/language-server.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deno-build.mjs b/deno-build.mjs index dfb4ac192..9e0b39a9d 100644 --- a/deno-build.mjs +++ b/deno-build.mjs @@ -25,8 +25,8 @@ const denoLibRoot = join(projectRoot, "deno", "lib"); const skipList = [ join(nodeSrcRoot, "__tests__", "object-in-es5-env.test.ts"), - join(nodeSrcRoot, "__tests__", "languageServerFeatures.test.ts"), - join(nodeSrcRoot, "__tests__", "languageServerFeatures.source.ts"), + join(nodeSrcRoot, "__tests__", "language-server.test.ts"), + join(nodeSrcRoot, "__tests__", "language-server.source.ts"), ]; const walkAndBuild = (/** @type string */ dir) => { for (const entry of readdirSync(join(nodeSrcRoot, dir), { diff --git a/src/__tests__/language-server.test.ts b/src/__tests__/language-server.test.ts index 05445e68a..88767b4ab 100644 --- a/src/__tests__/language-server.test.ts +++ b/src/__tests__/language-server.test.ts @@ -6,7 +6,7 @@ import { expect, test, describe } from "@jest/globals"; // import { filePath } from "./language-server.source"; // The following tool is helpful for understanding the TypeScript AST associated with these tests: -// https://ts-ast-viewer.com/ (just copy the contents of languageServerFeatures.source into the viewer) +// https://ts-ast-viewer.com/ (just copy the contents of language-server.source into the viewer) test("", () => {}); // describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { From 9eb2508fac78cc36faefd050e9616bb6d34814c1 Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 23 Jun 2023 13:20:23 -0700 Subject: [PATCH 11/22] Clean up configs --- configs/babel-jest.config.json | 10 + babel.config.js => configs/babel.config.js | 0 jest.config.json => configs/jest.config.json | 5 +- rollup.config.js => configs/rollup.config.js | 2 +- .../swc-jest.config.json | 2 +- .../ts-jest.config.json | 2 +- .../tsconfig.base.json | 16 +- .../tsconfig.cjs.json | 9 +- .../tsconfig.esm.json | 5 +- .../tsconfig.test.json | 3 +- .../tsconfig.types.json | 7 +- vitest.config.ts => configs/vitest.config.ts | 2 +- deno/lib/__tests__/language-server.source.ts | 76 ------- deno/lib/__tests__/language-server.test.ts | 209 ------------------ package.json | 19 +- src/__tests__/language-server.test.ts | 2 +- tsconfig.json | 2 +- 17 files changed, 40 insertions(+), 331 deletions(-) create mode 100644 configs/babel-jest.config.json rename babel.config.js => configs/babel.config.js (100%) rename jest.config.json => configs/jest.config.json (76%) rename rollup.config.js => configs/rollup.config.js (91%) rename swc-jest.config.json => configs/swc-jest.config.json (93%) rename ts-jest.config.json => configs/ts-jest.config.json (93%) rename tsconfig.base.json => configs/tsconfig.base.json (73%) rename tsconfig.cjs.json => configs/tsconfig.cjs.json (69%) rename tsconfig.esm.json => configs/tsconfig.esm.json (73%) rename tsconfig.test.json => configs/tsconfig.test.json (83%) rename tsconfig.types.json => configs/tsconfig.types.json (60%) rename vitest.config.ts => configs/vitest.config.ts (84%) delete mode 100644 deno/lib/__tests__/language-server.source.ts delete mode 100644 deno/lib/__tests__/language-server.test.ts diff --git a/configs/babel-jest.config.json b/configs/babel-jest.config.json new file mode 100644 index 000000000..f46b627de --- /dev/null +++ b/configs/babel-jest.config.json @@ -0,0 +1,10 @@ +{ + "rootDir": "..", + "testRegex": "src/.*\\.test\\.ts$", + "transform": { + "^.+\\.tsx?$": ["babel-jest", { "configFile": "./configs/babel.config.js" }] + }, + "modulePathIgnorePatterns": ["language-server", "__vitest__"], + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], + "coverageReporters": ["json-summary", "text", "lcov"] +} diff --git a/babel.config.js b/configs/babel.config.js similarity index 100% rename from babel.config.js rename to configs/babel.config.js diff --git a/jest.config.json b/configs/jest.config.json similarity index 76% rename from jest.config.json rename to configs/jest.config.json index 3b0e10956..096278dcf 100644 --- a/jest.config.json +++ b/configs/jest.config.json @@ -1,5 +1,8 @@ { - "rootDir": ".", + "rootDir": "..", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, "testRegex": "src/.*\\.test\\.ts$", "modulePathIgnorePatterns": ["language-server", "__vitest__"], "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], diff --git a/rollup.config.js b/configs/rollup.config.js similarity index 91% rename from rollup.config.js rename to configs/rollup.config.js index 1ccb37057..8f2090d33 100644 --- a/rollup.config.js +++ b/configs/rollup.config.js @@ -21,7 +21,7 @@ export default [ ], plugins: [ typescript({ - tsconfig: "tsconfig.esm.json", + tsconfig: "./configs/tsconfig.esm.json", sourceMap: false, }), ], diff --git a/swc-jest.config.json b/configs/swc-jest.config.json similarity index 93% rename from swc-jest.config.json rename to configs/swc-jest.config.json index 516809441..dd44db1f8 100644 --- a/swc-jest.config.json +++ b/configs/swc-jest.config.json @@ -1,5 +1,5 @@ { - "rootDir": ".", + "rootDir": "..", "transform": { "^.+\\.(t|j)sx?$": "@swc/jest" }, diff --git a/ts-jest.config.json b/configs/ts-jest.config.json similarity index 93% rename from ts-jest.config.json rename to configs/ts-jest.config.json index 8051d1085..096278dcf 100644 --- a/ts-jest.config.json +++ b/configs/ts-jest.config.json @@ -1,5 +1,5 @@ { - "rootDir": ".", + "rootDir": "..", "transform": { "^.+\\.tsx?$": "ts-jest" }, diff --git a/tsconfig.base.json b/configs/tsconfig.base.json similarity index 73% rename from tsconfig.base.json rename to configs/tsconfig.base.json index 374e5ad04..073703ed4 100644 --- a/tsconfig.base.json +++ b/configs/tsconfig.base.json @@ -1,12 +1,6 @@ { "compilerOptions": { - "lib": [ - "es5", - "es6", - "es7", - "esnext", - "dom" - ], + "lib": ["es5", "es6", "es7", "esnext", "dom"], "target": "es2018", "removeComments": false, "esModuleInterop": true, @@ -22,9 +16,5 @@ "downlevelIteration": true, "isolatedModules": true }, - "include": [ - "./src/**/*", - "playground.ts", - "./.eslintrc.js" - ] -} \ No newline at end of file + "include": ["../src/**/*", "../playground.ts", "../.eslintrc.js"] +} diff --git a/tsconfig.cjs.json b/configs/tsconfig.cjs.json similarity index 69% rename from tsconfig.cjs.json rename to configs/tsconfig.cjs.json index 9a393fdf8..32729f179 100644 --- a/tsconfig.cjs.json +++ b/configs/tsconfig.cjs.json @@ -2,14 +2,11 @@ "extends": "./tsconfig.base.json", "compilerOptions": { "module": "commonjs", - "outDir": "lib", + "outDir": "../lib", "declaration": true, "declarationMap": false, "sourceMap": false, "removeComments": true }, - "exclude": [ - "./src/**/__tests__", - "playground.ts" - ] -} \ No newline at end of file + "exclude": ["../src/**/__tests__", "../playground.ts"] +} diff --git a/tsconfig.esm.json b/configs/tsconfig.esm.json similarity index 73% rename from tsconfig.esm.json rename to configs/tsconfig.esm.json index 6d2fc8ef1..b5c23f25a 100644 --- a/tsconfig.esm.json +++ b/configs/tsconfig.esm.json @@ -7,8 +7,5 @@ "declarationMap": false, "sourceMap": false }, - "exclude": [ - "./src/**/__tests__", - "./src/playground.ts" - ] + "exclude": ["../src/**/__tests__", "../src/playground.ts"] } diff --git a/tsconfig.test.json b/configs/tsconfig.test.json similarity index 83% rename from tsconfig.test.json rename to configs/tsconfig.test.json index 625604ecc..1a9fe2c6d 100644 --- a/tsconfig.test.json +++ b/configs/tsconfig.test.json @@ -6,7 +6,8 @@ "target": "es5", "declaration": true, "declarationMap": false, - "sourceMap": false + "sourceMap": false, + "noEmit": true }, "exclude": [] } diff --git a/tsconfig.types.json b/configs/tsconfig.types.json similarity index 60% rename from tsconfig.types.json rename to configs/tsconfig.types.json index ff811649d..83aec7b76 100644 --- a/tsconfig.types.json +++ b/configs/tsconfig.types.json @@ -1,13 +1,10 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "outDir": "./lib/types", + "outDir": "../lib/types", "declaration": true, "declarationMap": true, "emitDeclarationOnly": true }, - "exclude": [ - "./src/**/__tests__", - "./src/playground.ts" - ] + "exclude": ["../src/**/__tests__", "../src/playground.ts"] } diff --git a/vitest.config.ts b/configs/vitest.config.ts similarity index 84% rename from vitest.config.ts rename to configs/vitest.config.ts index 581e75fb1..a9671f849 100644 --- a/vitest.config.ts +++ b/configs/vitest.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ alias: { "@jest/globals": "vitest", }, - include: ["**/*.test.ts"], + include: ["src/**/*.test.ts"], isolate: false, watch: false, }, diff --git a/deno/lib/__tests__/language-server.source.ts b/deno/lib/__tests__/language-server.source.ts deleted file mode 100644 index b0105556c..000000000 --- a/deno/lib/__tests__/language-server.source.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as z from "../index.ts"; - -export const filePath = __filename; - -// z.object() - -export const Test = z.object({ - f1: z.number(), -}); - -export type Test = z.infer; - -export const instanceOfTest: Test = { - f1: 1, -}; - -// z.object().merge() - -export const TestMerge = z - .object({ - f2: z.string().optional(), - }) - .merge(Test); - -export type TestMerge = z.infer; - -export const instanceOfTestMerge: TestMerge = { - f1: 1, - f2: "string", -}; - -// z.union() - -export const TestUnion = z.union([ - z.object({ - f2: z.string().optional(), - }), - Test, -]); - -export type TestUnion = z.infer; - -export const instanceOfTestUnion: TestUnion = { - f1: 1, - f2: "string", -}; - -// z.object().partial() - -export const TestPartial = Test.partial(); - -export type TestPartial = z.infer; - -export const instanceOfTestPartial: TestPartial = { - f1: 1, -}; - -// z.object().pick() - -export const TestPick = TestMerge.pick({ f1: true }); - -export type TestPick = z.infer; - -export const instanceOfTestPick: TestPick = { - f1: 1, -}; - -// z.object().omit() - -export const TestOmit = TestMerge.omit({ f2: true }); - -export type TestOmit = z.infer; - -export const instanceOfTestOmit: TestOmit = { - f1: 1, -}; diff --git a/deno/lib/__tests__/language-server.test.ts b/deno/lib/__tests__/language-server.test.ts deleted file mode 100644 index bc35d7370..000000000 --- a/deno/lib/__tests__/language-server.test.ts +++ /dev/null @@ -1,209 +0,0 @@ -// @ts-ignore TS6133 -import { expect } from "https://deno.land/x/expect@v0.2.6/mod.ts"; -const test = Deno.test; -// import path from "path"; -// import { Node, Project, SyntaxKind } from "ts-morph"; - -// import { filePath } from "./language-server.source"; - -// The following tool is helpful for understanding the TypeScript AST associated with these tests: -// https://ts-ast-viewer.com/ (just copy the contents of languageServerFeatures.source into the viewer) - -test("", () => {}); -// describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { -// // Compile file developmentEnvironment.source -// const project = new Project({ -// tsConfigFilePath: path.join(__dirname, "..", "..", "tsconfig.json"), -// skipAddingFilesFromTsConfig: true, -// }); -// const sourceFile = project.addSourceFileAtPath(filePath); - -// test("works for object properties inferred from z.object()", () => { -// // Find usage of Test.f1 property -// const instanceVariable = -// sourceFile.getVariableDeclarationOrThrow("instanceOfTest"); -// const propertyBeingAssigned = getPropertyBeingAssigned( -// instanceVariable, -// "f1" -// ); - -// // Find definition of Test.f1 property -// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// SyntaxKind.VariableDeclaration -// ); - -// // Assert that find definition returned the Zod definition of Test -// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); -// expect(parentOfProperty?.getName()).toEqual("Test"); -// }); - -// // test("works for first object properties inferred from z.object().merge()", () => { -// // // Find usage of TestMerge.f1 property -// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( -// // "instanceOfTestMerge" -// // ); -// // const propertyBeingAssigned = getPropertyBeingAssigned( -// // instanceVariable, -// // "f1" -// // ); - -// // // Find definition of TestMerge.f1 property -// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// // SyntaxKind.VariableDeclaration -// // ); - -// // // Assert that find definition returned the Zod definition of Test -// // expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); -// // expect(parentOfProperty?.getName()).toEqual("Test"); -// // }); - -// // test("works for second object properties inferred from z.object().merge()", () => { -// // // Find usage of TestMerge.f2 property -// // const instanceVariable = sourceFile.getVariableDeclarationOrThrow( -// // "instanceOfTestMerge" -// // ); -// // const propertyBeingAssigned = getPropertyBeingAssigned( -// // instanceVariable, -// // "f2" -// // ); - -// // // Find definition of TestMerge.f2 property -// // const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// // const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// // SyntaxKind.VariableDeclaration -// // ); - -// // // Assert that find definition returned the Zod definition of TestMerge -// // expect(definitionOfProperty?.getText()).toEqual( -// // "f2: z.string().optional()" -// // ); -// // expect(parentOfProperty?.getName()).toEqual("TestMerge"); -// // }); - -// test("works for first object properties inferred from z.union()", () => { -// // Find usage of TestUnion.f1 property -// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( -// "instanceOfTestUnion" -// ); -// const propertyBeingAssigned = getPropertyBeingAssigned( -// instanceVariable, -// "f1" -// ); - -// // Find definition of TestUnion.f1 property -// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// SyntaxKind.VariableDeclaration -// ); - -// // Assert that find definition returned the Zod definition of Test -// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); -// expect(parentOfProperty?.getName()).toEqual("Test"); -// }); - -// test("works for second object properties inferred from z.union()", () => { -// // Find usage of TestUnion.f2 property -// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( -// "instanceOfTestUnion" -// ); -// const propertyBeingAssigned = getPropertyBeingAssigned( -// instanceVariable, -// "f2" -// ); - -// // Find definition of TestUnion.f2 property -// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// SyntaxKind.VariableDeclaration -// ); - -// // Assert that find definition returned the Zod definition of TestUnion -// expect(definitionOfProperty?.getText()).toEqual( -// "f2: z.string().optional()" -// ); -// expect(parentOfProperty?.getName()).toEqual("TestUnion"); -// }); - -// test("works for object properties inferred from z.object().partial()", () => { -// // Find usage of TestPartial.f1 property -// const instanceVariable = sourceFile.getVariableDeclarationOrThrow( -// "instanceOfTestPartial" -// ); -// const propertyBeingAssigned = getPropertyBeingAssigned( -// instanceVariable, -// "f1" -// ); - -// // Find definition of TestPartial.f1 property -// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// SyntaxKind.VariableDeclaration -// ); - -// // Assert that find definition returned the Zod definition of Test -// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); -// expect(parentOfProperty?.getName()).toEqual("Test"); -// }); - -// test("works for object properties inferred from z.object().pick()", () => { -// // Find usage of TestPick.f1 property -// const instanceVariable = -// sourceFile.getVariableDeclarationOrThrow("instanceOfTestPick"); -// const propertyBeingAssigned = getPropertyBeingAssigned( -// instanceVariable, -// "f1" -// ); - -// // Find definition of TestPick.f1 property -// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// SyntaxKind.VariableDeclaration -// ); - -// // Assert that find definition returned the Zod definition of Test -// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); -// expect(parentOfProperty?.getName()).toEqual("Test"); -// }); - -// test("works for object properties inferred from z.object().omit()", () => { -// // Find usage of TestOmit.f1 property -// const instanceVariable = -// sourceFile.getVariableDeclarationOrThrow("instanceOfTestOmit"); -// const propertyBeingAssigned = getPropertyBeingAssigned( -// instanceVariable, -// "f1" -// ); - -// // Find definition of TestOmit.f1 property -// const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; -// const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( -// SyntaxKind.VariableDeclaration -// ); - -// // Assert that find definition returned the Zod definition of Test -// expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); -// expect(parentOfProperty?.getName()).toEqual("Test"); -// }); -// }); - -// const getPropertyBeingAssigned = (node: Node, name: string) => { -// const propertyAssignment = node.forEachDescendant((descendent) => -// Node.isPropertyAssignment(descendent) && descendent.getName() == name -// ? descendent -// : undefined -// ); - -// if (propertyAssignment == null) -// fail(`Could not find property assignment with name ${name}`); - -// const propertyLiteral = propertyAssignment.getFirstDescendantByKind( -// SyntaxKind.Identifier -// ); - -// if (propertyLiteral == null) -// fail(`Could not find property literal with name ${name}`); - -// return propertyLiteral; -// }; diff --git a/package.json b/package.json index 7bf7f60d5..19f114de9 100644 --- a/package.json +++ b/package.json @@ -90,18 +90,17 @@ "clean": "rm -rf lib/* deno/lib/*", "build": "yarn run clean && npm run build:cjs && npm run build:esm && npm run build:deno", "build:deno": "node ./deno-build.mjs && cp ./README.md ./deno/lib", - "build:esm": "rollup --config rollup.config.js", - "build:cjs": "tsc -p tsconfig.cjs.json", - "build:types": "tsc -p tsconfig.types.json", - "build:test": "tsc -p tsconfig.test.json", - "rollup": "rollup --config rollup.config.js", - "test:watch": "jest --watch", + "build:esm": "rollup --config ./configs/rollup.config.js", + "build:cjs": "tsc -p ./configs/tsconfig.cjs.json", + "build:types": "tsc -p ./configs/tsconfig.types.json", + "build:test": "tsc -p ./configs/tsconfig.test.json", + "test:watch": "yarn test:ts-jest --watch", "test": "yarn test:ts-jest", - "test:babel": "jest --coverage", + "test:babel": "jest --coverage --config ./configs/babel-jest.config.json", "test:bun": "bun test", - "test:vitest": "npx vitest --no-isolate", - "test:ts-jest": "npx jest --config ./ts-jest.config.json", - "test:swc": "npx jest --config ./swc-jest.config.json", + "test:vitest": "npx vitest --config ./configs/vitest.config.ts", + "test:ts-jest": "npx jest --config ./configs/ts-jest.config.json", + "test:swc": "npx jest --config ./configs/swc-jest.config.json", "test:deno": "cd deno && deno test", "prepublishOnly": "npm run test && npm run build && npm run build:deno", "play": "nodemon -e ts -w . -x tsx playground.ts", diff --git a/src/__tests__/language-server.test.ts b/src/__tests__/language-server.test.ts index 88767b4ab..fb5c647e5 100644 --- a/src/__tests__/language-server.test.ts +++ b/src/__tests__/language-server.test.ts @@ -1,5 +1,5 @@ // @ts-ignore TS6133 -import { expect, test, describe } from "@jest/globals"; +import { describe, expect, test } from "@jest/globals"; // import path from "path"; // import { Node, Project, SyntaxKind } from "ts-morph"; diff --git a/tsconfig.json b/tsconfig.json index ffcbb9477..a1b3dc7e4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./tsconfig.base.json" + "extends": "./configs/tsconfig.base.json" } From cfbc7b3f6714ced250dd4053822faf472bf1828e Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 23 Jun 2023 18:55:32 -0700 Subject: [PATCH 12/22] Fix root jest config --- jest.config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 jest.config.json diff --git a/jest.config.json b/jest.config.json new file mode 100644 index 000000000..8051d1085 --- /dev/null +++ b/jest.config.json @@ -0,0 +1,10 @@ +{ + "rootDir": ".", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testRegex": "src/.*\\.test\\.ts$", + "modulePathIgnorePatterns": ["language-server", "__vitest__"], + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], + "coverageReporters": ["json-summary", "text", "lcov"] +} From 8677f688b0ab1bb5991e90744f46a15082772bd6 Mon Sep 17 00:00:00 2001 From: Zach Olivare Date: Sun, 30 Jul 2023 16:05:08 -0500 Subject: [PATCH 13/22] docs(comparison-yup): Yup added partial() and deepPartial() in v1 (#2603) So update Yup's section of the Zod comparison accordingly. See: https://github.com/jquense/yup/issues/1906 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index a32bb3da8..3cf7e3cfb 100644 --- a/README.md +++ b/README.md @@ -2718,7 +2718,6 @@ Yup is a full-featured library that was implemented first in vanilla JS, and lat - Supports casting and transforms - All object fields are optional by default -- Missing object methods: (partial, deepPartial) - Missing promise schemas - Missing function schemas From fb00edd04ca338b8d791a96dead161076538c6c2 Mon Sep 17 00:00:00 2001 From: Mathieu Laurent Date: Sun, 30 Jul 2023 23:58:02 +0200 Subject: [PATCH 14/22] docs: add VeeValidate form library for Vue.js (#2578) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cf7e3cfb..cf53c3bb0 100644 --- a/README.md +++ b/README.md @@ -471,7 +471,8 @@ There are a growing number of tools that are built atop or support Zod natively! - [`@modular-forms/solid`](https://github.com/fabian-hiller/modular-forms): Modular form library for SolidJS that supports Zod for validation. - [`houseform`](https://github.com/crutchcorn/houseform/): A React form library that uses Zod for validation. - [`sveltekit-superforms`](https://github.com/ciscoheat/sveltekit-superforms): Supercharged form library for SvelteKit with Zod validation. -- [`mobx-zod-form`](https://github.com/MonoidDev/mobx-zod-form): Data-first form builder based on MobX & Zod +- [`mobx-zod-form`](https://github.com/MonoidDev/mobx-zod-form): Data-first form builder based on MobX & Zod. +- [`@vee-validate/zod`](https://github.com/logaretm/vee-validate/tree/main/packages/zod): Form library for Vue.js with Zod schema validation. #### Zod to X From ab8e71793431eeb163613007c134132e6c2ab078 Mon Sep 17 00:00:00 2001 From: 7yue Date: Mon, 31 Jul 2023 09:49:08 +0800 Subject: [PATCH 15/22] docs: fix typo in z.object (#2570) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cf53c3bb0..45c87dfb0 100644 --- a/README.md +++ b/README.md @@ -1204,7 +1204,7 @@ Starting from this object: ```ts const user = z.object({ - email: z.string() + email: z.string(), username: z.string(), }); // { email: string; username: string } @@ -1269,7 +1269,7 @@ Starting from this object: ```ts const user = z.object({ - email: z.string() + email: z.string(), username: z.string(), }).partial(); // { email?: string | undefined; username?: string | undefined } From d870407a020f9518fbae662f9f48a9aba005a3e2 Mon Sep 17 00:00:00 2001 From: Mathieu Laurent Date: Mon, 31 Jul 2023 03:49:55 +0200 Subject: [PATCH 16/22] docs: fix incomplete Records example (#2579) --- README.md | 6 ++++++ README_ZH.md | 6 ++++++ deno/lib/README.md | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/README.md b/README.md index 45c87dfb0..bf4868698 100644 --- a/README.md +++ b/README.md @@ -1525,6 +1525,12 @@ type NumberCache = z.infer; This is particularly useful for storing or caching items by ID. ```ts +const userSchema = z.object({ name: z.string() }); +const userStoreSchema = z.record(userSchema); + +type UserStore = z.infer; +// => type UserStore = { [ x: string ]: { name: string } } + const userStore: UserStore = {}; userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = { diff --git a/README_ZH.md b/README_ZH.md index ef86a460d..6ca66463d 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -845,6 +845,12 @@ type NumberCache = z.infer; 这对于按 ID 存储或缓存项目特别有用。 ```ts +const userSchema = z.object({ name: z.string() }); +const userStoreSchema = z.record(userSchema); + +type UserStore = z.infer; +// => type UserStore = { [ x: string ]: { name: string } } + const userStore: UserStore = {}; userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = { diff --git a/deno/lib/README.md b/deno/lib/README.md index a32bb3da8..a561e8a52 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -1524,6 +1524,12 @@ type NumberCache = z.infer; This is particularly useful for storing or caching items by ID. ```ts +const userSchema = z.object({ name: z.string() }); +const userStoreSchema = z.record(userSchema); + +type UserStore = z.infer; +// => type UserStore = { [ x: string ]: { name: string } } + const userStore: UserStore = {}; userStore["77d2586b-9e8e-4ecf-8b21-ea7e0530eadd"] = { From 5adae24e9b2fc98fc679defa8f78e4142d4c3451 Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Sun, 30 Jul 2023 19:50:06 -0600 Subject: [PATCH 17/22] docs: add conform form integration (#2577) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds conform. It didn't look like there was much of an order so I put it at the top since that's where it'd go in alphabetical order anyway 🤷‍♂️ --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bf4868698..25ecbcf7e 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,7 @@ There are a growing number of tools that are built atop or support Zod natively! #### Form integrations +- [`conform`](https://conform.guide/api/zod): A progressive enhancement first form validation library for Remix and React Router - [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form. - [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s. - [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod. From 8b8ab3e79691ebafbb9aac3ce089eaf0dcd6d8fe Mon Sep 17 00:00:00 2001 From: Sam Chung Date: Mon, 31 Jul 2023 11:50:33 +1000 Subject: [PATCH 18/22] Update README.md (#2562) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 25ecbcf7e..e66f02537 100644 --- a/README.md +++ b/README.md @@ -485,7 +485,8 @@ There are a growing number of tools that are built atop or support Zod natively! - [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas. - [`zod-to-openapi`](https://github.com/asteasolutions/zod-to-openapi): Generate full OpenAPI (Swagger) docs from Zod, including schemas, endpoints & parameters. - [`nestjs-graphql-zod`](https://github.com/incetarik/nestjs-graphql-zod): Generates NestJS GraphQL model classes from Zod schemas. Provides GraphQL method decorators working with Zod schemas. -- [`zod-openapi`](https://github.com/samchungy/zod-openapi): Create full OpenAPI v3.x documentation from Zod Schemas. +- [`zod-openapi`](https://github.com/samchungy/zod-openapi): Create full OpenAPI v3.x documentation from Zod schemas. +- [`fastify-zod-openapi`](https://github.com/samchungy/fastify-zod-openapi): Fastify type provider, validation, serialization and @fastify/swagger support for Zod schemas. #### X to Zod From 6aab9016873c12be08d19bcc097b3e5ba4c9d6fe Mon Sep 17 00:00:00 2001 From: hiro Date: Mon, 31 Jul 2023 10:52:08 +0900 Subject: [PATCH 19/22] fix typo test name (#2542) * fix(typo): methd -> method * fix(typo): methd -> method --- deno/lib/__tests__/primitive.test.ts | 2 +- src/__tests__/primitive.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deno/lib/__tests__/primitive.test.ts b/deno/lib/__tests__/primitive.test.ts index d3f7d0f92..5815f765e 100644 --- a/deno/lib/__tests__/primitive.test.ts +++ b/deno/lib/__tests__/primitive.test.ts @@ -448,7 +448,7 @@ test("get literal value", () => { expect(literalStringSchema.value).toEqual("asdf"); }); -test("optional convenience methd", () => { +test("optional convenience method", () => { z.ostring().parse(undefined); z.onumber().parse(undefined); z.oboolean().parse(undefined); diff --git a/src/__tests__/primitive.test.ts b/src/__tests__/primitive.test.ts index 28c11e713..cd1c4f5fc 100644 --- a/src/__tests__/primitive.test.ts +++ b/src/__tests__/primitive.test.ts @@ -447,7 +447,7 @@ test("get literal value", () => { expect(literalStringSchema.value).toEqual("asdf"); }); -test("optional convenience methd", () => { +test("optional convenience method", () => { z.ostring().parse(undefined); z.onumber().parse(undefined); z.oboolean().parse(undefined); From 81a89f593f4d6b05f770bbb3ad0fc98075f468dd Mon Sep 17 00:00:00 2001 From: Nick Campbell <661795+nickcampbell18@users.noreply.github.com> Date: Mon, 31 Jul 2023 02:55:01 +0100 Subject: [PATCH 20/22] Update nullish documentation to correct chaining order (#2457) This follows on from 0c0e49517e4dfa to keep the docs in sync. --- README.md | 2 +- README_ZH.md | 2 +- deno/lib/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e66f02537..bc8e51cf1 100644 --- a/README.md +++ b/README.md @@ -2361,7 +2361,7 @@ A convenience method that returns a "nullish" version of a schema. Nullish schem const nullishString = z.string().nullish(); // string | null | undefined // equivalent to -z.string().optional().nullable(); +z.string().nullable().optional(); ``` ### `.array` diff --git a/README_ZH.md b/README_ZH.md index 6ca66463d..f8878f292 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1623,7 +1623,7 @@ z.nullable(z.string()); const nullishString = z.string().nullish(); // string | null | undefined // equivalent to -z.string().optional().nullable(); +z.string().nullable().optional(); ``` ### `.array` diff --git a/deno/lib/README.md b/deno/lib/README.md index a561e8a52..3e2ecfd23 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -2358,7 +2358,7 @@ A convenience method that returns a "nullish" version of a schema. Nullish schem const nullishString = z.string().nullish(); // string | null | undefined // equivalent to -z.string().optional().nullable(); +z.string().nullable().optional(); ``` ### `.array` From 78a409012a4dc34a455f5c4a7e028ca47c921e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=CA=9C=C9=AA=E1=B4=8D=E1=B4=9C=CA=80=E1=B4=80=20Yu=CC=84?= Date: Mon, 31 Jul 2023 13:44:47 +0900 Subject: [PATCH 21/22] docs: update comparison with `runtypes` (#2536) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc8e51cf1..ce0bf26c0 100644 --- a/README.md +++ b/README.md @@ -2789,7 +2789,7 @@ This more declarative API makes schema definitions vastly more concise. [https://github.com/pelotom/runtypes](https://github.com/pelotom/runtypes) -Good type inference support, but limited options for object type masking (no `.pick` , `.omit` , `.extend` , etc.). No support for `Record` s (their `Record` is equivalent to Zod's `object` ). They DO support readonly types, which Zod does not. +Good type inference support. They DO support readonly types, which Zod does not. - Supports "pattern matching": computed properties that distribute over unions - Supports readonly types From 1ecd6241ef97b33ce229b49f1346ffeee5d0ba74 Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Sat, 5 Aug 2023 23:07:56 -0700 Subject: [PATCH 22/22] Fix prettier --- README.md | 10 ++++++---- deno/lib/README.md | 22 +++++++++++++--------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ce0bf26c0..73efc76f7 100644 --- a/README.md +++ b/README.md @@ -1270,10 +1270,12 @@ Contrary to the `.partial` method, the `.required` method makes all properties r Starting from this object: ```ts -const user = z.object({ - email: z.string(), - username: z.string(), -}).partial(); +const user = z + .object({ + email: z.string(), + username: z.string(), + }) + .partial(); // { email?: string | undefined; username?: string | undefined } ``` diff --git a/deno/lib/README.md b/deno/lib/README.md index 3e2ecfd23..73efc76f7 100644 --- a/deno/lib/README.md +++ b/deno/lib/README.md @@ -460,6 +460,7 @@ There are a growing number of tools that are built atop or support Zod natively! #### Form integrations +- [`conform`](https://conform.guide/api/zod): A progressive enhancement first form validation library for Remix and React Router - [`react-hook-form`](https://github.com/react-hook-form/resolvers#zod): A first-party Zod resolver for React Hook Form. - [`zod-validation-error`](https://github.com/causaly/zod-validation-error): Generate user-friendly error messages from `ZodError`s. - [`zod-formik-adapter`](https://github.com/robertLichtnow/zod-formik-adapter): A community-maintained Formik adapter for Zod. @@ -471,7 +472,8 @@ There are a growing number of tools that are built atop or support Zod natively! - [`@modular-forms/solid`](https://github.com/fabian-hiller/modular-forms): Modular form library for SolidJS that supports Zod for validation. - [`houseform`](https://github.com/crutchcorn/houseform/): A React form library that uses Zod for validation. - [`sveltekit-superforms`](https://github.com/ciscoheat/sveltekit-superforms): Supercharged form library for SvelteKit with Zod validation. -- [`mobx-zod-form`](https://github.com/MonoidDev/mobx-zod-form): Data-first form builder based on MobX & Zod +- [`mobx-zod-form`](https://github.com/MonoidDev/mobx-zod-form): Data-first form builder based on MobX & Zod. +- [`@vee-validate/zod`](https://github.com/logaretm/vee-validate/tree/main/packages/zod): Form library for Vue.js with Zod schema validation. #### Zod to X @@ -483,7 +485,8 @@ There are a growing number of tools that are built atop or support Zod natively! - [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod): Create Fastify type providers from Zod schemas. - [`zod-to-openapi`](https://github.com/asteasolutions/zod-to-openapi): Generate full OpenAPI (Swagger) docs from Zod, including schemas, endpoints & parameters. - [`nestjs-graphql-zod`](https://github.com/incetarik/nestjs-graphql-zod): Generates NestJS GraphQL model classes from Zod schemas. Provides GraphQL method decorators working with Zod schemas. -- [`zod-openapi`](https://github.com/samchungy/zod-openapi): Create full OpenAPI v3.x documentation from Zod Schemas. +- [`zod-openapi`](https://github.com/samchungy/zod-openapi): Create full OpenAPI v3.x documentation from Zod schemas. +- [`fastify-zod-openapi`](https://github.com/samchungy/fastify-zod-openapi): Fastify type provider, validation, serialization and @fastify/swagger support for Zod schemas. #### X to Zod @@ -1203,7 +1206,7 @@ Starting from this object: ```ts const user = z.object({ - email: z.string() + email: z.string(), username: z.string(), }); // { email: string; username: string } @@ -1267,10 +1270,12 @@ Contrary to the `.partial` method, the `.required` method makes all properties r Starting from this object: ```ts -const user = z.object({ - email: z.string() - username: z.string(), -}).partial(); +const user = z + .object({ + email: z.string(), + username: z.string(), + }) + .partial(); // { email?: string | undefined; username?: string | undefined } ``` @@ -2724,7 +2729,6 @@ Yup is a full-featured library that was implemented first in vanilla JS, and lat - Supports casting and transforms - All object fields are optional by default -- Missing object methods: (partial, deepPartial) - Missing promise schemas - Missing function schemas @@ -2787,7 +2791,7 @@ This more declarative API makes schema definitions vastly more concise. [https://github.com/pelotom/runtypes](https://github.com/pelotom/runtypes) -Good type inference support, but limited options for object type masking (no `.pick` , `.omit` , `.extend` , etc.). No support for `Record` s (their `Record` is equivalent to Zod's `object` ). They DO support readonly types, which Zod does not. +Good type inference support. They DO support readonly types, which Zod does not. - Supports "pattern matching": computed properties that distribute over unions - Supports readonly types