mirror of https://github.com/rust-lang/rust.git
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
This commit is contained in:
commit
f24dab764f
19
Cargo.lock
19
Cargo.lock
|
@ -597,7 +597,7 @@ checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
|
|||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_derive 3.2.18",
|
||||
"clap_lex 0.2.2",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
|
@ -614,7 +614,9 @@ checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
|
|||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive 4.0.13",
|
||||
"clap_lex 0.3.0",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
]
|
||||
|
@ -641,6 +643,19 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.2"
|
||||
|
@ -2097,8 +2112,10 @@ name = "jsondoclint"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.15",
|
||||
"fs-err",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.62"
|
||||
clap = { version = "4.0.15", features = ["derive"] }
|
||||
fs-err = "2.8.1"
|
||||
rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.85"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub enum SelectorPart {
|
||||
Field(String),
|
||||
Index(usize),
|
||||
|
|
|
@ -1,59 +1,103 @@
|
|||
use std::env;
|
||||
use std::io::{BufWriter, Write};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use clap::Parser;
|
||||
use fs_err as fs;
|
||||
use rustdoc_json_types::{Crate, Id, FORMAT_VERSION};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
||||
pub(crate) mod item_kind;
|
||||
mod json_find;
|
||||
mod validator;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
|
||||
struct Error {
|
||||
kind: ErrorKind,
|
||||
id: Id,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Clone)]
|
||||
enum ErrorKind {
|
||||
NotFound,
|
||||
NotFound(Vec<json_find::Selector>),
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct JsonOutput {
|
||||
path: String,
|
||||
errors: Vec<Error>,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Cli {
|
||||
/// The path to the json file to be linted
|
||||
path: String,
|
||||
|
||||
/// Show verbose output
|
||||
#[arg(long)]
|
||||
verbose: bool,
|
||||
|
||||
#[arg(long)]
|
||||
json_output: Option<String>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let path = env::args().nth(1).ok_or_else(|| anyhow!("no path given"))?;
|
||||
let Cli { path, verbose, json_output } = Cli::parse();
|
||||
|
||||
let contents = fs::read_to_string(&path)?;
|
||||
let krate: Crate = serde_json::from_str(&contents)?;
|
||||
assert_eq!(krate.format_version, FORMAT_VERSION);
|
||||
|
||||
let mut validator = validator::Validator::new(&krate);
|
||||
let krate_json: Value = serde_json::from_str(&contents)?;
|
||||
|
||||
let mut validator = validator::Validator::new(&krate, krate_json);
|
||||
validator.check_crate();
|
||||
|
||||
if let Some(json_output) = json_output {
|
||||
let output = JsonOutput { path: path.clone(), errors: validator.errs.clone() };
|
||||
let mut f = BufWriter::new(fs::File::create(json_output)?);
|
||||
serde_json::to_writer(&mut f, &output)?;
|
||||
f.flush()?;
|
||||
}
|
||||
|
||||
if !validator.errs.is_empty() {
|
||||
for err in validator.errs {
|
||||
match err.kind {
|
||||
ErrorKind::NotFound => {
|
||||
let krate_json: Value = serde_json::from_str(&contents)?;
|
||||
|
||||
let sels =
|
||||
json_find::find_selector(&krate_json, &Value::String(err.id.0.clone()));
|
||||
match &sels[..] {
|
||||
[] => unreachable!(
|
||||
"id must be in crate, or it wouldn't be reported as not found"
|
||||
),
|
||||
[sel] => eprintln!(
|
||||
"{} not in index or paths, but refered to at '{}'",
|
||||
err.id.0,
|
||||
json_find::to_jsonpath(&sel)
|
||||
),
|
||||
[sel, ..] => eprintln!(
|
||||
"{} not in index or paths, but refered to at '{}' and more",
|
||||
err.id.0,
|
||||
json_find::to_jsonpath(&sel)
|
||||
),
|
||||
ErrorKind::NotFound(sels) => match &sels[..] {
|
||||
[] => {
|
||||
unreachable!(
|
||||
"id {:?} must be in crate, or it wouldn't be reported as not found",
|
||||
err.id
|
||||
)
|
||||
}
|
||||
}
|
||||
[sel] => eprintln!(
|
||||
"{} not in index or paths, but refered to at '{}'",
|
||||
err.id.0,
|
||||
json_find::to_jsonpath(&sel)
|
||||
),
|
||||
[sel, ..] => {
|
||||
if verbose {
|
||||
let sels = sels
|
||||
.iter()
|
||||
.map(json_find::to_jsonpath)
|
||||
.map(|i| format!("'{i}'"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
eprintln!(
|
||||
"{} not in index or paths, but refered to at {sels}",
|
||||
err.id.0
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"{} not in index or paths, but refered to at '{}' and {} more",
|
||||
err.id.0,
|
||||
json_find::to_jsonpath(&sel),
|
||||
sels.len() - 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@ use rustdoc_json_types::{
|
|||
Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
|
||||
TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{item_kind::Kind, Error, ErrorKind};
|
||||
use crate::{item_kind::Kind, json_find, Error, ErrorKind};
|
||||
|
||||
/// The Validator walks over the JSON tree, and ensures it is well formed.
|
||||
/// It is made of several parts.
|
||||
|
@ -22,6 +23,7 @@ use crate::{item_kind::Kind, Error, ErrorKind};
|
|||
pub struct Validator<'a> {
|
||||
pub(crate) errs: Vec<Error>,
|
||||
krate: &'a Crate,
|
||||
krate_json: Value,
|
||||
/// Worklist of Ids to check.
|
||||
todo: HashSet<&'a Id>,
|
||||
/// Ids that have already been visited, so don't need to be checked again.
|
||||
|
@ -39,9 +41,10 @@ enum PathKind {
|
|||
}
|
||||
|
||||
impl<'a> Validator<'a> {
|
||||
pub fn new(krate: &'a Crate) -> Self {
|
||||
pub fn new(krate: &'a Crate, krate_json: Value) -> Self {
|
||||
Self {
|
||||
krate,
|
||||
krate_json,
|
||||
errs: Vec::new(),
|
||||
seen_ids: HashSet::new(),
|
||||
todo: HashSet::new(),
|
||||
|
@ -373,7 +376,11 @@ impl<'a> Validator<'a> {
|
|||
} else {
|
||||
if !self.missing_ids.contains(id) {
|
||||
self.missing_ids.insert(id);
|
||||
self.fail(id, ErrorKind::NotFound)
|
||||
|
||||
let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone()));
|
||||
assert_ne!(sels.len(), 0);
|
||||
|
||||
self.fail(id, ErrorKind::NotFound(sels))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,16 @@ use std::collections::HashMap;
|
|||
|
||||
use rustdoc_json_types::{Crate, Item, Visibility};
|
||||
|
||||
use crate::json_find::SelectorPart;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[track_caller]
|
||||
fn check(krate: &Crate, errs: &[Error]) {
|
||||
let mut validator = Validator::new(krate);
|
||||
let krate_string = serde_json::to_string(krate).unwrap();
|
||||
let krate_json = serde_json::from_str(&krate_string).unwrap();
|
||||
|
||||
let mut validator = Validator::new(krate, krate_json);
|
||||
validator.check_crate();
|
||||
|
||||
assert_eq!(errs, &validator.errs[..]);
|
||||
|
@ -46,5 +51,16 @@ fn errors_on_missing_links() {
|
|||
format_version: rustdoc_json_types::FORMAT_VERSION,
|
||||
};
|
||||
|
||||
check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]);
|
||||
check(
|
||||
&k,
|
||||
&[Error {
|
||||
kind: ErrorKind::NotFound(vec![vec![
|
||||
SelectorPart::Field("index".to_owned()),
|
||||
SelectorPart::Field("0".to_owned()),
|
||||
SelectorPart::Field("links".to_owned()),
|
||||
SelectorPart::Field("Not Found".to_owned()),
|
||||
]]),
|
||||
id: id("1"),
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue