fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: add Zod 4 page

Lubos 482cab45 6ec51d9f

+454 -37
+8
docs/.vitepress/config/index.ts
··· 6 6 export default defineConfig({ 7 7 ...shared, 8 8 locales: { 9 + ...shared.locales, 9 10 root: { label: 'English', ...en }, 11 + }, 12 + vite: { 13 + ...shared.vite, 14 + resolve: { 15 + ...shared.vite?.resolve, 16 + preserveSymlinks: true, 17 + }, 10 18 }, 11 19 });
+1 -1
docs/.vitepress/theme/Layout.vue
··· 1 - <script setup> 1 + <script setup lang="ts"> 2 2 import DefaultTheme from 'vitepress/theme'; 3 3 4 4 const { Layout } = DefaultTheme;
+53
docs/.vitepress/theme/components/VersionSwitcher.vue
··· 1 + <script setup lang="ts"> 2 + import { ref } from 'vue'; 3 + import { useRoute, useRouter } from 'vitepress'; 4 + import VueSelect from 'vue3-select-component'; 5 + 6 + type Option = { 7 + label: string; 8 + value: string; 9 + }; 10 + 11 + const props = defineProps<{ 12 + default: string; 13 + values: Array<Option>; 14 + }>(); 15 + 16 + const route = useRoute(); 17 + const router = useRouter(); 18 + 19 + const selected = ref(getCurrentVersion(route.path)); 20 + 21 + function getCurrentVersion(path: string) { 22 + const segments = path.replace(/(^\/|\/$)/g, '').split('/'); 23 + const versionValues = props.values.map((v) => v.value); 24 + const last = segments[segments.length - 1]; 25 + return versionValues.includes(last) ? last : props.default; 26 + } 27 + 28 + function switchVersion(option: Option) { 29 + const path = route.path; 30 + const segments = path.replace(/(^\/|\/$)/g, '').split('/'); 31 + const versionValues = props.values.map((v) => v.value); 32 + const last = segments[segments.length - 1]; 33 + if (versionValues.includes(last)) { 34 + segments.pop(); 35 + } 36 + if (option.value !== props.default) { 37 + segments.push(option.value); 38 + } 39 + const nextPath = `/${segments.filter(Boolean).join('/')}`; 40 + if (nextPath !== route.path) { 41 + router.go(nextPath); 42 + } 43 + } 44 + </script> 45 + 46 + <template> 47 + <VueSelect 48 + v-model="selected" 49 + :isClearable="false" 50 + :options="props.values" 51 + @option-selected="switchVersion" 52 + /> 53 + </template>
+84 -18
docs/.vitepress/theme/custom.css
··· 31 31 --vp-home-hero-image-filter: blur(144px); 32 32 } 33 33 34 + html.mac { 35 + --vs-background-color: var(--vp-input-switch-bg-color); 36 + --vs-border: 1px solid var(--vp-input-border-color); 37 + --vs-menu-border: 1px solid var(--vp-input-border-color); 38 + --vs-menu-box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; 39 + --vs-option-background-color: var(--vp-sidebar-bg-color); 40 + --vs-option-disabled-background-color: var(--vp-sidebar-bg-color); 41 + --vs-option-focused-background-color: var(--vp-sidebar-bg-color); 42 + --vs-option-focused-text-color: var(--vp-c-brand-1); 43 + --vs-option-hover-background-color: var(--vp-sidebar-bg-color); 44 + --vs-option-hover-text-color: var(--vp-c-brand-1); 45 + --vs-option-selected-background-color: var(--vp-sidebar-bg-color); 46 + --vs-option-selected-text-color: var(--vp-c-brand-1); 47 + --vs-option-text-color: var(--vp-c-text-2); 48 + --vs-padding-x: 8px; 49 + --vs-padding-y: 4px; 50 + --vs-padding: var(--vs-padding-y) var(--vs-padding-x); 51 + --vs-text-color: var(--vp-c-text-1); 52 + --vs-width: auto; 53 + } 54 + 34 55 [data-soon] { 35 56 background-color: var(--vp-button-brand-bg); 36 57 border-radius: 1em; ··· 46 67 background-color: var(--vp-sidebar-bg-color); 47 68 border: none; 48 69 margin: 0; 70 + } 71 + 72 + .VPFeatures.VPHomeFeatures > .container { 73 + max-width: initial; 74 + } 75 + 76 + .VPFeatures.VPHomeFeatures > .container > .items { 77 + gap: 1rem; 78 + justify-content: center; 79 + margin: 0; 80 + padding: 0.2rem 0; 81 + } 82 + 83 + .VPFeatures.VPHomeFeatures > .container > .items > .item { 84 + flex-shrink: 0; 85 + max-width: 390px; 86 + padding: 0; 87 + width: 100%; 49 88 } 50 89 51 90 .authors-list { ··· 244 283 text-transform: lowercase; 245 284 } 246 285 247 - .VPFeatures.VPHomeFeatures > .container { 248 - max-width: initial; 249 - } 250 - 251 286 .migration { 252 287 background-color: var(--vp-c-brand-3); 253 288 border-radius: 10px; ··· 270 305 border-color: var(--vp-c-brand-1); 271 306 } 272 307 273 - .VPFeatures.VPHomeFeatures > .container > .items { 274 - gap: 1rem; 275 - justify-content: center; 276 - margin: 0; 277 - padding: 0.2rem 0; 278 - } 279 - 280 308 .contributors-list ul { 281 309 margin-bottom: 1.3rem; 282 310 margin-top: 1.3rem; 283 311 } 284 312 313 + .heading-with-version { 314 + display: flex; 315 + column-gap: 1rem; 316 + } 317 + 318 + .vue-select .control { 319 + cursor: pointer; 320 + transition: border-color 0.25s; 321 + } 322 + 323 + .vue-select .control:hover { 324 + border-color: var(--vp-c-brand-1); 325 + } 326 + 327 + .vue-select .control .indicators-container { 328 + padding: 0; 329 + } 330 + 331 + .vue-select .control .indicators-container button.dropdown-icon { 332 + height: 100%; 333 + padding: var(--vs-padding); 334 + width: calc( 335 + var(--vs-indicator-icon-size) + var(--vs-padding-x) + var(--vs-padding-x) 336 + ); 337 + } 338 + 339 + .vue-select .menu .menu-option { 340 + border-left: 2px solid transparent; 341 + border-right: 2px solid transparent; 342 + transition: 343 + background-color 0.25s, 344 + border-color 0.25s, 345 + color 0.25s, 346 + opacity 0.25s; 347 + } 348 + 349 + .vue-select .menu:hover .menu-option.focused:not(:hover) { 350 + border-left: 2px solid transparent; 351 + } 352 + 353 + .vue-select .menu .menu-option:hover, 354 + .vue-select .menu:not(:hover) .menu-option.focused { 355 + border-left: 2px solid var(--vp-c-brand-1); 356 + } 357 + 285 358 @media (min-width: 640px) { 286 359 .VPFeatures.VPHomeFeatures > .container > .items { 287 360 gap: 1rem; ··· 315 388 background-color: var(--vp-sidebar-bg-color); 316 389 } 317 390 } 318 - 319 - .VPFeatures.VPHomeFeatures > .container > .items > .item { 320 - flex-shrink: 0; 321 - max-width: 390px; 322 - padding: 0; 323 - width: 100%; 324 - }
+2
docs/.vitepress/theme/index.ts
··· 6 6 import './custom.css'; 7 7 8 8 import AuthorsList from './components/AuthorsList.vue'; 9 + import VersionSwitcher from './components/VersionSwitcher.vue'; 9 10 import Layout from './Layout.vue'; 10 11 11 12 export default { 12 13 Layout, 13 14 enhanceApp: ({ app }) => { 14 15 app.component('AuthorsList', AuthorsList); 16 + app.component('VersionSwitcher', VersionSwitcher); 15 17 }, 16 18 extends: DefaultTheme, 17 19 } satisfies Theme;
+1 -1
docs/openapi-ts/clients.md
··· 3 3 description: REST clients for Hey API. Compatible with all our features. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { embedProject } from '../embed' 8 8 </script> 9 9
+1 -1
docs/openapi-ts/clients/axios.md
··· 3 3 description: Axios client for Hey API. Compatible with all our features. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { embedProject } from '../../embed' 8 8 </script> 9 9
+1 -1
docs/openapi-ts/clients/fetch.md
··· 3 3 description: Fetch API client for Hey API. Compatible with all our features. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { embedProject } from '../../embed' 8 8 </script> 9 9
+1 -1
docs/openapi-ts/clients/legacy.md
··· 3 3 description: Legacy clients for Hey API. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { embedProject } from '../../embed' 8 8 </script> 9 9
+1 -1
docs/openapi-ts/community/spotlight.md
··· 3 3 description: Meet the people behind @hey-api/openapi-ts. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { VPTeamMembers } from 'vitepress/theme' 8 8 import { coreTeam } from '../../data/coreTeam.js' 9 9 import { hallOfFame } from '../../data/hallOfFame.js'
+1 -1
docs/openapi-ts/get-started.md
··· 3 3 description: Get started with @hey-api/openapi-ts. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { embedProject } from '../embed' 8 8 </script> 9 9
+1 -1
docs/openapi-ts/plugins/tanstack-query.md
··· 3 3 description: TanStack Query plugin for Hey API. Compatible with all our features. 4 4 --- 5 5 6 - <script setup> 6 + <script setup lang="ts"> 7 7 import { embedProject } from '../../embed' 8 8 </script> 9 9
+1 -1
docs/openapi-ts/plugins/valibot.md
··· 3 3 description: Valibot plugin for Hey API. Compatible with all our features. 4 4 --- 5 5 6 - <!-- <script setup> 6 + <!-- <script setup lang="ts"> 7 7 import { embedProject } from '../../embed' 8 8 </script> --> 9 9
+8 -8
docs/openapi-ts/plugins/zod.md
··· 3 3 description: Zod plugin for Hey API. Compatible with all our features. 4 4 --- 5 5 6 - <!-- <script setup> 7 - import { embedProject } from '../../embed' 8 - </script> --> 9 - 10 - # Zod 6 + <script setup lang="ts"> 7 + // import { embedProject } from '../../embed' 8 + import ZodVersionSwitcher from './zod/ZodVersionSwitcher.vue'; 9 + </script> 11 10 12 - ::: warning 13 - Zod plugin is currently in beta. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/openapi-ts/issues/876). 14 - ::: 11 + <div class="heading-with-version"> 12 + <h1>Zod</h1> 13 + <ZodVersionSwitcher /> 14 + </div> 15 15 16 16 ### About 17 17
+16
docs/openapi-ts/plugins/zod/ZodVersionSwitcher.vue
··· 1 + <script setup lang="ts"> 2 + const versions = [ 3 + { 4 + label: 'v3', 5 + value: 'v3', 6 + }, 7 + { 8 + label: 'v4', 9 + value: 'v4', 10 + }, 11 + ]; 12 + </script> 13 + 14 + <template> 15 + <VersionSwitcher :values="versions" default="v4" /> 16 + </template>
+247
docs/openapi-ts/plugins/zod/v3.md
··· 1 + --- 2 + title: Zod 3 + description: Zod plugin for Hey API. Compatible with all our features. 4 + --- 5 + 6 + <script setup lang="ts"> 7 + // import { embedProject } from '../../embed' 8 + import ZodVersionSwitcher from './ZodVersionSwitcher.vue'; 9 + </script> 10 + 11 + <div class="heading-with-version"> 12 + <h1>Zod</h1> 13 + <ZodVersionSwitcher /> 14 + </div> 15 + 16 + ### About 17 + 18 + [Zod](https://zod.dev) is a TypeScript-first schema validation library with static type inference. 19 + 20 + <!-- ### Demo 21 + 22 + <button class="buttonLink" @click="(event) => embedProject('hey-api-client-fetch-plugin-zod-example')(event)"> 23 + Launch demo 24 + </button> --> 25 + 26 + ## Features 27 + 28 + - seamless integration with `@hey-api/openapi-ts` ecosystem 29 + - Zod schemas for requests, responses, and reusable definitions 30 + 31 + ## Installation 32 + 33 + In your [configuration](/openapi-ts/get-started), add `zod` to your plugins and you'll be ready to generate Zod artifacts. :tada: 34 + 35 + ```js 36 + export default { 37 + input: 'https://get.heyapi.dev/hey-api/backend', 38 + output: 'src/client', 39 + plugins: [ 40 + // ...other plugins 41 + 'zod', // [!code ++] 42 + ], 43 + }; 44 + ``` 45 + 46 + ### SDKs 47 + 48 + To add data validators to your SDKs, set `sdk.validator` to `true`. 49 + 50 + ```js 51 + export default { 52 + input: 'https://get.heyapi.dev/hey-api/backend', 53 + output: 'src/client', 54 + plugins: [ 55 + // ...other plugins 56 + 'zod', 57 + { 58 + name: '@hey-api/sdk', // [!code ++] 59 + validator: true, // [!code ++] 60 + }, 61 + ], 62 + }; 63 + ``` 64 + 65 + Learn more about data validators in your SDKs on the [SDKs](/openapi-ts/output/sdk#validators) page. 66 + 67 + ## Output 68 + 69 + The Zod plugin will generate the following artifacts, depending on the input specification. 70 + 71 + ## Requests 72 + 73 + A single request schema is generated for each endpoint. It may contain a request body, parameters, and headers. 74 + 75 + ::: code-group 76 + 77 + ```js [config] 78 + export default { 79 + input: 'https://get.heyapi.dev/hey-api/backend', 80 + output: 'src/client', 81 + plugins: [ 82 + // ...other plugins 83 + { 84 + name: 'zod', 85 + requests: true, // [!code ++] 86 + }, 87 + ], 88 + }; 89 + ``` 90 + 91 + ```ts [output] 92 + const zData = z.object({ 93 + body: z 94 + .object({ 95 + foo: z.string().optional(), 96 + bar: z.union([z.number(), z.null()]).optional(), 97 + }) 98 + .optional(), 99 + path: z.object({ 100 + baz: z.string(), 101 + }), 102 + query: z.never().optional(), 103 + }); 104 + ``` 105 + 106 + ::: 107 + 108 + ::: tip 109 + If you need to access individual fields, you can do so using the [`.shape`](https://zod.dev/api?id=shape) API. For example, we can get the request body schema with `zData.shape.body`. 110 + ::: 111 + 112 + You can customize the naming and casing pattern for `requests` schemas using the `.name` and `.case` options. 113 + 114 + ## Responses 115 + 116 + A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes. 117 + 118 + ::: code-group 119 + 120 + ```js [config] 121 + export default { 122 + input: 'https://get.heyapi.dev/hey-api/backend', 123 + output: 'src/client', 124 + plugins: [ 125 + // ...other plugins 126 + { 127 + name: 'zod', 128 + responses: true, // [!code ++] 129 + }, 130 + ], 131 + }; 132 + ``` 133 + 134 + ```ts [output] 135 + const zResponse = z.union([ 136 + z.object({ 137 + foo: z.string().optional(), 138 + }), 139 + z.object({ 140 + bar: z.number().optional(), 141 + }), 142 + ]); 143 + ``` 144 + 145 + ::: 146 + 147 + You can customize the naming and casing pattern for `responses` schemas using the `.name` and `.case` options. 148 + 149 + ## Definitions 150 + 151 + A Zod schema is generated for every reusable definition from your input. 152 + 153 + ::: code-group 154 + 155 + ```js [config] 156 + export default { 157 + input: 'https://get.heyapi.dev/hey-api/backend', 158 + output: 'src/client', 159 + plugins: [ 160 + // ...other plugins 161 + { 162 + name: 'zod', 163 + definitions: true, // [!code ++] 164 + }, 165 + ], 166 + }; 167 + ``` 168 + 169 + ```ts [output] 170 + const zFoo = z.number().int(); 171 + 172 + const zBar = z.object({ 173 + bar: z.array(z.number().int()).optional(), 174 + }); 175 + ``` 176 + 177 + ::: 178 + 179 + You can customize the naming and casing pattern for `definitions` schemas using the `.name` and `.case` options. 180 + 181 + ## Metadata 182 + 183 + It's often useful to associate a schema with some additional [metadata](https://zod.dev/metadata) for documentation, code generation, AI structured outputs, form validation, and other purposes. If this is your use case, you can set `metadata` to `true` to generate additional metadata about schemas. 184 + 185 + ::: code-group 186 + 187 + ```js [config] 188 + export default { 189 + input: 'https://get.heyapi.dev/hey-api/backend', 190 + output: 'src/client', 191 + plugins: [ 192 + // ...other plugins 193 + { 194 + name: 'zod', 195 + metadata: true, // [!code ++] 196 + }, 197 + ], 198 + }; 199 + ``` 200 + 201 + ```ts [output] 202 + export const zFoo = z.string().describe('Additional metadata'); 203 + ``` 204 + 205 + ::: 206 + 207 + ## Types 208 + 209 + In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources. 210 + 211 + ::: code-group 212 + 213 + ```js [config] 214 + export default { 215 + input: 'https://get.heyapi.dev/hey-api/backend', 216 + output: 'src/client', 217 + plugins: [ 218 + // ...other plugins 219 + { 220 + name: 'zod', 221 + types: { 222 + infer: false, // by default, no `z.infer` types [!code ++] 223 + }, 224 + responses: { 225 + types: { 226 + infer: true, // `z.infer` types only for response schemas [!code ++] 227 + }, 228 + }, 229 + }, 230 + ], 231 + }; 232 + ``` 233 + 234 + ```ts [output] 235 + export type ResponseZodType = z.infer<typeof zResponse>; 236 + ``` 237 + 238 + ::: 239 + 240 + You can customize the naming and casing pattern for schema-specific `types` using the `.name` and `.case` options. 241 + 242 + ## Config API 243 + 244 + You can view the complete list of options in the [UserConfig](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/plugins/zod/types.d.ts) interface. 245 + 246 + <!--@include: ../../../partials/examples.md--> 247 + <!--@include: ../../../partials/sponsors.md-->
+2 -1
docs/package.json
··· 11 11 "preview": "vitepress preview" 12 12 }, 13 13 "dependencies": { 14 - "@stackblitz/sdk": "1.11.0" 14 + "@stackblitz/sdk": "1.11.0", 15 + "vue3-select-component": "0.11.8" 15 16 }, 16 17 "devDependencies": { 17 18 "sharp": "0.33.5",
+25 -1
pnpm-lock.yaml
··· 92 92 '@stackblitz/sdk': 93 93 specifier: 1.11.0 94 94 version: 1.11.0 95 + vue3-select-component: 96 + specifier: 0.11.8 97 + version: 0.11.8(vue@3.5.13(typescript@5.8.3)) 95 98 devDependencies: 96 99 sharp: 97 100 specifier: 0.33.5 ··· 4775 4778 4776 4779 '@rollup/rollup-linux-x64-gnu@4.41.1': 4777 4780 resolution: {integrity: sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==} 4781 + cpu: [x64] 4782 + os: [linux] 4783 + 4784 + '@rollup/rollup-linux-x64-gnu@4.44.0': 4785 + resolution: {integrity: sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==} 4778 4786 cpu: [x64] 4779 4787 os: [linux] 4780 4788 ··· 11710 11718 hasBin: true 11711 11719 peerDependencies: 11712 11720 typescript: '>=5.0.0' 11721 + 11722 + vue3-select-component@0.11.8: 11723 + resolution: {integrity: sha512-fNFZXg/fwrels/xYH3URXkV4df4mPxy4q35DZMjUth6u1JUGYHTci29ND5GgNmQncS2vQeMyeTzejqlQD16zOA==} 11724 + peerDependencies: 11725 + vue: ^3.5.0 11713 11726 11714 11727 vue@3.5.13: 11715 11728 resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} ··· 16227 16240 '@rollup/rollup-linux-x64-gnu@4.41.1': 16228 16241 optional: true 16229 16242 16243 + '@rollup/rollup-linux-x64-gnu@4.44.0': 16244 + optional: true 16245 + 16230 16246 '@rollup/rollup-linux-x64-musl@4.31.0': 16231 16247 optional: true 16232 16248 ··· 17627 17643 17628 17644 axios@1.8.2: 17629 17645 dependencies: 17630 - follow-redirects: 1.15.9(debug@4.4.0) 17646 + follow-redirects: 1.15.9 17631 17647 form-data: 4.0.2 17632 17648 proxy-from-env: 1.1.0 17633 17649 transitivePeerDependencies: ··· 19558 19574 focus-trap@7.6.4: 19559 19575 dependencies: 19560 19576 tabbable: 6.2.0 19577 + 19578 + follow-redirects@1.15.9: {} 19561 19579 19562 19580 follow-redirects@1.15.9(debug@4.4.0): 19563 19581 optionalDependencies: ··· 24857 24875 '@volar/typescript': 2.4.12 24858 24876 '@vue/language-core': 2.2.0(typescript@5.8.3) 24859 24877 typescript: 5.8.3 24878 + 24879 + vue3-select-component@0.11.8(vue@3.5.13(typescript@5.8.3)): 24880 + dependencies: 24881 + vue: 3.5.13(typescript@5.8.3) 24882 + optionalDependencies: 24883 + '@rollup/rollup-linux-x64-gnu': 4.44.0 24860 24884 24861 24885 vue@3.5.13(typescript@5.8.3): 24862 24886 dependencies: