vld-ts 0.3.0

Generate TypeScript Zod schemas from vld schemas and types
Documentation

Crates.io docs.rs License Platform GitHub issues GitHub stars

vld-ts

Generate TypeScript Zod and Valibot schemas directly from vld schemas and types.

Overview

vld-ts is vld-first: use your vld schemas/types as the source of truth and generate frontend Zod/Valibot from them.

Installation

[dependencies]
vld-ts = "0.1"

Quick start

use vld_ts::{
    impl_to_openapi, impl_to_valibot, impl_to_zod, openapi_refs, to_openapi, to_valibot, to_zod,
    ToOpenApi, ToRefs, ToValibot, ToZod,
};

vld::schema! {
    pub struct Address {
        pub city: String => vld::string().min(1),
    }
}

vld::schema! {
    pub struct Order {
        pub shipping: Address => vld::nested!(Address),
    }
}

impl_to_zod!(Order);
impl_to_valibot!(Order);
impl_to_openapi!(Order);
impl_to_openapi!(Address);

// From schema instance
let zod = to_zod(&vld::string().min(2).email());
assert!(zod.contains(".email()"));

// From vld type (single schema expression, no imports/exports)
let order_zod = Order::to_zod();
assert!(order_zod.starts_with("z.object("));
assert!(order_zod.contains("shipping: z.lazy(() => AddressSchema)"));
assert!(!order_zod.contains("import { z } from \"zod\""));


// Valibot from schema instance
let single_valibot = to_valibot(&vld::string().min(2).email());
assert!(single_valibot.contains("v.string()"));
assert!(single_valibot.contains("v.email()"));

// Valibot from vld type (single schema expression, no imports/exports)
let order_valibot = Order::to_valibot();
assert!(order_valibot.starts_with("v.object"));
assert!(order_valibot.contains("shipping: v.lazy(() => AddressSchema)"));
assert!(!order_valibot.contains("import * as v from \"valibot\""));


// OpenAPI schema object from schema instance
let email_schema = to_openapi(&vld::string().email());
assert_eq!(email_schema["type"], "string");

// OpenAPI schema object from vld type
let openapi_schema = Address::to_openapi();
assert_eq!(openapi_schema["type"], "object");
let refs = openapi_refs(&Order::to_openapi());
assert!(refs.contains(&"#/components/schemas/Address".to_string()));
let refs2 = Order::to_refs();
assert!(refs2.contains(&"#/components/schemas/Address".to_string()));

Generated output

// Auto-generated by vld-ts — do not edit manually
import { z } from "zod";

export const UserSchema = z.object({
  name: z.string().min(2).max(50),
  email: z.string().email(),
  age: z.number().int().min(0).optional()
});
export type User = z.infer<typeof UserSchema>;

export const EmailSchema = z.string().email();
export type Email = z.infer<typeof EmailSchema>;
// Auto-generated by vld-ts — do not edit manually
import * as v from "valibot";

export const UserSchema = v.objectWithRest({
  name: v.pipe(v.string(), v.minLength(2), v.maxLength(50)),
  email: v.pipe(v.string(), v.email())
}, v.unknown());
export type User = v.InferOutput<typeof UserSchema>;

Supported output features

JSON Schema Zod output
type: "string" z.string()
type: "number" z.number()
type: "integer" z.number().int()
type: "boolean" z.boolean()
type: "null" z.null()
type: "array" z.array(...)
type: "object" z.object({...})
oneOf z.union([...])
allOf z.intersection(...)
anyOf z.union([...])
enum z.literal(...) / z.union()
format: "email" .email()
format: "uuid" .uuid()
format: "date"/"date-time" .date() / .datetime()
minLength/maxLength .min()/.max()
minimum/maximum .min()/.max()
pattern .regex()
description .describe()
nullable (oneOf + null) .nullable()
$ref to named schemas z.lazy(() => NameSchema)

Examples

cargo run -p vld-ts --example generate_zod

License

MIT