use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{Expr, Type};
#[derive(Debug, Clone)]
pub struct ParamConfig {
pub name: String,
pub ty: Type,
pub location: ParamLocation,
pub description: Option<String>,
#[allow(dead_code)]
pub required: bool,
pub deprecated: bool,
pub example: Option<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub enum ParamLocation {
Path,
Query,
Header,
Cookie,
}
impl ToTokens for ParamLocation {
fn to_tokens(&self, tokens: &mut TokenStream) {
let t = match self {
ParamLocation::Path => quote::quote!(Path),
ParamLocation::Query => quote::quote!(Query),
ParamLocation::Header => quote::quote!(Header),
ParamLocation::Cookie => quote::quote!(Cookie),
};
tokens.extend(t);
}
}
#[derive(Debug, Clone)]
pub struct ResponseConfig {
pub status: u16,
pub description: String,
pub body: Option<Type>,
pub content_type: Option<String>,
}
#[derive(Debug, Default)]
pub struct OpenApiConfig {
pub user_summary: Option<String>,
pub user_description: Option<String>,
pub user_tags: Vec<String>,
pub user_params: Vec<ParamConfig>,
pub user_responses: Vec<ResponseConfig>,
pub user_request_body: Option<RequestBodyConfig>,
pub deprecated: bool,
pub auto_summary: Option<String>,
pub auto_description: Option<String>,
pub auto_params: Vec<ParamConfig>,
pub auto_response: Option<ResponseConfig>,
pub auto_request_body: Option<RequestBodyConfig>,
}
#[derive(Debug, Clone)]
pub struct RequestBodyConfig {
pub ty: Type,
pub description: Option<String>,
#[allow(dead_code)]
pub required: bool,
pub content_type: String,
}
impl OpenApiConfig {
pub fn new() -> Self {
Self::default()
}
pub fn final_summary(&self) -> Option<&str> {
self.user_summary
.as_deref()
.or(self.auto_summary.as_deref())
}
pub fn final_description(&self) -> Option<&str> {
self.user_description
.as_deref()
.or(self.auto_description.as_deref())
}
pub fn final_tags(&self) -> &[String] {
&self.user_tags
}
pub fn final_params(&self) -> Vec<ParamConfig> {
let mut params = self.auto_params.clone();
for user_param in &self.user_params {
if let Some(pos) = params.iter().position(|p| p.name == user_param.name) {
params[pos] = user_param.clone();
} else {
params.push(user_param.clone());
}
}
params
}
pub fn final_responses(&self) -> Vec<ResponseConfig> {
let mut responses = Vec::new();
if let Some(ref auto_resp) = self.auto_response {
responses.push(auto_resp.clone());
}
responses.extend(self.user_responses.iter().cloned());
responses
}
pub fn final_request_body(&self) -> Option<&RequestBodyConfig> {
self.user_request_body
.as_ref()
.or(self.auto_request_body.as_ref())
}
}