diff --git a/.npmignore b/.npmignore index 5a9ca69..f0268f9 100644 --- a/.npmignore +++ b/.npmignore @@ -15,3 +15,4 @@ CONTRIBUTING.md CHANGELOG.md UPCOMING.md SECURITY.md +vitest* diff --git a/.vscode/launch.json b/.vscode/launch.json index 446142b..2c8a04b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,32 +5,29 @@ "version": "0.2.0", "configurations": [ { - "type": "bun", + "name": "tsx", + "type": "node", "request": "launch", - "name": "Debug Bun", - // The path to a JavaScript or TypeScript file to run. + // Debug current file in VSCode "program": "${file}", - // The arguments to pass to the program, if any. - "args": [], - // The working directory of the program. - "cwd": "${workspaceFolder}", - // The environment variables to pass to the program. - "env": {}, - // If the environment variables should not be inherited from the parent process. - "strictEnv": false, - // If the program should be run in watch mode. - // This is equivalent to passing `--watch` to the `bun` executable. - // You can also set this to "hot" to enable hot reloading using `--hot`. - "watchMode": false, - // If the debugger should stop on the first line of the program. - "stopOnEntry": false, - // If the debugger should be disabled. (for example, breakpoints will not be hit) - "noDebug": false, - // The path to the `bun` executable, defaults to your `PATH` environment variable. - "runtime": "bun", - // The arguments to pass to the `bun` executable, if any. - // Unlike `args`, these are passed to the executable itself, not the program. - "runtimeArgs": [], - }, + /* + * Path to tsx binary + * Assuming locally installed + */ + "runtimeExecutable": "tsx", + /* + * Open terminal when debugging starts (Optional) + * Useful to see console.logs + */ + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + // Files to exclude from debugger (e.g. call stack) + "skipFiles": [ + // Node.js internal core modules + "/**", + // Ignore all dependencies (optional) + "${workspaceFolder}/node_modules/**", + ], + } ] } \ No newline at end of file diff --git a/UPCOMING.md b/UPCOMING.md index c65c735..6ee66da 100644 --- a/UPCOMING.md +++ b/UPCOMING.md @@ -1,5 +1,21 @@ -# 0.8 +# x.x.x -features: +Fixes: -- Benhmark +- Issue [#57](https://github.com/vitalics/ajv-ts/issues/57) - `merge` construct schema with `undefined` fields. +- Extend don't update `def` property. +- Advanced TS type for `.array()` call. + +Chore: + +- Move bech under `tests` folder + +Infra: + +- Configure vitest config file for testing and enable github actions reporter for CI +- Add `tsx` package for inspection. +- Update launch.json file for vscode debugger + +Tests: + +- add [#57](https://github.com/vitalics/ajv-ts/issues/57) issue test for `object` type. diff --git a/package.json b/package.json index 0ff6d84..ba83086 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "eslint-plugin-import": "2.25.2", "eslint-plugin-n": "15.0.0", "tsup": "8.1.0", + "tsx": "4.17.0", "typescript": "5.5.3", "vitest": "1.6.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d22f7ba..0cce9e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,6 +51,9 @@ importers: tsup: specifier: 8.1.0 version: 8.1.0(postcss@8.4.38)(typescript@5.5.3) + tsx: + specifier: 4.17.0 + version: 4.17.0 typescript: specifier: 5.5.3 version: 5.5.3 @@ -187,138 +190,282 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.23.0': + resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.23.0': + resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.23.0': + resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.23.0': + resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.23.0': + resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.23.0': + resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.23.0': + resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.23.0': + resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.23.0': + resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.23.0': + resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.23.0': + resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.23.0': + resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.23.0': + resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.23.0': + resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.23.0': + resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.23.0': + resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.23.0': + resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.23.0': + resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.0': + resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.23.0': + resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.23.0': + resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.23.0': + resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.23.0': + resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.23.0': + resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -983,6 +1130,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.23.0: + resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -1219,6 +1371,9 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} + get-tsconfig@4.7.6: + resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1918,6 +2073,9 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -2198,6 +2356,11 @@ packages: typescript: optional: true + tsx@4.17.0: + resolution: {integrity: sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==} + engines: {node: '>=18.0.0'} + hasBin: true + tty-table@4.2.3: resolution: {integrity: sha512-Fs15mu0vGzCrj8fmJNP7Ynxt5J7praPXqFN0leZeZBXJwkMxv9cb2D454k1ltrtUSJbZ4yH4e0CynsHLxmUfFA==} engines: {node: '>=8.0.0'} @@ -2630,72 +2793,144 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.23.0': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.23.0': + optional: true + '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.23.0': + optional: true + '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.23.0': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.23.0': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.23.0': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.23.0': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.23.0': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.23.0': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.23.0': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.23.0': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.23.0': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.23.0': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.23.0': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.23.0': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.23.0': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.23.0': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.23.0': + optional: true + + '@esbuild/openbsd-arm64@0.23.0': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.23.0': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.23.0': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.23.0': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.23.0': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true + '@esbuild/win32-x64@0.23.0': + optional: true + '@eslint-community/eslint-utils@4.4.0(eslint@8.0.1)': dependencies: eslint: 8.0.1 @@ -3478,6 +3713,33 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + esbuild@0.23.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.0 + '@esbuild/android-arm': 0.23.0 + '@esbuild/android-arm64': 0.23.0 + '@esbuild/android-x64': 0.23.0 + '@esbuild/darwin-arm64': 0.23.0 + '@esbuild/darwin-x64': 0.23.0 + '@esbuild/freebsd-arm64': 0.23.0 + '@esbuild/freebsd-x64': 0.23.0 + '@esbuild/linux-arm': 0.23.0 + '@esbuild/linux-arm64': 0.23.0 + '@esbuild/linux-ia32': 0.23.0 + '@esbuild/linux-loong64': 0.23.0 + '@esbuild/linux-mips64el': 0.23.0 + '@esbuild/linux-ppc64': 0.23.0 + '@esbuild/linux-riscv64': 0.23.0 + '@esbuild/linux-s390x': 0.23.0 + '@esbuild/linux-x64': 0.23.0 + '@esbuild/netbsd-x64': 0.23.0 + '@esbuild/openbsd-arm64': 0.23.0 + '@esbuild/openbsd-x64': 0.23.0 + '@esbuild/sunos-x64': 0.23.0 + '@esbuild/win32-arm64': 0.23.0 + '@esbuild/win32-ia32': 0.23.0 + '@esbuild/win32-x64': 0.23.0 + escalade@3.1.2: {} escape-string-regexp@1.0.5: {} @@ -3773,6 +4035,10 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 + get-tsconfig@4.7.6: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -4403,6 +4669,8 @@ snapshots: resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -4704,6 +4972,13 @@ snapshots: - supports-color - ts-node + tsx@4.17.0: + dependencies: + esbuild: 0.23.0 + get-tsconfig: 4.7.6 + optionalDependencies: + fsevents: 2.3.3 + tty-table@4.2.3: dependencies: chalk: 4.1.2 diff --git a/src/builder.ts b/src/builder.ts index d3be639..80feca5 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -405,7 +405,7 @@ export class SchemaBuilder< * * @see {@link array} */ - array>(): ArraySchemaBuilder { + array>(): ArraySchemaBuilder { return array(this) as never; } @@ -1380,10 +1380,21 @@ class ObjectSchemaBuilder< Merge, Merge > { - Object.entries(schema.schema).forEach(([key, def]) => { - this.schema.properties![key] = def.schema; + if (schema.schema.type !== 'object') { + throw new TypeError('Cannot merge not object type with object', { + cause: { + incoming: schema.schema, + given: this.schema, + }, + }) + } + const a = object(); + a.schema = Object.assign({}, this.schema); + Object.entries(schema.def).forEach(([key, def]) => { + a.schema.properties![key] = def.schema; }); - return this as never; + a.def = { ...this.def, ...schema.def } + return a as never; } /** * Same as `merge`, but not accepts `s.object`. @@ -1400,6 +1411,7 @@ class ObjectSchemaBuilder< Object.entries(def).forEach(([key, def]) => { a.schema.properties![key] = def.schema; }); + a.def = { ...this.def, ...def } return a as never; } diff --git a/tests/object.test.ts b/tests/object.test.ts index 2b7c482..a8babc1 100644 --- a/tests/object.test.ts +++ b/tests/object.test.ts @@ -1,4 +1,4 @@ -import { assertType, expect, test } from "vitest"; +import { assertType, expect, expectTypeOf, test } from "vitest"; import { assertEqualType } from "../src/utils"; import s from "../src"; @@ -396,3 +396,53 @@ test("object accepts type as generic", () => { assertEqualType>(true); }); + +test('#57 merge() should not contains undefined after merge', () => { + + const AjvVehicleSchema = s.object({ + make: s.string(), + model: s.string(), + year: s.number(), + }); + + const AjvTruckSchema = s + .object({ + commercialCapacity: s.number(), + forwardCabin: s.boolean(), + wheels: s.number(), + }) + .merge(AjvVehicleSchema); + + type AjvTruck = s.infer; + + const resp = AjvTruckSchema.safeParse({ + make: 'Bugatti', + model: 'Model T', + year: 2020, + commercialCapacity: 1000, + forwardCabin: true, + wheels: 4 + }) + expect(resp.success).toBe(true) + + expect(AjvTruckSchema.schema).toMatchObject( + { + type: 'object', + properties: { + commercialCapacity: { type: 'number' }, + forwardCabin: { type: 'boolean' }, + wheels: { type: 'number' }, + make: { type: 'string' }, + model: { type: 'string' }, + year: { type: 'number' }, + } + }) + assertType({ + make: 'Bugatti', + model: 'Model T', + year: 2020, + commercialCapacity: 1000, + forwardCabin: true, + wheels: 4 + }) +}) diff --git a/bench/benchmark.ts b/tests/parse.bench.test.ts similarity index 97% rename from bench/benchmark.ts rename to tests/parse.bench.test.ts index 6ade6af..b02538e 100644 --- a/bench/benchmark.ts +++ b/tests/parse.bench.test.ts @@ -1,3 +1,5 @@ +/// NOTE: experimental module + import Benchmark from "benchmark"; import s from "../src"; diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 0000000..3e793b9 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,8 @@ +/// +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + reporters: process.env.GITHUB_ACTIONS ? ['dot', 'github-actions'] : [], + }, +})