1use std::io::Write;
8
9use crate::report::ValidationReport;
10
11pub fn write_json(report: &ValidationReport, writer: &mut dyn Write) -> anyhow::Result<()> {
17 let json = serde_json::to_string_pretty(report)?;
18 writeln!(writer, "{json}")?;
19 Ok(())
20}
21
22pub fn write_human(report: &ValidationReport, writer: &mut dyn Write) -> anyhow::Result<()> {
30 writeln!(writer)?;
31 writeln!(writer, "{}", "=".repeat(80))?;
32 writeln!(writer, " GTS DOCUMENTATION VALIDATOR")?;
33 writeln!(writer, "{}", "=".repeat(80))?;
34 writeln!(writer)?;
35 writeln!(writer, " Files scanned: {}", report.scanned_files)?;
36 writeln!(writer, " Files failed: {}", report.failed_files)?;
37 writeln!(writer, " Errors found: {}", report.errors_count())?;
38 writeln!(writer)?;
39
40 if !report.scan_errors.is_empty() {
41 writeln!(writer, "{}", "-".repeat(80))?;
42 writeln!(writer, " SCAN ERRORS (files that could not be validated)")?;
43 writeln!(writer, "{}", "-".repeat(80))?;
44 for scan_err in &report.scan_errors {
45 writeln!(writer, "{}", scan_err.format_human_readable())?;
46 }
47 writeln!(writer)?;
48 }
49
50 if !report.validation_errors.is_empty() {
51 writeln!(writer, "{}", "-".repeat(80))?;
52 writeln!(writer, " VALIDATION ERRORS")?;
53 writeln!(writer, "{}", "-".repeat(80))?;
54 for error in &report.validation_errors {
55 writeln!(writer, "{}", error.format_human_readable())?;
56 }
57 writeln!(writer)?;
58 }
59
60 writeln!(writer, "{}", "=".repeat(80))?;
61 if report.ok {
62 writeln!(
63 writer,
64 "\u{2713} All {} files passed validation",
65 report.scanned_files
66 )?;
67 } else {
68 if !report.scan_errors.is_empty() {
69 writeln!(
70 writer,
71 "\u{2717} {} file(s) could not be scanned \u{2014} CI must treat this as a failure",
72 report.failed_files
73 )?;
74 }
75 if !report.validation_errors.is_empty() {
76 writeln!(
77 writer,
78 "\u{2717} {} invalid GTS identifier(s) found",
79 report.errors_count()
80 )?;
81 writeln!(writer)?;
82 writeln!(writer, " To fix:")?;
83
84 let has_vendor_mismatch = report
85 .validation_errors
86 .iter()
87 .any(|e| e.error.contains("Vendor mismatch"));
88 let has_wildcard_error = report
89 .validation_errors
90 .iter()
91 .any(|e| e.error.contains("Wildcard"));
92 let has_parse_error = report
93 .validation_errors
94 .iter()
95 .any(|e| !e.error.contains("Vendor mismatch") && !e.error.contains("Wildcard"));
96
97 if has_parse_error {
98 writeln!(
99 writer,
100 " - Schema IDs must end with ~ (e.g., gts.x.core.type.v1~)"
101 )?;
102 writeln!(
103 writer,
104 " - Each segment needs 5 parts: vendor.package.namespace.type.version"
105 )?;
106 writeln!(writer, " - No hyphens allowed, use underscores")?;
107 }
108 if has_wildcard_error {
109 writeln!(
110 writer,
111 " - Wildcards (*) only in filter/pattern contexts"
112 )?;
113 }
114 if has_vendor_mismatch {
115 writeln!(writer, " - Ensure all GTS IDs use the expected vendor")?;
116 }
117 }
118 }
119 writeln!(writer, "{}", "=".repeat(80))?;
120
121 Ok(())
122}