import axios from 'axios'; import { ComplianceReport } from '../types'; export class SlackNotifier { constructor(private webhookUrl: string) {} async notify(report: ComplianceReport): Promise { const { fileName, violations, summary } = report; const blocks = [ { type: 'header', text: { type: 'plain_text', text: `🚨 Design Violations Detected: ${fileName}`, emoji: true, }, }, { type: 'section', fields: [ { type: 'mrkdwn', text: `*Total Violations:*\n${summary.total}`, }, { type: 'mrkdwn', text: `*Critical:*\n${summary.bySeverity.critical || 0}`, }, { type: 'mrkdwn', text: `*Warnings:*\n${summary.bySeverity.warning || 0}`, }, { type: 'mrkdwn', text: `*Info:*\n${summary.bySeverity.info || 0}`, }, ], }, { type: 'divider', }, ]; // Add top 5 violations const topViolations = violations.slice(0, 5); for (const v of topViolations) { blocks.push({ type: 'section', text: { type: 'mrkdwn', text: `*${this.getSeverityEmoji(v.severity)} ${v.type.toUpperCase()}*\n${v.message}\n_${v.node.name} in ${v.frame || 'Unknown frame'}_`, }, }); } if (violations.length > 5) { blocks.push({ type: 'context', elements: [ { type: 'mrkdwn', text: `_+ ${violations.length - 5} more violations_`, }, ], }); } await axios.post(this.webhookUrl, { blocks, text: `Design violations detected in ${fileName}`, }); } private getSeverityEmoji(severity: string): string { switch (severity) { case 'critical': return '🔴'; case 'warning': return '🟡'; case 'info': return '🔵'; default: return '⚪'; } } }