Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.

This commit is contained in:
becarta
2025-05-23 12:43:00 +02:00
parent f40db0f5c9
commit a544759a3b
11127 changed files with 1647032 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

1
node_modules/zod-to-json-schema/.github/FUNDING.yml generated vendored Normal file
View File

@@ -0,0 +1 @@
github: [StefanTerdell]

1
node_modules/zod-to-json-schema/.prettierrc.json generated vendored Normal file
View File

@@ -0,0 +1 @@
{}

15
node_modules/zod-to-json-schema/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,15 @@
ISC License
Copyright (c) 2020, Stefan Terdell
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

398
node_modules/zod-to-json-schema/README.md generated vendored Normal file
View File

@@ -0,0 +1,398 @@
# Zod to Json Schema
[![NPM Version](https://img.shields.io/npm/v/zod-to-json-schema.svg)](https://npmjs.org/package/zod-to-json-schema)
[![NPM Downloads](https://img.shields.io/npm/dw/zod-to-json-schema.svg)](https://npmjs.org/package/zod-to-json-schema)
_Looking for the exact opposite? Check out [json-schema-to-zod](https://npmjs.org/package/json-schema-to-zod)_
## Summary
Does what it says on the tin; converts [Zod schemas](https://github.com/colinhacks/zod) into [JSON schemas](https://json-schema.org/)!
- Supports all relevant schema types, basic string, number and array length validations and string patterns.
- Resolves recursive and recurring schemas with internal `$ref`s.
- Supports targeting legacy Open API 3.0 specification (3.1 supports regular Json Schema).
- Supports Open AI strict mode schemas (Optional object properties are replaced with required but nullable ones).
## Sponsors
A great big thank you to our amazing sponsors! Please consider joining them through my [GitHub Sponsors page](https://github.com/sponsors/StefanTerdell). Every cent helps, but these fellas have really gone above and beyond 💚:
<table align="center" style="justify-content: center;align-items: center;display: flex;">
<tr>
<td align="center">
<p></p>
<p>
<a href="https://retool.com/?ref=stefanterdell&utm_source=github&utm_medium=referral&utm_campaign=stefanterdell">
<picture height="45px">
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/colinhacks/zod/assets/3084745/ac65013f-aeb4-48dd-a2ee-41040b69cbe6">
<img alt="stainless" height="45px" src="https://github.com/colinhacks/zod/assets/3084745/5ef4c11b-efeb-4495-90a8-41b83f798600">
</picture>
</a>
<br />
Build AI apps and workflows with <a href="https://retool.com/products/ai?ref=stefanterdell&utm_source=github&utm_medium=referral&utm_campaign=stefanterdell">Retool AI</a>
<br/>
<a href="https://retool.com/?ref=stefanterdell&utm_source=github&utm_medium=referral&utm_campaign=stefanterdell" style="text-decoration:none;">retool.com</a>
</p>
<p></p>
</td>
</tr>
<tr>
<td align="center">
<p></p>
<p>
<div style="background-color: white; padding: 4px; padding-bottom: 8px;" alt="stainless">
<a href="https://www.coderabbit.ai/">
<picture height="45px">
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/eea24edb-ff20-4532-b57c-e8719f455d6d">
<img alt="CodeRabbit logo" height="45px" src="https://github.com/user-attachments/assets/d791bc7d-dc60-4d55-9c31-97779839cb74">
</picture>
</a>
</div>
<br />
Cut code review time & bugs in half
<br/>
<a href="https://www.coderabbit.ai/" style="text-decoration:none;">coderabbit.ai</a>
</p>
<p></p>
</td>
</tr>
</table>
## Usage
### Basic example
```typescript
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const mySchema = z
.object({
myString: z.string().min(5),
myUnion: z.union([z.number(), z.boolean()]),
})
.describe("My neat object schema");
const jsonSchema = zodToJsonSchema(mySchema, "mySchema");
```
#### Expected output
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/mySchema",
"definitions": {
"mySchema": {
"description": "My neat object schema",
"type": "object",
"properties": {
"myString": {
"type": "string",
"minLength": 5
},
"myUnion": {
"type": ["number", "boolean"]
}
},
"additionalProperties": false,
"required": ["myString", "myUnion"]
}
}
}
```
## Options
### Schema name
You can pass a string as the second parameter of the main zodToJsonSchema function. If you do, your schema will end up inside a definitions object property on the root and referenced from there. Alternatively, you can pass the name as the `name` property of the options object (see below).
### Options object
Instead of the schema name (or nothing), you can pass an options object as the second parameter. The following options are available:
| Option | Effect |
| ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **name**?: _string_ | As described above. |
| **nameStrategy**?: "ref" \| "title" | Adds name as "title" meta instead of as a ref as described above |
| **basePath**?: string[] | The base path of the root reference builder. Defaults to ["#"]. |
| **$refStrategy**?: "root" \| "relative" \| "seen" \| "none" | The reference builder strategy; <ul><li>**"root"** resolves $refs from the root up, ie: "#/definitions/mySchema".</li><li>**"relative"** uses [relative JSON pointers](https://tools.ietf.org/id/draft-handrews-relative-json-pointer-00.html). _See known issues!_</li><li>**"seen"** reuses the output of any "seen" Zod schema. In theory it's a more performant version of "none", but in practice this behaviour can cause issues with nested schemas and has now gotten its own option.</li> <li>**"none"** ignores referencing all together, creating a new schema branch even on "seen" schemas. Recursive references defaults to "any", ie `{}`.</li></ul> Defaults to "root". |
| **effectStrategy**?: "input" \| "any" | The effects output strategy. Defaults to "input". _See known issues!_ |
| **dateStrategy**?: "format:date" \| "format:date-time" \| "string" \| "integer" | Date strategy, integer allow to specify in unix-time min and max values. "format:date" creates a string schema with format: "date". "format:date-time" creates a string schema with format: "date-time". "string" is intepreted as "format:date-time". "integer" creates an integer schema with format "unix-time" (unless target "openApi3" is used min max checks are also respected) |
| |
| **emailStrategy**?: "format:email" \| "format:idn-email" \| "pattern:zod" | Choose how to handle the email string check. Defaults to "format:email". |
| **base64Strategy**?: "format:binary" \| "contentEnconding:base64" \| "pattern:zod" | Choose how to handle the base64 string check. Defaults to "contentEncoding:base64" as described [here](https://json-schema.org/understanding-json-schema/reference/non_json_data#contentencoding). Note that "format:binary" is not represented in the output type as it's not part of the JSON Schema spec and only intended to be used when targeting OpenAPI 3.0. Later versions of OpenAPI support contentEncoding. |
| **definitionPath**?: "definitions" \| "$defs" | The name of the definitions property when name is passed. Defaults to "definitions". |
| **target**?: "jsonSchema7" \| "jsonSchema2019-09" \| "openApi3" \| "openAi" | Which spec to target. Defaults to "jsonSchema7" |
| **strictUnions**?: boolean | Scrubs unions of any-like json schemas, like `{}` or `true`. Multiple zod types may result in these out of necessity, such as z.instanceof() |
| **definitions**?: Record<string, ZodSchema> | See separate section below |
| **errorMessages**?: boolean | Include custom error messages created via chained function checks for supported zod types. See section below |
| **markdownDescription**?: boolean | Copies the `description` meta to `markdownDescription` |
| **patternStrategy**?: "escape" \| "preserve" | The Zod string validations `.includes()`, `.startsWith()`, and `.endsWith()` must be converted to regex to be compatible with JSON Schema's `pattern`. For safety, all non-alphanumeric characters are `escape`d by default (consider `z.string().includes(".")`), but this can occasionally cause problems with Unicode-flagged regex parsers. Use `preserve` to prevent this escaping behaviour and preserve the exact string written, even if it results in an inaccurate regex. |
| **applyRegexFlags**?: boolean | JSON Schema's `pattern` doesn't support RegExp flags, but Zod's `z.string().regex()` does. When this option is true (default false), a best-effort is made to transform regexes into a flag-independent form (e.g. `/x/i => /[xX]/` ). Supported flags: `i` (basic Latin only), `m`, `s`. |
| **pipeStrategy**?: "all" \| "input" \| "output" | Decide which types should be included when using `z.pipe`, for example `z.string().pipe(z.number())` would return both `string` and `number` by default, only `string` for "input" and only `number` for "output". |
| **removeAdditionalStrategy**?: "passthrough" \| "strict" | Decide when `additionalProperties` should be allowed. See the section on additional properties for details. |
| **allowedAdditionalProperties**?: `true` \| `undefined` | What value to give `additionalProperties` when allowed. See the section on additional properties for details. |
| **rejectedAdditionalProperties**?: `false` \| `undefined` | What value to give `additionalProperties` when rejected. See the section on additional properties for details. |
| **override**?: callback | See section |
| **postProcess**?: callback | See section |
### Definitions
The definitions option lets you manually add recurring schemas into definitions for cleaner outputs. It's fully compatible with named schemas, changed definitions path and base path. Here's a simple example:
```typescript
const myRecurringSchema = z.string();
const myObjectSchema = z.object({ a: myRecurringSchema, b: myRecurringSchema });
const myJsonSchema = zodToJsonSchema(myObjectSchema, {
definitions: { myRecurringSchema },
});
```
#### Result
```json
{
"type": "object",
"properties": {
"a": {
"$ref": "#/definitions/myRecurringSchema"
},
"b": {
"$ref": "#/definitions/myRecurringSchema"
}
},
"definitions": {
"myRecurringSchema": {
"type": "string"
}
}
}
```
### Error Messages
This feature allows optionally including error messages created via chained function calls for supported zod types:
```ts
// string schema with additional chained function call checks
const EmailSchema = z.string().email("Invalid email").min(5, "Too short");
const jsonSchema = zodToJsonSchema(EmailSchema, { errorMessages: true });
```
#### Result
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "string",
"format": "email",
"minLength": 5,
"errorMessage": {
"format": "Invalid email",
"minLength": "Too short"
}
}
```
This allows for field specific, validation step specific error messages which can be useful for building forms and such. This format is accepted by `react-hook-form`'s ajv resolver (and therefor `ajv-errors` which it uses under the hood). Note that if using AJV with this format will require [enabling `ajv-errors`](https://ajv.js.org/packages/ajv-errors.html#usage) as vanilla AJV does not accept this format by default.
#### Custom Error Message Support
- ZodString
- regex
- min, max
- email, cuid, uuid, url
- endsWith, startsWith
- ZodNumber
- min, max, lt, lte, gt, gte,
- int
- multipleOf
- ZodSet
- min, max
- ZodArray
- min, max
### Additional properties
By default, Zod removes undeclared properties when parsing object schemas. In order to replicate the expected output of this behaviour, the default for behaviour of zodToJsonSchema is to set `"additionalProperties"` to `false` (although the correctness of this can be debated). If you wish to allow undeclared properties you can either:
- Set `removeAdditionalStrategy` to `"strict"`. This will allow additional properties for any object schema that is not declared with `.strict()`.
- Leave `removeAdditionalStrategy` set to its default value of `"passthrough"`, and add `.passtrough()` to your object schema.
#### Removing the `additionalProperties` keyword using the `allowedAdditionalProperties` and/or `rejectedAdditionalProperties` options.
Some schema definitions (like Googles Gen AI API for instance) does not allow the `additionalProperties` keyword at all. Luckily the JSON Schema spec allows for this: leaving the keyword undefined _should_ have the same effect as setting it to true (as per usual YMMV). To enable this behaviour, set the option `allowedAdditionalProperties` to `undefined`.
To exclude the keyword even when additional properties are _not_ allowed, set the `rejectedAdditionalProperties` to `undefined` as well.
_Heads up ⚠️: Both of these options will be ignored if your schema is declared with `.catchall(...)` as the provided schema will be used instead (if valid)._
#### Expected outputs
| `z.object({})` + option | `"additionalProperties"` value |
| ------------------------- | ----------------------------------------------------------- |
| `.strip()` (default) | `false` if strategy is `"passtrough"`, `true` if `"strict"` |
| `.passtrough()` | `true` |
| `.strict()` | `false` |
| `.catchall(z.string())` | `{ "type": "string" }` |
| `.catchall(z.function())` | `undefined` (function schemas are not currently parseable) |
Substitute `true` and `false` for `undefined` according to `allowedAdditionalProperties` and/or `rejectedAdditionalProperties` respectively.
### `override`
This options takes a callback receiving a Zod schema definition, the current reference object (containing the current ref path and other options), an argument containing inforation about wether or not the schema has been encountered before, and a forceResolution argument.
Important: if you don't want to override the current item you have to return the `ignoreOverride` symbol exported from the index. This is because `undefined` is a valid option to return when you want the property to be excluded from the resulting JSON schema.
```typescript
import zodToJsonSchema, { ignoreOverride } from "zod-to-json-schema";
zodToJsonSchema(
z.object({
ignoreThis: z.string(),
overrideThis: z.string(),
removeThis: z.string(),
}),
{
override: (def, refs) => {
const path = refs.currentPath.join("/");
if (path === "#/properties/overrideThis") {
return {
type: "integer",
};
}
if (path === "#/properties/removeThis") {
return undefined;
}
// Important! Do not return `undefined` or void unless you want to remove the property from the resulting schema completely.
return ignoreOverride;
},
},
);
```
Expected output:
```json
{
"type": "object",
"required": ["ignoreThis", "overrideThis"],
"properties": {
"ignoreThis": {
"type": "string"
},
"overrideThis": {
"type": "integer"
}
},
"additionalProperties": false
}
```
### `postProcess`
Besided receiving all arguments of the `override` callback, the `postProcess` callback also receives the generated schema. It should always return a JSON Schema, or `undefined` if you wish to filter it out. Unlike the `override` callback you do not have to return `ignoreOverride` if you are happy with the produced schema; simply return it unchanged.
```typescript
import zodToJsonSchema, { PostProcessCallback } from "zod-to-json-schema";
// Define the callback to be used to process the output using the PostProcessCallback type:
const postProcess: PostProcessCallback = (
// The original output produced by the package itself:
jsonSchema,
// The ZodSchema def used to produce the original schema:
def,
// The refs object containing the current path, passed options, etc.
refs,
) => {
if (!jsonSchema) {
return jsonSchema;
}
// Try to expand description as JSON meta:
if (jsonSchema.description) {
try {
jsonSchema = {
...jsonSchema,
...JSON.parse(jsonSchema.description),
};
} catch {}
}
// Make all numbers nullable:
if ("type" in jsonSchema! && jsonSchema.type === "number") {
jsonSchema.type = ["number", "null"];
}
// Add the refs path, just because
(jsonSchema as any).path = refs.currentPath;
return jsonSchema;
};
const jsonSchema = zodToJsonSchema(zodSchema, { postProcess });
```
#### Using `postProcess` for including examples and other meta
Adding support for examples and other JSON Schema meta keys are among the most commonly requested features for this project. Unfortunately the current Zod major (3) has pretty anemic support for this, so some userland hacking is required. Since this is such a common usecase I've included a helper function that simply tries to parse any description as JSON and expand it into the resulting schema.
Simply stringify whatever you want added to the output schema as the description, then import and use `jsonDescription` as the postProcess option:
```typescript
import zodToJsonSchema, { jsonDescription } from "zod-to-json-schema";
const zodSchema = z.string().describe(
JSON.stringify({
title: "My string",
description: "My description",
examples: ["Foo", "Bar"],
whatever: 123,
}),
);
const jsonSchema = zodToJsonSchema(zodSchema, {
postProcess: jsonDescription,
});
```
Expected output:
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "string",
"title": "My string",
"description": "My description",
"examples": ["Foo", "Bar"],
"whatever": 123
}
```
## Known issues
- The OpenAI target should be considered experimental for now, as some combination of options may break the compatibility.
- When using `.transform`, the return type is inferred from the supplied function. In other words, there is no schema for the return type, and there is no way to convert it in runtime. Currently the JSON schema will therefore reflect the input side of the Zod schema and not necessarily the output (the latter aka. `z.infer`). If this causes problems with your schema, consider using the effectStrategy "any", which will allow any type of output.
- JSON Schemas does not support any other key type than strings for objects. When using `z.record` with any other key type, this will be ignored. An exception to this rule is `z.enum` as is supported since 3.11.3
- Relative JSON pointers, while published alongside [JSON schema draft 2020-12](https://json-schema.org/specification.html), is not technically a part of it. Currently, most resolvers do not handle them at all.
- Since v3, the Object parser uses `.isOptional()` to check if a property should be included in `required` or not. This has the potentially dangerous behavior of calling `.safeParse` with `undefined`. To work around this, make sure your `preprocess` and other effects callbacks are pure and not liable to throw errors. An issue has been logged in the Zod repo and can be [tracked here](https://github.com/colinhacks/zod/issues/1460).
- JSON Schema version 2020-12 is not yet officially supported. However, you should be able to use this library to obtain a compatible schema for the 2020-12 format just by changing the returned schema's `$schema` field to: "https://json-schema.org/draft/2020-12/schema#"
## Versioning
This package _does not_ follow semantic versioning. The major and minor versions of this package instead reflects feature parity with the [Zod package](http://npmjs.com/package/zod).
I will do my best to keep API-breaking changes to an absolute minimum, but new features may appear as "patches", such as introducing the options pattern in 3.9.1.
## Changelog
https://github.com/StefanTerdell/zod-to-json-schema/blob/master/changelog.md

12
node_modules/zod-to-json-schema/SECURITY.md generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.9.x | :white_check_mark: |
| < 3.9 | :x: |
## Reporting a Vulnerability
Please log an issue [here](https://github.com/StefanTerdell/zod-to-json-schema/issues)

79
node_modules/zod-to-json-schema/changelog.md generated vendored Normal file
View File

@@ -0,0 +1,79 @@
# Changelog
| Version | Change |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 3.24.5 | Update .npmignore to drop 2 mb of test files. Thanks [Misha Kaletsky](https://github.com/mmkal)! |
| 3.24.4 | Added options to set the value of additionalProperties in objects and record |
| 3.24.3 | Adds postProcess callback option |
| 3.24.2 | Restructured internals to remove circular dependencies which apparently might cause some build systems to whine a bit. Big thanks to [Víctor Hernández](https://github.com/NanezX) for the fix. |
| 3.24.1 | Adds OpenAI target |
| 3.24.0 | Implements new string checks (jwt, base64url, cidr ipv4/v6), matching the new Zod version |
| 3.23.5 | Module import hotfix by [Enzo Monjardín](https://github.com/enzomonjardin). Thanks! |
| 3.23.4 | Fixes branded regex property names and a weird edgecase in arrays. Thanks to [Isaiah Marc Sanchez](https://github.com/imsanchez) and [Mitchell Merry](https://github.com/mitchell-merry)! |
| 3.23.3 | More tests (Thanks [Brett Zamir!](https://github.com/brettz9)), removed dead code |
| 3.23.2 | Lazily loads Emoji regex to avoid incompatibility with some environments. Thanks [Jacob Lee](https://github.com/jacoblee93)! |
| 3.23.1 | Best-effort RegEx flag support by [Spappz](https://github.com/Spappz)! Some minor fixes and additions, such as the title option. |
| 3.23.0 | Adds support for base64, date, time, duration and nanoid string validations. A warm welcome and a big thanks to [Colin](https://www.github.com/colinhacks), the creator of Zod, joining in as a contributor :) |
| 3.22.5 | Adds new z.date() parsing options and override callback |
| 3.22.4 | Adds fix for nullable references in OpenAPI mode |
| 3.22.3 | Adjust root path from "#/" to "#" according to RFC 6901 |
| 3.22.2 | Adds "output" pipe strategy |
| 3.22.1 | Fixes broken imports when using some bundlers |
| 3.22.0 | Support readonly. Export both CJS and ESM. Export everything from index. Alternative map parser. Improved pattern handling and updated sources. |
| 3.21.4 | Fixes missing support for exact array length |
| 3.21.3 | Fixes issue #77 (Reference path to nullable schemas in Open-API mode) |
| 3.21.2 | Adds "integer" type Date output to support min/max checks, markdownDescription option, fixes "none" refStrategy by adding "seen" and adds an option to use "pattern" with Zods' email enum instead of "format". |
| 3.21.1 | New target (2019-09) along with improved intersection schemas, improved mutual recursion references in definitions, descriptions respected in union parser and not removed in collapsed |
| 3.21.0 | Added new string validations (ip, emoji, etc) and BigInt checks to support Zod 3.21 |
| 3.20.5 | Added uniqueItems to Set and an option to disregard pipe schemas |
| 3.20.4 | Bugfixes and improved record parsing for openApi3 |
| 3.20.3 | Added Cuid2 support introduced in Zod 3.20.3 |
| 3.20.2 | Reintroduced conditional simplified return-type for when target is OpenAPI 3 |
| 3.20.1 | Fixed inconsistent casing in imports |
| 3.20.0 | Adds support for Zod 3.20 with catch and pipe parser as well as new string validations. Refactored Ref handling; adding definitions no longer considered experimental. Main API function refactored and simplified; output type less defined but a lot easier to maintain. Doubt anyone will miss it. <br/><quote><i>Narrator: Someone did in fact miss it</i></quote> |
| 3.19.4 | Adds custom error message support |
| 3.19.3 | Mark `definitions` as experimental in the readme |
| 3.19.2 | Added `definitions` option |
| 3.19.1 | Strict unions fix |
| 3.19.0 | No new features added in Zod, parity bump |
| 3.18.2 | Fixes support for native enums |
| 3.18.1 | Add strictUnions options |
| 3.18.0 | Added support for branded types |
| 3.17.2 | Fix for reference paths when supplying name option string. |
| 3.17.1 | Added startsWith and endsWith string checks. Merge multiple pattern checks into allOf array. |
| 3.17.0 | Added switch case handler for new trim "check". No changes to functionality. |
| 3.15.x - 3.16.x | Skipped: Did not change the Zod API in any way relevant for this package. |
| 3.14.1 | Dependabot security updates |
| 3.14.0 | Moves Zod into peerDependencies. Supports checks for sets, NaN-type (sort of), discriminated union type and standalone optional properties (as unions with undefined) |
| 3.12.x - 3.13.x | Skipped |
| 3.11.3 | Joins unions of enums into single enum and allows enums as keys of records |
| 3.11.2 | Adds option to target Open API 3 spec (paths) instead of Json Schema 7. |
| 3.11.1 | Performance boost when using $refStrategy `none` and internal improvements. |
| 3.11.0 | Added description support introduced in Zod 3.11.5 |
| 3.10.x | Skipped: Minor 10 did not change the Zod API |
| 3.9.5 | Type bug fix: used dev dependency types in package |
| 3.9.4 | Path bug fix and test case when using optional definitions path |
| 3.9.3 | Added option to change definition property name to $defs |
| 3.9.2 | Added option to handle transform results as any instead of relying on their input schema. |
| 3.9.1 | Refactored the way reference pointers are passed around and added options pattern to main function without braking backwards compatibility! You can now add a base path, change the reference strategy (or opt out), and still set the schema name inside the options object or outside as before. |
| 3.9.0 | Added support for multipleOf number validaion, .rest() schemas for tuples and key validation for records (only compatible with string keys due to JSON Schema limitation). |
| 3.7.x - 3.8.x | Skipped to reach functional parity with Zod versioning. |
| 3.6.1 | Realised intersection had another potential ref pathing bug. Fixed. |
| 3.6.0 | Added support for default & effects (refine). Broke out changelog.md |
| 3.5.0 | Added support for CUID string validation |
| 3.4.3 | Fixed $ref pathing for catchall and intersection. Additional tests and code structure fixes. |
| 3.4.2 | Fixed broken intersection parser (Thanks [Noah2610](https://github.com/Noah2610)!) |
| 3.4.1 | Fixed pathing bug for nullable items. |
| 3.4.0 | Added support for z.lazy() |
| 3.3.0 | Added support for catchall (additionalProperties schema on objects). Rebuilt object parser. |
| 3.2.0 | Added support for Map and Set as seen by their most common JSON definitions. Beware no standardized definition seem to exist and JSON.parse doesn't handle either natively. Their implementations here are based on the spread approach. Also further simplified intersection definition to just allOf. |
| 3.1.0 | String patterns finally supported! Fixed bugs include broken external type, unsafe nullable parsing, bad intersection implementation, and missing support for passthrough keys in objects. |
| 3.0.3 | Fixed array deep pathing bug (path contained `array` instead of `items`) |
| 3.0.2 | Fixed broken type usage (NonEmptyArrayDefinition was removed from Zod) |
| 3.0.1 | Fixed a typo in the readme |
| 3.0.0 | Compatible with Zod 3.2.0. Huge props to [Mr Hammad Asif](https://github.com/mrhammadasif) for his work on this. |
| 0.6.2 | Hotfix for undefined object properties. Could crash the parser when using Pick |
| 0.6.1 | Fixed bug in union pathing. `$Ref` was missing `/anyOf` |
| 0.6.0 | Moved `@types/json-schema` and `typescript` to dev dependencies. `@types/json-schema` is now only used for the test suites. Using `strict: true` in ts config. |
| 0.5.1 | First working release with all relevant Zod types present with most validations (except for string patterns due to Zod not exposing the source regexp pattern for those). |
| < 0.5.1 | Deprecated due to broken package structure. Please be patient, I eat crayons. |

9
node_modules/zod-to-json-schema/contributing.md generated vendored Normal file
View File

@@ -0,0 +1,9 @@
# Contributing
Hey, thanks for wanting to contribute.
Before you open a PR, make sure to open an issue and discuss the problem you want to solve. I will not consider PRs without issues.
I use [gitmoji](https://gitmoji.dev/) for my commit messages because I think it's fun. I encourage you to do the same, but won't enforce it.
I check PRs and issues very rarely so please be patient.

32
node_modules/zod-to-json-schema/createIndex.ts generated vendored Normal file
View File

@@ -0,0 +1,32 @@
import { readdirSync, writeFileSync, statSync } from "fs";
const ignore = ["src/index.ts"];
function checkSrcDir(path: string): string[] {
const lines: string[] = [];
for (const item of readdirSync(path)) {
const itemPath = path + "/" + item;
if (ignore.includes(itemPath)) {
continue;
}
if (statSync(itemPath).isDirectory()) {
lines.push(...checkSrcDir(itemPath));
} else if (item.endsWith(".ts")) {
lines.push('export * from "./' + itemPath.slice(4, -2) + 'js"');
}
}
return lines;
}
const lines = checkSrcDir("src");
lines.push(
'import { zodToJsonSchema } from "./zodToJsonSchema.js"',
"export default zodToJsonSchema;",
);
writeFileSync("./src/index.ts", lines.join(";\n"));

50
node_modules/zod-to-json-schema/dist/cjs/Options.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultOptions = exports.defaultOptions = exports.jsonDescription = exports.ignoreOverride = void 0;
exports.ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
const jsonDescription = (jsonSchema, def) => {
if (def.description) {
try {
return {
...jsonSchema,
...JSON.parse(def.description),
};
}
catch { }
}
return jsonSchema;
};
exports.jsonDescription = jsonDescription;
exports.defaultOptions = {
name: undefined,
$refStrategy: "root",
basePath: ["#"],
effectStrategy: "input",
pipeStrategy: "all",
dateStrategy: "format:date-time",
mapStrategy: "entries",
removeAdditionalStrategy: "passthrough",
allowedAdditionalProperties: true,
rejectedAdditionalProperties: false,
definitionPath: "definitions",
target: "jsonSchema7",
strictUnions: false,
definitions: {},
errorMessages: false,
markdownDescription: false,
patternStrategy: "escape",
applyRegexFlags: false,
emailStrategy: "format:email",
base64Strategy: "contentEncoding:base64",
nameStrategy: "ref",
};
const getDefaultOptions = (options) => (typeof options === "string"
? {
...exports.defaultOptions,
name: options,
}
: {
...exports.defaultOptions,
...options,
});
exports.getDefaultOptions = getDefaultOptions;

25
node_modules/zod-to-json-schema/dist/cjs/Refs.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRefs = void 0;
const Options_js_1 = require("./Options.js");
const getRefs = (options) => {
const _options = (0, Options_js_1.getDefaultOptions)(options);
const currentPath = _options.name !== undefined
? [..._options.basePath, _options.definitionPath, _options.name]
: _options.basePath;
return {
..._options,
currentPath: currentPath,
propertyPath: undefined,
seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
def._def,
{
def: def._def,
path: [..._options.basePath, _options.definitionPath, name],
// Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
jsonSchema: undefined,
},
])),
};
};
exports.getRefs = getRefs;

View File

@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setResponseValueAndErrors = exports.addErrorMessage = void 0;
function addErrorMessage(res, key, errorMessage, refs) {
if (!refs?.errorMessages)
return;
if (errorMessage) {
res.errorMessage = {
...res.errorMessage,
[key]: errorMessage,
};
}
}
exports.addErrorMessage = addErrorMessage;
function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
res[key] = value;
addErrorMessage(res, key, errorMessage, refs);
}
exports.setResponseValueAndErrors = setResponseValueAndErrors;

55
node_modules/zod-to-json-schema/dist/cjs/index.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./Options.js"), exports);
__exportStar(require("./Refs.js"), exports);
__exportStar(require("./errorMessages.js"), exports);
__exportStar(require("./parseDef.js"), exports);
__exportStar(require("./parseTypes.js"), exports);
__exportStar(require("./parsers/any.js"), exports);
__exportStar(require("./parsers/array.js"), exports);
__exportStar(require("./parsers/bigint.js"), exports);
__exportStar(require("./parsers/boolean.js"), exports);
__exportStar(require("./parsers/branded.js"), exports);
__exportStar(require("./parsers/catch.js"), exports);
__exportStar(require("./parsers/date.js"), exports);
__exportStar(require("./parsers/default.js"), exports);
__exportStar(require("./parsers/effects.js"), exports);
__exportStar(require("./parsers/enum.js"), exports);
__exportStar(require("./parsers/intersection.js"), exports);
__exportStar(require("./parsers/literal.js"), exports);
__exportStar(require("./parsers/map.js"), exports);
__exportStar(require("./parsers/nativeEnum.js"), exports);
__exportStar(require("./parsers/never.js"), exports);
__exportStar(require("./parsers/null.js"), exports);
__exportStar(require("./parsers/nullable.js"), exports);
__exportStar(require("./parsers/number.js"), exports);
__exportStar(require("./parsers/object.js"), exports);
__exportStar(require("./parsers/optional.js"), exports);
__exportStar(require("./parsers/pipeline.js"), exports);
__exportStar(require("./parsers/promise.js"), exports);
__exportStar(require("./parsers/readonly.js"), exports);
__exportStar(require("./parsers/record.js"), exports);
__exportStar(require("./parsers/set.js"), exports);
__exportStar(require("./parsers/string.js"), exports);
__exportStar(require("./parsers/tuple.js"), exports);
__exportStar(require("./parsers/undefined.js"), exports);
__exportStar(require("./parsers/union.js"), exports);
__exportStar(require("./parsers/unknown.js"), exports);
__exportStar(require("./selectParser.js"), exports);
__exportStar(require("./zodToJsonSchema.js"), exports);
const zodToJsonSchema_js_1 = require("./zodToJsonSchema.js");
exports.default = zodToJsonSchema_js_1.zodToJsonSchema;

View File

@@ -0,0 +1 @@
{"type":"commonjs"}

72
node_modules/zod-to-json-schema/dist/cjs/parseDef.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseDef = void 0;
const Options_js_1 = require("./Options.js");
const selectParser_js_1 = require("./selectParser.js");
function parseDef(def, refs, forceResolution = false) {
const seenItem = refs.seen.get(def);
if (refs.override) {
const overrideResult = refs.override?.(def, refs, seenItem, forceResolution);
if (overrideResult !== Options_js_1.ignoreOverride) {
return overrideResult;
}
}
if (seenItem && !forceResolution) {
const seenSchema = get$ref(seenItem, refs);
if (seenSchema !== undefined) {
return seenSchema;
}
}
const newItem = { def, path: refs.currentPath, jsonSchema: undefined };
refs.seen.set(def, newItem);
const jsonSchemaOrGetter = (0, selectParser_js_1.selectParser)(def, def.typeName, refs);
// If the return was a function, then the inner definition needs to be extracted before a call to parseDef (recursive)
const jsonSchema = typeof jsonSchemaOrGetter === "function"
? parseDef(jsonSchemaOrGetter(), refs)
: jsonSchemaOrGetter;
if (jsonSchema) {
addMeta(def, refs, jsonSchema);
}
if (refs.postProcess) {
const postProcessResult = refs.postProcess(jsonSchema, def, refs);
newItem.jsonSchema = jsonSchema;
return postProcessResult;
}
newItem.jsonSchema = jsonSchema;
return jsonSchema;
}
exports.parseDef = parseDef;
const get$ref = (item, refs) => {
switch (refs.$refStrategy) {
case "root":
return { $ref: item.path.join("/") };
case "relative":
return { $ref: getRelativePath(refs.currentPath, item.path) };
case "none":
case "seen": {
if (item.path.length < refs.currentPath.length &&
item.path.every((value, index) => refs.currentPath[index] === value)) {
console.warn(`Recursive reference detected at ${refs.currentPath.join("/")}! Defaulting to any`);
return {};
}
return refs.$refStrategy === "seen" ? {} : undefined;
}
}
};
const getRelativePath = (pathA, pathB) => {
let i = 0;
for (; i < pathA.length && i < pathB.length; i++) {
if (pathA[i] !== pathB[i])
break;
}
return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/");
};
const addMeta = (def, refs, jsonSchema) => {
if (def.description) {
jsonSchema.description = def.description;
if (refs.markdownDescription) {
jsonSchema.markdownDescription = def.description;
}
}
return jsonSchema;
};

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseAnyDef = void 0;
function parseAnyDef() {
return {};
}
exports.parseAnyDef = parseAnyDef;

View File

@@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseArrayDef = void 0;
const zod_1 = require("zod");
const errorMessages_js_1 = require("../errorMessages.js");
const parseDef_js_1 = require("../parseDef.js");
function parseArrayDef(def, refs) {
const res = {
type: "array",
};
if (def.type?._def &&
def.type?._def?.typeName !== zod_1.ZodFirstPartyTypeKind.ZodAny) {
res.items = (0, parseDef_js_1.parseDef)(def.type._def, {
...refs,
currentPath: [...refs.currentPath, "items"],
});
}
if (def.minLength) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minItems", def.minLength.value, def.minLength.message, refs);
}
if (def.maxLength) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maxItems", def.maxLength.value, def.maxLength.message, refs);
}
if (def.exactLength) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minItems", def.exactLength.value, def.exactLength.message, refs);
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maxItems", def.exactLength.value, def.exactLength.message, refs);
}
return res;
}
exports.parseArrayDef = parseArrayDef;

View File

@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBigintDef = void 0;
const errorMessages_js_1 = require("../errorMessages.js");
function parseBigintDef(def, refs) {
const res = {
type: "integer",
format: "int64",
};
if (!def.checks)
return res;
for (const check of def.checks) {
switch (check.kind) {
case "min":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minimum", check.value, check.message, refs);
}
else {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "exclusiveMinimum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMinimum = true;
}
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minimum", check.value, check.message, refs);
}
break;
case "max":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maximum", check.value, check.message, refs);
}
else {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "exclusiveMaximum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMaximum = true;
}
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maximum", check.value, check.message, refs);
}
break;
case "multipleOf":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "multipleOf", check.value, check.message, refs);
break;
}
}
return res;
}
exports.parseBigintDef = parseBigintDef;

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBooleanDef = void 0;
function parseBooleanDef() {
return {
type: "boolean",
};
}
exports.parseBooleanDef = parseBooleanDef;

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseBrandedDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
function parseBrandedDef(_def, refs) {
return (0, parseDef_js_1.parseDef)(_def.type._def, refs);
}
exports.parseBrandedDef = parseBrandedDef;

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseCatchDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const parseCatchDef = (def, refs) => {
return (0, parseDef_js_1.parseDef)(def.innerType._def, refs);
};
exports.parseCatchDef = parseCatchDef;

View File

@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseDateDef = void 0;
const errorMessages_js_1 = require("../errorMessages.js");
function parseDateDef(def, refs, overrideDateStrategy) {
const strategy = overrideDateStrategy ?? refs.dateStrategy;
if (Array.isArray(strategy)) {
return {
anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),
};
}
switch (strategy) {
case "string":
case "format:date-time":
return {
type: "string",
format: "date-time",
};
case "format:date":
return {
type: "string",
format: "date",
};
case "integer":
return integerDateParser(def, refs);
}
}
exports.parseDateDef = parseDateDef;
const integerDateParser = (def, refs) => {
const res = {
type: "integer",
format: "unix-time",
};
if (refs.target === "openApi3") {
return res;
}
for (const check of def.checks) {
switch (check.kind) {
case "min":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minimum", check.value, // This is in milliseconds
check.message, refs);
break;
case "max":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maximum", check.value, // This is in milliseconds
check.message, refs);
break;
}
}
return res;
};

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseDefaultDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
function parseDefaultDef(_def, refs) {
return {
...(0, parseDef_js_1.parseDef)(_def.innerType._def, refs),
default: _def.defaultValue(),
};
}
exports.parseDefaultDef = parseDefaultDef;

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseEffectsDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
function parseEffectsDef(_def, refs) {
return refs.effectStrategy === "input"
? (0, parseDef_js_1.parseDef)(_def.schema._def, refs)
: {};
}
exports.parseEffectsDef = parseEffectsDef;

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseEnumDef = void 0;
function parseEnumDef(def) {
return {
type: "string",
enum: Array.from(def.values),
};
}
exports.parseEnumDef = parseEnumDef;

View File

@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseIntersectionDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const isJsonSchema7AllOfType = (type) => {
if ("type" in type && type.type === "string")
return false;
return "allOf" in type;
};
function parseIntersectionDef(def, refs) {
const allOf = [
(0, parseDef_js_1.parseDef)(def.left._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", "0"],
}),
(0, parseDef_js_1.parseDef)(def.right._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", "1"],
}),
].filter((x) => !!x);
let unevaluatedProperties = refs.target === "jsonSchema2019-09"
? { unevaluatedProperties: false }
: undefined;
const mergedAllOf = [];
// If either of the schemas is an allOf, merge them into a single allOf
allOf.forEach((schema) => {
if (isJsonSchema7AllOfType(schema)) {
mergedAllOf.push(...schema.allOf);
if (schema.unevaluatedProperties === undefined) {
// If one of the schemas has no unevaluatedProperties set,
// the merged schema should also have no unevaluatedProperties set
unevaluatedProperties = undefined;
}
}
else {
let nestedSchema = schema;
if ("additionalProperties" in schema &&
schema.additionalProperties === false) {
const { additionalProperties, ...rest } = schema;
nestedSchema = rest;
}
else {
// As soon as one of the schemas has additionalProperties set not to false, we allow unevaluatedProperties
unevaluatedProperties = undefined;
}
mergedAllOf.push(nestedSchema);
}
});
return mergedAllOf.length
? {
allOf: mergedAllOf,
...unevaluatedProperties,
}
: undefined;
}
exports.parseIntersectionDef = parseIntersectionDef;

View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseLiteralDef = void 0;
function parseLiteralDef(def, refs) {
const parsedType = typeof def.value;
if (parsedType !== "bigint" &&
parsedType !== "number" &&
parsedType !== "boolean" &&
parsedType !== "string") {
return {
type: Array.isArray(def.value) ? "array" : "object",
};
}
if (refs.target === "openApi3") {
return {
type: parsedType === "bigint" ? "integer" : parsedType,
enum: [def.value],
};
}
return {
type: parsedType === "bigint" ? "integer" : parsedType,
const: def.value,
};
}
exports.parseLiteralDef = parseLiteralDef;

View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseMapDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const record_js_1 = require("./record.js");
function parseMapDef(def, refs) {
if (refs.mapStrategy === "record") {
return (0, record_js_1.parseRecordDef)(def, refs);
}
const keys = (0, parseDef_js_1.parseDef)(def.keyType._def, {
...refs,
currentPath: [...refs.currentPath, "items", "items", "0"],
}) || {};
const values = (0, parseDef_js_1.parseDef)(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "items", "items", "1"],
}) || {};
return {
type: "array",
maxItems: 125,
items: {
type: "array",
items: [keys, values],
minItems: 2,
maxItems: 2,
},
};
}
exports.parseMapDef = parseMapDef;

View File

@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNativeEnumDef = void 0;
function parseNativeEnumDef(def) {
const object = def.values;
const actualKeys = Object.keys(def.values).filter((key) => {
return typeof object[object[key]] !== "number";
});
const actualValues = actualKeys.map((key) => object[key]);
const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
return {
type: parsedTypes.length === 1
? parsedTypes[0] === "string"
? "string"
: "number"
: ["string", "number"],
enum: actualValues,
};
}
exports.parseNativeEnumDef = parseNativeEnumDef;

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNeverDef = void 0;
function parseNeverDef() {
return {
not: {},
};
}
exports.parseNeverDef = parseNeverDef;

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNullDef = void 0;
function parseNullDef(refs) {
return refs.target === "openApi3"
? {
enum: ["null"],
nullable: true,
}
: {
type: "null",
};
}
exports.parseNullDef = parseNullDef;

View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNullableDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const union_js_1 = require("./union.js");
function parseNullableDef(def, refs) {
if (["ZodString", "ZodNumber", "ZodBigInt", "ZodBoolean", "ZodNull"].includes(def.innerType._def.typeName) &&
(!def.innerType._def.checks || !def.innerType._def.checks.length)) {
if (refs.target === "openApi3") {
return {
type: union_js_1.primitiveMappings[def.innerType._def.typeName],
nullable: true,
};
}
return {
type: [
union_js_1.primitiveMappings[def.innerType._def.typeName],
"null",
],
};
}
if (refs.target === "openApi3") {
const base = (0, parseDef_js_1.parseDef)(def.innerType._def, {
...refs,
currentPath: [...refs.currentPath],
});
if (base && "$ref" in base)
return { allOf: [base], nullable: true };
return base && { ...base, nullable: true };
}
const base = (0, parseDef_js_1.parseDef)(def.innerType._def, {
...refs,
currentPath: [...refs.currentPath, "anyOf", "0"],
});
return base && { anyOf: [base, { type: "null" }] };
}
exports.parseNullableDef = parseNullableDef;

View File

@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNumberDef = void 0;
const errorMessages_js_1 = require("../errorMessages.js");
function parseNumberDef(def, refs) {
const res = {
type: "number",
};
if (!def.checks)
return res;
for (const check of def.checks) {
switch (check.kind) {
case "int":
res.type = "integer";
(0, errorMessages_js_1.addErrorMessage)(res, "type", check.message, refs);
break;
case "min":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minimum", check.value, check.message, refs);
}
else {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "exclusiveMinimum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMinimum = true;
}
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minimum", check.value, check.message, refs);
}
break;
case "max":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maximum", check.value, check.message, refs);
}
else {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "exclusiveMaximum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMaximum = true;
}
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maximum", check.value, check.message, refs);
}
break;
case "multipleOf":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "multipleOf", check.value, check.message, refs);
break;
}
}
return res;
}
exports.parseNumberDef = parseNumberDef;

View File

@@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseObjectDef = void 0;
const zod_1 = require("zod");
const parseDef_js_1 = require("../parseDef.js");
function parseObjectDef(def, refs) {
const forceOptionalIntoNullable = refs.target === "openAi";
const result = {
type: "object",
properties: {},
};
const required = [];
const shape = def.shape();
for (const propName in shape) {
let propDef = shape[propName];
if (propDef === undefined || propDef._def === undefined) {
continue;
}
let propOptional = safeIsOptional(propDef);
if (propOptional && forceOptionalIntoNullable) {
if (propDef instanceof zod_1.ZodOptional) {
propDef = propDef._def.innerType;
}
if (!propDef.isNullable()) {
propDef = propDef.nullable();
}
propOptional = false;
}
const parsedDef = (0, parseDef_js_1.parseDef)(propDef._def, {
...refs,
currentPath: [...refs.currentPath, "properties", propName],
propertyPath: [...refs.currentPath, "properties", propName],
});
if (parsedDef === undefined) {
continue;
}
result.properties[propName] = parsedDef;
if (!propOptional) {
required.push(propName);
}
}
if (required.length) {
result.required = required;
}
const additionalProperties = decideAdditionalProperties(def, refs);
if (additionalProperties !== undefined) {
result.additionalProperties = additionalProperties;
}
return result;
}
exports.parseObjectDef = parseObjectDef;
function decideAdditionalProperties(def, refs) {
if (def.catchall._def.typeName !== "ZodNever") {
return (0, parseDef_js_1.parseDef)(def.catchall._def, {
...refs,
currentPath: [...refs.currentPath, "additionalProperties"],
});
}
switch (def.unknownKeys) {
case "passthrough":
return refs.allowedAdditionalProperties;
case "strict":
return refs.rejectedAdditionalProperties;
case "strip":
return refs.removeAdditionalStrategy === "strict"
? refs.allowedAdditionalProperties
: refs.rejectedAdditionalProperties;
}
}
function safeIsOptional(schema) {
try {
return schema.isOptional();
}
catch {
return true;
}
}

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseOptionalDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const parseOptionalDef = (def, refs) => {
if (refs.currentPath.toString() === refs.propertyPath?.toString()) {
return (0, parseDef_js_1.parseDef)(def.innerType._def, refs);
}
const innerSchema = (0, parseDef_js_1.parseDef)(def.innerType._def, {
...refs,
currentPath: [...refs.currentPath, "anyOf", "1"],
});
return innerSchema
? {
anyOf: [
{
not: {},
},
innerSchema,
],
}
: {};
};
exports.parseOptionalDef = parseOptionalDef;

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parsePipelineDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const parsePipelineDef = (def, refs) => {
if (refs.pipeStrategy === "input") {
return (0, parseDef_js_1.parseDef)(def.in._def, refs);
}
else if (refs.pipeStrategy === "output") {
return (0, parseDef_js_1.parseDef)(def.out._def, refs);
}
const a = (0, parseDef_js_1.parseDef)(def.in._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", "0"],
});
const b = (0, parseDef_js_1.parseDef)(def.out._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", a ? "1" : "0"],
});
return {
allOf: [a, b].filter((x) => x !== undefined),
};
};
exports.parsePipelineDef = parsePipelineDef;

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parsePromiseDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
function parsePromiseDef(def, refs) {
return (0, parseDef_js_1.parseDef)(def.type._def, refs);
}
exports.parsePromiseDef = parsePromiseDef;

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseReadonlyDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
const parseReadonlyDef = (def, refs) => {
return (0, parseDef_js_1.parseDef)(def.innerType._def, refs);
};
exports.parseReadonlyDef = parseReadonlyDef;

View File

@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseRecordDef = void 0;
const zod_1 = require("zod");
const parseDef_js_1 = require("../parseDef.js");
const string_js_1 = require("./string.js");
const branded_js_1 = require("./branded.js");
function parseRecordDef(def, refs) {
if (refs.target === "openAi") {
console.warn("Warning: OpenAI may not support records in schemas! Try an array of key-value pairs instead.");
}
if (refs.target === "openApi3" &&
def.keyType?._def.typeName === zod_1.ZodFirstPartyTypeKind.ZodEnum) {
return {
type: "object",
required: def.keyType._def.values,
properties: def.keyType._def.values.reduce((acc, key) => ({
...acc,
[key]: (0, parseDef_js_1.parseDef)(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "properties", key],
}) ?? {},
}), {}),
additionalProperties: refs.rejectedAdditionalProperties,
};
}
const schema = {
type: "object",
additionalProperties: (0, parseDef_js_1.parseDef)(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "additionalProperties"],
}) ?? refs.allowedAdditionalProperties,
};
if (refs.target === "openApi3") {
return schema;
}
if (def.keyType?._def.typeName === zod_1.ZodFirstPartyTypeKind.ZodString &&
def.keyType._def.checks?.length) {
const { type, ...keyType } = (0, string_js_1.parseStringDef)(def.keyType._def, refs);
return {
...schema,
propertyNames: keyType,
};
}
else if (def.keyType?._def.typeName === zod_1.ZodFirstPartyTypeKind.ZodEnum) {
return {
...schema,
propertyNames: {
enum: def.keyType._def.values,
},
};
}
else if (def.keyType?._def.typeName === zod_1.ZodFirstPartyTypeKind.ZodBranded &&
def.keyType._def.type._def.typeName === zod_1.ZodFirstPartyTypeKind.ZodString &&
def.keyType._def.type._def.checks?.length) {
const { type, ...keyType } = (0, branded_js_1.parseBrandedDef)(def.keyType._def, refs);
return {
...schema,
propertyNames: keyType,
};
}
return schema;
}
exports.parseRecordDef = parseRecordDef;

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseSetDef = void 0;
const errorMessages_js_1 = require("../errorMessages.js");
const parseDef_js_1 = require("../parseDef.js");
function parseSetDef(def, refs) {
const items = (0, parseDef_js_1.parseDef)(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "items"],
});
const schema = {
type: "array",
uniqueItems: true,
items,
};
if (def.minSize) {
(0, errorMessages_js_1.setResponseValueAndErrors)(schema, "minItems", def.minSize.value, def.minSize.message, refs);
}
if (def.maxSize) {
(0, errorMessages_js_1.setResponseValueAndErrors)(schema, "maxItems", def.maxSize.value, def.maxSize.message, refs);
}
return schema;
}
exports.parseSetDef = parseSetDef;

View File

@@ -0,0 +1,357 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseStringDef = exports.zodPatterns = void 0;
const errorMessages_js_1 = require("../errorMessages.js");
let emojiRegex = undefined;
/**
* Generated from the regular expressions found here as of 2024-05-22:
* https://github.com/colinhacks/zod/blob/master/src/types.ts.
*
* Expressions with /i flag have been changed accordingly.
*/
exports.zodPatterns = {
/**
* `c` was changed to `[cC]` to replicate /i flag
*/
cuid: /^[cC][^\s-]{8,}$/,
cuid2: /^[0-9a-z]+$/,
ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
/**
* `a-z` was added to replicate /i flag
*/
email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
/**
* Constructed a valid Unicode RegExp
*
* Lazily instantiate since this type of regex isn't supported
* in all envs (e.g. React Native).
*
* See:
* https://github.com/colinhacks/zod/issues/2433
* Fix in Zod:
* https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b
*/
emoji: () => {
if (emojiRegex === undefined) {
emojiRegex = RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$", "u");
}
return emojiRegex;
},
/**
* Unused
*/
uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
/**
* Unused
*/
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,
ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,
/**
* Unused
*/
ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,
ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,
base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,
nanoid: /^[a-zA-Z0-9_-]{21}$/,
jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,
};
function parseStringDef(def, refs) {
const res = {
type: "string",
};
if (def.checks) {
for (const check of def.checks) {
switch (check.kind) {
case "min":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minLength", typeof res.minLength === "number"
? Math.max(res.minLength, check.value)
: check.value, check.message, refs);
break;
case "max":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maxLength", typeof res.maxLength === "number"
? Math.min(res.maxLength, check.value)
: check.value, check.message, refs);
break;
case "email":
switch (refs.emailStrategy) {
case "format:email":
addFormat(res, "email", check.message, refs);
break;
case "format:idn-email":
addFormat(res, "idn-email", check.message, refs);
break;
case "pattern:zod":
addPattern(res, exports.zodPatterns.email, check.message, refs);
break;
}
break;
case "url":
addFormat(res, "uri", check.message, refs);
break;
case "uuid":
addFormat(res, "uuid", check.message, refs);
break;
case "regex":
addPattern(res, check.regex, check.message, refs);
break;
case "cuid":
addPattern(res, exports.zodPatterns.cuid, check.message, refs);
break;
case "cuid2":
addPattern(res, exports.zodPatterns.cuid2, check.message, refs);
break;
case "startsWith":
addPattern(res, RegExp(`^${escapeLiteralCheckValue(check.value, refs)}`), check.message, refs);
break;
case "endsWith":
addPattern(res, RegExp(`${escapeLiteralCheckValue(check.value, refs)}$`), check.message, refs);
break;
case "datetime":
addFormat(res, "date-time", check.message, refs);
break;
case "date":
addFormat(res, "date", check.message, refs);
break;
case "time":
addFormat(res, "time", check.message, refs);
break;
case "duration":
addFormat(res, "duration", check.message, refs);
break;
case "length":
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "minLength", typeof res.minLength === "number"
? Math.max(res.minLength, check.value)
: check.value, check.message, refs);
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "maxLength", typeof res.maxLength === "number"
? Math.min(res.maxLength, check.value)
: check.value, check.message, refs);
break;
case "includes": {
addPattern(res, RegExp(escapeLiteralCheckValue(check.value, refs)), check.message, refs);
break;
}
case "ip": {
if (check.version !== "v6") {
addFormat(res, "ipv4", check.message, refs);
}
if (check.version !== "v4") {
addFormat(res, "ipv6", check.message, refs);
}
break;
}
case "base64url":
addPattern(res, exports.zodPatterns.base64url, check.message, refs);
break;
case "jwt":
addPattern(res, exports.zodPatterns.jwt, check.message, refs);
break;
case "cidr": {
if (check.version !== "v6") {
addPattern(res, exports.zodPatterns.ipv4Cidr, check.message, refs);
}
if (check.version !== "v4") {
addPattern(res, exports.zodPatterns.ipv6Cidr, check.message, refs);
}
break;
}
case "emoji":
addPattern(res, exports.zodPatterns.emoji(), check.message, refs);
break;
case "ulid": {
addPattern(res, exports.zodPatterns.ulid, check.message, refs);
break;
}
case "base64": {
switch (refs.base64Strategy) {
case "format:binary": {
addFormat(res, "binary", check.message, refs);
break;
}
case "contentEncoding:base64": {
(0, errorMessages_js_1.setResponseValueAndErrors)(res, "contentEncoding", "base64", check.message, refs);
break;
}
case "pattern:zod": {
addPattern(res, exports.zodPatterns.base64, check.message, refs);
break;
}
}
break;
}
case "nanoid": {
addPattern(res, exports.zodPatterns.nanoid, check.message, refs);
}
case "toLowerCase":
case "toUpperCase":
case "trim":
break;
default:
/* c8 ignore next */
((_) => { })(check);
}
}
}
return res;
}
exports.parseStringDef = parseStringDef;
function escapeLiteralCheckValue(literal, refs) {
return refs.patternStrategy === "escape"
? escapeNonAlphaNumeric(literal)
: literal;
}
const ALPHA_NUMERIC = new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");
function escapeNonAlphaNumeric(source) {
let result = "";
for (let i = 0; i < source.length; i++) {
if (!ALPHA_NUMERIC.has(source[i])) {
result += "\\";
}
result += source[i];
}
return result;
}
// Adds a "format" keyword to the schema. If a format exists, both formats will be joined in an allOf-node, along with subsequent ones.
function addFormat(schema, value, message, refs) {
if (schema.format || schema.anyOf?.some((x) => x.format)) {
if (!schema.anyOf) {
schema.anyOf = [];
}
if (schema.format) {
schema.anyOf.push({
format: schema.format,
...(schema.errorMessage &&
refs.errorMessages && {
errorMessage: { format: schema.errorMessage.format },
}),
});
delete schema.format;
if (schema.errorMessage) {
delete schema.errorMessage.format;
if (Object.keys(schema.errorMessage).length === 0) {
delete schema.errorMessage;
}
}
}
schema.anyOf.push({
format: value,
...(message &&
refs.errorMessages && { errorMessage: { format: message } }),
});
}
else {
(0, errorMessages_js_1.setResponseValueAndErrors)(schema, "format", value, message, refs);
}
}
// Adds a "pattern" keyword to the schema. If a pattern exists, both patterns will be joined in an allOf-node, along with subsequent ones.
function addPattern(schema, regex, message, refs) {
if (schema.pattern || schema.allOf?.some((x) => x.pattern)) {
if (!schema.allOf) {
schema.allOf = [];
}
if (schema.pattern) {
schema.allOf.push({
pattern: schema.pattern,
...(schema.errorMessage &&
refs.errorMessages && {
errorMessage: { pattern: schema.errorMessage.pattern },
}),
});
delete schema.pattern;
if (schema.errorMessage) {
delete schema.errorMessage.pattern;
if (Object.keys(schema.errorMessage).length === 0) {
delete schema.errorMessage;
}
}
}
schema.allOf.push({
pattern: stringifyRegExpWithFlags(regex, refs),
...(message &&
refs.errorMessages && { errorMessage: { pattern: message } }),
});
}
else {
(0, errorMessages_js_1.setResponseValueAndErrors)(schema, "pattern", stringifyRegExpWithFlags(regex, refs), message, refs);
}
}
// Mutate z.string.regex() in a best attempt to accommodate for regex flags when applyRegexFlags is true
function stringifyRegExpWithFlags(regex, refs) {
if (!refs.applyRegexFlags || !regex.flags) {
return regex.source;
}
// Currently handled flags
const flags = {
i: regex.flags.includes("i"),
m: regex.flags.includes("m"),
s: regex.flags.includes("s"), // `.` matches newlines
};
// The general principle here is to step through each character, one at a time, applying mutations as flags require. We keep track when the current character is escaped, and when it's inside a group /like [this]/ or (also) a range like /[a-z]/. The following is fairly brittle imperative code; edit at your peril!
const source = flags.i ? regex.source.toLowerCase() : regex.source;
let pattern = "";
let isEscaped = false;
let inCharGroup = false;
let inCharRange = false;
for (let i = 0; i < source.length; i++) {
if (isEscaped) {
pattern += source[i];
isEscaped = false;
continue;
}
if (flags.i) {
if (inCharGroup) {
if (source[i].match(/[a-z]/)) {
if (inCharRange) {
pattern += source[i];
pattern += `${source[i - 2]}-${source[i]}`.toUpperCase();
inCharRange = false;
}
else if (source[i + 1] === "-" && source[i + 2]?.match(/[a-z]/)) {
pattern += source[i];
inCharRange = true;
}
else {
pattern += `${source[i]}${source[i].toUpperCase()}`;
}
continue;
}
}
else if (source[i].match(/[a-z]/)) {
pattern += `[${source[i]}${source[i].toUpperCase()}]`;
continue;
}
}
if (flags.m) {
if (source[i] === "^") {
pattern += `(^|(?<=[\r\n]))`;
continue;
}
else if (source[i] === "$") {
pattern += `($|(?=[\r\n]))`;
continue;
}
}
if (flags.s && source[i] === ".") {
pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`;
continue;
}
pattern += source[i];
if (source[i] === "\\") {
isEscaped = true;
}
else if (inCharGroup && source[i] === "]") {
inCharGroup = false;
}
else if (!inCharGroup && source[i] === "[") {
inCharGroup = true;
}
}
try {
new RegExp(pattern);
}
catch {
console.warn(`Could not convert regex pattern at ${refs.currentPath.join("/")} to a flag-independent form! Falling back to the flag-ignorant source`);
return regex.source;
}
return pattern;
}

View File

@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseTupleDef = void 0;
const parseDef_js_1 = require("../parseDef.js");
function parseTupleDef(def, refs) {
if (def.rest) {
return {
type: "array",
minItems: def.items.length,
items: def.items
.map((x, i) => (0, parseDef_js_1.parseDef)(x._def, {
...refs,
currentPath: [...refs.currentPath, "items", `${i}`],
}))
.reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
additionalItems: (0, parseDef_js_1.parseDef)(def.rest._def, {
...refs,
currentPath: [...refs.currentPath, "additionalItems"],
}),
};
}
else {
return {
type: "array",
minItems: def.items.length,
maxItems: def.items.length,
items: def.items
.map((x, i) => (0, parseDef_js_1.parseDef)(x._def, {
...refs,
currentPath: [...refs.currentPath, "items", `${i}`],
}))
.reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
};
}
}
exports.parseTupleDef = parseTupleDef;

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseUndefinedDef = void 0;
function parseUndefinedDef() {
return {
not: {},
};
}
exports.parseUndefinedDef = parseUndefinedDef;

View File

@@ -0,0 +1,84 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseUnionDef = exports.primitiveMappings = void 0;
const parseDef_js_1 = require("../parseDef.js");
exports.primitiveMappings = {
ZodString: "string",
ZodNumber: "number",
ZodBigInt: "integer",
ZodBoolean: "boolean",
ZodNull: "null",
};
function parseUnionDef(def, refs) {
if (refs.target === "openApi3")
return asAnyOf(def, refs);
const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
// This blocks tries to look ahead a bit to produce nicer looking schemas with type array instead of anyOf.
if (options.every((x) => x._def.typeName in exports.primitiveMappings &&
(!x._def.checks || !x._def.checks.length))) {
// all types in union are primitive and lack checks, so might as well squash into {type: [...]}
const types = options.reduce((types, x) => {
const type = exports.primitiveMappings[x._def.typeName]; //Can be safely casted due to row 43
return type && !types.includes(type) ? [...types, type] : types;
}, []);
return {
type: types.length > 1 ? types : types[0],
};
}
else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) {
// all options literals
const types = options.reduce((acc, x) => {
const type = typeof x._def.value;
switch (type) {
case "string":
case "number":
case "boolean":
return [...acc, type];
case "bigint":
return [...acc, "integer"];
case "object":
if (x._def.value === null)
return [...acc, "null"];
case "symbol":
case "undefined":
case "function":
default:
return acc;
}
}, []);
if (types.length === options.length) {
// all the literals are primitive, as far as null can be considered primitive
const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
return {
type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
enum: options.reduce((acc, x) => {
return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
}, []),
};
}
}
else if (options.every((x) => x._def.typeName === "ZodEnum")) {
return {
type: "string",
enum: options.reduce((acc, x) => [
...acc,
...x._def.values.filter((x) => !acc.includes(x)),
], []),
};
}
return asAnyOf(def, refs);
}
exports.parseUnionDef = parseUnionDef;
const asAnyOf = (def, refs) => {
const anyOf = (def.options instanceof Map
? Array.from(def.options.values())
: def.options)
.map((x, i) => (0, parseDef_js_1.parseDef)(x._def, {
...refs,
currentPath: [...refs.currentPath, "anyOf", `${i}`],
}))
.filter((x) => !!x &&
(!refs.strictUnions ||
(typeof x === "object" && Object.keys(x).length > 0)));
return anyOf.length ? { anyOf } : undefined;
};

View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseUnknownDef = void 0;
function parseUnknownDef() {
return {};
}
exports.parseUnknownDef = parseUnknownDef;

View File

@@ -0,0 +1,110 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectParser = void 0;
const zod_1 = require("zod");
const any_js_1 = require("./parsers/any.js");
const array_js_1 = require("./parsers/array.js");
const bigint_js_1 = require("./parsers/bigint.js");
const boolean_js_1 = require("./parsers/boolean.js");
const branded_js_1 = require("./parsers/branded.js");
const catch_js_1 = require("./parsers/catch.js");
const date_js_1 = require("./parsers/date.js");
const default_js_1 = require("./parsers/default.js");
const effects_js_1 = require("./parsers/effects.js");
const enum_js_1 = require("./parsers/enum.js");
const intersection_js_1 = require("./parsers/intersection.js");
const literal_js_1 = require("./parsers/literal.js");
const map_js_1 = require("./parsers/map.js");
const nativeEnum_js_1 = require("./parsers/nativeEnum.js");
const never_js_1 = require("./parsers/never.js");
const null_js_1 = require("./parsers/null.js");
const nullable_js_1 = require("./parsers/nullable.js");
const number_js_1 = require("./parsers/number.js");
const object_js_1 = require("./parsers/object.js");
const optional_js_1 = require("./parsers/optional.js");
const pipeline_js_1 = require("./parsers/pipeline.js");
const promise_js_1 = require("./parsers/promise.js");
const record_js_1 = require("./parsers/record.js");
const set_js_1 = require("./parsers/set.js");
const string_js_1 = require("./parsers/string.js");
const tuple_js_1 = require("./parsers/tuple.js");
const undefined_js_1 = require("./parsers/undefined.js");
const union_js_1 = require("./parsers/union.js");
const unknown_js_1 = require("./parsers/unknown.js");
const readonly_js_1 = require("./parsers/readonly.js");
const selectParser = (def, typeName, refs) => {
switch (typeName) {
case zod_1.ZodFirstPartyTypeKind.ZodString:
return (0, string_js_1.parseStringDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodNumber:
return (0, number_js_1.parseNumberDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodObject:
return (0, object_js_1.parseObjectDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodBigInt:
return (0, bigint_js_1.parseBigintDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodBoolean:
return (0, boolean_js_1.parseBooleanDef)();
case zod_1.ZodFirstPartyTypeKind.ZodDate:
return (0, date_js_1.parseDateDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodUndefined:
return (0, undefined_js_1.parseUndefinedDef)();
case zod_1.ZodFirstPartyTypeKind.ZodNull:
return (0, null_js_1.parseNullDef)(refs);
case zod_1.ZodFirstPartyTypeKind.ZodArray:
return (0, array_js_1.parseArrayDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodUnion:
case zod_1.ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
return (0, union_js_1.parseUnionDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodIntersection:
return (0, intersection_js_1.parseIntersectionDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodTuple:
return (0, tuple_js_1.parseTupleDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodRecord:
return (0, record_js_1.parseRecordDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodLiteral:
return (0, literal_js_1.parseLiteralDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodEnum:
return (0, enum_js_1.parseEnumDef)(def);
case zod_1.ZodFirstPartyTypeKind.ZodNativeEnum:
return (0, nativeEnum_js_1.parseNativeEnumDef)(def);
case zod_1.ZodFirstPartyTypeKind.ZodNullable:
return (0, nullable_js_1.parseNullableDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodOptional:
return (0, optional_js_1.parseOptionalDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodMap:
return (0, map_js_1.parseMapDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodSet:
return (0, set_js_1.parseSetDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodLazy:
return () => def.getter()._def;
case zod_1.ZodFirstPartyTypeKind.ZodPromise:
return (0, promise_js_1.parsePromiseDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodNaN:
case zod_1.ZodFirstPartyTypeKind.ZodNever:
return (0, never_js_1.parseNeverDef)();
case zod_1.ZodFirstPartyTypeKind.ZodEffects:
return (0, effects_js_1.parseEffectsDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodAny:
return (0, any_js_1.parseAnyDef)();
case zod_1.ZodFirstPartyTypeKind.ZodUnknown:
return (0, unknown_js_1.parseUnknownDef)();
case zod_1.ZodFirstPartyTypeKind.ZodDefault:
return (0, default_js_1.parseDefaultDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodBranded:
return (0, branded_js_1.parseBrandedDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodReadonly:
return (0, readonly_js_1.parseReadonlyDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodCatch:
return (0, catch_js_1.parseCatchDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodPipeline:
return (0, pipeline_js_1.parsePipelineDef)(def, refs);
case zod_1.ZodFirstPartyTypeKind.ZodFunction:
case zod_1.ZodFirstPartyTypeKind.ZodVoid:
case zod_1.ZodFirstPartyTypeKind.ZodSymbol:
return undefined;
default:
/* c8 ignore next */
return ((_) => undefined)(typeName);
}
};
exports.selectParser = selectParser;

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.zodToJsonSchema = void 0;
const parseDef_js_1 = require("./parseDef.js");
const Refs_js_1 = require("./Refs.js");
const zodToJsonSchema = (schema, options) => {
const refs = (0, Refs_js_1.getRefs)(options);
const definitions = typeof options === "object" && options.definitions
? Object.entries(options.definitions).reduce((acc, [name, schema]) => ({
...acc,
[name]: (0, parseDef_js_1.parseDef)(schema._def, {
...refs,
currentPath: [...refs.basePath, refs.definitionPath, name],
}, true) ?? {},
}), {})
: undefined;
const name = typeof options === "string"
? options
: options?.nameStrategy === "title"
? undefined
: options?.name;
const main = (0, parseDef_js_1.parseDef)(schema._def, name === undefined
? refs
: {
...refs,
currentPath: [...refs.basePath, refs.definitionPath, name],
}, false) ?? {};
const title = typeof options === "object" &&
options.name !== undefined &&
options.nameStrategy === "title"
? options.name
: undefined;
if (title !== undefined) {
main.title = title;
}
const combined = name === undefined
? definitions
? {
...main,
[refs.definitionPath]: definitions,
}
: main
: {
$ref: [
...(refs.$refStrategy === "relative" ? [] : refs.basePath),
refs.definitionPath,
name,
].join("/"),
[refs.definitionPath]: {
...definitions,
[name]: main,
},
};
if (refs.target === "jsonSchema7") {
combined.$schema = "http://json-schema.org/draft-07/schema#";
}
else if (refs.target === "jsonSchema2019-09" || refs.target === "openAi") {
combined.$schema = "https://json-schema.org/draft/2019-09/schema#";
}
if (refs.target === "openAi" &&
("anyOf" in combined ||
"oneOf" in combined ||
"allOf" in combined ||
("type" in combined && Array.isArray(combined.type)))) {
console.warn("Warning: OpenAI may not support schemas with unions as roots! Try wrapping it in an object property.");
}
return combined;
};
exports.zodToJsonSchema = zodToJsonSchema;

45
node_modules/zod-to-json-schema/dist/esm/Options.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
export const ignoreOverride = Symbol("Let zodToJsonSchema decide on which parser to use");
export const jsonDescription = (jsonSchema, def) => {
if (def.description) {
try {
return {
...jsonSchema,
...JSON.parse(def.description),
};
}
catch { }
}
return jsonSchema;
};
export const defaultOptions = {
name: undefined,
$refStrategy: "root",
basePath: ["#"],
effectStrategy: "input",
pipeStrategy: "all",
dateStrategy: "format:date-time",
mapStrategy: "entries",
removeAdditionalStrategy: "passthrough",
allowedAdditionalProperties: true,
rejectedAdditionalProperties: false,
definitionPath: "definitions",
target: "jsonSchema7",
strictUnions: false,
definitions: {},
errorMessages: false,
markdownDescription: false,
patternStrategy: "escape",
applyRegexFlags: false,
emailStrategy: "format:email",
base64Strategy: "contentEncoding:base64",
nameStrategy: "ref",
};
export const getDefaultOptions = (options) => (typeof options === "string"
? {
...defaultOptions,
name: options,
}
: {
...defaultOptions,
...options,
});

21
node_modules/zod-to-json-schema/dist/esm/Refs.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { getDefaultOptions } from "./Options.js";
export const getRefs = (options) => {
const _options = getDefaultOptions(options);
const currentPath = _options.name !== undefined
? [..._options.basePath, _options.definitionPath, _options.name]
: _options.basePath;
return {
..._options,
currentPath: currentPath,
propertyPath: undefined,
seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
def._def,
{
def: def._def,
path: [..._options.basePath, _options.definitionPath, name],
// Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
jsonSchema: undefined,
},
])),
};
};

View File

@@ -0,0 +1,14 @@
export function addErrorMessage(res, key, errorMessage, refs) {
if (!refs?.errorMessages)
return;
if (errorMessage) {
res.errorMessage = {
...res.errorMessage,
[key]: errorMessage,
};
}
}
export function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
res[key] = value;
addErrorMessage(res, key, errorMessage, refs);
}

39
node_modules/zod-to-json-schema/dist/esm/index.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
export * from "./Options.js";
export * from "./Refs.js";
export * from "./errorMessages.js";
export * from "./parseDef.js";
export * from "./parseTypes.js";
export * from "./parsers/any.js";
export * from "./parsers/array.js";
export * from "./parsers/bigint.js";
export * from "./parsers/boolean.js";
export * from "./parsers/branded.js";
export * from "./parsers/catch.js";
export * from "./parsers/date.js";
export * from "./parsers/default.js";
export * from "./parsers/effects.js";
export * from "./parsers/enum.js";
export * from "./parsers/intersection.js";
export * from "./parsers/literal.js";
export * from "./parsers/map.js";
export * from "./parsers/nativeEnum.js";
export * from "./parsers/never.js";
export * from "./parsers/null.js";
export * from "./parsers/nullable.js";
export * from "./parsers/number.js";
export * from "./parsers/object.js";
export * from "./parsers/optional.js";
export * from "./parsers/pipeline.js";
export * from "./parsers/promise.js";
export * from "./parsers/readonly.js";
export * from "./parsers/record.js";
export * from "./parsers/set.js";
export * from "./parsers/string.js";
export * from "./parsers/tuple.js";
export * from "./parsers/undefined.js";
export * from "./parsers/union.js";
export * from "./parsers/unknown.js";
export * from "./selectParser.js";
export * from "./zodToJsonSchema.js";
import { zodToJsonSchema } from "./zodToJsonSchema.js";
export default zodToJsonSchema;

View File

@@ -0,0 +1 @@
{"type":"module","main":"index.js"}

68
node_modules/zod-to-json-schema/dist/esm/parseDef.js generated vendored Normal file
View File

@@ -0,0 +1,68 @@
import { ignoreOverride } from "./Options.js";
import { selectParser } from "./selectParser.js";
export function parseDef(def, refs, forceResolution = false) {
const seenItem = refs.seen.get(def);
if (refs.override) {
const overrideResult = refs.override?.(def, refs, seenItem, forceResolution);
if (overrideResult !== ignoreOverride) {
return overrideResult;
}
}
if (seenItem && !forceResolution) {
const seenSchema = get$ref(seenItem, refs);
if (seenSchema !== undefined) {
return seenSchema;
}
}
const newItem = { def, path: refs.currentPath, jsonSchema: undefined };
refs.seen.set(def, newItem);
const jsonSchemaOrGetter = selectParser(def, def.typeName, refs);
// If the return was a function, then the inner definition needs to be extracted before a call to parseDef (recursive)
const jsonSchema = typeof jsonSchemaOrGetter === "function"
? parseDef(jsonSchemaOrGetter(), refs)
: jsonSchemaOrGetter;
if (jsonSchema) {
addMeta(def, refs, jsonSchema);
}
if (refs.postProcess) {
const postProcessResult = refs.postProcess(jsonSchema, def, refs);
newItem.jsonSchema = jsonSchema;
return postProcessResult;
}
newItem.jsonSchema = jsonSchema;
return jsonSchema;
}
const get$ref = (item, refs) => {
switch (refs.$refStrategy) {
case "root":
return { $ref: item.path.join("/") };
case "relative":
return { $ref: getRelativePath(refs.currentPath, item.path) };
case "none":
case "seen": {
if (item.path.length < refs.currentPath.length &&
item.path.every((value, index) => refs.currentPath[index] === value)) {
console.warn(`Recursive reference detected at ${refs.currentPath.join("/")}! Defaulting to any`);
return {};
}
return refs.$refStrategy === "seen" ? {} : undefined;
}
}
};
const getRelativePath = (pathA, pathB) => {
let i = 0;
for (; i < pathA.length && i < pathB.length; i++) {
if (pathA[i] !== pathB[i])
break;
}
return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/");
};
const addMeta = (def, refs, jsonSchema) => {
if (def.description) {
jsonSchema.description = def.description;
if (refs.markdownDescription) {
jsonSchema.markdownDescription = def.description;
}
}
return jsonSchema;
};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,3 @@
export function parseAnyDef() {
return {};
}

View File

@@ -0,0 +1,26 @@
import { ZodFirstPartyTypeKind } from "zod";
import { setResponseValueAndErrors } from "../errorMessages.js";
import { parseDef } from "../parseDef.js";
export function parseArrayDef(def, refs) {
const res = {
type: "array",
};
if (def.type?._def &&
def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) {
res.items = parseDef(def.type._def, {
...refs,
currentPath: [...refs.currentPath, "items"],
});
}
if (def.minLength) {
setResponseValueAndErrors(res, "minItems", def.minLength.value, def.minLength.message, refs);
}
if (def.maxLength) {
setResponseValueAndErrors(res, "maxItems", def.maxLength.value, def.maxLength.message, refs);
}
if (def.exactLength) {
setResponseValueAndErrors(res, "minItems", def.exactLength.value, def.exactLength.message, refs);
setResponseValueAndErrors(res, "maxItems", def.exactLength.value, def.exactLength.message, refs);
}
return res;
}

View File

@@ -0,0 +1,49 @@
import { setResponseValueAndErrors } from "../errorMessages.js";
export function parseBigintDef(def, refs) {
const res = {
type: "integer",
format: "int64",
};
if (!def.checks)
return res;
for (const check of def.checks) {
switch (check.kind) {
case "min":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
}
else {
setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMinimum = true;
}
setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
}
break;
case "max":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
}
else {
setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMaximum = true;
}
setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
}
break;
case "multipleOf":
setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs);
break;
}
}
return res;
}

View File

@@ -0,0 +1,5 @@
export function parseBooleanDef() {
return {
type: "boolean",
};
}

View File

@@ -0,0 +1,4 @@
import { parseDef } from "../parseDef.js";
export function parseBrandedDef(_def, refs) {
return parseDef(_def.type._def, refs);
}

View File

@@ -0,0 +1,4 @@
import { parseDef } from "../parseDef.js";
export const parseCatchDef = (def, refs) => {
return parseDef(def.innerType._def, refs);
};

View File

@@ -0,0 +1,46 @@
import { setResponseValueAndErrors } from "../errorMessages.js";
export function parseDateDef(def, refs, overrideDateStrategy) {
const strategy = overrideDateStrategy ?? refs.dateStrategy;
if (Array.isArray(strategy)) {
return {
anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),
};
}
switch (strategy) {
case "string":
case "format:date-time":
return {
type: "string",
format: "date-time",
};
case "format:date":
return {
type: "string",
format: "date",
};
case "integer":
return integerDateParser(def, refs);
}
}
const integerDateParser = (def, refs) => {
const res = {
type: "integer",
format: "unix-time",
};
if (refs.target === "openApi3") {
return res;
}
for (const check of def.checks) {
switch (check.kind) {
case "min":
setResponseValueAndErrors(res, "minimum", check.value, // This is in milliseconds
check.message, refs);
break;
case "max":
setResponseValueAndErrors(res, "maximum", check.value, // This is in milliseconds
check.message, refs);
break;
}
}
return res;
};

View File

@@ -0,0 +1,7 @@
import { parseDef } from "../parseDef.js";
export function parseDefaultDef(_def, refs) {
return {
...parseDef(_def.innerType._def, refs),
default: _def.defaultValue(),
};
}

View File

@@ -0,0 +1,6 @@
import { parseDef } from "../parseDef.js";
export function parseEffectsDef(_def, refs) {
return refs.effectStrategy === "input"
? parseDef(_def.schema._def, refs)
: {};
}

View File

@@ -0,0 +1,6 @@
export function parseEnumDef(def) {
return {
type: "string",
enum: Array.from(def.values),
};
}

View File

@@ -0,0 +1,52 @@
import { parseDef } from "../parseDef.js";
const isJsonSchema7AllOfType = (type) => {
if ("type" in type && type.type === "string")
return false;
return "allOf" in type;
};
export function parseIntersectionDef(def, refs) {
const allOf = [
parseDef(def.left._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", "0"],
}),
parseDef(def.right._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", "1"],
}),
].filter((x) => !!x);
let unevaluatedProperties = refs.target === "jsonSchema2019-09"
? { unevaluatedProperties: false }
: undefined;
const mergedAllOf = [];
// If either of the schemas is an allOf, merge them into a single allOf
allOf.forEach((schema) => {
if (isJsonSchema7AllOfType(schema)) {
mergedAllOf.push(...schema.allOf);
if (schema.unevaluatedProperties === undefined) {
// If one of the schemas has no unevaluatedProperties set,
// the merged schema should also have no unevaluatedProperties set
unevaluatedProperties = undefined;
}
}
else {
let nestedSchema = schema;
if ("additionalProperties" in schema &&
schema.additionalProperties === false) {
const { additionalProperties, ...rest } = schema;
nestedSchema = rest;
}
else {
// As soon as one of the schemas has additionalProperties set not to false, we allow unevaluatedProperties
unevaluatedProperties = undefined;
}
mergedAllOf.push(nestedSchema);
}
});
return mergedAllOf.length
? {
allOf: mergedAllOf,
...unevaluatedProperties,
}
: undefined;
}

View File

@@ -0,0 +1,21 @@
export function parseLiteralDef(def, refs) {
const parsedType = typeof def.value;
if (parsedType !== "bigint" &&
parsedType !== "number" &&
parsedType !== "boolean" &&
parsedType !== "string") {
return {
type: Array.isArray(def.value) ? "array" : "object",
};
}
if (refs.target === "openApi3") {
return {
type: parsedType === "bigint" ? "integer" : parsedType,
enum: [def.value],
};
}
return {
type: parsedType === "bigint" ? "integer" : parsedType,
const: def.value,
};
}

View File

@@ -0,0 +1,25 @@
import { parseDef } from "../parseDef.js";
import { parseRecordDef } from "./record.js";
export function parseMapDef(def, refs) {
if (refs.mapStrategy === "record") {
return parseRecordDef(def, refs);
}
const keys = parseDef(def.keyType._def, {
...refs,
currentPath: [...refs.currentPath, "items", "items", "0"],
}) || {};
const values = parseDef(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "items", "items", "1"],
}) || {};
return {
type: "array",
maxItems: 125,
items: {
type: "array",
items: [keys, values],
minItems: 2,
maxItems: 2,
},
};
}

View File

@@ -0,0 +1,16 @@
export function parseNativeEnumDef(def) {
const object = def.values;
const actualKeys = Object.keys(def.values).filter((key) => {
return typeof object[object[key]] !== "number";
});
const actualValues = actualKeys.map((key) => object[key]);
const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
return {
type: parsedTypes.length === 1
? parsedTypes[0] === "string"
? "string"
: "number"
: ["string", "number"],
enum: actualValues,
};
}

View File

@@ -0,0 +1,5 @@
export function parseNeverDef() {
return {
not: {},
};
}

View File

@@ -0,0 +1,10 @@
export function parseNullDef(refs) {
return refs.target === "openApi3"
? {
enum: ["null"],
nullable: true,
}
: {
type: "null",
};
}

View File

@@ -0,0 +1,33 @@
import { parseDef } from "../parseDef.js";
import { primitiveMappings } from "./union.js";
export function parseNullableDef(def, refs) {
if (["ZodString", "ZodNumber", "ZodBigInt", "ZodBoolean", "ZodNull"].includes(def.innerType._def.typeName) &&
(!def.innerType._def.checks || !def.innerType._def.checks.length)) {
if (refs.target === "openApi3") {
return {
type: primitiveMappings[def.innerType._def.typeName],
nullable: true,
};
}
return {
type: [
primitiveMappings[def.innerType._def.typeName],
"null",
],
};
}
if (refs.target === "openApi3") {
const base = parseDef(def.innerType._def, {
...refs,
currentPath: [...refs.currentPath],
});
if (base && "$ref" in base)
return { allOf: [base], nullable: true };
return base && { ...base, nullable: true };
}
const base = parseDef(def.innerType._def, {
...refs,
currentPath: [...refs.currentPath, "anyOf", "0"],
});
return base && { anyOf: [base, { type: "null" }] };
}

View File

@@ -0,0 +1,52 @@
import { addErrorMessage, setResponseValueAndErrors, } from "../errorMessages.js";
export function parseNumberDef(def, refs) {
const res = {
type: "number",
};
if (!def.checks)
return res;
for (const check of def.checks) {
switch (check.kind) {
case "int":
res.type = "integer";
addErrorMessage(res, "type", check.message, refs);
break;
case "min":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
}
else {
setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMinimum = true;
}
setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
}
break;
case "max":
if (refs.target === "jsonSchema7") {
if (check.inclusive) {
setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
}
else {
setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs);
}
}
else {
if (!check.inclusive) {
res.exclusiveMaximum = true;
}
setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
}
break;
case "multipleOf":
setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs);
break;
}
}
return res;
}

View File

@@ -0,0 +1,73 @@
import { ZodOptional } from "zod";
import { parseDef } from "../parseDef.js";
export function parseObjectDef(def, refs) {
const forceOptionalIntoNullable = refs.target === "openAi";
const result = {
type: "object",
properties: {},
};
const required = [];
const shape = def.shape();
for (const propName in shape) {
let propDef = shape[propName];
if (propDef === undefined || propDef._def === undefined) {
continue;
}
let propOptional = safeIsOptional(propDef);
if (propOptional && forceOptionalIntoNullable) {
if (propDef instanceof ZodOptional) {
propDef = propDef._def.innerType;
}
if (!propDef.isNullable()) {
propDef = propDef.nullable();
}
propOptional = false;
}
const parsedDef = parseDef(propDef._def, {
...refs,
currentPath: [...refs.currentPath, "properties", propName],
propertyPath: [...refs.currentPath, "properties", propName],
});
if (parsedDef === undefined) {
continue;
}
result.properties[propName] = parsedDef;
if (!propOptional) {
required.push(propName);
}
}
if (required.length) {
result.required = required;
}
const additionalProperties = decideAdditionalProperties(def, refs);
if (additionalProperties !== undefined) {
result.additionalProperties = additionalProperties;
}
return result;
}
function decideAdditionalProperties(def, refs) {
if (def.catchall._def.typeName !== "ZodNever") {
return parseDef(def.catchall._def, {
...refs,
currentPath: [...refs.currentPath, "additionalProperties"],
});
}
switch (def.unknownKeys) {
case "passthrough":
return refs.allowedAdditionalProperties;
case "strict":
return refs.rejectedAdditionalProperties;
case "strip":
return refs.removeAdditionalStrategy === "strict"
? refs.allowedAdditionalProperties
: refs.rejectedAdditionalProperties;
}
}
function safeIsOptional(schema) {
try {
return schema.isOptional();
}
catch {
return true;
}
}

View File

@@ -0,0 +1,20 @@
import { parseDef } from "../parseDef.js";
export const parseOptionalDef = (def, refs) => {
if (refs.currentPath.toString() === refs.propertyPath?.toString()) {
return parseDef(def.innerType._def, refs);
}
const innerSchema = parseDef(def.innerType._def, {
...refs,
currentPath: [...refs.currentPath, "anyOf", "1"],
});
return innerSchema
? {
anyOf: [
{
not: {},
},
innerSchema,
],
}
: {};
};

View File

@@ -0,0 +1,20 @@
import { parseDef } from "../parseDef.js";
export const parsePipelineDef = (def, refs) => {
if (refs.pipeStrategy === "input") {
return parseDef(def.in._def, refs);
}
else if (refs.pipeStrategy === "output") {
return parseDef(def.out._def, refs);
}
const a = parseDef(def.in._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", "0"],
});
const b = parseDef(def.out._def, {
...refs,
currentPath: [...refs.currentPath, "allOf", a ? "1" : "0"],
});
return {
allOf: [a, b].filter((x) => x !== undefined),
};
};

View File

@@ -0,0 +1,4 @@
import { parseDef } from "../parseDef.js";
export function parsePromiseDef(def, refs) {
return parseDef(def.type._def, refs);
}

View File

@@ -0,0 +1,4 @@
import { parseDef } from "../parseDef.js";
export const parseReadonlyDef = (def, refs) => {
return parseDef(def.innerType._def, refs);
};

View File

@@ -0,0 +1,60 @@
import { ZodFirstPartyTypeKind, } from "zod";
import { parseDef } from "../parseDef.js";
import { parseStringDef } from "./string.js";
import { parseBrandedDef } from "./branded.js";
export function parseRecordDef(def, refs) {
if (refs.target === "openAi") {
console.warn("Warning: OpenAI may not support records in schemas! Try an array of key-value pairs instead.");
}
if (refs.target === "openApi3" &&
def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {
return {
type: "object",
required: def.keyType._def.values,
properties: def.keyType._def.values.reduce((acc, key) => ({
...acc,
[key]: parseDef(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "properties", key],
}) ?? {},
}), {}),
additionalProperties: refs.rejectedAdditionalProperties,
};
}
const schema = {
type: "object",
additionalProperties: parseDef(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "additionalProperties"],
}) ?? refs.allowedAdditionalProperties,
};
if (refs.target === "openApi3") {
return schema;
}
if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString &&
def.keyType._def.checks?.length) {
const { type, ...keyType } = parseStringDef(def.keyType._def, refs);
return {
...schema,
propertyNames: keyType,
};
}
else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodEnum) {
return {
...schema,
propertyNames: {
enum: def.keyType._def.values,
},
};
}
else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodBranded &&
def.keyType._def.type._def.typeName === ZodFirstPartyTypeKind.ZodString &&
def.keyType._def.type._def.checks?.length) {
const { type, ...keyType } = parseBrandedDef(def.keyType._def, refs);
return {
...schema,
propertyNames: keyType,
};
}
return schema;
}

