UNPKG

credl-parser-evaluator

Version:

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

225 lines 14.6 kB
"use strict"; /** * Standardized validation messages for consistent error/warning reporting * * Guidelines: * - Keep messages concise and focused on the core issue * - Use present tense, avoid parenthetical commentary * - Additional guidance goes in the help field * - Template functions for dynamic content, constants for static messages */ Object.defineProperty(exports, "__esModule", { value: true }); exports.VALIDATION_HELP = exports.VALIDATION_MESSAGES = void 0; exports.VALIDATION_MESSAGES = { METADATA: { // Core messages - clean and testable MISSING_BLOCK: 'metadata block is required', INVALID_STRUCTURE: 'metadata must be an object', MISSING_VERSION: 'version is required and must be a non-empty string', INVALID_VERSION: 'version must be a valid CREDL specification version', MISSING_NAME: 'name is required and must be a non-empty string', MISSING_DESCRIPTION: 'description is required and must be a non-empty string', MISSING_ANALYSIS_START: 'analysis_start_date is required and must be a non-empty string', INVALID_DATE_FORMAT: 'must be in ISO 8601 format (YYYY-MM-DD)', INVALID_DATE: 'must be a valid date', // Template functions for dynamic content UNSUPPORTED_VERSION: (version, min) => `CREDL specification version ${version} is not supported (minimum: ${min})`, NEWER_VERSION: (version, max) => `CREDL specification version ${version} is newer than supported by parser (maximum: ${max}). Some features may not be supported.`, }, ASSETS: { MISSING_ARRAY: 'assets must be an array', EMPTY_ARRAY: 'at least one asset is required', INVALID_ASSET: 'asset must be an object', MISSING_ID: 'id is required and must be a non-empty string', MISSING_NAME: 'name is required and must be a non-empty string', MISSING_LOCATION: 'location is required and must be a non-empty string', MISSING_AREA: 'total_area_sf is required and must be a positive number', MISSING_BUILDINGS: 'buildings must be an array', EMPTY_BUILDINGS: 'at least one building is required', // Template functions DUPLICATE_ID: (id) => `duplicate asset id: ${id}`, INVALID_PROPERTY_TYPE: (validTypes) => `property_type must be one of: ${validTypes.join(', ')}`, BUILDING_AREA_EXCEEDED: (buildingArea, assetArea, percent) => `Building areas (${buildingArea.toLocaleString()} SF) exceed asset area (${assetArea.toLocaleString()} SF) by ${percent}%. Consider accounting for common areas.`, BUILDING_AREA_LOW: (buildingArea, assetArea, percent) => `Building areas (${buildingArea.toLocaleString()} SF) are only ${percent}% of asset area (${assetArea.toLocaleString()} SF). This seems unusually low.`, }, SPACES: { MISSING_ARRAY: 'spaces must be an array', INVALID_SPACE: 'space must be an object', MISSING_ID: 'id is required and must be a non-empty string', MISSING_PARENT_BUILDING: 'parent_building is required and must be a non-empty string', MISSING_AREA: 'area_sf is required and must be a positive number', AUTO_POPULATED_FIELD: 'source_template is auto-populated by template resolver and cannot be manually specified', PRESET_LEASE_CONFLICT: 'Cannot specify both preset_lease and lease fields. Choose either preset reference or direct specification.', PRESET_EXPENSE_CONFLICT: 'Cannot specify both preset_expense and expense fields. Choose either preset reference or direct specification.', MISSING_LEASE_INFO: 'space must have either lease/lease_assumptions blocks or preset references (preset_lease, preset_expenses)', // Template functions DUPLICATE_ID: (id) => `duplicate space id: ${id}`, INVALID_TYPE: (validTypes) => `type must be one of: ${validTypes.join(', ')}`, }, LEASE: { INVALID_STRUCTURE: 'lease must be an object', MISSING_RENT: 'rent_psf is required and must be a non-negative number', TENANT_REQUIRED: 'tenant is required for leased spaces and must be a non-empty string', TENANT_NOT_ALLOWED: 'tenant field is not allowed for vacant spaces', DATES_REQUIRED: 'start_date and end_date are required for leased spaces', INVALID_RENEWAL_PROBABILITY: 'renewal_probability must be a number between 0 and 1 if provided', // Template functions INVALID_STATUS: (validStatuses) => `status must be one of: ${validStatuses.join(', ')}`, INVALID_TYPE: (validTypes) => `lease_type must be one of: ${validTypes.join(', ')}`, }, ASSUMPTIONS: { MISSING_ARRAY: 'assumptions must be an array', INVALID_ASSUMPTION: 'assumption must be an object', MISSING_NAME: 'name is required and must be a non-empty string', MISSING_VALUE: 'value is required and must be a number for fixed assumptions', MISSING_FORMULA: 'formula is required and must be a non-empty string for expression assumptions', MISSING_PARAMETERS: 'parameters is required and must be an object for distribution assumptions', MISSING_VALUES: 'values is required and must be an array for table assumptions', EMPTY_VALUES: 'values array cannot be empty for table assumptions', INVALID_TABLE_VALUE: 'table value must be an object', // Template functions INVALID_TYPE: (validTypes) => `type must be one of: ${validTypes.join(', ')}`, SCOPE_CONFLICT: (name, scope) => `Scope conflict detected: Assumption '${name}' is defined multiple times for scope '${scope}'`, INVALID_DISTRIBUTION: (validTypes) => `distribution must be one of: ${validTypes.join(', ')}`, DISTRIBUTION_PARAM_REQUIRED: (param, distType) => `${param} is required for ${distType} distribution`, DISTRIBUTION_PARAM_POSITIVE: (param, distType) => `${param} is required and must be positive for ${distType} distribution`, MIN_MAX_ORDER: (distType) => `min must be less than max for ${distType} distribution`, }, MODELS: { MISSING_ARRAY: 'models must be an array', INVALID_MODEL: 'model must be an object', MISSING_ID: 'id is required and must be a non-empty string', MISSING_TYPE: 'type is required and must be a non-empty string', MISSING_INPUTS: 'inputs is required and must be an array', MISSING_OUTPUTS: 'outputs is required and must be an array', // Template functions DUPLICATE_ID: (id) => `duplicate model id: ${id}`, INVALID_TYPE: (validTypes) => `type must be one of: ${validTypes.join(', ')}`, }, SIMULATION: { MISSING_BLOCK: 'simulation block is required', INVALID_STRUCTURE: 'simulation must be an object', MISSING_TYPE: 'type is required and must be a non-empty string', MISSING_ITERATIONS: 'iterations is required and must be a positive number', HIGH_ITERATIONS: 'very high iteration count may impact performance', // Template functions INVALID_TYPE: (validTypes) => `type must be one of: ${validTypes.join(', ')}`, ITERATIONS_LIMIT: (count, max) => `iterations (${count}) exceeds recommended maximum (${max})`, }, OUTPUTS: { MISSING_BLOCK: 'outputs block is required', INVALID_STRUCTURE: 'outputs must be an object', MISSING_METRICS: 'metrics is required and must be an array', EMPTY_METRICS: 'at least one metric is required', // Template functions INVALID_FORMAT: (validFormats) => `format must be one of: ${validFormats.join(', ')}`, }, SCENARIOS: { // Core messages - clean and testable HYBRID_TYPE: 'combines case analysis with options analysis', EMPTY_CONTENT: 'has no overrides, triggers, or actions', MISSING_NAME: 'scenario name is required', MISSING_DESCRIPTION: 'scenario description is required', INVALID_NAME: 'scenario name must be a non-empty string', INVALID_DESCRIPTION: 'scenario description must be a non-empty string', INVALID_CONDITION: 'trigger condition is required and must be a non-empty string', MISSING_ACTION_TYPE: 'action type is required', // Template functions for dynamic content UNUSUAL_ACTION_TYPE: (type) => `has unusual action type "${type}"`, MISSING_ACTION_FIELD: (actionType, field) => `${actionType} action should specify ${field}`, }, WATERFALL: { // Core messages INVALID_STRUCTURE: 'waterfall must be an object', MISSING_TIERS: 'waterfall tiers must be an array', EMPTY_TIERS: 'waterfall must have at least one tier', INVALID_TIER: 'tier must be an object', MISSING_HURDLE: 'tier hurdle rate is required', MISSING_PROMOTE: 'tier promote percentage is required', INVALID_ENABLED: 'waterfall enabled field must be a boolean', INVALID_TIER_NUMBER: 'tier number must be an integer', INVALID_DESCRIPTION: 'tier description must be a string', NON_ASCENDING_HURDLES: 'tier hurdle rates should be in ascending order', NON_SEQUENTIAL_TIERS: 'tier numbers should be sequential integers starting from 1', // Template functions PROMOTE_OUT_OF_RANGE: (value) => `promote percentage ${value} should be between 0 and 1`, }, GENERAL: { VALIDATION_FAILED: 'Validation failed due to an unexpected error', YAML_SYNTAX_ERROR: 'YAML syntax error', INVALID_STRUCTURE: 'must be a valid YAML object', PARSE_FAILED: 'Failed to parse YAML', // Template functions UNEXPECTED_ERROR: (error) => `Unexpected error: ${error}`, } }; exports.VALIDATION_HELP = { METADATA: { VERSION_FORMAT: 'Use semantic versioning like "0.1" or "0.2". Check documentation for supported versions.', DATE_FORMAT: 'Use ISO 8601 date format: YYYY-MM-DD (e.g., "2024-01-15")', ANALYSIS_START: 'This date marks the beginning of your financial analysis period', CREATED_DATE: 'Record when this CREDL file was originally created', }, ASSETS: { REQUIRED_FIELDS: 'Assets need: id, name, property_type, location, total_area_sf, and buildings array', PROPERTY_TYPES: 'Valid property types: Office, Retail, Industrial, Residential, Mixed-Use', BUILDING_AREAS: 'Building areas should typically be 70-90% of total asset area to account for common areas', DUPLICATE_IDS: 'Each asset must have a unique identifier across your entire CREDL file', }, SPACES: { REQUIRED_FIELDS: 'Spaces need: id, parent_building, type, area_sf, and lease information', PARENT_BUILDING: 'Must reference a building ID that exists in your assets', LEASE_OPTIONS: 'Provide either direct lease/lease_assumptions OR use preset references (preset_lease, preset_expenses)', PRESET_CONFLICTS: 'Use either preset references OR direct values, not both to avoid ambiguity', SOURCE_TEMPLATE: 'This field is automatically set when spaces are generated from templates', }, LEASE: { REQUIRED_FOR_LEASED: 'Leased spaces must specify: tenant, start_date, end_date', VACANT_SPACES: 'Vacant spaces should not have tenant specified; dates are optional market assumptions', RENEWAL_PROBABILITY: 'Value between 0 (never renews) and 1 (always renews) for lease renewal likelihood', LEASE_TYPES: 'Common types: gross, net, double_net, triple_net, modified_gross', }, ASSUMPTIONS: { SCOPE_HIERARCHY: 'Scopes follow hierarchy: global → asset → building → space_type → space_id', SCOPE_CONFLICTS: 'Each assumption name can only be defined once per scope level', DISTRIBUTION_TYPES: 'Supported distributions: normal, uniform, triangular, lognormal', NORMAL_PARAMS: 'Normal distribution requires: mean (number), stddev (positive number)', UNIFORM_PARAMS: 'Uniform distribution requires: min (number), max (number, > min)', TRIANGULAR_PARAMS: 'Triangular distribution requires: min, max, mode (all numbers, min < mode < max)', TABLE_STRUCTURE: 'Table values must be objects with consistent structure across all entries', }, MODELS: { REQUIRED_FIELDS: 'Models need: id, type, inputs (array), outputs (array)', MODEL_TYPES: 'Common types: discounted_cash_flow, stochastic, sensitivity_analysis', INPUT_REFERENCES: 'Inputs should reference assumption names defined in your assumptions block', OUTPUT_CONSISTENCY: 'Outputs should match what your simulation and outputs blocks expect', }, SIMULATION: { ITERATION_GUIDELINES: 'Typical ranges: 1,000-10,000 iterations. Higher counts improve accuracy but slow processing', MONTE_CARLO: 'Monte Carlo simulations should include sampling processes and statistical metrics', PERFORMANCE_IMPACT: 'Very high iteration counts (>10,000) may significantly impact processing time', }, OUTPUTS: { REQUIRED_METRICS: 'Common metrics: npv, irr, cash_flow, roi, payback_period', FORMAT_OPTIONS: 'Supported formats: json, csv, excel, pdf', METRIC_CONSISTENCY: 'Ensure requested metrics are produced by your models', }, SCENARIOS: { HYBRID_TYPE: 'Consider using either overrides (case analysis) OR triggers/actions (options analysis) for clarity', UNUSUAL_ACTION_TYPE: 'Supported action types: add_spaces, delay_project, accelerate_project, expand_building, contract_scope', ADD_SPACES_TEMPLATE: 'add_spaces actions typically require: template, count, parent_building', ADD_SPACES_BUILDING: 'add_spaces actions should reference an existing building ID', }, WATERFALL: { TIER_STRUCTURE: 'Each tier requires: hurdle (number), promote (number). Optional: tier (integer), description (string)', PROMOTE_RANGE: 'Promote percentages typically range from 0 (0%) to 1 (100%)', HURDLE_ORDERING: 'Hurdle rates should increase with each tier (e.g., 0.08, 0.12, 0.16)', SEQUENTIAL_NUMBERING: 'If using tier numbers, they should be 1, 2, 3, etc. without gaps', }, GENERAL: { YAML_SYNTAX: 'Check for proper indentation, quotes, and YAML structure. Use a YAML validator if needed', VALIDATION_ERRORS: 'Fix errors in order - some errors may cascade and resolve multiple issues', CROSS_REFERENCES: 'Ensure all referenced IDs (buildings, assumptions, etc.) exist in their respective blocks', } }; //# sourceMappingURL=validation-messages.js.map