// === VALIDATEUR ET CONVERTISSEUR ULTRA-MODULAIRE === // Utilitaire pour valider et convertir les spécifications JSON ultra-modulaires class UltraModularValidator { constructor() { this.jsonLoader = new JSONContentLoader(); this.contentScanner = new ContentScanner(); this.validationRules = this.initValidationRules(); } initValidationRules() { return { // Champs obligatoires required: ['id', 'name'], // Champs recommandés pour une expérience optimale recommended: ['description', 'difficulty_level', 'original_lang', 'user_lang', 'tags'], // Types de contenu supportés contentTypes: ['vocabulary', 'sentences', 'grammar', 'audio', 'dialogues', 'poems', 'culture', 'matching', 'fillInBlanks', 'corrections', 'comprehension'], // Niveaux de difficulté valides difficultyLevels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], // Langues supportées supportedLanguages: ['english', 'french', 'spanish', 'german', 'chinese', 'japanese'] }; } /** * Valide une spécification JSON ultra-modulaire */ async validateSpecification(jsonContent) { const validation = { valid: true, errors: [], warnings: [], suggestions: [], score: 0, capabilities: null, compatibility: null }; try { // 1. Validation de structure de base this.validateBasicStructure(jsonContent, validation); // 2. Validation des métadonnées this.validateMetadata(jsonContent, validation); // 3. Validation du contenu éducatif this.validateEducationalContent(jsonContent, validation); // 4. Analyse des capacités const capabilities = this.contentScanner.analyzeContentCapabilities(jsonContent); validation.capabilities = capabilities; // 5. Analyse de compatibilité des jeux const compatibility = this.contentScanner.calculateGameCompatibility(capabilities); validation.compatibility = compatibility; // 6. Calcul du score de qualité validation.score = this.calculateQualityScore(jsonContent, capabilities, compatibility); // 7. Suggestions d'amélioration this.generateSuggestions(jsonContent, capabilities, validation); } catch (error) { validation.valid = false; validation.errors.push(`Erreur fatale de validation: ${error.message}`); } return validation; } /** * Valide la structure de base du JSON */ validateBasicStructure(jsonContent, validation) { // Vérifier les champs obligatoires for (const field of this.validationRules.required) { if (!jsonContent[field]) { validation.errors.push(`Champ obligatoire manquant: ${field}`); validation.valid = false; } } // Vérifier les champs recommandés for (const field of this.validationRules.recommended) { if (!jsonContent[field]) { validation.warnings.push(`Champ recommandé manquant: ${field}`); } } // Valider l'ID if (jsonContent.id && !/^[a-z0-9_]+$/.test(jsonContent.id)) { validation.errors.push('ID invalide: utilisez uniquement lettres minuscules, chiffres et underscores'); validation.valid = false; } } /** * Valide les métadonnées */ validateMetadata(jsonContent, validation) { // Valider le niveau de difficulté if (jsonContent.difficulty_level && !this.validationRules.difficultyLevels.includes(jsonContent.difficulty_level)) { validation.errors.push(`Niveau de difficulté invalide: ${jsonContent.difficulty_level}. Utilisez 1-10`); validation.valid = false; } // Valider les langues if (jsonContent.original_lang && !this.validationRules.supportedLanguages.includes(jsonContent.original_lang)) { validation.warnings.push(`Langue d'origine non standard: ${jsonContent.original_lang}`); } if (jsonContent.user_lang && !this.validationRules.supportedLanguages.includes(jsonContent.user_lang)) { validation.warnings.push(`Langue utilisateur non standard: ${jsonContent.user_lang}`); } // Valider les tags if (jsonContent.tags && !Array.isArray(jsonContent.tags)) { validation.errors.push('Les tags doivent être un tableau'); validation.valid = false; } // Valider les compétences couvertes if (jsonContent.skills_covered && !Array.isArray(jsonContent.skills_covered)) { validation.errors.push('Les compétences couvertes doivent être un tableau'); validation.valid = false; } } /** * Valide le contenu éducatif */ validateEducationalContent(jsonContent, validation) { let contentFound = false; // Vérifier qu'il y a au moins un type de contenu for (const contentType of this.validationRules.contentTypes) { if (jsonContent[contentType]) { contentFound = true; this.validateContentSection(contentType, jsonContent[contentType], validation); } } if (!contentFound) { validation.errors.push('Aucun contenu éducatif trouvé'); validation.valid = false; } } /** * Valide une section de contenu spécifique */ validateContentSection(contentType, content, validation) { switch (contentType) { case 'vocabulary': this.validateVocabulary(content, validation); break; case 'matching': this.validateMatching(content, validation); break; case 'fillInBlanks': this.validateFillInBlanks(content, validation); break; // ... autres validations spécifiques } } /** * Valide la section vocabulaire (6 niveaux de complexité) */ validateVocabulary(vocabulary, validation) { if (typeof vocabulary !== 'object') { validation.errors.push('Le vocabulaire doit être un objet'); return; } const entries = Object.entries(vocabulary); if (entries.length === 0) { validation.warnings.push('Section vocabulaire vide'); return; } let maxDepth = 0; for (const [word, definition] of entries) { if (typeof definition === 'string') { maxDepth = Math.max(maxDepth, 1); } else if (typeof definition === 'object') { maxDepth = Math.max(maxDepth, 2); // Détecter les niveaux avancés if (definition.examples || definition.grammar_notes) maxDepth = Math.max(maxDepth, 3); if (definition.etymology || definition.word_family) maxDepth = Math.max(maxDepth, 4); if (definition.cultural_significance) maxDepth = Math.max(maxDepth, 5); if (definition.memory_techniques || definition.visual_associations) maxDepth = Math.max(maxDepth, 6); } else { validation.warnings.push(`Définition invalide pour "${word}": doit être une chaîne ou un objet`); } } validation.suggestions.push(`Niveau de vocabulaire détecté: ${maxDepth}/6 - ${this.getVocabularyLevelDescription(maxDepth)}`); } /** * Valide le système de matching multi-colonnes */ validateMatching(matching, validation) { if (!Array.isArray(matching)) { validation.errors.push('La section matching doit être un tableau'); return; } for (const exercise of matching) { if (exercise.columns && Array.isArray(exercise.columns)) { // Nouveau format multi-colonnes if (exercise.columns.length < 2) { validation.warnings.push('Exercise matching: au moins 2 colonnes recommandées'); } if (!exercise.correct_matches || !Array.isArray(exercise.correct_matches)) { validation.errors.push('Exercise matching: correct_matches requis pour format multi-colonnes'); } } else if (exercise.leftColumn && exercise.rightColumn) { // Format traditionnel if (exercise.leftColumn.length !== exercise.rightColumn.length) { validation.warnings.push('Exercise matching: colonnes de tailles différentes'); } } else { validation.errors.push('Exercise matching: format invalide (colonnes manquantes)'); } } } /** * Valide les exercices à trous */ validateFillInBlanks(fillInBlanks, validation) { if (!Array.isArray(fillInBlanks)) { validation.errors.push('La section fillInBlanks doit être un tableau'); return; } for (const exercise of fillInBlanks) { if (!exercise.sentence) { validation.errors.push('Exercise fillInBlanks: sentence requis'); continue; } if (!exercise.sentence.includes('___')) { validation.warnings.push('Exercise fillInBlanks: aucun blank (___) trouvé dans la phrase'); } if (exercise.type === 'open_ended') { if (!exercise.aiPrompt && !exercise.acceptedAnswers) { validation.errors.push('Exercise fillInBlanks open_ended: aiPrompt ou acceptedAnswers requis'); } } else { if (!exercise.options || !exercise.correctAnswer) { validation.errors.push('Exercise fillInBlanks: options et correctAnswer requis'); } } } } /** * Calcule un score de qualité (0-100) */ calculateQualityScore(jsonContent, capabilities, compatibility) { let score = 0; // Score de base (métadonnées complètes) if (jsonContent.id) score += 5; if (jsonContent.name) score += 5; if (jsonContent.description) score += 5; if (jsonContent.difficulty_level) score += 5; if (jsonContent.original_lang && jsonContent.user_lang) score += 10; if (jsonContent.tags && jsonContent.tags.length > 0) score += 5; if (jsonContent.skills_covered && jsonContent.skills_covered.length > 0) score += 5; // Score de contenu éducatif (40 points max) if (capabilities.hasVocabulary) score += 10; if (capabilities.hasGrammar) score += 5; if (capabilities.hasSentences) score += 5; if (capabilities.hasExercises) score += 10; if (capabilities.hasAudioFiles) score += 5; if (capabilities.hasCulture) score += 5; // Bonus pour la richesse du contenu score += Math.min(15, capabilities.vocabularyDepth * 2.5); score += Math.min(10, capabilities.contentRichness); // Bonus pour la compatibilité des jeux const compatibleGames = Object.values(compatibility).filter(game => game.compatible).length; score += Math.min(10, compatibleGames * 2); return Math.round(Math.min(100, score)); } /** * Génère des suggestions d'amélioration */ generateSuggestions(jsonContent, capabilities, validation) { // Suggestions basées sur les capacités manquantes if (!capabilities.hasAudioFiles) { validation.suggestions.push('Ajoutez des fichiers audio pour débloquer les jeux de prononciation'); } if (!capabilities.hasExercises) { validation.suggestions.push('Ajoutez des exercices (fillInBlanks, corrections) pour plus d\'interactivité'); } if (!capabilities.hasCulture) { validation.suggestions.push('Ajoutez du contenu culturel pour enrichir l\'apprentissage'); } if (capabilities.vocabularyDepth < 3) { validation.suggestions.push('Enrichissez le vocabulaire avec des exemples et notes grammaticales'); } // Suggestions basées sur la compatibilité des jeux const incompatibleGames = Object.entries(validation.compatibility) .filter(([game, compat]) => !compat.compatible) .map(([game]) => game); if (incompatibleGames.length > 0) { validation.suggestions.push(`Jeux non compatibles: ${incompatibleGames.join(', ')} - vérifiez les requis de contenu`); } } /** * Convertit une spécification ultra-modulaire vers le format legacy */ async convertToLegacy(jsonContent) { const adaptedContent = this.jsonLoader.adapt(jsonContent); // Générer un module JavaScript compatible const jsModule = this.generateLegacyModule(adaptedContent); return { adaptedContent, jsModule, stats: this.jsonLoader.analyzeContent(adaptedContent) }; } /** * Génère un module JavaScript pour compatibilité legacy */ generateLegacyModule(adaptedContent) { const moduleName = this.toPascalCase(adaptedContent.id); return `// Module généré automatiquement depuis la spécification ultra-modulaire // ID: ${adaptedContent.id} // Généré le: ${new Date().toISOString()} window.ContentModules = window.ContentModules || {}; window.ContentModules.${moduleName} = ${JSON.stringify(adaptedContent, null, 4)}; console.log('📦 Module ${moduleName} chargé depuis spécification ultra-modulaire');`; } /** * Helpers */ getVocabularyLevelDescription(level) { const descriptions = { 1: 'Basique (chaînes simples)', 2: 'Standard (objets avec traduction)', 3: 'Enrichi (avec exemples)', 4: 'Avancé (avec étymologie)', 5: 'Expert (avec contexte culturel)', 6: 'Maître (avec techniques mnémotechniques)' }; return descriptions[level] || 'Niveau inconnu'; } toPascalCase(str) { return str.split(/[_-]/).map(word => word.charAt(0).toUpperCase() + word.slice(1) ).join(''); } } // Export global window.UltraModularValidator = UltraModularValidator; // Export Node.js (optionnel) if (typeof module !== 'undefined' && module.exports) { module.exports = UltraModularValidator; }