UNPKG

prisma-zod-generator

Version:

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

115 lines (112 loc) 4.96 kB
"use strict"; /** * Helper functions and utilities for Decimal type support * Matches zod-prisma-types implementation for seamless migration */ Object.defineProperty(exports, "__esModule", { value: true }); exports.generateDecimalHelpers = generateDecimalHelpers; exports.generateDecimalInputSchema = generateDecimalInputSchema; exports.generateDecimalModelSchema = generateDecimalModelSchema; exports.isDecimalJsAvailable = isDecimalJsAvailable; /** * Generate helper schemas for Decimal validation * These helpers enable proper Prisma.Decimal and Decimal.js support * * @param hasDecimalJs - Whether decimal.js is installed and should be imported * @param zodNamespace - The zod namespace to use (e.g., 'z' or 'zod') * @returns Object containing helper schema code and necessary imports */ function generateDecimalHelpers(hasDecimalJs, zodNamespace = 'z', prismaImportPath = '@prisma/client') { const imports = [`import { Prisma } from '${prismaImportPath}';`]; if (hasDecimalJs) { imports.push("import Decimal from 'decimal.js';"); } const helperCode = ` // DECIMAL HELPERS //------------------------------------------------------ export const DecimalJSLikeSchema: ${zodNamespace}.ZodType<Prisma.DecimalJsLike> = ${zodNamespace}.object({ d: ${zodNamespace}.array(${zodNamespace}.number()), e: ${zodNamespace}.number(), s: ${zodNamespace}.number(), // Zod v3/v4 compatible callable check toFixed: ${zodNamespace}.custom<Prisma.DecimalJsLike['toFixed']>((v) => typeof v === 'function'), }); // Accept canonical decimal strings (+/-, optional fraction, optional exponent), or Infinity/NaN. export const DECIMAL_STRING_REGEX = /^(?:[+-]?(?:[0-9]+(?:\.[0-9]+)?(?:[eE][+\-]?[0-9]+)?|Infinity)|NaN)$/; export const isValidDecimalInput = ( v?: null | string | number | Prisma.DecimalJsLike, ): v is string | number | Prisma.DecimalJsLike => { if (v === undefined || v === null) return false; return ( // Explicit instance checks first. Decimal.isDecimal is used instead of instanceof because // the browser and server Prisma runtimes bundle separate Decimal class copies, so // instanceof fails across copies while the structural isDecimal check is cross-copy safe. Prisma.Decimal.isDecimal(v) || // If Decimal.js is present and imported by the generator, this symbol exists at runtime // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - Decimal may be undefined when not installed; codegen controls the import (typeof Decimal !== 'undefined' && v instanceof Decimal) || (typeof v === 'object' && 'd' in v && 'e' in v && 's' in v && 'toFixed' in v) || (typeof v === 'string' && DECIMAL_STRING_REGEX.test(v)) || typeof v === 'number' ); }; `.trim(); return { helperCode, imports }; } /** * Generate Decimal field schema for input types (Create, Update, etc.) * Uses union of multiple formats with refinement validation * * @param zodNamespace - The zod namespace to use (e.g., 'z' or 'zod') * @param hasDecimalJs - Whether decimal.js is installed * @param fieldName - Name of the field (for error messages) * @returns Zod schema string */ function generateDecimalInputSchema(zodNamespace, hasDecimalJs, fieldName) { const unionTypes = [`${zodNamespace}.number()`, `${zodNamespace}.string()`]; if (hasDecimalJs) { unionTypes.push(`${zodNamespace}.instanceof(Decimal)`); } // Structural cross-runtime-copy safe branch: keeps foreign-copy Decimal instances intact // (instanceof would miss them and DecimalJSLikeSchema would strip them to plain objects). unionTypes.push(`${zodNamespace}.custom<InstanceType<typeof Prisma.Decimal>>((v) => Prisma.Decimal.isDecimal(v))`, 'DecimalJSLikeSchema'); const errorMessage = fieldName ? `Field '${fieldName}' must be a Decimal` : 'Must be a Decimal'; return `${zodNamespace}.union([ ${unionTypes.join(',\n ')}, ]).refine((v) => isValidDecimalInput(v), { message: "${errorMessage}", })`; } /** * Generate Decimal field schema for pure models (output/result types) * Uses the cross-runtime-copy safe Prisma.Decimal.isDecimal check * * @param zodNamespace - The zod namespace to use (e.g., 'z' or 'zod') * @param fieldName - Name of the field * @param modelName - Name of the model (for error messages) * @returns Zod schema string */ function generateDecimalModelSchema(zodNamespace, fieldName, modelName) { return `${zodNamespace}.custom<InstanceType<typeof Prisma.Decimal>>((v) => Prisma.Decimal.isDecimal(v), { message: "Field '${fieldName}' must be a Decimal. Location: ['Models', '${modelName}']", })`; } /** * Check if decimal.js is installed in the project * @returns true if decimal.js is available */ function isDecimalJsAvailable() { try { require.resolve('decimal.js'); return true; } catch { return false; } } //# sourceMappingURL=decimal-helpers.js.map