npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

eslint-plugin-zod-to-openapi

v0.0.26

Published

Eslint rules for zod-to-openapi

Downloads

325

Readme

eslint-plugin-zod-to-openapi

npm version npm downloads Powered by skuba

Intoduction

This is a set of Eslint rules created for use with @asteasolutions/zod-to-openapi. As a contributor and major user of the library, there are some learnings with using the library by itself and this package hopes to address those issues as well as optimise the overall developer experience with a sprinkle of magic ✨.

Table of Contents

Installation

To install simply run on yarn or npm

yarn add -D eslint-plugin-zod-to-openapi
# or
npm i -D eslint-plugin-zod-to-openapi

Add the following configuration to your .eslintrc file

{
  "plugins": ["zod-to-openapi"]
}
{
  "rules": {
    "zod-to-openapi/require-openapi": "error"
    "zod-to-openapi/require-comment": "error",
    "zod-to-openapi/prefer-zod-default": "warn",
  }
}

You may wish to use overrides as this plugin by default will assume that all Zod Objects are using zod-to-openapi.

"overrides": [
    {
      "files": ["src/api-types/*.ts"],
      "rules": {
        "zod-to-openapi/require-openapi": "error"
      }
    }
  ]

Rules

🔧 = autofixable

require-openapi

Requires that all Zod schemas have an .openapi() method. In order for your generated documentation to appear nice, you need to provide metadata for your types.

A simple example

const NameSchema = z.string(); // ❌ error
const NameSchema = z.string().openapi({ description: "A user's name" }); // ✅ correct

This rule is best used in conjunction with the require-comment rule. To avoid costly traversal we use the Typescript compiler to check the type and also consider any referenced variable which has a jsDoc comment as having an .openapi() field.

A complex example

/**
 * A user's name
 **/
const NameSchema = z.string().openapi({ description: "A user's name" });

const IdSchema = z.string().uuid();

/**
 * Other Schema
 **/
const OtherSchema = z
  .object({
    /**
     * A user's age
     **/
    age: z.number().openapi({ description: "A user's age" }),
  })
  .openapi({ description: 'Other Schema' });

const PersonSchema = z
  .object({
    /**
     * A user's name
     **/
    name: NameSchema, // ✅ correct
    id: IdSchema, // ❌ error (IdSchema has no comment)
    /**
     * A user's name
     **/
    age: OtherSchema.shape.age, // ✅ correct
  })
  .openapi({ description: 'Person' });

This rule also requires that all Zod Schemas in the OpenAPIRegistry.register method require an .openapi() method.

const registry = new OpenAPIRegistry();

export const ZodObject = registry.register(
  'registered',
  z.string().openapi({ description: 'hello' }), // ✅ correct
);

require-comment 🔧

This rule was rhe inspiration for the entire package. It requires that all Zod schemas which have an .openapi() object have a description and matching jsDoc comment.

In order for your IDE to display descriptions in inferred types, it requires JsDoc comments. This rule autogenerates comments based on your description example or examples and deprecated fields and adds it to your ZodSchema. These appear in both the inferred and actual ZodSchema. This rule is autofixable.

A simple example

const NameSchema = z.string().openapi({ example: 'Fred' }); // ❌ error (no description or comment)

/**
 * A user's name
 **/
const NameSchema = z
  .string()
  .openapi({ description: "A user's name", example: 'Fred' }); // ✅ correct

This rule is also able to infer JsDoc comments from other variables and automatically copies the comments across where otherwise you would gain no type comments.

A more complex example:

/**
 * @deprecated A user's name
 **/
const NameSchema = z
  .string()
  .openapi({ description: "A user's name", example: 'Fred', deprecated: true }); // ✅ correct

/**
 * Person
 **/
const PersonSchema = z
  .object({
    /**
     * @deprecated A user's name  // ℹ️ this comment is synced with NameSchema
     **/
    name: NameSchema, // ℹ️ This type will be marked as deprecated in your IDE
    /**
     * A user's age
     **/
    age: z
      .number()
      .positive()
      .int()
      .openapi({ description: "A user's age", example: 12 }),
  })
  .openapi({ description: 'Person' });

/**
 * Person
 **/
type Person = z.infer<typeof PersonSchema>; // ℹ️ This comment is synced with PersonSchema. This does not work for indexed access eg. z.infer<typeof PersonSchema>['name'].

require-example

Requires that the .openapi() method contains an example, examples key for Zod primatives. This makes our generated documentation much nicer. This includes:

  • ZodBoolean
  • ZodNumber
  • ZodString
  • ZodRecord
  • ZodEnum
const UserIdSchema = z.string().uuid(); // ❌ error (no example)
const UserIdSchema = z
  .string()
  .uuid()
  .openapi({ example: '48948579-f117-47e4-bc05-12f28e7fdccd' }); // ✅ correct

By default this rule looks for the example key. If you wish to use the examples key which is required in Open API 3.1 pass the key examples in the options argument of your rule configuration.

eg. 'zod-to-openapi/require-example': ['error', 'examples']

prefer-openapi-last

Prefers that the .openapi() method be the last call in a Zod Schema chain. This is done mainly out of consistency but also because there are some methods that can override the .openapi() method. eg. pick, omit

A simple example

const NameSchema = z.string().openapi({ example: 'Fred' }).length(5); // ❌ error

const NameSchema = z.string().length(5).openapi({ example: 'Fred' }); // ✅ correct

prefer-zod-default

Provides an error when the .openapi() default option is provided. ZodDefault should be used instead.

A simple example

const NameSchema = z.string().openapi({ example: 'Fred', default: 'Fred' }); // ❌ error
const NameSchema = z.string().default('Fred').openapi({ example: 'Fred' }); // ✅ correct

Development

Test

yarn test

Lint

# Fix issues
yarn format

# Check for issues
yarn lint

Package

# Compile source
yarn build

# Review bundle
npm pack

Release

This package is published to the public npm registry with a GitHub Actions release workflow.

The workflow runs on select branches:

on:
  push:
    branches:
      # add others as necessary
      - beta
      - master
      # - alpha

It depends on this repo being hosted on [seek-oss] with appropriate access.

To set up this repo for publishing, follow the instructions in our [OSS npm package guidance].

Commit messages

This package is published with semantic-release, which requires a particular commit format to manage semantic versioning. You can run the interactive yarn commit command in place of git commit to generate a compliant commit title and message. If you use the Squash and merge option on pull requests, take extra care to format the squashed commit in the GitHub UI before merging.

Releasing latest

Commits to the master branch will be released with the latest tag, which is the default used when running npm install or yarn install.

Releasing other dist-tags

semantic-release prescribes a branch-based workflow for managing distribution tags.

You can push to other branches to manage betas, maintenance updates to prior major versions, and more.

Here are some branches that semantic-release supports by default:

| Git branch | npm dist-tag | | :--------- | :----------- | | master | latest | | alpha | alpha | | beta | beta | | next | next | | 1.x | release-1.x |

For more information, see the semantic-release docs on triggering a release.