Files
Meshtastic-Android/scripts/check-doc-coverage.js

85 lines
3.1 KiB
JavaScript

#!/usr/bin/env node
// scripts/check-doc-coverage.js
// Checks that each user-facing feature module has corresponding documentation.
// Exit 0 = full coverage, Exit 1 = gaps found.
//
// Usage: node scripts/check-doc-coverage.js [repo-root]
"use strict";
const fs = require("fs");
const path = require("path");
const { forEachDocPage } = require("./lib/frontmatter");
const REPO_ROOT = path.resolve(process.argv[2] || ".");
const DOCS_DIR = path.join(REPO_ROOT, "docs", "en");
// Map of feature module directory names to expected doc page slugs.
// Modules not listed here are considered internal (no user-facing docs required).
const MODULE_TO_DOCS = {
"feature/connections": { pages: ["connections"], section: "user" },
"feature/discovery": { pages: ["discovery"], section: "user" },
"feature/docs": { pages: [], section: "user", internal: true },
"feature/firmware": { pages: ["firmware"], section: "user" },
"feature/intro": { pages: ["onboarding"], section: "user" },
"feature/map": { pages: ["map-and-waypoints"], section: "user" },
"feature/messaging": { pages: ["messages-and-channels"], section: "user" },
"feature/node": { pages: ["nodes", "node-metrics"], section: "user" },
"feature/settings": { pages: ["settings-radio-user", "settings-module-admin"], section: "user" },
"feature/telemetry": { pages: ["telemetry-and-sensors"], section: "user" },
};
// Collect existing doc pages
const existingPages = new Set();
forEachDocPage(DOCS_DIR, (_filePath, slug, section) => {
existingPages.add(`${section}/${slug}`);
});
console.log(`Checking doc coverage for ${Object.keys(MODULE_TO_DOCS).length} feature modules...`);
console.log(`Found ${existingPages.size} doc pages.`);
console.log("");
let gaps = 0;
for (const [module, config] of Object.entries(MODULE_TO_DOCS)) {
if (config.internal) continue;
const moduleDir = path.join(REPO_ROOT, module);
if (!fs.existsSync(moduleDir)) continue;
for (const page of config.pages) {
const key = `${config.section}/${page}`;
if (!existingPages.has(key)) {
console.log(`${module} → missing ${key}.md`);
gaps++;
}
}
}
// Also check for doc pages that reference non-existent modules (orphans)
const documentedModules = new Set();
for (const config of Object.values(MODULE_TO_DOCS)) {
for (const page of config.pages) {
documentedModules.add(`${config.section}/${page}`);
}
}
// Report coverage summary
const coveredModules = Object.entries(MODULE_TO_DOCS)
.filter(([, c]) => !c.internal)
.filter(([m]) => fs.existsSync(path.join(REPO_ROOT, m)));
const totalExpected = coveredModules.reduce((sum, [, c]) => sum + c.pages.length, 0);
const covered = totalExpected - gaps;
const pct = totalExpected > 0 ? Math.round((covered / totalExpected) * 100) : 100;
console.log("");
console.log(`Coverage: ${covered}/${totalExpected} required pages present (${pct}%)`);
if (gaps > 0) {
console.log(`\n${gaps} documentation gap(s) found.`);
process.exit(1);
} else {
console.log("All feature modules have documentation coverage.");
process.exit(0);
}