Files
Florian WildeandClaude Opus 5 7196c7110c Aufraeumarbeiten: ESLint, DOM-Verschachtelung, eigene Testwehr
ESLint hatte keine Konfiguration — das Skript "npm run lint" pruefte nichts.
Jetzt Flat Config ohne Formatierungsregeln, dafuer mit den Regeln, die die
Fehler dieses Projekts gemeldet haetten. Er hat gleich zwei gefunden, die
niemand gesucht hatte.

Das Badge rendert ein span statt eines div. Damit ist die Meldung
"div cannot be a descendant of p" weg, die seit Phase 3 auf der Einsatzseite
stand — sie ist der klassische Ausloeser fuer einen Hydration-Fehler.

Die E2E-Tests laufen gegen eine eigene Wehr. Nach fuenf Phasen standen in der
Beispielwehr 120 Atemschutz-Ueberwachungen statt einer und 115 Geraete statt
45; bei jedem Lauf aenderten sich alle Bildschirmfotos. Der Bestand ist einmal
zurueckgesetzt, npm run db:test-reset baut die Testwehr neu auf.

Behoben nebenbei:
- Die Fehlerflaeche der Karte konnte nie etwas anzeigen.
- Zwei useMemo der Lagekarte rechneten bei jedem Rendern neu.
- tests/e2e war vom Typecheck ausgenommen und liess einen doppelt
  deklarierten Bezeichner durch.

Closes #10
Closes #11
Closes #12

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 13:24:48 +02:00

136 lines
4.9 KiB
JavaScript

import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { FlatCompat } from "@eslint/eslintrc";
/**
* ESLint-Konfiguration.
*
* Bis Phase 8 gab es ein Skript `npm run lint`, aber keine Konfiguration —
* der Aufruf tat also nichts. Ein Werkzeug, das aussieht, als prüfe es etwas,
* und nichts prüft, ist schlechter als gar keines: es steht in der
* Befehlsliste, jemand ruft es auf, bekommt keine Beanstandung und hält das
* für ein Ergebnis.
*
* Zwei Festlegungen bestimmen, was hier drinsteht:
*
* **Keine Formatierungsregeln.** Die macht Prettier. Zwei Werkzeuge, die sich
* über Anführungszeichen und Zeilenlängen streiten, sind eines zu viel — und
* die Streitpunkte lenken von den Regeln ab, auf die es ankommt.
*
* **Nur Regeln, die einen echten Fehler anzeigen.** Der Maßstab sind die
* Fehler, die in diesem Projekt tatsächlich passiert sind:
*
* - `react-hooks/exhaustive-deps` hätte den Kiosk-Fehler aus Phase 4
* gemeldet: eine Mutation von React Query in den Abhängigkeiten eines
* useCallback, wodurch der Wiederholungszeitgeber der Warteschlange nie
* ansprang. Gefunden hat ihn damals ein E2E-Test — teuer.
* - unbenutzte Importe blieben in Phase 7 zweimal liegen und fielen erst
* beim Lesen auf.
* - `react/jsx-key` und `react/no-unescaped-entities` kommen aus den
* Next-Regeln und fangen genau die Sorte Flüchtigkeitsfehler, die man
* beim Lesen überliest.
*
* Bewusst **nicht** eingeschaltet sind die typgestützten Regeln von
* typescript-eslint (`no-floating-promises` und Verwandte). Sie brauchen den
* Compiler bei jedem Lauf, und der Lauf dauert dann Minuten statt Sekunden —
* bei einem Werkzeug, das vor jedem Commit laufen soll, ist das der falsche
* Tausch. `npm run typecheck` deckt den größten Teil davon ohnehin ab.
*/
const __dirname = dirname(fileURLToPath(import.meta.url));
const compat = new FlatCompat({ baseDirectory: __dirname });
/** Die Konfiguration selbst — benannt, damit sie kein anonymer Export ist. */
const konfiguration = [
{
ignores: [
".next/**",
"node_modules/**",
"playwright-report/**",
"test-results/**",
"coverage/**",
"docs/**",
// Von Prisma erzeugt, nicht von Hand geschrieben.
"src/generated/**",
"next-env.d.ts",
// Ein gewoehnliches Node-Skript fuer den Healthcheck des Containers.
// Es laeuft ausserhalb des Bundles, ist CommonJS und hat mit den
// Next-Regeln nichts zu tun.
"docker/healthcheck.js",
],
},
// Die Next-Regeln über die alte Schreibweise einbinden: eslint-config-next
// liefert noch keine Flat Config.
...compat.extends("next/core-web-vitals", "next/typescript"),
{
rules: {
/**
* Unbenutztes ist ein Fehler, kein Schönheitsmakel: ein Import, den
* niemand braucht, ist meistens der Rest einer halb zurückgebauten
* Änderung.
*
* Ausnahme sind Bezeichner mit führendem Unterstrich — so wird in
* diesem Projekt seit Phase 0 gekennzeichnet, dass ein Parameter
* absichtlich ungenutzt bleibt (`_anfrage`, `_abo`).
*/
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
/**
* Die Regel, die den teuersten Fehler des Projekts gemeldet hätte.
* Bewusst als Fehler und nicht als Warnung: Warnungen liest nach zwei
* Wochen niemand mehr.
*/
"react-hooks/exhaustive-deps": "error",
/**
* `any` schaltet den Compiler ab. Wo es unvermeidlich ist — bei
* Roh-SQL und beim Auswerten fremder Antworten —, steht es mit einer
* Ausnahmezeile und einer Begründung da.
*/
"@typescript-eslint/no-explicit-any": "error",
/** Ein leeres catch verschluckt genau den Fehler, den man sucht. */
"no-empty": ["error", { allowEmptyCatch: false }],
/**
* `console.log` gehört nicht in den Bestand. `console.info`, `.warn`
* und `.error` schon — der Worker und die Integrationen schreiben ihre
* Meldungen so, und die will man im Betrieb sehen.
*/
"no-console": ["error", { allow: ["info", "warn", "error"] }],
},
},
{
// In Tests ist `console.log` beim Fehlersuchen legitim, und die
// Abhängigkeitsregel für Hooks greift dort ohnehin nicht.
files: ["tests/**/*.ts", "tests/**/*.tsx", "scripts/**/*.ts", "prisma/**/*.ts"],
rules: {
"no-console": "off",
},
},
{
// Der Service Worker läuft außerhalb des Bundles und kennt weder Node
// noch die Browser-Globals in der Fassung, die ESLint hier annimmt.
files: ["public/sw.js"],
languageOptions: {
globals: { self: "readonly", caches: "readonly", clients: "readonly" },
},
rules: {
"no-undef": "off",
},
},
];
export default konfiguration;