UNPKG

@samiyev/guardian

Version:

Research-backed code quality guardian for AI-assisted development. Detects hardcodes, secrets, circular deps, framework leaks, entity exposure, and 9 architecture violations. Enforces Clean Architecture/DDD principles. Works with GitHub Copilot, Cursor, W

196 lines • 8.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OutputFormatter = void 0; const constants_1 = require("../../shared/constants"); const constants_2 = require("../constants"); const ViolationGrouper_1 = require("../groupers/ViolationGrouper"); const SEVERITY_LABELS = { [constants_1.SEVERITY_LEVELS.CRITICAL]: constants_2.SEVERITY_DISPLAY_LABELS.CRITICAL, [constants_1.SEVERITY_LEVELS.HIGH]: constants_2.SEVERITY_DISPLAY_LABELS.HIGH, [constants_1.SEVERITY_LEVELS.MEDIUM]: constants_2.SEVERITY_DISPLAY_LABELS.MEDIUM, [constants_1.SEVERITY_LEVELS.LOW]: constants_2.SEVERITY_DISPLAY_LABELS.LOW, }; const SEVERITY_HEADER = { [constants_1.SEVERITY_LEVELS.CRITICAL]: constants_2.SEVERITY_SECTION_HEADERS.CRITICAL, [constants_1.SEVERITY_LEVELS.HIGH]: constants_2.SEVERITY_SECTION_HEADERS.HIGH, [constants_1.SEVERITY_LEVELS.MEDIUM]: constants_2.SEVERITY_SECTION_HEADERS.MEDIUM, [constants_1.SEVERITY_LEVELS.LOW]: constants_2.SEVERITY_SECTION_HEADERS.LOW, }; class OutputFormatter { grouper = new ViolationGrouper_1.ViolationGrouper(); displayGroupedViolations(violations, displayFn, limit) { const grouped = this.grouper.groupBySeverity(violations); const severities = [ constants_1.SEVERITY_LEVELS.CRITICAL, constants_1.SEVERITY_LEVELS.HIGH, constants_1.SEVERITY_LEVELS.MEDIUM, constants_1.SEVERITY_LEVELS.LOW, ]; let totalDisplayed = 0; const totalAvailable = violations.length; for (const severity of severities) { const items = grouped.get(severity); if (items && items.length > 0) { console.warn(SEVERITY_HEADER[severity]); console.warn(`Found ${String(items.length)} issue(s)\n`); const itemsToDisplay = limit !== undefined ? items.slice(0, limit - totalDisplayed) : items; itemsToDisplay.forEach((item, index) => { displayFn(item, totalDisplayed + index); }); totalDisplayed += itemsToDisplay.length; if (limit !== undefined && totalDisplayed >= limit) { break; } } } if (limit !== undefined && totalAvailable > limit) { console.warn(`\nāš ļø Showing first ${String(limit)} of ${String(totalAvailable)} issues (use --limit to adjust)\n`); } } formatArchitectureViolation(v, index) { console.log(`${String(index + 1)}. ${v.file}`); console.log(` Severity: ${SEVERITY_LABELS[v.severity]}`); console.log(` Rule: ${v.rule}`); console.log(` ${v.message}`); console.log(""); } formatCircularDependency(cd, index) { console.log(`${String(index + 1)}. ${cd.message}`); console.log(` Severity: ${SEVERITY_LABELS[cd.severity]}`); console.log(" Cycle path:"); cd.cycle.forEach((file, i) => { console.log(` ${String(i + 1)}. ${file}`); }); console.log(` ${String(cd.cycle.length + 1)}. ${cd.cycle[0]} (back to start)`); console.log(""); } formatNamingViolation(nc, index) { console.log(`${String(index + 1)}. ${nc.file}`); console.log(` Severity: ${SEVERITY_LABELS[nc.severity]}`); console.log(` File: ${nc.fileName}`); console.log(` Layer: ${nc.layer}`); console.log(` Type: ${nc.type}`); console.log(` Message: ${nc.message}`); if (nc.suggestion) { console.log(` šŸ’” Suggestion: ${nc.suggestion}`); } console.log(""); } formatFrameworkLeak(fl, index) { console.log(`${String(index + 1)}. ${fl.file}`); console.log(` Severity: ${SEVERITY_LABELS[fl.severity]}`); console.log(` Package: ${fl.packageName}`); console.log(` Category: ${fl.categoryDescription}`); console.log(` Layer: ${fl.layer}`); console.log(` Rule: ${fl.rule}`); console.log(` ${fl.message}`); console.log(` šŸ’” Suggestion: ${fl.suggestion}`); console.log(""); } formatEntityExposure(ee, index) { const location = ee.line ? `${ee.file}:${String(ee.line)}` : ee.file; console.log(`${String(index + 1)}. ${location}`); console.log(` Severity: ${SEVERITY_LABELS[ee.severity]}`); console.log(` Entity: ${ee.entityName}`); console.log(` Return Type: ${ee.returnType}`); if (ee.methodName) { console.log(` Method: ${ee.methodName}`); } console.log(` Layer: ${ee.layer}`); console.log(` Rule: ${ee.rule}`); console.log(` ${ee.message}`); console.log(" šŸ’” Suggestion:"); ee.suggestion.split("\n").forEach((line) => { if (line.trim()) { console.log(` ${line}`); } }); console.log(""); } formatDependencyDirection(dd, index) { console.log(`${String(index + 1)}. ${dd.file}`); console.log(` Severity: ${SEVERITY_LABELS[dd.severity]}`); console.log(` From Layer: ${dd.fromLayer}`); console.log(` To Layer: ${dd.toLayer}`); console.log(` Import: ${dd.importPath}`); console.log(` ${dd.message}`); console.log(` šŸ’” Suggestion: ${dd.suggestion}`); console.log(""); } formatRepositoryPattern(rp, index) { console.log(`${String(index + 1)}. ${rp.file}`); console.log(` Severity: ${SEVERITY_LABELS[rp.severity]}`); console.log(` Layer: ${rp.layer}`); console.log(` Type: ${rp.violationType}`); console.log(` Details: ${rp.details}`); console.log(` ${rp.message}`); console.log(` šŸ’” Suggestion: ${rp.suggestion}`); console.log(""); } formatAggregateBoundary(ab, index) { const location = ab.line ? `${ab.file}:${String(ab.line)}` : ab.file; console.log(`${String(index + 1)}. ${location}`); console.log(` Severity: ${SEVERITY_LABELS[ab.severity]}`); console.log(` From Aggregate: ${ab.fromAggregate}`); console.log(` To Aggregate: ${ab.toAggregate}`); console.log(` Entity: ${ab.entityName}`); console.log(` Import: ${ab.importPath}`); console.log(` ${ab.message}`); console.log(" šŸ’” Suggestion:"); ab.suggestion.split("\n").forEach((line) => { if (line.trim()) { console.log(` ${line}`); } }); console.log(""); } formatSecretViolation(sv, index) { const location = `${sv.file}:${String(sv.line)}:${String(sv.column)}`; console.log(`${String(index + 1)}. ${location}`); console.log(` Severity: ${SEVERITY_LABELS[sv.severity]} āš ļø`); console.log(` Secret Type: ${sv.secretType}`); console.log(` ${sv.message}`); console.log(" šŸ” CRITICAL: Rotate this secret immediately!"); console.log(" šŸ’” Suggestion:"); sv.suggestion.split("\n").forEach((line) => { if (line.trim()) { console.log(` ${line}`); } }); console.log(""); } formatHardcodeViolation(hc, index) { console.log(`${String(index + 1)}. ${hc.file}:${String(hc.line)}:${String(hc.column)}`); console.log(` Severity: ${SEVERITY_LABELS[hc.severity]}`); console.log(` Type: ${hc.type}`); console.log(` Value: ${JSON.stringify(hc.value)}`); console.log(` Context: ${hc.context.trim()}`); console.log(` šŸ’” Suggested: ${hc.suggestion.constantName}`); console.log(` šŸ“ Location: ${hc.suggestion.location}`); console.log(""); } formatAnemicModelViolation(am, index) { const location = am.line ? `${am.file}:${String(am.line)}` : am.file; console.log(`${String(index + 1)}. ${location}`); console.log(` Severity: ${SEVERITY_LABELS[am.severity]}`); console.log(` Class: ${am.className}`); console.log(` Layer: ${am.layer}`); console.log(` Methods: ${String(am.methodCount)} | Properties: ${String(am.propertyCount)}`); if (am.hasPublicSetters) { console.log(" āš ļø Has public setters (DDD anti-pattern)"); } if (am.hasOnlyGettersSetters) { console.log(" āš ļø Only getters/setters (no business logic)"); } console.log(` ${am.message}`); console.log(" šŸ’” Suggestion:"); am.suggestion.split("\n").forEach((line) => { if (line.trim()) { console.log(` ${line}`); } }); console.log(""); } } exports.OutputFormatter = OutputFormatter; //# sourceMappingURL=OutputFormatter.js.map