View File

@@ -0,0 +1,20 @@
import { setResponseValueAndErrors } from "../errorMessages.js";
import { parseDef } from "../parseDef.js";
export function parseSetDef(def, refs) {
const items = parseDef(def.valueType._def, {
...refs,
currentPath: [...refs.currentPath, "items"],
});
const schema = {
type: "array",
uniqueItems: true,
items,
};
if (def.minSize) {
setResponseValueAndErrors(schema, "minItems", def.minSize.value, def.minSize.message, refs);
}
if (def.maxSize) {
setResponseValueAndErrors(schema, "maxItems", def.maxSize.value, def.maxSize.message, refs);
}
return schema;
}

View File

@@ -0,0 +1,353 @@
import { setResponseValueAndErrors } from "../errorMessages.js";
let emojiRegex = undefined;
/**
* Generated from the regular expressions found here as of 2024-05-22:
* https://github.com/colinhacks/zod/blob/master/src/types.ts.
*
* Expressions with /i flag have been changed accordingly.
*/
export const zodPatterns = {
/**
* `c` was changed to `[cC]` to replicate /i flag
*/
cuid: /^[cC][^\s-]{8,}$/,
cuid2: /^[0-9a-z]+$/,
ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
/**
* `a-z` was added to replicate /i flag
*/
email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
/**
* Constructed a valid Unicode RegExp
*
* Lazily instantiate since this type of regex isn't supported
* in all envs (e.g. React Native).
*
* See:
* https://github.com/colinhacks/zod/issues/2433
* Fix in Zod:
* https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b
*/
emoji: () => {
if (emojiRegex === undefined) {
emojiRegex = RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$", "u");
}
return emojiRegex;
},
/**
* Unused
*/
uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
/**
* Unused
*/
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,
ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,
/**
* Unused
*/
ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,
ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,
base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,
nanoid: /^[a-zA-Z0-9_-]{21}$/,
jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,
};
export function parseStringDef(def, refs) {
const res = {
type: "string",
};
if (def.checks) {
for (const check of def.checks) {
switch (check.kind) {
case "min":
setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number"
? Math.max(res.minLength, check.value)
: check.value, check.message, refs);
break;
case "max":
setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number"
? Math.min(res.maxLength, check.value)
: check.value, check.message, refs);
break;
case "email":
switch (refs.emailStrategy) {
case "format:email":
addFormat(res, "email", check.message, refs);
break;
case "format:idn-email":
addFormat(res, "idn-email", check.message, refs);
break;
case "pattern:zod":
addPattern(res, zodPatterns.email, check.message, refs);
break;
}
break;
case "url":
addFormat(res, "uri", check.message, refs);
break;
case "uuid":
addFormat(res, "uuid", check.message, refs);
break;
case "regex":
addPattern(res, check.regex, check.message, refs);
break;
case "cuid":
addPattern(res, zodPatterns.cuid, check.message, refs);
break;
case "cuid2":
addPattern(res, zodPatterns.cuid2, check.message, refs);
break;
case "startsWith":
addPattern(res, RegExp(`^${escapeLiteralCheckValue(check.value, refs)}`), check.message, refs);
break;
case "endsWith":
addPattern(res, RegExp(`${escapeLiteralCheckValue(check.value, refs)}$`), check.message, refs);
break;
case "datetime":
addFormat(res, "date-time", check.message, refs);
break;
case "date":
addFormat(res, "date", check.message, refs);
break;
case "time":
addFormat(res, "time", check.message, refs);
break;
case "duration":
addFormat(res, "duration", check.message, refs);
break;
case "length":
setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number"
? Math.max(res.minLength, check.value)
: check.value, check.message, refs);
setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number"
? Math.min(res.maxLength, check.value)
: check.value, check.message, refs);
break;
case "includes": {
addPattern(res, RegExp(escapeLiteralCheckValue(check.value, refs)), check.message, refs);
break;
}
case "ip": {
if (check.version !== "v6") {
addFormat(res, "ipv4", check.message, refs);
}
if (check.version !== "v4") {
addFormat(res, "ipv6", check.message, refs);
}
break;
}
case "base64url":
addPattern(res, zodPatterns.base64url, check.message, refs);
break;
case "jwt":
addPattern(res, zodPatterns.jwt, check.message, refs);
break;
case "cidr": {
if (check.version !== "v6") {
addPattern(res, zodPatterns.ipv4Cidr, check.message, refs);
}
if (check.version !== "v4") {
addPattern(res, zodPatterns.ipv6Cidr, check.message, refs);
}
break;
}
case "emoji":
addPattern(res, zodPatterns.emoji(), check.message, refs);
break;
case "ulid": {
addPattern(res, zodPatterns.ulid, check.message, refs);
break;
}
case "base64": {
switch (refs.base64Strategy) {
case "format:binary": {
addFormat(res, "binary", check.message, refs);
break;
}
case "contentEncoding:base64": {
setResponseValueAndErrors(res, "contentEncoding", "base64", check.message, refs);
break;
}
case "pattern:zod": {
addPattern(res, zodPatterns.base64, check.message, refs);
break;
}
}
break;
}
case "nanoid": {
addPattern(res, zodPatterns.nanoid, check.message, refs);
}
case "toLowerCase":
case "toUpperCase":
case "trim":
break;
default:
/* c8 ignore next */
((_) => { })(check);
}
}
}
return res;
}
function escapeLiteralCheckValue(literal, refs) {
return refs.patternStrategy === "escape"
? escapeNonAlphaNumeric(literal)
: literal;
}
const ALPHA_NUMERIC = new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");
function escapeNonAlphaNumeric(source) {
let result = "";
for (let i = 0; i < source.length; i++) {
if (!ALPHA_NUMERIC.has(source[i])) {
result += "\\";
}
result += source[i];
}
return result;
}
// Adds a "format" keyword to the schema. If a format exists, both formats will be joined in an allOf-node, along with subsequent ones.
function addFormat(schema, value, message, refs) {
if (schema.format || schema.anyOf?.some((x) => x.format)) {
if (!schema.anyOf) {
schema.anyOf = [];
}
if (schema.format) {
schema.anyOf.push({
format: schema.format,
...(schema.errorMessage &&
refs.errorMessages && {
errorMessage: { format: schema.errorMessage.format },
}),
});
delete schema.format;
if (schema.errorMessage) {
delete schema.errorMessage.format;
if (Object.keys(schema.errorMessage).length === 0) {
delete schema.errorMessage;
}
}
}
schema.anyOf.push({
format: value,
...(message &&
refs.errorMessages && { errorMessage: { format: message } }),
});
}
else {
setResponseValueAndErrors(schema, "format", value, message, refs);
}
}
// Adds a "pattern" keyword to the schema. If a pattern exists, both patterns will be joined in an allOf-node, along with subsequent ones.
function addPattern(schema, regex, message, refs) {
if (schema.pattern || schema.allOf?.some((x) => x.pattern)) {
if (!schema.allOf) {
schema.allOf = [];
}
if (schema.pattern) {
schema.allOf.push({
pattern: schema.pattern,
...(schema.errorMessage &&
refs.errorMessages && {
errorMessage: { pattern: schema.errorMessage.pattern },
}),
});
delete schema.pattern;
if (schema.errorMessage) {
delete schema.errorMessage.pattern;
if (Object.keys(schema.errorMessage).length === 0) {
delete schema.errorMessage;
}
}
}
schema.allOf.push({
pattern: stringifyRegExpWithFlags(regex, refs),
...(message &&
refs.errorMessages && { errorMessage: { pattern: message } }),
});
}
else {
setResponseValueAndErrors(schema, "pattern", stringifyRegExpWithFlags(regex, refs), message, refs);
}
}
// Mutate z.string.regex() in a best attempt to accommodate for regex flags when applyRegexFlags is true
function stringifyRegExpWithFlags(regex, refs) {
if (!refs.applyRegexFlags || !regex.flags) {
return regex.source;
}
// Currently handled flags
const flags = {
i: regex.flags.includes("i"),
m: regex.flags.includes("m"),
s: regex.flags.includes("s"), // `.` matches newlines
};
// The general principle here is to step through each character, one at a time, applying mutations as flags require. We keep track when the current character is escaped, and when it's inside a group /like [this]/ or (also) a range like /[a-z]/. The following is fairly brittle imperative code; edit at your peril!
const source = flags.i ? regex.source.toLowerCase() : regex.source;
let pattern = "";
let isEscaped = false;
let inCharGroup = false;
let inCharRange = false;
for (let i = 0; i < source.length; i++) {
if (isEscaped) {
pattern += source[i];
isEscaped = false;
continue;
}
if (flags.i) {
if (inCharGroup) {
if (source[i].match(/[a-z]/)) {
if (inCharRange) {
pattern += source[i];
pattern += `${source[i - 2]}-${source[i]}`.toUpperCase();
inCharRange = false;
}
else if (source[i + 1] === "-" && source[i + 2]?.match(/[a-z]/)) {
pattern += source[i];
inCharRange = true;
}
else {
pattern += `${source[i]}${source[i].toUpperCase()}`;
}
continue;
}
}
else if (source[i].match(/[a-z]/)) {
pattern += `[${source[i]}${source[i].toUpperCase()}]`;
continue;
}
}
if (flags.m) {
if (source[i] === "^") {
pattern += `(^|(?<=[\r\n]))`;
continue;
}
else if (source[i] === "$") {
pattern += `($|(?=[\r\n]))`;
continue;
}
}
if (flags.s && source[i] === ".") {
pattern += inCharGroup ? `${source[i]}\r\n` : `[${source[i]}\r\n]`;
continue;
}
pattern += source[i];
if (source[i] === "\\") {
isEscaped = true;
}
else if (inCharGroup && source[i] === "]") {
inCharGroup = false;
}
else if (!inCharGroup && source[i] === "[") {
inCharGroup = true;
}
}
try {
new RegExp(pattern);
}
catch {
console.warn(`Could not convert regex pattern at ${refs.currentPath.join("/")} to a flag-independent form! Falling back to the flag-ignorant source`);
return regex.source;
}
return pattern;
}

