/** * ValidationErrorCollection * * Esta clase representa un error de validación que agrega múltiples detalles de errores * en un formato estructurado. Es útil para manejar múltiples errores de validación * en una sola respuesta, permitiendo a los clientes entender qué campos fallaron y por qué. * * Ejemplo de uso: * * const errors: ValidationErrorDetail[] = [ * { path: "lines[1].unitPrice.amount", message: "Amount must be a positive number" }, * { path: "lines[1].unitPrice.scale", message: "Scale must be a non-negative integer" }, * ]; * const validationError = new ValidationErrorCollection(errors); * */ import { DomainError } from "./domain-error"; import { DomainValidationError } from "./domain-validation-error"; export interface ValidationErrorDetail { /** Path del campo inválido, ej. "lines[1].unitPrice.amount" */ path?: string; /** Mensaje legible del fallo */ message: string; /** Valor inválido (no se debe exponer directamente en API pública si es sensible) */ value?: unknown; } /** * Error de validación múltiple de dominio. * Permite agrupar varios fallos de validación en una única instancia. * * Ejemplo: * const errors: ValidationErrorDetail[] = [ * { path: "lines[1].unitPrice.amount", message: "Amount must be positive" }, * { path: "lines[1].unitPrice.scale", message: "Scale must be non-negative" }, * ]; * throw new ValidationErrorCollection(errors); */ export class ValidationErrorCollection extends DomainError { public readonly kind = "VALIDATION" as const; public readonly code = "MULTIPLE_VALIDATION_ERRORS" as const; public readonly details: ValidationErrorDetail[]; constructor( details: ValidationErrorDetail[], options?: ErrorOptions & { metadata?: Record } ) { super("Multiple validation errors", "MULTIPLE_VALIDATION_ERRORS", { ...options, metadata: { ...(options?.metadata ?? {}), errors: details }, }); this.name = "ValidationErrorCollection"; this.details = details; Object.setPrototypeOf(this, new.target.prototype); Object.freeze(this); } /** Crear a partir de varios DomainValidationError */ static fromErrors( errors: DomainValidationError[], options?: ErrorOptions & { metadata?: Record } ): ValidationErrorCollection { const details: ValidationErrorDetail[] = errors.map((e) => ({ path: e.field, message: e.detail, value: (e as any).cause, // opcional: valor que provocó el error })); return new ValidationErrorCollection(details, options); } /** Serialización para Problem+JSON / logs */ override toJSON() { const base = super.toJSON(); return { ...base, kind: this.kind, details: this.details.map((d) => ({ path: d.path, message: d.message, })), }; } } /** Type guard */ export const isValidationErrorCollection = (e: unknown): e is ValidationErrorCollection => e instanceof ValidationErrorCollection;