use crate::openapi::route::OpenApiRoute;
use crate::openapi::spec::OpenApiSpec;
use std::sync::Arc;
pub fn generate_routes_from_spec(spec: &Arc<OpenApiSpec>) -> Vec<OpenApiRoute> {
let mut routes = Vec::new();
for (path, path_item) in &spec.spec.paths.paths {
if let Some(item) = path_item.as_item() {
if let Some(op) = &item.get {
routes.push(OpenApiRoute::from_operation("GET", path.clone(), op, spec.clone()));
}
if let Some(op) = &item.post {
routes.push(OpenApiRoute::from_operation("POST", path.clone(), op, spec.clone()));
}
if let Some(op) = &item.put {
routes.push(OpenApiRoute::from_operation("PUT", path.clone(), op, spec.clone()));
}
if let Some(op) = &item.delete {
routes.push(OpenApiRoute::from_operation("DELETE", path.clone(), op, spec.clone()));
}
if let Some(op) = &item.patch {
routes.push(OpenApiRoute::from_operation("PATCH", path.clone(), op, spec.clone()));
}
if let Some(op) = &item.head {
routes.push(OpenApiRoute::from_operation("HEAD", path.clone(), op, spec.clone()));
}
if let Some(op) = &item.options {
routes.push(OpenApiRoute::from_operation(
"OPTIONS",
path.clone(),
op,
spec.clone(),
));
}
if let Some(op) = &item.trace {
routes.push(OpenApiRoute::from_operation("TRACE", path.clone(), op, spec.clone()));
}
}
}
routes
}
pub fn extract_path_parameters(path_template: &str) -> Vec<String> {
let mut params = Vec::new();
let mut in_param = false;
let mut current_param = String::new();
for ch in path_template.chars() {
match ch {
'{' => {
in_param = true;
current_param.clear();
}
'}' => {
if in_param {
params.push(current_param.clone());
in_param = false;
}
}
ch if in_param => {
current_param.push(ch);
}
_ => {}
}
}
params
}
pub fn convert_path_to_axum_format(path: &str) -> String {
path.to_string()
}
pub fn validate_path_parameters(template_path: &str, actual_path: &str) -> bool {
let routing_template = convert_path_to_axum_format(template_path);
route_matches_pattern(&routing_template, actual_path)
}
pub fn generate_route_key(method: &str, path: &str) -> String {
format!("{}:{}", method.to_uppercase(), path)
}
pub fn route_matches_pattern(route_path: &str, request_path: &str) -> bool {
let route_parts: Vec<&str> = route_path.split('/').filter(|s| !s.is_empty()).collect();
let request_parts: Vec<&str> = request_path.split('/').filter(|s| !s.is_empty()).collect();
match_segments(&route_parts, &request_parts, 0, 0)
}
fn match_segments(
route_parts: &[&str],
request_parts: &[&str],
route_idx: usize,
request_idx: usize,
) -> bool {
if route_idx == route_parts.len() && request_idx == request_parts.len() {
return true;
}
if route_idx == route_parts.len() {
return false;
}
let current_route = route_parts[route_idx];
match current_route {
"*" => {
if request_idx < request_parts.len() {
if match_segments(route_parts, request_parts, route_idx + 1, request_idx + 1) {
return true;
}
}
false
}
"**" => {
if match_segments(route_parts, request_parts, route_idx + 1, request_idx) {
return true;
}
if request_idx < request_parts.len()
&& match_segments(route_parts, request_parts, route_idx, request_idx + 1)
{
return true;
}
false
}
route_seg if route_seg.starts_with(':') => {
if request_idx < request_parts.len() {
return match_segments(route_parts, request_parts, route_idx + 1, request_idx + 1);
}
false
}
_ => {
if request_idx < request_parts.len() && current_route == request_parts[request_idx] {
return match_segments(route_parts, request_parts, route_idx + 1, request_idx + 1);
}
false
}
}
}
pub fn generate_parameter_extraction_code(route: &OpenApiRoute) -> String {
let mut code = String::new();
for param_name in &route.parameters {
if param_name.starts_with(':') {
code.push_str(&format!(
"let {} = path_params.get(\"{}\").cloned().unwrap_or_default();\n",
param_name.trim_start_matches(':'),
param_name.trim_start_matches(':')
));
}
}
code
}
pub fn generate_parameter_validation_code(route: &OpenApiRoute) -> String {
let mut code = String::new();
for param in &route.parameters {
if param.starts_with(':') {
code.push_str(&format!(
"if {}.is_empty() {{ return Err(Error::internal(\"Missing parameter: {}\")); }}\n",
param.trim_start_matches(':'),
param.trim_start_matches(':')
));
}
}
code
}
pub fn generate_mock_response_code(route: &OpenApiRoute) -> String {
let mut code = String::new();
code.push_str("let mut response = json!({});\n");
let _operation = &route.operation;
code.push_str("// Generate response based on OpenAPI operation\n");
code.push_str(&format!("// Operation: {} {}\n", route.method, route.path));
code
}