#!/usr/bin/env node /** Detect circular imports within src/modules/accounting. */ import { readFileSync, readdirSync, statSync } from "node:fs"; import { join, relative, sep, dirname } from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = join(fileURLToPath(new URL(".", import.meta.url)), ".."); const MOD = join(ROOT, "src", "modules", "accounting"); const EXT = new Set([".ts", ".tsx"]); const importRe = /from\s+["'](@\/src\/modules\/accounting\/[^"']+)["']/g; function walk(dir, files = []) { for (const entry of readdirSync(dir)) { const full = join(dir, entry); if (statSync(full).isDirectory()) walk(full, files); else if (EXT.has(entry.slice(entry.lastIndexOf(".")))) files.push(full); } return files; } /** @type {Map} */ const graph = new Map(); for (const file of walk(MOD)) { const rel = relative(MOD, file).split(sep).join("/").replace(/\.tsx?$/, ""); const content = readFileSync(file, "utf8"); const deps = []; let m; importRe.lastIndex = 0; while ((m = importRe.exec(content)) !== null) { const p = m[1].replace("@/src/modules/accounting/", ""); deps.push(p); } graph.set(rel, deps); } function findCycles() { /** @type {string[][]} */ const cycles = []; const visiting = new Set(); const visited = new Set(); /** @type {string[]} */ const stack = []; function dfs(node) { if (visiting.has(node)) { const idx = stack.indexOf(node); cycles.push(stack.slice(idx).concat(node)); return; } if (visited.has(node)) return; visiting.add(node); stack.push(node); for (const dep of graph.get(node) ?? []) { const key = dep.replace(/\/index$/, ""); if (graph.has(key)) dfs(key); } stack.pop(); visiting.delete(node); visited.add(node); } for (const node of graph.keys()) dfs(node); return cycles; } const cycles = findCycles(); console.log("Circular Dependency Check (accounting module)\n"); if (cycles.length) { console.error(`❌ ${cycles.length} cycle(s):`); for (const c of cycles) console.error(` ${c.join(" → ")}`); process.exit(1); } console.log(`✅ No cycles in ${graph.size} accounting module files`); process.exit(0);