View File

@@ -0,0 +1,32 @@
import { parseDef } from "../parseDef.js";
export function parseTupleDef(def, refs) {
if (def.rest) {
return {
type: "array",
minItems: def.items.length,
items: def.items
.map((x, i) => parseDef(x._def, {
...refs,
currentPath: [...refs.currentPath, "items", `${i}`],
}))
.reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
additionalItems: parseDef(def.rest._def, {
...refs,
currentPath: [...refs.currentPath, "additionalItems"],
}),
};
}
else {
return {
type: "array",
minItems: def.items.length,
maxItems: def.items.length,
items: def.items
.map((x, i) => parseDef(x._def, {
...refs,
currentPath: [...refs.currentPath, "items", `${i}`],
}))
.reduce((acc, x) => (x === undefined ? acc : [...acc, x]), []),
};
}
}

View File

@@ -0,0 +1,5 @@
export function parseUndefinedDef() {
return {
not: {},
};
}

View File

@@ -0,0 +1,80 @@
import { parseDef } from "../parseDef.js";
export const primitiveMappings = {
ZodString: "string",
ZodNumber: "number",
ZodBigInt: "integer",
ZodBoolean: "boolean",
ZodNull: "null",
};
export function parseUnionDef(def, refs) {
if (refs.target === "openApi3")
return asAnyOf(def, refs);
const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
// This blocks tries to look ahead a bit to produce nicer looking schemas with type array instead of anyOf.
if (options.every((x) => x._def.typeName in primitiveMappings &&
(!x._def.checks || !x._def.checks.length))) {
// all types in union are primitive and lack checks, so might as well squash into {type: [...]}
const types = options.reduce((types, x) => {
const type = primitiveMappings[x._def.typeName]; //Can be safely casted due to row 43
return type && !types.includes(type) ? [...types, type] : types;
}, []);
return {
type: types.length > 1 ? types : types[0],
};
}
else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) {
// all options literals
const types = options.reduce((acc, x) => {
const type = typeof x._def.value;
switch (type) {
case "string":
case "number":
case "boolean":
return [...acc, type];
case "bigint":
return [...acc, "integer"];
case "object":
if (x._def.value === null)
return [...acc, "null"];
case "symbol":
case "undefined":
case "function":
default:
return acc;
}
}, []);
if (types.length === options.length) {
// all the literals are primitive, as far as null can be considered primitive
const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
return {
type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
enum: options.reduce((acc, x) => {
return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
}, []),
};
}
}
else if (options.every((x) => x._def.typeName === "ZodEnum")) {
return {
type: "string",
enum: options.reduce((acc, x) => [
...acc,
...x._def.values.filter((x) => !acc.includes(x)),
], []),
};
}
return asAnyOf(def, refs);
}
const asAnyOf = (def, refs) => {
const anyOf = (def.options instanceof Map
? Array.from(def.options.values())
: def.options)
.map((x, i) => parseDef(x._def, {
...refs,
currentPath: [...refs.currentPath, "anyOf", `${i}`],
}))
.filter((x) => !!x &&
(!refs.strictUnions ||
(typeof x === "object" && Object.keys(x).length > 0)));
return anyOf.length ? { anyOf } : undefined;
};

