|
| 1 | +// coverage-table.ts — regenerate the README per-language alignment tables. Runs each |
| 2 | +// src-coverage + scope-gap adapter as a subprocess, parses its ##COV## / ##SCOPEGAP## summary |
| 3 | +// line, and writes two tables into the README between <!-- coverage:start --> / <!-- coverage:end -->. |
| 4 | +// node test/coverage-table.ts # print the tables (don't touch the README) |
| 5 | +// node test/coverage-table.ts --write # rewrite the README region |
| 6 | +// Needs the corpora the adapters use (/tmp/ts-repo, /tmp/test262, /tmp/yaml-test-suite) and a VS |
| 7 | +// Code install for the official grammars; an adapter whose inputs are missing renders as "—". |
| 8 | +import { execFileSync } from 'node:child_process'; |
| 9 | +import { readFileSync, writeFileSync } from 'node:fs'; |
| 10 | + |
| 11 | +const WRITE = process.argv.includes('--write'); |
| 12 | + |
| 13 | +function runAdapter(script: string, args: string[], marker: string): any | null { |
| 14 | + try { |
| 15 | + const out = execFileSync('node', [script, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 128 * 1024 * 1024 }); |
| 16 | + const line = out.split('\n').find((l) => l.startsWith(marker)); |
| 17 | + return line ? JSON.parse(line.slice(marker.length).trim()) : null; |
| 18 | + } catch { return null; } |
| 19 | +} |
| 20 | + |
| 21 | +// TS/JS use deterministic stride subsets for speed; the rest run their full corpus. |
| 22 | +const COV = [ |
| 23 | + { lang: 'TypeScript', script: 'test/src-coverage-ts.ts', args: ['1500'] }, |
| 24 | + { lang: 'JavaScript', script: 'test/src-coverage-js.ts', args: ['800'] }, |
| 25 | + { lang: 'JSX', script: 'test/src-coverage-jsx.ts', args: [] }, |
| 26 | + { lang: 'TSX', script: 'test/src-coverage-tsx.ts', args: [] }, |
| 27 | + { lang: 'HTML', script: 'test/src-coverage-html.ts', args: [] }, |
| 28 | + { lang: 'YAML', script: 'test/src-coverage-yaml.ts', args: [] }, |
| 29 | +]; |
| 30 | +const GAP = [ |
| 31 | + { lang: 'TypeScript', script: 'test/scope-gap-ts.ts', args: ['800'] }, |
| 32 | + { lang: 'HTML', script: 'test/scope-gap-html.ts', args: [] }, |
| 33 | + { lang: 'YAML', script: 'test/scope-gap-yaml.ts', args: [] }, |
| 34 | +]; |
| 35 | + |
| 36 | +const pct = (v: number | null | undefined) => (v == null ? '—' : v.toFixed(1) + '%'); |
| 37 | + |
| 38 | +console.error('Running src-coverage adapters…'); |
| 39 | +const covRows = COV.map((a) => { console.error(' ' + a.lang); return { lang: a.lang, r: runAdapter(a.script, a.args, '##COV##') }; }); |
| 40 | +console.error('Running scope-gap adapters…'); |
| 41 | +const gapRows = GAP.map((a) => { console.error(' ' + a.lang); return { lang: a.lang, r: runAdapter(a.script, a.args, '##SCOPEGAP##') }; }); |
| 42 | + |
| 43 | +const covBy = new Map(covRows.map((x) => [x.lang, x.r])); |
| 44 | +const gapBy = new Map(gapRows.map((x) => [x.lang, x.r])); |
| 45 | +const LANGS = ['TypeScript', 'JavaScript', 'JSX', 'TSX', 'HTML', 'YAML']; |
| 46 | + |
| 47 | +let md = ''; |
| 48 | +md += "Per-grammar alignment vs the **official parser** as the neutral oracle (`node test/coverage-table.ts --write`). *Parser* = Monogram's parser vs the official parser: `branch` = source-coverage-anchored branch alignment, `agree` = bidirectional accept/reject (tree-equality for structural oracles) — `test/src-coverage.ts`. *Highlighter* = Monogram's derived TextMate grammar vs the official one, both graded against the parser's token roles — `test/scope-gap.ts`, the [vscode#203212](https://github.com/microsoft/vscode/issues/203212) comparison.\n\n"; |
| 49 | +md += '| Grammar | Parser (branch · agree) | Highlighter — Monogram vs official |\n|---|---|---|\n'; |
| 50 | +for (const lang of LANGS) { |
| 51 | + const c = covBy.get(lang), g = gapBy.get(lang); |
| 52 | + const parser = c ? `${pct(c.denoms?.[c.denoms.length - 1]?.alignment)} · ${pct(c.agreePct)}` : '—'; |
| 53 | + const hl = g ? `${pct(g.monogramPct)} vs ${pct(g.officialPct)}` : '—'; |
| 54 | + md += `| ${lang} | ${parser} | ${hl} |\n`; |
| 55 | +} |
| 56 | + |
| 57 | +const block = '<!-- coverage:start -->\n' + md + '<!-- coverage:end -->'; |
| 58 | +if (!WRITE) { console.log('\n' + md); process.exit(0); } |
| 59 | + |
| 60 | +const README = 'README.md'; |
| 61 | +let txt = readFileSync(README, 'utf8'); |
| 62 | +if (!/<!-- coverage:start -->[\s\S]*?<!-- coverage:end -->/.test(txt)) { |
| 63 | + console.error('No <!-- coverage:start/end --> markers in README.md — add them first.'); |
| 64 | + process.exit(1); |
| 65 | +} |
| 66 | +txt = txt.replace(/<!-- coverage:start -->[\s\S]*?<!-- coverage:end -->/, () => block); |
| 67 | +writeFileSync(README, txt); |
| 68 | +console.error('✓ README coverage region updated.'); |
0 commit comments