// Frontend functions over a cyclomatic-complexity limit, counted for scripts/audit_metrics.py: a bare // `complexity` rule run (no type info, no other rules), so it takes seconds, not a full lint. Prints // one JSON object: {"limit": N, "over": count, "max": highest}. Shipped code only — tests and test // kits are lists of cases, not logic anyone has to change. // // node scripts/fe_complexity.mjs [limit] (default 20, the frontend's line) import { readdirSync, readFileSync } from "node:fs"; import { createRequire } from "node:module"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; const SRC = fileURLToPath(new URL("../frontend/src/", import.meta.url)); const require = createRequire(new URL("../frontend/package.json", import.meta.url)); const { Linter } = require("eslint"); const tseslint = require("typescript-eslint"); const limit = Number(process.argv[2] ?? 20); const files = readdirSync(SRC, { recursive: true }) .map((p) => p.split("\\").join("/")) .filter( (p) => /\.(ts|tsx)$/.test(p) && !/\.(test|testkit)\.tsx?$/.test(p) && !p.endsWith(".d.ts"), ); const linter = new Linter(); const config = [ { files: ["**/*.{ts,tsx}"], languageOptions: { parser: tseslint.parser, parserOptions: { ecmaFeatures: { jsx: true } }, }, rules: { complexity: ["error", limit] }, }, ]; let over = 0; let max = 0; for (const f of files) { for (const m of linter.verify(readFileSync(join(SRC, f), "utf8"), config, f)) { const n = Number(/complexity of (\d+)/.exec(m.message)?.[1]); if (!n) continue; over += 1; max = Math.max(max, n); } } console.log(JSON.stringify({ limit, over, max }));