Skip to content

Plannotator Datenmodelle ​

Dieser Anhang stellt alle von Plannotator verwendeten Datenmodelle vor, einschließlich der Kerndatenstrukturen für Planprüfung, Codeprüfung, URL-Sharing und mehr.

Übersicht der Kerndatenmodelle ​

Plannotator definiert die folgenden Kerndatenmodelle mit TypeScript:

ModellVerwendungszweckDefinitionsort
AnnotationKommentare in der Planprüfungpackages/ui/types.ts:11-33
BlockInhaltsblöcke nach Markdown-Parsingpackages/ui/types.ts:35-44
CodeAnnotationKommentare in der Codeprüfungpackages/ui/types.ts:55-66
ShareableAnnotationKompaktes Kommentarformat für URL-Sharingpackages/ui/utils/sharing.ts:14-19

Annotation (Plankommentar) ​

Annotation repräsentiert einen Kommentar in der Planprüfung und wird verwendet, um Löschungen, Einfügungen, Ersetzungen oder Kommentare im Plan zu markieren.

Vollständige Definition ​

typescript
export interface Annotation {
  id: string;              // Eindeutige Kennung
  blockId: string;         // Zugehörige Block-ID (veraltet, für Kompatibilität beibehalten)
  startOffset: number;     // Start-Offset (veraltet, für Kompatibilität beibehalten)
  endOffset: number;       // End-Offset (veraltet, für Kompatibilität beibehalten)
  type: AnnotationType;     // Kommentartyp
  text?: string;           // Kommentarinhalt (für INSERTION/REPLACEMENT/COMMENT)
  originalText: string;    // Ursprünglicher kommentierter Text
  createdA: number;        // Erstellungszeitstempel
  author?: string;         // Mitarbeiteridentität (für URL-Sharing)
  imagePaths?: string[];    // Pfade zu angehängten Bildern
  startMeta?: {            // web-highlighter Metadaten für elementübergreifende Auswahl
    parentTagName: string;
    parentIndex: number;
    textOffset: number;
  };
  endMeta?: {              // web-highlighter Metadaten für elementübergreifende Auswahl
    parentTagName: string;
    parentIndex: number;
    textOffset: number;
  };
}

AnnotationType Enumeration ​

typescript
export enum AnnotationType {
  DELETION = 'DELETION',           // Diesen Inhalt löschen
  INSERTION = 'INSERTION',         // Diesen Inhalt einfügen
  REPLACEMENT = 'REPLACEMENT',     // Diesen Inhalt ersetzen
  COMMENT = 'COMMENT',             // Diesen Inhalt kommentieren
  GLOBAL_COMMENT = 'GLOBAL_COMMENT', // Globaler Kommentar (nicht mit spezifischem Text verknüpft)
}

Feldbeschreibungen ​

FeldTypErforderlichBeschreibung
idstring✅Eindeutige Kennung, normalerweise automatisch generierte UUID
blockIdstring✅Zugehörige Block-ID (veraltet, für Kompatibilität beibehalten)
startOffsetnumber✅Start-Zeichen-Offset (veraltet, für Kompatibilität beibehalten)
endOffsetnumber✅End-Zeichen-Offset (veraltet, für Kompatibilität beibehalten)
typeAnnotationType✅Kommentartyp (DELETION/INSERTION/REPLACEMENT/COMMENT/GLOBAL_COMMENT)
textstring❌Kommentarinhalt (auszufüllen bei INSERTION/REPLACEMENT/COMMENT)
originalTextstring✅Ursprünglicher kommentierter Text
createdAnumber✅Erstellungszeitstempel (Millisekunden)
authorstring❌Mitarbeiteridentität (zur Unterscheidung von Autoren beim URL-Sharing)
imagePathsstring[]❌Array von Pfaden zu angehängten Bildern
startMetaobject❌Start-Metadaten für elementübergreifende Auswahl mit web-highlighter
endMetaobject❌End-Metadaten für elementübergreifende Auswahl mit web-highlighter

Beispiele ​

Löschungskommentar ​

typescript
{
  id: "anno-001",
  blockId: "block-0",
  startOffset: 0,
  endOffset: 50,
  type: AnnotationType.DELETION,
  originalText: "Dieser Teil wird nicht benötigt",
  createdA: Date.now(),
}

