prisma-zod-generator
Version:
Prisma 2+ generator to emit Zod schemas from your Prisma schema
476 lines (475 loc) • 19.9 kB
TypeScript
import type { ConnectorType, DMMF as PrismaDMMF } from '@prisma/generator-helper';
import type { GeneratorConfig as ZodGeneratorConfig } from './config/parser';
import { type EnhancedModelInfo } from './helpers/zod-integration';
import type { CustomImport } from './parsers/zod-comments';
import { SchemaEnumWithValues, TransformerParams } from './types';
import type { GeneratedManifest } from './utils/safeOutputManagement';
import { type StrictModeResolver } from './utils/strict-mode-resolver';
/**
* Filter validation result interface
*/
interface FilterValidationResult {
isValid: boolean;
errors: string[];
warnings: string[];
suggestions: string[];
}
export default class Transformer {
name: string;
fields: PrismaDMMF.SchemaArg[];
schemaImports: Set<string>;
models: PrismaDMMF.Model[];
modelOperations: PrismaDMMF.ModelMapping[];
enumTypes: SchemaEnumWithValues[];
enhancedModels: EnhancedModelInfo[];
static enumNames: string[];
static rawOpsMap: {
[name: string]: string;
};
static provider: ConnectorType;
static previewFeatures: string[] | undefined;
private static outputPath;
private hasJson;
private hasDecimal;
private static prismaClientOutputPath;
private static isCustomPrismaClientOutputPath;
private static prismaClientProvider;
private static prismaClientConfig;
private static isGenerateSelect;
private static isGenerateInclude;
private static generatorConfig;
private static strictModeResolver;
private static usedSchemaFilePaths;
private static isJsonSchemaModeEnabled;
private static getJsonSchemaOptions;
private static exportTypedSchemas;
private static exportZodSchemas;
private static typedSchemaSuffix;
private static zodSchemaSuffix;
private lastExcludedFieldNames;
private static jsonHelpersWritten;
private static decimalHelpersWritten;
private static currentManifest;
constructor(params: TransformerParams);
static setOutputPath(outPath: string): void;
static setIsGenerateSelect(isGenerateSelect: boolean): void;
static setIsGenerateInclude(isGenerateInclude: boolean): void;
static setGeneratorConfig(config: ZodGeneratorConfig): void;
static getGeneratorConfig(): ZodGeneratorConfig | null;
static getStrictModeResolver(): StrictModeResolver | null;
private static escapeRegExp;
/**
* Check if a model should be generated based on configuration
*/
static isModelEnabled(modelName: string): boolean;
/**
* Get list of enabled models for generation
*/
static getEnabledModels(allModels: PrismaDMMF.Model[]): PrismaDMMF.Model[];
/**
* Log information about model filtering
*/
static logModelFiltering(allModels: PrismaDMMF.Model[]): void;
/**
* Check if a specific operation should be generated for a model
*/
static isOperationEnabled(modelName: string, operationName: string): boolean;
/**
* Get list of enabled operations for a model
*/
static getEnabledOperations(modelName: string, allOperations: string[]): string[];
/**
* Log information about operation filtering for a model
*/
static logOperationFiltering(modelName: string, allOperations: string[]): void;
/**
* Check if a field should be included in schema generation
*/
static isFieldEnabled(fieldName: string, modelName?: string, variant?: 'pure' | 'input' | 'result'): boolean;
/**
* Check if a field name matches any pattern in the exclusion list
* Supports wildcards: *field, field*, *field*
*/
static isFieldMatchingPatterns(fieldName: string, patterns: string[]): boolean;
/**
* Filter fields based on configuration and relationship preservation
*/
static filterFields(fields: PrismaDMMF.SchemaArg[], modelName?: string, variant?: 'pure' | 'input' | 'result', models?: PrismaDMMF.Model[], schemaName?: string): PrismaDMMF.SchemaArg[];
/**
* Get excluded relation fields by comparing original and filtered fields
*/
static getExcludedRelationFields(originalFields: PrismaDMMF.SchemaArg[], filteredFields: PrismaDMMF.SchemaArg[], model: PrismaDMMF.Model): PrismaDMMF.Field[];
/**
* Get foreign key schema args for excluded relation fields
*/
static getForeignKeyFieldsForExcludedRelations(excludedRelationFields: PrismaDMMF.Field[], model: PrismaDMMF.Model): PrismaDMMF.SchemaArg[];
/**
* Check if a schema arg represents a relation field
*/
static isRelationFieldArg(field: PrismaDMMF.SchemaArg): boolean;
/**
* Extract related model name from field arg
*/
static extractRelatedModelFromFieldArg(field: PrismaDMMF.SchemaArg): string | null;
/**
* Extract model name from object schema context
*/
static extractModelNameFromContext(schemaName: string): string | null;
/**
* Determine schema variant from context
*/
static determineSchemaVariant(schemaName: string): 'pure' | 'input' | 'result';
/**
* Log information about field filtering
*/
static logFieldFiltering(originalCount: number, filteredCount: number, modelName?: string, variant?: string): void;
/**
* Check if a model has relationships to other ENABLED models
* This is a filtered version of checkModelHasModelRelation that only considers enabled models
*/
static checkModelHasEnabledModelRelation(model: PrismaDMMF.Model): boolean;
/**
* Check if a relation field points to an enabled model
*/
static isEnabledRelationField(modelField: PrismaDMMF.Field): boolean;
/**
* Filter relation fields to only include those pointing to enabled models
*/
static filterRelationFields(fields: PrismaDMMF.Field[]): PrismaDMMF.Field[];
/**
* Get list of enabled related models for a given model
*/
static getEnabledRelatedModels(model: PrismaDMMF.Model): string[];
/**
* Check if a model should have include schemas generated
* Only if it has relationships to other enabled models
*/
static shouldGenerateIncludeSchema(model: PrismaDMMF.Model): boolean;
/**
* Check if a model should have select schemas generated
*/
static shouldGenerateSelectSchema(_model: PrismaDMMF.Model): boolean;
/**
* Log relationship preservation information
*/
static logRelationshipPreservation(model: PrismaDMMF.Model): void;
static setExportTypedSchemas(exportTypedSchemas: boolean): void;
static setExportZodSchemas(exportZodSchemas: boolean): void;
static setTypedSchemaSuffix(typedSchemaSuffix: string): void;
static setZodSchemaSuffix(zodSchemaSuffix: string): void;
/**
* Generate the correct object schema name based on export settings
*/
static getObjectSchemaName(baseName: string): string;
static getOutputPath(): string;
static setCurrentManifest(manifest: GeneratedManifest | null): void;
static getCurrentManifest(): GeneratedManifest | null;
static setPrismaClientOutputPath(prismaClientCustomPath: string): void;
/**
* Resolve the import specifier for Prisma Client relative to a target directory.
* Falls back to '@prisma/client' when user did not configure a custom output.
*/
static resolvePrismaImportPath(targetDir: string): string;
static setPrismaClientProvider(provider: string): void;
static setPrismaClientConfig(config: Record<string, unknown>): void;
static getPrismaClientProvider(): string;
static getPrismaClientConfig(): Record<string, unknown>;
/**
* Determines the schemas directory path based on the output path.
* If the output path already ends with 'schemas', use it directly.
* Otherwise, append 'schemas' to the output path.
*/
static getSchemasPath(): string;
static generateIndex(): Promise<void>;
generateEnumSchemas(): Promise<void>;
/**
* Check if an enum schema should be generated based on enabled models
*/
private isEnumSchemaEnabled;
/**
* Shared regex patterns for model-specific enum detection
*/
private static readonly modelEnumPatterns;
/**
* Extract model name from enum name
*/
private extractModelNameFromEnum;
/**
* Normalize enum names to match import expectations
* For model-related enums, use Pascal case model names consistently
*/
private normalizeEnumName;
/**
* Convert model names to DMMF aggregate input names
* For doc_parser_agent model: matches Prisma's DMMF format Doc_parser_agentCountAggregateInput
*/
private getAggregateInputName;
/**
* Get the correct Prisma type name for model types
* Prisma uses the original model name as-is (e.g., doc_parser_agent -> Prisma.doc_parser_agentSelect)
*/
private getPrismaTypeName;
/**
* Check if a model has numeric fields that support avg/sum operations
*/
private modelHasNumericFields;
generateImportZodStatement(): "import * as z from 'zod';\n" | "import * as z from 'zod/v4';\n" | "import { z } from 'zod/v3';\n";
/**
* Generate custom import statements from @zod.import() annotations
*
* @param customImports - Array of custom import objects
* @param outputPath - Current output path for relative import adjustment
* @returns Generated import statements string
*/
generateCustomImportStatements(customImports: CustomImport[] | undefined, outputPath?: string): string;
/**
* Get custom imports for a specific schema context
* This method is called AFTER the schema content is generated to determine which imports are actually needed
*
* @param modelName - Name of the model
* @param schemaContent - The generated schema content to analyze for import usage
* @returns Array of custom imports needed for this specific schema
*/
getCustomImportsForModel(modelName: string | null, schemaContent?: string): CustomImport[];
/**
* Check if a field actually contains custom validation logic
*/
private fieldContainsCustomValidation;
/**
* Get custom schema for a specific field
*
* @param fieldName - Name of the field
* @returns Custom schema string or null if not found
*/
getCustomSchemaForField(fieldName: string): string | null;
/**
* Adjust relative import paths based on output directory structure
*
* @param importStatement - Original import statement
* @param outputPath - Current output path
* @returns Adjusted import statement
*/
private adjustRelativeImportPath;
generateExportSchemaStatement(name: string, schema: string): string;
generateObjectSchema(): Promise<void>;
generateObjectSchemaFields(): string[];
generateObjectSchemaField(field: PrismaDMMF.SchemaArg): [string, PrismaDMMF.SchemaArg, boolean][];
wrapWithZodValidators(mainValidator: string, field: PrismaDMMF.SchemaArg, inputType: PrismaDMMF.SchemaArg['inputTypes'][0], skipZodAnnotations?: boolean): string;
addSchemaImport(name: string): void;
/**
* Check if a schema import should be included based on minimal mode configuration
*/
private isSchemaImportEnabled;
/**
* Extract model name from schema name for import filtering
*/
private extractModelNameFromSchema;
/**
* Extract max length constraint from native type (e.g., @db.VarChar(255) -> 255)
*/
private extractMaxLengthFromNativeType;
/**
* Extract existing max constraint from @zod validations
*/
private extractExistingMaxConstraint;
/**
* Replace all max constraints in a validation string with a single constraint
*/
private replaceAllMaxConstraints;
/**
* Extract @zod validations for a specific field using the enhanced model information
*/
private extractZodValidationsForField;
generatePrismaStringLine(field: PrismaDMMF.SchemaArg, inputType: PrismaDMMF.SchemaArg['inputTypes'][0], inputsLength: number): string;
generateFieldValidators(zodStringWithMainType: string, field: PrismaDMMF.SchemaArg): string;
prepareObjectSchema(zodObjectSchemaFields: string[]): string;
generateExportObjectSchemaStatement(schema: string): string;
/**
* Emit a manual TS type and a `satisfies z.ZodType<...>` check for Zod-only, self-recursive schemas.
* This avoids TS7022 and keeps output variable types unchanged.
*/
private generateZodOnlySanityCheck;
/**
* Resolve the appropriate Prisma type identifier for an object schema export.
* In Prisma 6, certain aggregate input types are exported with a `Type` suffix.
* Example: Prisma.PlanetCountAggregateInputType instead of Prisma.PlanetCountAggregateInput
*/
private resolvePrismaTypeForObject;
addFinalWrappers({ zodStringFields }: {
zodStringFields: string[];
}): string;
generateJsonSchemaImplementation(): string;
private static ensureJsonHelpersFile;
private static ensureDecimalHelpersFile;
generateObjectSchemaImportStatements(customImports?: CustomImport[]): string;
/**
* Get the file extension to use for imports based on Prisma client configuration
* For ESM with importFileExtension = "js", we need to add .js extension
*/
private getImportFileExtension;
/**
* Convert model name to PascalCase for consistent file naming
*/
private getPascalCaseModelName;
/**
* Resolve an input object import honoring naming.input patterns, aliasing to stable identifiers.
*/
private generateInputImport;
/**
* Generate enum import honoring naming.enum patterns, aliasing to stable identifiers.
*/
private generateEnumImport;
/**
* Generate input import for object schemas honoring naming.input patterns.
* Similar to generateInputImport but for object-to-object imports using './' prefix.
*/
private generateObjectInputImport;
/**
* Generate schema file name with collision detection and custom naming support
*/
private static generateSchemaFileName;
/**
* Check for and handle file path collisions
*/
private static checkSchemaFileCollision;
/**
* Generate schema file with collision detection and consistent naming
*/
private static writeSchemaFile;
/**
* Clear collision detection state (called at start of generation)
*/
static clearSchemaFileCollisions(): void;
/**
* Generate import statement with validation - only if target will be generated
*/
static generateValidatedImportStatement(importName: string, importPath: string, modelName?: string): string;
/**
* Check if an import should be generated based on filtering rules
*/
static shouldGenerateImport(importName: string, relatedModelName?: string): boolean;
/**
* Extract model name from import name
*/
static extractModelFromImportName(importName: string): string | null;
/**
* Get import file extension (static version)
*/
static getImportFileExtension(): string;
generateSchemaImports(): string;
checkIsModelQueryType(type: string): {
isModelQueryType: boolean;
modelName: string;
queryName: string;
} | {
isModelQueryType: boolean;
modelName?: undefined;
queryName?: undefined;
};
resolveModelQuerySchemaName(modelName: string, queryName: string): string;
wrapWithZodObject(zodStringFields: string | string[]): string;
resolveObjectSchemaName(): string;
generateModelSchemas(): Promise<void>;
/**
* Generate result schemas for all enabled models
*/
generateResultSchemas(): Promise<void>;
generateImportStatements(imports: (string | undefined)[]): string;
/**
* Clean and validate import array, removing empty and invalid imports
*/
static cleanAndValidateImports(imports: (string | undefined)[]): string[];
/**
* Parse import statement to extract information
*/
static parseImportStatement(importStatement: string): {
importName: string;
importPath: string;
relatedModel?: string;
} | null;
/**
* Generate smart import statement that checks if target exists
*/
generateSmartImportStatement(importName: string, importPath: string, relatedModel?: string): string;
/**
* Log import management information
*/
static logImportManagement(originalImports: (string | undefined)[], cleanedImports: string[], context?: string): void;
/**
* Validate filter combinations and detect conflicts
*/
static validateFilterCombinations(allModels: PrismaDMMF.Model[]): FilterValidationResult;
/**
* Validate model dependencies and relationships
*/
static validateModelDependencies(allModels: PrismaDMMF.Model[], result: FilterValidationResult): void;
/**
* Validate operation consistency across models
*/
static validateOperationConsistency(allModels: PrismaDMMF.Model[], result: FilterValidationResult): void;
/**
* Validate field exclusion conflicts
*/
static validateFieldExclusions(allModels: PrismaDMMF.Model[], result: FilterValidationResult): void;
/**
* Validate variant consistency
*/
static validateVariantConsistency(result: FilterValidationResult): void;
/**
* Validate mode consistency
*/
static validateModeConsistency(result: FilterValidationResult): void;
/**
* Log filter validation results
*/
static logFilterValidation(validationResult: FilterValidationResult): void;
/**
* Perform comprehensive filter validation
*/
static performFilterValidation(allModels: PrismaDMMF.Model[]): boolean;
resolveSelectIncludeImportAndZodSchemaLine(model: PrismaDMMF.Model): {
selectImport: string;
includeImport: string;
selectZodSchemaLine: string;
includeZodSchemaLine: string;
selectZodSchemaLineLazy: string;
includeZodSchemaLineLazy: string;
selectValueExpr: string;
includeValueExpr: string;
};
private resolveIncludeFieldReference;
resolveOrderByWithRelationImportAndZodSchemaLine(model: PrismaDMMF.Model): {
orderByImport: string;
orderByZodSchemaLine: string;
};
/**
* Determines if a select schema should be inlined to avoid circular dependencies.
* Following community generator approach: ALWAYS inline select schemas.
* Use lazy loading only for specific relation fields within the inlined schema.
*/
shouldInlineSelectSchema(_model: PrismaDMMF.Model): boolean;
/**
* Generates inline select schema definition code within the FindMany file.
* This prevents circular imports by defining the schema locally.
* Follows community generator pattern with aggressive inlining.
*/
generateInlineSelectSchema(model: PrismaDMMF.Model): string;
/**
* Generates the additional imports needed for inlined select schemas.
* Returns import statements for Args schemas referenced in relation fields.
*/
generateInlineSelectImports(_model: PrismaDMMF.Model): string[];
/**
* Generates dual schema exports: typed version and Zod-method-friendly version
*/
generateDualSchemaExports(modelName: string, operationType: string, schemaDefinition: string, prismaType: string): string;
/**
* Generates dual select schema exports for inlined schemas
*/
generateDualSelectSchemaExports(model: PrismaDMMF.Model, operation?: 'FindFirst' | 'FindFirstOrThrow' | 'FindMany' | 'FindUnique' | 'FindUniqueOrThrow'): string;
/**
* Generates just the schema definition without export statement
*/
generateInlineSelectSchemaDefinition(model: PrismaDMMF.Model): string;
}
export {};