| 257 | } |
| 258 | |
| 259 | fn routes_from_decorator(expression: &Expression, routes: &mut Vec<Route>) { |
| 260 | let Expression::Call(CallExpression { |
| 261 | arguments: Arguments { args, keywords, .. }, |
| 262 | func, |
| 263 | .. |
| 264 | }) = expression |
| 265 | else { |
| 266 | return; |
| 267 | }; |
| 268 | |
| 269 | let Expression::Attribute(AttributeExpression { |
| 270 | attr: Identifier { id, .. }, |
| 271 | .. |
| 272 | }) = &**func |
| 273 | else { |
| 274 | return; |
| 275 | }; |
| 276 | |
| 277 | let method = id.as_str(); |
| 278 | |
| 279 | let Some(path) = args.first().and_then(expr_string) else { |
| 280 | return; |
| 281 | }; |
| 282 | |
| 283 | if ROUTE_VERBS.contains(&method) { |
| 284 | routes.push(Route { |
| 285 | path, |
| 286 | method: method.to_uppercase().into(), |
| 287 | }); |
| 288 | |
| 289 | return; |
| 290 | } |
| 291 | |
| 292 | if method == "route" || method == "api_route" { |
| 293 | // methods=[...] keyword, else default GET |
| 294 | if let Some(keyword) = keywords |
| 295 | .iter() |
| 296 | .find(|keyword| keyword.arg.as_ref().map(|id| id.as_str()) == Some("methods")) |
| 297 | { |
| 298 | if let Expression::List(list) = &keyword.value { |
| 299 | let mut any = false; |
| 300 | |
| 301 | for method in list.elts.iter().filter_map(expr_string) { |
| 302 | routes.push(Route { |
| 303 | path: path.clone(), |
| 304 | method: method.to_uppercase(), |
| 305 | }); |
| 306 | |
| 307 | any = true; |
| 308 | } |
| 309 | |
| 310 | if any { |
| 311 | return; |
| 312 | } |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | routes.push(Route { |