Ersetzungskommentar ​

typescript
{
  id: "anno-002",
  blockId: "block-0",
  startOffset: 0,
  endOffset: 50,
  type: AnnotationType.REPLACEMENT,
  text: "Neuer Inhalt",
  originalText: "Alter Inhalt",
  createdA: Date.now(),
  imagePaths: ["/tmp/plannotator/screenshot-001.png"],
}

Globaler Kommentar ​

typescript
{
  id: "anno-003",
  blockId: "",
  startOffset: 0,
  endOffset: 0,
  type: AnnotationType.GLOBAL_COMMENT,
  text: "Insgesamt ist der Plan sehr klar",
  originalText: "",
  createdA: Date.now(),
}

Erklärung veralteter Felder

Die Felder blockId, startOffset und endOffset wurden in älteren Versionen für zeichenbasiertes Text-Highlighting verwendet. Die aktuelle Version verwendet die web-highlighter-Bibliothek und implementiert elementübergreifende Auswahl über startMeta und endMeta. Diese Felder werden nur aus Kompatibilitätsgründen beibehalten.

Block (Planblock) ​

Block repräsentiert einen Inhaltsblock nach dem Parsen von Markdown-Text und wird zur strukturierten Anzeige von Planinhalten verwendet.

Vollständige Definition ​

typescript
export interface Block {
  id: string;              // Eindeutige Kennung
  type: BlockType;         // Blocktyp
  content: string;        // Reiner Textinhalt
  level?: number;         // Ebene (für Überschriften oder Listen)
  language?: string;      // Code-Sprache (für Codeblöcke)
  checked?: boolean;      // Checkbox-Status (für Listenelemente)
  order: number;          // Sortierreihenfolge
  startLine: number;      // Startzeilennummer (1-basiert)
}

BlockType Typ ​

typescript
type BlockType =
  | 'paragraph'     // Absatz
  | 'heading'       // Überschrift
  | 'blockquote'    // Zitatblock
  | 'list-item'     // Listenelement
  | 'code'          // Codeblock
  | 'hr'            // Trennlinie
  | 'table';        // Tabelle

Feldbeschreibungen ​

FeldTypErforderlichBeschreibung
idstring✅Eindeutige Kennung im Format block-{Nummer}
typeBlockType✅Blocktyp (paragraph/heading/blockquote/list-item/code/hr/table)
contentstring✅Reiner Textinhalt des Blocks
levelnumber❌Ebene: 1-6 für Überschriften, Einrückungsebene für Listenelemente
languagestring❌Sprache des Codeblocks (z.B. 'typescript', 'rust')
checkedboolean❌Checkbox-Status des Listenelements (true = aktiviert, false = deaktiviert)
ordernumber✅Sortierindex zur Beibehaltung der Blockreihenfolge
startLinenumber✅Startzeilennummer im Quell-Markdown (beginnend bei 1)

Beispiele ​

Überschriftenblock ​

typescript
{
  id: "block-0",
  type: "heading",
  content: "Implementation Plan",
  level: 1,
  order: 1,
  startLine: 1,
}

Absatzblock ​

typescript
{
  id: "block-1",
  type: "paragraph",
  content: "This is a paragraph with some text.",
  order: 2,
  startLine: 3,
}

Codeblock ​

typescript
{
  id: "block-2",
  type: "code",
  content: "function hello() {\n  return 'world';\n}",
  language: "typescript",
  order: 3,
  startLine: 5,
}

Listenelement (mit Checkbox) ​

typescript
{
  id: "block-3",
  type: "list-item",
  content: "Authentifizierungsmodul abschließen",
  level: 0,
  checked: true,
  order: 4,
  startLine: 10,
}

Markdown-Parsing

Plannotator verwendet einen benutzerdefinierten vereinfachten Markdown-Parser (parseMarkdownToBlocks), um Quell-Markdown in ein Block[]-Array zu konvertieren. Der Parser unterstützt gängige Syntax wie Überschriften, Listen, Codeblöcke, Tabellen und Zitatblöcke.

CodeAnnotation (Codekommentar) ​

