diff --git a/Cargo.lock b/Cargo.lock index 463a69efc9..bdd09ff7c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -741,6 +741,7 @@ dependencies = [ "open", "pretty_assertions", "pulldown-cmark", + "pulldown-cmark-to-cmark", "regex", "select", "serde", @@ -1073,6 +1074,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "pulldown-cmark-to-cmark" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32accf4473121d8c0b508ca5673363703762d6cc59cf25af1df48f653346f736" +dependencies = [ + "pulldown-cmark", +] + [[package]] name = "quick-error" version = "1.2.3" diff --git a/Cargo.toml b/Cargo.toml index a943e7361d..388b221b49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ log = "0.4" memchr = "2.0" open = "1.1" pulldown-cmark = "0.7.0" +pulldown-cmark-to-cmark = "5.0.0" regex = "1.0.0" serde = "1.0" serde_derive = "1.0" diff --git a/src/preprocess/index.rs b/src/preprocess/index.rs index fd60ad4dae..2c30acc0be 100644 --- a/src/preprocess/index.rs +++ b/src/preprocess/index.rs @@ -1,3 +1,6 @@ +use core::ops::Range; +use pulldown_cmark::{Event, LinkType, Parser, Tag}; +use pulldown_cmark_to_cmark::cmark; use regex::Regex; use std::path::Path; @@ -39,6 +42,7 @@ impl Preprocessor for IndexPreprocessor { path.set_file_name("index.md"); } } + ch.content = replace_readme_in_string(&ch.content); } }); @@ -46,6 +50,65 @@ impl Preprocessor for IndexPreprocessor { } } +fn replace_readme_in_string(content: &str) -> String { + lazy_static! { + static ref RE: Regex = Regex::new( + r"(?ix) #ignorecase, allow regex definition eXtended on multiple lines + (/readme.md) #part that will be replaced by index.md + " + ) + .unwrap(); + } + let parser = pulldown_cmark::Parser::new(content); + let mut buf = String::with_capacity(content.len()); + + let mut events = vec![]; + for event in parser { + events.push(match event { + Event::Start(Tag::Link(link_type, dest, title)) => Event::Start(Tag::Link( + link_type, + pulldown_cmark::CowStr::from(RE.replace_all(&dest, "/index.md").into_owned()), + title, + )), + Event::End(Tag::Link(link_type, dest, title)) => Event::End(Tag::Link( + link_type, + pulldown_cmark::CowStr::from(RE.replace_all(&dest, "/index.md").into_owned()), + title, + )), + // Event::FootnoteReference(text) => Event::FootnoteReference( + // pulldown_cmark::CowStr::from(RE.replace_all(&text, "/index.md").into_owned()), + // ), + // Event::End(Tag::Link(link_type, dest, title)) => Event::End(Tag::Link( + // link_type, + // pulldown_cmark::CowStr::from(dbg!(RE.replace_all(&dest, "/index.md").into_owned())), + // title, + // )), + // pulldown_cmark::Event::Text(text) + // if (text.chars().nth(0).unwrap() == Char::from(":")) => + // { + // pulldown_cmark::Event::Text(pulldown_cmark::CowStr::from(dbg!(RE + // .replace_all(&text, "/index.md") + // .into_owned()))) + // }, + v => dbg!(v), + }); + } + + // dbg!( + // match + cmark(events.iter(), &mut buf, None).unwrap() // .map(|_| buf) + // { + // Ok(_) => , + // Err(_) => content.to_string(), + // } + // ) + ; + buf + + // //TODO : change + // content.to_string() +} + fn warn_readme_name_conflict>(readme_path: P, index_path: P) { let file_name = readme_path.as_ref().file_name().unwrap_or_default(); let parent_dir = index_path @@ -102,4 +165,73 @@ mod tests { let path = "path/to/README-README.md"; assert!(!is_readme_file(path)); } + + #[test] + fn do_not_replace_readme_in_normal_string_test() { + let expected = "content: ( index.md)"; + + let content = "content: ( Readme.md )"; + assert_ne!(expected, replace_readme_in_string(content)); + + let content = "content: ( README.md )"; + assert_ne!(expected, replace_readme_in_string(content)); + + let content = "content: ( rEaDmE.md )"; + assert_ne!(expected, replace_readme_in_string(content)); + + let content = "content: ( README-README.md )"; + assert_ne!(expected, replace_readme_in_string(content)); + } + + //inspired by https://stackoverflow.com/questions/34662713/how-can-i-create-parameterized-tests-in-rust + macro_rules! replace_readme_tests { + ($expected:expr,$($name:ident: $value:expr,)*) => { + $( + #[test] + fn $name() { + let expected = $expected; + let content= $value; + assert_eq!(expected, replace_readme_in_string(content)); + } + )* + } + } + + replace_readme_tests! { + "[content](./bla/index.md) content: ( ./readme.md)", + replace_readme_only_in_link_cases_1:"[content](./bla/readme.md) content: ( ./readme.md)", + replace_readme_only_in_link_cases_2:"[content](./bla/rEaDme.md) content: ( ./readme.md)", + replace_readme_only_in_link_cases_3:"[content](./bla/README.MD) content: ( ./readme.md)", + replace_readme_only_in_link_cases_4:"[content](./bla/reAdme.md) content: ( ./readme.md)", + replace_readme_only_in_link_cases_5:"[content](./bla/Readme.md) content: ( ./readme.md)", + replace_readme_only_in_link_cases_6:"[content](./bla/README.md) content: ( ./readme.md)", + replace_readme_only_in_link_cases_7:"[content](./bla/readme.MD) content: ( ./readme.md)", + } + replace_readme_tests! { + "🤞🏼[content](./bla/index.md)🤞🏼\n[content]: ./index.md", + replace_readme_only_in_link_cases_even_with_multibyte_chars:"🤞🏼[content](./bla/readme.md)🤞🏼\n[content]: ./README.MD", + } + + replace_readme_tests! { + "[content]: ./bla/index.md ", + replace_readme_in_reference_link_test_1:"[content]: ./bla/readme.md ", + replace_readme_in_reference_link_test_2:"[content]: ./bla/ReAdme.md ", + replace_readme_in_reference_link_test_3:"[content]: ./bla/ReaDme.md ", + replace_readme_in_reference_link_test_4:"[content]: ./bla/README.MD ", + replace_readme_in_reference_link_test_5:"[content]: ./bla/REadmE.md ", + replace_readme_in_reference_link_test_6:"[content]: ./bla/ReAdme.md ", + replace_readme_in_reference_link_test_7:"[content]: ./bla/Readme.MD ", + replace_readme_in_reference_link_test_8:"[content]: ./bla/readme.MD ", + } + replace_readme_tests! { + "[content](./bla/index.md)", + replace_readme_in_inline_link_test_1:"[content]( ./bla/readme.md)", + replace_readme_in_inline_link_test_2:"[content]( ./bla/ReAdme.md)", + replace_readme_in_inline_link_test_3:"[content]( ./bla/ReaDme.md)", + replace_readme_in_inline_link_test_4:"[content]( ./bla/README.MD)", + replace_readme_in_inline_link_test_5:"[content]( ./bla/REadmE.md)", + replace_readme_in_inline_link_test_6:"[content]( ./bla/ReAdme.md)", + replace_readme_in_inline_link_test_7:"[content]( ./bla/Readme.MD)", + replace_readme_in_inline_link_test_8:"[content]( ./bla/readme.MD)", + } }