UNPKG

prisma-zod-generator

Version:

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

442 lines 17.3 kB
"use strict"; /** * Variant-Specific Configuration Handler * Manages per-variant configuration including field exclusions and validation rules */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigurationUtils = exports.VariantConfigurationManager = exports.ConfigInheritanceLevel = void 0; const variants_1 = require("../types/variants"); /** * Configuration inheritance hierarchy */ var ConfigInheritanceLevel; (function (ConfigInheritanceLevel) { ConfigInheritanceLevel["DEFAULT"] = "default"; ConfigInheritanceLevel["GLOBAL"] = "global"; ConfigInheritanceLevel["VARIANT"] = "variant"; ConfigInheritanceLevel["MODEL"] = "model"; })(ConfigInheritanceLevel || (exports.ConfigInheritanceLevel = ConfigInheritanceLevel = {})); /** * Variant Configuration Manager * Handles configuration inheritance, validation, and caching */ class VariantConfigurationManager { constructor(globalConfig) { this.configCache = new Map(); this.cacheTimeout = 5 * 60 * 1000; // 5 minutes this.globalConfig = this.buildDefaultGlobalConfig(); if (globalConfig) { this.globalConfig = this.mergeConfigs(this.globalConfig, globalConfig); } } /** * Get configuration for a specific model and variant */ getVariantConfig(modelName, variantType, overrides) { const cacheKey = this.generateCacheKey(modelName, variantType, overrides); // Check cache first const cached = this.getCachedConfig(cacheKey); if (cached) { return cached.config; } // Build configuration hierarchy const config = this.buildConfigurationHierarchy(modelName, variantType, overrides); // Cache the result this.cacheConfig(cacheKey, config, this.getInheritanceChain(modelName, variantType)); return config; } /** * Build configuration hierarchy from defaults to model-specific overrides */ buildConfigurationHierarchy(modelName, variantType, overrides) { // Start with defaults let config = this.getDefaultVariantConfig(variantType); // Apply global variant defaults const globalDefaults = this.globalConfig.variantDefaults[variantType]; if (globalDefaults) { config = this.mergeConfigs(config, globalDefaults); } // Apply model-specific overrides const modelOverrides = this.globalConfig.modelOverrides[modelName]; if (modelOverrides && modelOverrides[variantType]) { config = this.mergeConfigs(config, modelOverrides[variantType]); } // Apply explicit overrides if (overrides) { config = this.mergeConfigs(config, overrides); } return config; } /** * Get default configuration for a variant type */ getDefaultVariantConfig(variantType) { return { type: variantType, enabled: true, naming: variants_1.DEFAULT_NAMING_CONFIGS[variantType], fieldExclusions: variants_1.DEFAULT_FIELD_EXCLUSIONS[variantType], validationCustomizations: variants_1.DEFAULT_VALIDATION_CUSTOMIZATIONS[variantType], schemaOptions: variants_1.DEFAULT_SCHEMA_OPTIONS[variantType], priority: this.getDefaultPriority(variantType), }; } /** * Merge configurations with proper deep merging */ mergeConfigs(base, override) { const result = { ...base }; for (const key in override) { if (override.hasOwnProperty(key)) { const overrideValue = override[key]; const baseValue = result[key]; if (overrideValue !== undefined) { if (this.isPlainObject(overrideValue) && this.isPlainObject(baseValue)) { // Deep merge objects result[key] = this.mergeConfigs(baseValue, overrideValue); } else if (Array.isArray(overrideValue) && Array.isArray(baseValue)) { // Merge arrays (override replaces by default, but could be configured) result[key] = [...baseValue, ...overrideValue]; } else { // Replace primitive values result[key] = overrideValue; } } } } return result; } /** * Validate merged configuration */ validateMergedConfig(config) { const errors = []; const warnings = []; // Validate basic configuration if (!Object.values(variants_1.VariantType).includes(config.type)) { errors.push(`Invalid variant type: ${config.type}`); } // Validate naming configuration if (!config.naming.suffix || !config.naming.suffix.endsWith('.ts')) { errors.push('Naming suffix must end with .ts'); } if (!config.naming.schemaNameSuffix) { errors.push('Schema name suffix is required'); } // Validate field exclusions if (config.fieldExclusions.excludeFields) { const invalidFields = config.fieldExclusions.excludeFields.filter((field) => typeof field !== 'string' || field.trim() === ''); if (invalidFields.length > 0) { errors.push(`Invalid field exclusion names: ${invalidFields.join(', ')}`); } } // Validate validation customizations if (config.validationCustomizations.fieldValidations) { for (const [field, validation] of Object.entries(config.validationCustomizations.fieldValidations)) { if (typeof validation !== 'string' || validation.trim() === '') { errors.push(`Invalid validation for field '${field}': must be non-empty string`); } } } // Check for conflicting configurations if (config.fieldExclusions.excludeRelations && config.schemaOptions.generateTypes && config.type === variants_1.VariantType.RESULT) { warnings.push('Excluding relations in result schemas may cause type issues'); } // Validate priority if (config.priority < 0 || config.priority > 100) { errors.push('Priority must be between 0 and 100'); } return { isValid: errors.length === 0, errors, warnings, level: ConfigInheritanceLevel.VARIANT, appliedConfig: config, }; } /** * Update global configuration */ updateGlobalConfig(updates) { this.globalConfig = this.mergeConfigs(this.globalConfig, updates); this.clearCache(); // Clear cache when global config changes } /** * Add model-specific override */ addModelOverride(modelName, variantType, override) { if (!this.globalConfig.modelOverrides[modelName]) { this.globalConfig.modelOverrides[modelName] = {}; } const existing = this.globalConfig.modelOverrides[modelName][variantType] || {}; this.globalConfig.modelOverrides[modelName][variantType] = this.mergeConfigs(existing, override); // Clear affected cache entries this.clearModelCache(modelName, variantType); } /** * Remove model-specific override */ removeModelOverride(modelName, variantType) { if (variantType) { if (this.globalConfig.modelOverrides[modelName]) { delete this.globalConfig.modelOverrides[modelName][variantType]; this.clearModelCache(modelName, variantType); } } else { delete this.globalConfig.modelOverrides[modelName]; this.clearModelCache(modelName); } } /** * Get effective field exclusions for a model variant */ getEffectiveFieldExclusions(modelName, variantType, fieldNames) { const config = this.getVariantConfig(modelName, variantType); const exclusions = config.fieldExclusions; const excludedFields = []; const exclusionReasons = {}; fieldNames.forEach((fieldName) => { var _a; const reasons = []; // Check direct field exclusions if ((_a = exclusions.excludeFields) === null || _a === void 0 ? void 0 : _a.includes(fieldName)) { reasons.push('explicitly excluded'); } // Check auto-generated exclusions if (exclusions.excludeAutoGenerated && this.isAutoGeneratedField(fieldName)) { reasons.push('auto-generated field'); } // Additional exclusion logic could be added here if (reasons.length > 0) { excludedFields.push(fieldName); exclusionReasons[fieldName] = reasons; } }); return { excludedFields, includedFields: fieldNames.filter((name) => !excludedFields.includes(name)), exclusionReasons, }; } /** * Get effective validation customizations */ getEffectiveValidationCustomizations(modelName, variantType, fieldName) { var _a, _b, _c; const config = this.getVariantConfig(modelName, variantType); const customizations = config.validationCustomizations; const validations = []; // Add field-specific validations if ((_a = customizations.fieldValidations) === null || _a === void 0 ? void 0 : _a[fieldName]) { validations.push(customizations.fieldValidations[fieldName]); } // Add additional validations if ((_b = customizations.additionalValidations) === null || _b === void 0 ? void 0 : _b[fieldName]) { validations.push(...customizations.additionalValidations[fieldName]); } return { validations, isInlineDisabled: customizations.disableInlineValidations || false, customTemplate: (_c = customizations.validationTemplates) === null || _c === void 0 ? void 0 : _c[fieldName], }; } /** * Export configuration as JSON */ exportConfiguration() { return JSON.stringify(this.globalConfig, null, 2); } /** * Import configuration from JSON */ importConfiguration(configJson) { try { const imported = JSON.parse(configJson); this.globalConfig = this.mergeConfigs(this.buildDefaultGlobalConfig(), imported); this.clearCache(); } catch (error) { throw new Error(`Failed to import configuration: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Private helper methods */ buildDefaultGlobalConfig() { return { outputDirectory: './generated/schemas', enableVariants: true, variantDefaults: { [variants_1.VariantType.PURE]: {}, [variants_1.VariantType.INPUT]: {}, [variants_1.VariantType.RESULT]: {}, }, modelOverrides: {}, globalNaming: { useModelPrefix: true, usePascalCase: true, }, }; } getDefaultPriority(variantType) { switch (variantType) { case variants_1.VariantType.PURE: return 10; case variants_1.VariantType.INPUT: return 20; case variants_1.VariantType.RESULT: return 30; default: return 50; } } generateCacheKey(modelName, variantType, overrides) { const overrideHash = overrides ? this.hashObject(overrides) : ''; return `${modelName}:${variantType}:${overrideHash}`; } getCachedConfig(cacheKey) { const entry = this.configCache.get(cacheKey); if (entry && Date.now() - entry.timestamp < this.cacheTimeout) { return entry; } return null; } cacheConfig(cacheKey, config, inheritanceChain) { this.configCache.set(cacheKey, { config, hash: this.hashObject(config), timestamp: Date.now(), inheritanceChain, }); } clearCache() { this.configCache.clear(); } clearModelCache(modelName, variantType) { const keysToDelete = Array.from(this.configCache.keys()).filter((key) => { const parts = key.split(':'); return parts[0] === modelName && (!variantType || parts[1] === variantType); }); keysToDelete.forEach((key) => this.configCache.delete(key)); } getInheritanceChain(modelName, variantType) { var _a; const chain = [ConfigInheritanceLevel.DEFAULT]; if (this.globalConfig.variantDefaults[variantType]) { chain.push(ConfigInheritanceLevel.GLOBAL); } chain.push(ConfigInheritanceLevel.VARIANT); if ((_a = this.globalConfig.modelOverrides[modelName]) === null || _a === void 0 ? void 0 : _a[variantType]) { chain.push(ConfigInheritanceLevel.MODEL); } return chain; } isPlainObject(value) { return (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp)); } isAutoGeneratedField(fieldName) { const autoGeneratedFields = ['id', 'createdAt', 'updatedAt', 'deletedAt']; return autoGeneratedFields.includes(fieldName); } hashObject(obj) { return JSON.stringify(obj, Object.keys(obj).sort()); } } exports.VariantConfigurationManager = VariantConfigurationManager; /** * Configuration utility functions */ class ConfigurationUtils { /** * Compare two configurations for differences */ static compareConfigs(config1, config2) { const differences = []; this.deepCompare(config1, config2, '', differences); return { areSame: differences.length === 0, differences, }; } /** * Get configuration summary */ static getConfigSummary(config) { var _a, _b; return { type: config.type, excludedFieldsCount: (((_a = config.fieldExclusions.excludeFields) === null || _a === void 0 ? void 0 : _a.length) || 0) + (((_b = config.fieldExclusions.excludeFieldTypes) === null || _b === void 0 ? void 0 : _b.length) || 0), customValidationsCount: Object.keys(config.validationCustomizations.fieldValidations || {}).length + Object.keys(config.validationCustomizations.additionalValidations || {}).length, hasDocumentation: config.schemaOptions.includeDocumentation || false, priority: config.priority, }; } /** * Validate configuration compatibility */ static validateCompatibility(configs) { const conflicts = []; for (let i = 0; i < configs.length; i++) { for (let j = i + 1; j < configs.length; j++) { const config1 = configs[i]; const config2 = configs[j]; // Check for priority conflicts if (config1.priority === config2.priority) { conflicts.push({ config1: config1.type, config2: config2.type, issue: `Same priority (${config1.priority})`, }); } // Check for naming conflicts if (config1.naming.schemaNameSuffix === config2.naming.schemaNameSuffix) { conflicts.push({ config1: config1.type, config2: config2.type, issue: `Same schema name suffix: ${config1.naming.schemaNameSuffix}`, }); } } } return { isCompatible: conflicts.length === 0, conflicts, }; } static deepCompare(obj1, obj2, path, differences) { if (obj1 === obj2) return; if (typeof obj1 !== typeof obj2) { differences.push({ path, value1: obj1, value2: obj2 }); return; } if (obj1 === null || obj2 === null) { differences.push({ path, value1: obj1, value2: obj2 }); return; } if (typeof obj1 === 'object') { const keys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]); for (const key of keys) { const newPath = path ? `${path}.${key}` : key; this.deepCompare(obj1 === null || obj1 === void 0 ? void 0 : obj1[key], obj2 === null || obj2 === void 0 ? void 0 : obj2[key], newPath, differences); } } else if (obj1 !== obj2) { differences.push({ path, value1: obj1, value2: obj2 }); } } } exports.ConfigurationUtils = ConfigurationUtils; exports.default = VariantConfigurationManager; //# sourceMappingURL=config.js.map