Coder Social home page Coder Social logo

supervillain's Introduction

Supervillain

Converts Go structs to Zod schemas.

Usage:

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:

export const PostSchema = z.object({
  title: z.string(),
});
export type Post = z.infer<typeof PostSchema>;

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<typeof UserSchema>;

Custom Types

ZodSchema() method

You can define a custom conversion using a ZodSchema() method. This should have one of the following types:

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.

type State int

func (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:

export const JobSchema = z.object({
  State: z.string(),
})
export type Job = z.infer<typeof JobSchema>

Mapping

If you don't control the type yourself, you can also pass a map of type names to custom conversion functions:

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:

export const UserSchema = z.object({
  Money: z.string(),
})
export type User = z.infer<typeof UserSchema>

There are some custom types with tests in the "custom" directory.

The function signature for custom type handlers is:

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:

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.

supervillain's People

Contributors

southclaws avatar m4tty-d avatar 8gian avatar josiah-tt avatar joshuatokentransit avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.