mirror of
https://github.com/AtHeartEngineer/lemmy.git
synced 2026-01-10 00:28:07 -05:00
* Special characters in markdown links (ref #5380) * fix (fixes #5380) * fix test
This commit is contained in:
@@ -1,6 +1,15 @@
|
|||||||
use super::{link_rule::Link, MARKDOWN_PARSER};
|
use super::link_rule::Link;
|
||||||
use crate::settings::SETTINGS;
|
use crate::{settings::SETTINGS, utils::markdown::link_rule};
|
||||||
use markdown_it::{plugins::cmark::inline::image::Image, NodeValue};
|
use markdown_it::{
|
||||||
|
parser::linkfmt::LinkFormatter,
|
||||||
|
plugins::cmark::{
|
||||||
|
block::fence,
|
||||||
|
inline::{image, image::Image},
|
||||||
|
},
|
||||||
|
MarkdownIt,
|
||||||
|
NodeValue,
|
||||||
|
};
|
||||||
|
use std::sync::LazyLock;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use urlencoding::encode;
|
use urlencoding::encode;
|
||||||
|
|
||||||
@@ -55,7 +64,18 @@ pub fn markdown_find_links(src: &str) -> Vec<(usize, usize)> {
|
|||||||
|
|
||||||
// Walk the syntax tree to find positions of image or link urls
|
// Walk the syntax tree to find positions of image or link urls
|
||||||
fn find_urls<T: NodeValue + UrlAndTitle>(src: &str) -> Vec<(usize, usize)> {
|
fn find_urls<T: NodeValue + UrlAndTitle>(src: &str) -> Vec<(usize, usize)> {
|
||||||
let ast = MARKDOWN_PARSER.parse(src);
|
// Use separate markdown parser here, with most features disabled for faster parsing,
|
||||||
|
// and a dummy link formatter which doesnt normalize links.
|
||||||
|
static PARSER: LazyLock<MarkdownIt> = LazyLock::new(|| {
|
||||||
|
let mut p = MarkdownIt::new();
|
||||||
|
p.link_formatter = Box::new(NoopLinkFormatter {});
|
||||||
|
image::add(&mut p);
|
||||||
|
fence::add(&mut p);
|
||||||
|
link_rule::add(&mut p);
|
||||||
|
p
|
||||||
|
});
|
||||||
|
|
||||||
|
let ast = PARSER.parse(src);
|
||||||
let mut links_offsets = vec![];
|
let mut links_offsets = vec![];
|
||||||
ast.walk(|node, _depth| {
|
ast.walk(|node, _depth| {
|
||||||
if let Some(image) = node.cast::<T>() {
|
if let Some(image) = node.cast::<T>() {
|
||||||
@@ -94,6 +114,25 @@ impl UrlAndTitle for Link {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// markdown-it normalizes links by default, which breaks the link rewriting. So we use a dummy
|
||||||
|
/// formatter here which does nothing. Note this isnt actually used to render the markdown.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NoopLinkFormatter;
|
||||||
|
|
||||||
|
impl LinkFormatter for NoopLinkFormatter {
|
||||||
|
fn validate_link(&self, _url: &str) -> Option<()> {
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_link(&self, url: &str) -> String {
|
||||||
|
url.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_link_text(&self, url: &str) -> String {
|
||||||
|
url.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
@@ -107,6 +146,12 @@ mod tests {
|
|||||||
|
|
||||||
let links = find_urls::<Image>("");
|
let links = find_urls::<Image>("");
|
||||||
assert_eq!(vec![(8, 27)], links);
|
assert_eq!(vec![(8, 27)], links);
|
||||||
|
|
||||||
|
let links = find_urls::<Image>("");
|
||||||
|
assert_eq!(vec![(22, 60)], links);
|
||||||
|
|
||||||
|
let links = find_urls::<Image>("");
|
||||||
|
assert_eq!(vec![(8, 50)], links);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -152,7 +197,12 @@ mod tests {
|
|||||||
"custom emoji support",
|
"custom emoji support",
|
||||||
r#""#,
|
r#""#,
|
||||||
r#""#
|
r#""#
|
||||||
)
|
),
|
||||||
|
(
|
||||||
|
"image with special chars",
|
||||||
|
"ითხოვს ",
|
||||||
|
"ითხოვს ",
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
tests.iter().for_each(|&(msg, input, expected)| {
|
tests.iter().for_each(|&(msg, input, expected)| {
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::utils::validation::check_urls_are_valid;
|
use crate::utils::validation::check_urls_are_valid;
|
||||||
use image_links::markdown_rewrite_image_links;
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use regex::escape;
|
use regex::escape;
|
||||||
|
|
||||||
@@ -148,63 +147,6 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_markdown_proxy_images() {
|
|
||||||
let tests: Vec<_> =
|
|
||||||
vec",
|
|
||||||
"",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"local image unproxied",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"multiple image links",
|
|
||||||
" ",
|
|
||||||
" ",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"empty link handled",
|
|
||||||
"![image]()",
|
|
||||||
"![image]()"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"empty label handled",
|
|
||||||
"",
|
|
||||||
""
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"invalid image link removed",
|
|
||||||
"",
|
|
||||||
"![image]()"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"label with nested markdown handled",
|
|
||||||
"",
|
|
||||||
""
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"custom emoji support",
|
|
||||||
r#""#,
|
|
||||||
r#""#
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
tests.iter().for_each(|&(msg, input, expected)| {
|
|
||||||
let result = markdown_rewrite_image_links(input.to_string());
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
result.0, expected,
|
|
||||||
"Testing {}, with original input '{}'",
|
|
||||||
msg, input
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// This replicates the logic when saving url blocklist patterns and querying them.
|
// This replicates the logic when saving url blocklist patterns and querying them.
|
||||||
// Refer to lemmy_api_crud::site::update::update_site and
|
// Refer to lemmy_api_crud::site::update::update_site and
|
||||||
// lemmy_api_common::utils::get_url_blocklist().
|
// lemmy_api_common::utils::get_url_blocklist().
|
||||||
|
|||||||
Reference in New Issue
Block a user