#!/usr/bin/env node /** Simple import-graph cycle detection for src/modules/healthcare. */ import { readFileSync, readdirSync, statSync } from "node:fs"; import { join, relative } from "node:path"; import { fileURLToPath } from "node:url"; const ROOT = join(fileURLToPath(new URL(".", import.meta.url)), ".."); const MODULE = join(ROOT, "src", "modules", "healthcare"); const importRe = /from\s+["'](@\/[^"']+)["']/g; const graph = new Map(); function walk(dir) { for (const e of readdirSync(dir)) { const f = join(dir, e); if (statSync(f).isDirectory()) walk(f); else if (/\.tsx?$/.test(e)) { const rel = relative(ROOT, f).replace(/\\/g, "/"); const deps = []; const content = readFileSync(f, "utf8"); let m; importRe.lastIndex = 0; while ((m = importRe.exec(content)) !== null) { if (m[1].startsWith("@/src/modules/healthcare/")) deps.push(m[1]); } graph.set(rel, deps); } } } walk(MODULE); function resolve(importPath) { const base = importPath.replace("@/", "").replace(/\/$/, ""); const candidates = [ `${base}.tsx`, `${base}.ts`, `${base}/index.tsx`, `${base}/index.ts`, ]; for (const c of candidates) { if (graph.has(c)) return c; } return null; } function findCycles() { const cycles = []; const visited = new Set(); const stack = new Set(); function dfs(node, path) { if (stack.has(node)) { cycles.push([...path, node]); return; } if (visited.has(node)) return; visited.add(node); stack.add(node); for (const dep of graph.get(node) ?? []) { const resolved = resolve(dep); if (resolved) dfs(resolved, [...path, node]); } stack.delete(node); } for (const node of graph.keys()) dfs(node, []); return cycles; } const cycles = findCycles(); console.log("Circular Dependency Check (healthcare module)\n"); if (cycles.length) { console.error("❌ Cycles found:"); for (const c of cycles) console.error(" ", c.join(" → ")); process.exit(1); } console.log(`✅ No cycles in ${graph.size} healthcare module files`); process.exit(0);