diff --git a/crates/ruff_dev/src/generate_docs.rs b/crates/ruff_dev/src/generate_docs.rs index 2c3f24975a2a8..987b485db94cc 100644 --- a/crates/ruff_dev/src/generate_docs.rs +++ b/crates/ruff_dev/src/generate_docs.rs @@ -1,6 +1,7 @@ //! Generate Markdown documentation for applicable rules. #![allow(clippy::print_stdout, clippy::print_stderr)] +use std::collections::HashSet; use std::fs; use std::path::PathBuf; @@ -97,20 +98,22 @@ pub(crate) fn main(args: &Args) -> Result<()> { fn process_documentation(documentation: &str, out: &mut String, rule_name: &str) { let mut in_options = false; let mut after = String::new(); + let mut referenced_options = HashSet::new(); // HACK: This is an ugly regex hack that's necessary because mkdocs uses // a non-CommonMark-compliant Markdown parser, which doesn't support code // tags in link definitions // (see https://github.com/Python-Markdown/markdown/issues/280). - let documentation = Regex::new(r"\[`([^`]*?)`]($|[^\[\(])") - .unwrap() - .replace_all(documentation, |caps: &Captures| { + let documentation = Regex::new(r"\[`([^`]*?)`]($|[^\[(])").unwrap().replace_all( + documentation, + |caps: &Captures| { format!( "[`{option}`][{option}]{sep}", option = &caps[1], sep = &caps[2] ) - }); + }, + ); for line in documentation.split_inclusive('\n') { if line.starts_with("## ") { @@ -134,6 +137,7 @@ fn process_documentation(documentation: &str, out: &mut String, rule_name: &str) let anchor = option.replace('.', "_"); out.push_str(&format!("- [`{option}`][{option}]\n")); after.push_str(&format!("[{option}]: ../settings.md#{anchor}\n")); + referenced_options.insert(option); continue; } @@ -141,6 +145,20 @@ fn process_documentation(documentation: &str, out: &mut String, rule_name: &str) out.push_str(line); } + + let re = Regex::new(r"\[`([^`]*?)`]\[(.*?)]").unwrap(); + for (_, [option, _]) in re.captures_iter(&documentation).map(|c| c.extract()) { + if let Some(OptionEntry::Field(field)) = Options::metadata().find(option) { + if referenced_options.insert(option) { + let anchor = option.replace('.', "_"); + after.push_str(&format!("[{option}]: ../settings.md#{anchor}\n")); + } + if field.deprecated.is_some() { + eprintln!("Rule {rule_name} references deprecated option {option}."); + } + } + } + if !after.is_empty() { out.push('\n'); out.push('\n');