CodeAnnotation repräsentiert einen zeilenbasierten Kommentar in der Codeprüfung und wird verwendet, um Feedback zu bestimmten Zeilen oder Bereichen eines Git-Diffs hinzuzufügen.

Vollständige Definition ​

typescript
export interface CodeAnnotation {
  id: string;              // Eindeutige Kennung
  type: CodeAnnotationType;  // Kommentartyp
  filePath: string;         // Dateipfad
  lineStart: number;        // Startzeilennummer
  lineEnd: number;          // Endzeilennummer
  side: 'old' | 'new';     // Seite ('old' = gelöschte Zeilen, 'new' = hinzugefügte Zeilen)
  text?: string;           // Kommentarinhalt
  suggestedCode?: string;    // Vorgeschlagener Code (für suggestion-Typ)
  createdAt: number;        // Erstellungszeitstempel
  author?: string;         // Mitarbeiteridentität
}

CodeAnnotationType Typ ​

typescript
export type CodeAnnotationType =
  | 'comment'      // Normaler Kommentar
  | 'suggestion'  // Änderungsvorschlag (erfordert suggestedCode)
  | 'concern';     // Bedenken (wichtige Erinnerung)

Feldbeschreibungen ​

FeldTypErforderlichBeschreibung
idstring✅Eindeutige Kennung
typeCodeAnnotationType✅Kommentartyp (comment/suggestion/concern)
filePathstring✅Relativer Pfad der kommentierten Datei (z.B. src/auth.ts)
lineStartnumber✅Startzeilennummer (beginnend bei 1)
lineEndnumber✅Endzeilennummer (beginnend bei 1)
side'old' | 'new'✅Seite: 'old' = gelöschte Zeilen (alte Version), 'new' = hinzugefügte Zeilen (neue Version)
textstring❌Kommentarinhalt
suggestedCodestring❌Vorgeschlagener Code (erforderlich wenn type 'suggestion' ist)
createdAtnumber✅Erstellungszeitstempel (Millisekunden)
authorstring❌Mitarbeiteridentität

Erklärung des side-Feldes ​

Das side-Feld entspricht der Diff-Ansicht der @pierre/diffs-Bibliothek:

side-Wert@pierre/diffs EntsprechungBeschreibung
'old'deletionsGelöschte Zeilen (Inhalt in der alten Version)
'new'additionsHinzugefügte Zeilen (Inhalt in der neuen Version)

Beispiele ​

Normaler Kommentar (hinzugefügte Zeile) ​

typescript
{
  id: "code-anno-001",
  type: "comment",
  filePath: "src/auth.ts",
  lineStart: 15,
  lineEnd: 15,
  side: "new",
  text: "Hier muss der Fehlerfall behandelt werden",
  createdAt: Date.now(),
}

Änderungsvorschlag (gelöschte Zeile) ​

typescript
{
  id: "code-anno-002",
  type: "suggestion",
  filePath: "src/auth.ts",
  lineStart: 10,
  lineEnd: 12,
  side: "old",
  text: "Empfehle Verwendung von async/await",
  suggestedCode: "async function authenticate() {\n  const user = await fetchUser();\n  return user;\n}",
  createdAt: Date.now(),
}

ShareableAnnotation (Sharing-Kommentar) ​

ShareableAnnotation ist ein kompaktes Kommentarformat für URL-Sharing, dargestellt durch Array-Tupel zur Reduzierung der Payload-Größe.

Vollständige Definition ​

typescript
export type ShareableAnnotation =
  | ['D', string, string | null, string[]?]           // Deletion: [type, original, author, images]
  | ['R', string, string, string | null, string[]?]   // Replacement: [type, original, replacement, author, images]
  | ['C', string, string, string | null, string[]?]   // Comment: [type, original, comment, author, images]
  | ['I', string, string, string | null, string[]?]   // Insertion: [type, context, new text, author, images]
  | ['G', string, string | null, string[]?];          // Global Comment: [type, comment, author, images]

Typbeschreibungen ​

