import { ValidationResult } from "@business-logic/types/RuleEngine"; import EnumUtils from "./EnumUtils"; export type ExtractName = { [K in keyof T]: () => K; }; type GetValueOptions = { isRequired: boolean; }; function isNullOrWhiteSpace(input: unknown): boolean { if (typeof input !== "string") return input == null; return input.trim().length === 0; } // Matches: '() => _Enums.*****', e.g.: '() => _Enums.ModificationTypes' // Matches: '() => *****', e.g.: '() => ModificationTypes' // Returns: EnumName, e.g.: 'ModificationTypes' function getEnumName(propertySelector: () => object): string { const functionString = propertySelector.toString(); const match = functionString.match(/\(\s*\)\s*=>\s*(?:_?[A-Z]\w*\.)?(\w+)(?::)?/); return match ? match[1] : "Unknown"; } // Matches: 'x => x.*****', e.g.: 'x => x.name', 'x => x.tags' // Returns: PropertyName, e.g.: 'name', 'tags' function getNameof(propertySelector: (obj: T) => any): string { const propertyString = propertySelector.toString(); const match = propertyString.match(/(?:=>|return)\s*([\w\s.]+)/); if (match && match[1]) { const parts = match[1].split('.'); return parts[parts.length - 1].trim(); } throw new Error(`Invalid property selector: ${propertyString}`); } function getValueOrNull(json: any, propertySelector: (obj: T) => any): any | null { if (json == null) return null; const property = getNameof(propertySelector); if (json.hasOwnProperty(property)) return json[property]; return null; } function getValue(json: any, typeName: string, validationResults: ValidationResult[], options: GetValueOptions, propertySelector: (obj: T) => any): any | null { const retval = getValueOrNull(json, propertySelector); if (retval == null) validationResults.push(options.isRequired ? ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} is null but is required!`) : ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is null but is NOT required.`)); else { if (isNullOrWhiteSpace(retval)) validationResults.push(ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} is empty!`)); else validationResults.push(ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is valid.`)); } return retval; } function hasProperty(json: any, typeName: string, validationResults: ValidationResult[], options: GetValueOptions, propertySelector: (obj: ExtractName) => () => keyof T): boolean { const retval = json.hasOwnProperty(getNameof(propertySelector)); if (retval) validationResults.push(ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is valid.`)); else validationResults.push(options.isRequired ? ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is not defined but is required!`) : ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} is not defined but is NOT required!`)); return retval; } function getEnumValueOrNull(json: any, enumType: object, propertySelector: (obj: T) => any): any | null { if (json == null) return null; const property = getNameof(propertySelector); const retval = EnumUtils.validateEnumProperty(json, property, enumType); if (retval != null) return retval; else if (Object.values(enumType).includes(json[property])) return json[property]; return null; } function getEnumValue(json: any, typeName: string, validationResults: ValidationResult[], enumType: object, enumTypeInstance: () => object, options: GetValueOptions, propertySelector: (obj: T) => any): any | null { const retval = getEnumValueOrNull(json, enumType, propertySelector); if (retval == null) validationResults.push(options.isRequired ? ValidationResult.FromFailure(`Value for ${typeName}.${getNameof(propertySelector)} [${getEnumName(enumTypeInstance)}] is null but is required!`) : ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} [${getEnumName(enumTypeInstance)}] is null but is NOT required.`)); else validationResults.push(ValidationResult.FromSuccess(retval, `Value for ${typeName}.${getNameof(propertySelector)} is valid.`)); return retval; } export { getEnumName, getEnumValueOrNull, getNameof, getValueOrNull }; const PropertyUtils = { hasProperty, getValue, getEnumValue }; export default PropertyUtils;