Skip to content

Commit be44483

Browse files
authored
fix: cleanup zod generation (#170)
1 parent c55af88 commit be44483

2 files changed

Lines changed: 64 additions & 65 deletions

File tree

scripts/generate.js

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ async function main() {
2020
const jsonSchema = JSON.parse(
2121
schemaSrc.replaceAll("#/$defs/", "#/components/schemas/"),
2222
);
23+
addExperimentalTags(jsonSchema);
24+
const schemaDefs = jsonSchema.$defs;
25+
2326
await createClient({
2427
input: {
2528
openapi: "3.1.0",
@@ -37,6 +40,7 @@ async function main() {
3740
},
3841
plugins: [
3942
{
43+
compatibilityVersion: 4,
4044
name: "zod",
4145
"~resolvers": createDeserializationResolvers(),
4246
},
@@ -45,33 +49,11 @@ async function main() {
4549
],
4650
});
4751

48-
const schemaDefs = JSON.parse(
49-
await fs.readFile("./schema/schema.json", "utf8"),
50-
).$defs;
51-
5252
const zodPath = "./src/schema/zod.gen.ts";
5353
const zodSrc = await fs.readFile(zodPath, "utf8");
54-
const zod = await prettier.format(
55-
updateDocs(
56-
zodSrc
57-
.replace(`from "zod"`, `from "zod/v4"`)
58-
// Weird type issue
59-
.replaceAll(
60-
/z\.record\((?!z\.string\(\),\s*)([^)]+)\)/g,
61-
"z.record(z.string(), $1)",
62-
)
63-
.replaceAll(
64-
/z\.coerce\s*\.bigint\(\)\s*\.min\(BigInt\("-9223372036854775808"\),\s*\{\s*message:\s*"Invalid value: Expected int64 to be >= -9223372036854775808",\s*\}\s*\)\s*\.max\(BigInt\("9223372036854775807"\),\s*\{\s*message:\s*"Invalid value: Expected int64 to be <= 9223372036854775807",\s*\}\s*\)/gm,
65-
"z.number()",
66-
)
67-
.replaceAll(
68-
/z\.coerce\s*\.bigint\(\)\s*\.gte\(BigInt\(0\)\)\s*\.max\(BigInt\("18446744073709551615"\),\s*\{\s*message:\s*"Invalid value: Expected uint64 to be <= 18446744073709551615",\s*\}\s*\)/gm,
69-
"z.number()",
70-
),
71-
schemaDefs,
72-
),
73-
{ parser: "typescript" },
74-
);
54+
const zod = await prettier.format(updateDocs(zodSrc, schemaDefs), {
55+
parser: "typescript",
56+
});
7557
await fs.writeFile(zodPath, zod);
7658

7759
const tsPath = "./src/schema/types.gen.ts";
@@ -171,15 +153,30 @@ function updateDocs(src, schemaDefs) {
171153
}
172154
}
173155

174-
// Replace UNSTABLE comments with @experimental at the end of the comment block
175-
result = result.replace(
176-
/(\/\*\*[\s\S]*?\*\*UNSTABLE\*\*[\s\S]*?)(\n\s*)\*\//g,
177-
"$1$2*$2* @experimental$2*/",
178-
);
179-
180156
return result;
181157
}
182158

159+
function addExperimentalTags(value) {
160+
if (Array.isArray(value)) {
161+
for (const item of value) addExperimentalTags(item);
162+
return;
163+
}
164+
165+
if (!value || typeof value !== "object") return;
166+
167+
if (
168+
typeof value.description === "string" &&
169+
value.description.includes("**UNSTABLE**") &&
170+
!value.description.includes("@experimental")
171+
) {
172+
value.description += "\n\n@experimental";
173+
}
174+
175+
for (const child of Object.values(value)) {
176+
addExperimentalTags(child);
177+
}
178+
}
179+
183180
function createDeserializationResolvers() {
184181
return {
185182
array(ctx) {
@@ -201,6 +198,15 @@ function createDeserializationResolvers() {
201198
return ctx.chain.current;
202199
},
203200

201+
number(ctx) {
202+
if (!shouldEmitNumberForBigIntFormat(ctx.schema.format)) {
203+
return undefined;
204+
}
205+
206+
ctx.chain.current = ctx.$(ctx.symbols.z).attr("number").call();
207+
return ctx.chain.current;
208+
},
209+
204210
object(ctx) {
205211
if (!hasDefaultOnErrorProperties(ctx.schema)) return undefined;
206212

@@ -248,6 +254,10 @@ function createDeserializationResolvers() {
248254
};
249255
}
250256

257+
function shouldEmitNumberForBigIntFormat(format) {
258+
return format === "int64" || format === "uint64";
259+
}
260+
251261
function childContext(ctx, ...segments) {
252262
return {
253263
path: ref([...fromRef(ctx.path), ...segments]),

src/schema/zod.gen.ts

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
requiredDefaultOnError,
66
vecSkipError,
77
} from "../schema-deserialize.js";
8-
import { z } from "zod/v4";
8+
import * as z from "zod/v4";
99

1010
/**
1111
* **UNSTABLE**
@@ -400,13 +400,12 @@ export const zErrorCode = z.union([
400400
z.literal(-32002),
401401
z.literal(-32042),
402402
z
403-
.number()
404403
.int()
405404
.min(-2147483648, {
406-
message: "Invalid value: Expected int32 to be >= -2147483648",
405+
error: "Invalid value: Expected int32 to be >= -2147483648",
407406
})
408407
.max(2147483647, {
409-
message: "Invalid value: Expected int32 to be <= 2147483647",
408+
error: "Invalid value: Expected int32 to be <= 2147483647",
410409
}),
411410
]);
412411

@@ -839,11 +838,10 @@ export const zNesDocumentDidSaveCapabilities = z.object({
839838
export const zNesEditHistoryCapabilities = z.object({
840839
_meta: z.record(z.string(), z.unknown()).nullish(),
841840
maxCount: z
842-
.number()
843841
.int()
844842
.gte(0)
845843
.max(4294967295, {
846-
message: "Invalid value: Expected uint32 to be <= 4294967295",
844+
error: "Invalid value: Expected uint32 to be <= 4294967295",
847845
})
848846
.nullish(),
849847
});
@@ -860,11 +858,11 @@ export const zNesEditHistoryEntry = z.object({
860858
* A code excerpt from a file.
861859
*/
862860
export const zNesExcerpt = z.object({
863-
endLine: z.number().int().gte(0).max(4294967295, {
864-
message: "Invalid value: Expected uint32 to be <= 4294967295",
861+
endLine: z.int().gte(0).max(4294967295, {
862+
error: "Invalid value: Expected uint32 to be <= 4294967295",
865863
}),
866-
startLine: z.number().int().gte(0).max(4294967295, {
867-
message: "Invalid value: Expected uint32 to be <= 4294967295",
864+
startLine: z.int().gte(0).max(4294967295, {
865+
error: "Invalid value: Expected uint32 to be <= 4294967295",
868866
}),
869867
text: z.string(),
870868
});
@@ -898,11 +896,10 @@ export const zNesRecentFile = z.object({
898896
export const zNesRecentFilesCapabilities = z.object({
899897
_meta: z.record(z.string(), z.unknown()).nullish(),
900898
maxCount: z
901-
.number()
902899
.int()
903900
.gte(0)
904901
.max(4294967295, {
905-
message: "Invalid value: Expected uint32 to be <= 4294967295",
902+
error: "Invalid value: Expected uint32 to be <= 4294967295",
906903
})
907904
.nullish(),
908905
});
@@ -994,11 +991,10 @@ export const zNesTriggerKind = z.union([
994991
export const zNesUserActionsCapabilities = z.object({
995992
_meta: z.record(z.string(), z.unknown()).nullish(),
996993
maxCount: z
997-
.number()
998994
.int()
999995
.gte(0)
1000996
.max(4294967295, {
1001-
message: "Invalid value: Expected uint32 to be <= 4294967295",
997+
error: "Invalid value: Expected uint32 to be <= 4294967295",
1002998
})
1003999
.nullish(),
10041000
});
@@ -1267,11 +1263,11 @@ export const zPlanUpdate = z.object({
12671263
* The meaning of `character` depends on the negotiated position encoding.
12681264
*/
12691265
export const zPosition = z.object({
1270-
character: z.number().int().gte(0).max(4294967295, {
1271-
message: "Invalid value: Expected uint32 to be <= 4294967295",
1266+
character: z.int().gte(0).max(4294967295, {
1267+
error: "Invalid value: Expected uint32 to be <= 4294967295",
12721268
}),
1273-
line: z.number().int().gte(0).max(4294967295, {
1274-
message: "Invalid value: Expected uint32 to be <= 4294967295",
1269+
line: z.int().gte(0).max(4294967295, {
1270+
error: "Invalid value: Expected uint32 to be <= 4294967295",
12751271
}),
12761272
});
12771273

@@ -1369,7 +1365,7 @@ export const zPromptCapabilities = z.object({
13691365
* This version is only bumped for breaking changes.
13701366
* Non-breaking changes should be introduced via capabilities.
13711367
*/
1372-
export const zProtocolVersion = z.number().int().gte(0).lte(65535);
1368+
export const zProtocolVersion = z.int().gte(0).lte(65535);
13731369

13741370
/**
13751371
* Request parameters for the initialize method.
@@ -2029,19 +2025,17 @@ export const zLoadSessionRequest = z.object({
20292025
export const zReadTextFileRequest = z.object({
20302026
_meta: z.record(z.string(), z.unknown()).nullish(),
20312027
limit: z
2032-
.number()
20332028
.int()
20342029
.gte(0)
20352030
.max(4294967295, {
2036-
message: "Invalid value: Expected uint32 to be <= 4294967295",
2031+
error: "Invalid value: Expected uint32 to be <= 4294967295",
20372032
})
20382033
.nullish(),
20392034
line: z
2040-
.number()
20412035
.int()
20422036
.gte(0)
20432037
.max(4294967295, {
2044-
message: "Invalid value: Expected uint32 to be <= 4294967295",
2038+
error: "Invalid value: Expected uint32 to be <= 4294967295",
20452039
})
20462040
.nullish(),
20472041
path: z.string(),
@@ -2374,19 +2368,17 @@ export const zStringPropertySchema = z.object({
23742368
enum: z.array(z.string()).nullish(),
23752369
format: zStringFormat.nullish(),
23762370
maxLength: z
2377-
.number()
23782371
.int()
23792372
.gte(0)
23802373
.max(4294967295, {
2381-
message: "Invalid value: Expected uint32 to be <= 4294967295",
2374+
error: "Invalid value: Expected uint32 to be <= 4294967295",
23822375
})
23832376
.nullish(),
23842377
minLength: z
2385-
.number()
23862378
.int()
23872379
.gte(0)
23882380
.max(4294967295, {
2389-
message: "Invalid value: Expected uint32 to be <= 4294967295",
2381+
error: "Invalid value: Expected uint32 to be <= 4294967295",
23902382
})
23912383
.nullish(),
23922384
oneOf: z.array(zEnumOption).nullish(),
@@ -2434,11 +2426,10 @@ export const zTerminal = z.object({
24342426
export const zTerminalExitStatus = z.object({
24352427
_meta: z.record(z.string(), z.unknown()).nullish(),
24362428
exitCode: z
2437-
.number()
24382429
.int()
24392430
.gte(0)
24402431
.max(4294967295, {
2441-
message: "Invalid value: Expected uint32 to be <= 4294967295",
2432+
error: "Invalid value: Expected uint32 to be <= 4294967295",
24422433
})
24432434
.nullish(),
24442435
signal: z.string().nullish(),
@@ -2808,7 +2799,7 @@ export const zElicitationUrlMode = z.intersection(
28082799
z.union([zElicitationSessionScope, zElicitationRequestScope]),
28092800
z.object({
28102801
elicitationId: zElicitationId,
2811-
url: z.string().url(),
2802+
url: z.url(),
28122803
}),
28132804
);
28142805

@@ -2823,11 +2814,10 @@ export const zElicitationUrlMode = z.intersection(
28232814
export const zToolCallLocation = z.object({
28242815
_meta: z.record(z.string(), z.unknown()).nullish(),
28252816
line: z
2826-
.number()
28272817
.int()
28282818
.gte(0)
28292819
.max(4294967295, {
2830-
message: "Invalid value: Expected uint32 to be <= 4294967295",
2820+
error: "Invalid value: Expected uint32 to be <= 4294967295",
28312821
})
28322822
.nullish(),
28332823
path: z.string(),
@@ -3282,11 +3272,10 @@ export const zWaitForTerminalExitRequest = z.object({
32823272
export const zWaitForTerminalExitResponse = z.object({
32833273
_meta: z.record(z.string(), z.unknown()).nullish(),
32843274
exitCode: z
3285-
.number()
32863275
.int()
32873276
.gte(0)
32883277
.max(4294967295, {
3289-
message: "Invalid value: Expected uint32 to be <= 4294967295",
3278+
error: "Invalid value: Expected uint32 to be <= 4294967295",
32903279
})
32913280
.nullish(),
32923281
signal: z.string().nullish(),

0 commit comments

Comments
 (0)