-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: restrict elements that can appear inside of a label for a labled…
… link (#74) * fix: restrict elements that can appear inside of a label for a labled link * cargo fmt * add test for the codeblock bug * Apply suggestions from code review Co-authored-by: Farooq Karimi Zadeh <[email protected]> * clarify the confusing comment * fix broken documentation reference --------- Co-authored-by: Farooq Karimi Zadeh <[email protected]>
- Loading branch information
1 parent
19b18d1
commit 967dca4
Showing
7 changed files
with
278 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
src/parser/parse_from_text/markdown_elements/label_elements.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
use nom::{ | ||
bytes::complete::take, | ||
combinator::{peek, recognize}, | ||
IResult, | ||
}; | ||
|
||
use crate::parser::{ | ||
parse_from_text::{ | ||
base_parsers::{direct_delimited, CustomError}, | ||
markdown_elements::inline_code, | ||
}, | ||
Element, | ||
}; | ||
|
||
/// Parsers for label in labelled links and later also labeled hashtags | ||
/// parse elements inside of label in markdown set | ||
pub(crate) fn parse_label_elements(input: &str) -> Vec<Element> { | ||
let mut result = Vec::new(); | ||
let mut remaining = input; | ||
// println!("p-{}", input); | ||
while !remaining.is_empty() { | ||
// println!("r-{}", remaining); | ||
if let Ok((rest, element)) = parse_markdown_label_element(remaining) { | ||
// println!("e-{:?} - {}", element, remaining); | ||
remaining = rest; | ||
result.push(element); | ||
} else if let Ok((rest, element)) = markdown_label_text(remaining) { | ||
// println!("e-{:?} - {}", element, remaining); | ||
result.push(element); | ||
remaining = rest; | ||
} else { | ||
// println!("e-textDefault-{}", remaining); | ||
result.push(Element::Text(remaining)); | ||
break; | ||
} | ||
} | ||
result | ||
} | ||
|
||
pub(crate) fn parse_markdown_label_element( | ||
input: &str, | ||
) -> IResult<&str, Element, CustomError<&str>> { | ||
// the order is important | ||
// generaly more specific parsers that fail/return fast should be in the front | ||
// But keep in mind that the order can also change how and if the parser works as intended | ||
if let Ok((i, b)) = direct_delimited(input, "**") { | ||
Ok((i, Element::Bold(parse_label_elements(b)))) | ||
} else if let Ok((i, b)) = direct_delimited(input, "__") { | ||
Ok((i, Element::Bold(parse_label_elements(b)))) | ||
} else if let Ok((i, b)) = direct_delimited(input, "_") { | ||
Ok((i, Element::Italics(parse_label_elements(b)))) | ||
} else if let Ok((i, b)) = direct_delimited(input, "*") { | ||
Ok((i, Element::Italics(parse_label_elements(b)))) | ||
} else if let Ok((i, b)) = direct_delimited(input, "~~") { | ||
Ok((i, Element::StrikeThrough(parse_label_elements(b)))) | ||
} else if let Ok((i, b)) = inline_code(input) { | ||
Ok((i, Element::InlineCode { content: b })) | ||
} else { | ||
Err(nom::Err::Error(CustomError::NoElement)) | ||
} | ||
} | ||
/// consumes all text until [parse_label_elements] works again, this method is only for internal use by [markdown_label_text] | ||
/// | ||
/// its output is not useable on its own, always combinate this with [nom::combinator::recognize] | ||
fn eat_markdown_label_text(input: &str) -> IResult<&str, (), CustomError<&str>> { | ||
let mut remaining = input; | ||
while !remaining.is_empty() { | ||
// take 1, because other parsers didn't work (text is always the last used parser) | ||
let (remainder, _taken) = take(1usize)(remaining)?; | ||
remaining = remainder; | ||
// peek if there is an element | ||
if peek(|input| parse_markdown_label_element(input))(remaining).is_ok() { | ||
break; | ||
} | ||
// take until whitespace | ||
//remaining = take_while(|c| not_blank_space(c))(remaining)?.0; | ||
} | ||
Ok((remaining, ())) | ||
} | ||
|
||
/// Consumes text until another parser of [parse_markdown_label_element] works again | ||
/// | ||
/// used as last parser, if the others do not consume the input it consumes the input until another parser works again | ||
/// (uses whitespace seperation to make the parsing faster) | ||
fn markdown_label_text(input: &str) -> IResult<&str, Element, CustomError<&str>> { | ||
let (rest, content) = recognize(eat_markdown_label_text)(input)?; | ||
Ok((rest, Element::Text(content))) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -762,3 +762,101 @@ fn labeled_link_can_have_comma_or_dot_at_end() { | |
] | ||
); | ||
} | ||
|
||
#[test] | ||
fn labeled_link_should_not_allow_link_element() { | ||
assert_eq!( | ||
parse_markdown_text( | ||
"you can find the details [here https://delta.chat](https://delta.chat/en/help)." | ||
), | ||
vec![ | ||
Text("you can find the details "), | ||
LabeledLink { | ||
label: vec![Text("here https://delta.chat")], | ||
destination: https_link_no_puny("https://delta.chat/en/help", "delta.chat"), | ||
}, | ||
Text(".") | ||
] | ||
); | ||
} | ||
|
||
#[test] | ||
fn labeled_link_should_not_allow_hashtag_element() { | ||
assert_eq!( | ||
parse_markdown_text("you can find the details [here #42](https://delta.chat/en/help)."), | ||
vec![ | ||
Text("you can find the details "), | ||
LabeledLink { | ||
label: vec![Text("here #42")], | ||
destination: https_link_no_puny("https://delta.chat/en/help", "delta.chat"), | ||
}, | ||
Text(".") | ||
] | ||
); | ||
} | ||
|
||
#[test] | ||
fn labeled_link_should_not_allow_email() { | ||
assert_eq!( | ||
parse_markdown_text( | ||
"you can find the details [here [email protected]](https://delta.chat/en/help)." | ||
), | ||
vec![ | ||
Text("you can find the details "), | ||
LabeledLink { | ||
label: vec![Text("here [email protected]")], | ||
destination: https_link_no_puny("https://delta.chat/en/help", "delta.chat"), | ||
}, | ||
Text(".") | ||
] | ||
); | ||
} | ||
|
||
#[test] | ||
fn labeled_link_should_allow_bold() { | ||
assert_eq!( | ||
parse_markdown_text( | ||
"you can find the details [here **bold**](https://delta.chat/en/help)." | ||
), | ||
vec![ | ||
Text("you can find the details "), | ||
LabeledLink { | ||
label: vec![Text("here "), Bold(vec![Text("bold")])], | ||
destination: https_link_no_puny("https://delta.chat/en/help", "delta.chat"), | ||
}, | ||
Text(".") | ||
] | ||
); | ||
} | ||
|
||
#[test] | ||
fn labeled_link_should_not_allow_email_in_bold() { | ||
assert_ne!( | ||
parse_markdown_text( | ||
"you can find the details [here **[email protected]**](https://delta.chat/en/help)." | ||
), | ||
vec![ | ||
Text("you can find the details"), | ||
Bold(vec![Text("[email protected]")]), | ||
LabeledLink { | ||
label: vec![Text("here [email protected]")], | ||
destination: https_link_no_puny("https://delta.chat/en/help", "delta.chat"), | ||
}, | ||
Text(".") | ||
] | ||
); | ||
} | ||
|
||
#[test] | ||
fn labeled_link_should_not_allow_codeblock() { | ||
assert_ne!( | ||
parse_markdown_text("[```\nhello world\n```](https://delta.chat)"), | ||
vec![ | ||
LabeledLink { | ||
label: vec![Text("```\nhello world\n```")], | ||
destination: https_link_no_puny("https://delta.chat/en/help", "delta.chat"), | ||
}, | ||
Text(".") | ||
] | ||
); | ||
} |