This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
// Appends unregistered docs/superpowers/**/*.md entries to manifest.yaml.
|
||||
// Uses yaml.parseDocument for comment-preserving round-trip.
|
||||
// Idempotent: re-running adds 0 entries when all docs are already registered.
|
||||
// Usage: node scripts/scaffold-manifest.mjs
|
||||
import { readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs';
|
||||
import { dirname, resolve, join } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
import { scaffoldEntryObject, findUnregistered } from './lib/design-index.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const SP = resolve(__dirname, '../docs/superpowers');
|
||||
|
||||
// `yaml` lives in ui/node_modules — same resolution pattern as validate-design-docs.mjs
|
||||
const require = createRequire(pathToFileURL(resolve(__dirname, '../ui/package.json')));
|
||||
const YAML = await import(pathToFileURL(require.resolve('yaml')).href);
|
||||
|
||||
const SUBDIRS = ['specs', 'plans', 'archived/specs', 'archived/plans'];
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
const mfPath = join(SP, 'manifest.yaml');
|
||||
const rawYaml = existsSync(mfPath) ? readFileSync(mfPath, 'utf-8') : 'docs:\n';
|
||||
const doc = YAML.parseDocument(rawYaml);
|
||||
|
||||
// Ensure `docs` key exists as a sequence (handle null scalar from 'docs:\n' seed)
|
||||
const existingSeq = doc.get('docs', true);
|
||||
if (!(existingSeq instanceof YAML.YAMLSeq)) {
|
||||
doc.set('docs', new YAML.YAMLSeq());
|
||||
}
|
||||
const seq = doc.get('docs', true); // true = return the node itself, not the JS value
|
||||
seq.flow = false; // force block style for human curability
|
||||
|
||||
// Build the set of already-registered paths
|
||||
const registered = new Set(
|
||||
(seq.items ?? []).map((n) => n.get('path'))
|
||||
);
|
||||
|
||||
const unregistered = findUnregistered(listDocs(), registered);
|
||||
|
||||
for (const rel of unregistered) {
|
||||
const md = readFileSync(join(SP, rel), 'utf-8');
|
||||
const entry = scaffoldEntryObject(rel, md);
|
||||
const node = doc.createNode(entry);
|
||||
// Attach # TODO: verify topic comment to the topic scalar node
|
||||
const topicItem = node.get('topic', true);
|
||||
if (topicItem) topicItem.comment = ' TODO: verify topic';
|
||||
seq.add(node);
|
||||
}
|
||||
|
||||
writeFileSync(mfPath, String(doc), 'utf-8');
|
||||
console.log(`scaffold: added ${unregistered.length} entries (total ${seq.items.length})`);
|
||||
Reference in New Issue
Block a user