/** * __theming-diff — compares two `__theming-probe` captures (PLAN-theming §7.4). * * node scripts/__theming-diff.ts before.json after.json * * The gate is EMPTY: one differing computed value means the default moved, and * that is a stop-and-explain, not a warning. Temporary instrument (`__` prefix). */ import { readFileSync } from 'node:fs'; type Rows = Record>; const [a, b] = process.argv.slice(2); const A = JSON.parse(readFileSync(a, 'utf8')) as Record; const B = JSON.parse(readFileSync(b, 'utf8')) as Record; let diffs = 0; let compared = 0; const missing: string[] = []; for (const state of Object.keys(A)) { const ra = A[state]; const rb = B[state] ?? {}; for (const node of Object.keys(ra)) { const na = ra[node]; const nb = rb[node]; if (!nb) { missing.push(`${state} :: ${node}`); continue; } for (const prop of Object.keys(na)) { if (prop === '__key') continue; compared++; if (na[prop] !== nb[prop]) { diffs++; console.log( `DIFF ${state} :: ${node} :: ${prop}\n before: ${na[prop]}\n after: ${nb[prop]}` ); } } } } for (const m of missing) console.log(`MISSING NODE ${m}`); console.log( `\ncompared ${compared} computed values across ${Object.keys(A).length} states — ${diffs} diff(s), ${missing.length} missing node(s)` ); process.exit(diffs === 0 && missing.length === 0 ? 0 : 1);