docs: add interactive playground and quick start guide

- playground.js: Interaktives Script zum Ausprobieren aller Features
  - Forgejo API Client Demo
  - Post-Listing (53 Posts)
  - Vollständiges Parsing-Beispiel
  - AMB-Metadaten-Analyse mit Validierung
  - Content-Statistiken (Überschriften, Links, Bilder)
  - AST-Struktur-Visualisierung
  - JSON-Export-Vorschau
  - Farbige Console-Ausgabe

- QUICKSTART.md: Schnelleinstieg für Entwickler
  - Playground-Anleitung
  - Code-Beispiele für alle Use Cases
  - Alle verfügbaren Posts aufgelistet
  - Erweiterte Optionen
  - Links zur weiteren Dokumentation

Ready to use! 🚀
This commit is contained in:
Jörg Lohrer 2025-10-01 15:53:36 +02:00
parent c31423d811
commit 9fe34cc743
2 changed files with 526 additions and 0 deletions

246
playground.js Normal file
View file

@ -0,0 +1,246 @@
/**
* Interaktives Playground zum Ausprobieren des Parsers
*
* Verwendung:
* node playground.js
*/
import { createForgejoClient } from './src/forgejo-client.js'
import { parseMarkdownString, extractHeadings, extractLinks, extractImages } from './src/parser.js'
import { validateAMBMetadata } from './src/extractors/amb-extractor.js'
// Farben für Console-Output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m'
}
function print(text, color = 'reset') {
console.log(`${colors[color]}${text}${colors.reset}`)
}
function section(title) {
console.log('\n' + '='.repeat(70))
print(title, 'bright')
console.log('='.repeat(70) + '\n')
}
async function playground() {
section('🎮 MDParser Playground')
print('Dieses Script zeigt die verschiedenen Funktionen des Parsers.', 'cyan')
print('Du kannst den Code in playground.js anpassen, um zu experimentieren.\n', 'cyan')
// 1. Forgejo Client Setup
section('1⃣ Forgejo API Client')
const client = createForgejoClient()
print(`✓ Client erstellt`, 'green')
print(` Repository: ${client.owner}/${client.repo}`, 'blue')
print(` Branch: ${client.branch}`, 'blue')
// Repository-Info
const repo = await client.getRepository()
print(` Beschreibung: ${repo.description}`, 'blue')
// 2. Posts auflisten
section('2⃣ Posts auflisten')
const posts = await client.listPosts()
print(`${posts.length} Posts gefunden`, 'green')
// Die ersten 10 Posts anzeigen
print('\nErste 10 Posts:', 'yellow')
posts.slice(0, 10).forEach((post, i) => {
console.log(` ${i + 1}. ${post.name}`)
})
// 3. Einen Post parsen
section('3⃣ Post parsen')
// Du kannst hier einen anderen Post wählen!
const selectedPost = '2025-04-20-OER-und-Symbole'
print(`📄 Parse: ${selectedPost}`, 'yellow')
const markdown = await client.getPostContent(selectedPost)
print(`✓ Markdown geladen: ${markdown.length} Zeichen`, 'green')
const result = await parseMarkdownString(markdown)
print(`✓ Erfolgreich geparst`, 'green')
// 4. Metadaten analysieren
section('4⃣ AMB-Metadaten')
if (result.metadata) {
const meta = result.metadata
console.log('\n📋 Basis-Informationen:')
console.log(` Titel: ${meta.name || 'N/A'}`)
console.log(` Typ: ${meta.type}`)
console.log(` Lizenz: ${meta.license || 'N/A'}`)
console.log(` Datum: ${meta.datePublished || 'N/A'}`)
console.log(` ID: ${meta.id || 'N/A'}`)
console.log(` Sprache: ${meta.inLanguage ? meta.inLanguage.join(', ') : 'N/A'}`)
if (meta.creator && meta.creator.length > 0) {
console.log('\n👥 Autoren:')
meta.creator.forEach((creator, i) => {
const name = creator.name || `${creator.givenName} ${creator.familyName}`
console.log(` ${i + 1}. ${name}`)
if (creator.id) console.log(` └─ ID: ${creator.id}`)
if (creator.affiliation) {
console.log(` └─ Affiliation: ${creator.affiliation.name}`)
}
})
}
if (meta.about && meta.about.length > 0) {
console.log('\n🏷 Themen:')
meta.about.forEach(topic => console.log(` - ${topic}`))
}
if (meta.learningResourceType && meta.learningResourceType.length > 0) {
console.log('\n📚 Lernressourcen-Typen:')
meta.learningResourceType.forEach(type => console.log(` - ${type}`))
}
// Validierung
const validation = validateAMBMetadata(meta)
console.log('\n✓ Validierung:')
console.log(` Status: ${validation.valid ? '✅ Gültig' : '⚠️ Unvollständig'}`)
if (validation.errors.length > 0) {
console.log(` Fehler: ${validation.errors.length}`)
validation.errors.forEach(err => console.log(` - ${err}`))
}
if (validation.warnings.length > 0) {
console.log(` Warnings: ${validation.warnings.length}`)
validation.warnings.slice(0, 3).forEach(warn => console.log(` - ${warn}`))
if (validation.warnings.length > 3) {
console.log(` ... und ${validation.warnings.length - 3} weitere`)
}
}
if (meta._warnings && meta._warnings.length > 0) {
console.log('\n⚠ Parser-Warnings:')
meta._warnings.forEach(w => console.log(` - ${w}`))
}
} else {
print('⚠️ Keine Metadaten gefunden', 'yellow')
}
// 5. Content-Analyse
section('5⃣ Content-Analyse')
console.log('📝 Content-Statistik:')
console.log(` Länge: ${result.content.length} Zeichen`)
console.log(` Zeilen: ${result.content.split('\n').length}`)
console.log(` Wörter (ca.): ${result.content.split(/\s+/).length}`)
// Überschriften
const headings = extractHeadings(result.ast)
console.log(`\n📑 Überschriften: ${headings.length}`)
headings.forEach(h => {
const indent = ' ' + ' '.repeat(h.level - 2)
console.log(`${indent}H${h.level}: ${h.text}`)
})
// Links
const links = extractLinks(result.ast)
if (links.length > 0) {
console.log(`\n🔗 Links: ${links.length}`)
links.slice(0, 5).forEach(link => {
console.log(` - ${link.text || 'Kein Text'}`)
console.log(`${link.url}`)
})
if (links.length > 5) {
console.log(` ... und ${links.length - 5} weitere`)
}
}
// Bilder
const images = extractImages(result.ast)
if (images.length > 0) {
console.log(`\n🖼️ Bilder: ${images.length}`)
images.forEach(img => {
console.log(` - ${img.alt || 'Kein Alt-Text'}`)
console.log(`${img.url}`)
})
}
// 6. AST-Struktur
section('6⃣ AST-Struktur (Auszug)')
console.log('🌲 Root-Node:')
console.log(` Type: ${result.ast.type}`)
console.log(` Children: ${result.ast.children?.length || 0}`)
if (result.ast.children && result.ast.children.length > 0) {
console.log('\n Erste 5 Child-Nodes:')
result.ast.children.slice(0, 5).forEach((child, i) => {
console.log(` ${i + 1}. ${child.type}`)
if (child.depth) console.log(` └─ depth: ${child.depth}`)
if (child.value) {
const preview = child.value.substring(0, 50)
console.log(` └─ value: "${preview}${child.value.length > 50 ? '...' : ''}"`)
}
})
if (result.ast.children.length > 5) {
console.log(` ... und ${result.ast.children.length - 5} weitere`)
}
}
// 7. Rohdaten-Export
section('7⃣ JSON-Export')
const exportData = {
metadata: result.metadata,
content: result.content.substring(0, 500) + '...',
stats: {
chars: result.content.length,
lines: result.content.split('\n').length,
headings: headings.length,
links: links.length,
images: images.length
}
}
console.log('📦 Export-Vorschau (erste 500 Zeichen Content):')
console.log(JSON.stringify(exportData, null, 2))
// 8. Tipps
section('💡 Tipps zum Experimentieren')
print('Du kannst dieses Script anpassen:', 'cyan')
console.log('\n1. Anderen Post wählen:')
console.log(' const selectedPost = "2024-08-05-hello-world"')
console.log('\n2. Mehrere Posts analysieren:')
console.log(' for (const post of posts.slice(0, 5)) { ... }')
console.log('\n3. Parser-Optionen anpassen:')
console.log(' const result = await parseMarkdownString(markdown, {')
console.log(' extractYaml: true,')
console.log(' parseGfm: true,')
console.log(' extractAMB: true')
console.log(' })')
console.log('\n4. Weitere Funktionen ausprobieren:')
console.log(' import { extractYAML, hasYAML } from "./src/index.js"')
section('✅ Fertig!')
print('Viel Spaß beim Experimentieren! 🎉', 'green')
print('Für mehr Infos: README.md oder docs/ARCHITECTURE.md\n', 'cyan')
}
// Fehlerbehandlung
playground().catch(error => {
console.error('\n❌ Fehler:', error.message)
console.error(error.stack)
process.exit(1)
})