// ============================================================================= // TOM Generator ZIP Export - Helper Functions // Private helpers extracted from zip.ts to stay under 500 LOC hard cap // ============================================================================= import { TOMGeneratorState, DerivedTOM } from '../types' import { getControlById } from '../controls/loader' import type { ZIPExportOptions } from './zip' // ============================================================================= // HELPER FUNCTIONS // ============================================================================= export function generateReadme( state: TOMGeneratorState, opts: ZIPExportOptions ): string { const date = new Date().toISOString().split('T')[0] const lang = opts.language return `# TOM Export Package ${lang === 'de' ? 'Exportiert am' : 'Exported on'}: ${date} ${lang === 'de' ? 'Unternehmen' : 'Company'}: ${state.companyProfile?.name || 'N/A'} ## ${lang === 'de' ? 'Inhalt' : 'Contents'} ### /data - **profiles/** - ${lang === 'de' ? 'Profilinformationen (Unternehmen, Daten, Architektur, Sicherheit, Risiko)' : 'Profile information (company, data, architecture, security, risk)'} - **toms/** - ${lang === 'de' ? 'Abgeleitete TOMs und Zusammenfassungen' : 'Derived TOMs and summaries'} - **evidence/** - ${lang === 'de' ? 'Nachweisdokumente und Zuordnungen' : 'Evidence documents and mappings'} - **gap-analysis/** - ${lang === 'de' ? 'Lückenanalyse und Empfehlungen' : 'Gap analysis and recommendations'} ### /reference - **control-library/** - ${lang === 'de' ? 'Kontrollbibliothek mit allen 60+ Kontrollen' : 'Control library with all 60+ controls'} ### /documents - **tom-summary.md** - ${lang === 'de' ? 'Zusammenfassung als Markdown' : 'Summary as Markdown'} - **toms.csv** - ${lang === 'de' ? 'CSV für Tabellenimport' : 'CSV for spreadsheet import'} ## ${lang === 'de' ? 'Statistiken' : 'Statistics'} - ${lang === 'de' ? 'Gesamtzahl TOMs' : 'Total TOMs'}: ${state.derivedTOMs.length} - ${lang === 'de' ? 'Erforderlich' : 'Required'}: ${state.derivedTOMs.filter((t) => t.applicability === 'REQUIRED').length} - ${lang === 'de' ? 'Umgesetzt' : 'Implemented'}: ${state.derivedTOMs.filter((t) => t.implementationStatus === 'IMPLEMENTED').length} - ${lang === 'de' ? 'Schutzbedarf' : 'Protection Level'}: ${state.riskProfile?.protectionLevel || 'N/A'} ${state.gapAnalysis ? `- ${lang === 'de' ? 'Compliance Score' : 'Compliance Score'}: ${state.gapAnalysis.overallScore}%` : ''} --- ${lang === 'de' ? 'Generiert mit dem TOM Generator' : 'Generated with TOM Generator'} ` } export function groupTOMsByCategory( toms: DerivedTOM[] ): Map { const grouped = new Map() for (const tom of toms) { const control = getControlById(tom.controlId) if (!control) continue const category = control.category const existing: DerivedTOM[] = grouped.get(category) || [] existing.push(tom) grouped.set(category, existing) } return grouped } export function generateImplementationSummary( toms: Array<{ implementationStatus: string; applicability: string }> ): Record { return { total: toms.length, required: toms.filter((t) => t.applicability === 'REQUIRED').length, recommended: toms.filter((t) => t.applicability === 'RECOMMENDED').length, optional: toms.filter((t) => t.applicability === 'OPTIONAL').length, notApplicable: toms.filter((t) => t.applicability === 'NOT_APPLICABLE').length, implemented: toms.filter((t) => t.implementationStatus === 'IMPLEMENTED').length, partial: toms.filter((t) => t.implementationStatus === 'PARTIAL').length, notImplemented: toms.filter((t) => t.implementationStatus === 'NOT_IMPLEMENTED').length, } } export function groupEvidenceByControl( documents: Array<{ id: string; linkedControlIds: string[] }> ): Map { const grouped = new Map() for (const doc of documents) { for (const controlId of doc.linkedControlIds) { const existing = grouped.get(controlId) || [] existing.push(doc.id) grouped.set(controlId, existing) } } return grouped } export function generateRecommendationsMarkdown( recommendations: string[], language: 'de' | 'en' ): string { const title = language === 'de' ? 'Empfehlungen' : 'Recommendations' return `# ${title} ${recommendations.map((rec, i) => `${i + 1}. ${rec}`).join('\n\n')} --- ${language === 'de' ? 'Generiert am' : 'Generated on'} ${new Date().toISOString().split('T')[0]} ` } export function generateMarkdownSummary( state: TOMGeneratorState, opts: ZIPExportOptions ): string { const lang = opts.language const date = new Date().toLocaleDateString(lang === 'de' ? 'de-DE' : 'en-US') let md = `# ${lang === 'de' ? 'Technische und Organisatorische Maßnahmen' : 'Technical and Organizational Measures'} **${lang === 'de' ? 'Unternehmen' : 'Company'}:** ${state.companyProfile?.name || 'N/A'} **${lang === 'de' ? 'Stand' : 'Date'}:** ${date} **${lang === 'de' ? 'Schutzbedarf' : 'Protection Level'}:** ${state.riskProfile?.protectionLevel || 'N/A'} ## ${lang === 'de' ? 'Zusammenfassung' : 'Summary'} | ${lang === 'de' ? 'Metrik' : 'Metric'} | ${lang === 'de' ? 'Wert' : 'Value'} | |--------|-------| | ${lang === 'de' ? 'Gesamtzahl TOMs' : 'Total TOMs'} | ${state.derivedTOMs.length} | | ${lang === 'de' ? 'Erforderlich' : 'Required'} | ${state.derivedTOMs.filter((t) => t.applicability === 'REQUIRED').length} | | ${lang === 'de' ? 'Umgesetzt' : 'Implemented'} | ${state.derivedTOMs.filter((t) => t.implementationStatus === 'IMPLEMENTED').length} | | ${lang === 'de' ? 'Teilweise umgesetzt' : 'Partially Implemented'} | ${state.derivedTOMs.filter((t) => t.implementationStatus === 'PARTIAL').length} | | ${lang === 'de' ? 'Nicht umgesetzt' : 'Not Implemented'} | ${state.derivedTOMs.filter((t) => t.implementationStatus === 'NOT_IMPLEMENTED').length} | ` if (state.gapAnalysis) { md += ` ## ${lang === 'de' ? 'Compliance Score' : 'Compliance Score'} **${state.gapAnalysis.overallScore}%** ` } // Add required TOMs table const requiredTOMs = state.derivedTOMs.filter( (t) => t.applicability === 'REQUIRED' ) if (requiredTOMs.length > 0) { md += ` ## ${lang === 'de' ? 'Erforderliche Maßnahmen' : 'Required Measures'} | ID | ${lang === 'de' ? 'Maßnahme' : 'Measure'} | Status | |----|----------|--------| ${requiredTOMs.map((tom) => `| ${tom.controlId} | ${tom.name} | ${formatStatus(tom.implementationStatus, lang)} |`).join('\n')} ` } return md } export function generateCSV( toms: Array<{ controlId: string name: string description: string applicability: string implementationStatus: string responsiblePerson: string | null }>, opts: ZIPExportOptions ): string { const lang = opts.language const headers = lang === 'de' ? ['ID', 'Name', 'Beschreibung', 'Anwendbarkeit', 'Status', 'Verantwortlich'] : ['ID', 'Name', 'Description', 'Applicability', 'Status', 'Responsible'] const rows = toms.map((tom) => [ tom.controlId, escapeCSV(tom.name), escapeCSV(tom.description), tom.applicability, tom.implementationStatus, tom.responsiblePerson || '', ]) return [ headers.join(','), ...rows.map((row) => row.join(',')), ].join('\n') } export function escapeCSV(value: string): string { if (value.includes(',') || value.includes('"') || value.includes('\n')) { return `"${value.replace(/"/g, '""')}"` } return value } export function formatStatus(status: string, lang: 'de' | 'en'): string { const statuses: Record> = { NOT_IMPLEMENTED: { de: 'Nicht umgesetzt', en: 'Not Implemented' }, PARTIAL: { de: 'Teilweise', en: 'Partial' }, IMPLEMENTED: { de: 'Umgesetzt', en: 'Implemented' }, } return statuses[status]?.[lang] || status }