feat: Reinitialize frontend with SvelteKit and TypeScript

- Delete old Vite+Svelte frontend
- Initialize new SvelteKit project with TypeScript
- Configure Tailwind CSS v4 + DaisyUI
- Implement JWT authentication with auto-refresh
- Create login page with form validation (Zod)
- Add protected route guards
- Update Docker configuration for single-stage build
- Add E2E tests with Playwright (6/11 passing)
- Fix Svelte 5 reactivity with $state() runes

Known issues:
- 5 E2E tests failing (timing/async issues)
- Token refresh implementation needs debugging
- Validation error display timing
This commit is contained in:
2026-02-17 16:19:59 -05:00
parent 54df6018f5
commit de2d83092e
28274 changed files with 3816354 additions and 90 deletions

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Fabian Hiller
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

448
frontend/node_modules/@valibot/to-json-schema/README.md generated vendored Normal file
View File

@@ -0,0 +1,448 @@
# Valibot to JSON Schema
Utility to convert [Valibot](https://valibot.dev) schemas to JSON Schema. Supports JSON Schema draft-07, draft-2020-12, and OpenAPI 3.0 Schema Object formats.
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
toJsonSchema(v.string()); // { $schema: "http://json-schema.org/draft-07/schema#", type: "string" }
```
This package is particularly popular for:
- **API Documentation**: Generate OpenAPI specifications from your Valibot schemas
- **Code Generation**: Create client SDKs and types from your validation schemas
- **LLM Integration**: Generate structured outputs for Large Language Models
- **Schema Sharing**: Share validation logic between different programming languages
> Some Valibot features can't be mapped to JSON schema. For example, transformation actions have no equivalent in JSON schema. Also, some Valibot schemas or validations are too JS-specific and do not have an equivalent JSON schema attribute.
## Supported features
**Note**: Converted schemas may behave slightly differently in JSON schema validators (especially for string format) because their implementation is different from Valibot's.
| Schema | Status | Note |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `any` | ✅ | |
| `array` | ✅ | |
| `boolean` | ✅ | |
| `enum` | ✅ | |
| `exactOptional` | ✅ | |
| `intersect` | ✅ | |
| `lazy` | ⚠️ | The `.getter` function is always executed with `undefined` as input |
| `literal` | ⚠️ | Only JSON compatible values are supported |
| `looseObject` | ✅ | |
| `looseTuple` | ✅ | |
| `null` | ✅ | |
| `nullable` | ✅ | |
| `nullish` | ✅ | |
| `number` | ✅ | |
| `objectWithRest` | ✅ | |
| `object` | ✅ | |
| `optional` | ✅ | |
| `picklist` | ⚠️ | Only JSON compatible values are supported |
| `record` | ⚠️ | Only `string` schemas for the key of the record are supported. Adds `propertyNames` for key validation (not available in OpenAPI 3.0) |
| `strictObject` | ✅ | |
| `strictTuple` | ✅ | |
| `string` | ✅ | |
| `tupleWithRest` | ✅ | |
| `tuple` | ✅ | |
| `union` | ✅ | |
| `undefinedable` | ✅ | |
| `unknown` | ✅ | |
| `variant` | ⚠️ | The discriminator key will be ignored |
| Actions | Status | Note |
| -------------- | ------ | ----------------------------------------------------------- |
| `base64` | ✅ | |
| `bic` | ✅ | |
| `cuid2` | ✅ | |
| `decimal` | ✅ | |
| `description` | ✅ | |
| `digits` | ✅ | |
| `email` | ✅ | |
| `emoji` | ✅ | |
| `empty` | ✅ | |
| `entries` | ✅ | |
| `hexadecimal` | ✅ | |
| `hexColor` | ✅ | |
| `integer` | ✅ | |
| `ipv4` | ✅ | |
| `ipv6` | ✅ | |
| `isoDate` | ✅ | |
| `isoDateTime` | ✅ | |
| `isoTime` | ✅ | |
| `isoTimestamp` | ✅ | |
| `length` | ⚠️ | Only in combination with `string` and `array` schema |
| `maxEntries` | ✅ | |
| `maxLength` | ⚠️ | Only in combination with `string` and `array` schema |
| `maxValue` | ⚠️ | Only in combination with `number` schema |
| `metadata` | ⚠️ | Only for valid `title`, `description` and `examples` values |
| `minEntries` | ✅ | |
| `minLength` | ⚠️ | Only in combination with `string` and `array` schemas |
| `minValue` | ⚠️ | Only in combination with `number` schema |
| `multipleOf` | ✅ | |
| `nanoid` | ✅ | |
| `nonEmpty` | ✅ | |
| `octal` | ✅ | |
| `regex` | ⚠️ | RexExp flags are not supported in JSON schema |
| `title` | ✅ | |
| `ulid` | ✅ | |
| `url` | ✅ | |
| `uuid` | ✅ | |
| `value` | ✅ | |
## Configurations
| Option | Type | Note |
| -------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| target | `'draft-07' \| 'draft-2020-12' \| 'openapi-3.0'` | The target JSON Schema format. Defaults to `'draft-07'`. |
| typeMode | `'ignore' \| 'input' \| 'output'` | Whether to convert the input or output type of the Valibot schema to JSON Schema. |
| errorMode | `'throw' \| 'warn' \| 'ignore'` | The policy for handling incompatible schemas and actions. |
| definitions | `Record<string, GenericSchema>` | The schema definitions for constructing recursive schemas. If not specified, the definitions are generated automatically. |
| overrideSchema | `(context: OverrideSchemaContext) => JsonSchema \| null \| undefined` | Overrides the JSON Schema conversion for a specific Valibot schema. |
| ignoreActions | `string[]` | The actions that should be ignored during the conversion. |
| overrideAction | `(context: OverrideActionContext) => JsonSchema \| null \| undefined` | Overrides the JSON Schema reference for a specific Valibot action. |
| overrideRef | `(context: OverrideRefContext) => string \| null \| undefined` | Overrides the JSON Schema reference for a specific reference ID. |
### Target format
The `target` configuration allows you to specify which JSON Schema format to generate. Different targets have different capabilities and syntax:
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const schema = v.nullable(v.string());
// JSON Schema draft-07 (default)
toJsonSchema(schema);
// { $schema: "http://json-schema.org/draft-07/schema#", anyOf: [{ type: "string" }, { type: "null" }] }
// JSON Schema draft-2020-12
toJsonSchema(schema, { target: 'draft-2020-12' });
// { $schema: "https://json-schema.org/draft/2020-12/schema", anyOf: [{ type: "string" }, { type: "null" }] }
// OpenAPI 3.0 Schema Object
toJsonSchema(schema, { target: 'openapi-3.0' });
// { type: "string", nullable: true }
```
**Note**: Some features like `propertyNames` for record schemas are not available in OpenAPI 3.0.
### Type mode
The `typeMode` configuration controls whether to convert the input or output type of the Valibot schema to JSON Schema.
- When set to `'input'`, conversion stops before the first potential type transformation action or second schema in any pipeline.
- When set to `'output'`, conversion of any pipelines starts from the last schema in the pipeline. Therefore, the output type must be specified explicitly with a schema after the last type transformation action.
- When set to `'ignore'` (default), the entire pipeline is converted.
This is particularly useful when defining API endpoints where external developers need different schema information for requests vs responses:
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const ValibotSchema = v.pipe(
v.string(),
v.decimal(),
v.transform(Number),
v.number(),
v.maxValue(100)
);
toJsonSchema(ValibotSchema, { typeMode: 'input' });
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "string",
// pattern: "^[+-]?(?:\\d*\\.)?\\d+$"
// }
toJsonSchema(ValibotSchema, { typeMode: 'output' });
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "number",
// maximum: 100
// }
```
### Error mode
The `errorMode` configuration controls how the converter handles unsupported schemas and actions. By default, the error mode is set to `'throw'`. To force the conversion of unsupported Valibot features, you can set it to `'ignore'`.
> Unsupported schemas usually return an empty JSON schema (`{}`) and unsupported actions are usually ignored.
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
toJsonSchema(v.file(), { errorMode: 'ignore' }); // {}
toJsonSchema(v.pipe(v.string(), v.creditCard()), { errorMode: 'ignore' }); // { type: "string" }
```
### Override functions
The package provides powerful override capabilities to customize the JSON Schema conversion process. You can override the conversion of specific schemas, actions, or references.
#### Override schema conversion
Handle unsupported schemas or customize conversion behavior:
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const ValibotSchema = v.object({ createdAt: v.date() });
toJsonSchema(ValibotSchema, {
overrideSchema(context) {
if (context.valibotSchema.type === 'date') {
return { type: 'string', format: 'date-time' };
}
},
});
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "object",
// properties: {
// createdAt: { type: "string" format: "date-time" }
// },
// required: ["createdAt"]
// }
```
#### Override reference IDs
Customize reference IDs for OpenAPI or other specifications:
```js
import { toJsonSchemaDefs } from '@valibot/to-json-schema';
import * as v from 'valibot';
const UserSchema = v.object({ name: v.string() });
toJsonSchemaDefs(
{ UserSchema },
{ overrideRef: (context) => `#/schemas/${context.referenceId}` }
);
```
### Enhanced metadata support
Use the generic `metadata` action to add title, description, and examples to your schemas or the individual `title`and `description` actions:
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const ValibotSchema = v.pipe(
v.string(),
v.email(),
v.metadata({
title: 'Email Schema',
description: 'A schema that validates email addresses.',
examples: ['jane@example.com'],
})
);
toJsonSchema(ValibotSchema);
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "string",
// format: "email",
// title: "Email Schema",
// description: "A schema that validates email addresses.",
// examples: ["jane@example.com"]
// }
```
### Definitions
Nested and recursive schemas can be broken in multiple reusable definitions.
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const EmailSchema = v.pipe(v.string(), v.email());
toJsonSchema(v.object({ email: EmailSchema }), {
definitions: { EmailSchema },
});
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "object",
// properties: {
// email: {
// $ref: "#/$defs/EmailSchema"
// }
// },
// required: ["email"],
// $defs: {
// EmailSchema: {
// type: "string",
// format: "email"
// }
// }
// }
```
Definitions are not required for converting `lazy` schemas. Missing definitions will be generated automatically.
```js
import { toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const StringSchema = v.string();
toJsonSchema(v.object({ key: v.lazy(() => StringSchema) }));
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "object",
// properties: {
// key: {
// $ref: "#/$defs/0"
// }
// },
// required: ["key"],
// $defs: {
// 0: {
// type: "string"
// }
// }
// }
```
## Additional functions
### `toStandardJsonSchema`
Converts a Valibot schema to the [Standard JSON Schema](https://standardschema.dev/) format. This format is useful when working with tools and libraries that support the Standard JSON Schema specification.
```js
import { toStandardJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const schema = toStandardJsonSchema(
v.object({
id: v.pipe(v.string(), v.uuid()),
name: v.pipe(v.string(), v.nonEmpty()),
age: v.optional(v.number()),
})
);
```
### `toJsonSchemaDefs`
Converts only the provided Valibot schema definitions to JSON Schema definitions, without wrapping them in a root schema. This is particularly useful for OpenAPI specifications where you need only the schema definitions.
```js
import { toJsonSchemaDefs } from '@valibot/to-json-schema';
import * as v from 'valibot';
const EmailSchema = v.pipe(v.string(), v.email());
const UserSchema = v.object({
name: v.string(),
email: EmailSchema,
});
toJsonSchemaDefs({ EmailSchema, UserSchema });
// {
// EmailSchema: {
// type: "string",
// format: "email"
// },
// UserSchema: {
// type: "object",
// properties: {
// name: {
// type: "string"
// },
// email: {
// $ref: "#/$defs/EmailSchema"
// }
// },
// required: ["name", "email"]
// }
// }
```
#### OpenAPI integration
For OpenAPI specifications, you can customize reference IDs:
```js
import { toJsonSchemaDefs } from '@valibot/to-json-schema';
import * as v from 'valibot';
const ValibotSchema1 = v.string();
const ValibotSchema2 = v.number();
const ValibotSchema3 = v.tuple([ValibotSchema1, ValibotSchema2]);
toJsonSchemaDefs(
{ ValibotSchema1, ValibotSchema2, ValibotSchema3 },
{ overrideRef: (context) => `#/schemas/${context.referenceId}` }
);
// {
// ValibotSchema1: { type: "string" },
// ValibotSchema2: { type: "number" },
// ValibotSchema3: {
// type: "array",
// items: [
// { $ref: "#/schemas/ValibotSchema1" },
// { $ref: "#/schemas/ValibotSchema2" }
// ],
// minItems: 2
// }
// }
```
### Global definitions
For advanced use cases, you can manage global schema definitions that will be automatically used when converting schemas. This is particularly useful for larger projects with many reusable schemas.
```js
import { addGlobalDefs, toJsonSchema } from '@valibot/to-json-schema';
import * as v from 'valibot';
const ValibotSchema1 = v.string();
const ValibotSchema2 = v.number();
addGlobalDefs({ ValibotSchema1, ValibotSchema2 });
const ValibotSchema3 = v.tuple([ValibotSchema1, ValibotSchema2]);
toJsonSchema(ValibotSchema3);
// {
// $schema: "http://json-schema.org/draft-07/schema#",
// type: "array",
// items: [
// { $ref: "#/$defs/ValibotSchema1" },
// { $ref: "#/$defs/ValibotSchema2" }
// ],
// minItems: 2,
// $defs: {
// ValibotSchema1: { type: "string" },
// ValibotSchema2: { type: "number" }
// }
// }
```
You can also convert global definitions directly using `toJsonSchemaDefs`:
```js
const globalDefs = getGlobalDefs();
if (globalDefs) {
const schemaDefs = toJsonSchemaDefs(globalDefs);
}
```

View File

@@ -0,0 +1,545 @@
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) {
__defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
}
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let valibot = require("valibot");
valibot = __toESM(valibot);
//#region src/utils/addError.ts
/**
* Adds an error message to the errors array.
*
* @param errors The array of error messages.
* @param message The error message to add.
*
* @returns The new errors.
*/
function addError(errors, message) {
if (errors) {
errors.push(message);
return errors;
}
return [message];
}
//#endregion
//#region src/utils/handleError.ts
/**
* Throws an error or logs a warning based on the configuration.
*
* @param message The message to throw or log.
* @param config The conversion configuration.
*/
function handleError(message, config) {
switch (config?.errorMode) {
case "ignore": break;
case "warn":
console.warn(message);
break;
default: throw new Error(message);
}
}
//#endregion
//#region src/converters/convertAction/convertAction.ts
/**
* Converts any supported Valibot action to the JSON Schema format.
*
* @param jsonSchema The JSON Schema object.
* @param valibotAction The Valibot action object.
* @param config The conversion configuration.
*
* @returns The converted JSON Schema.
*/
function convertAction(jsonSchema, valibotAction, config) {
if (config?.ignoreActions?.includes(valibotAction.type)) return jsonSchema;
let errors;
switch (valibotAction.type) {
case "base64":
jsonSchema.contentEncoding = "base64";
break;
case "bic":
case "cuid2":
case "decimal":
case "digits":
case "emoji":
case "hexadecimal":
case "hex_color":
case "nanoid":
case "octal":
case "ulid":
jsonSchema.pattern = valibotAction.requirement.source;
break;
case "description":
jsonSchema.description = valibotAction.description;
break;
case "email":
jsonSchema.format = "email";
break;
case "empty":
if (jsonSchema.type === "array") jsonSchema.maxItems = 0;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.maxLength = 0;
}
break;
case "entries":
jsonSchema.minProperties = valibotAction.requirement;
jsonSchema.maxProperties = valibotAction.requirement;
break;
case "examples":
if (Array.isArray(jsonSchema.examples)) jsonSchema.examples = [...jsonSchema.examples, ...valibotAction.examples];
else jsonSchema.examples = valibotAction.examples;
break;
case "integer":
jsonSchema.type = "integer";
break;
case "ipv4":
jsonSchema.format = "ipv4";
break;
case "ipv6":
jsonSchema.format = "ipv6";
break;
case "iso_date":
jsonSchema.format = "date";
break;
case "iso_date_time":
case "iso_timestamp":
jsonSchema.format = "date-time";
break;
case "iso_time":
jsonSchema.format = "time";
break;
case "length":
if (jsonSchema.type === "array") {
jsonSchema.minItems = valibotAction.requirement;
jsonSchema.maxItems = valibotAction.requirement;
} else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minLength = valibotAction.requirement;
jsonSchema.maxLength = valibotAction.requirement;
}
break;
case "max_entries":
jsonSchema.maxProperties = valibotAction.requirement;
break;
case "max_length":
if (jsonSchema.type === "array") jsonSchema.maxItems = valibotAction.requirement;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.maxLength = valibotAction.requirement;
}
break;
case "max_value":
if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "max_value" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.maximum = valibotAction.requirement;
break;
case "metadata":
if (typeof valibotAction.metadata.title === "string") jsonSchema.title = valibotAction.metadata.title;
if (typeof valibotAction.metadata.description === "string") jsonSchema.description = valibotAction.metadata.description;
if (Array.isArray(valibotAction.metadata.examples)) if (Array.isArray(jsonSchema.examples)) jsonSchema.examples = [...jsonSchema.examples, ...valibotAction.metadata.examples];
else jsonSchema.examples = valibotAction.metadata.examples;
break;
case "min_entries":
jsonSchema.minProperties = valibotAction.requirement;
break;
case "min_length":
if (jsonSchema.type === "array") jsonSchema.minItems = valibotAction.requirement;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minLength = valibotAction.requirement;
}
break;
case "min_value":
if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "min_value" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minimum = valibotAction.requirement;
break;
case "multiple_of":
jsonSchema.multipleOf = valibotAction.requirement;
break;
case "non_empty":
if (jsonSchema.type === "array") jsonSchema.minItems = 1;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minLength = 1;
}
break;
case "regex":
if (valibotAction.requirement.flags) errors = addError(errors, "RegExp flags are not supported by JSON Schema.");
jsonSchema.pattern = valibotAction.requirement.source;
break;
case "title":
jsonSchema.title = valibotAction.title;
break;
case "url":
jsonSchema.format = "uri";
break;
case "uuid":
jsonSchema.format = "uuid";
break;
case "value":
jsonSchema.const = valibotAction.requirement;
break;
default: errors = addError(errors, `The "${valibotAction.type}" action cannot be converted to JSON Schema.`);
}
if (config?.overrideAction) {
const actionOverride = config.overrideAction({
valibotAction,
jsonSchema,
errors
});
if (actionOverride) return { ...actionOverride };
}
if (errors) for (const message of errors) handleError(message, config);
return jsonSchema;
}
//#endregion
//#region src/converters/convertSchema/convertSchema.ts
/**
* Flattens a Valibot pipe by recursively expanding nested pipes.
*
* @param pipe The pipeline to flatten.
*
* @returns A flat pipeline.
*/
function flattenPipe(pipe) {
return pipe.flatMap((item) => "pipe" in item ? flattenPipe(item.pipe) : item);
}
let refCount = 0;
/**
* Converts any supported Valibot schema to the JSON Schema format.
*
* @param jsonSchema The JSON Schema object.
* @param valibotSchema The Valibot schema object.
* @param config The conversion configuration.
* @param context The conversion context.
* @param skipRef Whether to skip using a reference.
*
* @returns The converted JSON Schema.
*/
function convertSchema(jsonSchema, valibotSchema, config, context, skipRef = false) {
if (!skipRef) {
const referenceId = context.referenceMap.get(valibotSchema);
if (referenceId) {
jsonSchema.$ref = `#/$defs/${referenceId}`;
if (config?.overrideRef) {
const refOverride = config.overrideRef({
...context,
referenceId,
valibotSchema,
jsonSchema
});
if (refOverride) jsonSchema.$ref = refOverride;
}
return jsonSchema;
}
}
if ("pipe" in valibotSchema) {
const flatPipe = flattenPipe(valibotSchema.pipe);
let startIndex = 0;
let stopIndex = flatPipe.length - 1;
if (config?.typeMode === "input") {
const inputStopIndex = flatPipe.slice(1).findIndex((item) => item.kind === "schema" || item.kind === "transformation" && (item.type === "find_item" || item.type === "parse_json" || item.type === "raw_transform" || item.type === "reduce_items" || item.type === "stringify_json" || item.type === "to_bigint" || item.type === "to_boolean" || item.type === "to_date" || item.type === "to_number" || item.type === "to_string" || item.type === "transform"));
if (inputStopIndex !== -1) stopIndex = inputStopIndex;
} else if (config?.typeMode === "output") {
const outputStartIndex = flatPipe.findLastIndex((item) => item.kind === "schema");
if (outputStartIndex !== -1) startIndex = outputStartIndex;
}
for (let index = startIndex; index <= stopIndex; index++) {
const valibotPipeItem = flatPipe[index];
if (valibotPipeItem.kind === "schema") {
if (index > startIndex) handleError("Set the \"typeMode\" config to \"input\" or \"output\" to convert pipelines with multiple schemas.", config);
jsonSchema = convertSchema(jsonSchema, valibotPipeItem, config, context, true);
} else jsonSchema = convertAction(jsonSchema, valibotPipeItem, config);
}
return jsonSchema;
}
let errors;
switch (valibotSchema.type) {
case "boolean":
jsonSchema.type = "boolean";
break;
case "null":
if (config?.target === "openapi-3.0") jsonSchema.enum = [null];
else jsonSchema.type = "null";
break;
case "number":
jsonSchema.type = "number";
break;
case "string":
jsonSchema.type = "string";
break;
case "array":
jsonSchema.type = "array";
jsonSchema.items = convertSchema({}, valibotSchema.item, config, context);
break;
case "tuple":
case "tuple_with_rest":
case "loose_tuple":
case "strict_tuple":
jsonSchema.type = "array";
if (config?.target === "openapi-3.0") {
jsonSchema.items = { anyOf: [] };
jsonSchema.minItems = valibotSchema.items.length;
for (const item of valibotSchema.items) jsonSchema.items.anyOf.push(convertSchema({}, item, config, context));
if (valibotSchema.type === "tuple_with_rest") jsonSchema.items.anyOf.push(convertSchema({}, valibotSchema.rest, config, context));
else if (valibotSchema.type === "strict_tuple" || valibotSchema.type === "tuple") jsonSchema.maxItems = valibotSchema.items.length;
} else if (config?.target === "draft-2020-12") {
jsonSchema.prefixItems = [];
jsonSchema.minItems = valibotSchema.items.length;
for (const item of valibotSchema.items) jsonSchema.prefixItems.push(convertSchema({}, item, config, context));
if (valibotSchema.type === "tuple_with_rest") jsonSchema.items = convertSchema({}, valibotSchema.rest, config, context);
else if (valibotSchema.type === "strict_tuple") jsonSchema.items = false;
} else {
jsonSchema.items = [];
jsonSchema.minItems = valibotSchema.items.length;
for (const item of valibotSchema.items) jsonSchema.items.push(convertSchema({}, item, config, context));
if (valibotSchema.type === "tuple_with_rest") jsonSchema.additionalItems = convertSchema({}, valibotSchema.rest, config, context);
else if (valibotSchema.type === "strict_tuple") jsonSchema.additionalItems = false;
}
break;
case "object":
case "object_with_rest":
case "loose_object":
case "strict_object":
jsonSchema.type = "object";
jsonSchema.properties = {};
jsonSchema.required = [];
for (const key in valibotSchema.entries) {
const entry = valibotSchema.entries[key];
jsonSchema.properties[key] = convertSchema({}, entry, config, context);
if (entry.type !== "exact_optional" && entry.type !== "nullish" && entry.type !== "optional") jsonSchema.required.push(key);
}
if (valibotSchema.type === "object_with_rest") jsonSchema.additionalProperties = convertSchema({}, valibotSchema.rest, config, context);
else if (valibotSchema.type === "strict_object") jsonSchema.additionalProperties = false;
break;
case "record":
if (config?.target === "openapi-3.0" && "pipe" in valibotSchema.key) errors = addError(errors, "The \"record\" schema with a schema for the key that contains a \"pipe\" cannot be converted to JSON Schema.");
if (valibotSchema.key.type !== "string") errors = addError(errors, `The "record" schema with the "${valibotSchema.key.type}" schema for the key cannot be converted to JSON Schema.`);
jsonSchema.type = "object";
if (config?.target !== "openapi-3.0") jsonSchema.propertyNames = convertSchema({}, valibotSchema.key, config, context);
jsonSchema.additionalProperties = convertSchema({}, valibotSchema.value, config, context);
break;
case "any":
case "unknown": break;
case "nullable":
case "nullish":
if (config?.target === "openapi-3.0") {
const innerSchema = convertSchema({}, valibotSchema.wrapped, config, context);
Object.assign(jsonSchema, innerSchema);
jsonSchema.nullable = true;
} else jsonSchema.anyOf = [convertSchema({}, valibotSchema.wrapped, config, context), { type: "null" }];
if (valibotSchema.default !== void 0) jsonSchema.default = valibot.getDefault(valibotSchema);
break;
case "exact_optional":
case "optional":
case "undefinedable":
jsonSchema = convertSchema(jsonSchema, valibotSchema.wrapped, config, context);
if (valibotSchema.default !== void 0) jsonSchema.default = valibot.getDefault(valibotSchema);
break;
case "literal":
if (typeof valibotSchema.literal !== "boolean" && typeof valibotSchema.literal !== "number" && typeof valibotSchema.literal !== "string") errors = addError(errors, "The value of the \"literal\" schema is not JSON compatible.");
if (config?.target === "openapi-3.0") jsonSchema.enum = [valibotSchema.literal];
else jsonSchema.const = valibotSchema.literal;
break;
case "enum":
jsonSchema.enum = valibotSchema.options;
break;
case "picklist":
if (valibotSchema.options.some((option) => typeof option !== "number" && typeof option !== "string")) errors = addError(errors, "An option of the \"picklist\" schema is not JSON compatible.");
jsonSchema.enum = valibotSchema.options;
break;
case "union":
jsonSchema.anyOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
break;
case "variant":
jsonSchema.oneOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
break;
case "intersect":
jsonSchema.allOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
break;
case "lazy": {
let wrappedValibotSchema = context.getterMap.get(valibotSchema.getter);
if (!wrappedValibotSchema) {
wrappedValibotSchema = valibotSchema.getter(void 0);
context.getterMap.set(valibotSchema.getter, wrappedValibotSchema);
}
let referenceId = context.referenceMap.get(wrappedValibotSchema);
if (!referenceId) {
referenceId = `${refCount++}`;
context.referenceMap.set(wrappedValibotSchema, referenceId);
context.definitions[referenceId] = convertSchema({}, wrappedValibotSchema, config, context, true);
}
jsonSchema.$ref = `#/$defs/${referenceId}`;
if (config?.overrideRef) {
const refOverride = config.overrideRef({
...context,
referenceId,
valibotSchema: wrappedValibotSchema,
jsonSchema
});
if (refOverride) jsonSchema.$ref = refOverride;
}
break;
}
default: errors = addError(errors, `The "${valibotSchema.type}" schema cannot be converted to JSON Schema.`);
}
if (config?.overrideSchema) {
const schemaOverride = config.overrideSchema({
...context,
referenceId: context.referenceMap.get(valibotSchema),
valibotSchema,
jsonSchema,
errors
});
if (schemaOverride) return { ...schemaOverride };
}
if (errors) for (const message of errors) handleError(message, config);
return jsonSchema;
}
//#endregion
//#region src/storages/globalDefs/globalDefs.ts
let store;
/**
* Adds new definitions to the global schema definitions.
*
* @param definitions The schema definitions.
*
* @beta
*/
function addGlobalDefs(definitions) {
store = {
...store ?? {},
...definitions
};
}
/**
* Returns the current global schema definitions.
*
* @returns The schema definitions.
*
* @beta
*/
function getGlobalDefs() {
return store;
}
//#endregion
//#region src/functions/toJsonSchema/toJsonSchema.ts
/**
* Converts a Valibot schema to the JSON Schema format.
*
* @param schema The Valibot schema object.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema.
*/
function toJsonSchema(schema, config) {
const context = {
definitions: {},
referenceMap: /* @__PURE__ */ new Map(),
getterMap: /* @__PURE__ */ new Map()
};
const definitions = config?.definitions ?? getGlobalDefs();
if (definitions) {
for (const key in definitions) context.referenceMap.set(definitions[key], key);
for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
}
const jsonSchema = convertSchema({}, schema, config, context);
const target = config?.target ?? "draft-07";
if (target === "draft-2020-12") jsonSchema.$schema = "https://json-schema.org/draft/2020-12/schema";
else if (target === "draft-07") jsonSchema.$schema = "http://json-schema.org/draft-07/schema#";
if (context.referenceMap.size) jsonSchema.$defs = context.definitions;
return jsonSchema;
}
//#endregion
//#region src/functions/toJsonSchemaDefs/toJsonSchemaDefs.ts
/**
* Converts Valibot schema definitions to JSON Schema definitions.
*
* @param definitions The Valibot schema definitions.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema definitions.
*/
function toJsonSchemaDefs(definitions, config) {
const context = {
definitions: {},
referenceMap: /* @__PURE__ */ new Map(),
getterMap: /* @__PURE__ */ new Map()
};
for (const key in definitions) context.referenceMap.set(definitions[key], key);
for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
return context.definitions;
}
//#endregion
//#region src/functions/toStandardJsonSchema/toStandardJsonSchema.ts
const SUPPORTED_TARGETS = [
"draft-07",
"draft-2020-12",
"openapi-3.0"
];
/**
* Converts a Valibot schema to the Standard JSON Schema format.
*
* @param schema The Valibot schema object.
*
* @returns The Standard JSON Schema.
*/
function toStandardJsonSchema(schema) {
return { "~standard": {
...schema["~standard"],
jsonSchema: {
input(options) {
if (SUPPORTED_TARGETS.includes(options.target)) return toJsonSchema(schema, {
typeMode: "input",
target: options.target,
...options.libraryOptions
});
throw new Error(`Unsupported target: ${options.target}`);
},
output(options) {
if (SUPPORTED_TARGETS.includes(options.target)) return toJsonSchema(schema, {
typeMode: "output",
target: options.target,
...options.libraryOptions
});
throw new Error(`Unsupported target: ${options.target}`);
}
}
} };
}
//#endregion
exports.addGlobalDefs = addGlobalDefs;
exports.getGlobalDefs = getGlobalDefs;
exports.toJsonSchema = toJsonSchema;
exports.toJsonSchemaDefs = toJsonSchemaDefs;
exports.toStandardJsonSchema = toStandardJsonSchema;