View File

@@ -0,0 +1,3 @@
export function parseUnknownDef() {
return {};
}

View File

@@ -0,0 +1,106 @@
import { ZodFirstPartyTypeKind } from "zod";
import { parseAnyDef } from "./parsers/any.js";
import { parseArrayDef } from "./parsers/array.js";
import { parseBigintDef } from "./parsers/bigint.js";
import { parseBooleanDef } from "./parsers/boolean.js";
import { parseBrandedDef } from "./parsers/branded.js";
import { parseCatchDef } from "./parsers/catch.js";
import { parseDateDef } from "./parsers/date.js";
import { parseDefaultDef } from "./parsers/default.js";
import { parseEffectsDef } from "./parsers/effects.js";
import { parseEnumDef } from "./parsers/enum.js";
import { parseIntersectionDef } from "./parsers/intersection.js";
import { parseLiteralDef } from "./parsers/literal.js";
import { parseMapDef } from "./parsers/map.js";
import { parseNativeEnumDef } from "./parsers/nativeEnum.js";
import { parseNeverDef } from "./parsers/never.js";
import { parseNullDef } from "./parsers/null.js";
import { parseNullableDef } from "./parsers/nullable.js";
import { parseNumberDef } from "./parsers/number.js";
import { parseObjectDef } from "./parsers/object.js";
import { parseOptionalDef } from "./parsers/optional.js";
import { parsePipelineDef } from "./parsers/pipeline.js";
import { parsePromiseDef } from "./parsers/promise.js";
import { parseRecordDef } from "./parsers/record.js";
import { parseSetDef } from "./parsers/set.js";
import { parseStringDef } from "./parsers/string.js";
import { parseTupleDef } from "./parsers/tuple.js";
import { parseUndefinedDef } from "./parsers/undefined.js";
import { parseUnionDef } from "./parsers/union.js";
import { parseUnknownDef } from "./parsers/unknown.js";
import { parseReadonlyDef } from "./parsers/readonly.js";
export const selectParser = (def, typeName, refs) => {
switch (typeName) {
case ZodFirstPartyTypeKind.ZodString:
return parseStringDef(def, refs);
case ZodFirstPartyTypeKind.ZodNumber:
return parseNumberDef(def, refs);
case ZodFirstPartyTypeKind.ZodObject:
return parseObjectDef(def, refs);
case ZodFirstPartyTypeKind.ZodBigInt:
return parseBigintDef(def, refs);
case ZodFirstPartyTypeKind.ZodBoolean:
return parseBooleanDef();
case ZodFirstPartyTypeKind.ZodDate:
return parseDateDef(def, refs);
case ZodFirstPartyTypeKind.ZodUndefined:
return parseUndefinedDef();
case ZodFirstPartyTypeKind.ZodNull:
return parseNullDef(refs);
case ZodFirstPartyTypeKind.ZodArray:
return parseArrayDef(def, refs);
case ZodFirstPartyTypeKind.ZodUnion:
case ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
return parseUnionDef(def, refs);
case ZodFirstPartyTypeKind.ZodIntersection:
return parseIntersectionDef(def, refs);
case ZodFirstPartyTypeKind.ZodTuple:
return parseTupleDef(def, refs);
case ZodFirstPartyTypeKind.ZodRecord:
return parseRecordDef(def, refs);
case ZodFirstPartyTypeKind.ZodLiteral:
return parseLiteralDef(def, refs);
case ZodFirstPartyTypeKind.ZodEnum:
return parseEnumDef(def);
case ZodFirstPartyTypeKind.ZodNativeEnum:
return parseNativeEnumDef(def);
case ZodFirstPartyTypeKind.ZodNullable:
return parseNullableDef(def, refs);
case ZodFirstPartyTypeKind.ZodOptional:
return parseOptionalDef(def, refs);
case ZodFirstPartyTypeKind.ZodMap:
return parseMapDef(def, refs);
case ZodFirstPartyTypeKind.ZodSet:
return parseSetDef(def, refs);
case ZodFirstPartyTypeKind.ZodLazy:
return () => def.getter()._def;
case ZodFirstPartyTypeKind.ZodPromise:
return parsePromiseDef(def, refs);
case ZodFirstPartyTypeKind.ZodNaN:
case ZodFirstPartyTypeKind.ZodNever:
return parseNeverDef();
case ZodFirstPartyTypeKind.ZodEffects:
return parseEffectsDef(def, refs);
case ZodFirstPartyTypeKind.ZodAny:
return parseAnyDef();
case ZodFirstPartyTypeKind.ZodUnknown:
return parseUnknownDef();
case ZodFirstPartyTypeKind.ZodDefault:
return parseDefaultDef(def, refs);
case ZodFirstPartyTypeKind.ZodBranded:
return parseBrandedDef(def, refs);
case ZodFirstPartyTypeKind.ZodReadonly:
return parseReadonlyDef(def, refs);
case ZodFirstPartyTypeKind.ZodCatch:
return parseCatchDef(def, refs);
case ZodFirstPartyTypeKind.ZodPipeline:
return parsePipelineDef(def, refs);
case ZodFirstPartyTypeKind.ZodFunction:
case ZodFirstPartyTypeKind.ZodVoid:
case ZodFirstPartyTypeKind.ZodSymbol:
return undefined;
default:
/* c8 ignore next */
return ((_) => undefined)(typeName);
}
};

