mod args;
mod collector;
mod cron_impl;
mod error;
mod file_utils;
mod http;
mod metadata;
mod method;
mod openapi_generator;
mod multipart_impl;
mod parser;
mod route;
mod route_impl;
mod router_codegen;
mod schema_impl;
mod schema_macro;
mod vespera_impl;
pub(crate) use cron_impl::CRON_STORAGE;
use proc_macro::TokenStream;
pub(crate) use route_impl::ROUTE_STORAGE;
pub(crate) use schema_impl::SCHEMA_STORAGE;
use crate::{
router_codegen::{AutoRouterInput, ExportAppInput, process_vespera_input},
vespera_impl::{process_export_app, process_vespera_macro},
};
#[cfg(not(tarpaulin_include))]
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
match route_impl::process_route_attribute(attr.into(), item.into()) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[cfg(not(tarpaulin_include))]
#[proc_macro_attribute]
pub fn cron(attr: TokenStream, item: TokenStream) -> TokenStream {
match cron_impl::process_cron_attribute(attr.into(), item.into()) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[cfg(not(tarpaulin_include))]
#[proc_macro_derive(Schema, attributes(schema, serde))]
pub fn derive_schema(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let (metadata, expanded) = schema_impl::process_derive_schema(&input);
let name = metadata.name.clone();
SCHEMA_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.insert(name, metadata);
TokenStream::from(expanded)
}
#[cfg(not(tarpaulin_include))]
#[proc_macro_derive(Multipart, attributes(serde, form_data, try_from_multipart))]
pub fn derive_multipart(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
TokenStream::from(multipart_impl::process_derive(&input))
}
#[cfg(not(tarpaulin_include))]
#[proc_macro]
pub fn schema(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as schema_macro::SchemaInput);
let storage = SCHEMA_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
match schema_macro::generate_schema_code(&input, &storage) {
Ok(tokens) => TokenStream::from(tokens),
Err(e) => e.to_compile_error().into(),
}
}
#[cfg(not(tarpaulin_include))]
#[proc_macro]
pub fn schema_type(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as schema_macro::SchemaTypeInput);
let (tokens, generated_metadata) = {
let storage = SCHEMA_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
match schema_macro::generate_schema_type_code(&input, &storage) {
Ok(result) => result,
Err(e) => return e.to_compile_error().into(),
}
};
if let Some(metadata) = generated_metadata {
let name = metadata.name.clone();
SCHEMA_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.insert(name, metadata);
}
TokenStream::from(tokens)
}
#[cfg(not(tarpaulin_include))]
#[proc_macro]
pub fn vespera(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as AutoRouterInput);
let processed = process_vespera_input(input);
let schema_storage = SCHEMA_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let route_storage = ROUTE_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
match process_vespera_macro(&processed, &schema_storage, &route_storage) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[cfg(not(tarpaulin_include))]
#[proc_macro]
pub fn export_app(input: TokenStream) -> TokenStream {
let ExportAppInput { name, dir } = syn::parse_macro_input!(input as ExportAppInput);
let folder_name = dir
.map(|d| d.value())
.or_else(|| std::env::var("VESPERA_DIR").ok())
.unwrap_or_else(|| "routes".to_string());
let schema_storage = SCHEMA_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") else {
return syn::Error::new(proc_macro2::Span::call_site(), "export_app! macro: CARGO_MANIFEST_DIR is not set. This macro must be used within a cargo build.").to_compile_error().into();
};
let route_storage = ROUTE_STORAGE
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
match process_export_app(
&name,
&folder_name,
&schema_storage,
&manifest_dir,
&route_storage,
) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}