maestro/scripts/validate-design-docs.mjs
oss-sync b1292e34b2
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (edc775f2)
2026-07-06 01:04:12 +00:00

59 lines
2.6 KiB
JavaScript

// Validates docs/superpowers/manifest.yaml against files on disk.
// Usage: node scripts/validate-design-docs.mjs [--check]
import { readFileSync, readdirSync, existsSync } from 'node:fs';
import { dirname, resolve, join } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { createRequire } from 'node:module';
import { validateManifest } from './lib/design-index.mjs';
import { buildIndex } from './gen-design-index.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const SP = resolve(__dirname, '../docs/superpowers');
// `yaml` lives in ui/node_modules — resolve relative to ui/package.json,
// exactly like scripts/validate-help-docs.mjs does.
let parseYaml;
try {
const require = createRequire(pathToFileURL(resolve(__dirname, '../ui/package.json')));
({ parse: parseYaml } = await import(pathToFileURL(require.resolve('yaml')).href));
} catch {
console.error("design-docs validation: cannot load 'yaml' from ui/node_modules — run `npm --prefix ui install`");
process.exit(1);
}
const SUBDIRS = ['specs', 'plans', 'archived/specs', 'archived/plans'];
export function listDocs() {
const out = [];
for (const d of SUBDIRS) {
const abs = join(SP, d);
if (!existsSync(abs)) continue;
for (const f of readdirSync(abs)) if (f.endsWith('.md')) out.push(`${d}/${f}`);
}
return out.sort();
}
// Main guard: only run validation side-effects when executed directly.
// Importing this module (e.g. to use listDocs) will NOT trigger the block below.
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
// FIX I-1: guard against missing manifest.yaml (Task 3 hasn't generated it yet)
const manifestRaw = existsSync(join(SP, 'manifest.yaml'))
? readFileSync(join(SP, 'manifest.yaml'), 'utf-8')
: 'docs: []';
const manifest = parseYaml(manifestRaw) ?? { docs: [] };
const { errors, warnings } = validateManifest(manifest.docs ?? [], listDocs());
for (const w of warnings) console.warn(`[warn] ${w}`);
for (const e of errors) console.error(`[error] ${e}`);
if (process.argv.includes('--check')) {
const cur = existsSync(join(SP, 'index.md')) ? readFileSync(join(SP, 'index.md'), 'utf-8') : '';
if (cur !== buildIndex()) {
console.error('[error] index.md is stale — run node scripts/gen-design-index.mjs');
process.exit(1);
}
}
if (errors.length) { console.error(`design-docs validation FAILED (${errors.length} errors)`); process.exit(1); }
console.log(`design-docs validation OK (${(manifest.docs ?? []).length} entries, ${warnings.length} warnings)`);
}