View File

@@ -0,0 +1,66 @@
import { parseDef } from "./parseDef.js";
import { getRefs } from "./Refs.js";
const zodToJsonSchema = (schema, options) => {
const refs = getRefs(options);
const definitions = typeof options === "object" && options.definitions
? Object.entries(options.definitions).reduce((acc, [name, schema]) => ({
...acc,
[name]: parseDef(schema._def, {
...refs,
currentPath: [...refs.basePath, refs.definitionPath, name],
}, true) ?? {},
}), {})
: undefined;
const name = typeof options === "string"
? options
: options?.nameStrategy === "title"
? undefined
: options?.name;
const main = parseDef(schema._def, name === undefined
? refs
: {
...refs,
currentPath: [...refs.basePath, refs.definitionPath, name],
}, false) ?? {};
const title = typeof options === "object" &&
options.name !== undefined &&
options.nameStrategy === "title"
? options.name
: undefined;
if (title !== undefined) {
main.title = title;
}
const combined = name === undefined
? definitions
? {
...main,
[refs.definitionPath]: definitions,
}
: main
: {
$ref: [
...(refs.$refStrategy === "relative" ? [] : refs.basePath),
refs.definitionPath,
name,
].join("/"),
[refs.definitionPath]: {
...definitions,
[name]: main,
},
};
if (refs.target === "jsonSchema7") {
combined.$schema = "http://json-schema.org/draft-07/schema#";
}
else if (refs.target === "jsonSchema2019-09" || refs.target === "openAi") {
combined.$schema = "https://json-schema.org/draft/2019-09/schema#";
}
if (refs.target === "openAi" &&
("anyOf" in combined ||
"oneOf" in combined ||
"allOf" in combined ||
("type" in combined && Array.isArray(combined.type)))) {
console.warn("Warning: OpenAI may not support schemas with unions as roots! Try wrapping it in an object property.");
}
return combined;
};
export { zodToJsonSchema };

