UNPKG

prisma-zod-generator

Version:

Prisma 2+ generator to emit Zod schemas from your Prisma schema

570 lines (569 loc) 17.1 kB
/** * 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; }