2.5.0 • Published 9 months ago

@ymgn-dev/zodify v2.5.0

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

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 git@github.com: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.

SyntaxNotes
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

TypeNotes
integerConverts to z.number().int()
int64Converts to z.number().int()
int32Converts to z.number().int()
int16Converts to z.number().int()
int8Converts to z.number().int()
safeintConverts to z.number().int()
uint64Converts to z.number().int()
uint32Converts to z.number().int()
uint16Converts to z.number().int()
uint8Converts to z.number().int()
numericConverts to z.number()
floatConverts to z.number()
float64Converts to z.number()
float32Converts to z.number()
decimalConverts to z.number()
decimal128Converts to z.number()
DecoratorNotes
@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.

TypeNotes
stringConverts to z.string()
plainDateConverts to z.string().date()
plainTimeConverts to z.string().time()
utcDateTimeConverts to z.string().datetime()
offsetDateTimeConverts to z.string().datetime()
durationConverts to z.string().duration()
urlConverts to z.string().url()
DecoratorNotes
@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

TypeNotes
booleanConverts 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.

TypeNotes
Element[]Converts to z.array(elementSchema)
DecoratorNotes
@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, and never are not currently supported.

2.5.0

9 months ago

2.4.0

9 months ago

2.3.0

9 months ago

2.2.0

9 months ago

2.1.0

9 months ago

2.0.0

10 months ago

1.1.1

10 months ago

1.1.0

10 months ago

1.0.2

10 months ago

1.0.1

10 months ago

1.0.0

10 months ago