View File

@@ -0,0 +1,36 @@
import { ZodSchema, ZodTypeDef } from "zod";
import { Refs, Seen } from "./Refs";
import { JsonSchema7Type } from "./parseTypes";
export type Targets = "jsonSchema7" | "jsonSchema2019-09" | "openApi3" | "openAi";
export type DateStrategy = "format:date-time" | "format:date" | "string" | "integer";
export declare const ignoreOverride: unique symbol;
export type OverrideCallback = (def: ZodTypeDef, refs: Refs, seen: Seen | undefined, forceResolution?: boolean) => JsonSchema7Type | undefined | typeof ignoreOverride;
export type PostProcessCallback = (jsonSchema: JsonSchema7Type | undefined, def: ZodTypeDef, refs: Refs) => JsonSchema7Type | undefined;
export declare const jsonDescription: PostProcessCallback;
export type Options<Target extends Targets = "jsonSchema7"> = {
name: string | undefined;
$refStrategy: "root" | "relative" | "none" | "seen";
basePath: string[];
effectStrategy: "input" | "any";
pipeStrategy: "input" | "output" | "all";
dateStrategy: DateStrategy | DateStrategy[];
mapStrategy: "entries" | "record";
removeAdditionalStrategy: "passthrough" | "strict";
allowedAdditionalProperties: true | undefined;
rejectedAdditionalProperties: false | undefined;
target: Target;
strictUnions: boolean;
definitionPath: string;
definitions: Record<string, ZodSchema>;
errorMessages: boolean;
markdownDescription: boolean;
patternStrategy: "escape" | "preserve";
applyRegexFlags: boolean;
emailStrategy: "format:email" | "format:idn-email" | "pattern:zod";
base64Strategy: "format:binary" | "contentEncoding:base64" | "pattern:zod";
nameStrategy: "ref" | "title";
override?: OverrideCallback;
postProcess?: PostProcessCallback;
};
export declare const defaultOptions: Options;
export declare const getDefaultOptions: <Target extends Targets>(options: string | Partial<Options<Target>> | undefined) => Options<Target>;

