use crate::parse_utils;
use std::collections::HashSet;
pub fn extract_http_methods(code: &str) -> HashSet<String> {
let mut methods = HashSet::new();
let http_methods = ["get", "post", "put", "delete", "patch", "options", "head"];
let mut pos = 0;
while let Some(route_pos) = code[pos..].find(".route(") {
let abs_pos = pos + route_pos;
if let Some((route_args, _, close_pos)) =
parse_utils::extract_parenthesized_content(code, abs_pos)
{
if let Some(first_method) = find_first_method_in_chain(&route_args, &http_methods) {
methods.insert(first_method);
}
pos = close_pos + 1;
} else {
break;
}
}
methods
}
fn find_first_method_in_chain(content: &str, http_methods: &[&str]) -> Option<String> {
let comma_pos = content.find(',')?;
let handler_part = &content[comma_pos + 1..];
let mut min_pos = handler_part.len();
let mut found_method = None;
for method in http_methods {
let pattern = format!("{}(", method);
let mut search_pos = 0;
while let Some(pos) = handler_part[search_pos..].find(&pattern) {
let abs_pos = search_pos + pos;
let is_first_in_chain = abs_pos == 0 || {
let prev_chars = &handler_part[..abs_pos].trim_end();
!prev_chars.ends_with('.')
};
if is_first_in_chain && abs_pos < min_pos {
min_pos = abs_pos;
found_method = Some(method.to_string());
}
search_pos = abs_pos + 1;
}
}
found_method
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_single_method() {
let code = r#"router = router.route("/", get(get::handler));"#;
let methods = extract_http_methods(code);
assert!(methods.contains("get"));
assert_eq!(methods.len(), 1);
}
#[test]
fn test_extract_chained_methods_only_first() {
let code = r#"router = router.route("/", get(get::handler).post(post::handler));"#;
let methods = extract_http_methods(code);
assert!(methods.contains("get"));
assert!(!methods.contains("post")); assert_eq!(methods.len(), 1);
}
#[test]
fn test_extract_multiple_routes_different_first_methods() {
let code = r#"
router = router.route("/", get(get::handler).post(post::handler));
router = router.route("/api", put(put::handler).delete(delete::handler));
router = router.route("/patch", patch(patch::handler));
"#;
let methods = extract_http_methods(code);
assert!(methods.contains("get"));
assert!(!methods.contains("post")); assert!(methods.contains("put"));
assert!(!methods.contains("delete")); assert!(methods.contains("patch"));
assert_eq!(methods.len(), 3); }
#[test]
fn test_no_methods() {
let code = r#"router = router.nest("/api", api::router());"#;
let methods = extract_http_methods(code);
assert_eq!(methods.len(), 0);
}
#[test]
fn test_multiple_different_routes() {
let code = r#"
router = router.route("/one", get(handler1));
router = router.route("/two", post(handler2));
"#;
let methods = extract_http_methods(code);
assert!(methods.contains("get"));
assert!(methods.contains("post"));
assert_eq!(methods.len(), 2);
}
}