Skip to content

Commit 7f73e5b

Browse files
authored
Zod v4 (#300)
* generate zod validators as baseline * zod v4 * remove msw and zod from the repo * npm version minor
1 parent a59aec2 commit 7f73e5b

File tree

5 files changed

+34
-34
lines changed

5 files changed

+34
-34
lines changed

oxide-openapi-gen-ts/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

oxide-openapi-gen-ts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@oxide/openapi-gen-ts",
3-
"version": "0.8.1",
3+
"version": "0.9.0",
44
"description": "OpenAPI client generator used to generate Oxide TypeScript SDK",
55
"keywords": [
66
"oxide",

oxide-openapi-gen-ts/src/client/msw-handlers.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function generateMSWHandlers(spec: OpenAPIV3.Document, destDir: string) {
3333
type PathParams,
3434
} from "msw";
3535
import type { SnakeCasedPropertiesDeep as Snakify, Promisable } from "type-fest";
36-
import { type ZodSchema } from "zod";
36+
import { type ZodType } from "zod/v4";
3737
import type * as Api from "./Api";
3838
import { snakeify } from "./util";
3939
import * as schema from "./validate";
@@ -105,7 +105,7 @@ export function generateMSWHandlers(spec: OpenAPIV3.Document, destDir: string) {
105105
w("}");
106106

107107
w(`
108-
function validateParams<S extends ZodSchema>(schema: S, req: Request, pathParams: PathParams) {
108+
function validateParams<S extends ZodType>(schema: S, req: Request, pathParams: PathParams) {
109109
const rawParams = new URLSearchParams(new URL(req.url).search)
110110
const params: [string, unknown][] = []
111111
@@ -131,7 +131,9 @@ export function generateMSWHandlers(spec: OpenAPIV3.Document, destDir: string) {
131131
return { paramsErr: json({ error_code, message }, { status }) }
132132
}
133133
134-
const handler = (handler: MSWHandlers[keyof MSWHandlers], paramSchema: ZodSchema | null, bodySchema: ZodSchema | null) =>
134+
const handler = (handler: MSWHandlers[keyof MSWHandlers],
135+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
136+
paramSchema: ZodType<any> | null, bodySchema: ZodType | null) =>
135137
async ({
136138
request: req,
137139
params: pathParams,

oxide-openapi-gen-ts/src/client/zodValidators.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function generateZodValidators(
2929

3030
w(`/* eslint-disable */
3131
32-
import { z, ZodType } from 'zod';
32+
import { z, ZodType } from 'zod/v4';
3333
import { processResponseBody, uniqueItems } from './util';
3434
3535
/**

oxide-openapi-gen-ts/src/schema/zod.ts

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,33 +38,33 @@ export const schemaToZod = makeSchemaGenerator({
3838
},
3939

4040
string(schema, { w0 }) {
41-
w0(`z.string()`);
42-
43-
if ("default" in schema) {
44-
w0(`.default(${JSON.stringify(schema.default)})`);
45-
}
41+
// Handle special formats that become standalone in Zod v4
4642
if (schema.format === "uuid") {
47-
w0(".uuid()");
48-
}
49-
50-
if (schema.format === "ip") {
51-
w0(".ip()");
43+
w0("z.uuid()");
44+
} else if (schema.format === "ip") {
45+
// Generic IP becomes IPv4 for backward compatibility
46+
w0("z.ipv4()");
5247
} else if (schema.format === "ipv4") {
53-
w0(".ip({ version: 'v4' })");
48+
w0("z.ipv4()");
5449
} else if (schema.format === "ipv6") {
55-
w0(".ip({ version: 'v6' })");
56-
}
50+
w0("z.ipv6()");
51+
} else {
52+
// Regular string handling
53+
w0(`z.string()`);
5754

58-
if ("minLength" in schema) {
59-
w0(`.min(${schema.minLength})`);
60-
}
61-
if ("maxLength" in schema) {
62-
w0(`.max(${schema.maxLength})`);
63-
}
64-
if ("pattern" in schema) {
65-
w0(`.regex(${new RegExp(schema.pattern!).toString()})`);
55+
if ("minLength" in schema) {
56+
w0(`.min(${schema.minLength})`);
57+
}
58+
if ("maxLength" in schema) {
59+
w0(`.max(${schema.maxLength})`);
60+
}
61+
if ("pattern" in schema) {
62+
w0(`.regex(${new RegExp(schema.pattern!).toString()})`);
63+
}
6664
}
65+
6766
if (schema.nullable) w0(".nullable()");
67+
if ("default" in schema) w0(`.default(${JSON.stringify(schema.default)})`);
6868
},
6969

7070
date(schema, { w0 }) {
@@ -98,7 +98,7 @@ export const schemaToZod = makeSchemaGenerator({
9898
const { w0, w } = io;
9999
// record type, which only tells us the type of the values
100100
if (!schema.properties || Object.keys(schema.properties).length === 0) {
101-
w0("z.record(z.string().min(1),");
101+
w0("z.record(z.string(),");
102102
if (typeof schema.additionalProperties === "object") {
103103
schemaToZod(schema.additionalProperties, io);
104104
} else {
@@ -179,14 +179,12 @@ export const schemaToZod = makeSchemaGenerator({
179179
w("])");
180180
}
181181

182-
if ("default" in schema) {
183-
w0(`.default(${JSON.stringify(schema.default)})`);
184-
}
185-
if (schema.nullable) io.w0(".nullable()");
182+
if (schema.nullable) w0(".nullable()");
183+
if ("default" in schema) w0(`.default(${JSON.stringify(schema.default)})`);
186184
},
187185

188186
empty({ w0 }) {
189-
w0("z.record(z.unknown())");
187+
w0("z.record(z.string(), z.unknown())");
190188
},
191189

192190
default(schema) {

0 commit comments

Comments
 (0)