bytedocs_rs/parser/
common.rs

1//! Common parsing utilities for extracting route information.
2//!
3//! This module provides shared functions for parsing route parameters,
4//! handler comments, and generating default responses.
5
6use crate::core::types::{Parameter, RouteInfo, Response};
7use regex::Regex;
8use std::collections::HashMap;
9
10/// Information extracted from handler comments.
11#[derive(Debug, Clone)]
12pub struct HandlerInfo {
13    pub summary: String,
14    pub description: String,
15    pub parameters: Vec<Parameter>,
16}
17
18/// Extracts path parameters from a route path.
19///
20/// Supports both `:param` and `{param}` style parameters.
21///
22/// # Arguments
23///
24/// * `path` - The route path (e.g., "/users/:id" or "/users/{id}")
25pub fn extract_path_params(path: &str) -> Vec<Parameter> {
26    let mut params = Vec::new();
27
28    // Extract :param style parameters
29    let colon_regex = Regex::new(r":(\w+)").unwrap();
30    for cap in colon_regex.captures_iter(path) {
31        if let Some(param_name) = cap.get(1) {
32            params.push(Parameter {
33                name: param_name.as_str().to_string(),
34                r#in: "path".to_string(),
35                r#type: "string".to_string(),
36                required: true,
37                description: String::new(),
38                example: None,
39            });
40        }
41    }
42
43    // Extract {param} style parameters
44    let brace_regex = Regex::new(r"\{(\w+)\}").unwrap();
45    for cap in brace_regex.captures_iter(path) {
46        if let Some(param_name) = cap.get(1) {
47            params.push(Parameter {
48                name: param_name.as_str().to_string(),
49                r#in: "path".to_string(),
50                r#type: "string".to_string(),
51                required: true,
52                description: String::new(),
53                example: None,
54            });
55        }
56    }
57
58    params
59}
60
61/// Parses handler comments to extract documentation information.
62///
63/// Supports annotations like `@summary`, `@description`, and `@param`.
64///
65/// # Arguments
66///
67/// * `comments` - Array of comment strings from the handler
68pub fn parse_handler_comments(comments: &[String]) -> HandlerInfo {
69    let mut info = HandlerInfo {
70        summary: String::new(),
71        description: String::new(),
72        parameters: Vec::new(),
73    };
74
75    // Parse @param annotations
76    let param_regex = Regex::new(r#"@param\s+(\w+)\s+(\w+)\s+(\w+)\s+(true|false)\s+"([^"]*)""#).unwrap();
77
78    for line in comments {
79        if let Some(caps) = param_regex.captures(line) {
80            let param = Parameter {
81                name: caps[1].to_string(),
82                r#in: caps[2].to_string(),
83                r#type: caps[3].to_string(),
84                required: &caps[4] == "true",
85                description: caps[5].to_string(),
86                example: None,
87            };
88            info.parameters.push(param);
89        } else if line.starts_with("@summary") {
90            info.summary = line.strip_prefix("@summary").unwrap_or("").trim().to_string();
91        } else if line.starts_with("@description") {
92            info.description = line.strip_prefix("@description").unwrap_or("").trim().to_string();
93        } else if info.summary.is_empty() && !line.trim().is_empty() {
94            // Use first non-empty line as summary if no @summary found
95            info.summary = line.trim().to_string();
96        }
97    }
98
99    info
100}
101
102/// Normalizes HTTP method to uppercase.
103pub fn normalize_method(method: &str) -> String {
104    method.to_uppercase()
105}
106
107/// Generates default HTTP response definitions.
108///
109/// Creates standard responses for 200, 400, 404, and 500 status codes.
110pub fn generate_default_responses() -> HashMap<String, Response> {
111    let mut responses = HashMap::new();
112
113    responses.insert("200".to_string(), Response {
114        description: "OK".to_string(),
115        example: Some(serde_json::json!({"status": "success"})),
116        schema: None,
117        content_type: Some("application/json".to_string()),
118    });
119
120    responses.insert("400".to_string(), Response {
121        description: "Bad Request".to_string(),
122        example: None,
123        schema: None,
124        content_type: Some("application/json".to_string()),
125    });
126
127    responses.insert("404".to_string(), Response {
128        description: "Not Found".to_string(),
129        example: None,
130        schema: None,
131        content_type: Some("application/json".to_string()),
132    });
133
134    responses.insert("500".to_string(), Response {
135        description: "Internal Server Error".to_string(),
136        example: None,
137        schema: None,
138        content_type: Some("application/json".to_string()),
139    });
140
141    responses
142}
143
144/// Trait for implementing framework-specific route parsers.
145pub trait FrameworkParser {
146    fn parse_routes(&self, app: &dyn std::any::Any) -> Vec<RouteInfo>;
147    fn extract_handler_info(&self, handler: &dyn std::any::Any) -> HandlerInfo;
148}