Skip to main content
Glama
DocumentationValidator.ts7.63 kB
import WorkflowValidator from '../resources/WorkflowValidator.js'; /** * Validateur pour la documentation des workflows n8n */ class DocumentationValidator implements WorkflowValidator { /** * Valide la documentation d'un workflow n8n * @param workflow Les données du workflow à valider * @param strictness Le niveau de rigueur de la validation * @returns Résultat de la validation avec les problèmes détectés */ validate(workflow: any, strictness: 'low' | 'medium' | 'high') { const issues: Array<{ message: string; recommendation: string; severity: 'low' | 'medium' | 'high'; location?: string; }> = []; // Vérifier la documentation du workflow this.checkWorkflowDocumentation(workflow, issues, strictness); // Vérifier la documentation des nœuds if (workflow.nodes && Array.isArray(workflow.nodes)) { workflow.nodes.forEach((node: any) => { this.checkNodeDocumentation(node, issues, strictness); }); } return { valid: issues.length === 0, issues, }; } /** * Vérifie la documentation au niveau du workflow */ private checkWorkflowDocumentation(workflow: any, issues: any[], strictness: string): void { // Vérifier si le workflow a un nom if (!workflow.name || workflow.name.trim() === '') { issues.push({ message: 'Le workflow n\'a pas de nom', recommendation: 'Donnez un nom descriptif au workflow', severity: 'high', }); } else if (workflow.name.length < 5 && strictness !== 'low') { issues.push({ message: 'Le nom du workflow est trop court', recommendation: 'Utilisez un nom plus descriptif pour le workflow', severity: 'medium', }); } // Vérifier si le workflow a une description if (!workflow.description || workflow.description.trim() === '') { issues.push({ message: 'Le workflow n\'a pas de description', recommendation: 'Ajoutez une description qui explique le but et le fonctionnement du workflow', severity: strictness === 'low' ? 'low' : 'medium', }); } else { // Vérifier la qualité de la description this.checkDescriptionQuality(workflow.description, 'workflow', issues, strictness); } // Vérifier les tags if (!workflow.tags || !Array.isArray(workflow.tags) || workflow.tags.length === 0) { issues.push({ message: 'Le workflow n\'a pas de tags', recommendation: 'Ajoutez des tags pour catégoriser le workflow et faciliter sa recherche', severity: strictness === 'high' ? 'medium' : 'low', }); } // Vérifier les métadonnées supplémentaires en fonction du niveau de rigueur if (strictness === 'high') { // Vérifier si le workflow a un propriétaire ou un responsable if (!workflow.owner && !workflow.createdBy) { issues.push({ message: 'Le workflow n\'a pas d\'information sur le propriétaire ou le créateur', recommendation: 'Ajoutez des informations sur le propriétaire ou le responsable du workflow', severity: 'low', }); } // Vérifier si le workflow a une date de dernière mise à jour if (!workflow.updatedAt) { issues.push({ message: 'Le workflow n\'a pas d\'information sur sa dernière mise à jour', recommendation: 'Ajoutez une date de dernière mise à jour pour suivre l\'évolution du workflow', severity: 'low', }); } } } /** * Vérifie la documentation au niveau des nœuds */ private checkNodeDocumentation(node: any, issues: any[], strictness: string): void { // Vérifier si le nœud a un nom descriptif if (!node.name || node.name.trim() === '') { issues.push({ message: 'Un nœud n\'a pas de nom', recommendation: 'Donnez un nom à tous les nœuds du workflow', severity: 'high', location: node.id, }); } else if (node.name === node.type || this.isDefaultNodeName(node.name, node.type)) { issues.push({ message: `Le nœud "${node.name}" utilise un nom par défaut`, recommendation: 'Renommez les nœuds avec des noms descriptifs qui expliquent leur fonction dans le workflow', severity: strictness === 'low' ? 'low' : 'medium', location: node.id, }); } // Vérifier les notes du nœud if ((!node.notes || node.notes.trim() === '') && this.isComplexNode(node)) { issues.push({ message: `Le nœud complexe "${node.name}" n'a pas de notes explicatives`, recommendation: 'Ajoutez des notes aux nœuds complexes pour expliquer leur configuration et leur rôle', severity: strictness === 'low' ? 'low' : 'medium', location: node.id, }); } else if (node.notes && node.notes.trim() !== '') { // Vérifier la qualité des notes this.checkDescriptionQuality(node.notes, `nœud "${node.name}"`, issues, strictness); } } /** * Vérifie si un nom de nœud est un nom par défaut */ private isDefaultNodeName(name: string, type: string): boolean { if (!name || !type) return false; // Extraire le nom de base du type (après le dernier point) const baseType = type.split('.').pop() || ''; // Vérifier si le nom contient le type de base return name.toLowerCase().includes(baseType.toLowerCase()); } /** * Vérifie si un nœud est considéré comme complexe et nécessite une documentation */ private isComplexNode(node: any): boolean { // Les nœuds considérés comme complexes et nécessitant une documentation const complexNodeTypes = [ 'function', 'code', 'switch', 'if', 'split', 'merge', 'http', 'webhook', 'api', 'database', 'execute', ]; // Vérifier si le type du nœud contient l'un des types complexes return complexNodeTypes.some(type => (node.type || '').toLowerCase().includes(type.toLowerCase()) ); } /** * Vérifie la qualité d'une description */ private checkDescriptionQuality(description: string, context: string, issues: any[], strictness: string): void { if (!description) return; // Vérifier la longueur de la description if (description.length < 10) { issues.push({ message: `La description du ${context} est trop courte`, recommendation: 'Fournissez une description plus détaillée', severity: 'low', }); } // Vérifier si la description contient des informations utiles (pour strictness medium et high) if (strictness !== 'low') { // Vérifier si la description mentionne le but ou la fonction const hasPurpose = /but|objectif|fonction|permet|sert à|utilise/i.test(description); if (!hasPurpose) { issues.push({ message: `La description du ${context} ne mentionne pas clairement son objectif`, recommendation: 'Incluez l\'objectif ou la fonction dans la description', severity: 'low', }); } // Pour strictness high, vérifier si la description est complète if (strictness === 'high' && description.length < 50) { issues.push({ message: `La description du ${context} pourrait être plus détaillée`, recommendation: 'Fournissez une description plus complète incluant l\'objectif, les entrées attendues et les sorties produites', severity: 'low', }); } } } } export default DocumentationValidator;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lowprofix/n8n-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server