Lines of
src/utils.rs
from check-in 997fb1cff4
that are changed by the sequence of edits moving toward
check-in 512369f93e:
1: use crate::Cursor;
2:
3: use std::{
4: borrow::Cow,
5: sync::LazyLock,
6: };
7:
8: use html_escape::encode_text;
9: use regex::{
10: Regex,
11: RegexBuilder,
12: };
13: use stacked_errors::{
14: bail,
15: Result,
16: };
17:
18: pub static RE_DOMAIN: LazyLock<Regex> = LazyLock::new(|| {
19: Regex::new(r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$").expect("Invalid domain regex")
20: });
21: pub static RE_CLOSING: LazyLock<Regex> = LazyLock::new(|| {
22: RegexBuilder::new(r"</[ \t]*(pre|code)[ \t]*>")
23: .case_insensitive(true).build().expect("Invalid closing tag regex")
24: });
25:
26: /// Stores binary attachment data and metadata for Telegram messages.
27: /// The data is wrapped in a `Cursor<Vec<u8>>` for efficient streaming,
28: /// while `name` holds the filename or display name of the attachment.
29: #[derive(Debug)]
30: pub struct Attachment {
31: pub data: Cursor<Vec<u8>>,
32: pub name: String,
33: }
34:
997fb1cff4 2026-08-01 35: /// Pass any text here to be validated as not breaking from Telegram preformatted blocks
997fb1cff4 2026-08-01 36: /// escape all HTML chars afterwards
37: pub fn validate <'a>(text: &'a str) -> Result<Cow<'a, str>> {
38: if RE_CLOSING.is_match(text) {
39: bail!("Telegram closing tag found.");
40: } else {
41: Ok(encode_text(text))
42: }
43: }