@@ -119,13 +119,11 @@ pub fn parse_function_parameter(
119119 }
120120 } else {
121121 // Single path parameter
122- // If there's exactly one path parameter, use its name
123- let name = if path_params. len ( ) == 1 {
124- path_params[ 0 ] . clone ( )
125- } else {
126- // Otherwise use the parameter name from the pattern
127- param_name
128- } ;
122+ // Allow only when exactly one path parameter is provided
123+ if path_params. len ( ) != 1 {
124+ return None ;
125+ }
126+ let name = path_params[ 0 ] . clone ( ) ;
129127 return Some ( vec ! [ Parameter {
130128 name,
131129 r#in: ParameterLocation :: Path ,
@@ -161,6 +159,11 @@ pub fn parse_function_parameter(
161159 return Some ( struct_params) ;
162160 }
163161
162+ // Ignore primitive-like query params (including Vec/Option of primitive)
163+ if is_primitive_like ( inner_ty) {
164+ return None ;
165+ }
166+
164167 // Check if it's a known type (primitive or known schema)
165168 // If unknown, don't add parameter
166169 if !is_known_type ( inner_ty, known_schemas, struct_definitions) {
@@ -188,6 +191,10 @@ pub fn parse_function_parameter(
188191 && let Some ( syn:: GenericArgument :: Type ( inner_ty) ) =
189192 args. args . first ( )
190193 {
194+ // Ignore primitive-like headers
195+ if is_primitive_like ( inner_ty) {
196+ return None ;
197+ }
191198 return Some ( vec ! [ Parameter {
192199 name: param_name. clone( ) ,
193200 r#in: ParameterLocation :: Header ,
@@ -257,6 +264,25 @@ fn is_map_type(ty: &Type) -> bool {
257264 false
258265}
259266
267+ fn is_primitive_like ( ty : & Type ) -> bool {
268+ if is_primitive_type ( ty) {
269+ return true ;
270+ }
271+ if let Type :: Path ( type_path) = ty {
272+ if let Some ( seg) = type_path. path . segments . last ( ) {
273+ let ident = seg. ident . to_string ( ) ;
274+ if let syn:: PathArguments :: AngleBracketed ( args) = & seg. arguments {
275+ if let Some ( syn:: GenericArgument :: Type ( inner_ty) ) = args. args . first ( ) {
276+ if ( ident == "Vec" || ident == "Option" ) && is_primitive_like ( inner_ty) {
277+ return true ;
278+ }
279+ }
280+ }
281+ }
282+ }
283+ false
284+ }
285+
260286fn is_known_type (
261287 ty : & Type ,
262288 known_schemas : & HashMap < String , String > ,
@@ -591,6 +617,55 @@ mod tests {
591617 assert_debug_snapshot ! ( parameters) ;
592618 }
593619
620+ #[ rstest]
621+ #[ case(
622+ "fn test(id: Query<i32>) {}" ,
623+ vec![ ] ,
624+ ) ]
625+ #[ case(
626+ "fn test(auth: Header<String>) {}" ,
627+ vec![ ] ,
628+ ) ]
629+ #[ case(
630+ "fn test(params: Query<Vec<i32>>) {}" ,
631+ vec![ ] ,
632+ ) ]
633+ #[ case(
634+ "fn test(params: Query<Option<String>>) {}" ,
635+ vec![ ] ,
636+ ) ]
637+ #[ case(
638+ "fn test(Path([a]): Path<[i32; 1]>) {}" ,
639+ vec![ ] ,
640+ ) ]
641+ #[ case(
642+ "fn test(id: Path<i32>) {}" ,
643+ vec![ "user_id" . to_string( ) , "post_id" . to_string( ) ] ,
644+ ) ]
645+ fn test_parse_function_parameter_wrong_cases (
646+ #[ case] func_src : & str ,
647+ #[ case] path_params : Vec < String > ,
648+ ) {
649+ let func: syn:: ItemFn = syn:: parse_str ( func_src) . unwrap ( ) ;
650+ let ( known_schemas, struct_definitions) = setup_test_data ( func_src) ;
651+
652+ for ( idx, arg) in func. sig . inputs . iter ( ) . enumerate ( ) {
653+ let result = parse_function_parameter (
654+ arg,
655+ & path_params,
656+ & known_schemas,
657+ & struct_definitions,
658+ ) ;
659+ assert ! (
660+ result. is_none( ) ,
661+ "Expected None at arg index {}, func: {}, got: {:?}" ,
662+ idx,
663+ func_src,
664+ result
665+ ) ;
666+ }
667+ }
668+
594669 #[ test]
595670 fn test_is_map_type ( ) {
596671 // Test HashMap
0 commit comments