joetjen.net
EN DE
Konfigurationssprache

Das Konfigurationsformat CASC

CASC ist eine Konfigurationssprache mit echter Spezifikation: verschachtelte Blöcke, typisierte Werte von Zeitdauern bis zu IP-Bereichen, Variablen, Umgebungszugriffe, Verweise auf andere Schlüssel, Imports und Schleifen — in einer Syntax, die als Klartext lesbar bleibt.

Format 1.0

Ein erster Blick

Eine CASC-Datei ist eine Folge von Anweisungen, die zusammen einen Baum benannter Werte ergeben. Diese hier liest eine Umgebungsdatei, einige Umgebungsvariablen und eine gemeinsame Variable und verweist von einem Schlüssel auf zwei andere:

config.casc
#@version = 1.0

import "env/${APP_ENV:dev}.casc"

@region = ${REGION:"eu-west"}

server {
  host = "0.0.0.0"
  port = !int(${PORT:8080})
}

database {
  host = "db.@{region}.internal"
  *password = ${DB_PASSWORD:?"DB_PASSWORD is required"}
  timeout = 500ms
  cache = 512MiB
}

health.url = "http://%{server.host}:%{server.port}/health"
  • #@version = 1.0 — jede Datei beginnt mit ihrer Formatversion.
  • import holt eine weitere Datei hinzu; ihr Pfad darf die Umgebung lesen.
  • @region ist eine Variable, ${…} liest die Umgebung, %{…} verweist auf einen anderen Schlüssel des fertigen Baums.
  • 500ms und 512MiB sind Werte eigenen Typs, keine Zeichenketten, die später noch geparst werden müssen.
  • *password ist als geheim markiert: der Wert bleibt überall geschwärzt, wo er landet.
  • :?"…" macht eine fehlende Umgebungsvariable zu einem Ladefehler mit eigener Meldung.

Gestaltung

  • Eine Art von Map. Block und Punkt-Pfad sind zwei Schreibweisen desselben Baums, und doppelt geschriebene Blöcke werden zusammengeführt.
  • Typisierte Literale. Zeitdauern, Bytegrößen, Datum und Uhrzeit, IP-Adressen und Tupel sind Werte der Sprache selbst.
  • Drei Verweisarten, eine Grammatik. @{} für Variablen, ${} für die Umgebung und %{} für Konfigurationspfade teilen sich Defaults, Wächter, Indizes und Filter.
  • Ausdrückliches Zusammenführen. Spätere Zuweisungen gewinnen, Blöcke werden tief gemischt; die Sigils ~, + und - ersetzen, hängen an und entfernen, wenn genau das gemeint ist.
  • Nichts Unbekanntes rutscht durch. Ein Tag, Resolver oder Import-Schema, das niemand registriert hat, ist ein Ladefehler, der es beim Namen nennt.
  • Geheimnisse in der Syntax. Ein * am Schlüssel markiert den Wert als geheim, und wer ihn interpoliert, erhält ein ebenfalls geschwärztes Ergebnis.

Der Name ist ein Wortspiel: Ein Cooper ist ein Böttcher, und ein „casc“ ist ein Fass. Das Format ist das, was im Fass steckt.

Eckdaten

EigenschaftWert
Endung.casc
KodierungUTF-8
Erste Zeile#@version = 1.0 — Pflicht, in jeder Datei
Kommentare# gefolgt von einem Leerzeichen, bis zum Zeilenende
ErgebnisEin Baum: Blöcke sind Maps, Blätter typisierte Werte
GrammatikPEG, geschrieben in Aether — siehe Grammatik

Implementierungen und Werkzeuge

Diese Seiten beschreiben das Format. Wie die folgenden Bibliotheken es laden oder bereitstellen, steht jeweils in deren eigener Dokumentation.

NameSpracheRolle
cooperElixirDie Referenzimplementierung
cooper_configElixirNutzt eine CASC-Datei als Konfiguration eines Mix-Projekts oder Releases
CASC for VS CodeTypeScriptSyntaxhervorhebung, Snippets und ein Language Server
cooperPraxisEin Port von Cooper, aus derselben Grammatik erzeugt
cooper_prxPraxisLiest die config.casc eines Praxis-Projekts
ichorElixirDer Grammatik-Compiler, mit dem beide Parser erzeugt werden

Auf diesen Seiten

  • Aufbau — Kopfzeile, Kommentare, Schlüssel, Blöcke, Zusammenführen.
  • Werte — alle Literal-Typen.
  • Verweise — Variablen, Umgebung, Konfigurationspfade, Filter, Tags.
  • Imports und Schleifen — Konfiguration aufteilen und erzeugen, mit einem vollständigen Beispiel.
  • Grammatik — die formale Grammatik und wo die Referenzimplementierung noch davon abweicht.