87 lines
2.9 KiB
TypeScript
87 lines
2.9 KiB
TypeScript
import { readdir, readFile, stat } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
/**
|
|
* Walk `packages/<category>/<plugin>/<pkg>/README.md` for the canonical
|
|
* 3-level layout. A README is only included when its sibling `package.json`
|
|
* declares an `@suaveplan/*` workspace package — this skips stale plugin- or
|
|
* category-level READMEs that don't correspond to a real package.
|
|
*/
|
|
async function findReadmes(dir: string): Promise<string[]> {
|
|
const results: string[] = [];
|
|
const categoryEntries = await readdir(dir, { withFileTypes: true });
|
|
|
|
for (const category of categoryEntries) {
|
|
if (!category.isDirectory()) continue;
|
|
if (category.name.startsWith(".")) continue;
|
|
const categoryPath = join(dir, category.name);
|
|
const pluginEntries = await readdir(categoryPath, {
|
|
withFileTypes: true,
|
|
}).catch(() => []);
|
|
|
|
for (const plugin of pluginEntries) {
|
|
if (!plugin.isDirectory()) continue;
|
|
if (plugin.name.startsWith(".")) continue;
|
|
const pluginPath = join(categoryPath, plugin.name);
|
|
const pkgEntries = await readdir(pluginPath, {
|
|
withFileTypes: true,
|
|
}).catch(() => []);
|
|
|
|
for (const pkg of pkgEntries) {
|
|
if (!pkg.isDirectory()) continue;
|
|
if (pkg.name.startsWith(".")) continue;
|
|
const pkgPath = join(pluginPath, pkg.name);
|
|
|
|
// Only count this README if there's a workspace package.json
|
|
// (skips stale plugin-level READMEs left from prior layouts).
|
|
const pkgJsonPath = join(pkgPath, "package.json");
|
|
try {
|
|
await stat(pkgJsonPath);
|
|
} catch {
|
|
continue;
|
|
}
|
|
|
|
const readmePath = join(pkgPath, "README.md");
|
|
try {
|
|
await readFile(readmePath);
|
|
results.push(readmePath);
|
|
} catch {
|
|
// README.md doesn't exist, skip
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
async function main() {
|
|
const readmePaths = await findReadmes("./packages");
|
|
const mismatches: string[] = [];
|
|
|
|
for (const path of readmePaths) {
|
|
const content = await readFile(path, "utf-8");
|
|
const firstLine = content.split(/\r?\n/)[0] ?? "";
|
|
if (!/^#\s@[^\s]+\s/.test(firstLine)) {
|
|
mismatches.push(path);
|
|
}
|
|
}
|
|
|
|
if (mismatches.length === 0) {
|
|
console.log("All README.md files start with '# @' on the first line.");
|
|
} else {
|
|
console.log(
|
|
`Found ${mismatches.length} README.md file(s) without '# @' as the first line:`
|
|
);
|
|
for (const path of mismatches) {
|
|
console.log(` ${path}`);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|