use anyhow::bail;
fn is_id(s: &str) -> bool {
s.len() == 10 && s.bytes().all(|b| b.is_ascii_alphanumeric())
}
pub fn parse(s: &str) -> anyhow::Result<String> {
let s = s.trim();
if is_id(s) {
return Ok(s.to_string());
}
if let Ok(u) = url::Url::parse(s) {
let segs: Vec<&str> = u.path_segments().map(|p| p.collect()).unwrap_or_default();
for w in segs.windows(2) {
if w[0] == "d" && is_id(w[1]) {
return Ok(w[1].to_string());
}
}
}
bail!("`{s}` is not a document id or Semora URL")
}
#[cfg(test)]
mod tests {
use super::parse;
#[test]
fn parses_ids_and_urls() {
assert_eq!(parse("k3F9xQ2mLp").unwrap(), "k3F9xQ2mLp");
assert_eq!(
parse("https://semora.example.com/d/k3F9xQ2mLp/").unwrap(),
"k3F9xQ2mLp"
);
assert_eq!(
parse("https://semora.example.com/d/k3F9xQ2mLp/guide/a.md").unwrap(),
"k3F9xQ2mLp"
);
assert_eq!(
parse("wss://semora.example.com/ws/d/k3F9xQ2mLp").unwrap(),
"k3F9xQ2mLp"
);
assert!(parse("nope").is_err());
assert!(parse("https://x/d/short/").is_err());
}
}