use {
crate::core::constants::configuration,
proc_macro2::TokenStream,
quote::quote,
};
pub fn include_documentation_worker(input: TokenStream) -> Result<TokenStream, syn::Error> {
let lit: syn::LitStr = syn::parse2(input)?;
let rel_path = lit.value();
#[expect(clippy::expect_used, reason = "CARGO_MANIFEST_DIR is always set by Cargo")]
let manifest_dir =
std::env::var(configuration::CARGO_MANIFEST_DIR).expect("CARGO_MANIFEST_DIR not set");
let full_path = std::path::Path::new(&manifest_dir).join(&rel_path);
let content = std::fs::read_to_string(&full_path).map_err(|e| {
syn::Error::new_spanned(&lit, format!("failed to read {}: {e}", full_path.display()))
})?;
let rewritten = rewrite_md_links(&content);
Ok(quote!(#rewritten))
}
fn rewrite_md_links(content: &str) -> String {
let mut result = String::with_capacity(content.len());
let mut rest = content;
while let Some(open_pos) = rest.find('[') {
result.push_str(&rest[.. open_pos]);
let after_open = &rest[open_pos + 1 ..];
if let Some(close_offset) = after_open.find(']') {
let link_text = &after_open[.. close_offset];
let after_close = &after_open[close_offset + 1 ..];
if let Some(url_content) = after_close.strip_prefix('(') {
if let Some(paren_end) = url_content.find(')') {
let url = &url_content[.. paren_end];
if let Some(module_name) = md_link_to_module(url) {
result.push('[');
result.push_str(link_text);
result.push_str("][crate::docs::");
result.push_str(&module_name);
result.push(']');
rest = &url_content[paren_end + 1 ..];
continue;
}
}
}
}
result.push('[');
rest = after_open;
}
result.push_str(rest);
result
}
fn md_link_to_module(url: &str) -> Option<String> {
let stripped = url.strip_prefix("./").unwrap_or(url);
let stem = stripped.strip_suffix(".md")?;
if stem.contains('/') || stem.contains('\\') {
return None;
}
if stem.is_empty() {
return None;
}
Some(stem.replace('-', "_"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_md_link_to_module_with_dot_slash() {
assert_eq!(md_link_to_module("./zero-cost.md"), Some("zero_cost".into()));
}
#[test]
fn test_md_link_to_module_without_prefix() {
assert_eq!(md_link_to_module("hkt.md"), Some("hkt".into()));
}
#[test]
fn test_md_link_to_module_with_hyphens() {
assert_eq!(md_link_to_module("./brand-inference.md"), Some("brand_inference".into()));
}
#[test]
fn test_md_link_to_module_parent_path_ignored() {
assert_eq!(md_link_to_module("../src/foo.md"), None);
}
#[test]
fn test_md_link_to_module_subdirectory_ignored() {
assert_eq!(md_link_to_module("./sub/foo.md"), None);
}
#[test]
fn test_md_link_to_module_non_md_ignored() {
assert_eq!(md_link_to_module("./foo.rs"), None);
}
#[test]
fn test_rewrite_simple_link() {
let input = "See [Zero-Cost](./zero-cost.md) for details.";
let expected = "See [Zero-Cost][crate::docs::zero_cost] for details.";
assert_eq!(rewrite_md_links(input), expected);
}
#[test]
fn test_rewrite_multiple_links() {
let input = "See [HKT](./hkt.md) and [Dispatch](./dispatch.md).";
let expected = "See [HKT][crate::docs::hkt] and [Dispatch][crate::docs::dispatch].";
assert_eq!(rewrite_md_links(input), expected);
}
#[test]
fn test_rewrite_leaves_parent_links() {
let input = "See [source](../src/foo.rs) for details.";
assert_eq!(rewrite_md_links(input), input);
}
#[test]
fn test_rewrite_leaves_non_md_links() {
let input = "See [docs](https://example.com) for details.";
assert_eq!(rewrite_md_links(input), input);
}
#[test]
fn test_rewrite_without_dot_slash_prefix() {
let input = "See [Optics](optics-analysis.md) for details.";
let expected = "See [Optics][crate::docs::optics_analysis] for details.";
assert_eq!(rewrite_md_links(input), expected);
}
#[test]
fn test_rewrite_preserves_surrounding_text() {
let input = "prefix [A](./a.md) middle [B](./b.md) suffix";
let expected = "prefix [A][crate::docs::a] middle [B][crate::docs::b] suffix";
assert_eq!(rewrite_md_links(input), expected);
}
#[test]
fn test_rewrite_inline_link_in_bold() {
let input = "**Config:** see [Pointer Abstraction](./pointer-abstraction.md) for how.";
let expected =
"**Config:** see [Pointer Abstraction][crate::docs::pointer_abstraction] for how.";
assert_eq!(rewrite_md_links(input), expected);
}
}