diff --git a/test-batch.js b/test-batch.js new file mode 100644 index 0000000..577b881 --- /dev/null +++ b/test-batch.js @@ -0,0 +1,186 @@ +/** + * Batch-Test: Analysiert mehrere Posts aus dem Repository + * und zeigt Statistiken über die Metadaten-Qualität + */ + +import { createForgejoClient, parseMarkdownString, validateAMBMetadata } from './src/index.js' + +const colors = { + reset: '\x1b[0m', + bright: '\x1b[1m', + green: '\x1b[32m', + yellow: '\x1b[33m', + red: '\x1b[31m', + blue: '\x1b[34m', + cyan: '\x1b[36m' +} + +function print(text, color = 'reset') { + console.log(`${colors[color]}${text}${colors.reset}`) +} + +async function testMultiplePosts() { + print('\n🔍 BATCH-TEST: Mehrere Posts analysieren\n', 'bright') + + const client = createForgejoClient() + + // Alle Posts abrufen + print('📡 Rufe alle Posts ab...', 'cyan') + const allPosts = await client.listPosts() + print(`✅ ${allPosts.length} Posts gefunden\n`, 'green') + + // Alle Posts testen + const postsToTest = allPosts + + const results = [] + const stats = { + total: 0, + withLicense: 0, + withCreator: 0, + withOrcid: 0, + withRor: 0, + withAbout: 0, + withLearningResourceType: 0, + withEducationalLevel: 0, + valid: 0, + avgContentLength: 0, + errors: [] + } + + print('🔬 Analysiere Posts...\n', 'cyan') + + for (let i = 0; i < postsToTest.length; i++) { + const post = postsToTest[i] + const num = `[${i + 1}/${postsToTest.length}]` + + try { + const markdown = await client.getPostContent(post.name) + const result = await parseMarkdownString(markdown) + + stats.total++ + stats.avgContentLength += result.content.length + + const meta = result.metadata + const validation = validateAMBMetadata(meta) + + // Statistiken sammeln + if (meta.license) stats.withLicense++ + if (meta.creator && meta.creator.length > 0) { + stats.withCreator++ + if (meta.creator.some(c => c.id && c.id.includes('orcid'))) stats.withOrcid++ + if (meta.creator.some(c => c.affiliation?.id && c.affiliation.id.includes('ror'))) stats.withRor++ + } + if (meta.about && meta.about.length > 0) stats.withAbout++ + if (meta.learningResourceType && meta.learningResourceType.length > 0) stats.withLearningResourceType++ + if (meta.educationalLevel && meta.educationalLevel.length > 0) stats.withEducationalLevel++ + if (validation.valid) stats.valid++ + + // Detaillierte Ausgabe + const status = validation.valid ? '✅' : '⚠️' + console.log(`${status} ${num} ${post.name}`) + console.log(` Titel: ${meta.name || 'N/A'}`) + console.log(` Lizenz: ${meta.license ? '✅' : '❌'}`) + console.log(` Creator: ${meta.creator?.length || 0} (ORCID: ${meta.creator?.some(c => c.id?.includes('orcid')) ? '✅' : '❌'})`) + console.log(` About: ${meta.about?.length || 0} Themen`) + console.log(` LearningResourceType: ${meta.learningResourceType?.length || 0}`) + console.log(` Content: ${result.content.length} Zeichen`) + console.log(` Validierung: ${validation.valid ? 'GÜLTIG' : `${validation.errors.length} Fehler`}`) + + if (validation.errors.length > 0) { + console.log(` Fehler: ${validation.errors.join(', ')}`) + } + + console.log() + + results.push({ + name: post.name, + metadata: meta, + validation, + contentLength: result.content.length + }) + + } catch (error) { + print(`❌ ${num} ${post.name}`, 'red') + print(` Fehler: ${error.message}`, 'red') + console.log() + stats.errors.push({ post: post.name, error: error.message }) + } + } + + // Zusammenfassung + print('\n' + '='.repeat(70), 'bright') + print('📊 ZUSAMMENFASSUNG', 'bright') + print('='.repeat(70) + '\n', 'bright') + + console.log('📈 Statistiken:') + console.log(` Analysiert: ${stats.total} Posts`) + console.log(` Gültig (AMB): ${stats.valid} / ${stats.total} (${Math.round(stats.valid/stats.total*100)}%)`) + console.log() + + console.log('📋 Metadaten-Vollständigkeit:') + console.log(` Lizenz: ${stats.withLicense} / ${stats.total} (${Math.round(stats.withLicense/stats.total*100)}%)`) + console.log(` Creator: ${stats.withCreator} / ${stats.total} (${Math.round(stats.withCreator/stats.total*100)}%)`) + console.log(` └─ mit ORCID: ${stats.withOrcid} / ${stats.withCreator} (${stats.withCreator ? Math.round(stats.withOrcid/stats.withCreator*100) : 0}%)`) + console.log(` └─ mit ROR: ${stats.withRor} / ${stats.withCreator} (${stats.withCreator ? Math.round(stats.withRor/stats.withCreator*100) : 0}%)`) + console.log(` About (Themen): ${stats.withAbout} / ${stats.total} (${Math.round(stats.withAbout/stats.total*100)}%)`) + console.log(` LearningResourceType: ${stats.withLearningResourceType} / ${stats.total} (${Math.round(stats.withLearningResourceType/stats.total*100)}%)`) + console.log(` EducationalLevel: ${stats.withEducationalLevel} / ${stats.total} (${Math.round(stats.withEducationalLevel/stats.total*100)}%)`) + console.log() + + console.log('📝 Content:') + console.log(` Durchschnittliche Länge: ${Math.round(stats.avgContentLength / stats.total)} Zeichen`) + console.log(` Kürzester: ${Math.min(...results.map(r => r.contentLength))} Zeichen`) + console.log(` Längster: ${Math.max(...results.map(r => r.contentLength))} Zeichen`) + console.log() + + if (stats.errors.length > 0) { + print(`❌ Fehler: ${stats.errors.length}`, 'red') + stats.errors.forEach(err => { + console.log(` - ${err.post}: ${err.error}`) + }) + console.log() + } + + // Top 5 Posts mit vollständigsten Metadaten + print('🏆 TOP 5 Posts mit vollständigsten Metadaten:', 'cyan') + const scored = results.map(r => { + let score = 0 + if (r.metadata.license) score++ + if (r.metadata.creator?.length > 0) score++ + if (r.metadata.creator?.some(c => c.id)) score++ + if (r.metadata.about?.length > 0) score++ + if (r.metadata.learningResourceType?.length > 0) score++ + if (r.metadata.educationalLevel?.length > 0) score++ + if (r.validation.valid) score++ + return { ...r, score } + }) + + scored.sort((a, b) => b.score - a.score) + scored.slice(0, 5).forEach((r, i) => { + console.log(` ${i + 1}. ${r.name}`) + console.log(` Score: ${r.score}/7`) + console.log(` Titel: ${r.metadata.name}`) + }) + console.log() + + // Posts mit fehlenden Pflichtfeldern + const incomplete = results.filter(r => !r.validation.valid) + if (incomplete.length > 0) { + print(`⚠️ ${incomplete.length} Posts mit fehlenden Pflichtfeldern:`, 'yellow') + incomplete.forEach(r => { + console.log(` - ${r.name}`) + if (r.validation.errors.length > 0) { + console.log(` Fehlt: ${r.validation.errors.join(', ')}`) + } + }) + } + + print('\n✅ Batch-Test abgeschlossen!\n', 'green') +} + +// Ausführen +testMultiplePosts().catch(error => { + console.error('\n❌ Fehler:', error.message) + console.error(error.stack) + process.exit(1) +})