TypErstes ZeichenTupelstrukturBeschreibung
DELETION'D'['D', original, author?, images?]Inhalt löschen
REPLACEMENT'R'['R', original, replacement, author?, images?]Inhalt ersetzen
COMMENT'C'['C', original, comment, author?, images?]Inhalt kommentieren
INSERTION'I'['I', context, newText, author?, images?]Inhalt einfügen
GLOBAL_COMMENT'G'['G', comment, author?, images?]Globaler Kommentar

Beispiele ​

typescript
// Löschung
['D', 'Zu löschender Inhalt', null, []]

// Ersetzung
['R', 'Originaltext', 'Ersetzen durch', null, ['/tmp/img.png']]

// Kommentar
['C', 'Dieser Code', 'Empfehle Optimierung', null, []]

// Einfügung
['I', 'Kontext', 'Einzufügender neuer Inhalt', null, []]

// Globaler Kommentar
['G', 'Insgesamt sehr gut', null, []]

Warum kompaktes Format?

Die Verwendung von Array-Tupeln anstelle von Objekten reduziert die Payload-Größe, was zu kürzeren URLs nach Komprimierung führt. Zum Beispiel:

  • Objektformat: {"type":"DELETION","originalText":"text"} → 38 Bytes
  • Kompaktformat: ["D","text",null,[]] → 18 Bytes

SharePayload (Sharing-Payload) ​

SharePayload ist die vollständige Datenstruktur für URL-Sharing, die Planinhalte und Kommentare enthält.

Vollständige Definition ​

typescript
export interface SharePayload {
  p: string;                  // Markdown-Text des Plans
  a: ShareableAnnotation[];    // Kommentar-Array (kompaktes Format)
  g?: string[];              // Globale Anhangspfade (Bilder)
}

Feldbeschreibungen ​

FeldTypErforderlichBeschreibung
pstring✅Markdown-Inhalt des ursprünglichen Plans
aShareableAnnotation[]✅Kommentar-Array (verwendet ShareableAnnotation kompaktes Format)
gstring[]❌Globale Anhangspfade (Bilder, die nicht mit spezifischen Kommentaren verknüpft sind)

Beispiel ​

typescript
{
  p: "# Implementation Plan\n\n1. Add auth\n2. Add UI",
  a: [
    ['C', 'Add auth', 'Muss OAuth unterstützen', null, []],
    ['G', 'Gesamtplan ist klar', null, []],
  ],
  g: ['/tmp/plannotator/diagram.png'],
}

Frontmatter (Vordere Metadaten) ​

Frontmatter repräsentiert YAML-Metadaten am Anfang einer Markdown-Datei zur Speicherung zusätzlicher Informationen.

Vollständige Definition ​

typescript
export interface Frontmatter {
  [key: string]: string | string[];
}

Beispiel ​

markdown
---
created: 2026-01-24T14:30:00.000Z
source: plannotator
tags: [authentication, typescript]
author: John Doe
---

### Implementation Plan (Beispiel)
...

Nach dem Parsen:

typescript
{
  created: "2026-01-24T14:30:00.000Z",
  source: "plannotator",
  tags: ["authentication", "typescript"],
  author: "John Doe",
}

Verwendungszweck von Frontmatter

Plannotator generiert beim Speichern von Plänen in Obsidian automatisch Frontmatter, einschließlich Erstellungszeit, Quell-Tags usw., um Notizverwaltung und -suche zu erleichtern.

Verwandte Hilfstypen ​

EditorMode (Editor-Modus) ​

typescript
export type EditorMode = 'selection' | 'comment' | 'redline';
  • 'selection': Textauswahlmodus
  • 'comment': Kommentarmodus
  • 'redline': Rotlinienmodus

DiffResult (Diff-Ergebnis) ​

typescript
export interface DiffResult {
  original: string;    // Ursprünglicher Inhalt
  modified: string;    // Geänderter Inhalt
  diffText: string;    // Unified Diff-Text
}

DiffAnnotationMetadata (Diff-Kommentar-Metadaten) ​

typescript
export interface DiffAnnotationMetadata {
  annotationId: string;      // Zugehörige Kommentar-ID
  type: CodeAnnotationType;  // Kommentartyp
  text?: string;            // Kommentarinhalt
  suggestedCode?: string;   // Vorgeschlagener Code
  author?: string;          // Autor
}

