Files
archicratie-edition/scripts/audit-glossary-navigation.mjs
Archicratia bfe8b3b45a
All checks were successful
SMOKE / smoke (push) Successful in 4s
CI / build-and-anchors (push) Successful in 44s
CI / build-and-anchors (pull_request) Successful in 41s
chore(glossaire): ajouter une gouvernance minimale du graphe
2026-04-28 21:00:53 +02:00

67 lines
1.5 KiB
JavaScript

import fs from "fs";
import path from "path";
import yaml from "js-yaml";
const ROOT = "src/content/glossaire";
const files = fs.readdirSync(ROOT).filter(f => f.endsWith(".md"));
const slugs = new Set(files.map(f => f.replace(".md", "")));
let missingNavigation = [];
let edges = {};
let incoming = {};
for (const file of files) {
const full = path.join(ROOT, file);
const raw = fs.readFileSync(full, "utf-8");
if (!raw.startsWith("---")) continue;
const data = yaml.load(raw.split("---")[1]) || {};
const slug = file.replace(".md", "");
if (!data.navigation) {
missingNavigation.push(slug);
}
const next = data?.navigation?.primaryNext;
if (next) {
edges[slug] = next;
incoming[next] = (incoming[next] || 0) + 1;
}
}
// 🔍 1. Fiches sans navigation
if (missingNavigation.length > 0) {
console.log("\n❌ Missing navigation:");
missingNavigation.forEach(s => console.log(" -", s));
}
// 🔍 2. Cycles directs
console.log("\n🔍 Direct cycles:");
for (const [a, b] of Object.entries(edges)) {
if (edges[b] === a) {
console.log(` - ${a} <-> ${b}`);
}
}
// 🔍 3. Hubs
console.log("\n📊 Top hubs:");
Object.entries(incoming)
.sort((a,b) => b[1]-a[1])
.slice(0,10)
.forEach(([slug, n]) => {
if (n > 5) console.log(`⚠️ ${slug}: ${n}`);
else console.log(` ${slug}: ${n}`);
});
// 🔍 4. Slugs morts
console.log("\n🔗 Checking dead primaryNext:");
for (const [a,b] of Object.entries(edges)) {
if (!slugs.has(b)) {
console.log(`${a}${b} (missing)`);
}
}
console.log("\n✅ Audit done");