|
17 | 17 | * |
18 | 18 | * Run: `bun run check:explicit-any` |
19 | 19 | */ |
20 | | -import { readFileSync, writeFileSync } from 'node:fs' |
| 20 | +import { existsSync, readFileSync, writeFileSync } from 'node:fs' |
21 | 21 | import path from 'node:path' |
22 | 22 | import { localBin } from './local-bin' |
23 | 23 |
|
@@ -56,7 +56,8 @@ function collect(): Baseline { |
56 | 56 | ], |
57 | 57 | { cwd: ROOT, stdout: 'pipe', stderr: 'pipe' } |
58 | 58 | ) |
59 | | - if (result.exitCode !== 0) { |
| 59 | + // Hits are reported as diagnostics, so only a run that produced none counts as a failure. |
| 60 | + if (result.exitCode !== 0 && !result.stdout.toString().includes('::')) { |
60 | 61 | console.error(`biome lint failed:\n${result.stderr.toString()}`) |
61 | 62 | process.exit(1) |
62 | 63 | } |
@@ -86,21 +87,44 @@ function total(counts: Counts): number { |
86 | 87 | } |
87 | 88 |
|
88 | 89 | const current = collect() |
| 90 | +const baseline: Baseline = existsSync(BASELINE) |
| 91 | + ? (JSON.parse(readFileSync(BASELINE, 'utf8')) as Baseline) |
| 92 | + : current |
| 93 | + |
| 94 | +/** Per-file counts clamped to the baseline, so an update can only lower them. */ |
| 95 | +function shrunkTo(after: Counts, before: Counts): Counts { |
| 96 | + return Object.fromEntries( |
| 97 | + Object.entries(after) |
| 98 | + .map(([file, count]): [string, number] => [file, Math.min(count, before[file] ?? 0)]) |
| 99 | + .filter(([, count]) => count > 0) |
| 100 | + ) |
| 101 | +} |
89 | 102 |
|
90 | 103 | if (process.argv.includes('--update')) { |
91 | | - const baseline: Baseline = { |
92 | | - explicitAny: sorted(current.explicitAny), |
93 | | - nonNullAssertion: sorted(current.nonNullAssertion), |
| 104 | + const next: Baseline = { |
| 105 | + explicitAny: sorted(shrunkTo(current.explicitAny, baseline.explicitAny ?? {})), |
| 106 | + nonNullAssertion: sorted(shrunkTo(current.nonNullAssertion, baseline.nonNullAssertion ?? {})), |
94 | 107 | } |
95 | | - writeFileSync(BASELINE, `${JSON.stringify(baseline, null, 2)}\n`) |
| 108 | + writeFileSync(BASELINE, `${JSON.stringify(next, null, 2)}\n`) |
96 | 109 | console.log( |
97 | | - `Wrote ${path.relative(ROOT, BASELINE)}: ${total(baseline.explicitAny)} explicit any, ` + |
98 | | - `${total(baseline.nonNullAssertion)} non-null assertions` |
| 110 | + `Wrote ${path.relative(ROOT, BASELINE)}: ${total(next.explicitAny)} explicit any, ` + |
| 111 | + `${total(next.nonNullAssertion)} non-null assertions` |
| 112 | + ) |
| 113 | + const raised = (Object.keys(METRICS) as Metric[]).flatMap((metric) => |
| 114 | + Object.entries(current[metric]) |
| 115 | + .filter(([file, count]) => count > (baseline[metric]?.[file] ?? 0)) |
| 116 | + .map( |
| 117 | + ([file, count]) => |
| 118 | + ` ${metric} ${file}: ${count} (baseline ${baseline[metric]?.[file] ?? 0})` |
| 119 | + ) |
99 | 120 | ) |
100 | | - process.exit(0) |
| 121 | + if (raised.length) { |
| 122 | + console.error(`✗ refused to raise the baseline for ${raised.length} file(s); fix them instead:`) |
| 123 | + console.error(raised.sort().join('\n')) |
| 124 | + } |
| 125 | + process.exit(raised.length ? 1 : 0) |
101 | 126 | } |
102 | 127 |
|
103 | | -const baseline = JSON.parse(readFileSync(BASELINE, 'utf8')) as Baseline |
104 | 128 | let regressed = 0 |
105 | 129 | let stale = 0 |
106 | 130 |
|
|
0 commit comments