UNPKG

credl-parser-evaluator

Version:

TypeScript-based CREDL Parser and Evaluator that processes CREDL files and outputs complete Intermediate Representations

265 lines 9.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PresetResolver = void 0; /** * PresetResolver handles parsing and storage of preset definitions */ class PresetResolver { constructor() { this.presets = new Map(); } /** * Parse and store preset definitions from a CREDL file */ parsePresets(credlFile, errors, warnings) { if (credlFile.presets === undefined) { return; // No presets to process } // Validate presets structure if (typeof credlFile.presets !== 'object' || credlFile.presets === null) { errors.push({ field: 'presets', message: 'must be an object', severity: 'error' }); return; } // Process each preset category (lease_profiles, expense_profiles, etc.) Object.keys(credlFile.presets).forEach(category => { const categoryData = credlFile.presets[category]; if (categoryData && typeof categoryData === 'object') { this.processPresetCategory(category, categoryData, errors, warnings); } }); } /** * Process a preset category */ processPresetCategory(category, categoryData, errors, warnings) { Object.keys(categoryData).forEach(presetName => { const presetData = categoryData[presetName]; // Always validate, even if presetData is null/undefined, so we can generate errors this.validateAndStorePreset(category, presetName, presetData, errors, warnings); }); } /** * Validate and store a single preset definition */ validateAndStorePreset(category, presetName, presetData, errors, warnings) { const fieldPrefix = `presets.${category}.${presetName}`; // Validate preset structure if (!presetData || typeof presetData !== 'object') { errors.push({ field: fieldPrefix, message: 'Preset data must be an object', severity: 'error' }); return; } // Validate preset name format if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(presetName)) { warnings.push({ field: fieldPrefix, message: `Preset name '${presetName}' should follow identifier naming conventions (alphanumeric and underscore only)`, severity: 'warning' }); } // Validate preset values this.validatePresetValues(presetData, fieldPrefix, errors, warnings); // Store preset with full category.name path const fullPresetName = `${category}.${presetName}`; this.presets.set(fullPresetName, presetData); } /** * Validate preset values structure and types */ validatePresetValues(values, fieldPrefix, errors, warnings) { if (!values || typeof values !== 'object') { errors.push({ field: fieldPrefix, message: 'Preset values must be an object', severity: 'error' }); return; } // Validate each preset value Object.keys(values).forEach(key => { const value = values[key]; const valueFieldPrefix = `${fieldPrefix}.${key}`; // Validate value key format if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) { warnings.push({ field: valueFieldPrefix, message: `Preset value key '${key}' should follow identifier naming conventions`, severity: 'warning' }); } // Validate value types (allow primitives and simple objects) if (!this.isValidPresetValue(value)) { errors.push({ field: valueFieldPrefix, message: 'Preset values must be primitives (string, number, boolean) or simple objects', severity: 'error' }); } // Warn about complex nested structures if (typeof value === 'object' && value !== null && this.getObjectDepth(value) > 2) { warnings.push({ field: valueFieldPrefix, message: 'Deep nested objects in preset values may be difficult to reference', severity: 'warning' }); } }); } /** * Check if a value is valid for preset storage */ isValidPresetValue(value) { if (value === null || value === undefined) { return true; } const type = typeof value; if (type === 'string' || type === 'number' || type === 'boolean') { return true; } if (type === 'object') { if (Array.isArray(value)) { return value.every(item => this.isValidPresetValue(item)); } return Object.values(value).every(val => this.isValidPresetValue(val)); } return false; } /** * Calculate the depth of nested objects */ getObjectDepth(obj) { if (typeof obj !== 'object' || obj === null) { return 0; } let maxDepth = 0; Object.values(obj).forEach(value => { const depth = this.getObjectDepth(value); maxDepth = Math.max(maxDepth, depth); }); return maxDepth + 1; } /** * Get a preset by name */ getPreset(name) { return this.presets.get(name); } /** * Get a specific preset value by key path */ getPresetValue(key) { // Parse key path like "lease_profiles.standard_office" or "lease_profiles.standard_office.rent_psf" const parts = key.split('.'); if (parts.length < 2) { return undefined; } // Handle full preset object reference (2 parts: category.preset) if (parts.length === 2) { const presetName = key; return this.presets.get(presetName); } // Handle individual field reference (3+ parts: category.preset.field[.subfield]) const presetName = `${parts[0]}.${parts[1]}`; const preset = this.presets.get(presetName); if (!preset) { return undefined; } // Navigate through the remaining path parts let current = preset; for (let i = 2; i < parts.length; i++) { const part = parts[i]; if (current && typeof current === 'object' && part && part in current) { current = current[part]; } else { return undefined; } } return current; } /** * Check if a preset exists */ hasPreset(name) { return this.presets.has(name); } /** * Get all preset names */ getPresetNames() { return Array.from(this.presets.keys()); } /** * Resolve a preset reference (e.g., "@lease_profiles.standard_office.rent_psf" or "lease_profiles.standard_office.rent_psf") */ resolvePresetReference(reference) { if (!reference || typeof reference !== 'string') { return reference; } let key; // Handle both @-prefixed and raw preset references for backward compatibility if (this.isPresetReference(reference)) { // Remove the @ prefix key = reference.substring(1); } else { // Assume it's a raw preset reference key = reference; } const resolvedValue = this.getPresetValue(key); // If we couldn't resolve it and it wasn't @-prefixed, return the original reference // If it was @-prefixed but couldn't resolve, return undefined to indicate failure if (resolvedValue === undefined) { return this.isPresetReference(reference) ? undefined : reference; } return resolvedValue; } /** * Check if a string is a preset reference */ isPresetReference(fieldName) { return typeof fieldName === 'string' && fieldName.startsWith('@'); } /** * Get validation summary */ getValidationSummary() { const presetNames = Array.from(this.presets.keys()); const sampleValues = []; // Get sample values from first few presets presetNames.slice(0, 3).forEach(presetName => { const preset = this.presets.get(presetName); if (preset && typeof preset === 'object') { Object.keys(preset).slice(0, 2).forEach(key => { sampleValues.push(`${presetName}.${key}`); }); } }); return { totalPresets: this.presets.size, presetNames, sampleValues }; } /** * Clear all presets */ clear() { this.presets.clear(); } /** * Get all presets (for debugging/inspection) */ getAllPresets() { return new Map(this.presets); } } exports.PresetResolver = PresetResolver; //# sourceMappingURL=PresetResolver.js.map