]> git.lizzy.rs Git - rust.git/blob - src/tools/jsondoclint/src/main.rs
Rollup merge of #106341 - Ezrashaw:refactor-error-code-tidy-check, r=mejrs,klensy...
[rust.git] / src / tools / jsondoclint / src / main.rs
1 use std::io::{BufWriter, Write};
2
3 use anyhow::{bail, Result};
4 use clap::Parser;
5 use fs_err as fs;
6 use rustdoc_json_types::{Crate, Id, FORMAT_VERSION};
7 use serde::Serialize;
8 use serde_json::Value;
9
10 pub(crate) mod item_kind;
11 mod json_find;
12 mod validator;
13
14 #[derive(Debug, PartialEq, Eq, Serialize, Clone)]
15 struct Error {
16     kind: ErrorKind,
17     id: Id,
18 }
19
20 #[derive(Debug, PartialEq, Eq, Serialize, Clone)]
21 enum ErrorKind {
22     NotFound(Vec<json_find::Selector>),
23     Custom(String),
24 }
25
26 #[derive(Debug, Serialize)]
27 struct JsonOutput {
28     path: String,
29     errors: Vec<Error>,
30 }
31
32 #[derive(Parser)]
33 struct Cli {
34     /// The path to the json file to be linted
35     path: String,
36
37     /// Show verbose output
38     #[arg(long)]
39     verbose: bool,
40
41     #[arg(long)]
42     json_output: Option<String>,
43 }
44
45 fn main() -> Result<()> {
46     let Cli { path, verbose, json_output } = Cli::parse();
47
48     let contents = fs::read_to_string(&path)?;
49     let krate: Crate = serde_json::from_str(&contents)?;
50     assert_eq!(krate.format_version, FORMAT_VERSION);
51
52     let krate_json: Value = serde_json::from_str(&contents)?;
53
54     let mut validator = validator::Validator::new(&krate, krate_json);
55     validator.check_crate();
56
57     if let Some(json_output) = json_output {
58         let output = JsonOutput { path: path.clone(), errors: validator.errs.clone() };
59         let mut f = BufWriter::new(fs::File::create(json_output)?);
60         serde_json::to_writer(&mut f, &output)?;
61         f.flush()?;
62     }
63
64     if !validator.errs.is_empty() {
65         for err in validator.errs {
66             match err.kind {
67                 ErrorKind::NotFound(sels) => match &sels[..] {
68                     [] => {
69                         unreachable!(
70                             "id {:?} must be in crate, or it wouldn't be reported as not found",
71                             err.id
72                         )
73                     }
74                     [sel] => eprintln!(
75                         "{} not in index or paths, but refered to at '{}'",
76                         err.id.0,
77                         json_find::to_jsonpath(&sel)
78                     ),
79                     [sel, ..] => {
80                         if verbose {
81                             let sels = sels
82                                 .iter()
83                                 .map(json_find::to_jsonpath)
84                                 .map(|i| format!("'{i}'"))
85                                 .collect::<Vec<_>>()
86                                 .join(", ");
87                             eprintln!(
88                                 "{} not in index or paths, but refered to at {sels}",
89                                 err.id.0
90                             );
91                         } else {
92                             eprintln!(
93                                 "{} not in index or paths, but refered to at '{}' and {} more",
94                                 err.id.0,
95                                 json_find::to_jsonpath(&sel),
96                                 sels.len() - 1,
97                             )
98                         }
99                     }
100                 },
101                 ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
102             }
103         }
104         bail!("Errors validating json {path}");
105     }
106
107     Ok(())
108 }