UNPKG

ajt-validator

Version:

Validation library for JavaScript and TypeScript

182 lines (181 loc) 7.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GenderValidator = exports.GenderOption = void 0; const base_1 = require("../base"); /** * Standard gender options */ var GenderOption; (function (GenderOption) { GenderOption["MALE"] = "male"; GenderOption["FEMALE"] = "female"; GenderOption["NON_BINARY"] = "non-binary"; GenderOption["OTHER"] = "other"; GenderOption["PREFER_NOT_TO_SAY"] = "prefer-not-to-say"; })(GenderOption || (exports.GenderOption = GenderOption = {})); /** * Validator for gender fields * Supports standard options, custom entries, and abbreviations */ class GenderValidator extends base_1.BaseValidator { /** * Create a new gender validator * @param options Configuration options */ constructor(options = {}) { super(); this.lowercaseAllowedValues = []; // Set default standard values from enum this.standardValues = Object.values(GenderOption); // Initialize default options this.options = Object.assign({ allowedValues: this.standardValues, allowCustom: false, customMaxLength: 50, normalize: true, caseSensitive: false, allowAbbreviations: true }, options); // Default abbreviation mapping this.abbreviations = Object.assign({ 'm': GenderOption.MALE, 'f': GenderOption.FEMALE, 'nb': GenderOption.NON_BINARY, 'o': GenderOption.OTHER, 'x': GenderOption.OTHER, 'pnts': GenderOption.PREFER_NOT_TO_SAY, 'prefer not': GenderOption.PREFER_NOT_TO_SAY }, (this.options.abbreviationMap || {})); // Precompute lowercase allowed values for case-insensitive matching if (!this.options.caseSensitive && this.options.allowedValues) { this.lowercaseAllowedValues = this.options.allowedValues.map(val => val.toLowerCase()); } } /** * Validate a gender value * @param value Gender string to validate * @returns Validation result with additional metadata */ validate(value) { // Check for null/empty/non-string values if (value === null || value === undefined || value === '') { return this.createError('GENDER_REQUIRED', 'Gender value is required'); } // Convert to string if it's not already const stringValue = String(value); let processedValue = stringValue; // Normalize if enabled if (this.options.normalize) { processedValue = stringValue.trim(); if (!this.options.caseSensitive) { processedValue = processedValue.toLowerCase(); } } // Check if it's a standard or allowed value const allowedValues = this.options.allowedValues || this.standardValues; const isAllowed = this.checkAllowedValue(processedValue, allowedValues); if (isAllowed) { return { isValid: true, value: stringValue, normalizedValue: processedValue, isStandardOption: this.checkIsStandardOption(processedValue) }; } // Check abbreviations if enabled if (this.options.allowAbbreviations) { const expandedValue = this.expandAbbreviation(processedValue); if (expandedValue && this.checkAllowedValue(expandedValue, allowedValues)) { return { isValid: true, value: stringValue, normalizedValue: processedValue, expandedValue, isStandardOption: this.checkIsStandardOption(expandedValue) }; } } // Allow custom value if enabled if (this.options.allowCustom) { if (processedValue.length > (this.options.customMaxLength || 50)) { return this.createError('GENDER_TOO_LONG', `Custom gender value cannot exceed ${this.options.customMaxLength} characters`); } return { isValid: true, value: stringValue, normalizedValue: processedValue, isStandardOption: false }; } // If we get here, the value is not valid return this.createError('INVALID_GENDER', `Gender must be one of: ${allowedValues.join(', ')}`); } /** * Check if value exists in allowed values list * @param value Value to check * @param allowedValues List of allowed values * @returns Whether the value is allowed */ checkAllowedValue(value, allowedValues) { if (this.options.caseSensitive) { return allowedValues.indexOf(value) !== -1; } else { // Use precomputed lowercase values if available if (this.lowercaseAllowedValues.length > 0) { return this.lowercaseAllowedValues.indexOf(value.toLowerCase()) !== -1; } // Fallback for dynamic allowed values return allowedValues.some(allowed => allowed.toLowerCase() === value.toLowerCase()); } } /** * Check if a value is a standard option * @param value Value to check (assumed to be already normalized) * @returns Whether the value is a standard option */ checkIsStandardOption(value) { if (this.options.caseSensitive) { return this.standardValues.indexOf(value) !== -1; } else { const lowercaseValue = value.toLowerCase(); return this.standardValues.some(standard => standard.toLowerCase() === lowercaseValue); } } /** * Expand an abbreviation to its full form * @param abbr Abbreviation to expand * @returns Expanded value if found, or undefined */ expandAbbreviation(abbr) { // Direct lookup for case-sensitive mode if (this.options.caseSensitive) { return this.abbreviations[abbr]; } // Case-insensitive lookup const lowerAbbr = abbr.toLowerCase(); // First try direct lowercase match if (this.abbreviations[lowerAbbr]) { return this.abbreviations[lowerAbbr]; } // If not found, search for case-insensitive match in keys const keys = Object.keys(this.abbreviations); for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (key.toLowerCase() === lowerAbbr) { return this.abbreviations[key]; } } return undefined; } /** * Get all standard gender options * @returns List of standard gender values */ getStandardOptions() { return [...this.standardValues]; } /** * Get all allowed abbreviations * @returns Map of abbreviations to full values */ getAbbreviations() { return Object.assign({}, this.abbreviations); } /** * Create an error result for gender validation */ createError(code, message) { return { isValid: false, errors: [{ code, message }] }; } } exports.GenderValidator = GenderValidator;