weaver_lib/
slugify.rs

1use unicode_normalization::UnicodeNormalization;
2
3/// Converts a heading into a CommonMark/GFM-compatible slug.
4///
5/// Example: `Intro - description` → `intro---description`
6pub fn slugify(input: &str) -> String {
7    let normalized = input.nfkd().collect::<String>().to_lowercase();
8    let mut slug = String::new();
9
10    for c in normalized.chars() {
11        if c.is_alphanumeric() {
12            slug.push(c);
13        } else if c.is_whitespace() || is_gfm_punctuation(c) {
14            slug.push('-');
15        }
16        // skip all other punctuation/symbols
17    }
18
19    // Don't strip or collapse multiple dashes
20    slug
21}
22
23/// Punctuation characters commonly mapped to '-' in GFM
24fn is_gfm_punctuation(c: char) -> bool {
25    matches!(
26        c,
27        '!' | '"'
28            | '#'
29            | '$'
30            | '%'
31            | '&'
32            | '('
33            | ')'
34            | '*'
35            | '+'
36            | ','
37            | '.'
38            | '/'
39            | ':'
40            | ';'
41            | '<'
42            | '='
43            | '>'
44            | '@'
45            | '['
46            | '\\'
47            | ']'
48            | '^'
49            | '_'
50            | '`'
51            | '{'
52            | '|'
53            | '}'
54            | '~'
55            | '-'
56    )
57}