SelectedLineRange (Ausgewählter Zeilenbereich) ​

typescript
export interface SelectedLineRange {
  start: number;                      // Startzeilennummer
  end: number;                        // Endzeilennummer
  side: 'deletions' | 'additions';   // Seite (entspricht @pierre/diffs Diff-Ansicht)
  endSide?: 'deletions' | 'additions'; // Endseite (für seitenübergreifende Auswahl)
}

Datenkonvertierungsbeziehungen ​

Annotation ↔ ShareableAnnotation ​

typescript
// Vollständig → Kompakt
function toShareable(annotations: Annotation[]): ShareableAnnotation[]

// Kompakt → Vollständig
function fromShareable(data: ShareableAnnotation[]): Annotation[]

Koordinatenverlust

Die von fromShareable generierten Annotation-Felder blockId, startOffset und endOffset sind leer oder 0 und müssen durch Textabgleich oder web-highlighter wiederhergestellt werden.

Markdown ↔ Block[] ​

typescript
// Markdown → Block[]
function parseMarkdownToBlocks(markdown: string): Block[]

// Block[] + Annotation[] → Markdown
function exportDiff(blocks: Block[], annotations: Annotation[]): string

Zusammenfassung dieser Lektion ​

Dieser Anhang stellte alle Kerndatenmodelle von Plannotator vor:

  • Annotation: Kommentare in der Planprüfung, unterstützt Typen wie Löschung, Einfügung, Ersetzung und Kommentar
  • Block: Inhaltsblöcke nach Markdown-Parsing zur strukturierten Anzeige von Plänen
  • CodeAnnotation: Zeilenbasierte Kommentare in der Codeprüfung, unterstützt Kommentare und Vorschläge
  • ShareableAnnotation: Kompaktes Format für URL-Sharing zur Reduzierung der Payload-Größe
  • SharePayload: Vollständige Datenstruktur für URL-Sharing

Diese Datenmodelle werden in Funktionen wie Planprüfung, Codeprüfung und URL-Sharing umfassend eingesetzt. Ihr Verständnis hilft bei der tiefgehenden Anpassung und Erweiterung von Plannotator.

Vorschau auf die nächste Lektion ​

In der nächsten Lektion lernen wir Plannotator Lizenzinformationen.

Sie werden sehen:

  • Kernbestimmungen der Business Source License 1.1 (BSL)
  • Erlaubte Nutzungsweisen und kommerzielle Einschränkungen
  • Zeitplan für die Umstellung auf Apache 2.0 im Jahr 2030
  • Wie man eine kommerzielle Lizenz erhält

Anhang: Quellcode-Referenz ​

Klicken Sie zum Erweitern der Quellcode-Positionen

Aktualisierungszeit: 2026-01-24

FunktionDateipfadZeilennummern
Annotation Interfacepackages/ui/types.ts11-33
AnnotationType Enumerationpackages/ui/types.ts1-7
Block Interfacepackages/ui/types.ts35-44
CodeAnnotation Interfacepackages/ui/types.ts55-66
CodeAnnotationType Typpackages/ui/types.ts53
ShareableAnnotation Typpackages/ui/utils/sharing.ts14-19
SharePayload Interfacepackages/ui/utils/sharing.ts21-25
toShareable()packages/ui/utils/sharing.ts76-95
fromShareable()packages/ui/utils/sharing.ts102-155
parseMarkdownToBlocks()packages/ui/utils/parser.ts70-244
exportDiff()packages/ui/utils/parser.ts246-323
extractFrontmatter()packages/ui/utils/parser.ts14-63

Wichtige Konstanten:

  • Keine

Wichtige Funktionen:

  • toShareable(annotations: Annotation[]): ShareableAnnotation[]: Konvertiert vollständige Kommentare in kompaktes Format
  • fromShareable(data: ShareableAnnotation[]): Annotation[]: Stellt kompaktes Format zu vollständigen Kommentaren wieder her
  • parseMarkdownToBlocks(markdown: string): Block[]: Parst Markdown zu Block-Array
  • exportDiff(blocks: Block[], annotations: Annotation[]): string: Exportiert Kommentare in Markdown-Format