Anfuehrungszeichen: 199 falsche Schlusszeichen im sichtbaren Text
Deutsch oeffnet mit „ und schliesst mit “. An 199 Stellen, die ein
Mensch liest, stand als Schlusszeichen ein GERADES " -- „Nächstes"
statt „Nächstes“. Auf sechzehn oeffentlichen Seiten, in vierzig
Dateien des Workspace und in zwoelf Servermodulen, die Texte
verschicken.
Auf dem Bildschirm sieht man den Unterschied sofort. Beim Schreiben
nicht: Das gerade " liegt auf der Tastatur, die anderen nicht.
WARUM EIN ERSTER ANLAUF ZURUECKGENOMMEN WURDE
Ein gerades " ist an vielen Stellen SYNTAX und kein Schriftzeichen --
Grenze einer Zeichenkette, Grenze eines HTML-Attributs, Zeichen in
einem regulaeren Ausdruck. Wer stumpf ersetzt, macht aus
„<a href="https://… ein kaputtes Attribut
/^["'„»\s]+|["'“«.\s]+$/ einen kaputten Ausdruck
"… nichts „mal " + "eben …" eine kaputte Zeichenkette
DIE UNTERSCHEIDUNG LAEUFT AN MERKMALEN, NICHT AN EINER LISTE
< > = dazwischen -> HTML-Marke oder Attribut
endet auf Leerzeichen -> die Zeichenkette hoert hier auf, der
Satz geht in der naechsten Zeile weiter.
Ein deutsches Schlusszeichen steht NIE
hinter einem Leerzeichen.
Rueckstrich mittendrin -> regulaerer Ausdruck
${ ohne } -> mitten in einem Ausdruck
Eine Liste erlaubter Ausnahmen waere die naechste, die niemand
pflegt. Zwoelf Stellen bleiben dadurch stehen, alle zwoelf einzeln
angesehen und alle zwoelf zu Recht -- dort steht das richtige
Schlusszeichen ohnehin weiter unten im Satz.
Fuenf davon waren allerdings ECHTE Fehler HINTER dem Link
(`…>HasiDog</a>".`) -- die erste Regel hatte nur das Attribut
gesehen, nicht den Satz danach. Gezielt nachgezogen.
Ein maskiertes `\"` in workspace-vorlagen.js (28 Hooks) wird zu “ --
ohne Rueckstrich, denn “ begrenzt nichts.
KOMMENTARE BLEIBEN, WIE SIE SIND. Dort liest es niemand ausser mir;
eine Wache, die auch Kosmetik anmahnt, wird weggeklickt. Beim ersten
Messen fielen ausserdem acht Stellen aus buehne.html faelschlich an,
weil `/* */` in HTML (in <style> und <script>) nicht ausgeblendet
war -- jetzt schon.
DIE WACHE DAZU
pruef-struktur prueft es ab sofort mit derselben Regel: 322 Dateien
mit sichtbarem Text, 0 Funde, und die zwoelf bewussten Ausnahmen
werden GEZAEHLT und genannt (erlaubt: 12). Eine Ausnahme, die niemand
sieht, waechst -- und irgendwann steht der echte Fall darin.
GEPRUEFT
pruef-struktur 59 -> 68 Pruefungen, 0 Fehler
node --check auf allen geaenderten JS-Dateien
nachgemessen: 199 geaendert, 12 mit Grund stehen geblieben
gruen geblieben: bewerbung-aufgaben 163, nachwuchs 262,
reaktion 421, support 63, content 45, terminregel 35, treff 85
Und nachgesehen, ob eine Pruefung noch die alte Schreibweise
ERWARTET: 13 Fundstellen, alle dreizehn nur Text in ihrer eigenen
Ausgabe, keine einzige ein Vergleich mit dem Seitentext.
GEGENPROBE: In reaktion.html ein Schlusszeichen zurueckgedreht ->
„workspace/reaktion.html:546 „Nächstes"", mit Datei und Zeile. Und
die Erkennung einzeln gegen HTML-Attribut, fortgesetzte
Zeichenkette, regulaeren Ausdruck und eingesetzten Wert geprueft.
Stempel gesetzt: workspace 670 Verweise in 45 Dateien, oeffentlich
554 in 48 Seiten.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+121
-1
@@ -28,7 +28,7 @@
|
||||
werden. Eine Pruefung, die immer bestaetigt, bestaetigt nichts. */
|
||||
|
||||
import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
|
||||
import { join, dirname, resolve } from "node:path";
|
||||
import { sep, join, dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { brotliCompressSync, constants } from "node:zlib";
|
||||
|
||||
@@ -772,6 +772,126 @@ console.log(`\n=== Laedt jedes Server-Modul? ===`);
|
||||
Deshalb wird es hier gesucht, statt darauf zu warten, dass es wieder
|
||||
jemanden trifft. Gemeint ist nur das TAGESDATUM; ein Zeitstempel
|
||||
(`erstellt`) darf und soll UTC sein. */
|
||||
console.log(`\n=== Das deutsche Schlusszeichen ===`);
|
||||
/* ===================================================================
|
||||
AM 01.10.2026 NACHGEMESSEN: 199 Stellen, die ein Mensch liest,
|
||||
schlossen ein deutsches Anfuehrungszeichen mit einem GERADEN " --
|
||||
auf sechzehn oeffentlichen Seiten, in vierzig Dateien des
|
||||
Workspace und in zwoelf Servermodulen, die Texte verschicken.
|
||||
|
||||
Deutsch oeffnet mit \u201E und schliesst mit \u201C. Auf dem
|
||||
Bildschirm sieht man den Unterschied sofort; beim Schreiben nicht,
|
||||
denn das gerade " liegt auf der Tastatur und die anderen nicht.
|
||||
Ohne Wache sind es in vier Wochen wieder zwanzig.
|
||||
|
||||
WAS BEWUSST STEHEN BLEIBT -- und warum die Regel so und nicht
|
||||
einfacher ist: Ein gerades " ist an vielen Stellen SYNTAX und kein
|
||||
Schriftzeichen. Es begrenzt eine Zeichenkette, ein HTML-Attribut
|
||||
oder steht in einem regulaeren Ausdruck. Ein erster Anlauf, der
|
||||
stumpf ersetzte, musste zurueckgenommen werden.
|
||||
|
||||
Die Unterscheidung laeuft an Merkmalen, nicht an einer Liste von
|
||||
Ausnahmen:
|
||||
< > = dazwischen -> HTML-Marke oder Attribut
|
||||
endet auf Leerzeichen -> die Zeichenkette hoert hier auf, der
|
||||
Satz geht in der naechsten Zeile weiter. Ein deutsches
|
||||
Schlusszeichen steht NIE hinter einem Leerzeichen.
|
||||
Rueckstrich mittendrin -> regulaerer Ausdruck
|
||||
${ ohne } -> mitten in einem Ausdruck
|
||||
=================================================================== */
|
||||
{
|
||||
const AUF = "\u201E"; /* „ */
|
||||
const ZU = "\u201C"; /* “ */
|
||||
/* Zusammengesetzt und nicht ausgeschrieben: Sonst zeigte diese
|
||||
Datei sich beim naechsten Lauf selbst an. */
|
||||
const suche = new RegExp(AUF + '([^' + ZU + AUF + '"`\n]{1,140})"', "g");
|
||||
|
||||
const warumNicht = (innen) => {
|
||||
if (/[<>=]/.test(innen)) return "HTML-Marke oder Attribut";
|
||||
if (innen.endsWith(" ")) return "Satz geht in der naechsten Zeile weiter";
|
||||
if (innen.replace(/\\+$/, "").includes("\\")) return "regulaerer Ausdruck";
|
||||
if ((innen.match(/\$\{/g) || []).length !== (innen.match(/\}/g) || []).length) {
|
||||
return "offener Ausdruck";
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/* WAS EIN MENSCH LIEST: die oeffentlichen Seiten, der Workspace und
|
||||
die Servermodule, die Texte verschicken. Pruef- und Messdateien
|
||||
schreiben nur in meine Konsole -- dort waere es Kosmetik, und
|
||||
eine Wache, die auch Kosmetik anmahnt, wird weggeklickt. */
|
||||
const sammeln = (ordner, tiefe = 0) => {
|
||||
const raus = [];
|
||||
for (const e of readdirSync(ordner, { withFileTypes: true })) {
|
||||
if (e.name === "node_modules" || e.name.startsWith(".")) continue;
|
||||
const voll = join(ordner, e.name);
|
||||
if (e.isDirectory()) { if (tiefe < 4) raus.push(...sammeln(voll, tiefe + 1)); continue; }
|
||||
if (/\.(js|mjs|html|css)$/.test(e.name)) raus.push(voll);
|
||||
}
|
||||
return raus;
|
||||
};
|
||||
const dateien = [
|
||||
...sammeln(join(SERVER, "..", "workspace")),
|
||||
...sammeln(join(SERVER, "..", "assets")),
|
||||
...readdirSync(join(SERVER, "..")).filter((n) => n.endsWith(".html"))
|
||||
.map((n) => join(SERVER, "..", n)),
|
||||
...readdirSync(SERVER).filter((n) => n.startsWith("workspace-") && n.endsWith(".js"))
|
||||
.map((n) => join(SERVER, n)),
|
||||
];
|
||||
ok(dateien.length > 100, `${dateien.length} Dateien mit sichtbarem Text angesehen`);
|
||||
|
||||
const falsch = [];
|
||||
const stehenGelassen = [];
|
||||
for (const pfad of dateien) {
|
||||
const art = pfad.slice(pfad.lastIndexOf("."));
|
||||
let text = readFileSync(pfad, "utf8")
|
||||
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
|
||||
.replace(/<!--[\s\S]*?-->/g, (m) => m.replace(/[^\n]/g, " "));
|
||||
if (art === ".js" || art === ".mjs") {
|
||||
text = text.replace(/^\s*\/\/.*$/gm, "");
|
||||
}
|
||||
/* Der Pfad AB DER WURZEL des Projekts -- ein abgeschnittener
|
||||
Pfad ist eine Meldung, der man nicht folgen kann. */
|
||||
const kurz = pfad.split(sep).join("/").split("/DogiHompage/").pop();
|
||||
for (const t of text.matchAll(suche)) {
|
||||
const zeile = text.slice(0, t.index).split("\n").length;
|
||||
const nein = warumNicht(t[1]);
|
||||
if (nein) stehenGelassen.push(`${kurz}:${zeile} (${nein})`);
|
||||
else falsch.push(`${kurz}:${zeile} ${AUF}${t[1].slice(0, 40)}"`);
|
||||
}
|
||||
}
|
||||
ok(falsch.length === 0,
|
||||
falsch.length
|
||||
? `schliessen ein deutsches Anfuehrungszeichen mit einem geraden ":\n `
|
||||
+ falsch.slice(0, 15).join("\n ")
|
||||
+ (falsch.length > 15 ? `\n ... und ${falsch.length - 15} weitere` : "")
|
||||
: `kein sichtbarer Text schliesst mit einem geraden " (${dateien.length} Dateien)`);
|
||||
|
||||
/* DIE AUSNAHMEN WERDEN GEZAEHLT UND GENANNT. Eine Ausnahme, die
|
||||
niemand sieht, waechst -- und irgendwann steht der echte Fall
|
||||
darin und faellt nicht mehr auf. */
|
||||
ok(stehenGelassen.length <= 12,
|
||||
`${stehenGelassen.length} Stellen bleiben mit Grund stehen`
|
||||
+ ` (erlaubt: 12) — ${stehenGelassen.slice(0, 3).join(", ") || "—"}`);
|
||||
|
||||
/* ---- GEGENPROBEN ------------------------------------------------ */
|
||||
const findet = (code) => {
|
||||
const treffer = [...code.matchAll(new RegExp(suche.source, "g"))];
|
||||
return treffer.filter((t) => !warumNicht(t[1])).length;
|
||||
};
|
||||
ok(findet(`Er sagte ${AUF}hallo".`) === 1,
|
||||
"Gegenprobe: ein gerades Schlusszeichen faellt auf");
|
||||
ok(findet(`Er sagte ${AUF}hallo${ZU}.`) === 0, " das richtige NICHT");
|
||||
ok(findet(`${AUF}<a href="x">y</a>`) === 0,
|
||||
" ein HTML-Attribut ist kein Schlusszeichen");
|
||||
ok(findet(`"… nichts ${AUF}mal " + "eben …"`) === 0,
|
||||
" und die Begrenzung einer Zeichenkette, die weitergeht, auch nicht");
|
||||
ok(findet('/^["\'' + AUF + '»\\s]+|["]/') === 0,
|
||||
" ein regulaerer Ausdruck ebenfalls nicht");
|
||||
ok(findet(AUF + "${a.titel}\"") === 1,
|
||||
" ein eingesetzter Wert dagegen schon");
|
||||
}
|
||||
|
||||
console.log(`\n=== Ruft ein Modul etwas, das es nie eingefuehrt hat? ===`);
|
||||
/* ===================================================================
|
||||
AM 01.10.2026 SELBST GEBAUT UND FAST AUSGELIEFERT.
|
||||
|
||||
Reference in New Issue
Block a user