Initial Commit
This commit is contained in:
86
scripts/find-readmes-without-header.ts
Normal file
86
scripts/find-readmes-without-header.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user