El patrón Chain of Responsibility encadena validaciones independientes, cada una con su propia responsabilidad.
1. El Problema de Partida
Antes de aceptar un post .mdx nuevo, scripts/validate-content.js comprobaba en un único método gigante: que el slug no colisione con otro existente, que translation_id no esté vacío, y que category exista en _category.json. Cada validación nueva (ej. "el date debe tener formato ISO") obligaba a editar ese mismo método monolítico.
2. La Solución Chain of Responsibility
// src/lib/validation/ValidationChain.js
class ValidationHandler {
next = null;
setNext(handler) { this.next = handler; return handler; }
handle(post) { return this.next ? this.next.handle(post) : null; }
}
class UniqueSlugHandler extends ValidationHandler {
constructor(existingSlugs) { super(); this.existingSlugs = existingSlugs; }
handle(post) {
if (this.existingSlugs.includes(post.slug)) return `Slug duplicado: ${post.slug}`;
return super.handle(post);
}
}
class TranslationIdHandler extends ValidationHandler {
handle(post) {
if (!post.translation_id) return 'Falta translation_id';
return super.handle(post);
}
}
class CategoryExistsHandler extends ValidationHandler {
constructor(categories) { super(); this.categories = categories; }
handle(post) {
if (!this.categories.includes(post.category)) return `Categoría inexistente: ${post.category}`;
return super.handle(post);
}
}
export function buildValidationChain(existingSlugs, categories) {
const slugCheck = new UniqueSlugHandler(existingSlugs);
slugCheck
.setNext(new TranslationIdHandler())
.setNext(new CategoryExistsHandler(categories));
return slugCheck;
}3. Uso
// scripts/validate-content.js
import { buildValidationChain } from '@/lib/validation/ValidationChain';
const chain = buildValidationChain(existingSlugs, categoryIds);
const error = chain.handle({ slug: 'proxy', translation_id: 'proxy-guide', category: 'design-patterns' });
if (error) console.error(`❌ ${error}`); else console.log('✅ Post válido');4. Ventajas
- Cada regla vive aislada y se testea sin montar las demás.
- Añadir una validación nueva (ej. formato de fecha) = una clase más en la cadena.
- Orden explícito y reordenable sin tocar la lógica interna de cada validador.