UNPKG

@elsikora/nestjs-crud-automator

Version:

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

191 lines (187 loc) 9.61 kB
'use strict'; var tslib_es6 = require('../external/tslib/tslib.es6.js'); require('../enum/validator/has-paired-custom-suffixes-fields-argument-type.enum.js'); var mustMatchOneOfSchemasErrorType_enum = require('../enum/validator/must-match-one-of-schemas-error-type.enum.js'); var classValidator = require('class-validator'); // eslint-disable-next-line @elsikora/typescript/naming-convention exports.MustMatchOneOfSchemasConstraint = class MustMatchOneOfSchemasConstraint { allowedValues = []; discriminatorField = null; discriminatorValue = null; errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.UNKNOWN; schemasInfo = {}; /** * Provides a custom error message based on the type of validation failure * @param {ValidationArguments} _arguments - Validation arguments containing property information * @returns {string} A descriptive error message explaining why validation failed */ defaultMessage(_arguments) { const propertyName = _arguments.property; switch (this.errorType) { case mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.INVALID_DISCRIMINATOR: { const schemasList = this.allowedValues .map((value) => { const schemaName = this.schemasInfo[value] ?? "Unknown schema"; return `'${value}' (${schemaName})`; }) .join(", "); return `${propertyName} has invalid discriminator value '${String(this.discriminatorValue)}' for field '${String(this.discriminatorField)}'. must be one of: ${schemasList}`; } case mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.MISSING_DISCRIMINATOR: { return `${propertyName} is missing required discriminator field '${String(this.discriminatorField)}'`; } case mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.SCHEMA_MISMATCH: { const schemasList = this.allowedValues .map((value) => { const schemaName = this.schemasInfo[value] ?? "Unknown schema"; return `'${value}' (${schemaName})`; }) .join(", "); return `${propertyName} must match one of the schemas: ${schemasList}`; } case mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.UNKNOWN: { return `${propertyName} must match one of the valid schemas`; } default: { return `${propertyName} must match one of the valid schemas`; } } } /** * Validates whether an object matches one of the allowed schemas based on its discriminator field * @param {unknown} value - The value being validated * @param {ValidationArguments} _arguments - Validation arguments containing constraints * @returns {boolean} True if the value matches a valid schema, false otherwise */ validate(value, _arguments) { if (!value || typeof value !== "object" || Array.isArray(value)) { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.SCHEMA_MISMATCH; this.prepareAllowedSchemas(_arguments); return false; } const valueAsRecord = value; if (Object.keys(valueAsRecord).length === 0) { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.SCHEMA_MISMATCH; this.prepareAllowedSchemas(_arguments); return false; } const constraints = _arguments.constraints; if (!constraints?.[0]?.discriminator) { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.UNKNOWN; return false; } try { const discriminator = constraints[0].discriminator; if (!discriminator.propertyName || typeof discriminator.propertyName !== "string") { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.UNKNOWN; return false; } this.discriminatorField = discriminator.propertyName; if (!(discriminator.propertyName in valueAsRecord)) { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.MISSING_DISCRIMINATOR; return false; } const discriminatorValue = valueAsRecord[discriminator.propertyName]; if (typeof discriminatorValue !== "string" || discriminatorValue === "") { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.INVALID_DISCRIMINATOR; this.discriminatorValue = String(discriminatorValue); this.prepareAllowedSchemas(_arguments); return false; } this.discriminatorValue = discriminatorValue; if (!discriminator.mapping || typeof discriminator.mapping !== "object") { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.SCHEMA_MISMATCH; this.prepareAllowedSchemas(_arguments); return false; } this.prepareAllowedSchemas(_arguments); if (!this.allowedValues.includes(discriminatorValue)) { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.INVALID_DISCRIMINATOR; return false; } return true; } catch { this.errorType = mustMatchOneOfSchemasErrorType_enum.EMastMatchOneOfSchemasValidationErrorType.SCHEMA_MISMATCH; this.prepareAllowedSchemas(_arguments); return false; } } /** * Prepares the list of allowed schemas and their names based on validation constraints * @param {ValidationArguments} _arguments - Validation arguments containing constraints * @returns {void} * @private */ prepareAllowedSchemas(_arguments) { this.allowedValues = []; this.schemasInfo = {}; const constraints = _arguments.constraints; if (!constraints?.[0]) { return; } const { discriminator, schemas } = constraints[0]; if (!discriminator?.mapping) { return; } this.allowedValues = Object.keys(discriminator.mapping); for (const [key, value] of Object.entries(discriminator.mapping)) { let schemaName = "Unknown schema"; if (Array.isArray(schemas)) { // eslint-disable-next-line @elsikora/typescript/no-unsafe-function-type const schemaClass = schemas.find((schema) => { if (typeof value === "function" && schema === value) { return true; } return typeof value === "string" && schema.name === value; }); if (schemaClass) { schemaName = schemaClass.name ?? "Anonymous class"; } } else if (schemas && typeof schemas === "object") { if (typeof value === "string" && value in schemas) { const schemaClass = schemas[value]; schemaName = schemaClass.name ?? value; } else if (typeof value === "function") { schemaName = value.name ?? "Anonymous class"; } } this.schemasInfo[key] = schemaName; } } }; exports.MustMatchOneOfSchemasConstraint = tslib_es6.__decorate([ classValidator.ValidatorConstraint({ async: false, name: "must-match-one-of-schemas" }) ], exports.MustMatchOneOfSchemasConstraint); /** * Decorator that checks if the object matches one of the schemas based on the discriminator field * @param {IMustMatchOneOfSchemasDiscriminatorConfig} discriminatorConfig - Configuration for the discriminator * @param {ValidationOptions} [validationOptions] - Validation options * @returns {PropertyDecorator} - Decorator */ function MustMatchOneOfSchemasValidator(discriminatorConfig, validationOptions) { return function (target, propertyKey) { if (typeof propertyKey !== "string") { throw new TypeError("MatchesOneOfSchemas decorator can only be applied to string properties"); } if (!discriminatorConfig?.discriminator) { throw new TypeError("discriminatorConfig must contain a discriminator property"); } const discriminator = discriminatorConfig.discriminator; if (!discriminator.propertyName || !discriminator.mapping) { throw new TypeError("discriminator must contain propertyName and mapping properties"); } classValidator.registerDecorator({ constraints: [discriminatorConfig], name: "must-match-one-of-schemas", options: validationOptions, propertyName: propertyKey, target: target.constructor, validator: exports.MustMatchOneOfSchemasConstraint, }); }; } exports.MustMatchOneOfSchemasValidator = MustMatchOneOfSchemasValidator; //# sourceMappingURL=must-match-one-of-schemas.validator.js.map