@@ -101,7 +101,7 @@ pub fn parse_function_parameter(
101101 if is_map_type ( inner_ty) {
102102 return None ;
103103 }
104-
104+
105105 // Check if it's a struct - expand to individual parameters
106106 if let Some ( struct_params) = parse_query_struct_to_parameters (
107107 inner_ty,
@@ -110,7 +110,13 @@ pub fn parse_function_parameter(
110110 ) {
111111 return Some ( struct_params) ;
112112 }
113-
113+
114+ // Check if it's a known type (primitive or known schema)
115+ // If unknown, don't add parameter
116+ if !is_known_type ( inner_ty, known_schemas, struct_definitions) {
117+ return None ;
118+ }
119+
114120 // Otherwise, treat as single parameter
115121 return Some ( vec ! [ Parameter {
116122 name: param_name. clone( ) ,
@@ -205,6 +211,55 @@ fn is_map_type(ty: &Type) -> bool {
205211 false
206212}
207213
214+ /// Check if a type is a known type (primitive, known schema, or struct definition)
215+ fn is_known_type (
216+ ty : & Type ,
217+ known_schemas : & HashMap < String , String > ,
218+ struct_definitions : & HashMap < String , String > ,
219+ ) -> bool {
220+ // Check if it's a primitive type
221+ if is_primitive_type ( ty) {
222+ return true ;
223+ }
224+
225+ // Check if it's a known struct
226+ if let Type :: Path ( type_path) = ty {
227+ let path = & type_path. path ;
228+ if path. segments . is_empty ( ) {
229+ return false ;
230+ }
231+
232+ let segment = path. segments . last ( ) . unwrap ( ) ;
233+ let ident_str = segment. ident . to_string ( ) ;
234+
235+ // Get type name (handle both simple and qualified paths)
236+ let type_name = if path. segments . len ( ) > 1 {
237+ ident_str. clone ( )
238+ } else {
239+ ident_str. clone ( )
240+ } ;
241+
242+ // Check if it's in struct_definitions or known_schemas
243+ if struct_definitions. contains_key ( & type_name) || known_schemas. contains_key ( & type_name) {
244+ return true ;
245+ }
246+
247+ // Check for generic types like Vec<T>, Option<T> - recursively check inner type
248+ if let syn:: PathArguments :: AngleBracketed ( args) = & segment. arguments {
249+ match ident_str. as_str ( ) {
250+ "Vec" | "Option" => {
251+ if let Some ( syn:: GenericArgument :: Type ( inner_ty) ) = args. args . first ( ) {
252+ return is_known_type ( inner_ty, known_schemas, struct_definitions) ;
253+ }
254+ }
255+ _ => { }
256+ }
257+ }
258+ }
259+
260+ false
261+ }
262+
208263/// Parse struct fields to individual query parameters
209264/// Returns None if the type is not a struct or cannot be parsed
210265fn parse_query_struct_to_parameters (
@@ -218,43 +273,43 @@ fn parse_query_struct_to_parameters(
218273 if path. segments . is_empty ( ) {
219274 return None ;
220275 }
221-
276+
222277 let segment = path. segments . last ( ) . unwrap ( ) ;
223278 let ident_str = segment. ident . to_string ( ) ;
224-
279+
225280 // Get type name (handle both simple and qualified paths)
226281 let type_name = if path. segments . len ( ) > 1 {
227282 ident_str. clone ( )
228283 } else {
229284 ident_str. clone ( )
230285 } ;
231-
286+
232287 // Check if it's a known struct
233288 if let Some ( struct_def) = struct_definitions. get ( & type_name) {
234289 if let Ok ( struct_item) = syn:: parse_str :: < syn:: ItemStruct > ( struct_def) {
235290 let mut parameters = Vec :: new ( ) ;
236-
291+
237292 // Extract rename_all attribute from struct
238293 let rename_all = extract_rename_all ( & struct_item. attrs ) ;
239-
294+
240295 if let syn:: Fields :: Named ( fields_named) = & struct_item. fields {
241296 for field in & fields_named. named {
242297 let rust_field_name = field
243298 . ident
244299 . as_ref ( )
245300 . map ( |i| i. to_string ( ) )
246301 . unwrap_or_else ( || "unknown" . to_string ( ) ) ;
247-
302+
248303 // Check for field-level rename attribute first (takes precedence)
249304 let field_name = if let Some ( renamed) = extract_field_rename ( & field. attrs ) {
250305 renamed
251306 } else {
252307 // Apply rename_all transformation if present
253308 rename_field ( & rust_field_name, rename_all. as_deref ( ) )
254309 } ;
255-
310+
256311 let field_type = & field. ty ;
257-
312+
258313 // Check if field is Option<T>
259314 let is_optional = matches ! (
260315 field_type,
@@ -266,22 +321,26 @@ fn parse_query_struct_to_parameters(
266321 . map( |s| s. ident == "Option" )
267322 . unwrap_or( false )
268323 ) ;
269-
324+
270325 // Parse field type to schema (inline, not ref)
271326 // For Query parameters, we need inline schemas, not refs
272327 let mut field_schema = parse_type_to_schema_ref_with_schemas (
273328 field_type,
274329 known_schemas,
275330 struct_definitions,
276331 ) ;
277-
332+
278333 // Convert ref to inline if needed (Query parameters should not use refs)
279334 // If it's a ref to a known struct, get the struct definition and inline it
280335 if let SchemaRef :: Ref ( ref_ref) = & field_schema {
281336 // Try to extract type name from ref path (e.g., "#/components/schemas/User" -> "User")
282- if let Some ( type_name) = ref_ref. ref_path . strip_prefix ( "#/components/schemas/" ) {
337+ if let Some ( type_name) =
338+ ref_ref. ref_path . strip_prefix ( "#/components/schemas/" )
339+ {
283340 if let Some ( struct_def) = struct_definitions. get ( type_name) {
284- if let Ok ( nested_struct_item) = syn:: parse_str :: < syn:: ItemStruct > ( struct_def) {
341+ if let Ok ( nested_struct_item) =
342+ syn:: parse_str :: < syn:: ItemStruct > ( struct_def)
343+ {
285344 // Parse the nested struct to schema (inline)
286345 let nested_schema = parse_struct_to_schema (
287346 & nested_struct_item,
@@ -293,7 +352,7 @@ fn parse_query_struct_to_parameters(
293352 }
294353 }
295354 }
296-
355+
297356 // If it's Option<T>, make it nullable
298357 let final_schema = if is_optional {
299358 if let SchemaRef :: Inline ( mut schema) = field_schema {
@@ -316,9 +375,9 @@ fn parse_query_struct_to_parameters(
316375 SchemaRef :: Inline ( schema) => SchemaRef :: Inline ( schema) ,
317376 }
318377 } ;
319-
378+
320379 let required = !is_optional;
321-
380+
322381 parameters. push ( Parameter {
323382 name : field_name,
324383 r#in : ParameterLocation :: Query ,
@@ -329,7 +388,7 @@ fn parse_query_struct_to_parameters(
329388 } ) ;
330389 }
331390 }
332-
391+
333392 if !parameters. is_empty ( ) {
334393 return Some ( parameters) ;
335394 }
0 commit comments