UNPKG

@elsikora/nestjs-crud-automator

Version:

A library for automating the creation of CRUD operations in NestJS.

151 lines (148 loc) 9.05 kB
import { __decorate } from '../external/tslib/tslib.es6.js'; import { VALIDATOR_HAS_PAIRED_CUSTOM_SUFFIXES_FIELDS_CONSTANT } from '../constant/validator/has-paired-custom-suffixes-fields.constant.js'; import { EHasPairedCustomSuffixesFieldsArgumentType } from '../enum/validator/has-paired-custom-suffixes-fields-argument-type.enum.js'; import '../enum/validator/must-match-one-of-schemas-error-type.enum.js'; import { ValidatorConstraint } from 'class-validator'; // eslint-disable-next-line @elsikora/typescript/naming-convention let HasPairedCustomSuffixesFieldsValidator = class HasPairedCustomSuffixesFieldsValidator { /** * Provides a custom error message describing the validation failure * @param {ValidationArguments} properties - Validation arguments containing the object being validated * @returns {string} A descriptive error message explaining why validation failed */ defaultMessage(properties) { const object = properties.object; const fieldGroups = object.__fieldGroups; const operatorSuffix = object.__operatorSuffix; const valueSuffixes = object.__valueSuffixes; const indexableObject = properties.object; for (const [baseName, groupSuffixes] of fieldGroups) { const hasValueSuffix = valueSuffixes.some((suffix) => groupSuffixes.has(suffix)); if (hasValueSuffix && !groupSuffixes.has(operatorSuffix)) { return `group "${baseName}" with value suffix must have an operator suffix [${operatorSuffix}]`; } if (groupSuffixes.has(operatorSuffix)) { if (groupSuffixes.size === 1) { return `group "${baseName}" with operator suffix must have at least one value with suffix [${[...valueSuffixes].join(", ")}]`; } const operatorField = `${baseName}[${operatorSuffix}]`; const operatorValue = indexableObject[operatorField]; const operator = operatorValue; const operatorConfig = VALIDATOR_HAS_PAIRED_CUSTOM_SUFFIXES_FIELDS_CONSTANT.DEFAULT_OPERATION_CONFIGS[operator]; if (!operatorConfig) { return `Invalid operator "${operator}" for group "${baseName}"`; } if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.NULL) { const valueCount = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).length; if (valueCount > 0) { return `group "${baseName}" with ${operator} operation should not have any values`; } continue; } const valueFields = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).map((suffix) => `${baseName}[${suffix}]`); if (valueFields.length === 0) { return `group "${baseName}" requires a value for ${operator} operation`; } if (valueFields.length > 1) { return `group "${baseName}" can only have one value with suffix [${[...valueSuffixes].join(", ")}] when operator is present`; } // @ts-ignore // eslint-disable-next-line @elsikora/typescript/no-unsafe-assignment const value = indexableObject[valueFields[0]]; const isArray = Array.isArray(value); if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.ARRAY && !isArray) { return `group "${baseName}" with ${operator} operation requires an array value`; } if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.SINGLE && isArray) { return `group "${baseName}" with ${operator} operation requires a single value, not an array`; } if (isArray) { if (operatorConfig.exactLength !== undefined && value.length !== operatorConfig.exactLength) { return `group "${baseName}" with ${operator} operation requires exactly ${String(operatorConfig.exactLength)} values`; } if (operatorConfig.minLength !== undefined && value.length < operatorConfig.minLength) { return `group "${baseName}" with ${operator} operation requires at least ${String(operatorConfig.minLength)} values`; } if (operatorConfig.maxLength !== undefined && value.length > operatorConfig.maxLength) { return `group "${baseName}" with ${operator} operation requires at most ${String(operatorConfig.maxLength)} values`; } } } } return `fields must have valid operator-value suffix pairs`; } /** * Validates that fields with suffixes follow the proper operator-value pairing pattern * @param {unknown} _value - The value being validated (unused) * @param {{ constraints: [string, Array<string>] } & ValidationArguments} properties - Validation arguments and constraints * @returns {boolean} True if the object has properly paired suffixes, false otherwise */ validate(_value, properties) { const [operatorSuffix, valueSuffixes] = properties.constraints; const indexableObject = properties.object; const fields = Object.keys(indexableObject); const fieldGroups = new Map(); const suffixPattern = [operatorSuffix, ...valueSuffixes].map((suffix) => suffix.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`)).join("|"); const regex = new RegExp(`^(.+?)\\[(${suffixPattern})\\]$`); for (const field of fields) { const match = regex.exec(field); if (match) { const [, baseName, suffix] = match; if (!fieldGroups.has(baseName)) { fieldGroups.set(baseName, new Set()); } if (indexableObject[field] !== undefined) { fieldGroups.get(baseName)?.add(suffix); } } } properties.object.__fieldGroups = fieldGroups; properties.object.__operatorSuffix = operatorSuffix; properties.object.__valueSuffixes = valueSuffixes; for (const [baseName, groupSuffixes] of fieldGroups) { const hasValueSuffix = valueSuffixes.some((suffix) => groupSuffixes.has(suffix)); if (hasValueSuffix && !groupSuffixes.has(operatorSuffix)) { return false; } if (groupSuffixes.has(operatorSuffix)) { const operatorField = `${baseName}[${operatorSuffix}]`; const operatorValue = indexableObject[operatorField]; const operator = operatorValue; const operatorConfig = VALIDATOR_HAS_PAIRED_CUSTOM_SUFFIXES_FIELDS_CONSTANT.DEFAULT_OPERATION_CONFIGS[operator]; if (!operatorConfig) return false; if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.NULL) { const valueCount = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).length; if (valueCount > 0) return false; continue; } const valueFields = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).map((suffix) => `${baseName}[${suffix}]`); if (valueFields.length !== 1) return false; // @ts-ignore // eslint-disable-next-line @elsikora/typescript/no-unsafe-assignment const value = indexableObject[valueFields[0]]; const isArray = Array.isArray(value); if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.ARRAY && !isArray) return false; if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.SINGLE && isArray) return false; if (isArray) { if (operatorConfig.exactLength !== undefined && value.length !== operatorConfig.exactLength) return false; if (operatorConfig.minLength !== undefined && value.length < operatorConfig.minLength) return false; if (operatorConfig.maxLength !== undefined && value.length > operatorConfig.maxLength) return false; } } } return true; } }; HasPairedCustomSuffixesFieldsValidator = __decorate([ ValidatorConstraint({ async: false, name: "has-paired-custom-suffixes-fields" }) ], HasPairedCustomSuffixesFieldsValidator); export { HasPairedCustomSuffixesFieldsValidator }; //# sourceMappingURL=has-paired-custom-suffixes-fields.validator.js.map