14
node_modules/zod-to-json-schema/dist/types/Refs.d.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import { ZodTypeDef } from "zod";
import { Options, Targets } from "./Options.js";
import { JsonSchema7Type } from "./parseTypes.js";
export type Refs = {
seen: Map<ZodTypeDef, Seen>;
currentPath: string[];
propertyPath: string[] | undefined;
} & Options<Targets>;
export type Seen = {
def: ZodTypeDef;
path: string[];
jsonSchema: JsonSchema7Type | undefined;
};
export declare const getRefs: (options?: string | Partial<Options<Targets>>) => Refs;

View File

@@ -0,0 +1,11 @@
import { JsonSchema7TypeUnion } from "./parseTypes.js";
import { Refs } from "./Refs.js";
export type ErrorMessages<T extends JsonSchema7TypeUnion, OmitProperties extends string = ""> = Partial<Omit<{
[key in keyof T]: string;
}, OmitProperties | "type" | "errorMessages">>;
export declare function addErrorMessage<T extends {
errorMessage?: ErrorMessages<any>;
}>(res: T, key: keyof T, errorMessage: string | undefined, refs: Refs): void;
export declare function setResponseValueAndErrors<Json7Type extends JsonSchema7TypeUnion & {
errorMessage?: ErrorMessages<Json7Type>;
}, Key extends keyof Omit<Json7Type, "errorMessage">>(res: Json7Type, key: Key, value: Json7Type[Key], errorMessage: string | undefined, refs: Refs): void;

