@ymgn-dev/zodify
v2.5.0
Published
TypeSpec to Zod schema generator
Downloads
373
Readme
Zodify
A tool that generates Zod type definitions from OpenAPI YAML.
[!WARNING] Please note that this tool only targets YAML generated based on TypeSpec definitions.
Japanese version: README_ja.md
Setup
git clone [email protected]:ymgn-dev/zodify.git
cd zodify
npm run build
Usage
Specify the OpenAPI YAML file with the -i
option and the output .ts
file with the -o
option.
node dist/index.mjs -i ./path/to/openapi.yaml -o ./path/to/output.ts
Supported Syntax
Comment Decorators
You can add comments to models and properties using the @doc()
decorator.
@doc("This is a comment for the model")
model SampleModel {
@doc("This is the model's ID")
@format("uuid")
id: string;
@doc("Creation date")
createdAt: utcDateTime;
@doc("Update date")
updatedAt: utcDateTime;
}
The above model will be converted as follows:
// This is a comment for the model
export const sampleModelSchema = z.object({
// This is the model's ID
id: z.string().uuid(),
// Creation date
createdAt: z.string().datetime(),
// Update date
updatedAt: z.string().datetime(),
})
Additionally, if you want to generate Zod schemas that cannot be expressed using the standard decorators below, you can use an extended notation for the @doc()
decorator.
Write regular comments (optional) to the left of zod:
, and the Zod schema on the right.
Note that when using this extended notation, the type-specific decorators below will be ignored.
model SampleModel {
@doc("Email address, unset defaults to an empty string zod: z.union([z.string().email(), z.literal("")]).default("")")
email: string;
}
export const sampleModelSchema = z.object({
// Email address, unset defaults to an empty string
email: z.union([z.string().email(), z.literal('')]).default(''),
})
Models
This syntax is used for defining top-level models.
| Syntax | Notes |
| --- | --- |
| model Element { }
| Converts to z.object({ ... })
|
| model Elements is Array<Element> { }
| Converts to z.array(...)
|
| enum Element { }
| Converts to z.enum([ ... ])
|
model SampleModel {
a: numeric;
b: string;
}
model ArraySampleModel is Array<SampleModel> {}
enum EnumSample {
A,
B,
C
}
Scalars
This syntax is used for defining types that do not exist in TypeSpec.
@doc("UUID")
@format("uuid")
scalar Uuid extends string;
@doc("Integer greater than 100")
@minValueExclusive(100)
scalar Gt100 extends int32;
The above model will be converted as follows:
// UUID
export const uuidSchema = z.string().uuid()
// Integer greater than 100
export const gt100Schema = z.number().int().gt(100)
Numbers
| Type | Notes |
| --- | --- |
| integer | Converts to z.number().int()
|
| int64 | Converts to z.number().int()
|
| int32 | Converts to z.number().int()
|
| int16 | Converts to z.number().int()
|
| int8 | Converts to z.number().int()
|
| safeint | Converts to z.number().int()
|
| uint64 | Converts to z.number().int()
|
| uint32 | Converts to z.number().int()
|
| uint16 | Converts to z.number().int()
|
| uint8 | Converts to z.number().int()
|
| numeric | Converts to z.number()
|
| float | Converts to z.number()
|
| float64 | Converts to z.number()
|
| float32 | Converts to z.number()
|
| decimal | Converts to z.number()
|
| decimal128 | Converts to z.number()
|
| Decorator | Notes |
| --- | --- |
| @minValue(42)
| Converts to .gte(42)
|
| @maxValue(42)
| Converts to .lte(42)
|
| @minValueExclusive(8)
| Converts to .gt(8)
|
| @maxValueExclusive(8)
| Converts to .lt(8)
|
Additional Notes
To make properties in a TypeSpec model optional, add a ?
after the property name.
You can also set default values using =
. It is possible to combine both optional and default values.
model Sample {
a?: int32;
b: integer = 42;
c?: float = 3.14;
}
The above model will be converted as follows:
export const sampleSchema = z.object({
a: z.number().int().optional(),
b: z.number().int().default(42),
c: z.number().optional().default(3.14),
})
@doc("Numeric values")
model NumericValues {
@minValue(42.6)
@maxValue(95.8)
a: numeric;
@minValueExclusive(8)
@maxValueExclusive(16)
b: integer;
@doc("Optional input")
c: float;
@doc("Has a default value")
d: int64 = 42;
e: int32;
f: int16;
g: int8;
h: safeint;
i: uint64;
j: uint32;
k: uint16;
l: uint8;
m: float64;
n: float32;
o: decimal;
p: decimal128;
}
Strings
[!WARNING]
bytes
is not supported because it is not defined in Zod.
[!NOTE] Some types are not supported in TypeSpec but are supported in Zod. These types can be converted using the
@format()
decorator described below.
| Type | Notes |
| --- | --- |
| string | Converts to z.string()
|
| plainDate | Converts to z.string().date()
|
| plainTime | Converts to z.string().time()
|
| utcDateTime | Converts to z.string().datetime()
|
| offsetDateTime | Converts to z.string().datetime()
|
| duration | Converts to z.string().duration()
|
| url | Converts to z.string().url()
|
| Decorator | Notes |
| --- | --- |
| @minLength(42)
| Converts to .min(42)
|
| @maxLength(42)
| Converts to .max(42)
|
| @format("date")
| Equivalent to plainDate type, converts to .date()
|
| @format("time")
| Equivalent to plainTime type, converts to .time()
|
| @format("date-time")
| Equivalent to utcDateTime and offsetDateTime types, converts to .datetime()
|
| @format("duration")
| Equivalent to duration type, converts to .duration()
|
| @format("uri")
| Equivalent to url type, converts to .url()
|
| @format("email")
| Converts to .email()
|
| @format("uuid")
| Converts to .uuid()
|
| @format("cuid")
| Converts to .cuid()
|
| @format("ip")
| Converts to .ip()
|
Additional Notes
To make properties in a TypeSpec model optional, add a ?
after the property name.
You can also set default values using =
. It is possible to combine both optional and default values.
model Sample {
a?: string;
b: string = "Sample string";
c?: string = "Sample string";
}
The above model will be converted as follows:
export const sampleSchema = z.object({
a: z.string().optional(),
b: z.string().default('Sample string'),
c: z.string().optional().default('Sample string'),
})
@doc("String values")
model StringValues {
@minLength(42)
@maxLength(96)
a: string;
b: plainDate;
c: plainTime;
d: utcDateTime;
e: offsetDateTime;
f: duration;
g: url;
@format("email")
h: string;
@format("uuid")
i: string;
}
Booleans
| Type | Notes |
| --- | --- |
| boolean | Converts to z.boolean()
|
Additional Notes
To make properties in a TypeSpec model optional, add a ?
after the property name.
You can also set default values using =
. It is possible to combine both optional and default values.
model Sample {
a?: boolean;
b: boolean = true;
c?: boolean = false;
}
The above model will be converted as follows:
export const sampleSchema = z.object({
a: z.boolean().optional(),
b: z.boolean().default(true),
c: z.boolean().optional().default(false),
})
@doc("Boolean values")
model BooleanValues {
a: boolean;
}
Arrays, Objects, and Enums
[!WARNING]
Record<Element>
is not currently supported.
| Type | Notes |
| --- | --- |
| Element[] | Converts to z.array(elementSchema)
|
| Decorator | Notes |
| --- | --- |
| @minItems(42)
| Converts to .min(42)
|
| @maxItems(42)
| Converts to .max(42)
|
Additional Notes
To make properties in a TypeSpec model optional, add a ?
after the property name.
You can also set default values using =
. For arrays, TypeSpec requires default values to be written as #[...]
.
It is possible to combine both optional and default values.
model OtherModel {
@format("uuid")
id: string;
}
@doc("Array test")
model Sample {
a?: string[];
b: string[] = #["sample1", "sample2"];
c?: string[] = #[];
d: int32[] = #[4, 8, 32];
e: OtherModel[] = #[];
}
The above model will be converted as follows:
export const otherModelSchema = z.object({
id: z.string().uuid(),
})
// Array test
export const sampleSchema = z.object({
a: z.array(z.string()).optional(),
b: z.array(z.string()).default(['sample1', 'sample2']),
c: z.array(z.string()).optional().default([]),
d: z.array(z.number().int()).default([4, 8, 32]),
e: z.array(otherModelSchema).default([]),
})
@doc("Arrays")
model ArrayValues {
@minItems(42)
@maxItems(96)
a: string[];
b: OtherModel[];
}
Others
[!WARNING]
null
,unknown
,void
, andnever
are not currently supported.