import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" import type { Finding, FindingClass, FindingStatus } from "./types"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } export function groupBy(items: T[], key: (item: T) => string): Record { const result: Record = {}; for (const item of items) { const k = key(item); (result[k] ??= []).push(item); } return result; } const STATUS_ORDER: Record = { ERROR: 0, WARNING: 1, INFO: 2 }; const CLASS_ORDER: Record = { RULE: 0, RISK: 1, REVIEW: 2, INFO: 3 }; export function sortFindings(findings: Finding[]): Finding[] { return [...findings].sort((a, b) => { const status = STATUS_ORDER[a.status] - STATUS_ORDER[b.status]; if (status !== 0) return status; const ac = CLASS_ORDER[a.finding_class ?? "INFO"] ?? 9; const bc = CLASS_ORDER[b.finding_class ?? "INFO"] ?? 9; if (ac !== bc) return ac - bc; return (a.designator || "").localeCompare(b.designator || "") || (a.rule_id || "").localeCompare(b.rule_id || "") || (a.finding || "").localeCompare(b.finding || ""); }); } export function getFindingKey(finding: Finding, index: number): string { return finding.finding_id ?? `${finding.designator}-idx-${index}`; } export function subtypeLabel(subtype: string | null): string { if (!subtype) return ""; const parts = subtype.split("."); return parts[parts.length - 1] .replace(/_/g, " ") .replace(/\b\w/g, (c) => c.toUpperCase()); }