Skip to content

Commit f24dab7

Browse files
Rollup merge of #106381 - aDotInTheVoid:jsondoclint-more-options, r=notriddle
Jsondoclint: Add `--verbose` and `--json-output` options There quite helpful for manually using jsondoclint as a debugging tool, especially on large files (these were written to look into core.json). r? rustdoc
2 parents 5d828d2 + 226ab7f commit f24dab7

File tree

6 files changed

+121
-34
lines changed

6 files changed

+121
-34
lines changed

Cargo.lock

+18-1
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
597597
dependencies = [
598598
"atty",
599599
"bitflags",
600-
"clap_derive",
600+
"clap_derive 3.2.18",
601601
"clap_lex 0.2.2",
602602
"indexmap",
603603
"once_cell",
@@ -614,7 +614,9 @@ checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
614614
dependencies = [
615615
"atty",
616616
"bitflags",
617+
"clap_derive 4.0.13",
617618
"clap_lex 0.3.0",
619+
"once_cell",
618620
"strsim",
619621
"termcolor",
620622
]
@@ -641,6 +643,19 @@ dependencies = [
641643
"syn",
642644
]
643645

646+
[[package]]
647+
name = "clap_derive"
648+
version = "4.0.13"
649+
source = "registry+https://github.com/rust-lang/crates.io-index"
650+
checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
651+
dependencies = [
652+
"heck",
653+
"proc-macro-error",
654+
"proc-macro2",
655+
"quote",
656+
"syn",
657+
]
658+
644659
[[package]]
645660
name = "clap_lex"
646661
version = "0.2.2"
@@ -2097,8 +2112,10 @@ name = "jsondoclint"
20972112
version = "0.1.0"
20982113
dependencies = [
20992114
"anyhow",
2115+
"clap 4.0.15",
21002116
"fs-err",
21012117
"rustdoc-json-types",
2118+
"serde",
21022119
"serde_json",
21032120
]
21042121

src/tools/jsondoclint/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ edition = "2021"
77

88
[dependencies]
99
anyhow = "1.0.62"
10+
clap = { version = "4.0.15", features = ["derive"] }
1011
fs-err = "2.8.1"
1112
rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" }
13+
serde = { version = "1.0", features = ["derive"] }
1214
serde_json = "1.0.85"

src/tools/jsondoclint/src/json_find.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::fmt::Write;
22

3+
use serde::Serialize;
34
use serde_json::Value;
45

5-
#[derive(Debug, Clone, PartialEq, Eq)]
6+
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
67
pub enum SelectorPart {
78
Field(String),
89
Index(usize),

src/tools/jsondoclint/src/main.rs

+71-27
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,103 @@
1-
use std::env;
1+
use std::io::{BufWriter, Write};
22

3-
use anyhow::{anyhow, bail, Result};
3+
use anyhow::{bail, Result};
4+
use clap::Parser;
45
use fs_err as fs;
56
use rustdoc_json_types::{Crate, Id, FORMAT_VERSION};
7+
use serde::Serialize;
68
use serde_json::Value;
79

810
pub(crate) mod item_kind;
911
mod json_find;
1012
mod validator;
1113

12-
#[derive(Debug, PartialEq, Eq)]
14+
#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
1315
struct Error {
1416
kind: ErrorKind,
1517
id: Id,
1618
}
1719

18-
#[derive(Debug, PartialEq, Eq)]
20+
#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
1921
enum ErrorKind {
20-
NotFound,
22+
NotFound(Vec<json_find::Selector>),
2123
Custom(String),
2224
}
2325

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+
2445
fn main() -> Result<()> {
25-
let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?;
46+
let Cli { path, verbose, json_output } = Cli::parse();
47+
2648
let contents = fs::read_to_string(&path)?;
2749
let krate: Crate = serde_json::from_str(&contents)?;
2850
assert_eq!(krate.format_version, FORMAT_VERSION);
2951

30-
let mut validator = validator::Validator::new(&krate);
52+
let krate_json: Value = serde_json::from_str(&contents)?;
53+
54+
let mut validator = validator::Validator::new(&krate, krate_json);
3155
validator.check_crate();
3256

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+
3364
if !validator.errs.is_empty() {
3465
for err in validator.errs {
3566
match err.kind {
36-
ErrorKind::NotFound => {
37-
let krate_json: Value = serde_json::from_str(&contents)?;
38-
39-
let sels =
40-
json_find::find_selector(&krate_json, &Value::String(err.id.0.clone()));
41-
match &sels[..] {
42-
[] => unreachable!(
43-
"id must be in crate, or it wouldn't be reported as not found"
44-
),
45-
[sel] => eprintln!(
46-
"{} not in index or paths, but refered to at '{}'",
47-
err.id.0,
48-
json_find::to_jsonpath(&sel)
49-
),
50-
[sel, ..] => eprintln!(
51-
"{} not in index or paths, but refered to at '{}' and more",
52-
err.id.0,
53-
json_find::to_jsonpath(&sel)
54-
),
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+
}
5599
}
56-
}
100+
},
57101
ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
58102
}
59103
}

src/tools/jsondoclint/src/validator.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use rustdoc_json_types::{
77
Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
88
TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
99
};
10+
use serde_json::Value;
1011

11-
use crate::{item_kind::Kind, Error, ErrorKind};
12+
use crate::{item_kind::Kind, json_find, Error, ErrorKind};
1213

1314
/// The Validator walks over the JSON tree, and ensures it is well formed.
1415
/// It is made of several parts.
@@ -22,6 +23,7 @@ use crate::{item_kind::Kind, Error, ErrorKind};
2223
pub struct Validator<'a> {
2324
pub(crate) errs: Vec<Error>,
2425
krate: &'a Crate,
26+
krate_json: Value,
2527
/// Worklist of Ids to check.
2628
todo: HashSet<&'a Id>,
2729
/// Ids that have already been visited, so don't need to be checked again.
@@ -39,9 +41,10 @@ enum PathKind {
3941
}
4042

4143
impl<'a> Validator<'a> {
42-
pub fn new(krate: &'a Crate) -> Self {
44+
pub fn new(krate: &'a Crate, krate_json: Value) -> Self {
4345
Self {
4446
krate,
47+
krate_json,
4548
errs: Vec::new(),
4649
seen_ids: HashSet::new(),
4750
todo: HashSet::new(),
@@ -373,7 +376,11 @@ impl<'a> Validator<'a> {
373376
} else {
374377
if !self.missing_ids.contains(id) {
375378
self.missing_ids.insert(id);
376-
self.fail(id, ErrorKind::NotFound)
379+
380+
let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone()));
381+
assert_ne!(sels.len(), 0);
382+
383+
self.fail(id, ErrorKind::NotFound(sels))
377384
}
378385
}
379386
}

src/tools/jsondoclint/src/validator/tests.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ use std::collections::HashMap;
22

33
use rustdoc_json_types::{Crate, Item, Visibility};
44

5+
use crate::json_find::SelectorPart;
6+
57
use super::*;
68

79
#[track_caller]
810
fn check(krate: &Crate, errs: &[Error]) {
9-
let mut validator = Validator::new(krate);
11+
let krate_string = serde_json::to_string(krate).unwrap();
12+
let krate_json = serde_json::from_str(&krate_string).unwrap();
13+
14+
let mut validator = Validator::new(krate, krate_json);
1015
validator.check_crate();
1116

1217
assert_eq!(errs, &validator.errs[..]);
@@ -46,5 +51,16 @@ fn errors_on_missing_links() {
4651
format_version: rustdoc_json_types::FORMAT_VERSION,
4752
};
4853

49-
check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]);
54+
check(
55+
&k,
56+
&[Error {
57+
kind: ErrorKind::NotFound(vec![vec![
58+
SelectorPart::Field("index".to_owned()),
59+
SelectorPart::Field("0".to_owned()),
60+
SelectorPart::Field("links".to_owned()),
61+
SelectorPart::Field("Not Found".to_owned()),
62+
]]),
63+
id: id("1"),
64+
}],
65+
);
5066
}

0 commit comments

Comments
 (0)