Skip to content
Merged

Enum #18

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changepacks/changepack_log_1XG0SAoIz8gJQBgMn7g77.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"crates/vespera_macro/Cargo.toml":"Patch","crates/vespera/Cargo.toml":"Patch","crates/vespera_core/Cargo.toml":"Patch"},"note":"Support enum","date":"2025-12-03T12:00:56.589333100Z"}
4 changes: 1 addition & 3 deletions crates/vespera_core/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};

/// OpenAPI document version
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Default)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum OpenApiVersion {
#[serde(rename = "3.0.0")]
V3_0_0,
Expand All @@ -22,7 +21,6 @@ pub enum OpenApiVersion {
V3_1_0,
}


/// Contact information
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down
6 changes: 5 additions & 1 deletion crates/vespera_core/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ pub struct Schema {
/// Array item schema
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<Box<SchemaRef>>,
/// Prefix items for tuple arrays (OpenAPI 3.1 / JSON Schema 2020-12)
#[serde(skip_serializing_if = "Option::is_none")]
pub prefix_items: Option<Vec<SchemaRef>>,
/// Minimum number of items
#[serde(skip_serializing_if = "Option::is_none")]
pub min_items: Option<usize>,
Expand All @@ -149,7 +152,7 @@ pub struct Schema {
/// List of required properties
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<Vec<String>>,
/// Whether additional properties are allowed
/// Whether additional properties are allowed (can be boolean or SchemaRef)
#[serde(skip_serializing_if = "Option::is_none")]
pub additional_properties: Option<serde_json::Value>,
/// Minimum number of properties
Expand Down Expand Up @@ -210,6 +213,7 @@ impl Schema {
max_length: None,
pattern: None,
items: None,
prefix_items: None,
min_items: None,
max_items: None,
unique_items: None,
Expand Down
4 changes: 2 additions & 2 deletions crates/vespera_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub fn derive_schema(input: TokenStream) -> TokenStream {
definition: quote::quote!(#input).to_string(),
});

// For now, we just mark the struct as having SchemaBuilder
// Mark both struct and enum as having SchemaBuilder
// The actual schema generation will be done at runtime
let expanded = quote! {
impl vespera::schema::SchemaBuilder for #name {}
Expand Down Expand Up @@ -283,7 +283,7 @@ fn generate_router_code(
})
.collect::<Vec<syn::PathSegment>>(),
);
let func_name = syn::Ident::new(&function_name, Span::call_site());
let func_name = syn::Ident::new(function_name, Span::call_site());
router_nests.push(quote!(
.route(#path, #method_path(#p::#func_name))
));
Expand Down
29 changes: 22 additions & 7 deletions crates/vespera_macro/src/openapi_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use vespera_core::{
};

use crate::metadata::CollectedMetadata;
use crate::parser::{build_operation_from_function, parse_struct_to_schema};
use crate::parser::{build_operation_from_function, parse_enum_to_schema, parse_struct_to_schema};

/// Generate OpenAPI document from collected metadata
pub fn generate_openapi_doc_with_metadata(
Expand All @@ -21,17 +21,32 @@ pub fn generate_openapi_doc_with_metadata(
let mut known_schema_names: std::collections::HashMap<String, String> =
std::collections::HashMap::new();

// First, collect all struct schemas
// First, register all schema names so they can be referenced during parsing
for struct_meta in &metadata.structs {
let schema = parse_struct_to_schema(
&syn::parse_str(&struct_meta.definition).unwrap(),
&known_schema_names,
);
let schema_name = struct_meta.name.clone();
schemas.insert(schema_name.clone(), schema);
known_schema_names.insert(schema_name.clone(), schema_name);
}

// Then, parse all struct and enum schemas (now they can reference each other)
for struct_meta in &metadata.structs {
let parsed = syn::parse_str::<syn::Item>(&struct_meta.definition).unwrap();
let schema = match parsed {
syn::Item::Struct(struct_item) => {
parse_struct_to_schema(&struct_item, &known_schema_names)
}
syn::Item::Enum(enum_item) => parse_enum_to_schema(&enum_item, &known_schema_names),
_ => {
// Fallback to struct parsing for backward compatibility
parse_struct_to_schema(
&syn::parse_str(&struct_meta.definition).unwrap(),
&known_schema_names,
)
}
};
let schema_name = struct_meta.name.clone();
schemas.insert(schema_name.clone(), schema);
}

// Process routes from metadata
for route_meta in &metadata.routes {
// Try to parse the file to get the actual function
Expand Down
Loading