| Matthias Andreas Benkard | d1e2fac | 2026-07-13 07:09:04 +0200 | [diff] [blame] | 1 | package eu.mulk.aendggner.aenderung; |
| 2 | |
| 3 | import org.jspecify.annotations.Nullable; |
| 4 | |
| 5 | /** |
| 6 | * Ein einzelner Änderungsbefehl eines Änderungsgesetzes, wie er im Handbuch der Rechtsförmlichkeit |
| 7 | * vorgesehen ist. Nicht erkannte Befehle landen als {@link UnbekannterBefehl} im Ergebnis — sie |
| 8 | * werden nie stillschweigend verworfen. |
| 9 | */ |
| 10 | public sealed interface Aenderungsbefehl { |
| 11 | |
| 12 | /** Die betroffene Stelle im Stammgesetz. */ |
| 13 | Stelle stelle(); |
| 14 | |
| 15 | /** Herkunft des Befehls im Änderungsgesetz. */ |
| 16 | Provenienz provenienz(); |
| 17 | |
| 18 | /** Strukturelle Ebene eines eingefügten oder angefügten Elements. */ |
| 19 | enum Ebene { |
| 20 | PARAGRAPH, |
| 21 | ABSATZ, |
| 22 | SATZ, |
| 23 | NUMMER, |
| 24 | BUCHSTABE |
| 25 | } |
| 26 | |
| 27 | /** Anker für Wörter-Einfügungen innerhalb eines Textbereichs. */ |
| 28 | sealed interface WortAnker { |
| 29 | record NachWoertern(String woerter) implements WortAnker {} |
| 30 | |
| 31 | record VorWoertern(String woerter) implements WortAnker {} |
| 32 | |
| 33 | record AmEnde() implements WortAnker {} |
| 34 | |
| 35 | record VorKommaAmEnde() implements WortAnker {} |
| 36 | } |
| 37 | |
| 38 | /** „… werden die Wörter „A“ durch die Wörter „B“ ersetzt.“ */ |
| 39 | record Ersetzung( |
| 40 | Stelle stelle, String alt, String neu, boolean jeweils, boolean amEnde, Provenienz provenienz) |
| 41 | implements Aenderungsbefehl {} |
| 42 | |
| 43 | /** „§ X wird wie folgt gefasst: „…““ */ |
| 44 | record Neufassung(Stelle stelle, String neuerText, Provenienz provenienz) |
| 45 | implements Aenderungsbefehl {} |
| 46 | |
| Matthias Andreas Benkard | 8ae4972 | 2026-07-13 21:32:53 +0200 | [diff] [blame] | 47 | /** |
| 48 | * „§ 2 Absatz 2 wird durch die folgenden Absätze 2 und 3 ersetzt: „…““ — ein Ziel wird durch |
| 49 | * einen Block ersetzt, der auch mehrere neue Einheiten enthalten darf. |
| Matthias Andreas Benkard | ebd5a7b | 2026-07-15 20:54:27 +0200 | [diff] [blame] | 50 | * |
| 51 | * @param stelle das (erste) zu ersetzende Ziel. |
| 52 | * @param bisStelle bei einem zusammenhängenden Bereich („Die Absätze 8 und 9 …“, „Die Sätze 4 bis |
| 53 | * 5 …“) das letzte Ziel; {@code null} bei einem Einzelziel. |
| Matthias Andreas Benkard | 8ae4972 | 2026-07-13 21:32:53 +0200 | [diff] [blame] | 54 | */ |
| Matthias Andreas Benkard | ebd5a7b | 2026-07-15 20:54:27 +0200 | [diff] [blame] | 55 | record StrukturErsetzung( |
| 56 | Stelle stelle, @Nullable Stelle bisStelle, Ebene ebene, String text, Provenienz provenienz) |
| 57 | implements Aenderungsbefehl { |
| 58 | |
| 59 | /** Einzelziel-Konstruktor (kein Bereich). */ |
| 60 | public StrukturErsetzung(Stelle stelle, Ebene ebene, String text, Provenienz provenienz) { |
| 61 | this(stelle, null, ebene, text, provenienz); |
| 62 | } |
| 63 | } |
| Matthias Andreas Benkard | 8ae4972 | 2026-07-13 21:32:53 +0200 | [diff] [blame] | 64 | |
| Matthias Andreas Benkard | d1e2fac | 2026-07-13 07:09:04 +0200 | [diff] [blame] | 65 | /** „… werden nach dem Wort „A“ die Wörter „B“ eingefügt.“ */ |
| 66 | record WoerterEinfuegung(Stelle stelle, WortAnker anker, String woerter, Provenienz provenienz) |
| 67 | implements Aenderungsbefehl {} |
| 68 | |
| 69 | /** |
| 70 | * „Nach § 28 wird folgender § 28a eingefügt: „…““ |
| 71 | * |
| 72 | * @param stelle die Ankerstelle, relativ zu der eingefügt wird. |
| 73 | * @param vorher {@code true} bei „Vor …“, {@code false} bei „Nach …“. |
| 74 | * @param bezeichnung die Bezeichnung des neuen Elements (z.B. „28a“, „5a“); {@code null}, wenn |
| 75 | * der Befehl keine nennt (z.B. „folgender Satz“). |
| 76 | */ |
| 77 | record StrukturEinfuegung( |
| 78 | Stelle stelle, |
| 79 | boolean vorher, |
| 80 | Ebene ebene, |
| 81 | @Nullable String bezeichnung, |
| 82 | String text, |
| 83 | Provenienz provenienz) |
| 84 | implements Aenderungsbefehl {} |
| 85 | |
| 86 | /** „Folgender Absatz 9 wird angefügt: „…““ / „Dem Absatz 3 wird folgender Satz angefügt: …“ */ |
| 87 | record Anfuegung( |
| 88 | Stelle stelle, Ebene ebene, @Nullable String bezeichnung, String text, Provenienz provenienz) |
| 89 | implements Aenderungsbefehl {} |
| 90 | |
| 91 | /** „§ X / Absatz Y wird aufgehoben.“ */ |
| 92 | record Aufhebung(Stelle stelle, Provenienz provenienz) implements Aenderungsbefehl {} |
| 93 | |
| 94 | /** „… werden die Wörter „A“ gestrichen.“ */ |
| 95 | record Streichung(Stelle stelle, String woerter, Provenienz provenienz) |
| 96 | implements Aenderungsbefehl {} |
| 97 | |
| 98 | /** „Der bisherige Absatz 2 wird Absatz 3.“ */ |
| 99 | record Umnummerierung(Stelle stelle, Stelle neu, Provenienz provenienz) |
| 100 | implements Aenderungsbefehl {} |
| 101 | |
| Matthias Andreas Benkard | b05e44a | 2026-07-13 21:33:20 +0200 | [diff] [blame] | 102 | /** |
| Matthias Andreas Benkard | 9a29b38 | 2026-07-13 21:33:43 +0200 | [diff] [blame] | 103 | * „Der Wortlaut wird Absatz 1.“ — der bisher unnummerierte Normtext erhält die Absatznummer, wird |
| 104 | * also zum ersten Absatz (Vorbereitung für das Anfügen weiterer Absätze). |
| 105 | */ |
| 106 | record WortlautZuAbsatz(Stelle stelle, String nummer, Provenienz provenienz) |
| 107 | implements Aenderungsbefehl {} |
| 108 | |
| 109 | /** |
| Matthias Andreas Benkard | 65eff08 | 2026-07-18 12:24:32 +0200 | [diff] [blame] | 110 | * „Der Wortlaut wird Satz 1.“ (bayerisches Landesrecht) — der bisher unnummerierte Text erhält |
| 111 | * die amtliche Satznummer als Superskript (Vorbereitung für das Anfügen weiterer Sätze). |
| 112 | */ |
| 113 | record WortlautZuSatz(Stelle stelle, String nummer, Provenienz provenienz) |
| 114 | implements Aenderungsbefehl {} |
| 115 | |
| 116 | /** |
| 117 | * „Dem Wortlaut werden die folgenden Abs. 1 bis 4 vorangestellt: „…““ (bayerisches Landesrecht) — |
| 118 | * neue Absätze treten vor den bisherigen Normtext. |
| 119 | */ |
| 120 | record WortlautVoranstellung(Stelle stelle, String text, Provenienz provenienz) |
| 121 | implements Aenderungsbefehl {} |
| 122 | |
| 123 | /** |
| 124 | * „Fußnote 1 wird aufgehoben.“ / „Die Fußnoten 9 und 10 werden aufgehoben.“ (bayerisches |
| 125 | * Landesrecht) — entfernt die Fußnotenzeile(n) „ⁿ) [Amtl. Anm.:] …“ samt der Inline-Marker „ⁿ)“ |
| 126 | * aus der Kontextnorm. |
| 127 | */ |
| 128 | record FussnotenAufhebung(Stelle stelle, java.util.List<String> nummern, Provenienz provenienz) |
| 129 | implements Aenderungsbefehl { |
| 130 | |
| 131 | public FussnotenAufhebung { |
| 132 | nummern = java.util.List.copyOf(nummern); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * „In Satz 1 wird die Satznummerierung „1“ gestrichen.“ (bayerisches Landesrecht) — entfernt die |
| 138 | * amtliche Superskript-Satznummer am Anfang des bezeichneten Bereichs (etwa nachdem der zweite |
| 139 | * und letzte Satz eines Absatzes aufgehoben wurde). |
| 140 | */ |
| 141 | record SatznummerierungStreichung(Stelle stelle, String nummer, Provenienz provenienz) |
| 142 | implements Aenderungsbefehl {} |
| 143 | |
| 144 | /** |
| Matthias Andreas Benkard | b7e9f0f | 2026-07-16 21:12:08 +0200 | [diff] [blame] | 145 | * „Nach § 33 werden die folgenden Überschriften zu Teil 3 und zu Teil 3 Abschnitt 1 eingefügt: |
| 146 | * „…““ bzw. „Die bisherigen Überschriften zu Teil 4 und Teil 4 Abschnitt 1 werden durch die |
| 147 | * folgende Überschrift zu Abschnitt 2 ersetzt: „…““ — neue Gliederungs-Überschriften im |
| 148 | * Gliederungsbaum. |
| 149 | * |
| 150 | * @param stelle der Anker-§ („Nach § 33“); leer bei der Ersetzungsform. |
| 151 | * @param neue die neuen Einheiten in Zitatreihenfolge (Titel stehen im Zitat). |
| 152 | * @param ersetzte die zu ersetzenden bisherigen Einheiten (leer bei der Einfügeform); jede als |
| 153 | * Pfad („Teil 4 Abschnitt 1“ → [Teil 4, Abschnitt 1]). |
| 154 | * @param text das Zitat mit den Überschriften. |
| 155 | */ |
| 156 | record GliederungsUeberschriften( |
| 157 | Stelle stelle, |
| 158 | java.util.List<Stelle.Gliederungseinheit> neue, |
| 159 | java.util.List<java.util.List<Stelle.Gliederungseinheit>> ersetzte, |
| 160 | String text, |
| 161 | Provenienz provenienz) |
| 162 | implements Aenderungsbefehl { |
| 163 | |
| 164 | public GliederungsUeberschriften { |
| 165 | neue = java.util.List.copyOf(neue); |
| 166 | ersetzte = java.util.List.copyOf(ersetzte); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /** |
| Matthias Andreas Benkard | b05e44a | 2026-07-13 21:33:20 +0200 | [diff] [blame] | 171 | * „In A und B wird jeweils …“ — ein Befehl, der dieselbe Operation auf mehrere, per „und“ |
| 172 | * koordinierte Stellen anwendet. Die Teilbefehle teilen sich Provenienz und Befehlszeile; der |
| 173 | * Applier fasst sie zu einem Protokolleintrag zusammen. |
| 174 | */ |
| 175 | record Sammelbefehl(java.util.List<Aenderungsbefehl> teilbefehle) implements Aenderungsbefehl { |
| 176 | |
| 177 | public Sammelbefehl { |
| 178 | teilbefehle = java.util.List.copyOf(teilbefehle); |
| 179 | } |
| 180 | |
| 181 | @Override |
| 182 | public Stelle stelle() { |
| 183 | return teilbefehle.get(0).stelle(); |
| 184 | } |
| 185 | |
| 186 | @Override |
| 187 | public Provenienz provenienz() { |
| 188 | return teilbefehle.get(0).provenienz(); |
| 189 | } |
| 190 | } |
| 191 | |
| Matthias Andreas Benkard | d1e2fac | 2026-07-13 07:09:04 +0200 | [diff] [blame] | 192 | /** Fallback für alles, was der Parser nicht versteht — muss manuell geprüft werden. */ |
| 193 | record UnbekannterBefehl(Stelle stelle, String originalText, Provenienz provenienz) |
| 194 | implements Aenderungsbefehl {} |
| 195 | } |