1use std::path::PathBuf;
2
3#[derive(Debug, Clone)]
4pub struct AdrMeta {
5 pub number: u32,
6 pub title: String,
7 pub status: String,
8 pub date: String,
9 pub supersedes: Option<u32>,
10 pub superseded_by: Option<u32>,
11 pub path: PathBuf,
12}
13
14pub fn slugify(s: &str) -> String {
15 let mut out = String::with_capacity(s.len());
16 let mut last_dash = false;
17 for ch in s.chars() {
18 let c = ch.to_ascii_lowercase();
19 if c.is_ascii_alphanumeric() {
20 out.push(c);
21 last_dash = false;
22 } else if (c.is_ascii_whitespace() || c == '-' || c == '_') && !last_dash {
23 out.push('-');
24 last_dash = true;
25 }
26 }
27 while out.ends_with('-') {
28 out.pop();
29 }
30 while out.starts_with('-') {
31 out.remove(0);
32 }
33 if out.is_empty() {
34 "adr".to_string()
35 } else {
36 out
37 }
38}
39
40pub fn parse_number(s: &str) -> anyhow::Result<u32> {
41 let s = s.trim();
42 let s = s.trim_start_matches('0');
43 if s.is_empty() {
44 Ok(0)
45 } else {
46 Ok(s.parse::<u32>()?)
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_slugify() {
56 assert_eq!(slugify("Hello World"), "hello-world");
57 assert_eq!(slugify(" Multiple Spaces "), "multiple-spaces");
58 assert_eq!(slugify("Caps_and-Dashes"), "caps-and-dashes");
59 assert_eq!(slugify("@#Weird!! Title??"), "weird-title");
60 assert_eq!(slugify(""), "adr");
61 assert_eq!(slugify("çåññøñ"), "adr");
63 assert_eq!(slugify(" -Hello- -World- "), "hello-world");
65 }
66
67 #[test]
68 fn test_parse_number() {
69 assert_eq!(parse_number("0003").unwrap(), 3);
70 assert_eq!(parse_number("3").unwrap(), 3);
71 assert_eq!(parse_number("0000").unwrap(), 0);
72 assert!(parse_number("abc").is_err());
73 }
74}