UNPKG

prisma-zod-generator

Version:

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

528 lines 19.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultConfigurationManager = void 0; exports.getDefaultConfiguration = getDefaultConfiguration; exports.getMinimalConfiguration = getMinimalConfiguration; exports.mergeWithDefaults = mergeWithDefaults; exports.fillMissingModelConfigs = fillMissingModelConfigs; exports.normalizeConfiguration = normalizeConfiguration; exports.createPreset = createPreset; exports.getAvailablePresets = getAvailablePresets; exports.processConfiguration = processConfiguration; const schema_1 = require("./schema"); /** * Deep merge utility for configuration objects */ function deepMerge(target, source) { const result = { ...target }; for (const key in source) { if (source[key] !== undefined) { if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key]) && typeof target[key] === 'object' && target[key] !== null && !Array.isArray(target[key])) { result[key] = deepMerge(target[key], source[key]); } else { result[key] = source[key]; } } } return result; } /** * Default configuration factory */ class DefaultConfigurationManager { /** * Get complete default configuration */ static getDefaultConfiguration() { return { mode: schema_1.DEFAULT_CONFIG.mode, output: schema_1.DEFAULT_CONFIG.output, useMultipleFiles: true, singleFileName: 'schemas.ts', validateWhereUniqueAtLeastOne: false, strictCreateInputs: true, preserveRequiredScalarsOnCreate: true, inferCreateArgsFromSchemas: false, pureModels: false, // Default to false, can be overridden by user config pureModelsLean: true, pureModelsIncludeRelations: false, pureModelsExcludeCircularRelations: false, dateTimeStrategy: 'date', dateTimeSplitStrategy: true, jsonSchemaCompatible: false, jsonSchemaOptions: { dateTimeFormat: 'isoString', bigIntFormat: 'string', bytesFormat: 'base64String', conversionOptions: { unrepresentable: 'any', cycles: 'throw', reused: 'inline', }, }, optionalFieldBehavior: 'nullish', naming: { preset: 'default', // Intentionally leave pureModel overrides empty so presets can supply their own // values without being clobbered by merged defaults. Resolver will apply // fallback defaults when no preset/overrides are provided. pureModel: {}, }, globalExclusions: { input: [], result: [], pure: [], }, variants: { pure: { enabled: schema_1.DEFAULT_CONFIG.variants.pure.enabled, suffix: schema_1.DEFAULT_CONFIG.variants.pure.suffix, excludeFields: [], }, input: { enabled: schema_1.DEFAULT_CONFIG.variants.input.enabled, suffix: schema_1.DEFAULT_CONFIG.variants.input.suffix, excludeFields: [], }, result: { enabled: schema_1.DEFAULT_CONFIG.variants.result.enabled, suffix: schema_1.DEFAULT_CONFIG.variants.result.suffix, excludeFields: [], }, }, models: {}, }; } /** * Get default configuration for minimal mode */ static getMinimalConfiguration() { const baseConfig = this.getDefaultConfiguration(); return { ...baseConfig, mode: 'minimal', pureModels: true, // Enable pure models by default in minimal mode pureModelsLean: true, pureModelsIncludeRelations: false, naming: { preset: 'default', pureModel: {}, }, variants: { pure: { enabled: true, suffix: '.model', excludeFields: [], }, input: { enabled: true, suffix: '.input', excludeFields: ['id', 'createdAt', 'updatedAt'], }, result: { enabled: false, // Not typically needed in minimal mode suffix: '.result', excludeFields: [], }, }, }; } /** * Get default configuration for custom mode */ static getCustomConfiguration() { const baseConfig = this.getDefaultConfiguration(); return { ...baseConfig, mode: 'custom', }; } /** * Get default variant configuration */ static getDefaultVariantConfig(variantType, modelFields) { const defaults = schema_1.DEFAULT_CONFIG.variants[variantType]; const baseConfig = { enabled: defaults.enabled, suffix: defaults.suffix, excludeFields: [], }; // Apply variant-specific defaults switch (variantType) { case 'input': // Only exclude fields that actually exist in the model const commonInputExclusions = ['id', 'createdAt', 'updatedAt']; const actualExclusions = modelFields ? commonInputExclusions.filter((field) => modelFields.includes(field)) : commonInputExclusions; return { ...baseConfig, excludeFields: actualExclusions, }; case 'result': return { ...baseConfig, excludeFields: [], // Usually include all fields in results }; case 'pure': return { ...baseConfig, excludeFields: [], // Pure models typically include all fields }; default: return baseConfig; } } /** * Get default model configuration */ static getDefaultModelConfig(modelName, mode = 'full', modelFields) { const operations = mode === 'minimal' ? [...schema_1.MINIMAL_OPERATIONS] : [...schema_1.PRISMA_OPERATIONS]; return { enabled: true, operations, variants: { pure: this.getDefaultVariantConfig('pure', modelFields), input: this.getDefaultVariantConfig('input', modelFields), result: this.getDefaultVariantConfig('result', modelFields), }, }; } /** * Merge user configuration with defaults */ static mergeWithDefaults(userConfig) { // Start with appropriate default based on mode let defaultConfig; switch (userConfig.mode) { case 'minimal': defaultConfig = this.getMinimalConfiguration(); break; case 'custom': defaultConfig = this.getCustomConfiguration(); break; case 'full': default: defaultConfig = this.getDefaultConfiguration(); break; } // Deep merge user config with defaults const mergedConfig = deepMerge(defaultConfig, userConfig); // Apply mode-specific adjustments return this.applyModeSpecificDefaults(mergedConfig); } /** * Apply mode-specific default adjustments */ static applyModeSpecificDefaults(config) { var _a; const result = { ...config }; switch (config.mode) { case 'minimal': // Ensure minimal mode has appropriate defaults if (((_a = result.variants) === null || _a === void 0 ? void 0 : _a.result) && result.variants.result.enabled === undefined) { result.variants.result.enabled = false; } // Apply minimal operations to models that don't specify operations if (result.models) { Object.keys(result.models).forEach((modelName) => { var _a; const modelConfig = (_a = result.models) === null || _a === void 0 ? void 0 : _a[modelName]; if (modelConfig && !modelConfig.operations) { modelConfig.operations = [...schema_1.MINIMAL_OPERATIONS]; } }); } break; case 'full': // Ensure all variants are enabled by default in full mode if (result.variants) { Object.keys(result.variants).forEach((variantName) => { var _a; const variant = (_a = result.variants) === null || _a === void 0 ? void 0 : _a[variantName]; if (variant && variant.enabled === undefined) { variant.enabled = true; } }); } break; case 'custom': // Custom mode uses explicit configuration, minimal adjustments break; } return result; } /** * Fill in missing model configurations with defaults */ static fillMissingModelConfigs(config, availableModels, modelFieldInfo) { const result = { ...config }; if (!result.models) { result.models = {}; } // Only add default configuration for explicitly configured models // Don't auto-add models that weren't specified by the user Object.keys(result.models).forEach((modelName) => { const models = result.models; if (models === null || models === void 0 ? void 0 : models[modelName]) { // Fill in missing properties for existing model configs const modelConfig = models[modelName]; const defaultModelConfig = this.getDefaultModelConfig(modelName, result.mode, modelFieldInfo === null || modelFieldInfo === void 0 ? void 0 : modelFieldInfo[modelName]); models[modelName] = deepMerge(defaultModelConfig, modelConfig); } }); return result; } /** * Validate and normalize configuration */ static normalizeConfiguration(config) { const result = { ...config }; // Support legacy/minimal boolean flag by mapping to mode const legacy = result; if (legacy.minimal === true && result.mode !== 'minimal') { result.mode = 'minimal'; } // Normalize mode if (!result.mode || !schema_1.GENERATION_MODES.includes(result.mode)) { result.mode = schema_1.DEFAULT_CONFIG.mode; } // Normalize output path if (!result.output || typeof result.output !== 'string') { result.output = schema_1.DEFAULT_CONFIG.output; } // Normalize global exclusions if (!result.globalExclusions) { result.globalExclusions = {}; } const variantTypes = ['input', 'result', 'pure']; variantTypes.forEach((variantType) => { const globalExclusions = result.globalExclusions; if (globalExclusions && !Array.isArray(globalExclusions[variantType])) { globalExclusions[variantType] = []; } }); // Normalize operations in global exclusions if (result.globalExclusions && !Array.isArray(result.globalExclusions.operations)) { result.globalExclusions.operations = []; } // Normalize variants if (!result.variants) { result.variants = {}; } const variants = ['pure', 'input', 'result']; variants.forEach((variantName) => { const variantsConfig = result.variants; if (variantsConfig && !variantsConfig[variantName]) { variantsConfig[variantName] = this.getDefaultVariantConfig(variantName); } else if (variantsConfig) { const variant = variantsConfig[variantName]; if (variant) { const defaultVariant = this.getDefaultVariantConfig(variantName); variantsConfig[variantName] = deepMerge(defaultVariant, variant); } } }); // Normalize models if (!result.models) { result.models = {}; } // Normalize file options if (typeof result.useMultipleFiles !== 'boolean') { result.useMultipleFiles = true; } if (!result.singleFileName || typeof result.singleFileName !== 'string') { result.singleFileName = 'schemas.ts'; } return result; } /** * Create configuration preset for common use cases */ static createPreset(presetName) { switch (presetName) { case 'minimal': return this.getMinimalConfiguration(); case 'trpc': return { mode: 'custom', output: './generated/zod', globalExclusions: { input: ['id', 'createdAt', 'updatedAt'], result: [], pure: ['password', 'hashedPassword'], }, variants: { pure: { enabled: true, suffix: '.model', excludeFields: [], }, input: { enabled: true, suffix: '.input', excludeFields: [], }, result: { enabled: true, suffix: '.output', excludeFields: [], }, }, models: {}, }; case 'api-validation': return { mode: 'custom', output: './src/schemas', globalExclusions: { input: ['id', 'createdAt', 'updatedAt'], result: [], pure: [], }, variants: { pure: { enabled: false, suffix: '.model', excludeFields: [], }, input: { enabled: true, suffix: '.request', excludeFields: [], }, result: { enabled: true, suffix: '.response', excludeFields: [], }, }, models: {}, }; case 'full-featured': return { mode: 'full', output: './generated/zod-schemas', globalExclusions: {}, variants: { pure: { enabled: true, suffix: '.model', excludeFields: [], }, input: { enabled: true, suffix: '.input', excludeFields: ['id', 'createdAt', 'updatedAt'], }, result: { enabled: true, suffix: '.result', excludeFields: [], }, }, models: {}, }; default: return this.getDefaultConfiguration(); } } /** * Get available configuration presets */ static getAvailablePresets() { return [ { name: 'minimal', description: 'Basic CRUD operations only, minimal file output', useCase: 'Simple applications that only need basic database operations', }, { name: 'trpc', description: 'Optimized for tRPC usage with input/output variants', useCase: 'Full-stack applications using tRPC for type-safe APIs', }, { name: 'api-validation', description: 'Request/response validation for REST APIs', useCase: 'REST API applications needing request/response validation', }, { name: 'full-featured', description: 'Complete schema generation with all features enabled', useCase: 'Complex applications needing comprehensive schema coverage', }, ]; } } exports.DefaultConfigurationManager = DefaultConfigurationManager; /** * Convenience functions */ /** * Get default configuration */ function getDefaultConfiguration() { return DefaultConfigurationManager.getDefaultConfiguration(); } /** * Get minimal configuration */ function getMinimalConfiguration() { return DefaultConfigurationManager.getMinimalConfiguration(); } /** * Merge user config with defaults */ function mergeWithDefaults(userConfig) { return DefaultConfigurationManager.mergeWithDefaults(userConfig); } /** * Fill missing model configurations */ function fillMissingModelConfigs(config, availableModels, modelFieldInfo) { return DefaultConfigurationManager.fillMissingModelConfigs(config, availableModels, modelFieldInfo); } /** * Normalize configuration */ function normalizeConfiguration(config) { return DefaultConfigurationManager.normalizeConfiguration(config); } /** * Create preset configuration */ function createPreset(presetName) { return DefaultConfigurationManager.createPreset(presetName); } /** * Get available presets */ function getAvailablePresets() { return DefaultConfigurationManager.getAvailablePresets(); } /** * Process and finalize configuration * * This is the main function that should be used to process configuration * from parsing through defaults application and normalization. */ function processConfiguration(userConfig, availableModels, modelFieldInfo) { // 1. Merge with defaults let config = mergeWithDefaults(userConfig); // 2. Normalize the configuration config = normalizeConfiguration(config); // 3. Fill in missing model configurations if models are provided if (availableModels && availableModels.length > 0) { config = fillMissingModelConfigs(config, availableModels, modelFieldInfo); } return config; } //# sourceMappingURL=defaults.js.map