typescript-runtime-schemas
Version:
A TypeScript schema generation tool that extracts Zod schemas from TypeScript source files with runtime validation support. Generate validation schemas directly from your existing TypeScript types with support for computed types and constraint-based valid
335 lines • 13.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZodSchemaGenerator = void 0;
exports.generateZodSchemasFromSource = generateZodSchemasFromSource;
exports.generateZodSchemasFromFile = generateZodSchemasFromFile;
exports.generateZodSchemasFromDirectory = generateZodSchemasFromDirectory;
exports.generateZodSchemasFromGlob = generateZodSchemasFromGlob;
const zod_1 = require("zod");
/**
* ZodSchemaGenerator - Converts parsed constraint schemas to Zod schemas
*/
class ZodSchemaGenerator {
/**
* Generate Zod schemas from extracted constraint schemas
*/
static generateSchemas(extractedSchemas, includeSourceInfo = true) {
return extractedSchemas.map((extracted) => ({
typeName: extracted.typeName,
zodSchema: this.convertToZodSchema(extracted.schema),
sourceInfo: includeSourceInfo ? extracted.sourceInfo : undefined,
}));
}
/**
* Generate a single Zod schema from an extracted schema
*/
static generateSingle(extractedSchema, includeSourceInfo = true) {
return {
typeName: extractedSchema.typeName,
zodSchema: this.convertToZodSchema(extractedSchema.schema),
sourceInfo: includeSourceInfo ? extractedSchema.sourceInfo : undefined,
};
}
/**
* Convert a ParsedSchema to a Zod schema
*/
static convertToZodSchema(parsedSchema) {
const zodProperties = {};
for (const [propertyName, propertySchema] of Object.entries(parsedSchema)) {
zodProperties[propertyName] = this.convertPropertyToZod(propertySchema);
}
return zod_1.z.object(zodProperties);
}
/**
* Convert a PropertySchema to a Zod type
*/
static convertPropertyToZod(propertySchema) {
let zodType;
// Start with the base type
switch (propertySchema.type) {
case "string":
zodType = zod_1.z.string();
break;
case "number":
zodType = zod_1.z.number();
break;
case "boolean":
zodType = zod_1.z.boolean();
break;
case "array":
if (propertySchema.arrayElementType) {
const elementType = this.convertPropertyToZod(propertySchema.arrayElementType);
zodType = zod_1.z.array(elementType);
}
else {
zodType = zod_1.z.array(zod_1.z.unknown());
}
break;
case "object":
if (propertySchema.properties) {
const nestedProperties = {};
for (const [nestedName, nestedSchema] of Object.entries(propertySchema.properties)) {
nestedProperties[nestedName] =
this.convertPropertyToZod(nestedSchema);
}
zodType = zod_1.z.object(nestedProperties);
}
else {
zodType = zod_1.z.object({});
}
break;
default:
zodType = zod_1.z.unknown();
}
// Apply constraints
zodType = this.applyConstraints(zodType, propertySchema.constraints, propertySchema.type);
// Handle optional properties
if (!propertySchema.required) {
zodType = zodType.optional();
}
return zodType;
}
/**
* Apply constraints to a Zod type
*/
static applyConstraints(zodType, constraints, baseType) {
let result = zodType;
for (const [constraintName, constraintValue] of Object.entries(constraints)) {
result = this.applyConstraint(result, constraintName, constraintValue, baseType);
}
return result;
}
/**
* Apply a single constraint to a Zod type
*/
static applyConstraint(zodType, constraintName, constraintValue, baseType) {
switch (constraintName) {
// Numeric constraints
case "min":
if (baseType === "number") {
return zodType.min(constraintValue);
}
else if (baseType === "array") {
return zodType.min(constraintValue);
}
break;
case "max":
if (baseType === "number") {
return zodType.max(constraintValue);
}
else if (baseType === "array") {
return zodType.max(constraintValue);
}
break;
case "integer":
if (baseType === "number" && constraintValue === true) {
return zodType.int();
}
break;
case "positive":
if (baseType === "number" && constraintValue === true) {
return zodType.positive();
}
break;
case "negative":
if (baseType === "number" && constraintValue === true) {
return zodType.negative();
}
break;
// String constraints
case "minLength":
if (baseType === "string") {
return zodType.min(constraintValue);
}
else if (baseType === "array") {
return zodType.min(constraintValue);
}
break;
case "maxLength":
if (baseType === "string") {
return zodType.max(constraintValue);
}
else if (baseType === "array") {
return zodType.max(constraintValue);
}
break;
case "email":
if (baseType === "string" && constraintValue === true) {
return zodType.email();
}
break;
case "uuid":
if (baseType === "string" && constraintValue === true) {
return zodType.uuid();
}
break;
case "url":
if (baseType === "string" && constraintValue === true) {
return zodType.url();
}
break;
case "regex":
if (baseType === "string" && typeof constraintValue === "string") {
try {
const regex = new RegExp(constraintValue);
return zodType.regex(regex);
}
catch (error) {
console.warn(`Invalid regex pattern: ${constraintValue}`, error);
}
}
break;
case "nonEmpty":
if (baseType === "string" && constraintValue === true) {
return zodType.min(1);
}
break;
// Custom constraints - using refinements for complex validations
case "phone":
if (baseType === "string" && constraintValue === true) {
return zodType.refine((val) => /^[\+]?[1-9][\d]{0,15}$/.test(val), { message: "Invalid phone number format" });
}
break;
case "creditCard":
if (baseType === "string" && constraintValue === true) {
return zodType.refine((val) => /^[0-9]{13,19}$/.test(val.replace(/\s/g, "")), { message: "Invalid credit card number format" });
}
break;
case "ipAddress":
if (baseType === "string" && constraintValue === true) {
return zodType.ip();
}
break;
case "base64":
if (baseType === "string" && constraintValue === true) {
return zodType.refine((val) => /^[A-Za-z0-9+/]*={0,2}$/.test(val), { message: "Invalid base64 format" });
}
break;
case "json":
if (baseType === "string" && constraintValue === true) {
return zodType.refine((val) => {
try {
JSON.parse(val);
return true;
}
catch {
return false;
}
}, { message: "Invalid JSON format" });
}
break;
case "date":
if (baseType === "string" && constraintValue === true) {
return zodType.datetime();
}
break;
// Range constraints
case "range":
if (baseType === "number" &&
typeof constraintValue === "object" &&
constraintValue.min !== undefined &&
constraintValue.max !== undefined) {
return zodType
.min(constraintValue.min)
.max(constraintValue.max);
}
break;
// OneOf constraints
case "oneOf":
if (baseType === "string" && Array.isArray(constraintValue)) {
return zod_1.z.enum(constraintValue);
}
break;
// File constraints (using refinements)
case "fileSize":
if (baseType === "number" && typeof constraintValue === "number") {
return zodType.max(constraintValue);
}
break;
case "mimeType":
if (baseType === "string" && typeof constraintValue === "string") {
return zodType.refine((val) => val === constraintValue, { message: `Expected MIME type: ${constraintValue}` });
}
break;
default:
console.warn(`Unknown constraint: ${constraintName} with value:`, constraintValue);
}
return zodType;
}
}
exports.ZodSchemaGenerator = ZodSchemaGenerator;
// Convenience functions for integration with existing pipeline
/**
* Generate Zod schemas from source code string
*/
async function generateZodSchemasFromSource(sourceCode, options) {
const { extractSchemasFromSource } = await Promise.resolve().then(() => __importStar(require("./schema-extractor")));
const extractedSchemas = await extractSchemasFromSource(sourceCode, {
includeSourceInfo: options?.includeSourceInfo ?? true,
});
return ZodSchemaGenerator.generateSchemas(extractedSchemas, options?.includeSourceInfo ?? true);
}
/**
* Generate Zod schemas from a file
*/
async function generateZodSchemasFromFile(filePath, options) {
const { extractSchemasFromFile } = await Promise.resolve().then(() => __importStar(require("./schema-extractor")));
const extractedSchemas = await extractSchemasFromFile(filePath, {
includeSourceInfo: options?.includeSourceInfo ?? true,
});
return ZodSchemaGenerator.generateSchemas(extractedSchemas, options?.includeSourceInfo ?? true);
}
/**
* Generate Zod schemas from a directory
*/
async function generateZodSchemasFromDirectory(dirPath, options) {
const { extractSchemasFromDirectory } = await Promise.resolve().then(() => __importStar(require("./schema-extractor")));
const extractedSchemas = await extractSchemasFromDirectory(dirPath, {
includeSourceInfo: options?.includeSourceInfo ?? true,
});
return ZodSchemaGenerator.generateSchemas(extractedSchemas, options?.includeSourceInfo ?? true);
}
/**
* Generate Zod schemas using glob patterns
*/
async function generateZodSchemasFromGlob(dirPath, glob, exclude, options) {
const { extractSchemasFromGlob } = await Promise.resolve().then(() => __importStar(require("./schema-extractor")));
const extractedSchemas = await extractSchemasFromGlob(dirPath, glob, exclude, {
includeSourceInfo: options?.includeSourceInfo ?? true,
});
return ZodSchemaGenerator.generateSchemas(extractedSchemas, options?.includeSourceInfo ?? true);
}
//# sourceMappingURL=zod-schema-generator.js.map