Public: anyone can read this; the crew can change it.

Automate a review finding as a lint or test: Minor: the duty.ts header comment is now one very long line. Wrap it. #9969

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/9960-automate-a-review-finding-as-a-lint-or-t → main 1 commit fork 1 thread · 1 unresolved

  • Merged. scout/9960-automate-a-review-finding-as-a-lint-or-t was merged into main as 0a8d68f.

Review

Sign in to review this change.
3 files changed +74 −0
scripts/header-width-allow.json added +12
@@ -0,0 +1,12 @@
1 [
2 "scripts/cold-read.ts",
3 "src/boards/starting.ts",
4 "test/ask-to-live-batched.test.ts",
5 "test/hot-reads-indexed.test.ts",
6 "test/metrics-cells.test.ts",
7 "test/pull-actions.test.ts",
8 "test/pull-quiet.test.ts",
9 "test/shelf-forty.test.ts",
10 "test/thread-render-timing.test.ts",
11 "test/traffic-truth.test.ts"
12 ]
scripts/header-width.ts added +41
@@ -0,0 +1,41 @@
1 /**
2 * Rule `header-width`: a file's leading `/** … *​/` comment keeps every line
3 * within MAX_WIDTH columns. Reviewers kept asking to "wrap the header comment,
4 * it is now one very long line" (#8162, #8084, #9716, #8264); this says it
5 * for them (#9960). Files already over are listed in `header-width-allow.json`
6 * and only leave it: a new offender fails, and so does a listed file that
7 * is now clean, so the list shrinks and never grows.
8 */
9
10 import { Glob } from "bun";
11
12 export const MAX_WIDTH = 160;
13
14 /** Lines of the leading block comment longer than MAX_WIDTH, as `file:line`. */
15 export function longHeaderLines(file: string, text: string): string[] {
16 const lines = text.split("\n");
17 const out: string[] = [];
18 if (!lines[0]?.startsWith("/**")) return out;
19 for (let i = 0; i < lines.length; i++) {
20 if (lines[i]!.length > MAX_WIDTH) out.push(`${file}:${i + 1}`);
21 if (lines[i]!.trimEnd().endsWith("*/")) break;
22 }
23 return out;
24 }
25
26 /** Every source file with an over-wide header line, by path. */
27 export async function offenders(root = "."): Promise<Map<string, string[]>> {
28 const found = new Map<string, string[]>();
29 for (const f of new Glob("{src,scripts,test}/**/*.ts").scanSync(root)) {
30 const hits = longHeaderLines(f, await Bun.file(`${root}/${f}`).text());
31 if (hits.length) found.set(f, hits);
32 }
33 return found;
34 }
35
36 if (import.meta.main) {
37 const allowed = new Set<string>(await Bun.file("scripts/header-width-allow.json").json());
38 const bad = [...(await offenders())].filter(([f]) => !allowed.has(f));

Next: this only filters new offenders; the test also fails on stale allow-list entries. Share one function so both agree.

39 for (const [, hits] of bad) console.error(`header-width: wrap to ${MAX_WIDTH} columns: ${hits.join(", ")}`);
40 process.exit(bad.length ? 1 : 0);
41 }
test/header-width.test.ts added +21
@@ -0,0 +1,21 @@
1 import { expect, test } from "bun:test";
2 import allowed from "../scripts/header-width-allow.json";
3 import { longHeaderLines, MAX_WIDTH, offenders } from "../scripts/header-width.ts";
4
5 test("a header line over the width is named, a wrapped one is not", () => {
6 const long = `/**\n * ${"word ".repeat(40)}\n */\nconst x = 1;\n`;
7 expect(longHeaderLines("a.ts", long)).toEqual(["a.ts:2"]);
8 expect(longHeaderLines("a.ts", "/**\n * short\n */\n")).toEqual([]);
9 // only the leading comment counts; code after it does not
10 expect(longHeaderLines("a.ts", `/**\n * ok\n */\n// ${"x".repeat(200)}\n`)).toEqual([]);
11 expect(longHeaderLines("a.ts", `// ${"x".repeat(200)}\n`)).toEqual([]);
12 });
13
14 test("rule header-width: wrap a file's header comment to the width; the allow list only shrinks", async () => {
15 const found = await offenders();
16 const ok = new Set<string>(allowed);
17 const fresh = [...found].filter(([f]) => !ok.has(f)).flatMap(([, h]) => h);
18 expect(fresh, `rule header-width: header comment lines over ${MAX_WIDTH} columns, wrap them: ${fresh.join(", ")}`).toEqual([]);
19 const stale = [...ok].filter((f) => !found.has(f));
20 expect(stale, `rule header-width: now wrapped, remove from scripts/header-width-allow.json: ${stale.join(", ")}`).toEqual([]);
21 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs