Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Southclaws/supervillain
Converts Go structs to Zod schemas
https://github.com/Southclaws/supervillain
go go-generics schemas typescript zod
Last synced: 2 months ago
JSON representation
Converts Go structs to Zod schemas
- Host: GitHub
- URL: https://github.com/Southclaws/supervillain
- Owner: Southclaws
- License: mit
- Created: 2021-08-21T18:08:39.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-07-05T09:26:48.000Z (7 months ago)
- Last Synced: 2024-07-26T01:53:39.405Z (6 months ago)
- Topics: go, go-generics, schemas, typescript, zod
- Language: Go
- Homepage:
- Size: 51.8 KB
- Stars: 66
- Watchers: 4
- Forks: 6
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-zod - `Supervillain` - Generate Zod schemas from your Go structs. (Convertors and Generators)
README
# Supervillain
Converts Go structs to Zod schemas.
Usage:
```go
type Post struct {
Title string
}
type User struct {
Name string
Nickname *string // pointers become optional
Age int
Height float64
Tags []string
Favourites []struct { // nested structs are kept inline
Name string
}
Posts []Post // external structs are emitted as separate exports
}StructToZodSchema(User{})
```Outputs:
```typescript
export const PostSchema = z.object({
title: z.string(),
});
export type Post = z.infer;export const UserSchema = z.object({
name: z.string(),
nickname: z.string().optional(),
age: z.number(),
height: z.number(),
tags: z.string().array(),
favourites: z
.object({
name: z.string(),
})
.array(),
posts: PostSchema.array(),
});
export type User = z.infer;
```## Custom Types
### ZodSchema() method
You can define a custom conversion using a `ZodSchema()` method. This should have one of the following types:
```go
ZodSchema() string
ZodSchema(c *supervillain.Converter, t reflect.Type, name, generic string, indent int) string
ZodSchema(convert func(t reflect.Type, name string, indent int) string, t reflect.Type, name, generic string, indent int) string
```
(The first signature is available to simplify the simple case; the last signature is available in case you do not want the package defining the type to depend on supervillain.)Zod will obtain a schema by creating a zero value of your type and calling its ZodSchema() method.
```go
type State intfunc (s State) MarshalJSON() ([]byte, error) {
return json.Marshal(fmt.Sprint(s))
}func (s State) ZodSchema() string {
return "z.string()"
}type Job struct {
State State
}c.Convert(Job{})
```Outputs:
```typescript
export const JobSchema = z.object({
State: z.string(),
})
export type Job = z.infer
```### Mapping
If you don't control the type yourself, you can also pass a map of type names to custom conversion functions:
```go
c := supervillain.NewConverter(map[string]supervillain.CustomFn{
"github.com/shopspring/decimal.Decimal": func(c *supervillain.Converter, t reflect.Type, s, g string, i int) string {
// Shopspring's decimal type serialises to a string.
return "z.string()"
},
})c.Convert(User{
Money decimal.Decimal
})
```Outputs:
```typescript
export const UserSchema = z.object({
Money: z.string(),
})
export type User = z.infer
```There are some custom types with tests in the "custom" directory.
The function signature for custom type handlers is:
```go
func(c *supervillain.Converter, t reflect.Type, typeName, genericTypeName string, indentLevel int) string
```You can use the Converter to process nested types. The `genericTypeName` is the name of the `T` in `Generic[T]` and the indent level is for passing to other converter APIs.
### Custom Schema Enforcement
Types with a custom MarshalJSON() method but no custom schema are typically problematic, since the generated schema may not match the custom marshalled format. You can use the `WithStrictCustomSchemas` option to cause conversion to fail (panic) if such a type is found:
```go
c := NewConverter(map[string]CustomFn{}, WithStrictCustomSchemas(true))
// or
StructToZodSchema(User{}, WithStrictCustomSchemas(true))
```## Caveats
- Does not support self-referential types - should be a simple fix.
- Sometimes outputs in the wrong order - it really needs an intermediate DAG to solve this.