refactor(go): split training/store, ucca/rules, ucca_handlers, document_export under 500 LOC
Each of the four oversized files (training/store.go 1569 LOC, ucca/rules.go 1231 LOC, ucca_handlers.go 1135 LOC, document_export.go 1101 LOC) is split by logical group into same-package files, all under the 500-line hard cap. Zero behavior changes, no renamed exported symbols. Also fixed pre-existing hazard_library split (missing functions and duplicate UUID keys from a prior session). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
198
ai-compliance-sdk/internal/iace/document_export_helpers.go
Normal file
198
ai-compliance-sdk/internal/iace/document_export_helpers.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package iace
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// buildAssessmentMap builds a map from hazardID string to the latest RiskAssessment.
|
||||
func buildAssessmentMap(assessments []RiskAssessment) map[string]*RiskAssessment {
|
||||
m := make(map[string]*RiskAssessment)
|
||||
for i := range assessments {
|
||||
a := &assessments[i]
|
||||
key := a.HazardID.String()
|
||||
if existing, ok := m[key]; !ok || a.Version > existing.Version {
|
||||
m[key] = a
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// riskLevelColor returns RGB values for PDF fill color based on risk level.
|
||||
func riskLevelColor(level RiskLevel) (r, g, b int) {
|
||||
switch level {
|
||||
case RiskLevelNotAcceptable:
|
||||
return 180, 0, 0
|
||||
case RiskLevelVeryHigh:
|
||||
return 220, 40, 40
|
||||
case RiskLevelCritical:
|
||||
return 255, 80, 80
|
||||
case RiskLevelHigh:
|
||||
return 255, 165, 80
|
||||
case RiskLevelMedium:
|
||||
return 255, 230, 100
|
||||
case RiskLevelLow:
|
||||
return 180, 230, 140
|
||||
case RiskLevelNegligible:
|
||||
return 140, 210, 140
|
||||
default:
|
||||
return 240, 240, 240
|
||||
}
|
||||
}
|
||||
|
||||
// riskLevelLabel returns a German display label for a risk level.
|
||||
func riskLevelLabel(level RiskLevel) string {
|
||||
switch level {
|
||||
case RiskLevelNotAcceptable:
|
||||
return "Nicht akzeptabel"
|
||||
case RiskLevelVeryHigh:
|
||||
return "Sehr hoch"
|
||||
case RiskLevelCritical:
|
||||
return "Kritisch"
|
||||
case RiskLevelHigh:
|
||||
return "Hoch"
|
||||
case RiskLevelMedium:
|
||||
return "Mittel"
|
||||
case RiskLevelLow:
|
||||
return "Niedrig"
|
||||
case RiskLevelNegligible:
|
||||
return "Vernachlaessigbar"
|
||||
default:
|
||||
return string(level)
|
||||
}
|
||||
}
|
||||
|
||||
// reductionTypeLabel returns a German label for a reduction type.
|
||||
func reductionTypeLabel(rt ReductionType) string {
|
||||
switch rt {
|
||||
case ReductionTypeDesign:
|
||||
return "Konstruktiv"
|
||||
case ReductionTypeProtective:
|
||||
return "Schutzmassnahme"
|
||||
case ReductionTypeInformation:
|
||||
return "Information"
|
||||
default:
|
||||
return string(rt)
|
||||
}
|
||||
}
|
||||
|
||||
// mitigationStatusLabel returns a German label for a mitigation status.
|
||||
func mitigationStatusLabel(status MitigationStatus) string {
|
||||
switch status {
|
||||
case MitigationStatusPlanned:
|
||||
return "Geplant"
|
||||
case MitigationStatusImplemented:
|
||||
return "Umgesetzt"
|
||||
case MitigationStatusVerified:
|
||||
return "Verifiziert"
|
||||
case MitigationStatusRejected:
|
||||
return "Abgelehnt"
|
||||
default:
|
||||
return string(status)
|
||||
}
|
||||
}
|
||||
|
||||
// regulationLabel returns a German label for a regulation type.
|
||||
func regulationLabel(reg RegulationType) string {
|
||||
switch reg {
|
||||
case RegulationNIS2:
|
||||
return "NIS-2 Richtlinie"
|
||||
case RegulationAIAct:
|
||||
return "EU AI Act"
|
||||
case RegulationCRA:
|
||||
return "Cyber Resilience Act"
|
||||
case RegulationMachineryRegulation:
|
||||
return "EU Maschinenverordnung 2023/1230"
|
||||
default:
|
||||
return string(reg)
|
||||
}
|
||||
}
|
||||
|
||||
// escapeXML escapes special XML characters in text content.
|
||||
func escapeXML(s string) string {
|
||||
var buf bytes.Buffer
|
||||
if err := xml.EscapeText(&buf, []byte(s)); err != nil {
|
||||
return s
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// countByRiskLevel counts assessments per risk level.
|
||||
func countByRiskLevel(assessments []RiskAssessment) map[RiskLevel]int {
|
||||
counts := make(map[RiskLevel]int)
|
||||
for _, a := range assessments {
|
||||
counts[a.RiskLevel]++
|
||||
}
|
||||
return counts
|
||||
}
|
||||
|
||||
// pdfTruncate truncates a string for PDF cell display.
|
||||
func pdfTruncate(s string, maxLen int) string {
|
||||
runes := []rune(s)
|
||||
if len(runes) <= maxLen {
|
||||
return s
|
||||
}
|
||||
if maxLen <= 3 {
|
||||
return string(runes[:maxLen])
|
||||
}
|
||||
return string(runes[:maxLen-3]) + "..."
|
||||
}
|
||||
|
||||
// cellRef builds an Excel cell reference like "A1", "B12".
|
||||
func cellRef(col string, row int) string {
|
||||
return fmt.Sprintf("%s%d", col, row)
|
||||
}
|
||||
|
||||
// rgbHex converts RGB values to a hex color string (without #).
|
||||
func rgbHex(r, g, b int) string {
|
||||
return fmt.Sprintf("%02X%02X%02X", r, g, b)
|
||||
}
|
||||
|
||||
// addZipEntry writes a text file into a zip archive.
|
||||
func addZipEntry(zw *zip.Writer, name, content string) error {
|
||||
w, err := zw.Create(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write([]byte(content))
|
||||
return err
|
||||
}
|
||||
|
||||
// docxHeading builds a DOCX paragraph with a heading style.
|
||||
func docxHeading(text string, level int) string {
|
||||
sizes := map[int]int{1: 64, 2: 52, 3: 44}
|
||||
sz, ok := sizes[level]
|
||||
if !ok {
|
||||
sz = 44
|
||||
}
|
||||
escaped := escapeXML(text)
|
||||
return fmt.Sprintf(` <w:p>
|
||||
<w:pPr>
|
||||
<w:pStyle w:val="Heading%d"/>
|
||||
<w:spacing w:after="200"/>
|
||||
</w:pPr>
|
||||
<w:r>
|
||||
<w:rPr><w:b/><w:sz w:val="%d"/><w:szCs w:val="%d"/></w:rPr>
|
||||
<w:t xml:space="preserve">%s</w:t>
|
||||
</w:r>
|
||||
</w:p>
|
||||
`, level, sz, sz, escaped)
|
||||
}
|
||||
|
||||
// docxParagraph builds a DOCX paragraph, optionally italic.
|
||||
func docxParagraph(text string, italic bool) string {
|
||||
escaped := escapeXML(text)
|
||||
rpr := ""
|
||||
if italic {
|
||||
rpr = "<w:rPr><w:i/></w:rPr>"
|
||||
}
|
||||
return fmt.Sprintf(` <w:p>
|
||||
<w:r>
|
||||
%s
|
||||
<w:t xml:space="preserve">%s</w:t>
|
||||
</w:r>
|
||||
</w:p>
|
||||
`, rpr, escaped)
|
||||
}
|
||||
Reference in New Issue
Block a user