(arg)
| 58 | // ─── result loading ────────────────────────────────────────────────────────── |
| 59 | |
| 60 | function loadRun(arg) { |
| 61 | if (!fs.existsSync(arg)) { |
| 62 | throw new Error(`not found: ${arg}`); |
| 63 | } |
| 64 | const stat = fs.statSync(arg); |
| 65 | let target = arg; |
| 66 | if (stat.isDirectory()) { |
| 67 | const candidates = fs.readdirSync(arg) |
| 68 | .filter((f) => f.endsWith('.json')) |
| 69 | .map((f) => path.join(arg, f)) |
| 70 | .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs); |
| 71 | if (candidates.length === 0) throw new Error(`no .json files in ${arg}`); |
| 72 | target = candidates[0]; |
| 73 | } |
| 74 | const raw = fs.readFileSync(target, 'utf-8'); |
| 75 | let data; |
| 76 | try { |
| 77 | data = JSON.parse(raw); |
| 78 | } catch (e) { |
| 79 | throw new Error(`malformed JSON in ${target}: ${e.message}`); |
| 80 | } |
| 81 | if (!Array.isArray(data.results)) { |
| 82 | throw new Error(`${target}: missing "results" array — not a harness output?`); |
| 83 | } |
| 84 | return { path: target, data }; |
| 85 | } |
| 86 | |
| 87 | // ─── metric extraction ─────────────────────────────────────────────────────── |
| 88 |
no outgoing calls
no test coverage detected