|
1 | 1 | pub mod logging; |
| 2 | +pub mod text; |
2 | 3 | pub mod timing; |
3 | | - |
4 | | -/// Converts GitHub @mentions to markdown-backticked text to prevent notifications. |
5 | | -/// For example, "@user" becomes "`user`". |
6 | | -/// |
7 | | -/// Handles GitHub mention formats: |
8 | | -/// - Usernames (@username) |
9 | | -/// - Teams (@org/team) |
10 | | -/// - Nested teams (@org/team/subteam) |
11 | | -/// |
12 | | -/// GitHub's nested team documentation: |
13 | | -/// https://docs.github.com/en/organizations/organizing-members-into-teams/about-teams#nested-teams |
14 | | -/// |
15 | | -/// Ignores email addresses and other @ symbols that don't match GitHub mention patterns. |
16 | | -pub fn suppress_github_mentions(text: &str) -> String { |
17 | | - if text.is_empty() || !text.contains('@') { |
18 | | - return text.to_string(); |
19 | | - } |
20 | | - |
21 | | - let segment = r"[A-Za-z0-9][A-Za-z0-9\-]{0,38}"; |
22 | | - let pattern = format!(r"@{0}(?:/{0})*", segment); |
23 | | - |
24 | | - let re = regex::Regex::new(&pattern).unwrap(); |
25 | | - re.replace_all(text, |caps: ®ex::Captures| { |
26 | | - let mention = &caps[0]; |
27 | | - let position = caps.get(0).unwrap().start(); |
28 | | - |
29 | | - if !is_github_mention(text, mention, position) { |
30 | | - return mention.to_string(); |
31 | | - } |
32 | | - |
33 | | - let name = &mention[1..]; // Drop the @ symbol |
34 | | - format!("`{}`", name) |
35 | | - }) |
36 | | - .to_string() |
37 | | -} |
38 | | - |
39 | | -// Determines if a potential mention would actually trigger a notification |
40 | | -fn is_github_mention(text: &str, mention: &str, pos: usize) -> bool { |
41 | | - // Not a valid mention if preceded by alphanumeric or underscore (email) |
42 | | - if pos > 0 { |
43 | | - let c = text.chars().nth(pos - 1).unwrap(); |
44 | | - if c.is_alphanumeric() || c == '_' { |
45 | | - return false; |
46 | | - } |
47 | | - } |
48 | | - |
49 | | - // Check if followed by invalid character |
50 | | - let end = pos + mention.len(); |
51 | | - if end < text.len() { |
52 | | - let next_char = text.chars().nth(end).unwrap(); |
53 | | - if next_char.is_alphanumeric() || next_char == '_' || next_char == '-' { |
54 | | - return false; |
55 | | - } |
56 | | - } |
57 | | - |
58 | | - true |
59 | | -} |
60 | | - |
61 | | -#[cfg(test)] |
62 | | -mod tests { |
63 | | - use super::*; |
64 | | - |
65 | | - #[test] |
66 | | - fn test_suppress_github_mentions() { |
67 | | - // User mentions |
68 | | - assert_eq!(suppress_github_mentions("Hello @user"), "Hello `user`"); |
69 | | - |
70 | | - // Org team mentions |
71 | | - assert_eq!(suppress_github_mentions("@org/team"), "`org/team`"); |
72 | | - assert_eq!( |
73 | | - suppress_github_mentions("@org/team/subteam"), |
74 | | - "`org/team/subteam`" |
75 | | - ); |
76 | | - assert_eq!( |
77 | | - suppress_github_mentions("@big/team/sub/group"), |
78 | | - "`big/team/sub/group`" |
79 | | - ); |
80 | | - assert_eq!( |
81 | | - suppress_github_mentions("Thanks @user, @rust-lang/libs and @github/docs/content!"), |
82 | | - "Thanks `user`, `rust-lang/libs` and `github/docs/content`!" |
83 | | - ); |
84 | | - |
85 | | - // Non mentions |
86 | | - assert_eq!(suppress_github_mentions("@"), "@"); |
87 | | - assert_eq!(suppress_github_mentions(""), ""); |
88 | | - assert_eq!( |
89 | | - suppress_github_mentions("No mentions here"), |
90 | | - "No mentions here" |
91 | | - ); |
92 | | - assert_eq!( |
93 | | - suppress_github_mentions ("[email protected]"), |
94 | | - |
95 | | - ); |
96 | | - |
97 | | - assert_eq!(suppress_github_mentions("@user_test"), "@user_test"); |
98 | | - } |
99 | | -} |
0 commit comments