1use serde::Serialize;
2
3use super::{Summary, calculate_line_column, read_source_code};
4use crate::{Fix, violation::Violation};
5
6pub fn format_json(violations: &[Violation]) -> String {
7 let json_violations: Vec<JsonViolation> = violations.iter().map(violation_to_json).collect();
8
9 let summary = Summary::from_violations(violations);
10 let output = JsonOutput {
11 violations: json_violations,
12 summary,
13 };
14
15 serde_json::to_string_pretty(&output).unwrap_or_default()
16}
17
18fn violation_to_json(violation: &Violation) -> JsonViolation {
19 let source_code = read_source_code(violation.file.as_ref());
20
21 let (line_start, column_start) = calculate_line_column(&source_code, violation.span.start);
22 let (line_end, column_end) = calculate_line_column(&source_code, violation.span.end);
23
24 JsonViolation {
25 rule_id: violation.rule_id.to_string(),
26 lint_level: violation.lint_level.to_string(),
27 message: violation.message.to_string(),
28 file: violation.file.as_ref().map(ToString::to_string),
29 line_start,
30 line_end,
31 column_start,
32 column_end,
33 offset_start: violation.span.start,
34 offset_end: violation.span.end,
35 suggestion: violation.help.as_ref().map(ToString::to_string),
36 fix: violation.fix.as_ref().map(fix_to_json),
37 }
38}
39
40fn fix_to_json(fix: &Fix) -> JsonFix {
41 JsonFix {
42 description: fix.explanation.to_string(),
43 replacements: fix
44 .replacements
45 .iter()
46 .map(|r| JsonReplacement {
47 offset_start: r.span.start,
48 offset_end: r.span.end,
49 new_text: r.replacement_text.to_string(),
50 })
51 .collect(),
52 }
53}
54
55#[derive(Serialize)]
56pub struct JsonOutput {
57 pub violations: Vec<JsonViolation>,
58 pub summary: Summary,
59}
60
61#[derive(Serialize)]
62pub struct JsonViolation {
63 pub rule_id: String,
64 pub lint_level: String,
65 pub message: String,
66 pub file: Option<String>,
67 pub line_start: usize,
68 pub line_end: usize,
69 pub column_start: usize,
70 pub column_end: usize,
71 pub offset_start: usize,
72 pub offset_end: usize,
73 pub suggestion: Option<String>,
74 pub fix: Option<JsonFix>,
75}
76
77#[derive(Serialize)]
78pub struct JsonFix {
79 pub description: String,
80 pub replacements: Vec<JsonReplacement>,
81}
82
83#[derive(Serialize)]
84pub struct JsonReplacement {
85 pub offset_start: usize,
86 pub offset_end: usize,
87 pub new_text: String,
88}