UNPKG

@kubb/plugin-zod

Version:

Zod schema generator plugin for Kubb, creating type-safe validation schemas from OpenAPI specifications for runtime data validation.

460 lines (455 loc) 19 kB
'use strict'; var react = require('@kubb/react'); var transformers2 = require('@kubb/core/transformers'); var jsxRuntime = require('@kubb/react/jsx-runtime'); var pluginOas = require('@kubb/plugin-oas'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var transformers2__default = /*#__PURE__*/_interopDefault(transformers2); // src/components/Operations.tsx function Operations({ name, operations }) { const operationsJSON = operations.reduce( (prev, acc) => { prev[`"${acc.operation.getOperationId()}"`] = acc.data; return prev; }, {} ); const pathsJSON = operations.reduce( (prev, acc) => { prev[`"${acc.operation.path}"`] = { ...prev[`"${acc.operation.path}"`] || {}, [acc.operation.method]: `operations["${acc.operation.getOperationId()}"]` }; return prev; }, {} ); return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx(react.File.Source, { name, isExportable: true, isIndexable: true, children: /* @__PURE__ */ jsxRuntime.jsx(react.Const, { export: true, name, asConst: true, children: `{${transformers2__default.default.stringifyObject(operationsJSON)}}` }) }), /* @__PURE__ */ jsxRuntime.jsx(react.File.Source, { name: "paths", isExportable: true, isIndexable: true, children: /* @__PURE__ */ jsxRuntime.jsx(react.Const, { export: true, name: "paths", asConst: true, children: `{${transformers2__default.default.stringifyObject(pathsJSON)}}` }) }) ] }); } var zodKeywordMapper = { any: () => "z.any()", unknown: () => "z.unknown()", void: () => "z.void()", number: (coercion, min, max) => { return [coercion ? "z.coerce.number()" : "z.number()", min !== void 0 ? `.min(${min})` : void 0, max !== void 0 ? `.max(${max})` : void 0].filter(Boolean).join(""); }, integer: (coercion, min, max, version = "3") => { return [ coercion ? "z.coerce.number().int()" : version === "4" ? "z.int()" : "z.number().int()", min !== void 0 ? `.min(${min})` : void 0, max !== void 0 ? `.max(${max})` : void 0 ].filter(Boolean).join(""); }, interface: (value, strict) => { if (strict) { return `z.strictInterface({ ${value} })`; } return `z.interface({ ${value} })`; }, object: (value, strict, version = "3") => { if (version === "4" && strict) { return `z.strictObject({ ${value} })`; } if (strict) { return `z.object({ ${value} }).strict()`; } return `z.object({ ${value} })`; }, string: (coercion, min, max) => { return [coercion ? "z.coerce.string()" : "z.string()", min !== void 0 ? `.min(${min})` : void 0, max !== void 0 ? `.max(${max})` : void 0].filter(Boolean).join(""); }, //support for discriminatedUnion boolean: () => "z.boolean()", undefined: () => "z.undefined()", nullable: () => ".nullable()", null: () => "z.null()", nullish: () => ".nullish()", array: (items = [], min, max, unique) => { return [ `z.array(${items?.join("")})`, min !== void 0 ? `.min(${min})` : void 0, max !== void 0 ? `.max(${max})` : void 0, unique ? `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : void 0 ].filter(Boolean).join(""); }, tuple: (items = []) => `z.tuple([${items?.join(", ")}])`, enum: (items = []) => `z.enum([${items?.join(", ")}])`, union: (items = []) => `z.union([${items?.join(", ")}])`, const: (value) => `z.literal(${value ?? ""})`, /** * ISO 8601 */ datetime: (offset = false, local = false, version = "3") => { if (offset) { return version === "4" ? `z.iso.datetime({ offset: ${offset} })` : `z.string().datetime({ offset: ${offset} })`; } if (local) { return version === "4" ? `z.iso.datetime({ local: ${local} })` : `z.string().datetime({ local: ${local} })`; } return "z.string().datetime()"; }, /** * Type `'date'` Date * Type `'string'` ISO date format (YYYY-MM-DD) * @default ISO date format (YYYY-MM-DD) */ date: (type = "string", coercion, version = "3") => { if (type === "string") { return version === "4" ? "z.iso.date()" : "z.string().date()"; } if (coercion) { return "z.coerce.date()"; } return "z.date()"; }, /** * Type `'date'` Date * Type `'string'` ISO time format (HH:mm:ss[.SSSSSS]) * @default ISO time format (HH:mm:ss[.SSSSSS]) */ time: (type = "string", coercion, version = "3") => { if (type === "string") { return version === "4" ? "z.iso.time()" : "z.string().time()"; } if (coercion) { return "z.coerce.date()"; } return "z.date()"; }, uuid: (coercion, version = "3") => version === "4" ? coercion ? "z.coerce.string().uuid()" : "z.uuid()" : coercion ? "z.coerce.string().uuid()" : "z.string().uuid()", url: (coercion, version = "3") => version === "4" ? coercion ? "z.coerce.string().url()" : "z.url()" : coercion ? "z.coerce.string().url()" : "z.string().url()", default: (value) => { if (typeof value === "object") { return ".default({})"; } return `.default(${value ?? ""})`; }, and: (items = []) => items?.map((item) => `.and(${item})`).join(""), describe: (value = "") => `.describe(${value})`, min: (value) => `.min(${value ?? ""})`, max: (value) => `.max(${value ?? ""})`, optional: () => ".optional()", matches: (value = "", coercion) => coercion ? `z.coerce.string().regex(${value})` : `z.string().regex(${value})`, email: (coercion, version = "3") => version === "4" ? coercion ? "z.coerce.string().email()" : "z.email()" : coercion ? "z.coerce.string().email()" : "z.string().email()", firstName: void 0, lastName: void 0, password: void 0, phone: void 0, readOnly: void 0, writeOnly: void 0, ref: (value, version = "3") => { if (!value) { return void 0; } return version === "4" ? value : `z.lazy(() => ${value})`; }, blob: () => "z.instanceof(File)", deprecated: void 0, example: void 0, schema: void 0, catchall: (value) => value ? `.catchall(${value})` : void 0, name: void 0 }; function sort(items) { const order = [ pluginOas.schemaKeywords.string, pluginOas.schemaKeywords.datetime, pluginOas.schemaKeywords.date, pluginOas.schemaKeywords.time, pluginOas.schemaKeywords.tuple, pluginOas.schemaKeywords.number, pluginOas.schemaKeywords.object, pluginOas.schemaKeywords.enum, pluginOas.schemaKeywords.url, pluginOas.schemaKeywords.email, pluginOas.schemaKeywords.firstName, pluginOas.schemaKeywords.lastName, pluginOas.schemaKeywords.password, pluginOas.schemaKeywords.matches, pluginOas.schemaKeywords.uuid, pluginOas.schemaKeywords.null, pluginOas.schemaKeywords.min, pluginOas.schemaKeywords.max, pluginOas.schemaKeywords.default, pluginOas.schemaKeywords.describe, pluginOas.schemaKeywords.optional, pluginOas.schemaKeywords.nullable, pluginOas.schemaKeywords.nullish ]; if (!items) { return []; } return transformers2__default.default.orderBy(items, [(v) => order.indexOf(v.keyword)], ["asc"]); } var shouldCoerce = (coercion, type) => { if (coercion === void 0) { return false; } if (typeof coercion === "boolean") { return coercion; } return !!coercion[type]; }; function parse({ parent, current, name, siblings }, options) { const value = zodKeywordMapper[current.keyword]; const hasMatches = siblings.some((it) => pluginOas.isKeyword(it, pluginOas.schemaKeywords.matches)); const hasRef = siblings.some((it) => pluginOas.isKeyword(it, pluginOas.schemaKeywords.ref)); if (hasMatches && hasRef && pluginOas.isKeyword(current, pluginOas.schemaKeywords.matches)) { return void 0; } if (!value) { return void 0; } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.union)) { if (Array.isArray(current.args) && current.args.length === 1) { return parse({ parent, name, current: current.args[0], siblings }, options); } if (Array.isArray(current.args) && !current.args.length) { return ""; } return zodKeywordMapper.union( sort(current.args).map((schema, _index, siblings2) => parse({ parent: current, name, current: schema, siblings: siblings2 }, options)).filter(Boolean) ); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.and)) { const items = sort(current.args).filter((schema) => { return ![pluginOas.schemaKeywords.optional, pluginOas.schemaKeywords.describe].includes(schema.keyword); }).map((schema, _index, siblings2) => parse({ parent: current, name, current: schema, siblings: siblings2 }, options)).filter(Boolean); return `${items.slice(0, 1)}${zodKeywordMapper.and(items.slice(1))}`; } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.array)) { return zodKeywordMapper.array( sort(current.args.items).map((schemas, _index, siblings2) => parse({ parent: current, name, current: schemas, siblings: siblings2 }, options)).filter(Boolean), current.args.min, current.args.max, current.args.unique ); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.enum)) { if (current.args.asConst) { if (current.args.items.length === 1) { const child = { keyword: pluginOas.schemaKeywords.const, args: current.args.items[0] }; return parse({ parent: current, name, current: child, siblings: [child] }, options); } return zodKeywordMapper.union( current.args.items.map((schema) => ({ keyword: pluginOas.schemaKeywords.const, args: schema })).map((schema, _index, siblings2) => { return parse({ parent: current, name, current: schema, siblings: siblings2 }, options); }).filter(Boolean) ); } return zodKeywordMapper.enum( current.args.items.map((schema) => { if (schema.format === "boolean") { return transformers2__default.default.stringify(schema.value); } if (schema.format === "number") { return transformers2__default.default.stringify(schema.value); } return transformers2__default.default.stringify(schema.value); }) ); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.ref)) { return zodKeywordMapper.ref(current.args?.name, options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.object)) { const propertyEntries = Object.entries(current.args?.properties || {}).filter((item) => { const schema = item[1]; return schema && typeof schema.map === "function"; }); const properties = propertyEntries.map(([name2, schemas]) => { const nameSchema = schemas.find((schema) => schema.keyword === pluginOas.schemaKeywords.name); const mappedName = nameSchema?.args || name2; if (options.mapper?.[mappedName]) { return `"${name2}": ${options.mapper?.[mappedName]}`; } const baseSchemaOutput = sort(schemas).map((schema) => parse({ parent: current, name: name2, current: schema, siblings: schemas }, options)).filter(Boolean).join(""); const objectValue = options.wrapOutput ? options.wrapOutput({ output: baseSchemaOutput, schema: options.rawSchema?.properties?.[name2] }) || baseSchemaOutput : baseSchemaOutput; if (options.version === "4" && pluginOas.SchemaGenerator.find(schemas, pluginOas.schemaKeywords.ref)) { return `get ${name2}(){ return ${objectValue} }`; } return `"${name2}": ${objectValue}`; }).join(",\n"); const additionalProperties = current.args?.additionalProperties?.length ? current.args.additionalProperties.map((schema, _index, siblings2) => parse({ parent: current, name, current: schema, siblings: siblings2 }, options)).filter(Boolean).join("") : void 0; const text = [ zodKeywordMapper.object(properties, current.args?.strict, options.version), additionalProperties ? zodKeywordMapper.catchall(additionalProperties) : void 0 ].filter(Boolean); return text.join(""); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.tuple)) { return zodKeywordMapper.tuple( current.args.items.map((schema, _index, siblings2) => parse({ parent: current, name, current: schema, siblings: siblings2 }, options)).filter(Boolean) ); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.const)) { if (current.args.format === "number" && current.args.value !== void 0) { return zodKeywordMapper.const(Number(current.args.value)); } if (current.args.format === "boolean" && current.args.value !== void 0) { return zodKeywordMapper.const(current.args.value); } return zodKeywordMapper.const(transformers2__default.default.stringify(current.args.value)); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.matches)) { if (current.args) { return zodKeywordMapper.matches(transformers2__default.default.toRegExpString(current.args, null), shouldCoerce(options.coercion, "strings")); } } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.default)) { if (current.args) { return zodKeywordMapper.default(current.args); } } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.describe)) { if (current.args) { return zodKeywordMapper.describe(transformers2__default.default.stringify(current.args.toString())); } } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.string)) { return zodKeywordMapper.string(shouldCoerce(options.coercion, "strings")); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.uuid)) { return zodKeywordMapper.uuid(shouldCoerce(options.coercion, "strings"), options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.email)) { return zodKeywordMapper.email(shouldCoerce(options.coercion, "strings"), options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.url)) { return zodKeywordMapper.url(shouldCoerce(options.coercion, "strings"), options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.number)) { return zodKeywordMapper.number(shouldCoerce(options.coercion, "numbers")); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.integer)) { return zodKeywordMapper.integer(shouldCoerce(options.coercion, "numbers"), void 0, void 0, options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.min)) { return zodKeywordMapper.min(current.args); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.max)) { return zodKeywordMapper.max(current.args); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.datetime)) { return zodKeywordMapper.datetime(current.args.offset, current.args.local, options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.date)) { return zodKeywordMapper.date(current.args.type, shouldCoerce(options.coercion, "dates"), options.version); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.time)) { return zodKeywordMapper.time(current.args.type, shouldCoerce(options.coercion, "dates"), options.version); } if (current.keyword in zodKeywordMapper && "args" in current) { const value2 = zodKeywordMapper[current.keyword]; return value2(current.args); } if (pluginOas.isKeyword(current, pluginOas.schemaKeywords.optional)) { if (siblings.some((schema) => pluginOas.isKeyword(schema, pluginOas.schemaKeywords.default))) return ""; return value(); } if (current.keyword in zodKeywordMapper) { return value(); } return void 0; } function Zod({ name, typeName, tree, rawSchema, inferTypeName, mapper, coercion, keysToOmit, description, wrapOutput, version, emptySchemaType }) { const hasTuple = !!pluginOas.SchemaGenerator.deepSearch(tree, pluginOas.schemaKeywords.tuple); const schemas = sort(tree).filter((item) => { if (hasTuple && (pluginOas.isKeyword(item, pluginOas.schemaKeywords.min) || pluginOas.isKeyword(item, pluginOas.schemaKeywords.max))) { return false; } return true; }); const output = schemas.map( (schema, _index, siblings) => parse( { parent: void 0, current: schema, siblings }, { name, keysToOmit, typeName, description, mapper, coercion, wrapOutput, rawSchema, version } ) ).filter(Boolean).join(""); let suffix = ""; const firstSchema = schemas.at(0); const lastSchema = schemas.at(-1); if (lastSchema && pluginOas.isKeyword(lastSchema, pluginOas.schemaKeywords.nullable)) { if (firstSchema && pluginOas.isKeyword(firstSchema, pluginOas.schemaKeywords.ref)) { if (version === "3") { suffix = ".unwrap().schema.unwrap()"; } else { suffix = ".unwrap().unwrap()"; } } else { suffix = ".unwrap()"; } } else { if (firstSchema && pluginOas.isKeyword(firstSchema, pluginOas.schemaKeywords.ref) && version === "3") { suffix = ".schema"; } } const emptyValue = parse( { parent: void 0, current: { keyword: pluginOas.schemaKeywords[emptySchemaType] }, siblings: [] }, { name, keysToOmit, typeName, description, mapper, coercion, wrapOutput, rawSchema, version } ); const baseSchemaOutput = [output, keysToOmit?.length ? `${suffix}.omit({ ${keysToOmit.map((key) => `${key}: true`).join(",")} })` : void 0].filter(Boolean).join("") || emptyValue || ""; const wrappedSchemaOutput = wrapOutput ? wrapOutput({ output: baseSchemaOutput, schema: rawSchema }) || baseSchemaOutput : baseSchemaOutput; const finalOutput = typeName ? `${wrappedSchemaOutput} as unknown as ToZod<${typeName}>` : wrappedSchemaOutput; return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx(react.File.Source, { name, isExportable: true, isIndexable: true, children: /* @__PURE__ */ jsxRuntime.jsx( react.Const, { export: true, name, JSDoc: { comments: [description ? `@description ${transformers2__default.default.jsStringEscape(description)}` : void 0].filter(Boolean) }, children: finalOutput } ) }), inferTypeName && /* @__PURE__ */ jsxRuntime.jsxs(react.File.Source, { name: inferTypeName, isExportable: true, isIndexable: true, isTypeOnly: true, children: [ typeName && /* @__PURE__ */ jsxRuntime.jsx(react.Type, { export: true, name: inferTypeName, children: typeName }), !typeName && /* @__PURE__ */ jsxRuntime.jsx(react.Type, { export: true, name: inferTypeName, children: `z.infer<typeof ${name}>` }) ] }) ] }); } exports.Operations = Operations; exports.Zod = Zod; //# sourceMappingURL=chunk-FYI4GRXP.cjs.map //# sourceMappingURL=chunk-FYI4GRXP.cjs.map