// ยง26: fails when any area passes its budget or the TypeScript total passes the // 13,400-line ceiling. const CEILING = 13_400; // Prefixes are matched in order, so the specific files come before the directories. const TS_AREAS: [string, string[], number][] = [ ["bucket", ["src/bucket/"], 1170], ["mirror", ["src/mirror/"], 1100], ["describe", ["src/describe/"], 530], ["pages", ["src/pages/"], 2600], ["releases", ["src/releases/"], 900], ["tarball", ["src/tarball/"], 300], ["issues", ["src/issues/"], 1700], ["admin", ["src/admin/"], 2800], ["import-kepr2", ["scripts/import-kepr2.ts"], 300], ["server", ["src/server/", "src/main.ts", "scripts/budget.ts"], 2000], ]; const ASSET_AREAS: [string, string, number][] = [ ["public/js", "public/js/**/*.js", 1400], ["public/css", "public/css/**/*.css", 3700], ]; async function lineCount(path: string): Promise { const text = await Bun.file(path).text(); return text.split("\n").length - (text.endsWith("\n") ? 1 : 0); } async function countFiles(pattern: string): Promise> { const counts = new Map(); for await (const path of new Bun.Glob(pattern).scan(".")) counts.set(path, await lineCount(path)); return counts; } const tsFiles = await countFiles("{src,scripts}/**/*.ts"); const totals = new Map(TS_AREAS.map(([name]) => [name, 0])); const unassigned: string[] = []; for (const [path, lines] of tsFiles) { if (path.endsWith(".test.ts")) continue; const area = TS_AREAS.find(([, prefixes]) => prefixes.some((prefix) => path.startsWith(prefix))); if (!area) unassigned.push(path); else totals.set(area[0], (totals.get(area[0]) ?? 0) + lines); } const rows: [string, number, number][] = TS_AREAS.map(([name, , budget]) => [ name, totals.get(name) ?? 0, budget, ]); const total = rows.reduce((sum, [, lines]) => sum + lines, 0); for (const [name, pattern, budget] of ASSET_AREAS) { const files = await countFiles(pattern); rows.push([name, [...files.values()].reduce((a, b) => a + b, 0), budget]); } let failed = false; for (const [name, lines, budget] of rows) { const over = lines > budget; failed ||= over; console.log(`${name.padEnd(14)} ${String(lines).padStart(6)} / ${budget}${over ? " OVER" : ""}`); } console.log(`${"typescript".padEnd(14)} ${String(total).padStart(6)} / ${CEILING}`); if (total > CEILING) failed = true; for (const path of unassigned) console.error(`no budget area for ${path}`); if (failed || unassigned.length > 0) process.exit(1);