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}