Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@asteasolutions/zod-to-openapi

Package Overview
Dependencies
Maintainers
3
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@asteasolutions/zod-to-openapi - npm Package Compare versions

Comparing version 1.2.3 to 1.3.0

2

dist/lib/lodash.js

@@ -23,3 +23,3 @@ "use strict";

Object.entries(object).forEach(([key, value]) => {
if (!keys.some((keyToOmit) => keyToOmit === key)) {
if (!keys.some(keyToOmit => keyToOmit === key)) {
result[key] = value;

@@ -26,0 +26,0 @@ }

@@ -1,2 +0,2 @@

import type { z } from "zod";
import type { z } from 'zod';
declare type ZodTypes = {

@@ -22,2 +22,3 @@ ZodArray: z.ZodArray<any>;

ZodUnion: z.ZodUnion<any>;
ZodDiscriminatedUnion: z.ZodDiscriminatedUnion<any, any, any>;
ZodUnknown: z.ZodUnknown;

@@ -24,0 +25,0 @@ ZodVoid: z.ZodVoid;

@@ -16,5 +16,7 @@ import { OpenAPIObject, InfoObject, ServerObject, SecurityRequirementObject, TagObject, ExternalDocumentationObject, ComponentsObject } from 'openapi3-ts';

private pathRefs;
private rawComponents;
constructor(definitions: OpenAPIDefinitions[]);
generateDocument(config: OpenAPIObjectConfig): OpenAPIObject;
generateComponents(): ComponentsObject;
private buildComponents;
private sortDefinitions;

@@ -36,2 +38,3 @@ private generateSingle;

private getResponse;
private descriptionFromResponseConfig;
private toOpenAPISchema;

@@ -38,0 +41,0 @@ private isOptionalSchema;

@@ -24,20 +24,25 @@ "use strict";

this.pathRefs = {};
this.rawComponents = [];
this.sortDefinitions();
}
generateDocument(config) {
this.definitions.forEach((definition) => this.generateSingle(definition));
return Object.assign(Object.assign({}, config), { components: {
schemas: this.schemaRefs,
parameters: this.paramRefs,
}, paths: this.pathRefs });
this.definitions.forEach(definition => this.generateSingle(definition));
return Object.assign(Object.assign({}, config), { components: this.buildComponents(), paths: this.pathRefs });
}
generateComponents() {
this.definitions.forEach((definition) => this.generateSingle(definition));
this.definitions.forEach(definition => this.generateSingle(definition));
return {
components: {
schemas: this.schemaRefs,
parameters: this.paramRefs,
},
components: this.buildComponents(),
};
}
buildComponents() {
var _a, _b;
const rawComponents = {};
this.rawComponents.forEach(({ componentType, name, component }) => {
var _a;
(_a = rawComponents[componentType]) !== null && _a !== void 0 ? _a : (rawComponents[componentType] = {});
rawComponents[componentType][name] = component;
});
return Object.assign(Object.assign({}, rawComponents), { schemas: Object.assign(Object.assign({}, ((_a = rawComponents.schemas) !== null && _a !== void 0 ? _a : {})), this.schemaRefs), parameters: Object.assign(Object.assign({}, ((_b = rawComponents.parameters) !== null && _b !== void 0 ? _b : {})), this.paramRefs) });
}
sortDefinitions() {

@@ -50,4 +55,4 @@ const generationOrder = [

this.definitions.sort((left, right) => {
const leftIndex = generationOrder.findIndex((type) => type === left.type);
const rightIndex = generationOrder.findIndex((type) => type === right.type);
const leftIndex = generationOrder.findIndex(type => type === left.type);
const rightIndex = generationOrder.findIndex(type => type === right.type);
return leftIndex - rightIndex;

@@ -57,12 +62,16 @@ });

generateSingle(definition) {
if (definition.type === 'parameter') {
return this.generateParameterDefinition(definition.schema);
switch (definition.type) {
case 'parameter':
this.generateParameterDefinition(definition.schema);
return;
case 'schema':
this.generateSchemaDefinition(definition.schema);
return;
case 'route':
this.generateSingleRoute(definition.route);
return;
case 'component':
this.rawComponents.push(definition);
return;
}
if (definition.type === 'schema') {
return this.generateSchemaDefinition(definition.schema);
}
if (definition.type === 'route') {
return this.generateSingleRoute(definition.route);
}
throw new errors_1.ZodToOpenAPIError('Invalid definition type');
}

@@ -250,3 +259,3 @@ generateParameterDefinition(zodSchema) {

: [];
const headerParameters = (_b = (_a = request.headers) === null || _a === void 0 ? void 0 : _a.flatMap((header) => this.generateInlineParameters(header, 'header'))) !== null && _b !== void 0 ? _b : [];
const headerParameters = (_b = (_a = request.headers) === null || _a === void 0 ? void 0 : _a.flatMap(header => this.generateInlineParameters(header, 'header'))) !== null && _b !== void 0 ? _b : [];
return [...pathParameters, ...queryParameters, ...headerParameters];

@@ -256,3 +265,3 @@ }

const { method, path, request, responses } = route, pathItemConfig = __rest(route, ["method", "path", "request", "responses"]);
const generatedResponses = (0, lodash_1.mapValues)(responses, (response) => {
const generatedResponses = (0, lodash_1.mapValues)(responses, response => {
return this.getResponse(response);

@@ -269,18 +278,11 @@ });

getResponse(response) {
const description = this.descriptionFromResponseConfig(response);
if ((0, zod_is_type_1.isZodType)(response, 'ZodVoid')) {
const metadata = this.getMetadata(response);
if (!(metadata === null || metadata === void 0 ? void 0 : metadata.description)) {
throw new errors_1.MissingResponseDescriptionError();
}
return {
description: metadata.description,
};
return { description };
}
const metadata = this.getMetadata(response.schema);
const responseSchema = this.generateInnerSchema(response.schema);
if (!(metadata === null || metadata === void 0 ? void 0 : metadata.description)) {
throw new errors_1.MissingResponseDescriptionError();
}
return {
description: metadata.description,
description,
headers: response.headers,
links: response.links,
content: {

@@ -293,2 +295,19 @@ [response.mediaType]: {

}
descriptionFromResponseConfig(response) {
if ((0, zod_is_type_1.isZodType)(response, 'ZodVoid')) {
const metadata = this.getMetadata(response);
if (!(metadata === null || metadata === void 0 ? void 0 : metadata.description)) {
throw new errors_1.MissingResponseDescriptionError();
}
return metadata.description;
}
if (response.description) {
return response.description;
}
const metadata = this.getMetadata(response.schema);
if (!(metadata === null || metadata === void 0 ? void 0 : metadata.description)) {
throw new errors_1.MissingResponseDescriptionError();
}
return metadata.description;
}
toOpenAPISchema(zodSchema, isNullable) {

@@ -368,9 +387,15 @@ var _a, _b, _c, _d, _e;

return {
anyOf: options.map((schema) => this.generateInnerSchema(schema)),
anyOf: options.map(schema => this.generateInnerSchema(schema)),
};
}
if ((0, zod_is_type_1.isZodType)(zodSchema, 'ZodDiscriminatedUnion')) {
const options = [...zodSchema.options.values()];
return {
anyOf: options.map(schema => this.generateInnerSchema(schema)),
};
}
if ((0, zod_is_type_1.isZodType)(zodSchema, 'ZodIntersection')) {
const subtypes = this.flattenIntersectionTypes(zodSchema);
return {
allOf: subtypes.map((schema) => this.generateInnerSchema(schema)),
allOf: subtypes.map(schema => this.generateInnerSchema(schema)),
};

@@ -411,3 +436,3 @@ }

type: 'object',
properties: (0, lodash_1.mapValues)(propTypes, (propSchema) => this.generateInnerSchema(propSchema)),
properties: (0, lodash_1.mapValues)(propTypes, propSchema => this.generateInnerSchema(propSchema)),
required: requiredProperties.length > 0 ? requiredProperties : undefined,

@@ -423,3 +448,3 @@ additionalProperties: unknownKeysOption === 'passthrough' || undefined,

const options = schema._def.options;
return options.flatMap((option) => this.flattenUnionTypes(option));
return options.flatMap(option => this.flattenUnionTypes(option));
}

@@ -426,0 +451,0 @@ flattenIntersectionTypes(schema) {

@@ -1,2 +0,2 @@

import { OperationObject } from 'openapi3-ts';
import { CallbackObject, ComponentsObject, ExampleObject, HeaderObject, HeadersObject, ISpecificationExtension, LinkObject, LinksObject, OperationObject, ParameterObject, RequestBodyObject, ResponseObject, SchemaObject, SecuritySchemeObject } from 'openapi3-ts';
import type { ZodVoid, ZodObject, ZodSchema, ZodType } from 'zod';

@@ -7,2 +7,5 @@ declare type Method = 'get' | 'post' | 'put' | 'delete' | 'patch';

schema: ZodType<unknown>;
description?: string;
headers?: HeadersObject;
links?: LinksObject;
} | ZodVoid;

@@ -22,3 +25,11 @@ export interface RouteConfig extends OperationObject {

}
export declare type OpenAPIComponentObject = SchemaObject | ResponseObject | ParameterObject | ExampleObject | RequestBodyObject | HeaderObject | SecuritySchemeObject | LinkObject | CallbackObject | ISpecificationExtension;
export declare type ComponentTypeKey = Exclude<keyof ComponentsObject, number>;
export declare type ComponentTypeOf<K extends ComponentTypeKey> = NonNullable<ComponentsObject[K]>[string];
export declare type OpenAPIDefinitions = {
type: 'component';
componentType: ComponentTypeKey;
name: string;
component: OpenAPIComponentObject;
} | {
type: 'schema';

@@ -50,3 +61,17 @@ schema: ZodSchema<any>;

registerPath(route: RouteConfig): void;
/**
* Registers a raw OpenAPI component. Use this if you have a simple object instead of a Zod schema.
*
* @param type The component type, e.g. `schemas`, `responses`, `securitySchemes`, etc.
* @param name The name of the object, it is the key under the component
* type in the resulting OpenAPI document
* @param component The actual object to put there
*/
registerComponent<K extends ComponentTypeKey>(type: K, name: string, component: ComponentTypeOf<K>): {
name: string;
ref: {
$ref: string;
};
};
}
export {};

@@ -11,3 +11,3 @@ "use strict";

var _a, _b;
const parentDefinitions = (_b = (_a = this.parents) === null || _a === void 0 ? void 0 : _a.flatMap((par) => par.definitions)) !== null && _b !== void 0 ? _b : [];
const parentDefinitions = (_b = (_a = this.parents) === null || _a === void 0 ? void 0 : _a.flatMap(par => par.definitions)) !== null && _b !== void 0 ? _b : [];
return [...parentDefinitions, ...this._definitions];

@@ -46,3 +46,23 @@ }

}
/**
* Registers a raw OpenAPI component. Use this if you have a simple object instead of a Zod schema.
*
* @param type The component type, e.g. `schemas`, `responses`, `securitySchemes`, etc.
* @param name The name of the object, it is the key under the component
* type in the resulting OpenAPI document
* @param component The actual object to put there
*/
registerComponent(type, name, component) {
this._definitions.push({
type: 'component',
componentType: type,
name,
component,
});
return {
name,
ref: { $ref: `#/components/${type}/${name}` },
};
}
}
exports.OpenAPIRegistry = OpenAPIRegistry;

@@ -16,2 +16,8 @@ "use strict";

function extendZodWithOpenApi(zod) {
if (typeof zod.ZodSchema.prototype.openapi !== 'undefined') {
// This zod instance is already extended with the required methods,
// doing it again will just result in multiple wrapper methods for
// `optional` and `nullable`
return;
}
zod.ZodSchema.prototype.openapi = function (openapi) {

@@ -18,0 +24,0 @@ var _a;

{
"name": "@asteasolutions/zod-to-openapi",
"version": "1.2.3",
"version": "1.3.0",
"description": "Builds OpenAPI schemas from Zod schemas",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [

@@ -27,2 +28,4 @@ "dist",

"test": "jest",
"prettier": "prettier --write .",
"lint": "prettier --check .",
"prepublishOnly": "npm run build"

@@ -39,2 +42,3 @@ },

"jest": "^27.5.1",
"prettier": "^2.7.1",
"ts-jest": "^27.1.4",

@@ -41,0 +45,0 @@ "typescript": "^4.6.3",

@@ -12,2 +12,3 @@ # Zod to OpenAPI

5. [Defining routes](#defining-routes)
6. [Defining custom components](#defining-custom-components)
6. [A full example](#a-full-example)

@@ -321,2 +322,6 @@ 7. [Adding it as part of your build](#adding-it-as-part-of-your-build)

### Defining custom components
You can define components that are not OpenAPI schemas, including security schemes, response headers and others. See [this test file](spec/custom-components.spec.ts) for examples.
### A full example

@@ -323,0 +328,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc