prisma-zod-generator
Version:
Prisma 2+ generator to emit Zod schemas from your Prisma schema
570 lines (569 loc) • 17.1 kB
TypeScript
/**
* Pure Model Schema Generator
*
* Generates Zod schemas representing the raw Prisma model structure,
* similar to zod-prisma functionality but with enhanced inline validation support.
*/
import { DMMF } from '@prisma/generator-helper';
import { type CustomImport } from '../parsers/zod-comments';
/**
* Configuration for Prisma type mapping
*/
export interface TypeMappingConfig {
/** How to handle Decimal fields: 'string' | 'number' | 'decimal' */
decimalMode: 'string' | 'number' | 'decimal';
/** How to handle JSON fields: 'unknown' | 'record' | 'any' */
jsonMode: 'unknown' | 'record' | 'any';
/** Whether to use strict date validation */
strictDateValidation: boolean;
/** Whether to validate BigInt values */
validateBigInt: boolean;
/** Custom type mappings for specific field types */
customTypeMappings?: Record<string, string>;
/** Whether to include database-specific validations */
includeDatabaseValidations: boolean;
/** Provider-specific options */
provider?: 'postgresql' | 'mysql' | 'sqlite' | 'sqlserver' | 'mongodb';
/** Zod import target for version-specific behavior */
zodImportTarget?: 'auto' | 'v3' | 'v4';
/** Whether to generate JSON Schema compatible schemas */
jsonSchemaCompatible?: boolean;
/** JSON Schema compatibility options */
jsonSchemaOptions?: {
dateTimeFormat?: 'isoString' | 'isoDate';
bigIntFormat?: 'string' | 'number';
bytesFormat?: 'base64String' | 'hexString';
};
/** Complex type configuration */
complexTypes: {
/** Decimal field configuration */
decimal: {
/** Precision validation for decimal fields */
validatePrecision: boolean;
/** Maximum precision digits */
maxPrecision?: number;
/** Maximum scale digits */
maxScale?: number;
/** Allow negative values */
allowNegative: boolean;
};
/** DateTime field configuration */
dateTime: {
/** Allow future dates */
allowFuture: boolean;
/** Allow past dates */
allowPast: boolean;
/** Minimum date (ISO string) */
minDate?: string;
/** Maximum date (ISO string) */
maxDate?: string;
/** Timezone handling: 'utc' | 'local' | 'preserve' */
timezoneMode: 'utc' | 'local' | 'preserve';
};
/** JSON field configuration */
json: {
/** Maximum nesting depth */
maxDepth?: number;
/** Maximum JSON string length */
maxLength?: number;
/** Allow null values in JSON */
allowNull: boolean;
/** Validate JSON structure */
validateStructure: boolean;
};
/** Bytes field configuration */
bytes: {
/** Maximum file size in bytes */
maxSize?: number;
/** Minimum file size in bytes */
minSize?: number;
/** Allowed MIME types */
allowedMimeTypes?: string[];
/** Validate as base64 string instead of Uint8Array */
useBase64: boolean;
};
};
}
/**
* Default type mapping configuration
*/
export declare const DEFAULT_TYPE_MAPPING_CONFIG: TypeMappingConfig;
/**
* Interface for Prisma field type mapping result
*/
export interface FieldTypeMappingResult {
/** Base Zod schema string */
zodSchema: string;
/** Required imports for this field type */
imports: Set<string>;
/** JSDoc comments for the field */
documentation?: string;
/** Additional validations to apply */
additionalValidations: string[];
/** Whether this field requires special handling */
requiresSpecialHandling: boolean;
/** Database-specific considerations */
databaseSpecific?: {
constraints: string[];
optimizations: string[];
};
}
/**
* Interface for field optionality analysis result
*/
export interface FieldOptionalityResult {
/** Whether the field should be optional in input schemas */
isOptional: boolean;
/** Whether the field can be null */
isNullable: boolean;
/** Whether the field has a default value */
hasDefaultValue: boolean;
/** Whether the field is auto-generated */
isAutoGenerated: boolean;
/** Reason for optionality decision */
optionalityReason: 'required' | 'schema_optional' | 'has_default' | 'auto_generated' | 'back_relation' | 'nullable_foreign_keys';
/** Zod modifier to apply (e.g., '.optional()', '.default(value)') */
zodModifier: string;
/** Additional notes about optionality decision */
additionalNotes: string[];
}
/**
* Interface for composed field schema
*/
export interface ComposedFieldSchema {
/** Field name */
fieldName: string;
/** Original Prisma field type */
prismaType: string;
/** Generated Zod schema string */
zodSchema: string;
/** Whether this field is a relation (object kind) */
isRelation?: boolean;
/** Field documentation */
documentation?: string;
/** Validation comments and notes */
validations: string[];
/** Required imports for this field */
imports: Set<string>;
/** Whether field is optional */
isOptional: boolean;
/** Whether field is a list/array */
isList: boolean;
/** Whether field has custom validations applied */
hasCustomValidations: boolean;
/** Database constraints for this field */
databaseConstraints: string[];
/** Whether Prisma marks the field with a default value */
hasDefaultValue?: boolean;
/** Whether the field is auto-generated (id with default, updatedAt, now(), etc.) */
isAutoGenerated?: boolean;
/** Custom imports required via @zod.import annotations on this field */
customImports?: CustomImport[];
}
/**
* Interface for model schema composition
*/
export interface ModelSchemaComposition {
/** Model name */
modelName: string;
/** Generated schema name */
schemaName: string;
/** Composed field schemas */
fields: ComposedFieldSchema[];
/** All required imports */
imports: Set<string>;
/** All exports from this schema */
exports: Set<string>;
/** Model-level documentation */
documentation?: string;
/** Model-level validation from @zod.import().refine(...) etc. */
modelLevelValidation?: string | null;
/** Custom imports from @zod.import() annotations */
customImports?: CustomImport[];
/** Generation statistics */
statistics: {
totalFields: number;
processedFields: number;
validatedFields: number;
enhancedFields: number;
relationFields: number;
complexTypeFields: number;
};
/** Generation metadata */
generationMetadata: {
timestamp: string;
generatorVersion: string;
prismaVersion: string;
configHash: string;
};
}
/**
* Interface for generated schema file content
*/
export interface SchemaFileContent {
/** Complete file content */
content: string;
/** Required imports */
imports: Set<string>;
/** Available exports */
exports: Set<string>;
/** Suggested filename */
filename: string;
/** Schema dependencies */
dependencies: string[];
}
/**
* Interface for schema collection data
*/
export interface SchemaData {
/** Model composition */
composition: ModelSchemaComposition;
/** Generated file content */
fileContent: SchemaFileContent;
/** Processing errors for this schema */
processingErrors: string[];
}
/**
* Interface for complete schema collection
*/
export interface SchemaCollection {
/** Map of model name to schema data */
schemas: Map<string, SchemaData>;
/** Generated index file */
indexFile: SchemaFileContent;
/** Schema dependencies map */
dependencies: Map<string, string[]>;
/** Global imports used across all schemas */
globalImports: Set<string>;
/** Generation summary */
generationSummary: {
totalModels: number;
processedModels: number;
totalFields: number;
processedFields: number;
enhancedFields: number;
errorCount: number;
warnings: string[];
};
}
/**
* Interface for model validation report
*/
export interface ModelValidationReport {
/** Model name */
modelName: string;
/** Whether model is valid */
isValid: boolean;
/** Total field count */
fieldCount: number;
/** Successfully processed fields */
processedFields: number;
/** Fields with enhanced validations */
enhancedFields: number;
/** Validation issues */
issues: string[];
/** Warnings */
warnings: string[];
}
/**
* Interface for schema validation report
*/
export interface SchemaValidationReport {
/** Overall validation status */
isValid: boolean;
/** Generation summary */
summary: SchemaCollection['generationSummary'];
/** Per-model validation reports */
modelReports: ModelValidationReport[];
/** Global issues affecting multiple schemas */
globalIssues: string[];
/** Recommendations for improvement */
recommendations: string[];
}
/**
* Interface for JSDoc generation metadata
*/
export interface JSDocMetadata {
/** Primary description from field documentation */
description: string;
/** Field type information */
typeInfo: {
prismaType: string;
zodType: string;
isArray: boolean;
isOptional: boolean;
isNullable: boolean;
};
/** Validation information */
validations: {
appliedValidations: string[];
inlineValidations: string[];
optionalityReason?: string;
};
/** Database-specific information */
databaseInfo: {
constraints: string[];
defaultValue?: string;
isId: boolean;
isUnique: boolean;
isUpdatedAt: boolean;
};
/** Additional metadata */
metadata: {
modelName: string;
fieldName: string;
hasCustomValidations: boolean;
provider?: string;
};
}
/**
* Prisma field type mapper
*/
export declare class PrismaTypeMapper {
private config;
constructor(config?: Partial<TypeMappingConfig>);
/**
* Map a Prisma field to Zod schema
*
* @param field - Prisma DMMF field
* @param model - Parent model for context
* @returns Field type mapping result
*/
mapFieldToZodSchema(field: DMMF.Field, model: DMMF.Model): FieldTypeMappingResult;
/**
* Map scalar types to Zod schemas
*/
private mapScalarType;
/**
* Map Decimal type with enhanced validation based on configuration
*/
private mapDecimalType;
/**
* Map DateTime type with enhanced validation and timezone handling
*/
private mapDateTimeType;
/**
* Map JSON type with enhanced validation and structure checking
*/
private mapJsonType;
/**
* Map Bytes type with enhanced validation for binary data and file handling
*/
private mapBytesType;
/**
* Format file size in human-readable format
*/
private formatFileSize;
/**
* Map enum types
*/
private mapEnumType;
/**
* Map object types (relations)
*/
private mapObjectType;
/**
* Handle unsupported field types
*/
private mapUnsupportedType;
/**
* Apply list wrapper for array fields
*/
private applyListWrapper;
/**
* Apply optional wrapper for optional fields
*/
private applyOptionalWrapper;
/**
* Apply enhanced optionality wrapper with default values and special handling
*/
private applyEnhancedOptionalityWrapper;
/**
* Determine field optionality with sophisticated logic
*
* @param field - Prisma DMMF field
* @param model - Parent model for context
* @returns Optionality information
*/
determineFieldOptionality(field: DMMF.Field, model: DMMF.Model): FieldOptionalityResult;
/**
* Check if a field with default value should be optional
*/
private shouldMakeDefaultFieldOptional;
/**
* Add default value information to optionality result
*/
private addDefaultValueInfo;
/**
* Check if field is auto-generated
*/
private isAutoGeneratedField;
/**
* Handle special optionality rules for specific field types
*/
private handleSpecialFieldOptionalityRules;
/**
* Apply database-specific optionality rules
*/
private applyDatabaseSpecificOptionalityRules;
/**
* PostgreSQL-specific optionality rules
*/
private applyPostgreSQLOptionalityRules;
/**
* MySQL-specific optionality rules
*/
private applyMySQLOptionalityRules;
/**
* SQLite-specific optionality rules
*/
private applySQLiteOptionalityRules;
/**
* MongoDB-specific optionality rules
*/
private applyMongoDBOptionalityRules;
/**
* Apply inline validation from @zod comments
*/
private applyInlineValidations;
/**
* Generate comprehensive JSDoc documentation for a field
*/
private generateJSDocumentation;
/**
* Collect metadata for JSDoc generation
*/
private collectJSDocMetadata;
/**
* Build JSDoc string from metadata
*/
private buildJSDocString;
/**
* Extract clean description from field documentation, removing @zod annotations
*/
private extractCleanDescription;
/**
* Extract base Zod type from schema string
*/
private extractZodBaseType;
/**
* Build type description for JSDoc @type annotation
*/
private buildTypeDescription;
/**
* Build field properties list for JSDoc
*/
private buildFieldProperties;
/**
* Format default value for documentation
*/
private formatDefaultValue;
/**
* Generate example usage for the field
*/
private generateFieldExample;
/**
* Add database-specific validations
*/
private addDatabaseValidations;
/**
* Add PostgreSQL-specific optimizations
*/
private addPostgreSQLOptimizations;
/**
* Add MySQL-specific optimizations
*/
private addMySQLOptimizations;
/**
* Add MongoDB-specific optimizations
*/
private addMongoDBOptimizations;
/**
* Get all available Prisma types for validation
*/
static getSupportedPrismaTypes(): string[];
/**
* Validate type mapping configuration
*/
static validateTypeMapping(config: Partial<TypeMappingConfig>): string[];
/**
* Generate complete Zod schema for a Prisma model
*/
generateModelSchema(model: DMMF.Model): ModelSchemaComposition;
/**
* Generate TypeScript schema file content from model composition
*/
generateSchemaFileContent(composition: ModelSchemaComposition): SchemaFileContent;
/**
* Generate model-level documentation
*/
private generateModelDocumentation;
/**
* Generate imports section
*/
private generateImportsSection;
/**
* Find which enum an import corresponds to by matching against the enum naming configuration
*/
private findEnumForImport;
/**
* Generate schema definition
*/
private generateSchemaDefinition;
/**
* Generate TypeScript type definition
*/
private generateTypeDefinition;
/**
* Extract schema dependencies for import resolution
*/
private extractSchemaDependencies;
/**
* Generate configuration hash for caching
*/
private generateConfigHash;
/**
* Generate complete schema collection for multiple models
*/
generateSchemaCollection(models: DMMF.Model[]): SchemaCollection;
/**
* Generate index file content that exports all schemas
*/
private generateIndexFileContent;
/**
* Validate schema dependencies for circular references and missing schemas
*/
private validateSchemaDependencies;
/**
* Generate schema validation report
*/
generateValidationReport(collection: SchemaCollection): SchemaValidationReport;
/**
* Get type mapping statistics
*/
getTypeMappingStatistics(fields: DMMF.Field[]): {
totalFields: number;
scalarFields: number;
enumFields: number;
relationFields: number;
listFields: number;
optionalFields: number;
typeCounts: Record<string, number>;
};
/**
* Resolve model type name to avoid conflicts with enum types
*/
private resolveModelTypeName;
/**
* Convert a parsed JSON object to a Zod schema string
*/
private convertObjectToZodSchema;
/**
* Convert a parsed JSON array to a Zod schema string
*/
private convertArrayToZodSchema;
/**
* Infer a Zod type from a JavaScript value
*/
private inferZodTypeFromValue;
}