npm package: @masterportal/mpconfigparser
Description: parses the config.json.md to a tree structure; also usable as validator
Author: Landesbetrieb Geoinformation und Vermessung
Latest version: 2.0.0

> Switch to the [English version](./README.md).

# MP Config Parser

Der MP Config Parser ist ein Paket, das Tools und Definitionen zum Parsen einer `config.json.md` für das [Masterportal](https://bitbucket.org/geowerkstatt-hamburg/masterportal/src/dev/) umfasst. Zurückgeliefert wird eine Graphstruktur, die die Möglichkeiten für eine `config.json`-Datei beschreibt, und ein Warnungslog, der Fehler in der Struktur der `config.json.md` anzeigt.

Im [Masterportal Admintool](https://bitbucket.org/geowerkstatt-hamburg/mp-admintool/src/master/) wird dies zur Formulargenerierung eingesetzt. Im Masterportal wird dies zur Validierung des Zustands der `config.json.md` eingesetzt; außerdem wird überprüft, ob deutsche und englische Dokumentation strukturell identisch sind.

```bash
# Verwendung als CLI tool
node ./node_modules/mpconfigparser/cli.js ./doc/config.json.md ./doc/config.json.de.md
```

Es folgt die Beschreibung der Struktur der `config.json.md`.

Mit `config` ist die gesamte `config.json` gemeint.

Mit ε, ε2, ... sind punktseparierte Listen von Titelfragmenten gemeint. (etwa "Portalconfig.menu.tools")

## Dokumentstruktur

* Das h1-Kapitel mit einem Namen, der mit "config.json" beginnt, stellt den Startknoten der Konfiguration dar
    * Das h2-Kapitel "layerConfig" darin wird zu einem gesonderten (nicht-generierten) Formular verarbeitet
    * Das h2-Kapitel "Datatypes" wird zur Referenzierung interpretiert, ist aber außerhalb der Kapitelordnung; es kann dadurch keinen Key "Datatypes" auf oberster Ebene der config.json geben
      * "Datatypes.Extent" und "Datatypes.Coordinate" sind spezielle Typen; ihre Bedeutung kann nicht durch Änderung der Markdown beeinflusst werden
    * Alle anderen h2-Kapitel darin werden als Grundlage zur Formulargenerierung genutzt
    * Es darf kein h2-Kapitel "version" geben: Dieses Feld wird im Hintergrund benutzt, um Versionsinformationen abzulegen
* Paragraphen/Listen/... werden wie vorgefunden zu HTML umgewandelt und in den Formularen als Hilfstexte dargestellt
* Inhalte außerhalb des h1-Kapitels "config.json" werden nicht im Admintool dargestellt
    * Inhaltsverzeichnis, Links, ...

## Admintoolstruktur basierend auf Kapiteln

* h1: Keine Darstellung
* h2: Jedes h2 ist ein Schritt in der Konfiguration (Step in der Sidebar)
* h3: Jedes h3 ist ein Unterschritt für einen Schritt (Unterelement zum Step)
* h4+: Ist ein Unterkapitel im Formular für h2 bzw. h3, das als Box abgehoben wird
    * Wenn ein Kapitel also mehrere Abschnitte im Formular, aber keine Unterkapitel haben soll, muss h4 auf h2 folgen

## Titelstruktur

* Fall 1: Titel beschreiben eine Objektverschachtelung
    * Für Kapitel mit Titel ε gilt, dass das Objekt config.ε beschrieben wird
    * Für ein Kapitel ε mit ε = ε2.x gilt, falls ε2 nicht-leer ist, ist in mindestens einer Zeile der tabellarischen Beschreibung zu ε2 der Typ x
* Fall 2: Titel beschreiben einen Typ
    * Für ein Kapitel mit Titel ε gilt, dass das Objekt config.ε nicht existiert
    * Für ein Kapitel ε gilt, dass ein ε2 existiert mit
        * ε2 entspricht wiederum den Regeln von Fall 1 oder Fall 2
        * ε2 referenziert als Typ oder erbt von ε

Die Struktur dahinter ist ein kreisfreier Graph, wobei die Knoten Kapitel sind. Kanten sind

* Kindverweise (Objektverschachtelung)
* Querverweise (Objektverschachtelung)
* Vererbungsbeziehungen

Titel können weiterhin ` {data-toc-label='Arbitrary label'}` als Suffix haben. Diese Titel werden im Graph als Label beibehalten, enthalten jedoch keine strukturellen Informationen.

## Referenzstruktur

Die Struktur `[a]: # (ε)` wird genutzt, wobei a die Art der Beziehung beschreibt, und ε den referenzierten Pfad. Diese Struktur ist in der Ansicht von Markdown für den Leser nicht sichtbar und wird deshalb hier zweckentfremdet.

### Kindverweis

Direkte Verweise ergeben sich implizit daraus, dass in ε der Typ x benutzt wird und ε.x existiert.

### Querverweis

Hierfür wird im Markdown nach dem Titel und einer Leerzeile der Eintrag `[type:x]: # (ε)` gesetzt. Damit wird für den Typen "x" *für dieses Kapitel*
festgelegt, dass das Objekt dahinter nach der Beschreibung in ε strukturiert ist. Es darf im gleichen Kapitel keine zwei Definitionen [type:x] und [type:y]
geben mit `x.toLowerCase() === y.toLowerCase()`.

### Vererbung

Zur Annotation einer Vererbung ist im Markdown nach dem Titel und einer Leerzeile der Eintrag `[inherits]: # (ε)` gesetzt. Damit
werden alle Zeilen von ε als Grundlage genutzt und die neue Definition wird über sie kopiert.

Weiterhin gilt, dass erbende Kapitel anstelle ihrer vererbenden Kapitel genutzt werden können. Falls also A von B erbt, und C hat
für eine Zeile den Typen B, dann kann hier anstelle von B auch ein A verwendet werden. Dies gilt auch transitiv.

Abstrakte Kapitel können implizit deklariert werden, indem sie nirgends als Typ verwandt werden. Wenn also A von B erbt, aber B nirgends
als Typ vermerkt ist, ist B gleichsam abstrakt. Hierdurch können gemeinsame Propertysets rausgezogen werden.

## Tabellenstruktur

Tabellen beschreiben die Struktur von Objekten. Für Kapitel ab h2 werden Tabellen interpretiert. Tabellen haben folgende Spalten in dieser Reihenfolge. Die Spalte "Expert" ist derzeit optional. Wenn sie nicht vorhanden ist, wird angenommen, dass kein Eintrag in dieser Tabelle zum Expertenmodus gehört.

|Name|Verpflichtend|Typ|Default|Beschreibung|Expert|
|----|-------------|---|-------|------------|--------|
|Beliebiger String, der als Key in einem Objekt zugelassen ist. Der Name wird von camelCase zu Title Case umgewandelt und als Label benutzt.|"ja" oder "nein" ist erlaubt. Wenn "ja" gesetzt ist, muss der User einen Wert hinterlegen, der truthy ist.|siehe unten|Vorbelegung für den Eintrag. Muss mit `JSON.parse` verarbeitbar sein und dem Typen entsprechen.|Beliebiger Beschreibungstext, der am Formularelement dargestellt wird. Enthält dieser Text "@deprecated", wird ein entsprechender Hinweis angezeigt und das Feld wird read-only.|true oder false; wenn true, wird das Element nur im Expertenmodus angezeigt.|

### Typ

Im Feld Typ wird ein String nach folgendem Muster erwartet. Abhängig vom Typ werden dem Nutzer typspezifische Eingabeelemente angeboten.

#### Primitive

* `Number`
* `Boolean`
* `String`

#### Selbstdefinierte

* `Integer` (Ganzzahlen)
* `Float` (entspricht Number)
* `Coordinate` (Auswahl über Karte)
* `Extent` (Auswahl über Karte)
* `LayerId` (Auswahl über Dropdown)
* `RestId` (Auswahl über Dropdown)
* `StyleId` (Auswahl über Dropdown)

#### Enums

* `enum[1,2,3]`
    * Hier wären 1, 2, und 3 Optionen für den Enum
    * Alle primitiven Typen sind erlaubt

#### Objektreferenzen

Für einen String x, der nicht den bisher definierten Typen entspricht, wird angenommen, dass ein Objekt gemeint ist.

* Ist ein Querverweis wie im Kapitel "Referenzstruktur" definiert, wird dieser hier aufgelöst
* Sonst wird für x in ε angenommen, dass ε.x existiert

#### Arrays

Jeder bisherige Typ kann mit einem [] gesuffixed werden, sodass eine beliebige Anzahl dieser Elemente gesetzt werden kann.

#### Verorderung

Wenn es mehrere Typen für ein Feld gibt, können diese mit "/" getrennt werden. Dem User werden dann Radio-Buttons zur Verfügung gestellt, um sein Eingabeelement zu wählen.