39
node_modules/zod-to-json-schema/dist/types/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,39 @@
export * from "./Options.js";
export * from "./Refs.js";
export * from "./errorMessages.js";
export * from "./parseDef.js";
export * from "./parseTypes.js";
export * from "./parsers/any.js";
export * from "./parsers/array.js";
export * from "./parsers/bigint.js";
export * from "./parsers/boolean.js";
export * from "./parsers/branded.js";
export * from "./parsers/catch.js";
export * from "./parsers/date.js";
export * from "./parsers/default.js";
export * from "./parsers/effects.js";
export * from "./parsers/enum.js";
export * from "./parsers/intersection.js";
export * from "./parsers/literal.js";
export * from "./parsers/map.js";
export * from "./parsers/nativeEnum.js";
export * from "./parsers/never.js";
export * from "./parsers/null.js";
export * from "./parsers/nullable.js";
export * from "./parsers/number.js";
export * from "./parsers/object.js";
export * from "./parsers/optional.js";
export * from "./parsers/pipeline.js";
export * from "./parsers/promise.js";
export * from "./parsers/readonly.js";
export * from "./parsers/record.js";
export * from "./parsers/set.js";
export * from "./parsers/string.js";
export * from "./parsers/tuple.js";
export * from "./parsers/undefined.js";
export * from "./parsers/union.js";
export * from "./parsers/unknown.js";
export * from "./selectParser.js";
export * from "./zodToJsonSchema.js";
import { zodToJsonSchema } from "./zodToJsonSchema.js";
export default zodToJsonSchema;

View File

@@ -0,0 +1,4 @@
import { ZodTypeDef } from "zod";
import { Refs } from "./Refs.js";
import { JsonSchema7Type } from "./parseTypes.js";
export declare function parseDef(def: ZodTypeDef, refs: Refs, forceResolution?: boolean): JsonSchema7Type | undefined;

View File

@@ -0,0 +1,34 @@
import { JsonSchema7AnyType } from "./parsers/any.js";
import { JsonSchema7ArrayType } from "./parsers/array.js";
import { JsonSchema7BigintType } from "./parsers/bigint.js";
import { JsonSchema7BooleanType } from "./parsers/boolean.js";
import { JsonSchema7DateType } from "./parsers/date.js";
import { JsonSchema7EnumType } from "./parsers/enum.js";
import { JsonSchema7AllOfType } from "./parsers/intersection.js";
import { JsonSchema7LiteralType } from "./parsers/literal.js";
import { JsonSchema7MapType } from "./parsers/map.js";
import { JsonSchema7NativeEnumType } from "./parsers/nativeEnum.js";
import { JsonSchema7NeverType } from "./parsers/never.js";
import { JsonSchema7NullType } from "./parsers/null.js";
import { JsonSchema7NullableType } from "./parsers/nullable.js";
import { JsonSchema7NumberType } from "./parsers/number.js";
import { JsonSchema7ObjectType } from "./parsers/object.js";
import { JsonSchema7RecordType } from "./parsers/record.js";
import { JsonSchema7SetType } from "./parsers/set.js";
import { JsonSchema7StringType } from "./parsers/string.js";
import { JsonSchema7TupleType } from "./parsers/tuple.js";
import { JsonSchema7UndefinedType } from "./parsers/undefined.js";
import { JsonSchema7UnionType } from "./parsers/union.js";
import { JsonSchema7UnknownType } from "./parsers/unknown.js";
type JsonSchema7RefType = {
$ref: string;
};
type JsonSchema7Meta = {
title?: string;
default?: any;
description?: string;
markdownDescription?: string;
};
export type JsonSchema7TypeUnion = JsonSchema7StringType | JsonSchema7ArrayType | JsonSchema7NumberType | JsonSchema7BigintType | JsonSchema7BooleanType | JsonSchema7DateType | JsonSchema7EnumType | JsonSchema7LiteralType | JsonSchema7NativeEnumType | JsonSchema7NullType | JsonSchema7NumberType | JsonSchema7ObjectType | JsonSchema7RecordType | JsonSchema7TupleType | JsonSchema7UnionType | JsonSchema7UndefinedType | JsonSchema7RefType | JsonSchema7NeverType | JsonSchema7MapType | JsonSchema7AnyType | JsonSchema7NullableType | JsonSchema7AllOfType | JsonSchema7UnknownType | JsonSchema7SetType;
export type JsonSchema7Type = JsonSchema7TypeUnion & JsonSchema7Meta;
export {};

View File

@@ -0,0 +1,2 @@
export type JsonSchema7AnyType = {};
export declare function parseAnyDef(): JsonSchema7AnyType;

View File

@@ -0,0 +1,12 @@
import { ZodArrayDef } from "zod";
import { ErrorMessages } from "../errorMessages.js";
import { JsonSchema7Type } from "../parseTypes.js";
import { Refs } from "../Refs.js";
export type JsonSchema7ArrayType = {
type: "array";
items?: JsonSchema7Type;
minItems?: number;
maxItems?: number;
errorMessages?: ErrorMessages<JsonSchema7ArrayType, "items">;
};
export declare function parseArrayDef(def: ZodArrayDef, refs: Refs): JsonSchema7ArrayType;

View File

@@ -0,0 +1,14 @@
import { ZodBigIntDef } from "zod";
import { Refs } from "../Refs.js";
import { ErrorMessages } from "../errorMessages.js";
export type JsonSchema7BigintType = {
type: "integer";
format: "int64";
minimum?: BigInt;
exclusiveMinimum?: BigInt;
maximum?: BigInt;
exclusiveMaximum?: BigInt;
multipleOf?: BigInt;
errorMessage?: ErrorMessages<JsonSchema7BigintType>;
};
export declare function parseBigintDef(def: ZodBigIntDef, refs: Refs): JsonSchema7BigintType;

View File

@@ -0,0 +1,4 @@
export type JsonSchema7BooleanType = {
type: "boolean";
};
export declare function parseBooleanDef(): JsonSchema7BooleanType;

View File

@@ -0,0 +1,3 @@
import { ZodBrandedDef } from "zod";
import { Refs } from "../Refs.js";
export declare function parseBrandedDef(_def: ZodBrandedDef<any>, refs: Refs): import("../parseTypes.js").JsonSchema7Type | undefined;

View File

@@ -0,0 +1,3 @@
import { ZodCatchDef } from "zod";
import { Refs } from "../Refs.js";
export declare const parseCatchDef: (def: ZodCatchDef<any>, refs: Refs) => import("../parseTypes.js").JsonSchema7Type | undefined;

View File

@@ -0,0 +1,15 @@
import { ZodDateDef } from "zod";
import { Refs } from "../Refs.js";
import { ErrorMessages } from "../errorMessages.js";
import { JsonSchema7NumberType } from "./number.js";
import { DateStrategy } from "../Options.js";
export type JsonSchema7DateType = {
type: "integer" | "string";
format: "unix-time" | "date-time" | "date";
minimum?: number;
maximum?: number;
errorMessage?: ErrorMessages<JsonSchema7NumberType>;
} | {
anyOf: JsonSchema7DateType[];
};
export declare function parseDateDef(def: ZodDateDef, refs: Refs, overrideDateStrategy?: DateStrategy): JsonSchema7DateType;

Some files were not shown because too many files have changed in this diff Show More