Der Waechter gegen Namensstreit gilt jetzt fuer das ganze Haus
Er wurde gestern fuer `reaktion.css` gebaut, nachdem `.stufen` dort
zweimal stand und die Stufenleiter der Spenden dadurch das Aussehen
der Chat-Leiste bekam -- drei Stufen nebeneinander, 572 Pixel in
einer 327 Pixel schmalen Spalte, mit der waagerechten Rollleiste auf
Filipes Bildschirmfoto.
Eine Wache, die nur eine Datei ansieht, findet genau die Fehler
dieser einen Datei. Auf alle 36 Stilvorlagen angewandt fand sie
GENAU EINE weitere Stelle.
DER FUND: `.wahl2__eintrag` in gate.css
Zeile 1584 display: block (mit text-overflow: ellipsis)
Zeile 2634 display: flex (fuer Personenbilder, 08.09.2026)
Kein Streit zweier Bauteile, sondern eine spaetere Erweiterung --
und trotzdem ein echter Fehler: `text-overflow: ellipsis` wirkt bei
`display: flex` NICHT auf ein anonymes Flex-Kind. Der Knopf
„… eintragen" in jeder Auswahl des Hauses hat langen Text seither
HART abgeschnitten statt mit „…" gekuerzt.
GEMESSEN -- und nur im Bild zu sehen: `scrollWidth` ist in beiden
Faellen gleich (364 px bei 200 px Breite). Die Zahlen sagten
„kein Unterschied", das Bildschirmfoto zeigte einen. Ein Beleg mehr
dafuer, dass zwei gleiche Zahlen nicht dasselbe Ergebnis bedeuten.
REPARIERT
- Der eigene Eintrag bekommt einen `.wahl2__name`-Span, wie jeder
andere Eintrag auch. Damit kuerzt er wieder mit „…".
- Die zwei Grundregeln sind eine. Wer die erste las, glaubte an
`display: block` -- 1050 Zeilen weiter stand das Gegenteil.
DIE WACHE
923 Grundregeln in 36 Stilvorlagen, keine Klasse zweimal
verschieden gebaut. Gezaehlt wird nur, was sich widersprechen
kann: nicht dieselbe Klasse in einem Zusammenhang (`.saal .pult`),
nicht eine Variante in einer Medienabfrage, nicht
„erst versteckt, dann gezeigt". Sechs Gegenproben, darunter der
echte Fall vom 28.09. und eine Klasse im Kommentar.
GEPRUEFT: css-klassen, freie-namen, suchfeld, tippziele alle EXIT 0.
This commit is contained in:
@@ -899,5 +899,90 @@ function formfehler(text) {
|
||||
: `Gegenprobe: alle ${proben.length} Faelle richtig eingeordnet`);
|
||||
}
|
||||
|
||||
/* ==== ZWEI GRUNDREGELN, EIN NAME, ZWEI BAUARTEN =====================
|
||||
|
||||
Gebaut am 28.09.2026 fuer `reaktion.css`, wo `.stufen` zweimal
|
||||
stand: einmal fuer die Stufenleiter der Spenden (`display: grid`),
|
||||
600 Zeilen spaeter fuer die Chat-Leiste (`display: flex`). Die
|
||||
spaetere gewinnt -- und die Stufenleiter stellte ihre drei Stufen
|
||||
nebeneinander, 572 Pixel in einer 327 Pixel schmalen Spalte, mit
|
||||
waagerechter Rollleiste. Auf dem Bildschirmfoto sah das aus wie
|
||||
ein Platzproblem.
|
||||
|
||||
AB JETZT FUER ALLE STILVORLAGEN. Eine Wache, die nur eine Datei
|
||||
ansieht, findet genau die Fehler dieser einen Datei -- und der
|
||||
zweite Fund lag in gate.css.
|
||||
|
||||
GEZAEHLT WIRD NUR, WAS SICH WIDERSPRECHEN KANN:
|
||||
- Die Auswahl muss GENAU die Klasse sein. `.saal .pult { … }`
|
||||
ist dieselbe Klasse in einem Zusammenhang, kein zweites
|
||||
Bauteil.
|
||||
- Regeln in einer Medienabfrage zaehlen nicht -- sie sind per
|
||||
Definition Varianten fuer eine andere Umgebung.
|
||||
- `display: none` zaehlt nicht. „Erst versteckt, dann gezeigt"
|
||||
ist das haeufigste Paar im Haus; wer es meldet, baut eine
|
||||
Warnung, die immer kommt. */
|
||||
{
|
||||
const ordner = join(HIER, "..", "workspace", "assets", "css");
|
||||
const ohneMedien = (t) => t.replace(
|
||||
/@media[^{]*\{(?:[^{}]|\{[^{}]*\})*\}/g,
|
||||
(m) => m.replace(new RegExp("[^" + String.fromCharCode(10) + "]", "g"), " "));
|
||||
const positiv = (w) => w && w !== "none" && !/^none\b/.test(w);
|
||||
/* LOOKBEHIND STATT VERBRAUCHEN: Mit `(^|[};])` frisst der erste
|
||||
Treffer die Klammer, die der naechste als Anfang braeuchte --
|
||||
`.a { … } .a { … }` liefert dann nur EINEN Treffer, und genau
|
||||
der Fall, um den es geht, faellt durch. */
|
||||
const grundregeln = (roh) => {
|
||||
const raus = {};
|
||||
const text = ohneMedien(roh.replace(/\/\*[\s\S]*?\*\//g,
|
||||
(m) => m.replace(new RegExp("[^" + String.fromCharCode(10) + "]", "g"), " ")));
|
||||
for (const m of text.matchAll(
|
||||
/(?:^|(?<=[};]))\s*(\.(-?[a-zA-Z_][a-zA-Z0-9_-]*))\s*\{([^{}]*)\}/g)) {
|
||||
const w = (m[3].match(/(?:^|[\s;])display\s*:\s*([^;]+)/) || [, ""])[1].trim();
|
||||
if (!positiv(w)) continue;
|
||||
(raus[m[2]] ||= []).push(w);
|
||||
}
|
||||
return raus;
|
||||
};
|
||||
const streitIn = (roh) => Object.entries(grundregeln(roh))
|
||||
.filter(([, was]) => new Set(was).size > 1)
|
||||
.map(([name, was]) => `${name} (${[...new Set(was)].join(" vs. ")})`);
|
||||
|
||||
const dateien = readdirSync(ordner).filter((n) => n.endsWith(".css"));
|
||||
const funde = [];
|
||||
let geprueft = 0;
|
||||
for (const name of dateien) {
|
||||
const roh = readFileSync(join(ordner, name), "utf8");
|
||||
geprueft += Object.keys(grundregeln(roh)).length;
|
||||
for (const z of streitIn(roh)) funde.push(`${name}: ${z}`);
|
||||
}
|
||||
ok(geprueft > 100 && funde.length === 0,
|
||||
funde.length ? `Namensstreit: ${funde.join(" | ")}`
|
||||
: `${geprueft} Grundregeln in ${dateien.length} Stilvorlagen -- `
|
||||
+ "keine Klasse zweimal verschieden gebaut");
|
||||
|
||||
/* GEGENPROBEN IN BEIDE RICHTUNGEN. */
|
||||
const faelle = [
|
||||
["der Fall vom 28.09. (zwei Grundregeln, anderes display)",
|
||||
".stufen { display: grid; } .stufen { display: flex; }", true],
|
||||
["verstecken und zeigen",
|
||||
".probe { display: none; } .probe { display: grid; }", false],
|
||||
["dieselbe Klasse in einem Zusammenhang",
|
||||
".pult { display: grid; } .saal .pult { display: flex; }", false],
|
||||
["eine Variante in einer Medienabfrage",
|
||||
".paar { display: grid; } @media (pointer: coarse) { .paar { display: flex; } }", false],
|
||||
["zweimal dasselbe display",
|
||||
".gleich { display: grid; } .gleich { display: grid; }", false],
|
||||
["eine Klasse im Kommentar",
|
||||
"/* .a { display: flex; } */ .a { display: grid; }", false],
|
||||
];
|
||||
const daneben = faelle
|
||||
.filter(([, text, soll]) => (streitIn(text).length > 0) !== soll)
|
||||
.map(([name]) => name);
|
||||
ok(daneben.length === 0,
|
||||
daneben.length ? `Gegenprobe daneben bei: ${daneben.join(", ")}`
|
||||
: `Gegenprobe: alle ${faelle.length} Faelle richtig eingeordnet`);
|
||||
}
|
||||
|
||||
console.log(`\n${fehler === 0 ? "ALLES IN ORDNUNG" : `${fehler} FEHLER`}`);
|
||||
process.exit(fehler ? 1 : 0);
|
||||
|
||||
Reference in New Issue
Block a user