autocorrect/result/
rdjson.rs

1//! Rdjson format for reviewdog
2//! https://github.com/reviewdog/reviewdog/tree/master/proto/rdf
3use super::LintResult;
4use serde::{Deserialize, Serialize};
5
6#[derive(Serialize, Deserialize, Clone)]
7struct RdfJson {
8    source: RdfSource,
9    severity: String,
10    diagnostics: String,
11}
12
13#[derive(Serialize, Deserialize, Clone)]
14struct RdfSource {
15    name: String,
16    url: String,
17}
18
19#[derive(Serialize, Deserialize, Clone)]
20struct RdfDiagnostic {
21    message: String,
22    severity: String,
23    code: RdfCode,
24    location: RdfLocation,
25    suggestions: Vec<RdfSuggetion>,
26}
27
28#[derive(Serialize, Deserialize, Clone)]
29struct RdfLocation {
30    path: String,
31    range: RdfRange,
32}
33
34#[derive(Serialize, Deserialize, Clone)]
35struct RdfRange {
36    start: Option<RdfLineColumn>,
37    end: Option<RdfLineColumn>,
38}
39
40#[derive(Serialize, Deserialize, Clone)]
41struct RdfLineColumn {
42    // start from 1
43    line: usize,
44    // start from 1, byte count in UTF-8, not char count
45    // For example: "你好" is 6 bytes
46    column: usize,
47}
48
49#[derive(Serialize, Deserialize, Clone)]
50struct RdfSuggetion {
51    text: String,
52    range: RdfRange,
53}
54
55#[derive(Serialize, Deserialize, Clone)]
56struct RdfCode {
57    value: Option<String>,
58    url: String,
59}
60
61fn to_severity_str(severity: super::Severity) -> String {
62    match severity {
63        super::Severity::Error => "ERROR".to_owned(),
64        super::Severity::Warning => "WARNING".to_owned(),
65        super::Severity::Pass => "PASS".to_owned(),
66    }
67}
68
69/// RDF JSONSchema
70/// https://github.com/reviewdog/reviewdog/blob/master/proto/rdf/jsonschema/Diagnostic.jsonschema
71#[doc(hidden)]
72pub(crate) fn to_rdjson_diagnostics(lint_result: &LintResult) -> Vec<String> {
73    let mut diagnostics = vec![];
74    lint_result.lines.iter().for_each(|line_result| {
75        let start: RdfLineColumn = RdfLineColumn {
76            line: line_result.line,
77            column: line_result.col,
78        };
79        let end = RdfLineColumn {
80            line: line_result.line + line_result.old.split("\n").count() - 1,
81            column: line_result.col + line_result.old.split("\n").last().unwrap_or("").len(),
82        };
83
84        let rdf_diagnostic: RdfDiagnostic = RdfDiagnostic {
85            message: "".to_owned(),
86            location: RdfLocation {
87                path: lint_result.filepath.replace("./", ""),
88                range: RdfRange {
89                    start: Some(start.clone()),
90                    end: Some(end.clone()),
91                },
92            },
93            severity: to_severity_str(line_result.severity),
94            code: RdfCode {
95                value: Some("AutoCorrect".to_owned()),
96                url: "https://github.com/huacnlee/autocorrect".to_owned(),
97            },
98            suggestions: vec![RdfSuggetion {
99                text: line_result.new.clone(),
100                range: RdfRange {
101                    start: Some(start),
102                    end: Some(end),
103                },
104            }],
105        };
106
107        diagnostics.push(serde_json::to_string(&rdf_diagnostic).unwrap())
108    });
109
110    diagnostics
111}
112
113#[doc(hidden)]
114pub fn to_lint_results_rdjson(lint_results: Vec<LintResult>) -> String {
115    let diagnostics = lint_results
116        .iter()
117        .flat_map(to_rdjson_diagnostics)
118        .collect::<Vec<_>>()
119        .join(",");
120    format!(
121        r#"{{"source":{{"name":"AutoCorrect Lint","url": "https://github.com/huacnlee/autocorrect"}},"diagnostics": [{diagnostics}]}}"#,
122    )
123}
124
125#[cfg(test)]
126mod tests {
127    #[test]
128    fn test_to_lint_results_rdjson() {
129        let rdjson = super::to_lint_results_rdjson(crate::result::json::crate_test_lint_results());
130
131        let expected = r#"{"source":{"name":"AutoCorrect Lint","url": "https://github.com/huacnlee/autocorrect"},"diagnostics": [{"message":"","severity":"ERROR","code":{"value":"AutoCorrect","url":"https://github.com/huacnlee/autocorrect"},"location":{"path":"test/foo/bar.rs","range":{"start":{"line":1,"column":1},"end":{"line":1,"column":13}}},"suggestions":[{"text":"hello 你好。","range":{"start":{"line":1,"column":1},"end":{"line":1,"column":13}}}]},{"message":"","severity":"ERROR","code":{"value":"AutoCorrect","url":"https://github.com/huacnlee/autocorrect"},"location":{"path":"test/foo/bar.rs","range":{"start":{"line":2,"column":1},"end":{"line":2,"column":14}}},"suggestions":[{"text":"这是第 2 行","range":{"start":{"line":2,"column":1},"end":{"line":2,"column":14}}}]}]}"#;
132        if expected != rdjson {
133            println!("--------------- rdjson:\n{}", rdjson);
134        }
135        assert_json_eq!(expected, rdjson);
136    }
137}