1#![doc = include_str!("../README.md")]
2
3use link_aggregator::LinkTools;
4pub use transform::*;
5
6use pulldown_cmark::{BrokenLink, CowStr, Event, Options, Parser};
7
8use crate::aggregation::Aggregation;
9
10pub mod aggregation;
11pub mod link;
12pub mod link_aggregator;
13mod transform;
14
15pub fn broken_link_callback_with_replacers<'a>(
16 replacers: Vec<Box<dyn LinkTransformer>>,
17) -> impl Fn(BrokenLink<'a>) -> Option<(CowStr<'a>, CowStr<'a>)> {
18 move |link: BrokenLink<'a>| {
19 for replacer in &replacers {
20 if replacer.pattern().is_match(&link.reference) {
21 let mut link = link::Link {
22 link_type: link.link_type,
23 destination: link.reference,
24 title: "".into(),
25 text: vec![],
26 };
27 replacer.apply(&mut link).unwrap();
28 return Some((link.destination, link.title));
29 }
30 }
31 None
32 }
33}
34
35pub fn process_broken_links<'a>(
36 input: &'a str,
37 replacers: Vec<Box<dyn LinkTransformer>>,
38 cb: &'a mut impl Fn(BrokenLink<'a>) -> Option<(CowStr<'a>, CowStr<'a>)>,
39) -> impl Iterator<Item = Event<'a>> {
40 let parser = Parser::new_with_broken_link_callback(input, Options::empty(), Some(cb));
42
43 parser.aggregate_links().flat_map(move |mut aggregation| {
45 let Aggregation::Link(ref mut link) = aggregation else {
47 return aggregation;
48 };
49 let Some(Event::Text(first)) = link.text.get_mut(0) else {
51 return aggregation;
52 };
53 for replacer in &replacers {
55 if replacer.strip_tag() {
58 if first.starts_with(&replacer.tag()) {
59 let new_text = first.replace(&replacer.tag(), "");
60 *first = new_text.into();
61 return Aggregation::Link(link.clone());
62 }
63 }
64 }
65 aggregation
66 })
67}
68
69pub fn process_links<'a>(
70 input: impl Iterator<Item = Event<'a>>,
71 replacers: &'a [Box<dyn LinkTransformer>],
72) -> impl Iterator<Item = Event<'a>> {
73 input
74 .aggregate_links()
75 .flat_map(move |aggregation| {
76 let Aggregation::Link(mut link) = aggregation else {
77 return anyhow::Ok(aggregation);
78 };
79 for replacement in replacers {
80 if replacement.pattern().is_match(&link.destination) {
81 replacement.apply(&mut link)?;
82 break;
83 }
84 }
85 Ok(Aggregation::Link(link))
86 })
87 .flatten()
88}