cargo_docs_md/error.rs
1//! Error types for docs-md.
2//!
3//! This module defines all errors that can occur during documentation generation.
4//! Errors use the `miette` crate for enhanced diagnostics, providing:
5//! - Human-readable error messages
6//! - Diagnostic codes for programmatic handling
7//! - Helpful suggestions for resolution
8//!
9//! # Error Categories
10//!
11//! - **I/O Errors** (`FileRead`, `CreateDir`, `FileWrite`): File system operations
12//! - **Parse Errors** (`JsonParse`): Invalid or malformed rustdoc JSON
13//! - **Lookup Errors** (`ItemNotFound`): Missing items in the documentation index
14
15use std::io as StdIO;
16use std::path::PathBuf;
17
18use miette::Diagnostic;
19use serde_json as SJSON;
20use thiserror::Error as ThisError;
21
22/// Errors that can occur during documentation generation.
23///
24/// Each variant includes:
25/// - A human-readable error message
26/// - A diagnostic code (e.g., `docs_md::io::read`)
27/// - Optional help text for resolution
28/// - The underlying source error (where applicable)
29#[derive(Debug, Diagnostic, ThisError)]
30pub enum Error {
31 /// Failed to read a file from disk.
32 ///
33 /// This typically occurs when:
34 /// - The file doesn't exist
35 /// - The process lacks read permissions
36 /// - The path is invalid
37 #[error("Failed to read file")]
38 #[diagnostic(
39 code(docs_md::io::read),
40 help("Check that the file exists and is readable")
41 )]
42 FileRead(#[source] StdIO::Error),
43
44 /// Failed to parse the rustdoc JSON file.
45 ///
46 /// This can happen when:
47 /// - The file is not valid JSON
48 /// - The JSON schema doesn't match `rustdoc-types` expectations
49 /// - The file is from an incompatible rustdoc version
50 #[error("Failed to parse rustdoc JSON")]
51 #[diagnostic(
52 code(docs_md::parse::json),
53 help("Ensure the file is valid rustdoc JSON output (generated with --output-format json)")
54 )]
55 JsonParse(#[source] SJSON::Error),
56
57 /// Failed to parse the rustdoc JSON file using SIMD-accelerated parser.
58 ///
59 /// This variant is used when the `simd-json` feature is enabled.
60 #[cfg(feature = "simd-json")]
61 #[error("Failed to parse rustdoc JSON (simd-json)")]
62 #[diagnostic(
63 code(docs_md::parse::simd_json),
64 help("Ensure the file is valid rustdoc JSON output (generated with --output-format json)")
65 )]
66 SimdJsonParse(#[source] simd_json::Error),
67
68 /// Failed to create the output directory.
69 ///
70 /// This typically occurs when:
71 /// - The parent directory doesn't exist
72 /// - The process lacks write permissions
73 /// - The path is invalid or too long
74 #[error("Failed to create output directory")]
75 #[diagnostic(code(docs_md::io::mkdir))]
76 CreateDir(#[source] StdIO::Error),
77
78 /// Failed to write a markdown file.
79 ///
80 /// This typically occurs when:
81 /// - The output directory is not writable
82 /// - The disk is full
83 /// - The file is locked by another process
84 #[error("Failed to write file")]
85 #[diagnostic(code(docs_md::io::write))]
86 FileWrite(#[source] StdIO::Error),
87
88 /// An item ID was not found in the crate's index.
89 ///
90 /// The rustdoc JSON index should contain all referenced items.
91 /// This error indicates data inconsistency, possibly from:
92 /// - Corrupted JSON
93 /// - Incompatible rustdoc-types version
94 /// - Items removed during filtering
95 ///
96 /// The string contains the ID that was not found.
97 #[error("Item not found in index: {0}")]
98 #[diagnostic(code(docs_md::parse::item_not_found))]
99 ItemNotFound(String),
100
101 // ========== Multi-crate errors ==========
102 /// The specified directory path is invalid or inaccessible.
103 ///
104 /// This typically occurs when:
105 /// - The path doesn't exist
106 /// - The path is a file, not a directory
107 /// - The process lacks read permissions
108 #[error("Invalid directory: {0}")]
109 #[diagnostic(
110 code(docs_md::io::dir),
111 help("Check that the directory exists and is readable")
112 )]
113 InvalidDirectory(String),
114
115 /// No rustdoc JSON files were found in the specified directory.
116 ///
117 /// The directory should contain `.json` files generated by rustdoc
118 /// with the `--output-format json` flag.
119 #[error("No rustdoc JSON files found in directory: {0}")]
120 #[diagnostic(
121 code(docs_md::parse::no_json),
122 help(
123 "Run `RUSTDOCFLAGS='-Z unstable-options --output-format json' cargo +nightly doc` to generate JSON files"
124 )
125 )]
126 NoJsonFiles(PathBuf),
127
128 /// Multiple crates with the same name were found.
129 ///
130 /// Each JSON file should represent a unique crate. This error
131 /// indicates duplicate crate names in the input directory.
132 #[error("Duplicate crate name: {0}")]
133 #[diagnostic(
134 code(docs_md::parse::duplicate_crate),
135 help("Remove duplicate JSON files or rename crates")
136 )]
137 DuplicateCrate(String),
138
139 /// Could not determine the crate name from a JSON file.
140 ///
141 /// The rustdoc JSON format should include a root item with
142 /// the crate name. This error indicates a malformed file.
143 #[error("Could not determine crate name from JSON file: {0}")]
144 #[diagnostic(
145 code(docs_md::parse::no_crate_name),
146 help("Ensure the file is valid rustdoc JSON with a root module item")
147 )]
148 NoCrateName(PathBuf),
149
150 /// Failed to create a progress bar with the given template.
151 ///
152 /// This indicates an invalid progress bar template string.
153 /// Since templates are compile-time constants, this error
154 /// typically indicates a programming error.
155 #[error("Invalid progress bar template")]
156 #[diagnostic(
157 code(docs_md::ui::progress_template),
158 help("Check the progress bar template syntax")
159 )]
160 ProgressBarTemplate(#[source] indicatif::style::TemplateError),
161
162 // ========== Source parsing errors (source-parsing feature) ==========
163 /// Failed to locate crate source in the Cargo registry.
164 ///
165 /// This occurs when:
166 /// - The crate is not downloaded in ~/.cargo/registry/src/
167 /// - The specified version doesn't exist
168 /// - The registry path is misconfigured
169 #[cfg(feature = "source-parsing")]
170 #[error("Source locator error: {0}")]
171 #[diagnostic(
172 code(docs_md::source::locator),
173 help("Ensure the crate is a dependency and has been downloaded (cargo fetch)")
174 )]
175 SourceLocator(String),
176
177 /// Failed to parse Rust source code with syn.
178 ///
179 /// This occurs when:
180 /// - The source file contains invalid Rust syntax
181 /// - The file cannot be read
182 /// - Module resolution fails
183 #[cfg(feature = "source-parsing")]
184 #[error("Source parser error: {0}")]
185 #[diagnostic(
186 code(docs_md::source::parser),
187 help("Check that the source files contain valid Rust code")
188 )]
189 SourceParser(String),
190
191 /// Failed to collect dependency sources.
192 ///
193 /// This occurs when:
194 /// - Cargo metadata cannot be loaded
195 /// - The registry path doesn't exist
196 /// - File copy operations fail
197 /// - Too many .source_* directories exist
198 #[cfg(feature = "source-parsing")]
199 #[error("Source collector error: {0}")]
200 #[diagnostic(
201 code(docs_md::source::collector),
202 help("Ensure cargo metadata is available and ~/.cargo/registry/src/ exists")
203 )]
204 SourceCollector(String),
205}