Lines of
src/utils.rs
from check-in 6ce625a569
that are changed by the sequence of edits moving toward
check-in 85fa6bddaa:
1: use crate::Cursor;
2:
3: use lazy_static::lazy_static;
4: use regex::Regex;
6ce625a569 2026-01-12 5: use scraper::Html;
6: use stacked_errors::{
7: bail,
8: Result,
9: };
10:
11: lazy_static! {
12: pub static ref RE_DOMAIN: Regex = Regex::new(r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$").unwrap();
13: }
14:
15: /// `Attachment` object to store number attachment data and corresponding file name
16: #[derive(Debug)]
17: pub struct Attachment {
18: pub data: Cursor<Vec<u8>>,
19: pub name: String,
20: }
21:
6ce625a569 2026-01-12 22: /// Pass any text here to be validated as HTML, breaks on validation errors
dafeec0481 2026-01-18 23: pub fn validate (text: &str) -> Result<&str> {
6ce625a569 2026-01-12 24: // Technically full validation is not needed nor required here, all text after validation
6ce625a569 2026-01-12 25: // is used in Telegram messages as RAW text enclosed in `pre`/`code` tags, so the only reason
6ce625a569 2026-01-12 26: // for this check is to make sure there's no dangling closing tags in the text that might
6ce625a569 2026-01-12 27: // break Telegram message formatting
6ce625a569 2026-01-12 28: let fragment = Html::parse_fragment(text);
6ce625a569 2026-01-12 29: if !fragment.errors.is_empty() {
6ce625a569 2026-01-12 30: bail!(fragment.errors.join("\n"));
dafeec0481 2026-01-18 31: }
6ce625a569 2026-01-12 32: Ok(text)
33: }