UNPKG

pi-lens

Version:

Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo

48 lines (47 loc) • 1.81 kB
import * as path from "node:path"; function resolveCyclePath(cwd, file) { return path.isAbsolute(file) ? file : path.resolve(cwd, file); } /** The files making up a cycle: prefer the full `path`, fall back to `file`. */ function cycleMembers(dep) { return dep.path.length > 0 ? dep.path : [dep.file]; } /** * A madge circular dependency is a *set* of files (`a → b → c → a`), unlike a * single-point knip finding. Emit a diagnostic on EACH file in the cycle so it * surfaces wherever the agent is looking, each one rendering the whole cycle. */ export function circularDepToProjectDiagnostics(cwd, dep) { const members = cycleMembers(dep); const rendered = `${members.map((f) => path.basename(f)).join(" → ")} → ${path.basename(members[0] ?? "")}`; return members.map((file) => ({ filePath: resolveCyclePath(cwd, file), severity: "warning", semantic: "warning", tool: "madge", runner: "madge", rule: "madge:circular", message: `Part of circular dependency: ${rendered}`, source: "project-scan", })); } /** * Map madge's circular-dependency findings into per-file `ProjectDiagnostic`s. * Deduplicates cycles reported from different anchor files (same member set), so * a cycle is emitted once per participating file, not once per anchor. */ export function circularDepsToProjectDiagnostics(cwd, circular) { const seen = new Set(); const out = []; for (const dep of circular) { const key = cycleMembers(dep) .map((f) => resolveCyclePath(cwd, f)) .sort((a, b) => a.localeCompare(b)) .join("|"); if (seen.has(key)) continue; seen.add(key); out.push(...circularDepToProjectDiagnostics(cwd, dep)); } return out; }