igneum/tools/reference-apps/registry-writeback.mjs

36 lines
2.4 KiB
JavaScript

// Writes a lane's run fields into docs/plans/igneum-2.0-test-registry.json under rule 26: the named cases get run_status,
// evidence_path, run_id, updated (and clock, owner_lane when given) inserted into their objects as new lines, and every
// other byte of the file stays exactly as master carries it (no re-serialisation: rule 26 compares master's lines).
// Refuses a case id the file does not hold. A field the case already carries is replaced on its own line.
// node registry-writeback.mjs <registry.json> <updates.json>
// updates.json: { "EVM-05": { "run_status": "PASS", "evidence_path": "...", "run_id": "...", "clock": "..." }, ... }
import { readFileSync, writeFileSync } from 'node:fs';
const [, , file, updatesFile] = process.argv;
if (!file || !updatesFile) { console.error('usage: node registry-writeback.mjs <registry.json> <updates.json>'); process.exit(2); }
let text = readFileSync(file, 'utf8');
const updates = JSON.parse(readFileSync(updatesFile, 'utf8'));
const now = new Date().toISOString();
const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let touched = 0;
for (const [id, fields] of Object.entries(updates)) {
const m = new RegExp(`^([ \\t]*)"id":\\s*"${esc(id)}",?[ \\t]*\\n`, 'm').exec(text);
if (!m) { console.error('case not in the registry: ' + id); process.exit(1); }
const indent = m[1]; let at = m.index + m[0].length;
// the case object's end: its opening line is the one before the id line; the closing brace sits at that line's indent
const openLine = text.lastIndexOf('\n', m.index - 1); const opener = text.slice(text.lastIndexOf('\n', openLine - 1) + 1, openLine);
const parentIndent = (opener.match(/^[ \t]*/) || [''])[0];
const endRe = new RegExp(`^${parentIndent}\\},?[ \\t]*\\n`, 'mg'); endRe.lastIndex = at;
const end = endRe.exec(text); if (!end) { console.error('no object end for ' + id); process.exit(1); }
let body = text.slice(at, end.index);
const all = { ...fields, updated: now };
for (const [k, v] of Object.entries(all)) {
const line = `${indent}"${k}": ${JSON.stringify(v)},\n`;
const have = new RegExp(`^${indent}"${esc(k)}":.*\\n`, 'm');
body = have.test(body) ? body.replace(have, line) : line + body;
}
text = text.slice(0, at) + body + text.slice(end.index);
touched++;
}
JSON.parse(text); // the result must still parse
writeFileSync(file, text);
console.log(`inserted run fields into ${touched} case(s) of ${file} at ${now}, master's lines untouched`);