pub fn parse_argument_comment(text: &str) -> Option<&str> { let trimmed = text.trim_end(); let comment_start = trimmed.rfind("/*")?; let comment = &trimmed[comment_start..]; let name = comment.strip_prefix("/*")?.strip_suffix("*/")?; is_identifier(name).then_some(name) } pub fn parse_argument_comment_prefix(text: &str) -> Option<&str> { let trimmed = text.trim_start(); let comment = trimmed.strip_prefix("/*")?; let (name, _) = comment.split_once("*/")?; is_identifier(name).then_some(name) } fn is_identifier(text: &str) -> bool { let mut chars = text.chars(); let Some(first) = chars.next() else { return false; }; if !(first == '_' || first.is_ascii_alphabetic()) { return false; } chars.all(|ch| ch == '_' || ch.is_ascii_alphanumeric()) } #[cfg(test)] mod tests { use super::parse_argument_comment; use super::parse_argument_comment_prefix; #[test] fn parses_trailing_comment() { assert_eq!(parse_argument_comment("(/*base_url*/ "), Some("base_url")); assert_eq!( parse_argument_comment(", /*timeout_ms*/ "), Some("timeout_ms") ); assert_eq!( parse_argument_comment(".method::(/*base_url*/ "), Some("base_url") ); } #[test] fn rejects_non_matching_shapes() { assert_eq!(parse_argument_comment("(\n"), None); assert_eq!(parse_argument_comment("(/* base_url*/ "), None); assert_eq!(parse_argument_comment("(/*base_url */ "), None); assert_eq!(parse_argument_comment("(/*base_url=*/ "), None); assert_eq!(parse_argument_comment("(/*1base_url*/ "), None); assert_eq!(parse_argument_comment_prefix("/*env=*/ None"), None); } #[test] fn parses_prefix_comment() { assert_eq!(parse_argument_comment_prefix("/*env*/ None"), Some("env")); assert_eq!( parse_argument_comment_prefix("\n /*retry_count*/ 3"), Some("retry_count") ); } }