#!/usr/bin/env node // Lightweight per-function complexity audit. No deps. // Heuristic: counts decision points (if / else if / for / while / switch case / catch / ternary / && / ||) per function body. // Not as rigorous as SonarJS cognitive complexity, but finds the same outliers. // Output: docs/complexity-hotspots.md — top 50 functions. import { readdirSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; import { join, relative, extname } from 'node:path'; const ROOT = new URL('..', import.meta.url).pathname.replace(/\/$/, ''); const SCAN_ROOTS = ['apps/mana/apps/web/src', 'apps/api/src', 'services', 'packages']; const CODE_EXT = new Set(['.ts', '.tsx', '.js', '.mjs', '.svelte']); const IGNORE = new Set(['node_modules', '.svelte-kit', 'dist', 'build', 'coverage', '.turbo']); function walk(dir) { const out = []; let entries; try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return out; } for (const e of entries) { if (IGNORE.has(e.name)) continue; const p = join(dir, e.name); if (e.isDirectory()) out.push(...walk(p)); else if (e.isFile() && CODE_EXT.has(extname(e.name))) out.push(p); } return out; } // Strip /* */ and // comments and string contents to avoid false matches. function sanitize(src) { return src .replace(/\/\*[\s\S]*?\*\//g, '') .replace(/\/\/[^\n]*/g, '') .replace(/`[^`\\]*(?:\\.[^`\\]*)*`/g, '``') .replace(/'[^'\\\n]*(?:\\.[^'\\\n]*)*'/g, "''") .replace(/"[^"\\\n]*(?:\\.[^"\\\n]*)*"/g, '""'); } // For .svelte: extract