commit fbd6630f6dcc586961ffc738ad7c443c0e5272a6 Author: Jörg Lohrer Date: Wed Oct 1 15:28:30 2025 +0200 chore: initial project setup - Git repository mit .gitignore und .editorconfig - NPM-Projekt mit package.json und Dependencies - Projekt-Struktur (src/, docs/, examples/, test/) - Umfassende README.md mit Features und Roadmap - Architektur-Dokumentation mit Mermaid-Diagrammen - Design-Entscheidungen dokumentiert - .env.example für Forgejo API-Konfiguration - MIT Lizenz und Contributing Guidelines Status: Phase 1 - Core Parser (Setup abgeschlossen) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..23de5de --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# EditorConfig is awesome: https://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false +max_line_length = off + +[*.json] +indent_size = 2 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f050bf3 --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +# Forgejo/Gitea API Configuration +FORGEJO_API_BASE_URL=https://git.rpi-virtuell.de/api/v1 +FORGEJO_OWNER=Comenius-Institut +FORGEJO_REPO=FOERBICO_und_rpi-virtuell +FORGEJO_BRANCH=main +FORGEJO_TOKEN= + +# Optional: API Rate Limiting +API_RATE_LIMIT_DELAY_MS=100 + +# Logging +LOG_LEVEL=info diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca8a07a --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +.pnpm-debug.log* + +# Environment variables +.env +.env.local +.env.*.local + +# IDE / Editor +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/extensions.json +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# Build / Distribution +dist/ +build/ +*.tgz + +# Test coverage +coverage/ +.nyc_output/ + +# Logs +logs/ +*.log + +# Temporary files +tmp/ +temp/ +*.tmp + +# OS +Thumbs.db diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..db2252b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,82 @@ +# Contributing to MDParser + +Vielen Dank für dein Interesse an MDParser! 🎉 + +## 🚀 Quick Start + +1. **Fork & Clone** + ```bash + git clone https://git.rpi-virtuell.de/dein-username/mdparser.git + cd mdparser + ``` + +2. **Dependencies installieren** + ```bash + npm install + ``` + +3. **Branch erstellen** + ```bash + git checkout -b feature/mein-feature + ``` + +4. **Entwickeln & Testen** + ```bash + npm test + npm run lint + ``` + +5. **Commit & Push** + ```bash + git commit -m "feat: beschreibung" + git push origin feature/mein-feature + ``` + +6. **Pull Request erstellen** + +## 📝 Code-Style + +- **ESLint** für Linting +- **Prettier** für Formatierung +- **ESM** (ES Modules) verwenden +- **JSDoc** für Funktions-Dokumentation + +```javascript +/** + * Parst eine Markdown-Datei mit YAML Front Matter + * @param {string} filePath - Pfad zur Markdown-Datei + * @param {Object} options - Optionale Konfiguration + * @returns {Promise} Parsed result + */ +export async function parseMarkdownFile(filePath, options = {}) { + // ... +} +``` + +## 🧪 Testing + +- Alle neuen Features benötigen Tests +- Tests mit `npm test` ausführen +- Test-Fixtures in `test/fixtures/` ablegen + +## 📦 Commit-Conventions + +Wir verwenden [Conventional Commits](https://www.conventionalcommits.org/): + +- `feat:` - Neues Feature +- `fix:` - Bugfix +- `docs:` - Dokumentation +- `test:` - Tests +- `refactor:` - Code-Refactoring +- `chore:` - Maintenance + +Beispiele: +``` +feat: add WordPress transformer +fix: handle missing YAML gracefully +docs: update API documentation +``` + +## 📄 Lizenz + +MIT - siehe [LICENSE](LICENSE) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4375f74 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Jörg Lohrer, Comenius-Institut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..068b9e2 --- /dev/null +++ b/README.md @@ -0,0 +1,257 @@ +# 📚 MDParser - Markdown to JSON Parser + +Ein modularer Parser für Markdown-Dateien mit YAML Front Matter, optimiert für AMB-Metadatenstandard (schema.org) und Transformation zu WordPress & Nostr. + +## 🎯 Features + +- ✅ **YAML Front Matter Parsing** - Volle Unterstützung für komplexe YAML-Strukturen +- ✅ **AMB-Metadaten** - Schema.org-konforme Metadaten-Extraktion +- ✅ **Forgejo/Gitea API** - Direkter Zugriff auf Git-Repository-Inhalte +- ✅ **AST-basiert** - Strukturierte Markdown-Verarbeitung mit unified/remark +- ✅ **Isomorph** - Funktioniert in Node.js und im Browser +- ✅ **Erweiterbar** - Modulare Architektur für Custom-Transformationen +- 🚧 **WordPress REST API v2** - Transformer (geplant) +- 🚧 **Nostr NIP-23** - Long-form Content Transformer (geplant) + +## 📦 Installation + +```bash +# Repository klonen +git clone https://git.rpi-virtuell.de/Comenius-Institut/mdparser.git +cd mdparser + +# Dependencies installieren +npm install + +# Environment-Variablen konfigurieren +cp .env.example .env +# .env bearbeiten und API-Zugangsdaten eintragen +``` + +## 🚀 Quick Start + +```javascript +import { parseMarkdownFile } from './src/parser.js'; + +// Markdown mit YAML Front Matter parsen +const result = await parseMarkdownFile('./content/posts/example/index.md'); + +console.log(result.metadata); // Schema.org Metadaten +console.log(result.content); // Markdown AST +console.log(result.html); // HTML-Output (optional) +``` + +## 🏗️ Projekt-Struktur + +``` +mdparser/ +├── src/ +│ ├── index.js # Haupteinstiegspunkt +│ ├── parser.js # Core Parser (unified/remark) +│ ├── forgejo-client.js # Forgejo API Client +│ ├── extractors/ +│ │ ├── yaml-extractor.js # YAML Front Matter Parsing +│ │ └── amb-extractor.js # AMB/Schema.org Metadaten +│ └── transformers/ # (geplant) +│ ├── wordpress.js +│ └── nostr.js +├── examples/ +│ ├── parse-forgejo.js # Beispiel: Forgejo API +│ ├── parse-local.js # Beispiel: Lokale Datei +│ └── parse-url.js # Beispiel: HTTP URL +├── test/ +│ └── parser.test.js +├── docs/ +│ ├── ARCHITECTURE.md # Architektur-Dokumentation +│ ├── API.md # API-Referenz +│ └── DECISIONS.md # Design-Entscheidungen +├── .env.example +├── .gitignore +├── .editorconfig +├── package.json +└── README.md +``` + +## 🔧 Konfiguration + +### Environment-Variablen (`.env`) + +```bash +# Forgejo/Gitea API +FORGEJO_API_BASE_URL=https://git.rpi-virtuell.de/api/v1 +FORGEJO_OWNER=Comenius-Institut +FORGEJO_REPO=FOERBICO_und_rpi-virtuell +FORGEJO_BRANCH=main +FORGEJO_TOKEN= # Optional für private Repos + +# API Rate Limiting +API_RATE_LIMIT_DELAY_MS=100 + +# Logging +LOG_LEVEL=info +``` + +## 📖 Verwendung + +### 1. Lokale Markdown-Datei parsen + +```javascript +import { parseMarkdownFile } from './src/parser.js'; + +const result = await parseMarkdownFile('./content/post/index.md'); +console.log(result); +``` + +### 2. Forgejo API verwenden + +```javascript +import { ForgejoClient } from './src/forgejo-client.js'; + +const client = new ForgejoClient({ + baseUrl: 'https://git.rpi-virtuell.de/api/v1', + owner: 'Comenius-Institut', + repo: 'FOERBICO_und_rpi-virtuell' +}); + +// Einzelne Datei abrufen +const content = await client.getFileContent( + 'Website/content/posts/2025-04-20-OER-und-Symbole/index.md' +); + +// Alle Posts auflisten +const posts = await client.listPosts('Website/content/posts'); +``` + +### 3. AMB-Metadaten extrahieren + +```javascript +import { extractAMBMetadata } from './src/extractors/amb-extractor.js'; + +const ambData = extractAMBMetadata(result.yaml); + +// Ausgabe: Schema.org-konforme Struktur +console.log(ambData.name); // Titel +console.log(ambData.creator); // Autoren +console.log(ambData.license); // Lizenz +console.log(ambData.about); // Themen/Tags +``` + +## 🎓 AMB-Metadatenstandard + +Dieses Projekt unterstützt den **AMB-Standard** (Metadaten für Bildungsressourcen) basierend auf schema.org: + +**Unterstützte Felder:** +- `@context`, `type`, `name`, `description` +- `creator` (Person/Organization mit ORCID/ROR) +- `license`, `inLanguage`, `datePublished` +- `about` (Hochschulfächersystematik) +- `learningResourceType`, `educationalLevel` +- `image`, `id` (URL) + +Siehe [AMB-Dokumentation](https://dini-ag-kim.github.io/amb/) für Details. + +## 🔌 API-Referenz + +### `parseMarkdownFile(filePath, options)` + +Parst eine Markdown-Datei mit YAML Front Matter. + +**Parameter:** +- `filePath` (string) - Pfad zur Markdown-Datei +- `options` (object) - Optionale Konfiguration + - `extractYaml` (boolean) - YAML extrahieren (default: true) + - `parseGfm` (boolean) - GitHub Flavored Markdown (default: true) + - `toHtml` (boolean) - HTML-Output generieren (default: false) + +**Rückgabe:** +```javascript +{ + yaml: { /* YAML Front Matter als Objekt */ }, + metadata: { /* Extrahierte AMB-Metadaten */ }, + ast: { /* Markdown Abstract Syntax Tree */ }, + content: { /* Reiner Content ohne Front Matter */ }, + html: "..." // Optional +} +``` + +Siehe [docs/API.md](./docs/API.md) für vollständige API-Dokumentation. + +## 🧪 Tests + +```bash +# Tests ausführen +npm test + +# Mit Watch-Mode während Entwicklung +npm run dev +``` + +## 🤝 Entwicklung + +### Technologie-Stack + +| Bereich | Bibliothek | Begründung | +|---------|-----------|------------| +| **Markdown Parser** | unified + remark-parse | AST-basiert, erweiterbar, isomorph | +| **YAML Parser** | yaml | Robust, spec-compliant | +| **Front Matter** | remark-frontmatter | Nahtlose Integration mit remark | +| **GFM Support** | remark-gfm | Tabellen, Task Lists, etc. | +| **HTTP Client** | native fetch | Standard, keine Dependencies | + +### Warum unified/remark? + +✅ **Isomorph** - Node.js + Browser +✅ **AST-basiert** - Präzise Manipulation +✅ **Erweiterbar** - Riesiges Plugin-Ökosystem +✅ **Standard** - MDAST ist De-facto-Standard +✅ **Aktiv** - Große Community, gute Wartung + +Siehe [docs/DECISIONS.md](./docs/DECISIONS.md) für detaillierte Design-Entscheidungen. + +## 📋 Roadmap + +### Phase 1: Core Parser (aktuell) +- [x] Projekt-Setup mit Git, npm, Dokumentation +- [ ] Markdown + YAML Parser implementieren +- [ ] Forgejo API Client +- [ ] AMB-Metadaten-Extraktor +- [ ] Beispiele und Tests + +### Phase 2: Transformers (nächster Schritt) +- [ ] WordPress REST API v2 Transformer + - title, content, excerpt, featured_media + - tags, categories, custom fields + - author mapping +- [ ] Nostr NIP-23 Transformer + - d (identifier), title, summary + - published_at, image + - t (tags), e/a/p (references) + +### Phase 3: Erweiterte Features +- [ ] Browser-Build (ESM) +- [ ] CLI-Tool +- [ ] Batch-Processing +- [ ] Caching-Strategie +- [ ] Error-Handling & Logging + +## 📄 Lizenz + +MIT License - siehe [LICENSE](./LICENSE) für Details. + +## 👥 Autoren + +- **Jörg Lohrer** - [ORCID](https://orcid.org/0000-0002-9282-0406) +- Comenius-Institut - [ROR](https://ror.org/025e8aw85) + +## 🔗 Links + +- **Projekt-Repository**: https://git.rpi-virtuell.de/Comenius-Institut/mdparser +- **Forgejo API**: https://git.rpi-virtuell.de/api/swagger +- **AMB-Standard**: https://dini-ag-kim.github.io/amb/ +- **unified/remark**: https://unifiedjs.com/ +- **WordPress REST API**: https://developer.wordpress.org/rest-api/ +- **Nostr NIPs**: https://github.com/nostr-protocol/nips + +--- + +**Status:** 🚧 In aktiver Entwicklung - Phase 1 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..42c8ed2 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,435 @@ +# 🏛️ Architektur-Dokumentation + +## Überblick + +MDParser ist ein modularer, erweiterbarer Parser für Markdown-Dateien mit YAML Front Matter, optimiert für die Verarbeitung von AMB-konformen Bildungsressourcen. + +## 📐 Architektur-Diagramm + +```mermaid +flowchart TB + subgraph "Datenquellen" + File["📄 Lokale Datei"] + URL["🌐 HTTP/HTTPS URL"] + API["🔌 Forgejo/Gitea API"] + end + + subgraph "Core Parser" + Fetch["Fetch Module
Daten abrufen"] + Unified["unified Pipeline
remark-parse
remark-frontmatter
remark-gfm"] + YAMLParser["YAML Parser
yaml library"] + end + + subgraph "Extraction Layer" + FrontMatter["Front Matter
Extractor"] + AMBExtract["AMB Metadata
Extractor
(schema.org)"] + ContentExtract["Content
Extractor
(AST)"] + end + + subgraph "Output Formats" + JSON["📦 JSON
Structured Data"] + AST["🌲 MDAST
Abstract Syntax Tree"] + HTML["📝 HTML
(optional)"] + end + + subgraph "Transformers (Phase 2)" + WP["WordPress
REST API v2"] + Nostr["Nostr
NIP-23"] + end + + File --> Fetch + URL --> Fetch + API --> Fetch + + Fetch --> Unified + Unified --> YAMLParser + Unified --> FrontMatter + + FrontMatter --> AMBExtract + FrontMatter --> ContentExtract + + AMBExtract --> JSON + ContentExtract --> AST + ContentExtract --> HTML + + JSON --> WP + JSON --> Nostr + AST --> WP + AST --> Nostr + + style Unified fill:#e1f5ff,stroke:#01579b + style AMBExtract fill:#f3e5f5,stroke:#4a148c + style JSON fill:#e8f5e9,stroke:#1b5e20 +``` + +## 🎯 Design-Prinzipien + +### 1. **Modularität** +- Jede Komponente hat eine klare Verantwortung +- Lose Kopplung zwischen Modulen +- Einfach erweiterbar durch Plugin-System + +### 2. **Isomorphie** +- Code funktioniert in Node.js **und** Browser +- Keine Node.js-spezifischen APIs im Core +- Native `fetch` für HTTP-Requests + +### 3. **Standards-Konformität** +- AMB-Metadatenstandard (schema.org) +- MDAST (Markdown Abstract Syntax Tree) +- CommonMark + GFM (GitHub Flavored Markdown) + +### 4. **Fehlertoleranz** +- Graceful Degradation bei fehlenden Metadaten +- Validierung mit aussagekräftigen Fehlermeldungen +- Optionale Felder werden sauber behandelt + +## 📦 Modul-Struktur + +### Core Module + +#### 1. **Parser (`src/parser.js`)** +```javascript +export async function parseMarkdownFile(filePath, options) { + // Haupteinstiegspunkt für Markdown-Parsing + // Orchestriert unified Pipeline + return { + yaml: {}, // Rohes YAML Front Matter + metadata: {}, // Extrahierte AMB-Metadaten + ast: {}, // Markdown AST + content: "", // Reiner Content + html: "" // Optional: HTML-Output + } +} +``` + +**Technologie:** unified + remark Ökosystem + +**Plugins:** +- `remark-parse` - Markdown → AST +- `remark-frontmatter` - YAML Front Matter Support +- `remark-gfm` - GitHub Flavored Markdown +- `remark-stringify` - AST → Markdown (optional) +- `remark-html` - AST → HTML (optional) + +#### 2. **Forgejo Client (`src/forgejo-client.js`)** +```javascript +export class ForgejoClient { + constructor(config) { /* ... */ } + + async getFileContent(path) { /* ... */ } + async listDirectory(path) { /* ... */ } + async listPosts(postsDir) { /* ... */ } + async getRepository() { /* ... */ } +} +``` + +**API-Endpoints:** +- `/repos/{owner}/{repo}/contents/{path}` - Dateiinhalt +- `/repos/{owner}/{repo}/git/trees/{sha}` - Verzeichnis-Listing +- Content wird Base64-dekodiert + +#### 3. **YAML Extractor (`src/extractors/yaml-extractor.js`)** +```javascript +export function extractYAML(markdownContent) { + // Extrahiert YAML Front Matter + // Parst mit yaml library + return yamlObject +} +``` + +**Technologie:** `yaml` library (v2.x) + +**Features:** +- Komplexe YAML-Strukturen +- Arrays, nested Objects +- Multi-line Strings +- Datum-Parsing + +#### 4. **AMB Metadata Extractor (`src/extractors/amb-extractor.js`)** +```javascript +export function extractAMBMetadata(yamlObject) { + // Transformiert YAML → Schema.org + // Validiert AMB-Konformität + return ambMetadata +} +``` + +**Mapping:** +```javascript +{ + "@context": "https://schema.org/", + "type": "LearningResource", + "name": yaml.commonMetadata.name, + "description": yaml.commonMetadata.description, + "creator": mapCreators(yaml.commonMetadata.creator), + "license": yaml.commonMetadata.license, + "inLanguage": yaml.commonMetadata.inLanguage, + "datePublished": yaml.commonMetadata.datePublished, + "about": yaml.commonMetadata.about, + "image": yaml.commonMetadata.image, + "id": yaml.commonMetadata.id, + "learningResourceType": yaml.commonMetadata.learningResourceType, + "educationalLevel": yaml.commonMetadata.educationalLevel +} +``` + +### Transformation Layer (Phase 2) + +#### 5. **WordPress Transformer (`src/transformers/wordpress.js`)** +```javascript +export function transformToWordPress(parsedData) { + return { + title: "", + content: "", + excerpt: "", + featured_media: 0, + tags: [], + categories: [], + meta: {}, + author: 0 + } +} +``` + +**WordPress REST API v2 Format** + +#### 6. **Nostr Transformer (`src/transformers/nostr.js`)** +```javascript +export function transformToNostr(parsedData) { + return { + kind: 30023, // NIP-23 Long-form + tags: [ + ["d", ""], // unique identifier + ["title", ""], + ["summary", ""], + ["published_at", ""], + ["image", ""], + ["t", ""], // hashtags + ["e", ""], // event refs + ["a", ""], // article refs + ["p", ""] // pubkey refs + ], + content: "" // Markdown content + } +} +``` + +## 🔄 Datenfluss + +### 1. Parsing-Pipeline + +```mermaid +sequenceDiagram + participant Client + participant Parser + participant Unified + participant YAML + participant AMB + + Client->>Parser: parseMarkdownFile(path) + Parser->>Unified: process(markdown) + Unified->>YAML: extract front matter + YAML-->>Parser: yamlObject + Parser->>AMB: extractAMBMetadata(yaml) + AMB-->>Parser: ambMetadata + Unified-->>Parser: ast + Parser-->>Client: { yaml, metadata, ast, content } +``` + +### 2. Forgejo API Integration + +```mermaid +sequenceDiagram + participant Client + participant ForgejoClient + participant API as Forgejo API + participant Parser + + Client->>ForgejoClient: getFileContent(path) + ForgejoClient->>API: GET /repos/.../contents/... + API-->>ForgejoClient: { content: base64, ... } + ForgejoClient->>ForgejoClient: decode base64 + ForgejoClient-->>Client: markdown string + Client->>Parser: parseMarkdownFile(markdown) + Parser-->>Client: parsed data +``` + +### 3. Transformation (Phase 2) + +```mermaid +flowchart LR + Parse["Parsed Data
{yaml, metadata, ast}"] + WPT["WordPress
Transformer"] + NostrT["Nostr
Transformer"] + WPAPI["WordPress
REST API"] + NostrRelay["Nostr
Relay"] + + Parse --> WPT + Parse --> NostrT + + WPT --> WPAPI + NostrT --> NostrRelay + + style Parse fill:#e8f5e9 + style WPT fill:#fff3e0 + style NostrT fill:#f3e5f5 +``` + +## 🛠️ Technologie-Entscheidungen + +### Warum unified/remark? + +| Alternative | Pro | Contra | Entscheidung | +|-------------|-----|--------|--------------| +| **marked** | ✅ Sehr populär
✅ Einfach | ❌ HTML-fokussiert
❌ Kein AST | ❌ Abgelehnt | +| **markdown-it** | ✅ Erweiterbar
✅ Performance | ❌ Komplexe API
❌ HTML-fokussiert | ❌ Abgelehnt | +| **unified/remark** | ✅ AST-basiert
✅ Isomorph
✅ Plugin-System
✅ Standard | ⚠️ Lernkurve | ✅ **GEWÄHLT** | +| **gray-matter + marked** | ✅ Einfach | ❌ Weniger strukturiert | ⚠️ Fallback | + +### Warum `yaml` library? + +| Alternative | Pro | Contra | Entscheidung | +|-------------|-----|--------|--------------| +| **js-yaml** | ✅ Populär | ❌ Größere Bundle-Size | ❌ Abgelehnt | +| **yaml** | ✅ Modern
✅ Spec-compliant
✅ Klein | - | ✅ **GEWÄHLT** | +| JSON.parse | ✅ Native | ❌ Kein YAML-Support | ❌ Nicht geeignet | + +### Warum native `fetch`? + +- ✅ Standard in Node.js 18+ +- ✅ Identische API im Browser +- ✅ Keine Dependencies +- ✅ Async/await Support + +## 📊 Performance-Überlegungen + +### Caching-Strategie + +```javascript +// Optional: Cache für häufig abgerufene Dateien +const cache = new Map() + +async function parseWithCache(path, options) { + const cacheKey = `${path}-${JSON.stringify(options)}` + + if (cache.has(cacheKey)) { + return cache.get(cacheKey) + } + + const result = await parseMarkdownFile(path, options) + cache.set(cacheKey, result) + + return result +} +``` + +### Rate Limiting für APIs + +```javascript +// Forgejo API: Max. 10 Requests/Sekunde +const rateLimiter = new RateLimiter({ + tokensPerInterval: 10, + interval: 1000 +}) +``` + +## 🔒 Sicherheit + +### Input-Validierung + +- YAML-Bombing-Schutz (max. depth/size) +- Path-Traversal-Schutz bei Dateizugriffen +- Content-Type-Validierung bei API-Requests + +### Sanitization + +- XSS-Schutz bei HTML-Output (optional mit DOMPurify) +- SQL-Injection-Schutz bei DB-Integration (Phase 2) + +## 🧪 Testing-Strategie + +### Unit Tests +``` +test/ +├── parser.test.js +├── yaml-extractor.test.js +├── amb-extractor.test.js +├── forgejo-client.test.js +└── transformers/ + ├── wordpress.test.js + └── nostr.test.js +``` + +### Integration Tests +- End-to-End mit echtem Forgejo-Repository +- Mocking der API-Responses + +### Test-Fixtures +``` +test/fixtures/ +├── valid-amb.md +├── missing-metadata.md +├── complex-yaml.md +└── github-flavored.md +``` + +## 🚀 Deployment-Szenarien + +### 1. **Node.js CLI** +```bash +npm install -g mdparser +mdparser parse ./content/post.md +``` + +### 2. **Node.js Library** +```javascript +import { parseMarkdownFile } from 'mdparser' +const result = await parseMarkdownFile('./post.md') +``` + +### 3. **Browser (ESM)** +```html + +``` + +### 4. **Serverless Function** +```javascript +// Vercel/Netlify Function +export default async function handler(req, res) { + const result = await parseMarkdownFile(req.body.url) + res.json(result) +} +``` + +## 📈 Roadmap & Erweiterungen + +### Phase 1: Core Parser ✅ (aktuell) +- [x] Projekt-Setup +- [ ] Parser-Implementierung +- [ ] Forgejo-Client +- [ ] AMB-Extraktor +- [ ] Tests & Dokumentation + +### Phase 2: Transformers 🚧 +- [ ] WordPress-Integration +- [ ] Nostr-Integration +- [ ] Batch-Processing + +### Phase 3: Advanced Features 🔮 +- [ ] Browser-Build +- [ ] CLI-Tool +- [ ] Webhook-Support +- [ ] Real-time Sync +- [ ] GraphQL-API + +## 🤝 Contribution Guidelines + +Siehe [CONTRIBUTING.md](../CONTRIBUTING.md) für Details zu: +- Code-Style (ESLint + Prettier) +- Commit-Conventions +- Pull-Request-Prozess +- Testing-Requirements diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md new file mode 100644 index 0000000..2ee2eaa --- /dev/null +++ b/docs/DECISIONS.md @@ -0,0 +1,344 @@ +# 🎯 Design-Entscheidungen + +Dieses Dokument dokumentiert wichtige technische Entscheidungen und deren Begründungen. + +## 1. Parser-Technologie: unified/remark + +**Entscheidung:** unified + remark als Core-Parser + +**Datum:** 2025-10-01 + +### Kontext +Es wurden mehrere Markdown-Parser für die Verarbeitung von Bildungsressourcen mit YAML Front Matter evaluiert. + +### Alternativen + +| Parser | Vorteile | Nachteile | Score | +|--------|----------|-----------|-------| +| **marked** | Sehr populär (30k+ GitHub Stars)
Einfache API
Gute Performance | Fokus auf HTML-Output
Kein AST-Zugriff
Begrenzte Erweiterbarkeit | 6/10 | +| **markdown-it** | Erweiterbar durch Plugins
Sehr schnell
CommonMark-konform | Komplexe API
HTML-fokussiert
Keine Browser-Isomorphie | 7/10 | +| **unified/remark** | AST-basiert (MDAST)
Isomorph (Node + Browser)
Riesiges Plugin-Ökosystem
De-facto Standard | Steilere Lernkurve
Mehr Setup-Code | **9/10** | +| **gray-matter + marked** | Sehr einfach
Schneller Einstieg | Weniger strukturiert
Begrenzte Flexibilität | 5/10 | + +### Entscheidungskriterien + +1. **AST-Zugriff** (Gewichtung: 30%) + - ✅ unified: Voller MDAST-Zugriff für präzise Manipulation + - ❌ marked: Kein AST, nur Token-Stream + +2. **Isomorphie** (Gewichtung: 25%) + - ✅ unified: Funktioniert identisch in Node.js und Browser + - ⚠️ markdown-it: Primär Node.js-fokussiert + +3. **Erweiterbarkeit** (Gewichtung: 20%) + - ✅ unified: 200+ Plugins im Ökosystem + - ⚠️ marked: Begrenzte Extension-API + +4. **Standards** (Gewichtung: 15%) + - ✅ unified: MDAST ist De-facto-Standard + - ✅ markdown-it: CommonMark-konform + +5. **Community & Wartung** (Gewichtung: 10%) + - ✅ unified: Sehr aktiv, Teil von unifiedjs + - ✅ marked: Aktiv maintained + +### Konsequenzen + +**Positiv:** +- Maximale Flexibilität für zukünftige Features +- AST-Transformationen für WordPress/Nostr +- Browser-Support ohne Code-Änderungen +- Plugin-System für Custom-Syntax + +**Negativ:** +- Mehr initialer Setup-Code erforderlich +- Höhere Komplexität für einfache Use-Cases +- Größere Learning-Curve für Contributors + +### Code-Beispiel + +```javascript +import { unified } from 'unified' +import remarkParse from 'remark-parse' +import remarkFrontmatter from 'remark-frontmatter' +import remarkGfm from 'remark-gfm' + +const processor = unified() + .use(remarkParse) + .use(remarkFrontmatter, ['yaml']) + .use(remarkGfm) + +const ast = processor.parse(markdown) +``` + +--- + +## 2. YAML-Parser: `yaml` library + +**Entscheidung:** `yaml` (v2.x) statt `js-yaml` + +**Datum:** 2025-10-01 + +### Kontext +YAML Front Matter muss zuverlässig geparst werden, inkl. komplexer Strukturen (Arrays, nested Objects). + +### Alternativen + +| Library | Bundle Size | Spec-Konformität | Performance | Score | +|---------|-------------|------------------|-------------|-------| +| **yaml** | 42 KB | YAML 1.2 | Sehr gut | **9/10** | +| **js-yaml** | 68 KB | YAML 1.2 | Gut | 7/10 | +| JSON.parse | 0 KB (native) | N/A (nur JSON) | Exzellent | 3/10 | + +### Entscheidung: `yaml` + +**Gründe:** +1. ✅ **Kleinere Bundle-Size** (42 KB vs. 68 KB) +2. ✅ **Moderne API** (ESM-first, TypeScript-Typen) +3. ✅ **Spec-compliant** (YAML 1.2) +4. ✅ **Aktive Entwicklung** +5. ✅ **Bessere Error-Messages** + +### Konsequenzen + +- Zuverlässiges Parsing komplexer YAML-Strukturen +- Gute Performance auch bei großen Dateien +- Kleinere Bundle-Size für Browser-Builds + +--- + +## 3. HTTP-Client: Native `fetch` + +**Entscheidung:** Native `fetch` API statt axios/node-fetch + +**Datum:** 2025-10-01 + +### Kontext +HTTP-Requests für Forgejo API und URL-basierte Markdown-Dateien. + +### Alternativen + +| Option | Vorteile | Nachteile | Score | +|--------|----------|-----------|-------| +| **native fetch** | In Node 18+ integriert
Identisch im Browser
Keine Dependencies | Erfordert Node.js 18+ | **10/10** | +| **axios** | Feature-reich
Interceptors
Auto-Transform | Zusätzliche Dependency
25 KB Bundle | 6/10 | +| **node-fetch** | Populär | Zusätzliche Dependency
Nicht identisch mit Browser | 5/10 | + +### Entscheidung: Native `fetch` + +**Gründe:** +1. ✅ **Zero Dependencies** +2. ✅ **Isomorphie** - Identische API in Node.js 18+ und Browser +3. ✅ **Standard** - Web API Standard +4. ✅ **Async/await** - Moderne Syntax + +**Requirement:** Node.js >= 18.0.0 + +### Konsequenzen + +- Keine zusätzlichen Dependencies +- Code funktioniert ohne Änderungen im Browser +- Einfachere Maintenance + +--- + +## 4. Module-System: ESM (ES Modules) + +**Entscheidung:** Pure ESM, kein CommonJS + +**Datum:** 2025-10-01 + +### Kontext +Wahl des Module-Systems für das Projekt. + +### Entscheidung: ESM + +```json +{ + "type": "module" +} +``` + +**Gründe:** +1. ✅ **Standard** - ESM ist der JavaScript-Standard +2. ✅ **Browser-kompatibel** - Direkt in Browsern lauffähig +3. ✅ **Tree-Shaking** - Bessere Bundle-Optimierung +4. ✅ **Zukunftssicher** - CommonJS ist Legacy + +**Import-Syntax:** +```javascript +import { parseMarkdownFile } from './parser.js' +// statt: +// const { parseMarkdownFile } = require('./parser.js') +``` + +### Konsequenzen + +**Positiv:** +- Moderne, zukunftssichere Codebasis +- Bessere Bundle-Optimierung +- Browser-Kompatibilität + +**Negativ:** +- Keine Kompatibilität mit alten CommonJS-only Tools +- Erfordert `.js` Extension bei relativen Imports + +--- + +## 5. Datenquelle-Priorität: API-First + +**Entscheidung:** Primärer Fokus auf Forgejo API + +**Datum:** 2025-10-01 + +### Kontext +Verschiedene Datenquellen müssen unterstützt werden. + +### Priorisierung + +1. **Forgejo/Gitea API** (Priorität 1) + - Primäre Datenquelle + - Direkter API-Zugriff + - No Git-Clone nötig + +2. **HTTP/HTTPS URLs** (Priorität 2) + - Einfacher Fallback + - Für öffentliche Dateien + +3. **Lokale Dateien** (Priorität 3) + - Für Entwicklung und Tests + - Node.js-only + +### Implementation + +```javascript +// src/index.js +export async function parseMarkdown(source, options = {}) { + if (isForgejoURL(source)) { + return parseFromForgejo(source, options) + } else if (isHTTPURL(source)) { + return parseFromURL(source, options) + } else { + return parseFromFile(source, options) + } +} +``` + +--- + +## 6. Error-Handling: Graceful Degradation + +**Entscheidung:** Fehlertolerante Metadaten-Extraktion + +**Datum:** 2025-10-01 + +### Prinzip + +Fehlende oder ungültige Metadaten führen nicht zu Fehler, sondern zu Warnings. + +```javascript +{ + metadata: { + name: "Unbekannt", // Fallback + _warnings: [ + "Fehlendes Feld: commonMetadata.name" + ] + } +} +``` + +**Gründe:** +1. ✅ Robustheit gegenüber unvollständigen Daten +2. ✅ Bessere User Experience +3. ✅ Ermöglicht partielle Verarbeitung + +--- + +## 7. Browser-Build: Phase 2 + +**Entscheidung:** Browser-Build wird in Phase 2 implementiert + +**Datum:** 2025-10-01 + +### Kontext +Browser-Unterstützung ist wichtig, aber nicht im ersten Release. + +### Phasen-Plan + +**Phase 1 (jetzt):** +- Node.js-kompatibel +- Isomorpher Code (aber kein Build) +- Tests in Node.js + +**Phase 2:** +- ESM Browser-Build +- Bundling mit Rollup/esbuild +- Browser-Tests + +**Grund:** +- Fokus auf Core-Funktionalität +- Vermeidung von Over-Engineering +- Schnelleres Initial-Release + +--- + +## 8. Testing: Node.js Native Test Runner + +**Entscheidung:** Node.js `--test` statt Jest/Mocha + +**Datum:** 2025-10-01 + +### Alternativen + +| Test-Framework | Vorteile | Nachteile | Score | +|----------------|----------|-----------|-------| +| **Node.js native** | Keine Dependencies
Schnell
ESM-Support | Weniger Features | **8/10** | +| **Jest** | Feature-reich
Snapshots | Langsam
ESM-Probleme | 6/10 | +| **Vitest** | Schnell
ESM-first | Weitere Dependency | 7/10 | + +### Entscheidung: Node.js Native + +```javascript +// test/parser.test.js +import { test } from 'node:test' +import assert from 'node:assert' + +test('parses markdown with YAML', async () => { + const result = await parseMarkdownFile('./fixtures/test.md') + assert.ok(result.yaml) +}) +``` + +**Gründe:** +- ✅ Zero Dependencies für Tests +- ✅ Schnelle Ausführung +- ✅ Native ESM-Support +- ✅ Ausreichend für unsere Zwecke + +--- + +## Zusammenfassung: Technologie-Stack + +| Kategorie | Technologie | Begründung | +|-----------|-------------|------------| +| **Parser** | unified + remark | AST-basiert, isomorph, erweiterbar | +| **YAML** | yaml (v2.x) | Klein, modern, spec-compliant | +| **HTTP** | native fetch | Zero deps, isomorph | +| **Modules** | ESM | Standard, zukunftssicher | +| **Testing** | Node.js native | Zero deps, schnell | +| **Code Style** | Prettier + ESLint | Standard, automatisierbar | + +--- + +## Änderungshistorie + +| Datum | Entscheidung | Autor | +|-------|--------------|-------| +| 2025-10-01 | Initial: unified/remark | Jörg Lohrer | +| 2025-10-01 | YAML library | Jörg Lohrer | +| 2025-10-01 | Native fetch | Jörg Lohrer | +| 2025-10-01 | ESM-only | Jörg Lohrer | + +--- + +**Fragen oder Vorschläge?** → [Issue erstellen](https://git.rpi-virtuell.de/Comenius-Institut/mdparser/issues) diff --git a/package.json b/package.json new file mode 100644 index 0000000..bae06e0 --- /dev/null +++ b/package.json @@ -0,0 +1,50 @@ +{ + "name": "mdparser", + "version": "0.1.0", + "description": "Markdown Parser für AMB-konforme Inhalte mit YAML Front Matter - optimiert für Forgejo/Gitea API und Transformation zu WordPress/Nostr", + "type": "module", + "main": "src/index.js", + "scripts": { + "start": "node src/index.js", + "dev": "node --watch src/index.js", + "test": "node --test", + "lint": "eslint src/", + "format": "prettier --write 'src/**/*.js'", + "example": "node examples/parse-forgejo.js" + }, + "keywords": [ + "markdown", + "parser", + "yaml", + "frontmatter", + "AMB", + "schema.org", + "forgejo", + "gitea", + "wordpress", + "nostr", + "oer", + "education" + ], + "author": "Jörg Lohrer", + "license": "MIT", + "dependencies": { + "unified": "^11.0.5", + "remark-parse": "^11.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "yaml": "^2.4.5", + "dotenv": "^16.4.5" + }, + "devDependencies": { + "eslint": "^9.9.0", + "prettier": "^3.3.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://git.rpi-virtuell.de/Comenius-Institut/mdparser.git" + } +}