This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
// 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)`);
|
||||
}
|
||||
Reference in New Issue
Block a user