mdparser/docs/DECISIONS.md
Jörg Lohrer fbd6630f6d 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)
2025-10-01 15:28:30 +02:00

8.8 KiB

🎯 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

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

{
  "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:

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

// 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.

{
  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

// 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