Fix option links in mkdocs rule pages

In 28c9263722 I introduced automatic
linkification of option references in rule documentation,
which automatically converted the following:

    ## Options

    * `namespace-packages`

to:

    ## Options

    * [`namespace-packages`]

    [`namespace-packages`]: ../../settings#namespace-packages

While the above is a correct CommonMark[1] link definition,
what I was missing was that we used mkdocs for our documentation
generation, which as it turns out uses a non-CommonMark-compliant
Markdown parser, namely Python-Markdown, which contrary to CommonMark
doesn't support link definitions containing code tags.

This commit fixes the broken links via a regex hack.

[1]: https://commonmark.org/
This commit is contained in:
Martin Fischer 2023-02-14 08:16:31 +01:00 committed by Charlie Marsh
parent 860993187e
commit a77b4566e4
3 changed files with 56 additions and 2 deletions

View file

@ -10,6 +10,7 @@ clap = { workspace = true }
itertools = { workspace = true }
libcst = { workspace = true }
once_cell = { workspace = true }
regex.workspace = true
ruff = { path = "../ruff" }
ruff_cli = { path = "../ruff_cli" }
rustpython-common = { workspace = true }

View file

@ -4,6 +4,7 @@
use std::fs;
use anyhow::Result;
use regex::{Captures, Regex};
use ruff::registry::{Linter, Rule, RuleNamespace};
use ruff::settings::options::Options;
use ruff::settings::options_base::ConfigurationOptions;
@ -56,6 +57,21 @@ fn process_documentation(documentation: &str, out: &mut String) {
let mut in_options = false;
let mut after = String::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| {
format!(
"[`{option}`][{option}]{sep}",
option = &caps[1],
sep = &caps[2]
)
},
);
for line in documentation.split_inclusive('\n') {
if line.starts_with("## ") {
in_options = line == "## Options\n";
@ -69,8 +85,8 @@ fn process_documentation(documentation: &str, out: &mut String) {
);
let anchor = option.rsplit('.').next().unwrap();
out.push_str(&format!("* [`{option}`]\n"));
after.push_str(&format!("[`{option}`]: ../../settings#{anchor}"));
out.push_str(&format!("* [`{option}`][{option}]\n"));
after.push_str(&format!("[{option}]: ../../settings#{anchor}"));
continue;
}
@ -83,3 +99,39 @@ fn process_documentation(documentation: &str, out: &mut String) {
out.push_str(&after);
}
}
#[cfg(test)]
mod tests {
use super::process_documentation;
#[test]
fn test_process_documentation() {
let mut out = String::new();
process_documentation(
"
See also [`mccabe.max-complexity`].
Something [`else`][other].
## Options
* `mccabe.max-complexity`
[other]: http://example.com.",
&mut out,
);
assert_eq!(
out,
"
See also [`mccabe.max-complexity`][mccabe.max-complexity].
Something [`else`][other].
## Options
* [`mccabe.max-complexity`][mccabe.max-complexity]
[other]: http://example.com.
[mccabe.max-complexity]: ../../settings#max-complexity"
);
}
}