fix: …
Some checks failed
CI / build-and-anchors (push) Failing after 2m6s
SMOKE / smoke (push) Successful in 13s

This commit is contained in:
2026-02-23 12:07:01 +01:00
parent ae809e0152
commit 68c3416594
19 changed files with 930 additions and 240 deletions

View File

@@ -60,10 +60,12 @@ function getAlias(aliases, pageKey, oldId) {
// supporte:
// 1) { "<pageKey>": { "<old>": "<new>" } }
// 2) { "<old>": "<new>" }
const a1 = aliases?.[pageKey]?.[oldId];
if (a1) return a1;
const k1 = String(pageKey || "");
const k2 = k1 ? ("/" + k1.replace(/^\/+|\/+$/g, "") + "/") : "";
const a1 = (aliases?.[k1]?.[oldId]) || (k2 ? aliases?.[k2]?.[oldId] : "");
if (a1) return String(a1);
const a2 = aliases?.[oldId];
if (a2) return a2;
if (a2) return String(a2);
return "";
}

View File

@@ -14,6 +14,24 @@ const STRICT = argv.includes("--strict") || process.env.CI === "1" || process.en
function escRe(s) {
return String(s).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
async function exists(p) {
try {
await fs.access(p);
return true;
} catch {
return false;
}
}
function normalizeRoute(route) {
let r = String(route || "").trim();
if (!r.startsWith("/")) r = "/" + r;
if (!r.endsWith("/")) r = r + "/";
r = r.replace(/\/{2,}/g, "/");
return r;
}
function countIdAttr(html, id) {
const re = new RegExp(`\\bid=(["'])${escRe(id)}\\1`, "gi");
let c = 0;
@@ -22,7 +40,6 @@ function countIdAttr(html, id) {
}
function findStartTagWithId(html, id) {
// 1er élément qui porte id="..."
const re = new RegExp(
`<([a-zA-Z0-9:-]+)\\b[^>]*\\bid=(["'])${escRe(id)}\\2[^>]*>`,
"i"
@@ -36,34 +53,10 @@ function isInjectedAliasSpan(html, id) {
const found = findStartTagWithId(html, id);
if (!found) return false;
if (found.tagName !== "span") return false;
// class="... para-alias ..."
return /\bclass=(["'])(?:(?!\1).)*\bpara-alias\b(?:(?!\1).)*\1/i.test(found.tag);
}
function normalizeRoute(route) {
let r = String(route || "").trim();
if (!r.startsWith("/")) r = "/" + r;
if (!r.endsWith("/")) r = r + "/";
r = r.replace(/\/{2,}/g, "/");
return r;
}
async function exists(p) {
try {
await fs.access(p);
return true;
} catch {
return false;
}
}
function hasId(html, id) {
const re = new RegExp(`\\bid=(["'])${escRe(id)}\\1`, "i");
return re.test(html);
}
function injectBeforeId(html, newId, injectHtml) {
// insère juste avant la balise qui porte id="newId"
const re = new RegExp(
`(<[^>]+\\bid=(["'])${escRe(newId)}\\2[^>]*>)`,
"i"
@@ -82,6 +75,7 @@ async function main() {
}
const raw = await fs.readFile(ALIASES_PATH, "utf-8");
/** @type {Record<string, Record<string,string>>} */
let aliases;
try {
@@ -89,6 +83,7 @@ async function main() {
} catch (e) {
throw new Error(`JSON invalide: ${ALIASES_PATH} (${e?.message || e})`);
}
if (!aliases || typeof aliases !== "object" || Array.isArray(aliases)) {
throw new Error(`Format invalide: attendu { route: { oldId: newId } } dans ${ALIASES_PATH}`);
}
@@ -114,10 +109,10 @@ async function main() {
console.log(msg);
warnCount++;
}
if (entries.length === 0) continue;
const rel = route.replace(/^\/+|\/+$/g, ""); // sans slash
const rel = route.replace(/^\/+|\/+$/g, "");
const htmlPath = path.join(DIST_ROOT, rel, "index.html");
if (!(await exists(htmlPath))) {
@@ -135,24 +130,8 @@ async function main() {
if (!oldId || !newId) continue;
const oldCount = countIdAttr(html, oldId);
if (oldCount > 0) {
// ✅ déjà injecté (idempotent)
if (isInjectedAliasSpan(html, oldId)) continue;
// ⛔️ oldId existe déjà "en vrai" (ex: <p id="oldId">)
// => alias inutile / inversé / obsolète
const found = findStartTagWithId(html, oldId);
const where = found ? `<${found.tagName} … id="${oldId}" …>` : `id="${oldId}"`;
const msg =
`⚠️ alias inutile/inversé: oldId déjà présent dans la page (${where}). ` +
`Supprime l'alias ${oldId} -> ${newId} (ou corrige le sens) pour route=${route}`;
if (STRICT) throw new Error(msg);
console.log(msg);
warnCount++;
continue;
}
// juste après avoir calculé oldCount
// ✅ déjà injecté => idempotent
if (oldCount > 0 && isInjectedAliasSpan(html, oldId)) {
if (STRICT && oldCount !== 1) {
throw new Error(`oldId dupliqué (${oldCount}) alors qu'il est censé être unique: ${route} id=${oldId}`);
@@ -160,18 +139,23 @@ async function main() {
continue;
}
// avant l'injection, après hasId(newId)
const newCount = countIdAttr(html, newId);
if (newCount !== 1) {
const msg = `⚠️ newId non-unique (${newCount}) : ${route} new=${newId} (injection ambiguë)`;
// ⛔️ oldId existe déjà "en vrai" => alias inutile/inversé
if (oldCount > 0) {
const found = findStartTagWithId(html, oldId);
const where = found ? `<${found.tagName} … id="${oldId}" …>` : `id="${oldId}"`;
const msg =
`⚠️ alias inutile/inversé: oldId déjà présent (${where}). ` +
`Supprime ${oldId} -> ${newId} (ou corrige le sens) pour route=${route}`;
if (STRICT) throw new Error(msg);
console.log(msg);
warnCount++;
continue;
}
if (!hasId(html, newId)) {
const msg = `⚠️ newId introuvable: ${route} old=${oldId} -> new=${newId}`;
// newId doit exister UNE fois (sinon injection ambiguë)
const newCount = countIdAttr(html, newId);
if (newCount !== 1) {
const msg = `⚠️ newId non-unique (${newCount}) : ${route} new=${newId} (injection ambiguë)`;
if (STRICT) throw new Error(msg);
console.log(msg);
warnCount++;

View File

@@ -0,0 +1,31 @@
// scripts/purge-dist-dev-whoami.mjs
import fs from "node:fs/promises";
import path from "node:path";
const CWD = process.cwd();
const targetDir = path.join(CWD, "dist", "_auth", "whoami");
const targetIndex = path.join(CWD, "dist", "_auth", "whoami", "index.html");
// Purge idempotente (force=true => pas d'erreur si absent)
async function rmSafe(p) {
try {
await fs.rm(p, { recursive: true, force: true });
return true;
} catch {
return false;
}
}
async function main() {
const removedIndex = await rmSafe(targetIndex);
const removedDir = await rmSafe(targetDir);
// Optionnel: si dist/_auth devient vide, on laisse tel quel (pas besoin de toucher)
const any = removedIndex || removedDir;
console.log(`✅ purge-dist-dev-whoami: ${any ? "purged" : "nothing to purge"}`);
}
main().catch((e) => {
console.error("❌ purge-dist-dev-whoami failed:", e);
process.exit(1);
});

View File

@@ -205,7 +205,7 @@ for (const [route, mapping] of Object.entries(data)) {
newId,
htmlPath,
msg:
`oldId present but is NOT an injected alias span (<span class="para-alias">).</n` +
`oldId present but is NOT an injected alias span (<span class="para-alias">).\n` +
`Saw: ${seen}`,
});
continue;

View File

@@ -0,0 +1,26 @@
import fs from "node:fs/promises";
import path from "node:path";
const OUT = path.join(process.cwd(), "public", "_auth", "whoami");
const groupsRaw = process.env.PUBLIC_WHOAMI_GROUPS ?? "editors";
const user = process.env.PUBLIC_WHOAMI_USER ?? "dev";
const name = process.env.PUBLIC_WHOAMI_NAME ?? "Dev Local";
const email = process.env.PUBLIC_WHOAMI_EMAIL ?? "area.technik@proton.me";
const groups = groupsRaw
.split(/[;,]/)
.map((s) => s.trim())
.filter(Boolean)
.join(",");
const body =
`Remote-User: ${user}\n` +
`Remote-Name: ${name}\n` +
`Remote-Email: ${email}\n` +
`Remote-Groups: ${groups}\n`;
await fs.mkdir(path.dirname(OUT), { recursive: true });
await fs.writeFile(OUT, body, "utf8");
console.log(`✅ dev whoami written: ${path.relative(process.cwd(), OUT)} (${groups})`);