View File

@@ -0,0 +1,955 @@
//#region ../../library/src/types/metadata.d.ts
/**
* Base metadata interface.
*/
interface BaseMetadata<TInput$1> {
/**
* The object kind.
*/
readonly kind: "metadata";
/**
* The metadata type.
*/
readonly type: string;
/**
* The metadata reference.
*/
readonly reference: (...args: any[]) => BaseMetadata<any>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TInput$1;
readonly issue: never;
} | undefined;
}
//#endregion
//#region ../../library/src/types/dataset.d.ts
/**
* Unknown dataset interface.
*/
interface UnknownDataset {
/**
* Whether is's typed.
*/
typed?: false;
/**
* The dataset value.
*/
value: unknown;
/**
* The dataset issues.
*/
issues?: undefined;
}
/**
* Success dataset interface.
*/
interface SuccessDataset<TValue$1> {
/**
* Whether is's typed.
*/
typed: true;
/**
* The dataset value.
*/
value: TValue$1;
/**
* The dataset issues.
*/
issues?: undefined;
}
/**
* Partial dataset interface.
*/
interface PartialDataset<TValue$1, TIssue extends BaseIssue<unknown>> {
/**
* Whether is's typed.
*/
typed: true;
/**
* The dataset value.
*/
value: TValue$1;
/**
* The dataset issues.
*/
issues: [TIssue, ...TIssue[]];
}
/**
* Failure dataset interface.
*/
interface FailureDataset<TIssue extends BaseIssue<unknown>> {
/**
* Whether is's typed.
*/
typed: false;
/**
* The dataset value.
*/
value: unknown;
/**
* The dataset issues.
*/
issues: [TIssue, ...TIssue[]];
}
/**
* Output dataset type.
*/
type OutputDataset<TValue$1, TIssue extends BaseIssue<unknown>> = SuccessDataset<TValue$1> | PartialDataset<TValue$1, TIssue> | FailureDataset<TIssue>;
//#endregion
//#region ../../library/src/types/standard.d.ts
/**
* The Standard Schema properties interface.
*/
interface StandardProps<TInput$1, TOutput> {
/**
* The version number of the standard.
*/
readonly version: 1;
/**
* The vendor name of the schema library.
*/
readonly vendor: "valibot";
/**
* Validates unknown input values.
*/
readonly validate: (value: unknown) => StandardResult<TOutput> | Promise<StandardResult<TOutput>>;
/**
* Inferred types associated with the schema.
*/
readonly types?: StandardTypes<TInput$1, TOutput> | undefined;
}
/**
* The result interface of the validate function.
*/
type StandardResult<TOutput> = StandardSuccessResult<TOutput> | StandardFailureResult;
/**
* The result interface if validation succeeds.
*/
interface StandardSuccessResult<TOutput> {
/**
* The typed output value.
*/
readonly value: TOutput;
/**
* The non-existent issues.
*/
readonly issues?: undefined;
}
/**
* The result interface if validation fails.
*/
interface StandardFailureResult {
/**
* The issues of failed validation.
*/
readonly issues: readonly StandardIssue[];
}
/**
* The issue interface of the failure output.
*/
interface StandardIssue {
/**
* The error message of the issue.
*/
readonly message: string;
/**
* The path of the issue, if any.
*/
readonly path?: readonly (PropertyKey | StandardPathItem)[] | undefined;
}
/**
* The path item interface of the issue.
*/
interface StandardPathItem {
/**
* The key of the path item.
*/
readonly key: PropertyKey;
}
/**
* The Standard Schema types interface.
*/
interface StandardTypes<TInput$1, TOutput> {
/**
* The input type of the schema.
*/
readonly input: TInput$1;
/**
* The output type of the schema.
*/
readonly output: TOutput;
}
//#endregion
//#region ../../library/src/types/schema.d.ts
/**
* Base schema interface.
*/
interface BaseSchema<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> {
/**
* The object kind.
*/
readonly kind: "schema";
/**
* The schema type.
*/
readonly type: string;
/**
* The schema reference.
*/
readonly reference: (...args: any[]) => BaseSchema<unknown, unknown, BaseIssue<unknown>>;
/**
* The expected property.
*/
readonly expects: string;
/**
* Whether it's async.
*/
readonly async: false;
/**
* The Standard Schema properties.
*
* @internal
*/
readonly "~standard": StandardProps<TInput$1, TOutput>;
/**
* Parses unknown input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: UnknownDataset, config: Config<BaseIssue<unknown>>) => OutputDataset<TOutput, TIssue>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TOutput;
readonly issue: TIssue;
} | undefined;
}
/**
* Base schema async interface.
*/
interface BaseSchemaAsync<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> extends Omit<BaseSchema<TInput$1, TOutput, TIssue>, "reference" | "async" | "~run"> {
/**
* The schema reference.
*/
readonly reference: (...args: any[]) => BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: true;
/**
* Parses unknown input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: UnknownDataset, config: Config<BaseIssue<unknown>>) => Promise<OutputDataset<TOutput, TIssue>>;
}
//#endregion
//#region ../../library/src/types/transformation.d.ts
/**
* Base transformation interface.
*/
interface BaseTransformation<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> {
/**
* The object kind.
*/
readonly kind: "transformation";
/**
* The transformation type.
*/
readonly type: string;
/**
* The transformation reference.
*/
readonly reference: (...args: any[]) => BaseTransformation<any, any, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: false;
/**
* Transforms known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: SuccessDataset<TInput$1>, config: Config<BaseIssue<unknown>>) => OutputDataset<TOutput, BaseIssue<unknown> | TIssue>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TOutput;
readonly issue: TIssue;
} | undefined;
}
/**
* Base transformation async interface.
*/
interface BaseTransformationAsync<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> extends Omit<BaseTransformation<TInput$1, TOutput, TIssue>, "reference" | "async" | "~run"> {
/**
* The transformation reference.
*/
readonly reference: (...args: any[]) => BaseTransformation<any, any, BaseIssue<unknown>> | BaseTransformationAsync<any, any, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: true;
/**
* Transforms known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: SuccessDataset<TInput$1>, config: Config<BaseIssue<unknown>>) => Promise<OutputDataset<TOutput, BaseIssue<unknown> | TIssue>>;
}
//#endregion
//#region ../../library/src/types/validation.d.ts
/**
* Base validation interface.
*/
interface BaseValidation<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> {
/**
* The object kind.
*/
readonly kind: "validation";
/**
* The validation type.
*/
readonly type: string;
/**
* The validation reference.
*/
readonly reference: (...args: any[]) => BaseValidation<any, any, BaseIssue<unknown>>;
/**
* The expected property.
*/
readonly expects: string | null;
/**
* Whether it's async.
*/
readonly async: false;
/**
* Validates known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: OutputDataset<TInput$1, BaseIssue<unknown>>, config: Config<BaseIssue<unknown>>) => OutputDataset<TOutput, BaseIssue<unknown> | TIssue>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TOutput;
readonly issue: TIssue;
} | undefined;
}
/**
* Base validation async interface.
*/
interface BaseValidationAsync<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> extends Omit<BaseValidation<TInput$1, TOutput, TIssue>, "reference" | "async" | "~run"> {
/**
* The validation reference.
*/
readonly reference: (...args: any[]) => BaseValidation<any, any, BaseIssue<unknown>> | BaseValidationAsync<any, any, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: true;
/**
* Validates known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: OutputDataset<TInput$1, BaseIssue<unknown>>, config: Config<BaseIssue<unknown>>) => Promise<OutputDataset<TOutput, BaseIssue<unknown> | TIssue>>;
}
//#endregion
//#region ../../library/src/types/infer.d.ts
/**
* Infer input type.
*/
type InferInput<TItem$1 extends BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>> | BaseValidation<any, unknown, BaseIssue<unknown>> | BaseValidationAsync<any, unknown, BaseIssue<unknown>> | BaseTransformation<any, unknown, BaseIssue<unknown>> | BaseTransformationAsync<any, unknown, BaseIssue<unknown>> | BaseMetadata<any>> = NonNullable<TItem$1["~types"]>["input"];
/**
* Infer output type.
*/
type InferOutput<TItem$1 extends BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>> | BaseValidation<any, unknown, BaseIssue<unknown>> | BaseValidationAsync<any, unknown, BaseIssue<unknown>> | BaseTransformation<any, unknown, BaseIssue<unknown>> | BaseTransformationAsync<any, unknown, BaseIssue<unknown>> | BaseMetadata<any>> = NonNullable<TItem$1["~types"]>["output"];
//#endregion
//#region ../../library/src/types/utils.d.ts
/**
* Constructs a type that is maybe readonly.
*/
type MaybeReadonly<TValue$1> = TValue$1 | Readonly<TValue$1>;
//#endregion
//#region ../../library/src/types/other.d.ts
/**
* Error message type.
*/
type ErrorMessage<TIssue extends BaseIssue<unknown>> = ((issue: TIssue) => string) | string;
//#endregion
//#region ../../library/src/types/issue.d.ts
/**
* Array path item interface.
*/
interface ArrayPathItem {
/**
* The path item type.
*/
readonly type: "array";
/**
* The path item origin.
*/
readonly origin: "value";
/**
* The path item input.
*/
readonly input: MaybeReadonly<unknown[]>;
/**
* The path item key.
*/
readonly key: number;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Map path item interface.
*/
interface MapPathItem {
/**
* The path item type.
*/
readonly type: "map";
/**
* The path item origin.
*/
readonly origin: "key" | "value";
/**
* The path item input.
*/
readonly input: Map<unknown, unknown>;
/**
* The path item key.
*/
readonly key: unknown;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Object path item interface.
*/
interface ObjectPathItem {
/**
* The path item type.
*/
readonly type: "object";
/**
* The path item origin.
*/
readonly origin: "key" | "value";
/**
* The path item input.
*/
readonly input: Record<string, unknown>;
/**
* The path item key.
*/
readonly key: string;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Set path item interface.
*/
interface SetPathItem {
/**
* The path item type.
*/
readonly type: "set";
/**
* The path item origin.
*/
readonly origin: "value";
/**
* The path item input.
*/
readonly input: Set<unknown>;
/**
* The path item key.
*/
readonly key: null;
/**
* The path item key.
*/
readonly value: unknown;
}
/**
* Unknown path item interface.
*/
interface UnknownPathItem {
/**
* The path item type.
*/
readonly type: "unknown";
/**
* The path item origin.
*/
readonly origin: "key" | "value";
/**
* The path item input.
*/
readonly input: unknown;
/**
* The path item key.
*/
readonly key: unknown;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Issue path item type.
*/
type IssuePathItem = ArrayPathItem | MapPathItem | ObjectPathItem | SetPathItem | UnknownPathItem;
/**
* Base issue interface.
*/
interface BaseIssue<TInput$1> extends Config<BaseIssue<TInput$1>> {
/**
* The issue kind.
*/
readonly kind: "schema" | "validation" | "transformation";
/**
* The issue type.
*/
readonly type: string;
/**
* The raw input data.
*/
readonly input: TInput$1;
/**
* The expected property.
*/
readonly expected: string | null;
/**
* The received property.
*/
readonly received: string;
/**
* The error message.
*/
readonly message: string;
/**
* The input requirement.
*/
readonly requirement?: unknown | undefined;
/**
* The issue path.
*/
readonly path?: [IssuePathItem, ...IssuePathItem[]] | undefined;
/**
* The sub issues.
*/
readonly issues?: [BaseIssue<TInput$1>, ...BaseIssue<TInput$1>[]] | undefined;
}
//#endregion
//#region ../../library/src/types/config.d.ts
/**
* Config interface.
*/
interface Config<TIssue extends BaseIssue<unknown>> {
/**
* The selected language.
*/
readonly lang?: string | undefined;
/**
* The error message.
*/
readonly message?: ErrorMessage<TIssue> | undefined;
/**
* Whether it should be aborted early.
*/
readonly abortEarly?: boolean | undefined;
/**
* Whether a pipe should be aborted early.
*/
readonly abortPipeEarly?: boolean | undefined;
}
//#endregion
//#region ../../library/src/types/pipe.d.ts
/**
* Pipe action type.
*/
type PipeAction<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> = BaseValidation<TInput$1, TOutput, TIssue> | BaseTransformation<TInput$1, TOutput, TIssue> | BaseMetadata<TInput$1>;
//#endregion
//#region src/types/schema.d.ts
type JsonSchemaTypeName = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
type JsonSchemaType = string | number | boolean | JsonSchemaObject | JsonSchemaArray | null;
interface JsonSchemaObject {
[key: string]: JsonSchemaType;
}
interface JsonSchemaArray extends Array<JsonSchemaType> {}
type JsonSchemaDefinition = JsonSchema | boolean;
/**
* JSON Schema interface.
*/
interface JsonSchema {
$id?: string | undefined;
$ref?: string | undefined;
$schema?: string | undefined;
$comment?: string | undefined;
$defs?: Record<string, JsonSchemaDefinition> | undefined;
type?: JsonSchemaTypeName | JsonSchemaTypeName[] | undefined;
nullable?: boolean | undefined;
enum?: JsonSchemaType[] | undefined;
const?: JsonSchemaType | undefined;
multipleOf?: number | undefined;
maximum?: number | undefined;
exclusiveMaximum?: number | undefined;
minimum?: number | undefined;
exclusiveMinimum?: number | undefined;
maxLength?: number | undefined;
minLength?: number | undefined;
pattern?: string | undefined;
items?: JsonSchemaDefinition | JsonSchemaDefinition[] | undefined;
prefixItems?: JsonSchemaDefinition[] | undefined;
additionalItems?: JsonSchemaDefinition | undefined;
maxItems?: number | undefined;
minItems?: number | undefined;
uniqueItems?: boolean | undefined;
contains?: JsonSchemaDefinition | undefined;
maxProperties?: number | undefined;
minProperties?: number | undefined;
required?: string[] | undefined;
properties?: Record<string, JsonSchemaDefinition> | undefined;
patternProperties?: Record<string, JsonSchemaDefinition> | undefined;
additionalProperties?: JsonSchemaDefinition | undefined;
dependencies?: Record<string, JsonSchemaDefinition | string[]> | undefined;
propertyNames?: JsonSchemaDefinition | undefined;
if?: JsonSchemaDefinition | undefined;
then?: JsonSchemaDefinition | undefined;
else?: JsonSchemaDefinition | undefined;
allOf?: JsonSchemaDefinition[] | undefined;
anyOf?: JsonSchemaDefinition[] | undefined;
oneOf?: JsonSchemaDefinition[] | undefined;
not?: JsonSchemaDefinition | undefined;
format?: string | undefined;
contentMediaType?: string | undefined;
contentEncoding?: string | undefined;
definitions?: Record<string, JsonSchemaDefinition> | undefined;
title?: string | undefined;
description?: string | undefined;
default?: JsonSchemaType | undefined;
readOnly?: boolean | undefined;
writeOnly?: boolean | undefined;
examples?: JsonSchemaType | undefined;
}
/**
* JSON Schema 7 interface.
*
* @deprecated Use `JsonSchema` instead.
*/
interface JSONSchema7 extends JsonSchema {}
//#endregion
//#region src/types/config.d.ts
/**
* JSON Schema conversion context interface.
*/
interface ConversionContext {
/**
* The JSON Schema definitions that have already been created.
*/
readonly definitions: Record<string, JsonSchema>;
/**
* The JSON Schema reference map that is used to look up the reference ID
* for a given Valibot schema.
*/
readonly referenceMap: Map<BaseSchema<unknown, unknown, BaseIssue<unknown>>, string>;
/**
* The lazy schema getter map that is used internally to ensure that
* recursive lazy schemas are unwrapped only once.
*/
readonly getterMap: Map<(input: unknown) => BaseSchema<unknown, unknown, BaseIssue<unknown>>, BaseSchema<unknown, unknown, BaseIssue<unknown>>>;
}
/**
* JSON Schema override context interface for schemas.
*
* @beta
*/
interface OverrideSchemaContext extends ConversionContext {
/**
* The JSON Schema reference ID.
*/
readonly referenceId: string | undefined;
/**
* The Valibot schema to be converted.
*/
readonly valibotSchema: BaseSchema<unknown, unknown, BaseIssue<unknown>>;
/**
* The converted JSON Schema.
*/
readonly jsonSchema: JsonSchema;
/**
* The errors of the current Valibot schema conversion.
*/
readonly errors: [string, ...string[]] | undefined;
}
/**
* JSON Schema override context interface for actions.
*
* @beta
*/
interface OverrideActionContext {
/**
* The Valibot action to be converted.
*/
readonly valibotAction: PipeAction<any, any, BaseIssue<unknown>>;
/**
* The converted JSON Schema.
*/
readonly jsonSchema: JsonSchema;
/**
* The errors of the current Valibot action conversion.
*/
readonly errors: [string, ...string[]] | undefined;
}
/**
* JSON Schema override context interface for references.
*
* @beta
*/
interface OverrideRefContext extends ConversionContext {
/**
* The JSON Schema reference ID.
*/
readonly referenceId: string;
/**
* The Valibot schema to be converted.
*/
readonly valibotSchema: BaseSchema<unknown, unknown, BaseIssue<unknown>>;
/**
* The converted JSON Schema.
*/
readonly jsonSchema: JsonSchema;
}
/**
* JSON Schema conversion config interface.
*/
interface ConversionConfig {
/**
* The target JSON Schema draft version. Defaults to 'draft-07'.
*/
readonly target?: "draft-07" | "draft-2020-12" | "openapi-3.0";
/**
* Whether to convert the input or output type of the Valibot schema to JSON Schema.
*
* When set to 'input', conversion stops before the first potential type
* transformation action or second schema in any pipeline.
*
* When set to 'output', conversion of any pipelines starts from the last
* schema in the pipeline. Therefore, the output type must be specified
* explicitly with a schema after the last type transformation action.
*
* @beta
*/
readonly typeMode?: "ignore" | "input" | "output";
/**
* The policy for handling incompatible schemas and actions.
*/
readonly errorMode?: "throw" | "warn" | "ignore";
/**
* The schema definitions for constructing recursive schemas. If not
* specified, the definitions are generated automatically as needed.
*/
readonly definitions?: Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>>;
/**
* Overrides the JSON Schema conversion for a specific Valibot schema.
*
* Only return a JSON Schema if you want to override the default conversion
* behaviour and suppress errors for a specific schema. Returning either
* `null` or `undefined` will skip the override.
*
* @param context The conversion context.
*
* @returns A JSON Schema, if overridden.
*
* @beta
*/
readonly overrideSchema?: (context: OverrideSchemaContext) => JsonSchema | null | undefined;
/**
* The actions that should be ignored during the conversion.
*
* @beta
*/
readonly ignoreActions?: string[];
/**
* Overrides the JSON Schema reference for a specific Valibot action.
*
* Only return a JSON Schema if you want to override the default conversion
* behaviour and suppress errors for a specific action. Returning either
* `null` or `undefined` will skip the override.
*
* @param context The conversion context.
*
* @returns A JSON Schema, if overridden.
*
* @beta
*/
readonly overrideAction?: (context: OverrideActionContext) => JsonSchema | null | undefined;
/**
* Overrides the JSON Schema reference for a specific reference ID.
*
* @param context The conversion context.
*
* @returns A reference ID, if overridden.
*
* @beta
*/
readonly overrideRef?: (context: OverrideRefContext) => string | null | undefined;
}
//#endregion
//#region src/types/standard.d.ts
/**
* JSON Schema interface.
*/
interface StandardJsonSchema<TInput$1, TOutput> {
/**
* The Standard JSON Schema properties.
*/
readonly "~standard": StandardJsonProps<TInput$1, TOutput>;
}
/**
* The Standard JSON Schema properties interface.
*/
interface StandardJsonProps<TInput$1, TOutput> extends StandardProps<TInput$1, TOutput> {
/**
* Methods for generating the input/output JSON Schema.
*/
readonly jsonSchema: StandardJsonConverter;
}
/**
* The Standard JSON Schema converter interface.
*/
interface StandardJsonConverter {
/**
* Converts the input type to JSON Schema. May throw if conversion is not supported.
*/
readonly input: (options: StandardJsonOptions) => Record<string, unknown>;
/**
* Converts the output type to JSON Schema. May throw if conversion is not supported.
*/
readonly output: (options: StandardJsonOptions) => Record<string, unknown>;
}
/**
* The target version of the generated JSON Schema.
*/
type StandardJsonTarget = "draft-2020-12" | "draft-07" | "openapi-3.0" | ({} & string);
/**
* The options for the input/output methods.
*/
interface StandardJsonOptions {
/**
* Specifies the target version of the generated JSON Schema.
*/
readonly target: StandardJsonTarget;
/**
* Explicit support for additional vendor-specific parameters, if needed.
*/
readonly libraryOptions?: Record<string, unknown> | undefined;
}
//#endregion
//#region src/functions/toJsonSchema/toJsonSchema.d.ts
/**
* Converts a Valibot schema to the JSON Schema format.
*
* @param schema The Valibot schema object.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema.
*/
declare function toJsonSchema(schema: BaseSchema<unknown, unknown, BaseIssue<unknown>>, config?: ConversionConfig): JsonSchema;
//#endregion
//#region src/functions/toJsonSchemaDefs/toJsonSchemaDefs.d.ts
/**
* Converts Valibot schema definitions to JSON Schema definitions.
*
* @param definitions The Valibot schema definitions.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema definitions.
*/
declare function toJsonSchemaDefs<TDefinitions extends Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>>>(definitions: TDefinitions, config?: Omit<ConversionConfig, "definitions">): { [TKey in keyof TDefinitions]: JsonSchema };
//#endregion
//#region src/functions/toStandardJsonSchema/toStandardJsonSchema.d.ts
/**
* Converts a Valibot schema to the Standard JSON Schema format.
*
* @param schema The Valibot schema object.
*
* @returns The Standard JSON Schema.
*/
declare function toStandardJsonSchema<TSchema extends BaseSchema<unknown, unknown, BaseIssue<unknown>>>(schema: TSchema): StandardJsonSchema<InferInput<TSchema>, InferOutput<TSchema>>;
//#endregion
//#region src/storages/globalDefs/globalDefs.d.ts
/**
* Adds new definitions to the global schema definitions.
*
* @param definitions The schema definitions.
*
* @beta
*/
declare function addGlobalDefs(definitions: Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>>): void;
/**
* Returns the current global schema definitions.
*
* @returns The schema definitions.
*
* @beta
*/
declare function getGlobalDefs(): Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>> | undefined;
//#endregion
export { ConversionConfig, ConversionContext, JSONSchema7, JsonSchema, OverrideActionContext, OverrideRefContext, OverrideSchemaContext, StandardJsonSchema, addGlobalDefs, getGlobalDefs, toJsonSchema, toJsonSchemaDefs, toStandardJsonSchema };

View File

@@ -0,0 +1,955 @@
//#region ../../library/src/types/metadata.d.ts
/**
* Base metadata interface.
*/
interface BaseMetadata<TInput$1> {
/**
* The object kind.
*/
readonly kind: "metadata";
/**
* The metadata type.
*/
readonly type: string;
/**
* The metadata reference.
*/
readonly reference: (...args: any[]) => BaseMetadata<any>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TInput$1;
readonly issue: never;
} | undefined;
}
//#endregion
//#region ../../library/src/types/dataset.d.ts
/**
* Unknown dataset interface.
*/
interface UnknownDataset {
/**
* Whether is's typed.
*/
typed?: false;
/**
* The dataset value.
*/
value: unknown;
/**
* The dataset issues.
*/
issues?: undefined;
}
/**
* Success dataset interface.
*/
interface SuccessDataset<TValue$1> {
/**
* Whether is's typed.
*/
typed: true;
/**
* The dataset value.
*/
value: TValue$1;
/**
* The dataset issues.
*/
issues?: undefined;
}
/**
* Partial dataset interface.
*/
interface PartialDataset<TValue$1, TIssue extends BaseIssue<unknown>> {
/**
* Whether is's typed.
*/
typed: true;
/**
* The dataset value.
*/
value: TValue$1;
/**
* The dataset issues.
*/
issues: [TIssue, ...TIssue[]];
}
/**
* Failure dataset interface.
*/
interface FailureDataset<TIssue extends BaseIssue<unknown>> {
/**
* Whether is's typed.
*/
typed: false;
/**
* The dataset value.
*/
value: unknown;
/**
* The dataset issues.
*/
issues: [TIssue, ...TIssue[]];
}
/**
* Output dataset type.
*/
type OutputDataset<TValue$1, TIssue extends BaseIssue<unknown>> = SuccessDataset<TValue$1> | PartialDataset<TValue$1, TIssue> | FailureDataset<TIssue>;
//#endregion
//#region ../../library/src/types/standard.d.ts
/**
* The Standard Schema properties interface.
*/
interface StandardProps<TInput$1, TOutput> {
/**
* The version number of the standard.
*/
readonly version: 1;
/**
* The vendor name of the schema library.
*/
readonly vendor: "valibot";
/**
* Validates unknown input values.
*/
readonly validate: (value: unknown) => StandardResult<TOutput> | Promise<StandardResult<TOutput>>;
/**
* Inferred types associated with the schema.
*/
readonly types?: StandardTypes<TInput$1, TOutput> | undefined;
}
/**
* The result interface of the validate function.
*/
type StandardResult<TOutput> = StandardSuccessResult<TOutput> | StandardFailureResult;
/**
* The result interface if validation succeeds.
*/
interface StandardSuccessResult<TOutput> {
/**
* The typed output value.
*/
readonly value: TOutput;
/**
* The non-existent issues.
*/
readonly issues?: undefined;
}
/**
* The result interface if validation fails.
*/
interface StandardFailureResult {
/**
* The issues of failed validation.
*/
readonly issues: readonly StandardIssue[];
}
/**
* The issue interface of the failure output.
*/
interface StandardIssue {
/**
* The error message of the issue.
*/
readonly message: string;
/**
* The path of the issue, if any.
*/
readonly path?: readonly (PropertyKey | StandardPathItem)[] | undefined;
}
/**
* The path item interface of the issue.
*/
interface StandardPathItem {
/**
* The key of the path item.
*/
readonly key: PropertyKey;
}
/**
* The Standard Schema types interface.
*/
interface StandardTypes<TInput$1, TOutput> {
/**
* The input type of the schema.
*/
readonly input: TInput$1;
/**
* The output type of the schema.
*/
readonly output: TOutput;
}
//#endregion
//#region ../../library/src/types/schema.d.ts
/**
* Base schema interface.
*/
interface BaseSchema<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> {
/**
* The object kind.
*/
readonly kind: "schema";
/**
* The schema type.
*/
readonly type: string;
/**
* The schema reference.
*/
readonly reference: (...args: any[]) => BaseSchema<unknown, unknown, BaseIssue<unknown>>;
/**
* The expected property.
*/
readonly expects: string;
/**
* Whether it's async.
*/
readonly async: false;
/**
* The Standard Schema properties.
*
* @internal
*/
readonly "~standard": StandardProps<TInput$1, TOutput>;
/**
* Parses unknown input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: UnknownDataset, config: Config<BaseIssue<unknown>>) => OutputDataset<TOutput, TIssue>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TOutput;
readonly issue: TIssue;
} | undefined;
}
/**
* Base schema async interface.
*/
interface BaseSchemaAsync<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> extends Omit<BaseSchema<TInput$1, TOutput, TIssue>, "reference" | "async" | "~run"> {
/**
* The schema reference.
*/
readonly reference: (...args: any[]) => BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: true;
/**
* Parses unknown input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: UnknownDataset, config: Config<BaseIssue<unknown>>) => Promise<OutputDataset<TOutput, TIssue>>;
}
//#endregion
//#region ../../library/src/types/transformation.d.ts
/**
* Base transformation interface.
*/
interface BaseTransformation<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> {
/**
* The object kind.
*/
readonly kind: "transformation";
/**
* The transformation type.
*/
readonly type: string;
/**
* The transformation reference.
*/
readonly reference: (...args: any[]) => BaseTransformation<any, any, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: false;
/**
* Transforms known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: SuccessDataset<TInput$1>, config: Config<BaseIssue<unknown>>) => OutputDataset<TOutput, BaseIssue<unknown> | TIssue>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TOutput;
readonly issue: TIssue;
} | undefined;
}
/**
* Base transformation async interface.
*/
interface BaseTransformationAsync<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> extends Omit<BaseTransformation<TInput$1, TOutput, TIssue>, "reference" | "async" | "~run"> {
/**
* The transformation reference.
*/
readonly reference: (...args: any[]) => BaseTransformation<any, any, BaseIssue<unknown>> | BaseTransformationAsync<any, any, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: true;
/**
* Transforms known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: SuccessDataset<TInput$1>, config: Config<BaseIssue<unknown>>) => Promise<OutputDataset<TOutput, BaseIssue<unknown> | TIssue>>;
}
//#endregion
//#region ../../library/src/types/validation.d.ts
/**
* Base validation interface.
*/
interface BaseValidation<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> {
/**
* The object kind.
*/
readonly kind: "validation";
/**
* The validation type.
*/
readonly type: string;
/**
* The validation reference.
*/
readonly reference: (...args: any[]) => BaseValidation<any, any, BaseIssue<unknown>>;
/**
* The expected property.
*/
readonly expects: string | null;
/**
* Whether it's async.
*/
readonly async: false;
/**
* Validates known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: OutputDataset<TInput$1, BaseIssue<unknown>>, config: Config<BaseIssue<unknown>>) => OutputDataset<TOutput, BaseIssue<unknown> | TIssue>;
/**
* The input, output and issue type.
*
* @internal
*/
readonly "~types"?: {
readonly input: TInput$1;
readonly output: TOutput;
readonly issue: TIssue;
} | undefined;
}
/**
* Base validation async interface.
*/
interface BaseValidationAsync<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> extends Omit<BaseValidation<TInput$1, TOutput, TIssue>, "reference" | "async" | "~run"> {
/**
* The validation reference.
*/
readonly reference: (...args: any[]) => BaseValidation<any, any, BaseIssue<unknown>> | BaseValidationAsync<any, any, BaseIssue<unknown>>;
/**
* Whether it's async.
*/
readonly async: true;
/**
* Validates known input values.
*
* @param dataset The input dataset.
* @param config The configuration.
*
* @returns The output dataset.
*
* @internal
*/
readonly "~run": (dataset: OutputDataset<TInput$1, BaseIssue<unknown>>, config: Config<BaseIssue<unknown>>) => Promise<OutputDataset<TOutput, BaseIssue<unknown> | TIssue>>;
}
//#endregion
//#region ../../library/src/types/infer.d.ts
/**
* Infer input type.
*/
type InferInput<TItem$1 extends BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>> | BaseValidation<any, unknown, BaseIssue<unknown>> | BaseValidationAsync<any, unknown, BaseIssue<unknown>> | BaseTransformation<any, unknown, BaseIssue<unknown>> | BaseTransformationAsync<any, unknown, BaseIssue<unknown>> | BaseMetadata<any>> = NonNullable<TItem$1["~types"]>["input"];
/**
* Infer output type.
*/
type InferOutput<TItem$1 extends BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>> | BaseValidation<any, unknown, BaseIssue<unknown>> | BaseValidationAsync<any, unknown, BaseIssue<unknown>> | BaseTransformation<any, unknown, BaseIssue<unknown>> | BaseTransformationAsync<any, unknown, BaseIssue<unknown>> | BaseMetadata<any>> = NonNullable<TItem$1["~types"]>["output"];
//#endregion
//#region ../../library/src/types/utils.d.ts
/**
* Constructs a type that is maybe readonly.
*/
type MaybeReadonly<TValue$1> = TValue$1 | Readonly<TValue$1>;
//#endregion
//#region ../../library/src/types/other.d.ts
/**
* Error message type.
*/
type ErrorMessage<TIssue extends BaseIssue<unknown>> = ((issue: TIssue) => string) | string;
//#endregion
//#region ../../library/src/types/issue.d.ts
/**
* Array path item interface.
*/
interface ArrayPathItem {
/**
* The path item type.
*/
readonly type: "array";
/**
* The path item origin.
*/
readonly origin: "value";
/**
* The path item input.
*/
readonly input: MaybeReadonly<unknown[]>;
/**
* The path item key.
*/
readonly key: number;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Map path item interface.
*/
interface MapPathItem {
/**
* The path item type.
*/
readonly type: "map";
/**
* The path item origin.
*/
readonly origin: "key" | "value";
/**
* The path item input.
*/
readonly input: Map<unknown, unknown>;
/**
* The path item key.
*/
readonly key: unknown;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Object path item interface.
*/
interface ObjectPathItem {
/**
* The path item type.
*/
readonly type: "object";
/**
* The path item origin.
*/
readonly origin: "key" | "value";
/**
* The path item input.
*/
readonly input: Record<string, unknown>;
/**
* The path item key.
*/
readonly key: string;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Set path item interface.
*/
interface SetPathItem {
/**
* The path item type.
*/
readonly type: "set";
/**
* The path item origin.
*/
readonly origin: "value";
/**
* The path item input.
*/
readonly input: Set<unknown>;
/**
* The path item key.
*/
readonly key: null;
/**
* The path item key.
*/
readonly value: unknown;
}
/**
* Unknown path item interface.
*/
interface UnknownPathItem {
/**
* The path item type.
*/
readonly type: "unknown";
/**
* The path item origin.
*/
readonly origin: "key" | "value";
/**
* The path item input.
*/
readonly input: unknown;
/**
* The path item key.
*/
readonly key: unknown;
/**
* The path item value.
*/
readonly value: unknown;
}
/**
* Issue path item type.
*/
type IssuePathItem = ArrayPathItem | MapPathItem | ObjectPathItem | SetPathItem | UnknownPathItem;
/**
* Base issue interface.
*/
interface BaseIssue<TInput$1> extends Config<BaseIssue<TInput$1>> {
/**
* The issue kind.
*/
readonly kind: "schema" | "validation" | "transformation";
/**
* The issue type.
*/
readonly type: string;
/**
* The raw input data.
*/
readonly input: TInput$1;
/**
* The expected property.
*/
readonly expected: string | null;
/**
* The received property.
*/
readonly received: string;
/**
* The error message.
*/
readonly message: string;
/**
* The input requirement.
*/
readonly requirement?: unknown | undefined;
/**
* The issue path.
*/
readonly path?: [IssuePathItem, ...IssuePathItem[]] | undefined;
/**
* The sub issues.
*/
readonly issues?: [BaseIssue<TInput$1>, ...BaseIssue<TInput$1>[]] | undefined;
}
//#endregion
//#region ../../library/src/types/config.d.ts
/**
* Config interface.
*/
interface Config<TIssue extends BaseIssue<unknown>> {
/**
* The selected language.
*/
readonly lang?: string | undefined;
/**
* The error message.
*/
readonly message?: ErrorMessage<TIssue> | undefined;
/**
* Whether it should be aborted early.
*/
readonly abortEarly?: boolean | undefined;
/**
* Whether a pipe should be aborted early.
*/
readonly abortPipeEarly?: boolean | undefined;
}
//#endregion
//#region ../../library/src/types/pipe.d.ts
/**
* Pipe action type.
*/
type PipeAction<TInput$1, TOutput, TIssue extends BaseIssue<unknown>> = BaseValidation<TInput$1, TOutput, TIssue> | BaseTransformation<TInput$1, TOutput, TIssue> | BaseMetadata<TInput$1>;
//#endregion
//#region src/types/schema.d.ts
type JsonSchemaTypeName = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
type JsonSchemaType = string | number | boolean | JsonSchemaObject | JsonSchemaArray | null;
interface JsonSchemaObject {
[key: string]: JsonSchemaType;
}
interface JsonSchemaArray extends Array<JsonSchemaType> {}
type JsonSchemaDefinition = JsonSchema | boolean;
/**
* JSON Schema interface.
*/
interface JsonSchema {
$id?: string | undefined;
$ref?: string | undefined;
$schema?: string | undefined;
$comment?: string | undefined;
$defs?: Record<string, JsonSchemaDefinition> | undefined;
type?: JsonSchemaTypeName | JsonSchemaTypeName[] | undefined;
nullable?: boolean | undefined;
enum?: JsonSchemaType[] | undefined;
const?: JsonSchemaType | undefined;
multipleOf?: number | undefined;
maximum?: number | undefined;
exclusiveMaximum?: number | undefined;
minimum?: number | undefined;
exclusiveMinimum?: number | undefined;
maxLength?: number | undefined;
minLength?: number | undefined;
pattern?: string | undefined;
items?: JsonSchemaDefinition | JsonSchemaDefinition[] | undefined;
prefixItems?: JsonSchemaDefinition[] | undefined;
additionalItems?: JsonSchemaDefinition | undefined;
maxItems?: number | undefined;
minItems?: number | undefined;
uniqueItems?: boolean | undefined;
contains?: JsonSchemaDefinition | undefined;
maxProperties?: number | undefined;
minProperties?: number | undefined;
required?: string[] | undefined;
properties?: Record<string, JsonSchemaDefinition> | undefined;
patternProperties?: Record<string, JsonSchemaDefinition> | undefined;
additionalProperties?: JsonSchemaDefinition | undefined;
dependencies?: Record<string, JsonSchemaDefinition | string[]> | undefined;
propertyNames?: JsonSchemaDefinition | undefined;
if?: JsonSchemaDefinition | undefined;
then?: JsonSchemaDefinition | undefined;
else?: JsonSchemaDefinition | undefined;
allOf?: JsonSchemaDefinition[] | undefined;
anyOf?: JsonSchemaDefinition[] | undefined;
oneOf?: JsonSchemaDefinition[] | undefined;
not?: JsonSchemaDefinition | undefined;
format?: string | undefined;
contentMediaType?: string | undefined;
contentEncoding?: string | undefined;
definitions?: Record<string, JsonSchemaDefinition> | undefined;
title?: string | undefined;
description?: string | undefined;
default?: JsonSchemaType | undefined;
readOnly?: boolean | undefined;
writeOnly?: boolean | undefined;
examples?: JsonSchemaType | undefined;
}
/**
* JSON Schema 7 interface.
*
* @deprecated Use `JsonSchema` instead.
*/
interface JSONSchema7 extends JsonSchema {}
//#endregion
//#region src/types/config.d.ts
/**
* JSON Schema conversion context interface.
*/
interface ConversionContext {
/**
* The JSON Schema definitions that have already been created.
*/
readonly definitions: Record<string, JsonSchema>;
/**
* The JSON Schema reference map that is used to look up the reference ID
* for a given Valibot schema.
*/
readonly referenceMap: Map<BaseSchema<unknown, unknown, BaseIssue<unknown>>, string>;
/**
* The lazy schema getter map that is used internally to ensure that
* recursive lazy schemas are unwrapped only once.
*/
readonly getterMap: Map<(input: unknown) => BaseSchema<unknown, unknown, BaseIssue<unknown>>, BaseSchema<unknown, unknown, BaseIssue<unknown>>>;
}
/**
* JSON Schema override context interface for schemas.
*
* @beta
*/
interface OverrideSchemaContext extends ConversionContext {
/**
* The JSON Schema reference ID.
*/
readonly referenceId: string | undefined;
/**
* The Valibot schema to be converted.
*/
readonly valibotSchema: BaseSchema<unknown, unknown, BaseIssue<unknown>>;
/**
* The converted JSON Schema.
*/
readonly jsonSchema: JsonSchema;
/**
* The errors of the current Valibot schema conversion.
*/
readonly errors: [string, ...string[]] | undefined;
}
/**
* JSON Schema override context interface for actions.
*
* @beta
*/
interface OverrideActionContext {
/**
* The Valibot action to be converted.
*/
readonly valibotAction: PipeAction<any, any, BaseIssue<unknown>>;
/**
* The converted JSON Schema.
*/
readonly jsonSchema: JsonSchema;
/**
* The errors of the current Valibot action conversion.
*/
readonly errors: [string, ...string[]] | undefined;
}
/**
* JSON Schema override context interface for references.
*
* @beta
*/
interface OverrideRefContext extends ConversionContext {
/**
* The JSON Schema reference ID.
*/
readonly referenceId: string;
/**
* The Valibot schema to be converted.
*/
readonly valibotSchema: BaseSchema<unknown, unknown, BaseIssue<unknown>>;
/**
* The converted JSON Schema.
*/
readonly jsonSchema: JsonSchema;
}
/**
* JSON Schema conversion config interface.
*/
interface ConversionConfig {
/**
* The target JSON Schema draft version. Defaults to 'draft-07'.
*/
readonly target?: "draft-07" | "draft-2020-12" | "openapi-3.0";
/**
* Whether to convert the input or output type of the Valibot schema to JSON Schema.
*
* When set to 'input', conversion stops before the first potential type
* transformation action or second schema in any pipeline.
*
* When set to 'output', conversion of any pipelines starts from the last
* schema in the pipeline. Therefore, the output type must be specified
* explicitly with a schema after the last type transformation action.
*
* @beta
*/
readonly typeMode?: "ignore" | "input" | "output";
/**
* The policy for handling incompatible schemas and actions.
*/
readonly errorMode?: "throw" | "warn" | "ignore";
/**
* The schema definitions for constructing recursive schemas. If not
* specified, the definitions are generated automatically as needed.
*/
readonly definitions?: Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>>;
/**
* Overrides the JSON Schema conversion for a specific Valibot schema.
*
* Only return a JSON Schema if you want to override the default conversion
* behaviour and suppress errors for a specific schema. Returning either
* `null` or `undefined` will skip the override.
*
* @param context The conversion context.
*
* @returns A JSON Schema, if overridden.
*
* @beta
*/
readonly overrideSchema?: (context: OverrideSchemaContext) => JsonSchema | null | undefined;
/**
* The actions that should be ignored during the conversion.
*
* @beta
*/
readonly ignoreActions?: string[];
/**
* Overrides the JSON Schema reference for a specific Valibot action.
*
* Only return a JSON Schema if you want to override the default conversion
* behaviour and suppress errors for a specific action. Returning either
* `null` or `undefined` will skip the override.
*
* @param context The conversion context.
*
* @returns A JSON Schema, if overridden.
*
* @beta
*/
readonly overrideAction?: (context: OverrideActionContext) => JsonSchema | null | undefined;
/**
* Overrides the JSON Schema reference for a specific reference ID.
*
* @param context The conversion context.
*
* @returns A reference ID, if overridden.
*
* @beta
*/
readonly overrideRef?: (context: OverrideRefContext) => string | null | undefined;
}
//#endregion
//#region src/types/standard.d.ts
/**
* JSON Schema interface.
*/
interface StandardJsonSchema<TInput$1, TOutput> {
/**
* The Standard JSON Schema properties.
*/
readonly "~standard": StandardJsonProps<TInput$1, TOutput>;
}
/**
* The Standard JSON Schema properties interface.
*/
interface StandardJsonProps<TInput$1, TOutput> extends StandardProps<TInput$1, TOutput> {
/**
* Methods for generating the input/output JSON Schema.
*/
readonly jsonSchema: StandardJsonConverter;
}
/**
* The Standard JSON Schema converter interface.
*/
interface StandardJsonConverter {
/**
* Converts the input type to JSON Schema. May throw if conversion is not supported.
*/
readonly input: (options: StandardJsonOptions) => Record<string, unknown>;
/**
* Converts the output type to JSON Schema. May throw if conversion is not supported.
*/
readonly output: (options: StandardJsonOptions) => Record<string, unknown>;
}
/**
* The target version of the generated JSON Schema.
*/
type StandardJsonTarget = "draft-2020-12" | "draft-07" | "openapi-3.0" | ({} & string);
/**
* The options for the input/output methods.
*/
interface StandardJsonOptions {
/**
* Specifies the target version of the generated JSON Schema.
*/
readonly target: StandardJsonTarget;
/**
* Explicit support for additional vendor-specific parameters, if needed.
*/
readonly libraryOptions?: Record<string, unknown> | undefined;
}
//#endregion
//#region src/functions/toJsonSchema/toJsonSchema.d.ts
/**
* Converts a Valibot schema to the JSON Schema format.
*
* @param schema The Valibot schema object.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema.
*/
declare function toJsonSchema(schema: BaseSchema<unknown, unknown, BaseIssue<unknown>>, config?: ConversionConfig): JsonSchema;
//#endregion
//#region src/functions/toJsonSchemaDefs/toJsonSchemaDefs.d.ts
/**
* Converts Valibot schema definitions to JSON Schema definitions.
*
* @param definitions The Valibot schema definitions.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema definitions.
*/
declare function toJsonSchemaDefs<TDefinitions extends Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>>>(definitions: TDefinitions, config?: Omit<ConversionConfig, "definitions">): { [TKey in keyof TDefinitions]: JsonSchema };
//#endregion
//#region src/functions/toStandardJsonSchema/toStandardJsonSchema.d.ts
/**
* Converts a Valibot schema to the Standard JSON Schema format.
*
* @param schema The Valibot schema object.
*
* @returns The Standard JSON Schema.
*/
declare function toStandardJsonSchema<TSchema extends BaseSchema<unknown, unknown, BaseIssue<unknown>>>(schema: TSchema): StandardJsonSchema<InferInput<TSchema>, InferOutput<TSchema>>;
//#endregion
//#region src/storages/globalDefs/globalDefs.d.ts
/**
* Adds new definitions to the global schema definitions.
*
* @param definitions The schema definitions.
*
* @beta
*/
declare function addGlobalDefs(definitions: Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>>): void;
/**
* Returns the current global schema definitions.
*
* @returns The schema definitions.
*
* @beta
*/
declare function getGlobalDefs(): Record<string, BaseSchema<unknown, unknown, BaseIssue<unknown>>> | undefined;
//#endregion
export { ConversionConfig, ConversionContext, JSONSchema7, JsonSchema, OverrideActionContext, OverrideRefContext, OverrideSchemaContext, StandardJsonSchema, addGlobalDefs, getGlobalDefs, toJsonSchema, toJsonSchemaDefs, toStandardJsonSchema };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,513 @@
import * as v from "valibot";
//#region src/utils/addError.ts
/**
* Adds an error message to the errors array.
*
* @param errors The array of error messages.
* @param message The error message to add.
*
* @returns The new errors.
*/
function addError(errors, message) {
if (errors) {
errors.push(message);
return errors;
}
return [message];
}
//#endregion
//#region src/utils/handleError.ts
/**
* Throws an error or logs a warning based on the configuration.
*
* @param message The message to throw or log.
* @param config The conversion configuration.
*/
function handleError(message, config) {
switch (config?.errorMode) {
case "ignore": break;
case "warn":
console.warn(message);
break;
default: throw new Error(message);
}
}
//#endregion
//#region src/converters/convertAction/convertAction.ts
/**
* Converts any supported Valibot action to the JSON Schema format.
*
* @param jsonSchema The JSON Schema object.
* @param valibotAction The Valibot action object.
* @param config The conversion configuration.
*
* @returns The converted JSON Schema.
*/
function convertAction(jsonSchema, valibotAction, config) {
if (config?.ignoreActions?.includes(valibotAction.type)) return jsonSchema;
let errors;
switch (valibotAction.type) {
case "base64":
jsonSchema.contentEncoding = "base64";
break;
case "bic":
case "cuid2":
case "decimal":
case "digits":
case "emoji":
case "hexadecimal":
case "hex_color":
case "nanoid":
case "octal":
case "ulid":
jsonSchema.pattern = valibotAction.requirement.source;
break;
case "description":
jsonSchema.description = valibotAction.description;
break;
case "email":
jsonSchema.format = "email";
break;
case "empty":
if (jsonSchema.type === "array") jsonSchema.maxItems = 0;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.maxLength = 0;
}
break;
case "entries":
jsonSchema.minProperties = valibotAction.requirement;
jsonSchema.maxProperties = valibotAction.requirement;
break;
case "examples":
if (Array.isArray(jsonSchema.examples)) jsonSchema.examples = [...jsonSchema.examples, ...valibotAction.examples];
else jsonSchema.examples = valibotAction.examples;
break;
case "integer":
jsonSchema.type = "integer";
break;
case "ipv4":
jsonSchema.format = "ipv4";
break;
case "ipv6":
jsonSchema.format = "ipv6";
break;
case "iso_date":
jsonSchema.format = "date";
break;
case "iso_date_time":
case "iso_timestamp":
jsonSchema.format = "date-time";
break;
case "iso_time":
jsonSchema.format = "time";
break;
case "length":
if (jsonSchema.type === "array") {
jsonSchema.minItems = valibotAction.requirement;
jsonSchema.maxItems = valibotAction.requirement;
} else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minLength = valibotAction.requirement;
jsonSchema.maxLength = valibotAction.requirement;
}
break;
case "max_entries":
jsonSchema.maxProperties = valibotAction.requirement;
break;
case "max_length":
if (jsonSchema.type === "array") jsonSchema.maxItems = valibotAction.requirement;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.maxLength = valibotAction.requirement;
}
break;
case "max_value":
if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "max_value" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.maximum = valibotAction.requirement;
break;
case "metadata":
if (typeof valibotAction.metadata.title === "string") jsonSchema.title = valibotAction.metadata.title;
if (typeof valibotAction.metadata.description === "string") jsonSchema.description = valibotAction.metadata.description;
if (Array.isArray(valibotAction.metadata.examples)) if (Array.isArray(jsonSchema.examples)) jsonSchema.examples = [...jsonSchema.examples, ...valibotAction.metadata.examples];
else jsonSchema.examples = valibotAction.metadata.examples;
break;
case "min_entries":
jsonSchema.minProperties = valibotAction.requirement;
break;
case "min_length":
if (jsonSchema.type === "array") jsonSchema.minItems = valibotAction.requirement;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minLength = valibotAction.requirement;
}
break;
case "min_value":
if (jsonSchema.type !== "number" && jsonSchema.type !== "integer") errors = addError(errors, `The "min_value" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minimum = valibotAction.requirement;
break;
case "multiple_of":
jsonSchema.multipleOf = valibotAction.requirement;
break;
case "non_empty":
if (jsonSchema.type === "array") jsonSchema.minItems = 1;
else {
if (jsonSchema.type !== "string") errors = addError(errors, `The "${valibotAction.type}" action is not supported on type "${jsonSchema.type}".`);
jsonSchema.minLength = 1;
}
break;
case "regex":
if (valibotAction.requirement.flags) errors = addError(errors, "RegExp flags are not supported by JSON Schema.");
jsonSchema.pattern = valibotAction.requirement.source;
break;
case "title":
jsonSchema.title = valibotAction.title;
break;
case "url":
jsonSchema.format = "uri";
break;
case "uuid":
jsonSchema.format = "uuid";
break;
case "value":
jsonSchema.const = valibotAction.requirement;
break;
default: errors = addError(errors, `The "${valibotAction.type}" action cannot be converted to JSON Schema.`);
}
if (config?.overrideAction) {
const actionOverride = config.overrideAction({
valibotAction,
jsonSchema,
errors
});
if (actionOverride) return { ...actionOverride };
}
if (errors) for (const message of errors) handleError(message, config);
return jsonSchema;
}
//#endregion
//#region src/converters/convertSchema/convertSchema.ts
/**
* Flattens a Valibot pipe by recursively expanding nested pipes.
*
* @param pipe The pipeline to flatten.
*
* @returns A flat pipeline.
*/
function flattenPipe(pipe) {
return pipe.flatMap((item) => "pipe" in item ? flattenPipe(item.pipe) : item);
}
let refCount = 0;
/**
* Converts any supported Valibot schema to the JSON Schema format.
*
* @param jsonSchema The JSON Schema object.
* @param valibotSchema The Valibot schema object.
* @param config The conversion configuration.
* @param context The conversion context.
* @param skipRef Whether to skip using a reference.
*
* @returns The converted JSON Schema.
*/
function convertSchema(jsonSchema, valibotSchema, config, context, skipRef = false) {
if (!skipRef) {
const referenceId = context.referenceMap.get(valibotSchema);
if (referenceId) {
jsonSchema.$ref = `#/$defs/${referenceId}`;
if (config?.overrideRef) {
const refOverride = config.overrideRef({
...context,
referenceId,
valibotSchema,
jsonSchema
});
if (refOverride) jsonSchema.$ref = refOverride;
}
return jsonSchema;
}
}
if ("pipe" in valibotSchema) {
const flatPipe = flattenPipe(valibotSchema.pipe);
let startIndex = 0;
let stopIndex = flatPipe.length - 1;
if (config?.typeMode === "input") {
const inputStopIndex = flatPipe.slice(1).findIndex((item) => item.kind === "schema" || item.kind === "transformation" && (item.type === "find_item" || item.type === "parse_json" || item.type === "raw_transform" || item.type === "reduce_items" || item.type === "stringify_json" || item.type === "to_bigint" || item.type === "to_boolean" || item.type === "to_date" || item.type === "to_number" || item.type === "to_string" || item.type === "transform"));
if (inputStopIndex !== -1) stopIndex = inputStopIndex;
} else if (config?.typeMode === "output") {
const outputStartIndex = flatPipe.findLastIndex((item) => item.kind === "schema");
if (outputStartIndex !== -1) startIndex = outputStartIndex;
}
for (let index = startIndex; index <= stopIndex; index++) {
const valibotPipeItem = flatPipe[index];
if (valibotPipeItem.kind === "schema") {
if (index > startIndex) handleError("Set the \"typeMode\" config to \"input\" or \"output\" to convert pipelines with multiple schemas.", config);
jsonSchema = convertSchema(jsonSchema, valibotPipeItem, config, context, true);
} else jsonSchema = convertAction(jsonSchema, valibotPipeItem, config);
}
return jsonSchema;
}
let errors;
switch (valibotSchema.type) {
case "boolean":
jsonSchema.type = "boolean";
break;
case "null":
if (config?.target === "openapi-3.0") jsonSchema.enum = [null];
else jsonSchema.type = "null";
break;
case "number":
jsonSchema.type = "number";
break;
case "string":
jsonSchema.type = "string";
break;
case "array":
jsonSchema.type = "array";
jsonSchema.items = convertSchema({}, valibotSchema.item, config, context);
break;
case "tuple":
case "tuple_with_rest":
case "loose_tuple":
case "strict_tuple":
jsonSchema.type = "array";
if (config?.target === "openapi-3.0") {
jsonSchema.items = { anyOf: [] };
jsonSchema.minItems = valibotSchema.items.length;
for (const item of valibotSchema.items) jsonSchema.items.anyOf.push(convertSchema({}, item, config, context));
if (valibotSchema.type === "tuple_with_rest") jsonSchema.items.anyOf.push(convertSchema({}, valibotSchema.rest, config, context));
else if (valibotSchema.type === "strict_tuple" || valibotSchema.type === "tuple") jsonSchema.maxItems = valibotSchema.items.length;
} else if (config?.target === "draft-2020-12") {
jsonSchema.prefixItems = [];
jsonSchema.minItems = valibotSchema.items.length;
for (const item of valibotSchema.items) jsonSchema.prefixItems.push(convertSchema({}, item, config, context));
if (valibotSchema.type === "tuple_with_rest") jsonSchema.items = convertSchema({}, valibotSchema.rest, config, context);
else if (valibotSchema.type === "strict_tuple") jsonSchema.items = false;
} else {
jsonSchema.items = [];
jsonSchema.minItems = valibotSchema.items.length;
for (const item of valibotSchema.items) jsonSchema.items.push(convertSchema({}, item, config, context));
if (valibotSchema.type === "tuple_with_rest") jsonSchema.additionalItems = convertSchema({}, valibotSchema.rest, config, context);
else if (valibotSchema.type === "strict_tuple") jsonSchema.additionalItems = false;
}
break;
case "object":
case "object_with_rest":
case "loose_object":
case "strict_object":
jsonSchema.type = "object";
jsonSchema.properties = {};
jsonSchema.required = [];
for (const key in valibotSchema.entries) {
const entry = valibotSchema.entries[key];
jsonSchema.properties[key] = convertSchema({}, entry, config, context);
if (entry.type !== "exact_optional" && entry.type !== "nullish" && entry.type !== "optional") jsonSchema.required.push(key);
}
if (valibotSchema.type === "object_with_rest") jsonSchema.additionalProperties = convertSchema({}, valibotSchema.rest, config, context);
else if (valibotSchema.type === "strict_object") jsonSchema.additionalProperties = false;
break;
case "record":
if (config?.target === "openapi-3.0" && "pipe" in valibotSchema.key) errors = addError(errors, "The \"record\" schema with a schema for the key that contains a \"pipe\" cannot be converted to JSON Schema.");
if (valibotSchema.key.type !== "string") errors = addError(errors, `The "record" schema with the "${valibotSchema.key.type}" schema for the key cannot be converted to JSON Schema.`);
jsonSchema.type = "object";
if (config?.target !== "openapi-3.0") jsonSchema.propertyNames = convertSchema({}, valibotSchema.key, config, context);
jsonSchema.additionalProperties = convertSchema({}, valibotSchema.value, config, context);
break;
case "any":
case "unknown": break;
case "nullable":
case "nullish":
if (config?.target === "openapi-3.0") {
const innerSchema = convertSchema({}, valibotSchema.wrapped, config, context);
Object.assign(jsonSchema, innerSchema);
jsonSchema.nullable = true;
} else jsonSchema.anyOf = [convertSchema({}, valibotSchema.wrapped, config, context), { type: "null" }];
if (valibotSchema.default !== void 0) jsonSchema.default = v.getDefault(valibotSchema);
break;
case "exact_optional":
case "optional":
case "undefinedable":
jsonSchema = convertSchema(jsonSchema, valibotSchema.wrapped, config, context);
if (valibotSchema.default !== void 0) jsonSchema.default = v.getDefault(valibotSchema);
break;
case "literal":
if (typeof valibotSchema.literal !== "boolean" && typeof valibotSchema.literal !== "number" && typeof valibotSchema.literal !== "string") errors = addError(errors, "The value of the \"literal\" schema is not JSON compatible.");
if (config?.target === "openapi-3.0") jsonSchema.enum = [valibotSchema.literal];
else jsonSchema.const = valibotSchema.literal;
break;
case "enum":
jsonSchema.enum = valibotSchema.options;
break;
case "picklist":
if (valibotSchema.options.some((option) => typeof option !== "number" && typeof option !== "string")) errors = addError(errors, "An option of the \"picklist\" schema is not JSON compatible.");
jsonSchema.enum = valibotSchema.options;
break;
case "union":
jsonSchema.anyOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
break;
case "variant":
jsonSchema.oneOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
break;
case "intersect":
jsonSchema.allOf = valibotSchema.options.map((option) => convertSchema({}, option, config, context));
break;
case "lazy": {
let wrappedValibotSchema = context.getterMap.get(valibotSchema.getter);
if (!wrappedValibotSchema) {
wrappedValibotSchema = valibotSchema.getter(void 0);
context.getterMap.set(valibotSchema.getter, wrappedValibotSchema);
}
let referenceId = context.referenceMap.get(wrappedValibotSchema);
if (!referenceId) {
referenceId = `${refCount++}`;
context.referenceMap.set(wrappedValibotSchema, referenceId);
context.definitions[referenceId] = convertSchema({}, wrappedValibotSchema, config, context, true);
}
jsonSchema.$ref = `#/$defs/${referenceId}`;
if (config?.overrideRef) {
const refOverride = config.overrideRef({
...context,
referenceId,
valibotSchema: wrappedValibotSchema,
jsonSchema
});
if (refOverride) jsonSchema.$ref = refOverride;
}
break;
}
default: errors = addError(errors, `The "${valibotSchema.type}" schema cannot be converted to JSON Schema.`);
}
if (config?.overrideSchema) {
const schemaOverride = config.overrideSchema({
...context,
referenceId: context.referenceMap.get(valibotSchema),
valibotSchema,
jsonSchema,
errors
});
if (schemaOverride) return { ...schemaOverride };
}
if (errors) for (const message of errors) handleError(message, config);
return jsonSchema;
}
//#endregion
//#region src/storages/globalDefs/globalDefs.ts
let store;
/**
* Adds new definitions to the global schema definitions.
*
* @param definitions The schema definitions.
*
* @beta
*/
function addGlobalDefs(definitions) {
store = {
...store ?? {},
...definitions
};
}
/**
* Returns the current global schema definitions.
*
* @returns The schema definitions.
*
* @beta
*/
function getGlobalDefs() {
return store;
}
//#endregion
//#region src/functions/toJsonSchema/toJsonSchema.ts
/**
* Converts a Valibot schema to the JSON Schema format.
*
* @param schema The Valibot schema object.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema.
*/
function toJsonSchema(schema, config) {
const context = {
definitions: {},
referenceMap: /* @__PURE__ */ new Map(),
getterMap: /* @__PURE__ */ new Map()
};
const definitions = config?.definitions ?? getGlobalDefs();
if (definitions) {
for (const key in definitions) context.referenceMap.set(definitions[key], key);
for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
}
const jsonSchema = convertSchema({}, schema, config, context);
const target = config?.target ?? "draft-07";
if (target === "draft-2020-12") jsonSchema.$schema = "https://json-schema.org/draft/2020-12/schema";
else if (target === "draft-07") jsonSchema.$schema = "http://json-schema.org/draft-07/schema#";
if (context.referenceMap.size) jsonSchema.$defs = context.definitions;
return jsonSchema;
}
//#endregion
//#region src/functions/toJsonSchemaDefs/toJsonSchemaDefs.ts
/**
* Converts Valibot schema definitions to JSON Schema definitions.
*
* @param definitions The Valibot schema definitions.
* @param config The JSON Schema configuration.
*
* @returns The converted JSON Schema definitions.
*/
function toJsonSchemaDefs(definitions, config) {
const context = {
definitions: {},
referenceMap: /* @__PURE__ */ new Map(),
getterMap: /* @__PURE__ */ new Map()
};
for (const key in definitions) context.referenceMap.set(definitions[key], key);
for (const key in definitions) context.definitions[key] = convertSchema({}, definitions[key], config, context, true);
return context.definitions;
}
//#endregion
//#region src/functions/toStandardJsonSchema/toStandardJsonSchema.ts
const SUPPORTED_TARGETS = [
"draft-07",
"draft-2020-12",
"openapi-3.0"
];
/**
* Converts a Valibot schema to the Standard JSON Schema format.
*
* @param schema The Valibot schema object.
*
* @returns The Standard JSON Schema.
*/
function toStandardJsonSchema(schema) {
return { "~standard": {
...schema["~standard"],
jsonSchema: {
input(options) {
if (SUPPORTED_TARGETS.includes(options.target)) return toJsonSchema(schema, {
typeMode: "input",
target: options.target,
...options.libraryOptions
});
throw new Error(`Unsupported target: ${options.target}`);
},
output(options) {
if (SUPPORTED_TARGETS.includes(options.target)) return toJsonSchema(schema, {
typeMode: "output",
target: options.target,
...options.libraryOptions
});
throw new Error(`Unsupported target: ${options.target}`);
}
}
} };
}
//#endregion
export { addGlobalDefs, getGlobalDefs, toJsonSchema, toJsonSchemaDefs, toStandardJsonSchema };

View File

@@ -0,0 +1,75 @@
{
"name": "@valibot/to-json-schema",
"description": "The official JSON schema converter for Valibot",
"version": "1.5.0",
"license": "MIT",
"author": "Fabian Hiller",
"homepage": "https://valibot.dev",
"contributors": [
{
"name": "Guillaume Cornut"
}
],
"repository": {
"type": "git",
"url": "https://github.com/open-circle/valibot"
},
"keywords": [
"valibot",
"schema",
"converter",
"json-schema"
],
"type": "module",
"main": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/node": "^24.10.1",
"@vitest/coverage-v8": "^4.0.13",
"eslint": "^9.39.1",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsdoc": "^61.4.0",
"eslint-plugin-security": "^3.0.1",
"globals": "^16.5.0",
"tsdown": "^0.16.6",
"typescript": "^5.9.3",
"typescript-eslint": "^8.47.0",
"valibot": "^1.2.0",
"vite": "^7.2.4",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "4.0.13"
},
"peerDependencies": {
"valibot": "^1.2.0"
},
"scripts": {
"test": "vitest --typecheck",
"coverage": "vitest run --coverage --isolate",
"lint": "eslint \"src/**/*.ts*\" && tsc --noEmit && deno check ./src/index.ts",
"lint.fix": "eslint \"src/**/*.ts*\" --fix",
"format": "prettier --write ./src",
"format.check": "prettier --check ./src",
"build": "tsdown"
}
}