/* ===================================================================== Sucht doppelt vergebene Funktionsnamen. ANLASS Am 26.08.2026 brachte neuer Code eine Hilfsfunktion namens "kachel" mit. Weiter oben in derselben Datei gab es seit langem eine andere Funktion desselben Namens, die die Kacheln der Uebersicht baut. JavaScript kennt keine Ueberladung: Die spaetere Definition gewinnt. Ohne Warnung, ohne Fehler, ohne dass irgendetwas anschlaegt. Die Uebersicht zeigte danach in jeder Kachel "[object Object]". WARUM KEIN ANDERES WERKZEUG DAS FINDET - Der Browser meldet nichts: Zwei Funktionen desselben Namens sind erlaubtes JavaScript. - "node --check" meldet nichts: syntaktisch einwandfrei. - Die Oberflaechen-Tests meldeten nichts: Sie pruefen, ob Kacheln DA sind, nicht ob sinnvoller Text darin steht. - Am tueckischsten: Der neue Code selbst funktionierte einwandfrei. Der Schaden trat an einer ganz anderen Stelle auf, und nichts deutete auf die Ursache hin. Diese Pruefung kostet Sekundenbruchteile und haette den Fehler verhindert, bevor er ausgeliefert wurde. ===================================================================== */ import fs from "fs"; import path from "path"; let ok = 0, fehl = 0; const pruefe = (name, gut, info) => { if (gut) { ok++; console.log(" ok " + name + (info ? " -> " + info : "")); } else { fehl++; console.log(" FEHL " + name + (info ? " -> " + info : "")); } }; const WURZEL = process.cwd(); /* Alle Dateien mit eigenem JavaScript: die grossen Inline-Bloecke der Seiten und die Skriptdateien. */ const dateien = [ ...fs.readdirSync(WURZEL).filter((f) => f.endsWith(".html")).map((f) => f), ...fs.readdirSync(path.join(WURZEL, "webdesign")) .filter((f) => f.endsWith(".html")).map((f) => "webdesign/" + f), ...fs.readdirSync(path.join(WURZEL, "assets/js")) .filter((f) => f.endsWith(".js")).map((f) => "assets/js/" + f), ]; console.log(`Durchsucht: ${dateien.length} Dateien\n`); const betroffen = []; for (const rel of dateien) { const quelle = fs.readFileSync(path.join(WURZEL, rel), "utf8"); /* Nur Deklarationen am Zeilenanfang (mit Einrueckung). Damit bleiben Methoden in Objekten, verschachtelte Hilfsfunktionen in anderen Funktionen und Zeichenketten aussen vor -- die kollidieren nicht miteinander, weil sie in eigenen Gueltigkeitsbereichen liegen. */ const muster = /^[ \t]*function\s+([A-Za-z_$][\w$]*)\s*\(/gm; const gesehen = new Map(); let t; while ((t = muster.exec(quelle)) !== null) { const name = t[1]; const zeile = quelle.slice(0, t.index).split("\n").length; if (!gesehen.has(name)) gesehen.set(name, []); gesehen.get(name).push(zeile); } for (const [name, zeilen] of gesehen) { if (zeilen.length > 1) { betroffen.push({ datei: rel, name, zeilen }); } } } pruefe("kein Funktionsname ist doppelt vergeben", betroffen.length === 0, betroffen.length ? betroffen.length + " Kollision(en)" : dateien.length + " Dateien sauber"); for (const b of betroffen) { console.log(`\n ${b.datei}`); console.log(` "${b.name}" steht in Zeile ${b.zeilen.join(" und ")}`); console.log(` Die spaetere gewinnt — die fruehere ist damit wirkungslos.`); } /* Gegenprobe: Die Pruefung muss auch wirklich etwas finden koennen. Ohne diesen Abschnitt koennte das Muster kaputt sein und immer "sauber" melden. */ console.log("\nGEGENPROBE"); const beispiel = ` function tuwas(a) { return a; } var x = 1; function tuwas(a, b) { return b; } `; const m2 = /^[ \t]*function\s+([A-Za-z_$][\w$]*)\s*\(/gm; const treffer = [...beispiel.matchAll(m2)].map((x) => x[1]); pruefe(" findet eine eingebaute Kollision", treffer.filter((n) => n === "tuwas").length === 2, treffer.join(", ")); console.log(`\n===== ${ok} bestanden, ${fehl} fehlgeschlagen =====`); process.exit(fehl ? 1 : 0);